const ManageShiftClosing = (props) => { const {useMemo} = React; // Destructuring ReactBootstrap components and props const { Row, Col, Table, Card } = ReactBootstrap; // Assuming ReactBootstrap is passed via props or available in context const { userInfo, config, shift, handleClose } = props; // State management const [loading, setLoading] = useState(false); const [transactions, setTransactions] = useState(null); const [staffName, setStaffName] = useState(userInfo?.name); const [note, setNote] = useState(''); const inputCodeRef = useRef(null); // --- BILINGUAL LABELS --- const isVi = config?.lang === 'vi'; const LABELS = { title: isVi ? 'Xác Nhận Kết Ca' : 'Shift Closing Confirmation', staffName: isVi ? 'Tên Nhân Viên (*)' : 'Staff Name (*)', note: isVi ? 'Ghi Chú' : 'Note', reload: isVi ? 'Tải Lại' : 'Reload', confirm: isVi ? 'Xác Nhận Kết Ca' : 'Confirm Shift Close', close: isVi ? 'Đóng' : 'Close', dailyTotal: isVi ? 'TỔNG CỘNG TRONG NGÀY' : 'DAILY TOTAL', shiftSubtotal: isVi ? 'TỔNG CA ID' : 'SHIFT ID SUB-TOTAL', shiftId: isVi ? 'Mã Ca' : 'Shift ID', tenderCode: isVi ? 'Mã Tender' : 'Tender Code', tenderDesc: isVi ? 'Loại Thanh Toán' : 'Tender Type', transCount: isVi ? 'SL Bill' : 'Trans Count', totalAmount: isVi ? 'Tổng Số Tiền' : 'Total Amount', noTransactions: isVi ? 'Không tìm thấy giao dịch nào.' : 'No transactions found.', confirmAlert: isVi ? "Bạn có chắc muốn kết ca không?" : "Are you sure you want to close this shift?", closedBy: isVi ? 'Người Kết Ca' : 'Closed By', statusShift: isVi ? 'Đang chờ xác nhận' : 'Pending Confirmation', branchInfo: isVi ? 'Cửa hàng' : 'Store', }; // --- UTILITIES --- const formatCurrency = (amount) => { // Use 'vi-VN' locale for Vietnamese currency display return new Intl.NumberFormat('vi-VN').format(amount || 0); }; // --- DATA TRANSFORMATION (Use useMemo for performance) --- const { subtotals, groupedTransactions, dailyTotalAmt, dailyTotalCount } = useMemo(() => { if (!transactions || !transactions.data) { return { subtotals: {}, groupedTransactions: {}, dailyTotalAmt: 0, dailyTotalCount: 0 }; } const grouped = {}; const subs = {}; let dailyTotalAmt = 0; let dailyTotalCount = 0; transactions.data.forEach(trans => { const key = trans.shift_id; // Group transactions by shift_id if (!grouped[key]) { grouped[key] = []; } grouped[key].push(trans); // Calculate subtotals if (!subs[key]) { subs[key] = { total_cnt: 0, total_amt: 0 }; } subs[key].total_cnt += trans.trans_cnt; subs[key].total_amt += trans.total_amt; // Calculate daily totals dailyTotalAmt += trans.total_amt; dailyTotalCount += trans.trans_cnt; }); // Ensure keys are sorted for consistent display (optional but recommended) const sortedShiftIds = Object.keys(subs).sort((a, b) => a - b); const sortedSubtotals = {}; const sortedGroupedTransactions = {}; sortedShiftIds.forEach(id => { sortedSubtotals[id] = subs[id]; sortedGroupedTransactions[id] = grouped[id]; }); return { subtotals: sortedSubtotals, groupedTransactions: sortedGroupedTransactions, dailyTotalAmt, dailyTotalCount }; }, [transactions]); // --- API CALLS --- const handleReloadSalesByShift = async () => { try { setLoading(true); const url = `/api/get-pos-transaction-by-shift?shift_id=${shift?.id}`; const resultObj = await commonApi.APIGETByURL(url, config); if (resultObj.status === 200) { setTransactions(resultObj.data); } else { // Use custom modal/toast instead of alert() console.error(resultObj?.data?.message || 'No transactions found for this shift'); setTransactions({ data: [] }); } } catch (e) { console.log("ERROR get-pos-transaction-by-shift", e); setTransactions({ data: [] }); } finally { setLoading(false); if (inputCodeRef.current) { inputCodeRef.current.focus(); inputCodeRef.current.select(); } } }; const handleFinishShift = async () => { const sw = typeof Swal !== 'undefined' ? Swal : (window.Swal || null); let userConfirmed = false; if (sw) { const { isConfirmed } = await sw.fire({ title: isVi ? "Kết thúc ca?" : "Close Shift?", text: LABELS.confirmAlert, icon: "question", showCancelButton: true, confirmButtonColor: "#7c3aed", cancelButtonColor: "#64748b", confirmButtonText: isVi ? "Xác nhận" : "Confirm", cancelButtonText: isVi ? "Hủy" : "Cancel" }); userConfirmed = isConfirmed; } else { userConfirmed = window.confirm(LABELS.confirmAlert); } if (!userConfirmed) { return; } if (transactions?.data?.find(obj=>obj.shift_id===shift?.id)?.length===0){ if (sw) { sw.fire({ icon: 'warning', title: isVi ? "Không có giao dịch nào để kết ca!" : "No transactions to close shift!", confirmButtonColor: '#7c3aed' }); } else { alert(isVi ? "Không có giao dịch nào để kết ca!" : "No transactions to close shift!"); } return; } try { setLoading(true); const data = { "branch_no": 0, // Assuming this is correct "is_open": false, "staff_name": staffName, // Add required staff name "note": note, // Add note // Optional: Pass shift summary data if required by API }; const url = `/api/create-or-update-mdc-store-shifts`; const resultObj = await commonApi.APIPOSTByURL(url, data, config); if (resultObj.status === 201) { props.setShift(null); // Assuming setShift is passed via props handleClose(); // Close the modal/component window.location.reload(); // Reload the page to reflect changes } else { console.error("Failed to close shift:", resultObj); } } catch (e) { console.log("ERROR create-or-update-mdc-store-shifts", e); } finally { setLoading(false); } }; // --- LIFECYCLE --- useEffect(() => { handleReloadSalesByShift(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // --- RENDER LOGIC --- // Check if data is available and ready for display if (!transactions) { return ; } if (transactions?.data?.length === 0) { return
{LABELS.noTransactions}
; } return (
{transactions?.data?.find(obj=>obj.shift_id===shift?.id)?.length>0 ?

{LABELS.title} : {transactions?.data?.find(obj=>obj.shift_id===shift?.id)?.shift_name} ( {LABELS.branchInfo}: { userInfo?.branch_no})

:

{LABELS.noTransactions} ( {LABELS.branchInfo}: { userInfo?.branch_no})

} {/* SECTION 1: INPUTS AND ACTIONS */} setStaffName(e.target.value)} type='text' size="sm" autoFocus={true} inputRef={inputCodeRef} tabIndex={1} /> setNote(e.target.value)} type='text' size="sm" tabIndex={2} /> {LABELS.reload}} onClick={handleReloadSalesByShift} variant='outline-primary' type='button' tabIndex={3} style={{ width: '100%' }} /> {/* SECTION 2: DAILY TOTAL SUMMARY (No Table used, prominent display) */}
{LABELS.dailyTotal}
{LABELS.transCount}
{dailyTotalCount}
{LABELS.totalAmount}
{formatCurrency(dailyTotalAmt)}
{/* SECTION 3: DETAILED SHIFT BREAKDOWN (Grouped Tables) */}
{Object.entries(groupedTransactions).map(([shiftId, shiftTransactions]) => ( {/* Subtotal Header */} {LABELS.shiftSubtotal}: {shiftTransactions[0]?.shift_name} {formatCurrency(subtotals[shiftId].total_amt)} {/* Transaction Details Table */} {shiftTransactions?.map((transaction, index) => ( ))} {shiftTransactions[0]?.staff_name ? : }
{LABELS.tenderCode} {LABELS.tenderDesc} {LABELS.transCount} {LABELS.totalAmount}
{transaction.tender_code} {transaction.tender_desc} {transaction.trans_cnt} {formatCurrency(transaction.total_amt)}
{LABELS.shiftSubtotal} {shiftTransactions[0]?.shift_name} ( {LABELS.closedBy} : { shiftTransactions[0]?.staff_name}) {LABELS.shiftSubtotal} {shiftTransactions[0]?.shift_name} ({LABELS.statusShift}) {subtotals[shiftId].total_cnt} {formatCurrency(subtotals[shiftId].total_amt)}
))}
{/* SECTION 4: FOOTER ACTIONS */} {LABELS.close}} onClick={handleClose} variant='secondary' type='button' tabIndex={11} /> {transactions?.data?.find(obj=>obj.shift_id===shift?.id)?.length >0 && {LABELS.confirm}} onClick={handleFinishShift} variant='danger' type='button' disabled={staffName.trim() === ''} // Disable if staff name is empty tabIndex={10} /> }
); };