Skip to content

Commit

Permalink
(Enhancement) Enhance Billing Dashboard (#52)
Browse files Browse the repository at this point in the history
  • Loading branch information
ODORA0 authored Jul 1, 2024
1 parent addc4ae commit 3cb8c55
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 104 deletions.
69 changes: 35 additions & 34 deletions src/invoice/invoice-table.component.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useMemo, useState } from 'react';
import React, { useMemo, useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import fuzzy from 'fuzzy';
import {
Expand All @@ -12,20 +12,17 @@ import {
TableHead,
TableHeader,
TableRow,
TableToolbar,
TableToolbarContent,
type DataTableRow,
TableToolbarSearch,
TableSelectRow,
Tile,
type DataTableHeader,
type DataTableRow,
Button,
} from '@carbon/react';
import { isDesktop, showModal, useConfig, useDebounce, useLayoutType } from '@openmrs/esm-framework';
import { type LineItem, type MappedBill } from '../types';
import styles from './invoice-table.scss';
import { convertToCurrency } from '../helpers';
import { Edit } from '@carbon/react/icons';
import { Button } from '@carbon/react';

type InvoiceTableProps = {
bill: MappedBill;
Expand All @@ -39,12 +36,17 @@ const InvoiceTable: React.FC<InvoiceTableProps> = ({ bill, isSelectable = true,
const lineItems = bill?.lineItems ?? [];
const layout = useLayoutType();
const responsiveSize = isDesktop(layout) ? 'sm' : 'lg';
const pendingLineItems = lineItems?.filter((item) => item.paymentStatus === 'PENDING') ?? [];
const [selectedLineItems, setSelectedLineItems] = useState(pendingLineItems ?? []);
const [selectedLineItems, setSelectedLineItems] = useState<LineItem[]>([]);
const [searchTerm, setSearchTerm] = useState('');
const debouncedSearchTerm = useDebounce(searchTerm);
const { defaultCurrency, showEditBillButton } = useConfig();

useEffect(() => {
if (onSelectItem) {
onSelectItem(selectedLineItems);
}
}, [selectedLineItems, onSelectItem]);

const filteredLineItems = useMemo(() => {
if (!debouncedSearchTerm) {
return lineItems;
Expand All @@ -60,7 +62,7 @@ const InvoiceTable: React.FC<InvoiceTableProps> = ({ bill, isSelectable = true,
: lineItems;
}, [debouncedSearchTerm, lineItems]);

const tableHeaders: Array<typeof DataTableHeader> = [
const tableHeaders = [
{ header: 'No', key: 'no', width: 7 }, // Width as a percentage
{ header: 'Bill item', key: 'billItem', width: 25 },
{ header: 'Bill code', key: 'billCode', width: 20 },
Expand All @@ -71,7 +73,7 @@ const InvoiceTable: React.FC<InvoiceTableProps> = ({ bill, isSelectable = true,
{ header: t('actions', 'Actions'), key: 'actionButton' },
];

const handleSelectBillItem = (row) => {
const handleSelectBillItem = (row: LineItem) => {
const dispose = showModal('edit-bill-line-item-dialog', {
bill,
item: row,
Expand All @@ -82,36 +84,36 @@ const InvoiceTable: React.FC<InvoiceTableProps> = ({ bill, isSelectable = true,
const tableRows: Array<typeof DataTableRow> = useMemo(
() =>
filteredLineItems?.map((item, index) => {
const itemTotal = item.price * item.quantity;
const itemStatus = item.paymentStatus === 'PAID' || bill.tenderedAmount >= itemTotal ? 'PAID' : 'PENDING';
return {
no: `${index + 1}`,
id: `${item.uuid}`,
billItem: item.billableService ? item.billableService : item?.item,
billCode: bill?.receiptNumber,
status: item?.paymentStatus,
status: itemStatus,
quantity: item.quantity,
price: convertToCurrency(item.price, defaultCurrency),
total: convertToCurrency(item.price * item.quantity, defaultCurrency),
actionButton: {
content: (
<span>
{showEditBillButton ? (
<Button
renderIcon={Edit}
hasIconOnly
kind="ghost"
iconDescription={t('editThisBillItem', 'Edit this bill item')}
tooltipPosition="left"
onClick={() => handleSelectBillItem(item)}
/>
) : (
'--'
)}
</span>
),
},
total: convertToCurrency(itemTotal, defaultCurrency),
actionButton: (
<span>
{showEditBillButton ? (
<Button
renderIcon={Edit}
hasIconOnly
kind="ghost"
iconDescription={t('editThisBillItem', 'Edit this bill item')}
tooltipPosition="left"
onClick={() => handleSelectBillItem(item)}
/>
) : (
'--'
)}
</span>
),
};
}) ?? [],
[bill?.receiptNumber, filteredLineItems],
[bill?.receiptNumber, filteredLineItems, defaultCurrency, showEditBillButton, t],
);

if (isLoadingBill) {
Expand All @@ -138,7 +140,6 @@ const InvoiceTable: React.FC<InvoiceTableProps> = ({ bill, isSelectable = true,
newSelectedLineItems = selectedLineItems.filter((item) => item.uuid !== row.id);
}
setSelectedLineItems(newSelectedLineItems);
onSelectItem(newSelectedLineItems);
};

return (
Expand Down Expand Up @@ -172,7 +173,7 @@ const InvoiceTable: React.FC<InvoiceTableProps> = ({ bill, isSelectable = true,
</TableRow>
</TableHead>
<TableBody>
{rows.map((row, index) => (
{rows.map((row) => (
<TableRow
key={row.id}
{...getRowProps({
Expand All @@ -187,7 +188,7 @@ const InvoiceTable: React.FC<InvoiceTableProps> = ({ bill, isSelectable = true,
/>
)}
{row.cells.map((cell) => (
<TableCell key={cell.id}>{cell.value?.content ?? cell.value}</TableCell>
<TableCell key={cell.id}>{cell.value}</TableCell>
))}
</TableRow>
))}
Expand Down
12 changes: 5 additions & 7 deletions src/invoice/invoice.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ const Invoice: React.FC = () => {
const { patient, isLoading: isLoadingPatient } = usePatient(patientUuid);
const { bill, isLoading: isLoadingBill, error, mutate } = useBill(billUuid);
const [isPrinting, setIsPrinting] = useState(false);
const [selectedLineItems, setSelectedLineItems] = useState([]);
const [selectedLineItems, setSelectedLineItems] = useState<LineItem[]>([]);
const componentRef = useRef<HTMLDivElement>(null);
const onBeforeGetContentResolve = useRef<(() => void) | null>(null);
const handleSelectItem = (lineItems: Array<LineItem>) => {
const { defaultCurrency } = useConfig();
const handleSelectItem = (lineItems: LineItem[]) => {
setSelectedLineItems(lineItems);
};
const { defaultCurrency } = useConfig();

const handleAfterPrint = useCallback(() => {
onBeforeGetContentResolve.current = null;
Expand All @@ -52,9 +52,7 @@ const Invoice: React.FC = () => {

const handlePrint = useReactToPrint({
content: reactToPrintContent,
documentTitle: `Invoice ${bill?.receiptNumber} - ${patient?.name?.[0]?.given?.join(' ')} ${
patient?.name?.[0].family
}`,
documentTitle: `Invoice ${bill?.receiptNumber} - ${patient?.name?.[0]?.given?.join(' ')} ${patient?.name?.[0].family}`,
onBeforeGetContent: handleOnBeforeGetContent,
onAfterPrint: handleAfterPrint,
removeAfterPrint: true,
Expand Down Expand Up @@ -118,7 +116,7 @@ const Invoice: React.FC = () => {
size="md">
{t('printBill', 'Print bill')}
</Button>
{bill?.status === 'PAID' ? <PrintReceipt billId={bill?.id} /> : null}
{(bill?.status === 'PAID' || bill?.tenderedAmount > 0) && <PrintReceipt billId={bill?.id} />}
</div>
</div>

Expand Down
31 changes: 25 additions & 6 deletions src/invoice/payments/payment-form/payment-form.component.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useState } from 'react';
import React, { useCallback, useState, useEffect } from 'react';
import { Controller, useFieldArray, useFormContext } from 'react-hook-form';
import { useTranslation } from 'react-i18next';
import { TrashCan, Add } from '@carbon/react/icons';
Expand All @@ -8,19 +8,38 @@ import { type PaymentFormValue } from '../payments.component';
import { usePaymentModes } from '../payment.resource';
import styles from './payment-form.scss';

type PaymentFormProps = { disablePayment: boolean; amountDue: number };
type PaymentFormProps = {
disablePayment: boolean;
clientBalance: number;
isSingleLineItemSelected: boolean;
isSingleLineItem: boolean;
};

const DEFAULT_PAYMENT = { method: '', amount: 0, referenceCode: '' };

const PaymentForm: React.FC<PaymentFormProps> = ({ disablePayment, amountDue }) => {
const PaymentForm: React.FC<PaymentFormProps> = ({
disablePayment,
clientBalance,
isSingleLineItemSelected,
isSingleLineItem,
}) => {
const { t } = useTranslation();
const {
control,
formState: { errors },
} = useFormContext<PaymentFormValue>();
const { paymentModes, isLoading, error } = usePaymentModes();
const { fields, remove, append } = useFieldArray({ name: 'payment', control: control });
const [isFormVisible, setIsFormVisible] = useState(false);
const [isFormVisible, setIsFormVisible] = useState(isSingleLineItem);

useEffect(() => {
if (isSingleLineItem) {
setIsFormVisible(true);
if (fields.length === 0) {
append(DEFAULT_PAYMENT);
}
}
}, [isSingleLineItem, append, fields.length]);

const handleAppendPaymentMode = useCallback(() => {
setIsFormVisible(true);
Expand Down Expand Up @@ -90,12 +109,12 @@ const PaymentForm: React.FC<PaymentFormProps> = ({ disablePayment, amountDue })
)}
/>
<div className={styles.removeButtonContainer}>
<TrashCan onClick={handleRemovePaymentMode} className={styles.removeButton} size={20} />
<TrashCan onClick={() => handleRemovePaymentMode(index)} className={styles.removeButton} size={20} />
</div>
</div>
))}
<Button
disabled={disablePayment}
disabled={disablePayment || (!isSingleLineItem && !isSingleLineItemSelected)}
size="md"
onClick={handleAppendPaymentMode}
className={styles.paymentButtons}
Expand Down
Loading

0 comments on commit 3cb8c55

Please sign in to comment.