Skip to content

Commit

Permalink
Add Default Payment tab in Account Settings
Browse files Browse the repository at this point in the history
  • Loading branch information
longingia committed Sep 20, 2024
1 parent 899ca73 commit 7d038f5
Show file tree
Hide file tree
Showing 9 changed files with 199 additions and 162 deletions.
92 changes: 92 additions & 0 deletions assets/scripts/bank_details_dropdown.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
window.handleBankDetailsDropdown = function(event) {
const targetId = event.detail.target.id;

if (targetId === 'bank-details-dropdown') {
// Get the JSON response
const response = JSON.parse(event.detail.xhr.responseText);

// Clear the dropdown content first
const dropdown = document.getElementById('bank-details-dropdown');
dropdown.innerHTML = '';

// Check if the response is successful and contains bank details
if (response.status === 'success' && response.bank_details.length > 0) {
response.bank_details.forEach(function (bank_detail) {
// Create a new list item for each bank detail
const li = document.createElement('li');
li.classList.add('p-2', 'hover:bg-gray-200', 'flex', 'flex-row', 'justify-between', 'items-center', 'cursor-pointer');

// Set the bank detail as data attributes for the dropdown item
const detailDiv = document.createElement('div');
detailDiv.classList.add('flex', 'flex-col', 'items-start');
detailDiv.setAttribute('data-account-holder-name', bank_detail.account_holder_name);
detailDiv.setAttribute('data-account-number', bank_detail.account_number);
detailDiv.setAttribute('data-sort-code', bank_detail.sort_code);

// Set the inner HTML with bank details
detailDiv.innerHTML = `
<span class="font-semibold">${bank_detail.account_holder_name}</span>
<span class="text-sm text-gray-500">Account Number: ${bank_detail.account_number}</span>
<span class="text-sm text-gray-500">Sort Code: ${bank_detail.sort_code}</span>
`;

// Add an event listener to populate form fields when clicked
li.addEventListener('click', function () {
document.querySelector('input[name="account_holder_name"]').value = bank_detail.account_holder_name;
document.querySelector('input[name="account_number"]').value = bank_detail.account_number;
document.querySelector('input[name="sort_code"]').value = bank_detail.sort_code;

// Recheck the fields to enable/disable the save button
checkFieldsFilled();

dropdown.classList.add('opacity-0');
setTimeout(() => {
dropdown.style.display = 'none';
}, 0);
});

// Create the delete icon and handle delete request with fetch
const deleteIcon = document.createElement('div');
deleteIcon.innerHTML = '<i class="fa fa-trash text-red-500"></i>';
deleteIcon.classList.add('ml-4', 'cursor-pointer');

deleteIcon.addEventListener('click', function (e) {
e.stopPropagation();
// Send a fetch request to delete the bank detail
fetch(`/api/invoices/delete_bank_detail/${bank_detail.id}/`, {
method: 'DELETE',
headers: {
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value,
}
})
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
// Remove the deleted item from the dropdown
li.remove();
console.log('Bank detail deleted successfully');
} else {
console.error('Error deleting bank detail:', data.message);
}
})
.catch(error => {
console.error('Error deleting bank detail:', error);
});
});

// Append both the details div and delete icon to the list item
li.appendChild(detailDiv);
li.appendChild(deleteIcon);

// Append the new list item to the dropdown
dropdown.appendChild(li);
});

dropdown.style.display = 'block';
dropdown.classList.remove('opacity-0');
} else {
// Show a message if no bank details are available
dropdown.innerHTML = '<li class="p-2">No saved bank details found</li>';
}
}
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django.http import JsonResponse
from django.views.decorators.http import require_GET
from backend.models import DefaultValues
from django.views.decorators.http import require_GET, require_http_methods
from backend.models import DefaultValues, BankDetail

@require_GET
def get_bank_details(request):
Expand All @@ -21,3 +21,14 @@ def get_bank_details(request):
return JsonResponse({'status': 'success', 'bank_details': bank_details_list})
except DefaultValues.DoesNotExist:
return JsonResponse({'status': 'error', 'message': 'No saved bank details found'}, status=404)

@require_http_methods(["DELETE"])
def delete_bank_detail(request, bank_detail_id):
try:
bank_detail = BankDetail.objects.get(id=bank_detail_id)
bank_detail.delete()
return JsonResponse({'status': 'success'})
except BankDetail.DoesNotExist:
return JsonResponse({'status': 'error', 'message': 'Bank detail not found'}, status=404)
except Exception as e:
return JsonResponse({'status': 'error', 'message': str(e)}, status=500)
5 changes: 3 additions & 2 deletions backend/api/invoices/urls.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django.urls import path, include

from . import fetch, delete, edit, manage, get_bank_details
from . import bank_details, fetch, delete, edit, manage
from .create import set_destination
from .create.services import add_service
from .recurring.delete import delete_invoice_recurring_profile_endpoint
Expand Down Expand Up @@ -58,7 +58,8 @@
path("single/", include((SINGLE_INVOICE_URLS, "single"), namespace="single")),
path("recurring/", include((RECURRING_INVOICE_URLS, "recurring"), namespace="recurring")),
path("create/", include((CREATE_INVOICE_URLS, "create"), namespace="create")),
path("get_bank_details/", get_bank_details.get_bank_details, name="get_bank_details"),
path("get_bank_details/", bank_details.get_bank_details, name="get_bank_details"),
path("delete_bank_detail/<int:bank_detail_id>/", bank_details.delete_bank_detail, name='delete_bank_detail')
]

