import React, { useEffect, useState } from "react"; import ListAltOutlinedIcon from "@mui/icons-material/ListAltOutlined"; import Checkbox from "@mui/material/Checkbox"; import IconButton from "@mui/material/IconButton"; import Input from "@mui/material/Input"; import Table from "@mui/material/Table"; import TableBody from "@mui/material/TableBody"; import TableRow from "@mui/material/TableRow"; import Typography from "@mui/material/Typography"; import { TableCell } from "../../../components/Table/TableCell"; import TableHead from "../../../components/Table/TableHead"; import TableHeading from "../../../components/Table/TableHeading"; import { useDialog } from "../../../contexts/DialogContext"; import { useI18n } from "../../../contexts/I18nContext"; import { Adjustment, ItemProperties, Line } from "../types/purchase"; export const HIDDEN_ITEM_TYPES = ["SHIPPING", "PICKUP"]; export interface ReceiptTableProps { currency: string; lines: Line[]; editable?: boolean; onSelect?: (selected: Line[]) => void; } export const ReceiptTable: React.FC = ({ lines, currency, editable, onSelect, }) => { const [selected, setSelected] = useState([]); const { t } = useI18n(); const openDialog = useDialog(); const refundableLines = lines.filter((line) => Boolean(line.adjustments.reduce((t, v) => t + v.quantity, line.quantity)), ); const sortedLines = lines.sort((a, b) => a.line_number - b.line_number); // Group lines by their whole number part, sorted by their decimal part const groupedLines = sortedLines.reduce((lines, line) => { const lineNumber = Math.floor(line.line_number); lines[lineNumber] ??= []; lines[lineNumber].push(line); return lines; }, []); const toggleSelectAll = (_: React.ChangeEvent, checked: boolean) => { setSelected(checked ? refundableLines : []); }; const toggleLine = (item: Line, checked: boolean) => { const index = selected.map(({ line_number }) => line_number).indexOf(item.line_number); if (checked && index === -1) { setSelected([...selected, item]); } else { const unselected = [...selected]; unselected.splice(index, 1); setSelected(unselected); } }; const lineQuantityChange = (item: Line) => { const index = selected.map(({ line_number }) => line_number).indexOf(item.line_number); const changed = [...selected]; changed[index] = item; setSelected(changed); }; useEffect(() => { if (onSelect != null) onSelect(selected); }, [onSelect, selected]); const showItemProperties = async (title: string, itemProperties: ItemProperties) => { await openDialog( title, {Object.entries(itemProperties ?? {}).map(([key, value]) => ( {key.toUpperCase()} {`${value}`} ))}
, { ok: false, cancel: "Close", }, ); }; return ( {editable && ( 0 && selected.length < refundableLines.length} onChange={toggleSelectAll} /> )} {t("Item")} {t("Reference")} {["Quantity", "Unit Price", "Total", "Debit"].map((v, i) => ( {v} ))} {groupedLines.flatMap((lines) => lines.flatMap((line, index) => { const isSelected = selected .map(({ line_number }) => line_number) .includes(line.line_number); const currentQuantity = line.adjustments.reduce( (t, v) => t + v.quantity, line.quantity, ); const firstLine = index === 0; const subLine = !firstLine; const finalLine = index === lines.length - 1; const borderBottom = { borderBottomStyle: !finalLine ? "dotted" : undefined, borderBottomWidth: !finalLine ? 2 : undefined, } as const; const disabled = currentQuantity === 0; const firstRow = ( {editable ? ( {disabled ? null : ( toggleLine({ ...line, quantity: currentQuantity }, checked) } /> )} ) : null} {line.title} {line.item_properties && ( showItemProperties(line.title, line.item_properties as ItemProperties) } > )} {["SHIPPING", "PICKUP"].includes(line.item_type) ? null : line.reference} {line.quantity} {line.unit_price} {currency} {line.total_amount} {currency} {line.total_amount} {currency} ); const adjustmentsRows = line.adjustments.map((adjustment, i) => { const lastRow = !editable && i == line.adjustments.length - 1; const typeNameMap: Record = { CANCELLATION: "Cancellation", RETURN: "Return", REFUND: "Refund", DISCOUNT: "Discount", }; const withTitle = (name: string, title: string) => { if (title) { return `${typeNameMap[name]}: ${title}`; } else { return typeNameMap[name]; } }; const pending = adjustment.receipt_number === null; return ( {editable && ( )} {withTitle(adjustment.adjustment_type, adjustment.title)} {adjustment.quantity} {adjustment.total_amount} {currency} {Boolean(lastRow && line.remaining_amount != line.total_amount) && `${line?.remaining_amount} ${currency}`} ); }); const rows = [firstRow, ...adjustmentsRows]; if (editable) { rows.push( {!disabled && ( lineQuantityChange({ ...line, quantity: Number.parseInt(event.target.value) * -1, }) } /> )} , ); } return rows; }), )}
); };