diff --git a/frontend/public/assets/bank-logos/City_Union_bank.svg b/frontend/public/assets/bank-logos/City_Union_bank.svg new file mode 100644 index 0000000..a79ac26 --- /dev/null +++ b/frontend/public/assets/bank-logos/City_Union_bank.svg @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/frontend/src/components/features/BankReconciliation/RecordPaymentModal.tsx b/frontend/src/components/features/BankReconciliation/RecordPaymentModal.tsx index 980e41f..8428258 100644 --- a/frontend/src/components/features/BankReconciliation/RecordPaymentModal.tsx +++ b/frontend/src/components/features/BankReconciliation/RecordPaymentModal.tsx @@ -913,7 +913,7 @@ const GetUnpaidInvoicesButton = () => { {partyType && party && } - + Select Invoices Unpaid invoices from {partyName} for {formatCurrency(amount)}. @@ -967,13 +967,31 @@ const FetchInvoicesModal = ({ onClose }: { onClose: () => void }) => { }, [data]) const [selectedInvoices, setSelectedInvoices] = useState([]) + const [anchorIndex, setAnchorIndex] = useState(null) - const onSelectRow = (row: OutstandingInvoice) => { - if (selectedInvoices.includes(row)) { - setSelectedInvoices(selectedInvoices.filter((invoice) => invoice !== row)) + const onSelectRow = (row: OutstandingInvoice, index: number, shiftKey: boolean) => { + const rows = data?.message ?? [] + const isSelected = selectedInvoices.includes(row) + const nextChecked = !isSelected + + if (shiftKey && anchorIndex !== null && anchorIndex !== index) { + const [start, end] = anchorIndex < index ? [anchorIndex, index] : [index, anchorIndex] + const rangeRows = rows.slice(start, end + 1) + + setSelectedInvoices((prev) => { + if (nextChecked) { + const toAdd = rangeRows.filter((r) => !prev.includes(r)) + return [...prev, ...toAdd] + } + return prev.filter((r) => !rangeRows.includes(r)) + }) } else { - setSelectedInvoices([...selectedInvoices, row]) + setSelectedInvoices((prev) => + isSelected ? prev.filter((invoice) => invoice !== row) : [...prev, row] + ) } + + setAnchorIndex(index) } const { call: allocateAmountToReferences, loading: allocateAmountToReferencesLoading, error: allocateAmountToReferencesError } = useFrappePostCall('run_doc_method') @@ -1019,7 +1037,8 @@ const FetchInvoicesModal = ({ onClose }: { onClose: () => void }) => { onClose() }) } - return
+ return
+
{isLoading ? : null} {error && } {error && } @@ -1058,26 +1077,24 @@ const FetchInvoicesModal = ({ onClose }: { onClose: () => void }) => { - {data.message.map((ref) => ( + {data.message.map((ref, index) => ( { const target = e.target as HTMLElement - // Do not select the checkbox if the user clicks on the checkbox or the link - if (target.tagName !== 'INPUT' && !target.className.includes('chakra-checkbox') && !target.className.includes('chakra-link')) { - onSelectRow(ref) - } + if (target.closest('a')) return + onSelectRow(ref, index, e.shiftKey) }} - className="cursor-pointer"> - - { - if (checked) { - setSelectedInvoices([...selectedInvoices, ref]) - } else { - setSelectedInvoices(selectedInvoices.filter((invoice) => invoice !== ref)) - } - }} + className="cursor-pointer select-none"> + { + e.stopPropagation() + onSelectRow(ref, index, e.shiftKey) + }}> + @@ -1105,12 +1122,13 @@ const FetchInvoicesModal = ({ onClose }: { onClose: () => void }) => { ))} : null} -
+
+
Invoices: {selectedInvoices.length} / Total: {formatCurrency(selectedInvoices.reduce((acc, invoice) => acc + invoice.outstanding_amount, 0))}
- + diff --git a/frontend/src/components/features/BankReconciliation/logos.ts b/frontend/src/components/features/BankReconciliation/logos.ts index 463cd5b..2e4edaa 100644 --- a/frontend/src/components/features/BankReconciliation/logos.ts +++ b/frontend/src/components/features/BankReconciliation/logos.ts @@ -141,6 +141,10 @@ export const BANK_LOGOS: { keywords: string[], logo: string }[] = [ keywords: ['Bank of Maharashtra', 'BOM'], logo: 'assets/bank-logos/Bank_of_Maharashtra.svg' }, + { + keywords: ['City Union Bank', 'CUB'], + logo: 'assets/bank-logos/City_Union_bank.svg' + }, { keywords: ['Kotak Mahindra Bank', 'Kotak'], logo: 'assets/bank-logos/Kotak_Mahindra.svg'