app_name = "invoices"
41 changes: 11 additions & 30 deletions frontend/templates/pages/clients/detail/client_defaults.html
Original file line number Diff line number Diff line change
Expand Up @@ -188,36 +188,16 @@ <h2 class="text-xl font-semibold">FROM Details</h2>
class="input input-block input-bordered">
</div>
</div>
<h2 class="text-xl font-semibold">Payment Details</h2>
<div class="w-full flex flex-row gap-4 mt-4">
<div class="form-control mb-4">
<label class="label justify-start" for="invoice_account_holder_name">Account Holder Name</label>
<input name="invoice_account_holder_name"
type="text"
value="{{ defaults.invoice_account_holder_name | default_if_none:'' }}"
placeholder="Mr John Doe"
class="input input-block input-bordered">
</div>
<div class="form-control mb-4">
<label class="label justify-start" for="invoice_account_number">Account Number</label>
<input name="invoice_account_number"
type="text"
value="{{ defaults.invoice_account_number | default_if_none:'' }}"
placeholder="12345678"
onkeyup="this.value = validate_account_number(this.value);"
class="input input-block input-bordered">
</div>
<div class="form-control mb-4">
<label class="label justify-start" for="invoice_sort_code">Sort Code</label>
<input name="invoice_sort_code"
onkeyup="this.value = validate_sort_code(this.value);"
pattern="[0-9]{2}-[0-9]{2}-[0-9]{2}"
type="text"
value="{{ defaults.invoice_sort_code | default_if_none:'' }}"
placeholder="12-34-56"
class="input input-block input-bordered">
</div>
</div>
</div>
<input type="radio"
name="my_tabs_2"
role="tab"
class="tab"
aria-label="Payment"
checked="checked" />
<div role="tabpanel"
class="tab-content bg-base-100 border-base-300 rounded-box p-6">
{% include "pages/invoices/create/bank_details/_bank_details.html" with button_text="Add" dropdown_text="Manage Saved Payment Details" %}
</div>
</div>
<button class="btn btn-primary loading-htmx mt-4"
Expand All @@ -229,3 +209,4 @@ <h2 class="text-xl font-semibold">Payment Details</h2>
</button>
</form>
{% render_bundle 'validate_payment_details' 'js' %}
{% render_bundle 'bank_details_dropdown' 'js' %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div class="my-4 flex w-full flex-col">
<div class="w-full grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-2 md:gap-2 lg:gap-4">
{% include "pages/invoices/create/bank_details/holder_name.html" %}
{% include "pages/invoices/create/bank_details/account_number.html" %}
{% include "pages/invoices/create/bank_details/sort_code.html" %}
</div>
{% include "pages/invoices/create/bank_details/_save_bank_details.html" with button_text=button_text dropdown_text=dropdown_text %}
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{% load render_bundle from webpack_loader %}
<div class="input_card max-w-full min-w-full mt-6">
<div class="card-body">
<div class="flex py-4 gap-x-3">
<div role="button"
class="btn btn-primary w-1/3"
id="save-for-future-btn"
hx-post="{% url 'invoices:save_bank_details' %}"
hx-include="[name='account_holder_name'], [name='account_number'], [name='sort_code']"
hx-trigger="click"
hx-swap="none"
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
disabled>
{{ button_text|default:"Save for Future Use" }}
</div>
<div class="dropdown w-2/3">
<div tabindex="0" role="button" class="btn btn-primary w-full"
hx-get="{% url 'api:invoices:get_bank_details' %}"
hx-trigger="click"
hx-target="#bank-details-dropdown"
hx-swap="none">
{{ dropdown_text|default:"Choose From Saved Details" }}
</div>
<ul id="bank-details-dropdown" tabindex="0"
class="dropdown-content z-[1] menu p-8 shadow bg-base-200 rounded-box w-full min-w-full"
style="max-height: 250px; overflow-y: auto;">
</ul>
</div>
</div>
</div>
</div>

{% render_bundle 'bank_details_dropdown' 'js' %}

<script>
document.addEventListener('htmx:afterRequest', handleBankDetailsDropdown);

// Get references to the input fields and the save button
const accountHolderNameInput = document.querySelector('input[name="account_holder_name"]');
const accountNumberInput = document.querySelector('input[name="account_number"]');
const sortCodeInput = document.querySelector('input[name="sort_code"]');
const saveButton = document.getElementById("save-for-future-btn");

// Function to check if all fields are filled and enable/disable the button
function checkFieldsFilled() {
if (accountHolderNameInput.value && accountNumberInput.value.length === 8 && sortCodeInput.value.length === 8) {
saveButton.removeAttribute("disabled"); // Enable button
} else {
saveButton.setAttribute("disabled", "true"); // Disable button
}
}

// Attach the event listeners to each input field to check the fields as user types
accountHolderNameInput.addEventListener("input", checkFieldsFilled);
accountNumberInput.addEventListener("input", checkFieldsFilled);
sortCodeInput.addEventListener("input", checkFieldsFilled);

// Initial check on page load
checkFieldsFilled();
</script>

<style>
ul#bank-details-dropdown li:hover {
background-color: #e0e0e0;
color: #000000;
}
</style>

This file was deleted.

Loading

0 comments on commit 7d038f5

Please sign in to comment.