@argusoft/medplat-product-management 1.0.7 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/{BrandsPage-CdqGFmGf.js → BrandsPage-DmRW5bhm.js} +77 -78
  2. package/dist/{BrandsPage-CdqGFmGf.js.map → BrandsPage-DmRW5bhm.js.map} +1 -1
  3. package/dist/{CategoriesPage-DJM0Nalw.js → CategoriesPage-BsS5IQh3.js} +6 -7
  4. package/dist/{CategoriesPage-DJM0Nalw.js.map → CategoriesPage-BsS5IQh3.js.map} +1 -1
  5. package/dist/{DashboardPage-BASkXr00.js → DashboardPage-C3bKc5na.js} +3 -3
  6. package/dist/{DashboardPage-BASkXr00.js.map → DashboardPage-C3bKc5na.js.map} +1 -1
  7. package/dist/{FacilityPicker-jV-qXp1k.js → FacilityPicker-BiZeupmP.js} +6 -8
  8. package/dist/{FacilityPicker-jV-qXp1k.js.map → FacilityPicker-BiZeupmP.js.map} +1 -1
  9. package/dist/{InventoryPage-CTdq6txa.js → InventoryPage-C_AxSy7A.js} +9 -12
  10. package/dist/{InventoryPage-CTdq6txa.js.map → InventoryPage-C_AxSy7A.js.map} +1 -1
  11. package/dist/{MemberProfileCard-DwWda-tS.js → MemberProfileCard-BdUNgHRB.js} +3 -3
  12. package/dist/{MemberProfileCard-DwWda-tS.js.map → MemberProfileCard-BdUNgHRB.js.map} +1 -1
  13. package/dist/{PaymentCreatePage-B3bP-K01.js → PaymentCreatePage-CIVe0P0p.js} +114 -114
  14. package/dist/{PaymentCreatePage-B3bP-K01.js.map → PaymentCreatePage-CIVe0P0p.js.map} +1 -1
  15. package/dist/{PaymentsPage-Dh8bqXVE.js → PaymentsPage-BvPe5Q9F.js} +4 -4
  16. package/dist/{PaymentsPage-Dh8bqXVE.js.map → PaymentsPage-BvPe5Q9F.js.map} +1 -1
  17. package/dist/{PickupBatchLinesEditor-B2fLx1lU.js → PickupBatchLinesEditor-DHmcAG23.js} +2 -2
  18. package/dist/{PickupBatchLinesEditor-B2fLx1lU.js.map → PickupBatchLinesEditor-DHmcAG23.js.map} +1 -1
  19. package/dist/{PickupCreatePage-BeYhR45k.js → PickupCreatePage-CB0Sl0Hb.js} +58 -58
  20. package/dist/PickupCreatePage-CB0Sl0Hb.js.map +1 -0
  21. package/dist/{PickupsPage-C6lBtAoQ.js → PickupsPage-Ctpghavs.js} +7 -9
  22. package/dist/{PickupsPage-C6lBtAoQ.js.map → PickupsPage-Ctpghavs.js.map} +1 -1
  23. package/dist/{PmGuard-DrIl1sHL.js → PmGuard-b10TGXEi.js} +3 -3
  24. package/dist/{PmGuard-DrIl1sHL.js.map → PmGuard-b10TGXEi.js.map} +1 -1
  25. package/dist/{PmTable-BSV_bMJZ.js → PmTable-_GbScaa4.js} +3 -4
  26. package/dist/{PmTable-BSV_bMJZ.js.map → PmTable-_GbScaa4.js.map} +1 -1
  27. package/dist/{ProductEditPage-DZTUH95T.js → ProductEditPage-C1thoKHu.js} +8 -9
  28. package/dist/{ProductEditPage-DZTUH95T.js.map → ProductEditPage-C1thoKHu.js.map} +1 -1
  29. package/dist/{ProductsPage-CqOsah4_.js → ProductsPage-CupVmOD4.js} +4 -4
  30. package/dist/{ProductsPage-CqOsah4_.js.map → ProductsPage-CupVmOD4.js.map} +1 -1
  31. package/dist/{PurchaseCreatePage-D6os7srp.js → PurchaseCreatePage-YD3NmhPQ.js} +6 -6
  32. package/dist/{PurchaseCreatePage-D6os7srp.js.map → PurchaseCreatePage-YD3NmhPQ.js.map} +1 -1
  33. package/dist/{PurchaseRequestDetailPage-DErqGKiq.js → PurchaseRequestDetailPage-Dg_MRY_N.js} +6 -7
  34. package/dist/{PurchaseRequestDetailPage-DErqGKiq.js.map → PurchaseRequestDetailPage-Dg_MRY_N.js.map} +1 -1
  35. package/dist/{PurchaseRequestsPage-CHBoRzzH.js → PurchaseRequestsPage-DPAPzpmm.js} +4 -4
  36. package/dist/{PurchaseRequestsPage-CHBoRzzH.js.map → PurchaseRequestsPage-DPAPzpmm.js.map} +1 -1
  37. package/dist/{PurchasesPage-C-2K7wH6.js → PurchasesPage-It1GHiXl.js} +4 -4
  38. package/dist/{PurchasesPage-C-2K7wH6.js.map → PurchasesPage-It1GHiXl.js.map} +1 -1
  39. package/dist/{SaleCreatePage-DB3_UEgy.js → SaleCreatePage-C9kFmTvm.js} +20 -20
  40. package/dist/{SaleCreatePage-DB3_UEgy.js.map → SaleCreatePage-C9kFmTvm.js.map} +1 -1
  41. package/dist/{SalesPage-BhBGG426.js → SalesPage-D18DCseD.js} +74 -74
  42. package/dist/{SalesPage-BhBGG426.js.map → SalesPage-D18DCseD.js.map} +1 -1
  43. package/dist/{SettingsPage-CBUu9DZK.js → SettingsPage-VsxI-ano.js} +4 -4
  44. package/dist/{SettingsPage-CBUu9DZK.js.map → SettingsPage-VsxI-ano.js.map} +1 -1
  45. package/dist/{StorageUnitsPage-oe0lXLd1.js → StorageUnitsPage-7EqwuMOI.js} +7 -8
  46. package/dist/{StorageUnitsPage-oe0lXLd1.js.map → StorageUnitsPage-7EqwuMOI.js.map} +1 -1
  47. package/dist/{TransactionsPage-7dRZpZOD.js → TransactionsPage-DrH53pVS.js} +4 -4
  48. package/dist/{TransactionsPage-7dRZpZOD.js.map → TransactionsPage-DrH53pVS.js.map} +1 -1
  49. package/dist/{TransferCreatePage-DtkAlP9l.js → TransferCreatePage-CuvoMrYH.js} +4 -4
  50. package/dist/{TransferCreatePage-DtkAlP9l.js.map → TransferCreatePage-CuvoMrYH.js.map} +1 -1
  51. package/dist/{TransfersPage-BaEjbvnj.js → TransfersPage-Cf701t8s.js} +4 -4
  52. package/dist/{TransfersPage-BaEjbvnj.js.map → TransfersPage-Cf701t8s.js.map} +1 -1
  53. package/dist/{VialsPage-vo9Of9oC.js → VialsPage-8oAc1yFv.js} +5 -5
  54. package/dist/{VialsPage-vo9Of9oC.js.map → VialsPage-8oAc1yFv.js.map} +1 -1
  55. package/dist/constants-ClZJY2x1.js.map +1 -1
  56. package/dist/format-UOyOu75i.js.map +1 -1
  57. package/dist/index.js +253 -240
  58. package/dist/index.js.map +1 -1
  59. package/dist/{settingsStore-BlA2GIhl.js → settingsStore-BifOsjlB.js} +2 -2
  60. package/dist/{settingsStore-BlA2GIhl.js.map → settingsStore-BifOsjlB.js.map} +1 -1
  61. package/dist/{validation-B6Kl5Xf9.js → validation-BzlHnL-r.js} +16 -15
  62. package/dist/{validation-B6Kl5Xf9.js.map → validation-BzlHnL-r.js.map} +1 -1
  63. package/package.json +1 -1
  64. package/dist/PickupCreatePage-BeYhR45k.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"PaymentCreatePage-B3bP-K01.js","names":[],"sources":["../src/views/PaymentCreatePage.jsx"],"sourcesContent":["import { useMemo, useState } from \"react\";\nimport { useNavigate, useParams } from \"react-router-dom\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport {\n Alert,\n Box,\n Button,\n Card,\n CardContent,\n Chip,\n Divider,\n InputAdornment,\n LinearProgress,\n Stack,\n Table,\n TableBody,\n TableCell,\n TableContainer,\n TableHead,\n TableRow,\n TextField,\n Typography,\n} from \"@mui/material\";\nimport SaveRoundedIcon from \"@mui/icons-material/SaveRounded\";\nimport { showToast } from '@pm/utils/pmToast';\nimport PmPageShell from \"@pm/components/PmPageShell\";\nimport PmNav from \"@pm/components/PmNav\";\nimport PmGuard from \"@pm/components/PmGuard\";\nimport { usePermissionedEffect, usePmPermissions } from \"@pm/utils/permissions\";\nimport {\n createPayment,\n getMemberDuesDetails,\n getMemberOutstandingDues,\n} from \"@pm/services/pmApi\";\nimport MemberProfileCard from \"@pm/components/MemberProfileCard\";\nimport { PmSelect } from \"@pm/components/PmTable\";\nimport { PAYMENT_MODES } from \"@pm/utils/constants\";\nimport { currencySymbol } from \"@pm/utils/currency\";\nimport { usePmSettings } from \"@pm/utils/settingsStore\";\nimport { formatDate, formatNumber } from \"@pm/utils/format\";\nimport {\n isClean,\n validatePastOrTodayDate,\n validatePositiveNumber,\n} from \"@pm/utils/validation\";\nimport { useFieldErrors } from \"@pm/utils/useFieldErrors\";\n\nfunction daysSince(value) {\n if (!value) return null;\n const ms = new Date(value).getTime();\n if (Number.isNaN(ms)) return null;\n const diff = Date.now() - ms;\n return Math.max(0, Math.floor(diff / (24 * 3600 * 1000)));\n}\n\nexport default function PaymentCreatePage() {\n const { memberId } = useParams();\n const navigate = useNavigate();\n const settings = usePmSettings();\n const cur = currencySymbol(settings?.currencyCode);\n const perms = usePmPermissions();\n // Dues breakdown drives both the panel and the collect form's totalDue.\n // Without the dues permission we can't fetch it, so the page surfaces a\n // hard-stop alert and disables Confirm Collection.\n const canSeeDues = perms.has(\"view.manage.productManagement.dues\");\n const [error, setError] = useState(\"\");\n const [memberName, setMemberName] = useState(\"\");\n const [previousDue, setPreviousDue] = useState(0);\n const [duesDetails, setDuesDetails] = useState(null);\n const [detailsLoading, setDetailsLoading] = useState(false);\n const fieldErrors = useFieldErrors();\n const today = new Date().toISOString().substring(0, 10);\n const [form, setForm] = useState({\n id: uuidv4(),\n paymentDate: today,\n paymentMode: \"CASH\",\n collectingNow: \"\",\n notes: \"\",\n });\n\n async function loadMemberDues() {\n if (!memberId) {\n setDuesDetails(null);\n setDetailsLoading(false);\n setPreviousDue(0);\n return;\n }\n if (!canSeeDues) {\n // No dues access — leave panels empty. The hard-stop alert below\n // tells the operator to ask for the perm.\n setDuesDetails(null);\n setPreviousDue(0);\n setDetailsLoading(false);\n return;\n }\n setDetailsLoading(true);\n try {\n const [details, dues] = await Promise.all([\n getMemberDuesDetails(memberId).catch(() => null),\n getMemberOutstandingDues().catch(() => []),\n ]);\n setDuesDetails(details);\n const match = (dues ?? []).find((d) => d.memberId === memberId);\n setPreviousDue(\n match ? Number(match.totalDue) : Number(details?.totalDue ?? 0),\n );\n } catch (err) {\n showToast({\n message:\n err?.response?.data?.message ??\n err?.message ??\n \"Failed to load member dues\",\n type: \"error\",\n });\n } finally {\n setDetailsLoading(false);\n }\n }\n\n usePermissionedEffect(\n \"update.manage.productManagement.payment\",\n () => {\n void loadMemberDues();\n setForm((f) => ({ ...f, collectingNow: \"\" }));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n },\n [memberId],\n );\n\n // -------- Money math --------\n const totalDue = Number(duesDetails?.totalDue ?? 0);\n const collectedRaw = Number(form.collectingNow || 0);\n const collected = Math.min(Math.max(collectedRaw, 0), totalDue);\n const remainingAfter = Math.max(totalDue - collected, 0);\n\n const oldestDueDays = daysSince(duesDetails?.oldestDueDate);\n const lastSaleDays = daysSince(duesDetails?.lastSaleDate);\n\n // Collection only makes sense when there's an outstanding balance — once\n // it's zero the collect form is hidden entirely (a \"Nothing to collect\"\n // alert is shown instead) and the Save button stays disabled.\n const canCollect = !!memberId && totalDue > 0 && canSeeDues;\n\n // -------- Validation --------\n const formErrors = useMemo(() => {\n const errs = {\n member: memberId ? \"\" : \"No member selected\",\n paymentDate: validatePastOrTodayDate(form.paymentDate, {\n required: true,\n label: \"Payment date\",\n }),\n collectingNow: validatePositiveNumber(form.collectingNow, \"Amount\", {\n required: true,\n }),\n };\n if (\n !errs.collectingNow &&\n totalDue > 0 &&\n Number(form.collectingNow) > totalDue\n ) {\n errs.collectingNow = `Cannot collect more than the outstanding due (${formatNumber(totalDue)}).`;\n }\n return errs;\n }, [memberId, form.paymentDate, form.collectingNow, totalDue]);\n const formIsValid = canCollect && isClean(formErrors);\n\n async function save() {\n if (!formIsValid) {\n fieldErrors.markAllTouched();\n setError(\"Please fix the highlighted fields.\");\n return;\n }\n try {\n await createPayment({\n id: form.id,\n memberId,\n amount: Number(collected.toFixed(2)),\n paymentDate: form.paymentDate,\n paymentMode: form.paymentMode || null,\n notes: form.notes || null,\n allocations: null,\n });\n showToast({\n message: memberName\n ? `Payment recorded for ${memberName}. Applied to their oldest sales first.`\n : \"Payment recorded. Applied to the oldest sales first.\",\n type: \"success\",\n });\n navigate(\"/ui/medplat/manage/pm/payments\");\n } catch (err) {\n const message =\n err?.response?.data?.message ??\n err?.message ??\n \"Failed to record payment\";\n setError(message);\n showToast({ message, type: \"error\" });\n }\n }\n\n return (\n <Box>\n <PmNav />\n <PmGuard\n perm={\"update.manage.productManagement.payment\"}\n title=\"You don’t have permission to collect payments\"\n >\n <PmPageShell\n title=\"Collect Payment\"\n subtitle=\"Collect payment for what a customer owes. Payments are matched to sales in order received.\"\n actions={\n <Stack direction=\"row\" spacing={1}>\n <Button\n variant=\"outlined\"\n onClick={() => navigate(\"/ui/medplat/manage/pm/payments\")}\n >\n Cancel\n </Button>\n <Button\n variant=\"contained\"\n startIcon={<SaveRoundedIcon />}\n disabled={!formIsValid}\n onClick={() => void save()}\n >\n Confirm Collection\n </Button>\n </Stack>\n }\n >\n {error ? (\n <Alert severity=\"error\" sx={{ mb: 2 }}>\n {error}\n </Alert>\n ) : null}\n\n {!canSeeDues ? (\n <Alert severity=\"warning\" sx={{ mb: 2 }}>\n You don’t have access to view outstanding dues, so this collection\n flow can’t determine how much is owed. Ask an admin to grant the\n dues permission to collect payments here.\n </Alert>\n ) : null}\n\n {/* ---------- Member profile (from URL) ---------- */}\n <Card sx={{ borderRadius: 1.5, mb: 2 }}>\n <CardContent>\n <Typography variant=\"h6\" sx={{ fontWeight: 800, mb: 2 }}>\n Customer\n </Typography>\n {memberId ? (\n <MemberProfileCard\n memberId={memberId}\n previousDue={previousDue}\n currencySymbol={cur}\n onLoad={(p) => setMemberName(p?.name ?? \"\")}\n />\n ) : (\n <Alert severity=\"warning\">No member selected</Alert>\n )}\n </CardContent>\n </Card>\n\n {/* ---------- Dues + collect (only when a member is selected) ---------- */}\n {memberId ? (\n <>\n <Card sx={{ borderRadius: 1.5, mb: 2 }}>\n <CardContent>\n {detailsLoading ? <LinearProgress sx={{ mb: 2 }} /> : null}\n <Grid3MetricStrip\n total={totalDue}\n oldestDueDays={oldestDueDays}\n oldestDueDate={duesDetails?.oldestDueDate}\n lastSaleDays={lastSaleDays}\n lastSaleDate={duesDetails?.lastSaleDate}\n currency={cur}\n />\n </CardContent>\n </Card>\n\n <Card sx={{ borderRadius: 1.5, mb: 2 }}>\n <CardContent>\n <Stack\n direction=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"center\"\n sx={{ mb: 2 }}\n >\n <Typography variant=\"h6\" sx={{ fontWeight: 800 }}>\n Due Breakdown\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {(duesDetails?.openSales ?? []).length}{\" \"}\n {(duesDetails?.openSales ?? []).length === 1\n ? \"open sale\"\n : \"open sales\"}{\" \"}\n · oldest first\n </Typography>\n </Stack>\n <Divider sx={{ mb: 1 }} />\n {totalDue <= 0 ? (\n <Alert severity=\"success\" sx={{ mt: 1 }}>\n No outstanding dues for this member — nothing to collect.\n </Alert>\n ) : (\n <TableContainer>\n <Table size=\"small\">\n <TableHead>\n <TableRow>\n <TableCell sx={{ fontWeight: 800 }}>\n Sale Date\n </TableCell>\n <TableCell sx={{ fontWeight: 800 }}>\n Items\n </TableCell>\n <TableCell sx={{ fontWeight: 800 }} align=\"right\">\n Sale\n </TableCell>\n <TableCell sx={{ fontWeight: 800 }} align=\"right\">\n Paid\n </TableCell>\n <TableCell sx={{ fontWeight: 800 }} align=\"right\">\n Due\n </TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {(duesDetails?.openSales ?? []).map((sale) => (\n <TableRow key={sale.id} hover>\n <TableCell>\n <Stack\n direction=\"row\"\n spacing={1}\n alignItems=\"baseline\"\n >\n <Typography variant=\"body2\">\n {formatDate(sale.saleDate)}\n </Typography>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n >\n ({daysSince(sale.saleDate)}d ago)\n </Typography>\n </Stack>\n </TableCell>\n <TableCell>\n <Stack\n direction=\"row\"\n spacing={0.5}\n flexWrap=\"wrap\"\n >\n {(sale.items ?? []).map((it) => (\n <Chip\n key={it.id}\n size=\"small\"\n variant=\"outlined\"\n label={`${it.productName} × ${it.quantity}`}\n sx={{ mr: 0.5, mb: 0.5 }}\n />\n ))}\n </Stack>\n </TableCell>\n <TableCell\n align=\"right\"\n sx={{ fontVariantNumeric: \"tabular-nums\" }}\n >\n {cur}\n {formatNumber(sale.totalAmount)}\n </TableCell>\n <TableCell\n align=\"right\"\n sx={{\n fontVariantNumeric: \"tabular-nums\",\n color: \"text.secondary\",\n }}\n >\n {cur}\n {formatNumber(sale.paidAmount)}\n </TableCell>\n <TableCell\n align=\"right\"\n sx={{\n fontVariantNumeric: \"tabular-nums\",\n fontWeight: 700,\n color: \"warning.dark\",\n }}\n >\n {cur}\n {formatNumber(sale.dueAmount)}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </TableContainer>\n )}\n </CardContent>\n </Card>\n\n {/* ---------- Collection footer — only when there's something to collect ---------- */}\n {canCollect ? (\n <Card sx={{ borderRadius: 1.5, bgcolor: \"grey.50\", mb: 3 }}>\n <CardContent>\n <Stack direction={{ xs: \"column\", md: \"row\" }} spacing={2}>\n <TextField\n required\n size=\"small\"\n type=\"date\"\n label=\"Payment Date\"\n sx={{ flex: 1 }}\n InputLabelProps={{ shrink: true }}\n value={form.paymentDate}\n onChange={(e) =>\n setForm({ ...form, paymentDate: e.target.value })\n }\n onBlur={fieldErrors.onBlur(\"paymentDate\")}\n error={\n fieldErrors.show(\"paymentDate\") &&\n !!formErrors.paymentDate\n }\n helperText={\n fieldErrors.show(\"paymentDate\")\n ? formErrors.paymentDate\n : \"\"\n }\n />\n <PmSelect\n label=\"Payment Mode\"\n value={form.paymentMode}\n onChange={(v) => setForm({ ...form, paymentMode: v })}\n options={PAYMENT_MODES}\n sx={{ flex: 1 }}\n />\n <TextField\n size=\"small\"\n label=\"Notes\"\n sx={{ flex: 2 }}\n value={form.notes}\n onChange={(e) =>\n setForm({ ...form, notes: e.target.value })\n }\n />\n </Stack>\n\n <Divider sx={{ my: 2 }} />\n\n <Stack spacing={1.25}>\n <Stack\n direction=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"baseline\"\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n Total Due\n </Typography>\n <Typography\n variant=\"h5\"\n sx={{\n fontWeight: 800,\n fontVariantNumeric: \"tabular-nums\",\n color:\n totalDue > 0 ? \"warning.dark\" : \"text.primary\",\n }}\n >\n {cur}\n {formatNumber(totalDue)}\n </Typography>\n </Stack>\n\n <Stack\n direction=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"center\"\n spacing={2}\n >\n <Typography\n variant=\"body2\"\n color=\"text.secondary\"\n sx={{ flexShrink: 0 }}\n >\n Amount Collecting Now\n </Typography>\n <TextField\n required\n size=\"small\"\n type=\"number\"\n inputProps={{\n step: \"0.01\",\n min: 0,\n max: totalDue,\n style: { textAlign: \"right\", fontWeight: 700 },\n }}\n InputProps={{\n startAdornment: (\n <InputAdornment position=\"start\">\n {cur}\n </InputAdornment>\n ),\n }}\n sx={{ width: 220 }}\n placeholder=\"0.00\"\n value={form.collectingNow}\n onChange={(e) =>\n setForm({ ...form, collectingNow: e.target.value })\n }\n onBlur={fieldErrors.onBlur(\"collectingNow\")}\n error={\n fieldErrors.show(\"collectingNow\") &&\n !!formErrors.collectingNow\n }\n helperText={\n fieldErrors.show(\"collectingNow\")\n ? formErrors.collectingNow\n : \"Partial amounts accepted\"\n }\n />\n </Stack>\n\n <Divider sx={{ my: 0.5 }} />\n\n <Stack\n direction=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"baseline\"\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n Remaining Due After\n </Typography>\n <Typography\n variant=\"h5\"\n sx={{\n fontWeight: 800,\n fontVariantNumeric: \"tabular-nums\",\n color:\n remainingAfter > 0\n ? \"warning.dark\"\n : \"success.dark\",\n }}\n >\n {cur}\n {formatNumber(remainingAfter)}\n </Typography>\n </Stack>\n </Stack>\n </CardContent>\n </Card>\n ) : null}\n </>\n ) : null}\n </PmPageShell>\n </PmGuard>\n </Box>\n );\n}\n\n// Compact three-metric strip used inside the member dues panel.\nfunction Grid3MetricStrip({\n total,\n oldestDueDays,\n oldestDueDate,\n lastSaleDays,\n lastSaleDate,\n currency = \"₹\",\n}) {\n const cell = (label, value, sub, color) => (\n <Box\n sx={{\n flex: 1,\n p: 1.5,\n borderRadius: 2,\n bgcolor: \"background.paper\",\n border: 1,\n borderColor: \"divider\",\n textAlign: \"left\",\n }}\n >\n <Typography variant=\"caption\" color=\"text.secondary\">\n {label}\n </Typography>\n <Typography\n variant=\"h6\"\n sx={{ fontWeight: 800, color, fontVariantNumeric: \"tabular-nums\" }}\n >\n {value}\n </Typography>\n {sub ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {sub}\n </Typography>\n ) : null}\n </Box>\n );\n return (\n <Stack direction={{ xs: \"column\", md: \"row\" }} spacing={1.5}>\n {cell(\n \"Total Due\",\n `${currency}${formatNumber(total)}`,\n null,\n total > 0 ? \"warning.dark\" : \"text.primary\",\n )}\n {cell(\n \"Last Sale\",\n lastSaleDays == null\n ? \"—\"\n : `${lastSaleDays} day${lastSaleDays === 1 ? \"\" : \"s\"} ago`,\n lastSaleDate ? formatDate(lastSaleDate) : \"No prior sale\",\n \"text.primary\",\n )}\n {cell(\n \"Due Since\",\n oldestDueDays == null\n ? \"—\"\n : `${oldestDueDays} day${oldestDueDays === 1 ? \"\" : \"s\"}`,\n oldestDueDate ? formatDate(oldestDueDate) : \"No open sales\",\n oldestDueDays != null && oldestDueDays >= 30\n ? \"error.dark\"\n : \"text.primary\",\n )}\n </Stack>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"PaymentCreatePage-CIVe0P0p.js","names":[],"sources":["../src/views/PaymentCreatePage.jsx"],"sourcesContent":["import { useMemo, useState } from \"react\";\nimport { useNavigate, useParams } from \"react-router-dom\";\nimport { v4 as uuidv4 } from \"uuid\";\nimport {\n Alert,\n Box,\n Button,\n Card,\n CardContent,\n Chip,\n Divider,\n InputAdornment,\n LinearProgress,\n Stack,\n Table,\n TableBody,\n TableCell,\n TableContainer,\n TableHead,\n TableRow,\n TextField,\n Typography,\n} from \"@mui/material\";\nimport SaveRoundedIcon from \"@mui/icons-material/SaveRounded\";\nimport { showToast } from '@pm/utils/pmToast';\nimport PmPageShell from \"@pm/components/PmPageShell\";\nimport PmNav from \"@pm/components/PmNav\";\nimport PmGuard from \"@pm/components/PmGuard\";\nimport { usePermissionedEffect, usePmPermissions } from \"@pm/utils/permissions\";\nimport {\n createPayment,\n getMemberDuesDetails,\n getMemberOutstandingDues,\n} from \"@pm/services/pmApi\";\nimport MemberProfileCard from \"@pm/components/MemberProfileCard\";\nimport { PmSelect } from \"@pm/components/PmTable\";\nimport { PAYMENT_MODES } from \"@pm/utils/constants\";\nimport { currencySymbol } from \"@pm/utils/currency\";\nimport { usePmSettings } from \"@pm/utils/settingsStore\";\nimport { formatDate, formatNumber } from \"@pm/utils/format\";\nimport {\n isClean,\n validatePastOrTodayDate,\n validatePositiveNumber,\n} from \"@pm/utils/validation\";\nimport { useFieldErrors } from \"@pm/utils/useFieldErrors\";\n\nfunction daysSince(value) {\n if (!value) return null;\n const ms = new Date(value).getTime();\n if (Number.isNaN(ms)) return null;\n const diff = Date.now() - ms;\n return Math.max(0, Math.floor(diff / (24 * 3600 * 1000)));\n}\n\nexport default function PaymentCreatePage() {\n const { memberId } = useParams();\n const navigate = useNavigate();\n const settings = usePmSettings();\n const cur = currencySymbol(settings?.currencyCode);\n const perms = usePmPermissions();\n // Dues breakdown drives both the panel and the collect form's totalDue.\n // Without the dues permission we can't fetch it, so the page surfaces a\n // hard-stop alert and disables Confirm Collection.\n const canSeeDues = perms.has(\"view.manage.productManagement.dues\");\n const [error, setError] = useState(\"\");\n const [memberName, setMemberName] = useState(\"\");\n const [previousDue, setPreviousDue] = useState(0);\n const [duesDetails, setDuesDetails] = useState(null);\n const [detailsLoading, setDetailsLoading] = useState(false);\n const fieldErrors = useFieldErrors();\n const today = new Date().toISOString().substring(0, 10);\n const [form, setForm] = useState({\n id: uuidv4(),\n paymentDate: today,\n paymentMode: \"CASH\",\n collectingNow: \"\",\n notes: \"\",\n });\n\n async function loadMemberDues() {\n if (!memberId) {\n setDuesDetails(null);\n setDetailsLoading(false);\n setPreviousDue(0);\n return;\n }\n if (!canSeeDues) {\n // No dues access — leave panels empty. The hard-stop alert below\n // tells the operator to ask for the perm.\n setDuesDetails(null);\n setPreviousDue(0);\n setDetailsLoading(false);\n return;\n }\n setDetailsLoading(true);\n try {\n const [details, dues] = await Promise.all([\n getMemberDuesDetails(memberId).catch(() => null),\n getMemberOutstandingDues().catch(() => []),\n ]);\n setDuesDetails(details);\n const match = (dues ?? []).find((d) => d.memberId === memberId);\n setPreviousDue(\n match ? Number(match.totalDue) : Number(details?.totalDue ?? 0),\n );\n } catch (err) {\n showToast({\n message:\n err?.response?.data?.message ??\n err?.message ??\n \"Failed to load member dues\",\n type: \"error\",\n });\n } finally {\n setDetailsLoading(false);\n }\n }\n\n usePermissionedEffect(\n \"update.manage.productManagement.payment\",\n () => {\n void loadMemberDues();\n setForm((f) => ({ ...f, collectingNow: \"\" }));\n // eslint-disable-next-line react-hooks/exhaustive-deps\n },\n [memberId],\n );\n\n // -------- Money math --------\n const totalDue = Number(duesDetails?.totalDue ?? 0);\n const collectedRaw = Number(form.collectingNow || 0);\n const collected = Math.min(Math.max(collectedRaw, 0), totalDue);\n const remainingAfter = Math.max(totalDue - collected, 0);\n\n const oldestDueDays = daysSince(duesDetails?.oldestDueDate);\n const lastSaleDays = daysSince(duesDetails?.lastSaleDate);\n\n // Collection only makes sense when there's an outstanding balance — once\n // it's zero the collect form is hidden entirely (a \"Nothing to collect\"\n // alert is shown instead) and the Save button stays disabled.\n const canCollect = !!memberId && totalDue > 0 && canSeeDues;\n\n // -------- Validation --------\n const formErrors = useMemo(() => {\n const errs = {\n member: memberId ? \"\" : \"No member selected\",\n paymentDate: validatePastOrTodayDate(form.paymentDate, {\n required: true,\n label: \"Payment date\",\n }),\n collectingNow: validatePositiveNumber(form.collectingNow, \"Amount\", {\n required: true,\n }),\n };\n if (\n !errs.collectingNow &&\n totalDue > 0 &&\n Number(form.collectingNow) > totalDue\n ) {\n errs.collectingNow = `Cannot collect more than the outstanding due (${formatNumber(totalDue)}).`;\n }\n return errs;\n }, [memberId, form.paymentDate, form.collectingNow, totalDue]);\n const formIsValid = canCollect && isClean(formErrors);\n\n async function save() {\n if (!formIsValid) {\n fieldErrors.markAllTouched();\n setError(\"Please fix the highlighted fields.\");\n return;\n }\n try {\n await createPayment({\n id: form.id,\n memberId,\n amount: Number(collected.toFixed(2)),\n paymentDate: form.paymentDate,\n paymentMode: form.paymentMode || null,\n notes: form.notes || null,\n allocations: null,\n });\n showToast({\n message: memberName\n ? `Payment recorded for ${memberName}. Applied to their oldest sales first.`\n : \"Payment recorded. Applied to the oldest sales first.\",\n type: \"success\",\n });\n navigate(\"/ui/medplat/manage/pm/payments\");\n } catch (err) {\n const message =\n err?.response?.data?.message ??\n err?.message ??\n \"Failed to record payment\";\n setError(message);\n showToast({ message, type: \"error\" });\n }\n }\n\n return (\n <Box>\n <PmNav />\n <PmGuard\n perm={\"update.manage.productManagement.payment\"}\n title=\"You don’t have permission to collect payments\"\n >\n <PmPageShell\n title=\"Collect Payment\"\n subtitle=\"Collect payment for what a customer owes. Payments are matched to sales in order received.\"\n actions={\n <Stack direction=\"row\" spacing={1}>\n <Button\n variant=\"outlined\"\n onClick={() => navigate(\"/ui/medplat/manage/pm/payments\")}\n >\n Cancel\n </Button>\n <Button\n variant=\"contained\"\n startIcon={<SaveRoundedIcon />}\n disabled={!formIsValid}\n onClick={() => void save()}\n >\n Confirm Collection\n </Button>\n </Stack>\n }\n >\n {error ? (\n <Alert severity=\"error\" sx={{ mb: 2 }}>\n {error}\n </Alert>\n ) : null}\n\n {!canSeeDues ? (\n <Alert severity=\"warning\" sx={{ mb: 2 }}>\n You don’t have access to view outstanding dues, so this collection\n flow can’t determine how much is owed. Ask an admin to grant the\n dues permission to collect payments here.\n </Alert>\n ) : null}\n\n {/* ---------- Member profile (from URL) ---------- */}\n <Card sx={{ borderRadius: 1.5, mb: 2 }}>\n <CardContent>\n <Typography variant=\"h6\" sx={{ fontWeight: 800, mb: 2 }}>\n Customer\n </Typography>\n {memberId ? (\n <MemberProfileCard\n memberId={memberId}\n previousDue={previousDue}\n currencySymbol={cur}\n onLoad={(p) => setMemberName(p?.name ?? \"\")}\n />\n ) : (\n <Alert severity=\"warning\">No member selected</Alert>\n )}\n </CardContent>\n </Card>\n\n {/* ---------- Dues + collect (only when a member is selected) ---------- */}\n {memberId ? (\n <>\n <Card sx={{ borderRadius: 1.5, mb: 2 }}>\n <CardContent>\n {detailsLoading ? <LinearProgress sx={{ mb: 2 }} /> : null}\n <Grid3MetricStrip\n total={totalDue}\n oldestDueDays={oldestDueDays}\n oldestDueDate={duesDetails?.oldestDueDate}\n lastSaleDays={lastSaleDays}\n lastSaleDate={duesDetails?.lastSaleDate}\n currency={cur}\n />\n </CardContent>\n </Card>\n\n <Card sx={{ borderRadius: 1.5, mb: 2 }}>\n <CardContent>\n <Stack\n direction=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"center\"\n sx={{ mb: 2 }}\n >\n <Typography variant=\"h6\" sx={{ fontWeight: 800 }}>\n Due Breakdown\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {(duesDetails?.openSales ?? []).length}{\" \"}\n {(duesDetails?.openSales ?? []).length === 1\n ? \"open sale\"\n : \"open sales\"}{\" \"}\n · oldest first\n </Typography>\n </Stack>\n <Divider sx={{ mb: 1 }} />\n {totalDue <= 0 ? (\n <Alert severity=\"success\" sx={{ mt: 1 }}>\n No outstanding dues for this member — nothing to collect.\n </Alert>\n ) : (\n <TableContainer>\n <Table size=\"small\">\n <TableHead>\n <TableRow>\n <TableCell sx={{ fontWeight: 800 }}>\n Sale Date\n </TableCell>\n <TableCell sx={{ fontWeight: 800 }}>\n Items\n </TableCell>\n <TableCell sx={{ fontWeight: 800 }} align=\"right\">\n Sale\n </TableCell>\n <TableCell sx={{ fontWeight: 800 }} align=\"right\">\n Paid\n </TableCell>\n <TableCell sx={{ fontWeight: 800 }} align=\"right\">\n Due\n </TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {(duesDetails?.openSales ?? []).map((sale) => (\n <TableRow key={sale.id} hover>\n <TableCell>\n <Stack\n direction=\"row\"\n spacing={1}\n alignItems=\"baseline\"\n >\n <Typography variant=\"body2\">\n {formatDate(sale.saleDate)}\n </Typography>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n >\n ({daysSince(sale.saleDate)}d ago)\n </Typography>\n </Stack>\n </TableCell>\n <TableCell>\n <Stack\n direction=\"row\"\n spacing={0.5}\n flexWrap=\"wrap\"\n >\n {(sale.items ?? []).map((it) => (\n <Chip\n key={it.id}\n size=\"small\"\n variant=\"outlined\"\n label={`${it.productName} × ${it.quantity}`}\n sx={{ mr: 0.5, mb: 0.5 }}\n />\n ))}\n </Stack>\n </TableCell>\n <TableCell\n align=\"right\"\n sx={{ fontVariantNumeric: \"tabular-nums\" }}\n >\n {cur}\n {formatNumber(sale.totalAmount)}\n </TableCell>\n <TableCell\n align=\"right\"\n sx={{\n fontVariantNumeric: \"tabular-nums\",\n color: \"text.secondary\",\n }}\n >\n {cur}\n {formatNumber(sale.paidAmount)}\n </TableCell>\n <TableCell\n align=\"right\"\n sx={{\n fontVariantNumeric: \"tabular-nums\",\n fontWeight: 700,\n color: \"warning.dark\",\n }}\n >\n {cur}\n {formatNumber(sale.dueAmount)}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </TableContainer>\n )}\n </CardContent>\n </Card>\n\n {/* ---------- Collection footer — only when there's something to collect ---------- */}\n {canCollect ? (\n <Card sx={{ borderRadius: 1.5, bgcolor: \"grey.50\", mb: 3 }}>\n <CardContent>\n <Stack direction={{ xs: \"column\", md: \"row\" }} spacing={2}>\n <TextField\n required\n size=\"small\"\n type=\"date\"\n label=\"Payment Date\"\n sx={{ flex: 1 }}\n InputLabelProps={{ shrink: true }}\n value={form.paymentDate}\n onChange={(e) =>\n setForm({ ...form, paymentDate: e.target.value })\n }\n onBlur={fieldErrors.onBlur(\"paymentDate\")}\n error={\n fieldErrors.show(\"paymentDate\") &&\n !!formErrors.paymentDate\n }\n helperText={\n fieldErrors.show(\"paymentDate\")\n ? formErrors.paymentDate\n : \"\"\n }\n />\n <PmSelect\n label=\"Payment Mode\"\n value={form.paymentMode}\n onChange={(v) => setForm({ ...form, paymentMode: v })}\n options={PAYMENT_MODES}\n sx={{ flex: 1 }}\n />\n <TextField\n size=\"small\"\n label=\"Notes\"\n sx={{ flex: 2 }}\n value={form.notes}\n onChange={(e) =>\n setForm({ ...form, notes: e.target.value })\n }\n />\n </Stack>\n\n <Divider sx={{ my: 2 }} />\n\n <Stack spacing={1.25}>\n <Stack\n direction=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"baseline\"\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n Total Due\n </Typography>\n <Typography\n variant=\"h5\"\n sx={{\n fontWeight: 800,\n fontVariantNumeric: \"tabular-nums\",\n color:\n totalDue > 0 ? \"warning.dark\" : \"text.primary\",\n }}\n >\n {cur}\n {formatNumber(totalDue)}\n </Typography>\n </Stack>\n\n <Stack\n direction=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"center\"\n spacing={2}\n >\n <Typography\n variant=\"body2\"\n color=\"text.secondary\"\n sx={{ flexShrink: 0 }}\n >\n Amount Collecting Now\n </Typography>\n <TextField\n required\n size=\"small\"\n type=\"number\"\n inputProps={{\n step: \"0.01\",\n min: 0,\n max: totalDue,\n style: { textAlign: \"right\", fontWeight: 700 },\n }}\n InputProps={{\n startAdornment: (\n <InputAdornment position=\"start\">\n {cur}\n </InputAdornment>\n ),\n }}\n sx={{ width: 220 }}\n placeholder=\"0.00\"\n value={form.collectingNow}\n onChange={(e) =>\n setForm({ ...form, collectingNow: e.target.value })\n }\n onBlur={fieldErrors.onBlur(\"collectingNow\")}\n error={\n fieldErrors.show(\"collectingNow\") &&\n !!formErrors.collectingNow\n }\n helperText={\n fieldErrors.show(\"collectingNow\")\n ? formErrors.collectingNow\n : \"Partial amounts accepted\"\n }\n />\n </Stack>\n\n <Divider sx={{ my: 0.5 }} />\n\n <Stack\n direction=\"row\"\n justifyContent=\"space-between\"\n alignItems=\"baseline\"\n >\n <Typography variant=\"body2\" color=\"text.secondary\">\n Remaining Due After\n </Typography>\n <Typography\n variant=\"h5\"\n sx={{\n fontWeight: 800,\n fontVariantNumeric: \"tabular-nums\",\n color:\n remainingAfter > 0\n ? \"warning.dark\"\n : \"success.dark\",\n }}\n >\n {cur}\n {formatNumber(remainingAfter)}\n </Typography>\n </Stack>\n </Stack>\n </CardContent>\n </Card>\n ) : null}\n </>\n ) : null}\n </PmPageShell>\n </PmGuard>\n </Box>\n );\n}\n\n// Compact three-metric strip used inside the member dues panel.\nfunction Grid3MetricStrip({\n total,\n oldestDueDays,\n oldestDueDate,\n lastSaleDays,\n lastSaleDate,\n currency = \"₹\",\n}) {\n const cell = (label, value, sub, color) => (\n <Box\n sx={{\n flex: 1,\n p: 1.5,\n borderRadius: 2,\n bgcolor: \"background.paper\",\n border: 1,\n borderColor: \"divider\",\n textAlign: \"left\",\n }}\n >\n <Typography variant=\"caption\" color=\"text.secondary\">\n {label}\n </Typography>\n <Typography\n variant=\"h6\"\n sx={{ fontWeight: 800, color, fontVariantNumeric: \"tabular-nums\" }}\n >\n {value}\n </Typography>\n {sub ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {sub}\n </Typography>\n ) : null}\n </Box>\n );\n return (\n <Stack direction={{ xs: \"column\", md: \"row\" }} spacing={1.5}>\n {cell(\n \"Total Due\",\n `${currency}${formatNumber(total)}`,\n null,\n total > 0 ? \"warning.dark\" : \"text.primary\",\n )}\n {cell(\n \"Last Sale\",\n lastSaleDays == null\n ? \"—\"\n : `${lastSaleDays} day${lastSaleDays === 1 ? \"\" : \"s\"} ago`,\n lastSaleDate ? formatDate(lastSaleDate) : \"No prior sale\",\n \"text.primary\",\n )}\n {cell(\n \"Due Since\",\n oldestDueDays == null\n ? \"—\"\n : `${oldestDueDays} day${oldestDueDays === 1 ? \"\" : \"s\"}`,\n oldestDueDate ? formatDate(oldestDueDate) : \"No open sales\",\n oldestDueDays != null && oldestDueDays >= 30\n ? \"error.dark\"\n : \"text.primary\",\n )}\n </Stack>\n );\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
- import { C as e, R as t } from "./settingsStore-BlA2GIhl.js";
2
- import { a as n, c as r, i, l as a, s as o, t as s } from "./PmTable-BSV_bMJZ.js";
1
+ import { C as e, R as t } from "./settingsStore-BifOsjlB.js";
2
+ import { a as n, c as r, i, l as a, s as o, t as s } from "./PmTable-_GbScaa4.js";
3
3
  import { t as c } from "./format-UOyOu75i.js";
4
- import { a as l, n as u, r as d, t as f } from "./PmGuard-DrIl1sHL.js";
4
+ import { a as l, n as u, r as d, t as f } from "./PmGuard-b10TGXEi.js";
5
5
  import { useState as p } from "react";
6
6
  import { jsx as m, jsxs as h } from "react/jsx-runtime";
7
7
  import { Alert as g, Box as _, Button as v, Chip as y, Skeleton as b, Stack as x, TableBody as S, TableCell as C, TableHead as w, TableRow as T, Typography as E } from "@mui/material";
@@ -154,4 +154,4 @@ function A() {
154
154
  //#endregion
155
155
  export { A as default };
156
156
 
157
- //# sourceMappingURL=PaymentsPage-Dh8bqXVE.js.map
157
+ //# sourceMappingURL=PaymentsPage-BvPe5Q9F.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PaymentsPage-Dh8bqXVE.js","names":[],"sources":["../src/views/PaymentsPage.jsx"],"sourcesContent":["import { useState } from \"react\";\nimport { useNavigate } from \"react-router-dom\";\nimport {\n Alert,\n Box,\n Button,\n Chip,\n Skeleton,\n Stack,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n Typography,\n} from \"@mui/material\";\nimport PaymentsRoundedIcon from \"@mui/icons-material/PaymentsRounded\";\nimport AddRoundedIcon from \"@mui/icons-material/AddRounded\";\nimport RefreshRoundedIcon from \"@mui/icons-material/RefreshRounded\";\nimport { showToast } from '@pm/utils/pmToast';\nimport PmPageShell from \"@pm/components/PmPageShell\";\nimport PmNav from \"@pm/components/PmNav\";\nimport PmGuard from \"@pm/components/PmGuard\";\nimport { usePermissionedEffect } from \"@pm/utils/permissions\";\nimport {\n PmEmptyRow,\n PmMoney,\n PmRef,\n PmTable,\n PmTableCard,\n} from \"@pm/components/PmTable\";\nimport { getMembersByIds, listPayments } from \"@pm/services/pmApi\";\nimport { formatDate } from \"@pm/utils/format\";\n\nexport default function PaymentsPage() {\n const navigate = useNavigate();\n const [payments, setPayments] = useState([]);\n // Map of memberId -> display name, hydrated for memberIds present on the\n // loaded payments. Keeps the recent-payments table from showing raw UUIDs\n // without forcing a full member list load.\n const [memberNames, setMemberNames] = useState({});\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState(\"\");\n\n async function load() {\n setLoading(true);\n setError(\"\");\n try {\n const list = await listPayments(0, 50);\n setPayments(list);\n const ids = Array.from(\n new Set(list.map((p) => p.memberId).filter(Boolean)),\n );\n if (ids.length === 0) {\n setMemberNames({});\n } else {\n try {\n const refs = await getMembersByIds(ids);\n const map = {};\n refs.forEach((r) => {\n map[r.id] = r.name;\n });\n setMemberNames(map);\n } catch {\n setMemberNames({});\n }\n }\n } catch (err) {\n const message =\n err?.response?.data?.message ?? err?.message ?? \"Failed to load\";\n setError(message);\n showToast({ message, type: \"error\" });\n } finally {\n setLoading(false);\n }\n }\n\n usePermissionedEffect(\n \"view.manage.productManagement.payment\",\n () => {\n void load();\n },\n [],\n );\n\n return (\n <Box>\n <PmNav />\n <PmGuard perm={\"view.manage.productManagement.payment\"}>\n <PmPageShell\n title=\"Debt Payments\"\n subtitle=\"Payments collected from customers. Matched to their sales in order.\"\n actions={\n <Stack direction=\"row\" spacing={1}>\n <Button\n variant=\"outlined\"\n startIcon={<RefreshRoundedIcon />}\n onClick={() => void load()}\n >\n Refresh\n </Button>\n {/* DEMO-ONLY: in production a payment is started by passing the\n member id via the URL (/payments/new/:memberId) from an outside\n flow. Unhide this button to launch the create page directly. */}\n {false && (\n <Button\n variant=\"contained\"\n startIcon={<AddRoundedIcon />}\n onClick={() => navigate(\"/ui/medplat/manage/pm/payments/new\")}\n >\n New Payment\n </Button>\n )}\n </Stack>\n }\n >\n {error ? (\n <Alert severity=\"error\" sx={{ mb: 2 }}>\n {error}\n </Alert>\n ) : null}\n\n <PmTableCard\n eyebrow=\"History\"\n title=\"Recent Payments\"\n subtitle={\n loading\n ? \"Loading…\"\n : `${payments.length} ${payments.length === 1 ? \"payment\" : \"payments\"} recorded`\n }\n >\n <PmTable dense>\n <TableHead>\n <TableRow>\n <TableCell>Ref</TableCell>\n <TableCell>Date</TableCell>\n <TableCell>Member</TableCell>\n <TableCell>Mode</TableCell>\n <TableCell align=\"right\">Amount</TableCell>\n <TableCell align=\"right\">Allocations</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {loading ? (\n Array.from({ length: 4 }).map((_, i) => (\n <TableRow key={i}>\n {Array.from({ length: 6 }).map((__, j) => (\n <TableCell key={j}>\n <Skeleton height={22} />\n </TableCell>\n ))}\n </TableRow>\n ))\n ) : payments.length === 0 ? (\n <PmEmptyRow\n colSpan={6}\n icon={PaymentsRoundedIcon}\n title=\"No payments yet\"\n hint=\"Payments appear here with how many sales they're applied to.\"\n />\n ) : (\n payments.map((p) => {\n const memberName = memberNames[p.memberId];\n return (\n <TableRow key={p.id} hover>\n <TableCell>\n <PmRef id={p.serialId} />\n </TableCell>\n <TableCell>\n <Typography variant=\"body2\" sx={{ fontWeight: 700 }}>\n {formatDate(p.paymentDate)}\n </Typography>\n </TableCell>\n <TableCell>\n {memberName ? (\n <Typography\n variant=\"body2\"\n sx={{ fontWeight: 700 }}\n >\n {memberName}\n </Typography>\n ) : (\n <Typography\n variant=\"caption\"\n sx={{\n fontFamily: \"monospace\",\n color: \"text.secondary\",\n }}\n >\n {p.memberId?.slice(0, 8)}…\n </Typography>\n )}\n </TableCell>\n <TableCell>\n {p.paymentMode ? (\n <Chip\n size=\"small\"\n label={p.paymentMode}\n sx={{\n fontWeight: 700,\n borderRadius: 1.5,\n height: 22,\n }}\n />\n ) : (\n <Typography variant=\"caption\" color=\"text.disabled\">\n —\n </Typography>\n )}\n </TableCell>\n <TableCell align=\"right\">\n <PmMoney value={p.amount} tone=\"success\" />\n </TableCell>\n <TableCell align=\"right\">\n <Box\n component=\"span\"\n sx={{\n display: \"inline-flex\",\n px: 1,\n py: 0.2,\n borderRadius: 1.5,\n bgcolor: \"grey.100\",\n fontWeight: 800,\n fontVariantNumeric: \"tabular-nums\",\n color: \"text.secondary\",\n }}\n >\n {(p.allocations ?? []).length}\n </Box>\n </TableCell>\n </TableRow>\n );\n })\n )}\n </TableBody>\n </PmTable>\n </PmTableCard>\n </PmPageShell>\n </PmGuard>\n </Box>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"PaymentsPage-BvPe5Q9F.js","names":[],"sources":["../src/views/PaymentsPage.jsx"],"sourcesContent":["import { useState } from \"react\";\nimport { useNavigate } from \"react-router-dom\";\nimport {\n Alert,\n Box,\n Button,\n Chip,\n Skeleton,\n Stack,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n Typography,\n} from \"@mui/material\";\nimport PaymentsRoundedIcon from \"@mui/icons-material/PaymentsRounded\";\nimport AddRoundedIcon from \"@mui/icons-material/AddRounded\";\nimport RefreshRoundedIcon from \"@mui/icons-material/RefreshRounded\";\nimport { showToast } from '@pm/utils/pmToast';\nimport PmPageShell from \"@pm/components/PmPageShell\";\nimport PmNav from \"@pm/components/PmNav\";\nimport PmGuard from \"@pm/components/PmGuard\";\nimport { usePermissionedEffect } from \"@pm/utils/permissions\";\nimport {\n PmEmptyRow,\n PmMoney,\n PmRef,\n PmTable,\n PmTableCard,\n} from \"@pm/components/PmTable\";\nimport { getMembersByIds, listPayments } from \"@pm/services/pmApi\";\nimport { formatDate } from \"@pm/utils/format\";\n\nexport default function PaymentsPage() {\n const navigate = useNavigate();\n const [payments, setPayments] = useState([]);\n // Map of memberId -> display name, hydrated for memberIds present on the\n // loaded payments. Keeps the recent-payments table from showing raw UUIDs\n // without forcing a full member list load.\n const [memberNames, setMemberNames] = useState({});\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState(\"\");\n\n async function load() {\n setLoading(true);\n setError(\"\");\n try {\n const list = await listPayments(0, 50);\n setPayments(list);\n const ids = Array.from(\n new Set(list.map((p) => p.memberId).filter(Boolean)),\n );\n if (ids.length === 0) {\n setMemberNames({});\n } else {\n try {\n const refs = await getMembersByIds(ids);\n const map = {};\n refs.forEach((r) => {\n map[r.id] = r.name;\n });\n setMemberNames(map);\n } catch {\n setMemberNames({});\n }\n }\n } catch (err) {\n const message =\n err?.response?.data?.message ?? err?.message ?? \"Failed to load\";\n setError(message);\n showToast({ message, type: \"error\" });\n } finally {\n setLoading(false);\n }\n }\n\n usePermissionedEffect(\n \"view.manage.productManagement.payment\",\n () => {\n void load();\n },\n [],\n );\n\n return (\n <Box>\n <PmNav />\n <PmGuard perm={\"view.manage.productManagement.payment\"}>\n <PmPageShell\n title=\"Debt Payments\"\n subtitle=\"Payments collected from customers. Matched to their sales in order.\"\n actions={\n <Stack direction=\"row\" spacing={1}>\n <Button\n variant=\"outlined\"\n startIcon={<RefreshRoundedIcon />}\n onClick={() => void load()}\n >\n Refresh\n </Button>\n {/* DEMO-ONLY: in production a payment is started by passing the\n member id via the URL (/payments/new/:memberId) from an outside\n flow. Unhide this button to launch the create page directly. */}\n {false && (\n <Button\n variant=\"contained\"\n startIcon={<AddRoundedIcon />}\n onClick={() => navigate(\"/ui/medplat/manage/pm/payments/new\")}\n >\n New Payment\n </Button>\n )}\n </Stack>\n }\n >\n {error ? (\n <Alert severity=\"error\" sx={{ mb: 2 }}>\n {error}\n </Alert>\n ) : null}\n\n <PmTableCard\n eyebrow=\"History\"\n title=\"Recent Payments\"\n subtitle={\n loading\n ? \"Loading…\"\n : `${payments.length} ${payments.length === 1 ? \"payment\" : \"payments\"} recorded`\n }\n >\n <PmTable dense>\n <TableHead>\n <TableRow>\n <TableCell>Ref</TableCell>\n <TableCell>Date</TableCell>\n <TableCell>Member</TableCell>\n <TableCell>Mode</TableCell>\n <TableCell align=\"right\">Amount</TableCell>\n <TableCell align=\"right\">Allocations</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {loading ? (\n Array.from({ length: 4 }).map((_, i) => (\n <TableRow key={i}>\n {Array.from({ length: 6 }).map((__, j) => (\n <TableCell key={j}>\n <Skeleton height={22} />\n </TableCell>\n ))}\n </TableRow>\n ))\n ) : payments.length === 0 ? (\n <PmEmptyRow\n colSpan={6}\n icon={PaymentsRoundedIcon}\n title=\"No payments yet\"\n hint=\"Payments appear here with how many sales they're applied to.\"\n />\n ) : (\n payments.map((p) => {\n const memberName = memberNames[p.memberId];\n return (\n <TableRow key={p.id} hover>\n <TableCell>\n <PmRef id={p.serialId} />\n </TableCell>\n <TableCell>\n <Typography variant=\"body2\" sx={{ fontWeight: 700 }}>\n {formatDate(p.paymentDate)}\n </Typography>\n </TableCell>\n <TableCell>\n {memberName ? (\n <Typography\n variant=\"body2\"\n sx={{ fontWeight: 700 }}\n >\n {memberName}\n </Typography>\n ) : (\n <Typography\n variant=\"caption\"\n sx={{\n fontFamily: \"monospace\",\n color: \"text.secondary\",\n }}\n >\n {p.memberId?.slice(0, 8)}…\n </Typography>\n )}\n </TableCell>\n <TableCell>\n {p.paymentMode ? (\n <Chip\n size=\"small\"\n label={p.paymentMode}\n sx={{\n fontWeight: 700,\n borderRadius: 1.5,\n height: 22,\n }}\n />\n ) : (\n <Typography variant=\"caption\" color=\"text.disabled\">\n —\n </Typography>\n )}\n </TableCell>\n <TableCell align=\"right\">\n <PmMoney value={p.amount} tone=\"success\" />\n </TableCell>\n <TableCell align=\"right\">\n <Box\n component=\"span\"\n sx={{\n display: \"inline-flex\",\n px: 1,\n py: 0.2,\n borderRadius: 1.5,\n bgcolor: \"grey.100\",\n fontWeight: 800,\n fontVariantNumeric: \"tabular-nums\",\n color: \"text.secondary\",\n }}\n >\n {(p.allocations ?? []).length}\n </Box>\n </TableCell>\n </TableRow>\n );\n })\n )}\n </TableBody>\n </PmTable>\n </PmTableCard>\n </PmPageShell>\n </PmGuard>\n </Box>\n );\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { o as e } from "./PmTable-BSV_bMJZ.js";
1
+ import { o as e } from "./PmTable-_GbScaa4.js";
2
2
  import { t } from "./format-UOyOu75i.js";
3
3
  import { jsx as n, jsxs as r } from "react/jsx-runtime";
4
4
  import i from "prop-types";
@@ -113,4 +113,4 @@ m.propTypes = {
113
113
  //#endregion
114
114
  export { p as i, f as n, d as r, m as t };
115
115
 
116
- //# sourceMappingURL=PickupBatchLinesEditor-B2fLx1lU.js.map
116
+ //# sourceMappingURL=PickupBatchLinesEditor-DHmcAG23.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PickupBatchLinesEditor-B2fLx1lU.js","names":[],"sources":["../src/components/PickupBatchLinesEditor.jsx"],"sourcesContent":["import PropTypes from 'prop-types';\nimport { Card, Grid, IconButton, Stack, TextField } from '@mui/material';\nimport DeleteOutlineRoundedIcon from '@mui/icons-material/DeleteOutlineRounded';\nimport { PmSelect } from '@pm/components/PmTable';\nimport { formatDate } from '@pm/utils/format';\n\n// A batch is pickable when the facility still physically holds usable stock.\nexport function isPickableBatch(b) {\n return b.ownerType === 'FACILITY'\n && Number(b.qtyRemaining) > 0\n && !['EXPIRED', 'EXHAUSTED', 'QUARANTINED'].includes(b.status);\n}\n\nexport function emptyPickupLine(uuid) {\n // personalBatchId is pre-allocated client-side: the backend mints the batch\n // under this id, so a retry lands on the same batch instead of a second one.\n return { key: uuid(), personalBatchId: uuid(), sourceBatchId: '', pickedQty: 1 };\n}\n\n/**\n * Validates the lines against the batches they draw from. Returns one error\n * object per line, empty when the line is fine, matching the module's\n * \"'' means valid\" convention.\n */\nexport function validatePickupLines(lines, batches) {\n const byId = (id) => batches.find((b) => b.id === id);\n return lines.map((line) => {\n if (!line.sourceBatchId) return { sourceBatchId: 'Pick a batch.' };\n const remaining = Number(byId(line.sourceBatchId)?.qtyRemaining ?? 0);\n const qty = Number(line.pickedQty);\n if (!Number.isInteger(qty) || qty <= 0) return { pickedQty: 'Enter a whole number greater than 0.' };\n if (qty > remaining) return { pickedQty: `Only ${remaining} available in this batch.` };\n return {};\n });\n}\n\n/**\n * The repeatable \"which batches am I taking\" editor, shared by session creation\n * and by topping an open session up, so both get the same picker, the same\n * quantity cap and the same duplicate-batch handling.\n *\n * `excludeBatchIds` hides batches that are spoken for elsewhere — on a top-up\n * that is the batches the session already holds, which are topped up by\n * quantity rather than added again.\n */\nexport default function PickupBatchLinesEditor({\n lines,\n batches,\n errors,\n excludeBatchIds,\n onPatch,\n onRemove,\n allowRemoveLast,\n}) {\n const excluded = excludeBatchIds ?? new Set();\n return (\n <Stack spacing={2}>\n {lines.map((line, idx) => {\n const lerr = errors[idx] || {};\n const b = batches.find((x) => x.id === line.sourceBatchId);\n const remaining = Number(b?.qtyRemaining ?? 0);\n // Hide batches already chosen on another line, and any the caller\n // reserved. The line's own current value always stays selectable.\n const taken = new Set(\n lines.filter((_, i) => i !== idx).map((l) => l.sourceBatchId).filter(Boolean),\n );\n const options = batches\n .filter((eb) => eb.id === line.sourceBatchId || (!taken.has(eb.id) && !excluded.has(eb.id)))\n .map((eb) => ({\n value: eb.id,\n label: `${eb.productName} · qty ${eb.qtyRemaining}`\n + `${eb.lotNumber ? ` · ${eb.lotNumber}` : ''}`\n + `${eb.expiryDate ? ` · exp ${formatDate(eb.expiryDate)}` : ''}`,\n }));\n return (\n <Card key={line.key} variant=\"outlined\" sx={{ p: 2, borderRadius: 1.5 }}>\n <Grid container spacing={2} alignItems=\"flex-start\">\n <Grid item xs={12} md={7}>\n <PmSelect\n label=\"Batch\"\n required\n value={line.sourceBatchId}\n onChange={(v) => onPatch(idx, 'sourceBatchId', v)}\n options={options}\n error={!!lerr.sourceBatchId}\n helperText={lerr.sourceBatchId || ''}\n noOptionsText=\"No pickable stock in this facility\"\n />\n </Grid>\n <Grid item xs={8} md={3}>\n <TextField\n required fullWidth size=\"small\" type=\"number\"\n label=\"Quantity\"\n inputProps={{ min: 1, max: remaining || undefined }}\n value={line.pickedQty}\n onChange={(e) => onPatch(idx, 'pickedQty', e.target.value)}\n error={!!lerr.pickedQty}\n helperText={lerr.pickedQty || (b ? `Out of ${remaining} available` : '')}\n />\n </Grid>\n <Grid item xs={4} md={2} sx={{ textAlign: 'right' }}>\n <IconButton\n color=\"error\"\n onClick={() => onRemove(idx)}\n disabled={!allowRemoveLast && lines.length === 1}\n >\n <DeleteOutlineRoundedIcon />\n </IconButton>\n </Grid>\n </Grid>\n </Card>\n );\n })}\n </Stack>\n );\n}\n\nPickupBatchLinesEditor.propTypes = {\n lines: PropTypes.array.isRequired,\n batches: PropTypes.array.isRequired,\n errors: PropTypes.array.isRequired,\n excludeBatchIds: PropTypes.instanceOf(Set),\n onPatch: PropTypes.func.isRequired,\n onRemove: PropTypes.func.isRequired,\n // Creation always keeps one line; a top-up may legitimately have none.\n allowRemoveLast: PropTypes.bool,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"PickupBatchLinesEditor-DHmcAG23.js","names":[],"sources":["../src/components/PickupBatchLinesEditor.jsx"],"sourcesContent":["import PropTypes from 'prop-types';\nimport { Card, Grid, IconButton, Stack, TextField } from '@mui/material';\nimport DeleteOutlineRoundedIcon from '@mui/icons-material/DeleteOutlineRounded';\nimport { PmSelect } from '@pm/components/PmTable';\nimport { formatDate } from '@pm/utils/format';\n\n// A batch is pickable when the facility still physically holds usable stock.\nexport function isPickableBatch(b) {\n return b.ownerType === 'FACILITY'\n && Number(b.qtyRemaining) > 0\n && !['EXPIRED', 'EXHAUSTED', 'QUARANTINED'].includes(b.status);\n}\n\nexport function emptyPickupLine(uuid) {\n // personalBatchId is pre-allocated client-side: the backend mints the batch\n // under this id, so a retry lands on the same batch instead of a second one.\n return { key: uuid(), personalBatchId: uuid(), sourceBatchId: '', pickedQty: 1 };\n}\n\n/**\n * Validates the lines against the batches they draw from. Returns one error\n * object per line, empty when the line is fine, matching the module's\n * \"'' means valid\" convention.\n */\nexport function validatePickupLines(lines, batches) {\n const byId = (id) => batches.find((b) => b.id === id);\n return lines.map((line) => {\n if (!line.sourceBatchId) return { sourceBatchId: 'Pick a batch.' };\n const remaining = Number(byId(line.sourceBatchId)?.qtyRemaining ?? 0);\n const qty = Number(line.pickedQty);\n if (!Number.isInteger(qty) || qty <= 0) return { pickedQty: 'Enter a whole number greater than 0.' };\n if (qty > remaining) return { pickedQty: `Only ${remaining} available in this batch.` };\n return {};\n });\n}\n\n/**\n * The repeatable \"which batches am I taking\" editor, shared by session creation\n * and by topping an open session up, so both get the same picker, the same\n * quantity cap and the same duplicate-batch handling.\n *\n * `excludeBatchIds` hides batches that are spoken for elsewhere — on a top-up\n * that is the batches the session already holds, which are topped up by\n * quantity rather than added again.\n */\nexport default function PickupBatchLinesEditor({\n lines,\n batches,\n errors,\n excludeBatchIds,\n onPatch,\n onRemove,\n allowRemoveLast,\n}) {\n const excluded = excludeBatchIds ?? new Set();\n return (\n <Stack spacing={2}>\n {lines.map((line, idx) => {\n const lerr = errors[idx] || {};\n const b = batches.find((x) => x.id === line.sourceBatchId);\n const remaining = Number(b?.qtyRemaining ?? 0);\n // Hide batches already chosen on another line, and any the caller\n // reserved. The line's own current value always stays selectable.\n const taken = new Set(\n lines.filter((_, i) => i !== idx).map((l) => l.sourceBatchId).filter(Boolean),\n );\n const options = batches\n .filter((eb) => eb.id === line.sourceBatchId || (!taken.has(eb.id) && !excluded.has(eb.id)))\n .map((eb) => ({\n value: eb.id,\n label: `${eb.productName} · qty ${eb.qtyRemaining}`\n + `${eb.lotNumber ? ` · ${eb.lotNumber}` : ''}`\n + `${eb.expiryDate ? ` · exp ${formatDate(eb.expiryDate)}` : ''}`,\n }));\n return (\n <Card key={line.key} variant=\"outlined\" sx={{ p: 2, borderRadius: 1.5 }}>\n <Grid container spacing={2} alignItems=\"flex-start\">\n <Grid item xs={12} md={7}>\n <PmSelect\n label=\"Batch\"\n required\n value={line.sourceBatchId}\n onChange={(v) => onPatch(idx, 'sourceBatchId', v)}\n options={options}\n error={!!lerr.sourceBatchId}\n helperText={lerr.sourceBatchId || ''}\n noOptionsText=\"No pickable stock in this facility\"\n />\n </Grid>\n <Grid item xs={8} md={3}>\n <TextField\n required fullWidth size=\"small\" type=\"number\"\n label=\"Quantity\"\n inputProps={{ min: 1, max: remaining || undefined }}\n value={line.pickedQty}\n onChange={(e) => onPatch(idx, 'pickedQty', e.target.value)}\n error={!!lerr.pickedQty}\n helperText={lerr.pickedQty || (b ? `Out of ${remaining} available` : '')}\n />\n </Grid>\n <Grid item xs={4} md={2} sx={{ textAlign: 'right' }}>\n <IconButton\n color=\"error\"\n onClick={() => onRemove(idx)}\n disabled={!allowRemoveLast && lines.length === 1}\n >\n <DeleteOutlineRoundedIcon />\n </IconButton>\n </Grid>\n </Grid>\n </Card>\n );\n })}\n </Stack>\n );\n}\n\nPickupBatchLinesEditor.propTypes = {\n lines: PropTypes.array.isRequired,\n batches: PropTypes.array.isRequired,\n errors: PropTypes.array.isRequired,\n excludeBatchIds: PropTypes.instanceOf(Set),\n onPatch: PropTypes.func.isRequired,\n onRemove: PropTypes.func.isRequired,\n // Creation always keeps one line; a top-up may legitimately have none.\n allowRemoveLast: PropTypes.bool,\n};\n"],"mappings":";;;;;;;AAOA,SAAgB,EAAgB,GAAG;CACjC,OAAO,EAAE,cAAc,cAClB,OAAO,EAAE,YAAY,IAAI,KACzB,CAAC;EAAC;EAAW;EAAa;CAAa,EAAE,SAAS,EAAE,MAAM;AACjE;AAEA,SAAgB,EAAgB,GAAM;CAGpC,OAAO;EAAE,KAAK,EAAK;EAAG,iBAAiB,EAAK;EAAG,eAAe;EAAI,WAAW;CAAE;AACjF;AAOA,SAAgB,EAAoB,GAAO,GAAS;CAClD,IAAM,KAAQ,MAAO,EAAQ,MAAM,MAAM,EAAE,OAAO,CAAE;CACpD,OAAO,EAAM,KAAK,MAAS;EACzB,IAAI,CAAC,EAAK,eAAe,OAAO,EAAE,eAAe,gBAAgB;EACjE,IAAM,IAAY,OAAO,EAAK,EAAK,aAAa,GAAG,gBAAgB,CAAC,GAC9D,IAAM,OAAO,EAAK,SAAS;EAGjC,OAFI,CAAC,OAAO,UAAU,CAAG,KAAK,KAAO,IAAU,EAAE,WAAW,uCAAuC,IAC/F,IAAM,IAAkB,EAAE,WAAW,QAAQ,EAAU,2BAA2B,IAC/E,CAAC;CACV,CAAC;AACH;AAWA,SAAwB,EAAuB,EAC7C,UACA,YACA,WACA,oBACA,YACA,aACA,sBACC;CACD,IAAM,IAAW,qBAAmB,IAAI,IAAI;CAC5C,OACE,kBAAC,GAAD;EAAO,SAAS;YACb,EAAM,KAAK,GAAM,MAAQ;GACxB,IAAM,IAAO,EAAO,MAAQ,CAAC,GACvB,IAAI,EAAQ,MAAM,MAAM,EAAE,OAAO,EAAK,aAAa,GACnD,IAAY,OAAO,GAAG,gBAAgB,CAAC,GAGvC,IAAQ,IAAI,IAChB,EAAM,QAAQ,GAAG,MAAM,MAAM,CAAG,EAAE,KAAK,MAAM,EAAE,aAAa,EAAE,OAAO,OAAO,CAC9E,GACM,IAAU,EACb,QAAQ,MAAO,EAAG,OAAO,EAAK,iBAAkB,CAAC,EAAM,IAAI,EAAG,EAAE,KAAK,CAAC,EAAS,IAAI,EAAG,EAAE,CAAE,EAC1F,KAAK,OAAQ;IACZ,OAAO,EAAG;IACV,OAAO,GAAG,EAAG,YAAY,SAAS,EAAG,eAC9B,EAAG,YAAY,MAAM,EAAG,cAAc,KACtC,EAAG,aAAa,UAAU,EAAW,EAAG,UAAU,MAAM;GACjE,EAAE;GACJ,OACE,kBAAC,GAAD;IAAqB,SAAQ;IAAW,IAAI;KAAE,GAAG;KAAG,cAAc;IAAI;cACpE,kBAAC,GAAD;KAAM,WAAA;KAAU,SAAS;KAAG,YAAW;eAAvC;MACE,kBAAC,GAAD;OAAM,MAAA;OAAK,IAAI;OAAI,IAAI;iBACrB,kBAAC,GAAD;QACE,OAAM;QACN,UAAA;QACA,OAAO,EAAK;QACZ,WAAW,MAAM,EAAQ,GAAK,iBAAiB,CAAC;QACvC;QACT,OAAO,CAAC,CAAC,EAAK;QACd,YAAY,EAAK,iBAAiB;QAClC,eAAc;OACf,CAAA;MACG,CAAA;MACN,kBAAC,GAAD;OAAM,MAAA;OAAK,IAAI;OAAG,IAAI;iBACpB,kBAAC,GAAD;QACE,UAAA;QAAS,WAAA;QAAU,MAAK;QAAQ,MAAK;QACrC,OAAM;QACN,YAAY;SAAE,KAAK;SAAG,KAAK,KAAa,KAAA;QAAU;QAClD,OAAO,EAAK;QACZ,WAAW,MAAM,EAAQ,GAAK,aAAa,EAAE,OAAO,KAAK;QACzD,OAAO,CAAC,CAAC,EAAK;QACd,YAAY,EAAK,cAAc,IAAI,UAAU,EAAU,cAAc;OACtE,CAAA;MACG,CAAA;MACN,kBAAC,GAAD;OAAM,MAAA;OAAK,IAAI;OAAG,IAAI;OAAG,IAAI,EAAE,WAAW,QAAQ;iBAChD,kBAAC,GAAD;QACE,OAAM;QACN,eAAe,EAAS,CAAG;QAC3B,UAAU,CAAC,KAAmB,EAAM,WAAW;kBAE/C,kBAAC,GAAD,CAA2B,CAAA;OACjB,CAAA;MACR,CAAA;KACF;;GACF,GAnCK,EAAK,GAmCV;EAEV,CAAC;CACI,CAAA;AAEX;AAEA,EAAuB,YAAY;CACjC,OAAO,EAAU,MAAM;CACvB,SAAS,EAAU,MAAM;CACzB,QAAQ,EAAU,MAAM;CACxB,iBAAiB,EAAU,WAAW,GAAG;CACzC,SAAS,EAAU,KAAK;CACxB,UAAU,EAAU,KAAK;CAEzB,iBAAiB,EAAU;AAC7B"}
@@ -1,33 +1,33 @@
1
- import { A as e, F as t, P as n, Q as r, j as i, r as a } from "./settingsStore-BlA2GIhl.js";
2
- import { l as o, r as s } from "./PmTable-BSV_bMJZ.js";
3
- import { a as c, n as l, r as u, t as d } from "./PmGuard-DrIl1sHL.js";
4
- import { i as f, n as p, r as m, t as h } from "./PickupBatchLinesEditor-B2fLx1lU.js";
1
+ import { A as e, F as t, P as n, Q as r, j as i, r as a } from "./settingsStore-BifOsjlB.js";
2
+ import { l as o, r as s } from "./PmTable-_GbScaa4.js";
3
+ import { a as c, n as l, r as u, t as d } from "./PmGuard-b10TGXEi.js";
4
+ import { i as f, n as p, r as m, t as h } from "./PickupBatchLinesEditor-DHmcAG23.js";
5
5
  import { useEffect as g, useMemo as _, useState as v } from "react";
6
6
  import { jsx as y, jsxs as b } from "react/jsx-runtime";
7
- import { Alert as x, Autocomplete as S, Box as C, Button as w, Card as T, CardContent as E, Divider as D, Grid as O, Stack as ee, TextField as k, ToggleButton as te, ToggleButtonGroup as ne, Typography as re } from "@mui/material";
8
- import { v4 as A } from "uuid";
7
+ import { Alert as x, Autocomplete as S, Box as C, Button as w, Card as T, CardContent as E, Divider as D, Grid as O, Stack as ee, TextField as k, ToggleButton as A, ToggleButtonGroup as te, Typography as ne } from "@mui/material";
8
+ import { v4 as re } from "uuid";
9
9
  import ie from "@mui/icons-material/AddRounded";
10
10
  import { useNavigate as ae } from "react-router-dom";
11
11
  import oe from "@mui/icons-material/SaveRounded";
12
12
  import se from "@mui/icons-material/GroupsRounded";
13
- import { DateTimePicker as ce, LocalizationProvider as le } from "@mui/x-date-pickers";
14
- import { AdapterDayjs as j } from "@mui/x-date-pickers/AdapterDayjs";
15
- import ue from "@mui/icons-material/PersonRounded";
13
+ import { DateTimePicker as j, LocalizationProvider as M } from "@mui/x-date-pickers";
14
+ import { AdapterDayjs as N } from "@mui/x-date-pickers/AdapterDayjs";
15
+ import ce from "@mui/icons-material/PersonRounded";
16
16
  //#region \0rolldown/runtime.js
17
- var M = Object.create, N = Object.defineProperty, de = Object.getOwnPropertyDescriptor, P = Object.getOwnPropertyNames, fe = Object.getPrototypeOf, F = Object.prototype.hasOwnProperty, I = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t.exports), L = (e, t, n, r) => {
18
- if (t && typeof t == "object" || typeof t == "function") for (var i = P(t), a = 0, o = i.length, s; a < o; a++) s = i[a], !F.call(e, s) && s !== n && N(e, s, {
17
+ var P = Object.create, F = Object.defineProperty, le = Object.getOwnPropertyDescriptor, I = Object.getOwnPropertyNames, ue = Object.getPrototypeOf, L = Object.prototype.hasOwnProperty, R = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t.exports), z = (e, t, n, r) => {
18
+ if (t && typeof t == "object" || typeof t == "function") for (var i = I(t), a = 0, o = i.length, s; a < o; a++) s = i[a], !L.call(e, s) && s !== n && F(e, s, {
19
19
  get: ((e) => t[e]).bind(null, s),
20
- enumerable: !(r = de(t, s)) || r.enumerable
20
+ enumerable: !(r = le(t, s)) || r.enumerable
21
21
  });
22
22
  return e;
23
- }, R = /* @__PURE__ */ ((e, t, n) => (n = e == null ? {} : M(fe(e)), L(t || !e || !e.__esModule || !F.call(e, "default") ? N(n, "default", {
23
+ }, B = /* @__PURE__ */ ((e, t, n) => (n = e == null ? {} : P(ue(e)), z(t || !e || !e.__esModule ? F(n, "default", {
24
24
  value: e,
25
25
  enumerable: !0
26
- }) : n, e)))((/* @__PURE__ */ I(((e, t) => {
26
+ }) : n, e)))((/* @__PURE__ */ R(((e, t) => {
27
27
  (function(n, r) {
28
28
  typeof e == "object" && t !== void 0 ? t.exports = r() : typeof define == "function" && define.amd ? define(r) : (n = typeof globalThis < "u" ? globalThis : n || self).dayjs = r();
29
29
  })(e, (function() {
30
- var e = 1e3, t = 6e4, n = 36e5, r = "millisecond", i = "second", a = "minute", o = "hour", s = "day", c = "week", l = "month", u = "quarter", d = "year", f = "date", p = "Invalid Date", m = /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/, h = /\[([^\]]+)]|YYYY|YY|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g, g = {
30
+ var e = 1e3, t = 6e4, n = 36e5, r = "millisecond", i = "second", a = "minute", o = "hour", s = "day", c = "week", l = "month", u = "quarter", d = "year", f = "date", p = "Invalid Date", m = /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/, h = /\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g, g = {
31
31
  name: "en",
32
32
  weekdays: "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),
33
33
  months: "January_February_March_April_May_June_July_August_September_October_November_December".split("_"),
@@ -318,20 +318,20 @@ var M = Object.create, N = Object.defineProperty, de = Object.getOwnPropertyDesc
318
318
  }, w.en = b[y], w.Ls = b, w.p = {}, w;
319
319
  }));
320
320
  })))(), 1);
321
- function z() {
322
- return p(A);
321
+ function V() {
322
+ return p(re);
323
323
  }
324
- function B() {
325
- let p = ae(), M = a()?.allowGroupSessions === !0, [N, de] = v([]), [P, fe] = v([]), [F, I] = v([]), [L, B] = v([]), [pe, me] = v(!0), [V, H] = v(!1), [U, W] = v(""), [G, K] = v({
326
- id: A(),
324
+ function H() {
325
+ let p = ae(), P = a()?.allowGroupSessions === !0, [F, le] = v([]), [I, ue] = v([]), [L, R] = v([]), [z, H] = v([]), [de, fe] = v(!0), [U, pe] = v(!1), [me, W] = v(""), [G, K] = v({
326
+ id: re(),
327
327
  sessionType: "INDIVIDUAL",
328
328
  facilityId: "",
329
329
  memberUserIds: [],
330
- lines: [z()],
330
+ lines: [V()],
331
331
  notes: "",
332
332
  sessionName: "",
333
333
  sessionDescription: "",
334
- sessionStartTime: (0, R.default)(),
334
+ sessionStartTime: (0, B.default)(),
335
335
  sessionExpectedEndTime: null,
336
336
  sessionSite: ""
337
337
  });
@@ -343,29 +343,29 @@ function B() {
343
343
  i(),
344
344
  t().catch(() => [])
345
345
  ]);
346
- de(e), fe(r), B(a);
346
+ le(e), ue(r), H(a);
347
347
  } catch (e) {
348
348
  W(e?.response?.data?.message ?? e?.message ?? "Failed to load reference data");
349
349
  } finally {
350
- me(!1);
350
+ fe(!1);
351
351
  }
352
352
  }
353
353
  e();
354
354
  }, []), g(() => {
355
355
  let t = !0;
356
356
  if (!G.facilityId) {
357
- I([]);
357
+ R([]);
358
358
  return;
359
359
  }
360
360
  return e(G.facilityId).then((e) => {
361
- t && I(e);
361
+ t && R(e);
362
362
  }).catch(() => {
363
- t && I([]);
363
+ t && R([]);
364
364
  }), () => {
365
365
  t = !1;
366
366
  };
367
367
  }, [G.facilityId]);
368
- let he = L.length > 0, q = M && G.sessionType === "GROUP", ge = _(() => G.facilityId ? P.filter(m).filter((e) => e.ownerId === G.facilityId) : [], [P, G.facilityId]);
368
+ let he = z.length > 0, q = P && G.sessionType === "GROUP", ge = _(() => G.facilityId ? I.filter(m).filter((e) => e.ownerId === G.facilityId) : [], [I, G.facilityId]);
369
369
  function J(e, t) {
370
370
  K((n) => ({
371
371
  ...n,
@@ -377,7 +377,7 @@ function B() {
377
377
  ...t,
378
378
  facilityId: e,
379
379
  memberUserIds: [],
380
- lines: [z()]
380
+ lines: [V()]
381
381
  }));
382
382
  }
383
383
  function ve(e, t, n) {
@@ -395,7 +395,7 @@ function B() {
395
395
  function ye() {
396
396
  K((e) => ({
397
397
  ...e,
398
- lines: [...e.lines, z()]
398
+ lines: [...e.lines, V()]
399
399
  }));
400
400
  }
401
401
  function be(e) {
@@ -404,10 +404,10 @@ function B() {
404
404
  lines: t.lines.filter((t, n) => n !== e)
405
405
  }));
406
406
  }
407
- let xe = f(G.lines, ge), Se = G.lines.length > 0 && xe.every((e) => Object.keys(e).length === 0), Y = G.sessionName.trim() ? "" : "Session name is required.", X = G.sessionStartTime && R.default.isDayjs(G.sessionStartTime) && G.sessionStartTime.isValid(), Z = X ? G.sessionStartTime.valueOf() < Date.now() - 3e5 ? "Start time cannot be in the past." : "" : "Start time is required.", Ce = G.sessionExpectedEndTime && R.default.isDayjs(G.sessionExpectedEndTime) && G.sessionExpectedEndTime.isValid(), Q = Ce ? X && !G.sessionExpectedEndTime.isAfter(G.sessionStartTime) ? "Expected end must be after the start time." : "" : "Expected end time is required.", $ = q && G.memberUserIds.length === 0 ? "Pick at least one member for a group session." : "", we = !!G.facilityId && Se && !he && !Y && !Z && !Q && !$;
407
+ let xe = f(G.lines, ge), Se = G.lines.length > 0 && xe.every((e) => Object.keys(e).length === 0), Y = G.sessionName.trim() ? "" : "Session name is required.", X = G.sessionStartTime && B.default.isDayjs(G.sessionStartTime) && G.sessionStartTime.isValid(), Z = X ? G.sessionStartTime.valueOf() < Date.now() - 300 * 1e3 ? "Start time cannot be in the past." : "" : "Start time is required.", Ce = G.sessionExpectedEndTime && B.default.isDayjs(G.sessionExpectedEndTime) && G.sessionExpectedEndTime.isValid(), Q = Ce ? X && !G.sessionExpectedEndTime.isAfter(G.sessionStartTime) ? "Expected end must be after the start time." : "" : "Expected end time is required.", $ = q && G.memberUserIds.length === 0 ? "Pick at least one member for a group session." : "", we = !!G.facilityId && Se && !he && !Y && !Z && !Q && !$;
408
408
  async function Te() {
409
409
  if (we) {
410
- H(!0), W("");
410
+ pe(!0), W("");
411
411
  try {
412
412
  await r({
413
413
  id: G.id,
@@ -431,7 +431,7 @@ function B() {
431
431
  } catch (e) {
432
432
  W(e?.response?.data?.message ?? e?.message ?? "Failed to start session");
433
433
  } finally {
434
- H(!1);
434
+ pe(!1);
435
435
  }
436
436
  }
437
437
  }
@@ -451,16 +451,16 @@ function B() {
451
451
  }), /* @__PURE__ */ y(w, {
452
452
  variant: "contained",
453
453
  startIcon: /* @__PURE__ */ y(oe, {}),
454
- disabled: !we || V,
454
+ disabled: !we || U,
455
455
  onClick: () => void Te(),
456
- children: V ? "Starting…" : "Start Session"
456
+ children: U ? "Starting…" : "Start Session"
457
457
  })]
458
458
  }),
459
459
  children: [
460
- U ? /* @__PURE__ */ y(x, {
460
+ me ? /* @__PURE__ */ y(x, {
461
461
  severity: "error",
462
462
  sx: { mb: 2 },
463
- children: U
463
+ children: me
464
464
  }) : null,
465
465
  he ? /* @__PURE__ */ b(x, {
466
466
  severity: "warning",
@@ -490,11 +490,11 @@ function B() {
490
490
  children: [
491
491
  /* @__PURE__ */ y(s, {
492
492
  eyebrow: "Step 1",
493
- title: M ? "Session type & source" : "Session source",
494
- hint: M ? "Run the session yourself or share it with colleagues from the same facility." : "Pick the facility whose stock you are checking out for this outreach session.",
493
+ title: P ? "Session type & source" : "Session source",
494
+ hint: P ? "Run the session yourself or share it with colleagues from the same facility." : "Pick the facility whose stock you are checking out for this outreach session.",
495
495
  sx: { mb: 2 }
496
496
  }),
497
- M ? /* @__PURE__ */ b(ne, {
497
+ P ? /* @__PURE__ */ b(te, {
498
498
  exclusive: !0,
499
499
  size: "small",
500
500
  color: "primary",
@@ -503,13 +503,13 @@ function B() {
503
503
  t && J("sessionType", t);
504
504
  },
505
505
  sx: { mb: 2 },
506
- children: [/* @__PURE__ */ b(te, {
506
+ children: [/* @__PURE__ */ b(A, {
507
507
  value: "INDIVIDUAL",
508
- children: [/* @__PURE__ */ y(ue, {
508
+ children: [/* @__PURE__ */ y(ce, {
509
509
  fontSize: "small",
510
510
  sx: { mr: .75 }
511
511
  }), "Individual"]
512
- }), /* @__PURE__ */ b(te, {
512
+ }), /* @__PURE__ */ b(A, {
513
513
  value: "GROUP",
514
514
  children: [/* @__PURE__ */ y(se, {
515
515
  fontSize: "small",
@@ -526,12 +526,12 @@ function B() {
526
526
  md: q ? 5 : 12,
527
527
  children: /* @__PURE__ */ y(S, {
528
528
  size: "small",
529
- options: N,
529
+ options: F,
530
530
  getOptionLabel: (e) => e?.name ?? "",
531
531
  isOptionEqualToValue: (e, t) => e?.id === t?.id,
532
- value: N.find((e) => e.id === G.facilityId) ?? null,
532
+ value: F.find((e) => e.id === G.facilityId) ?? null,
533
533
  onChange: (e, t) => _e(t?.id ?? ""),
534
- loading: pe,
534
+ loading: de,
535
535
  renderInput: (e) => /* @__PURE__ */ y(k, {
536
536
  ...e,
537
537
  required: !0,
@@ -547,10 +547,10 @@ function B() {
547
547
  multiple: !0,
548
548
  size: "small",
549
549
  disabled: !G.facilityId,
550
- options: F,
550
+ options: L,
551
551
  getOptionLabel: (e) => e?.name ?? String(e?.id ?? ""),
552
552
  isOptionEqualToValue: (e, t) => e?.id === t?.id,
553
- value: F.filter((e) => G.memberUserIds.includes(e.id)),
553
+ value: L.filter((e) => G.memberUserIds.includes(e.id)),
554
554
  onChange: (e, t) => J("memberUserIds", t.map((e) => e.id)),
555
555
  renderInput: (e) => /* @__PURE__ */ y(k, {
556
556
  ...e,
@@ -601,7 +601,7 @@ function B() {
601
601
  errors: xe,
602
602
  onPatch: ve,
603
603
  onRemove: be
604
- }) : /* @__PURE__ */ y(re, {
604
+ }) : /* @__PURE__ */ y(ne, {
605
605
  variant: "body2",
606
606
  color: "text.secondary",
607
607
  children: "Pick a facility first to choose batches."
@@ -662,15 +662,15 @@ function B() {
662
662
  item: !0,
663
663
  xs: 12,
664
664
  md: 6,
665
- children: /* @__PURE__ */ y(le, {
666
- dateAdapter: j,
665
+ children: /* @__PURE__ */ y(M, {
666
+ dateAdapter: N,
667
667
  adapterLocale: "en",
668
- children: /* @__PURE__ */ y(ce, {
668
+ children: /* @__PURE__ */ y(j, {
669
669
  label: "Start time",
670
670
  value: G.sessionStartTime,
671
671
  onChange: (e) => J("sessionStartTime", e),
672
672
  ampm: !1,
673
- minDateTime: (0, R.default)().subtract(5, "minute"),
673
+ minDateTime: (0, B.default)().subtract(5, "minute"),
674
674
  slotProps: {
675
675
  actionBar: { actions: ["clear"] },
676
676
  textField: {
@@ -688,10 +688,10 @@ function B() {
688
688
  item: !0,
689
689
  xs: 12,
690
690
  md: 6,
691
- children: /* @__PURE__ */ y(le, {
692
- dateAdapter: j,
691
+ children: /* @__PURE__ */ y(M, {
692
+ dateAdapter: N,
693
693
  adapterLocale: "en",
694
- children: /* @__PURE__ */ y(ce, {
694
+ children: /* @__PURE__ */ y(j, {
695
695
  label: "Expected End Time",
696
696
  value: G.sessionExpectedEndTime,
697
697
  onChange: (e) => J("sessionExpectedEndTime", e),
@@ -745,6 +745,6 @@ function B() {
745
745
  })] });
746
746
  }
747
747
  //#endregion
748
- export { B as default };
748
+ export { H as default };
749
749
 
750
- //# sourceMappingURL=PickupCreatePage-BeYhR45k.js.map
750
+ //# sourceMappingURL=PickupCreatePage-CB0Sl0Hb.js.map