@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.
- package/dist/{BrandsPage-CdqGFmGf.js → BrandsPage-DmRW5bhm.js} +77 -78
- package/dist/{BrandsPage-CdqGFmGf.js.map → BrandsPage-DmRW5bhm.js.map} +1 -1
- package/dist/{CategoriesPage-DJM0Nalw.js → CategoriesPage-BsS5IQh3.js} +6 -7
- package/dist/{CategoriesPage-DJM0Nalw.js.map → CategoriesPage-BsS5IQh3.js.map} +1 -1
- package/dist/{DashboardPage-BASkXr00.js → DashboardPage-C3bKc5na.js} +3 -3
- package/dist/{DashboardPage-BASkXr00.js.map → DashboardPage-C3bKc5na.js.map} +1 -1
- package/dist/{FacilityPicker-jV-qXp1k.js → FacilityPicker-BiZeupmP.js} +6 -8
- package/dist/{FacilityPicker-jV-qXp1k.js.map → FacilityPicker-BiZeupmP.js.map} +1 -1
- package/dist/{InventoryPage-CTdq6txa.js → InventoryPage-C_AxSy7A.js} +9 -12
- package/dist/{InventoryPage-CTdq6txa.js.map → InventoryPage-C_AxSy7A.js.map} +1 -1
- package/dist/{MemberProfileCard-DwWda-tS.js → MemberProfileCard-BdUNgHRB.js} +3 -3
- package/dist/{MemberProfileCard-DwWda-tS.js.map → MemberProfileCard-BdUNgHRB.js.map} +1 -1
- package/dist/{PaymentCreatePage-B3bP-K01.js → PaymentCreatePage-CIVe0P0p.js} +114 -114
- package/dist/{PaymentCreatePage-B3bP-K01.js.map → PaymentCreatePage-CIVe0P0p.js.map} +1 -1
- package/dist/{PaymentsPage-Dh8bqXVE.js → PaymentsPage-BvPe5Q9F.js} +4 -4
- package/dist/{PaymentsPage-Dh8bqXVE.js.map → PaymentsPage-BvPe5Q9F.js.map} +1 -1
- package/dist/{PickupBatchLinesEditor-B2fLx1lU.js → PickupBatchLinesEditor-DHmcAG23.js} +2 -2
- package/dist/{PickupBatchLinesEditor-B2fLx1lU.js.map → PickupBatchLinesEditor-DHmcAG23.js.map} +1 -1
- package/dist/{PickupCreatePage-BeYhR45k.js → PickupCreatePage-CB0Sl0Hb.js} +58 -58
- package/dist/PickupCreatePage-CB0Sl0Hb.js.map +1 -0
- package/dist/{PickupsPage-C6lBtAoQ.js → PickupsPage-Ctpghavs.js} +7 -9
- package/dist/{PickupsPage-C6lBtAoQ.js.map → PickupsPage-Ctpghavs.js.map} +1 -1
- package/dist/{PmGuard-DrIl1sHL.js → PmGuard-b10TGXEi.js} +3 -3
- package/dist/{PmGuard-DrIl1sHL.js.map → PmGuard-b10TGXEi.js.map} +1 -1
- package/dist/{PmTable-BSV_bMJZ.js → PmTable-_GbScaa4.js} +3 -4
- package/dist/{PmTable-BSV_bMJZ.js.map → PmTable-_GbScaa4.js.map} +1 -1
- package/dist/{ProductEditPage-DZTUH95T.js → ProductEditPage-C1thoKHu.js} +8 -9
- package/dist/{ProductEditPage-DZTUH95T.js.map → ProductEditPage-C1thoKHu.js.map} +1 -1
- package/dist/{ProductsPage-CqOsah4_.js → ProductsPage-CupVmOD4.js} +4 -4
- package/dist/{ProductsPage-CqOsah4_.js.map → ProductsPage-CupVmOD4.js.map} +1 -1
- package/dist/{PurchaseCreatePage-D6os7srp.js → PurchaseCreatePage-YD3NmhPQ.js} +6 -6
- package/dist/{PurchaseCreatePage-D6os7srp.js.map → PurchaseCreatePage-YD3NmhPQ.js.map} +1 -1
- package/dist/{PurchaseRequestDetailPage-DErqGKiq.js → PurchaseRequestDetailPage-Dg_MRY_N.js} +6 -7
- package/dist/{PurchaseRequestDetailPage-DErqGKiq.js.map → PurchaseRequestDetailPage-Dg_MRY_N.js.map} +1 -1
- package/dist/{PurchaseRequestsPage-CHBoRzzH.js → PurchaseRequestsPage-DPAPzpmm.js} +4 -4
- package/dist/{PurchaseRequestsPage-CHBoRzzH.js.map → PurchaseRequestsPage-DPAPzpmm.js.map} +1 -1
- package/dist/{PurchasesPage-C-2K7wH6.js → PurchasesPage-It1GHiXl.js} +4 -4
- package/dist/{PurchasesPage-C-2K7wH6.js.map → PurchasesPage-It1GHiXl.js.map} +1 -1
- package/dist/{SaleCreatePage-DB3_UEgy.js → SaleCreatePage-C9kFmTvm.js} +20 -20
- package/dist/{SaleCreatePage-DB3_UEgy.js.map → SaleCreatePage-C9kFmTvm.js.map} +1 -1
- package/dist/{SalesPage-BhBGG426.js → SalesPage-D18DCseD.js} +74 -74
- package/dist/{SalesPage-BhBGG426.js.map → SalesPage-D18DCseD.js.map} +1 -1
- package/dist/{SettingsPage-CBUu9DZK.js → SettingsPage-VsxI-ano.js} +4 -4
- package/dist/{SettingsPage-CBUu9DZK.js.map → SettingsPage-VsxI-ano.js.map} +1 -1
- package/dist/{StorageUnitsPage-oe0lXLd1.js → StorageUnitsPage-7EqwuMOI.js} +7 -8
- package/dist/{StorageUnitsPage-oe0lXLd1.js.map → StorageUnitsPage-7EqwuMOI.js.map} +1 -1
- package/dist/{TransactionsPage-7dRZpZOD.js → TransactionsPage-DrH53pVS.js} +4 -4
- package/dist/{TransactionsPage-7dRZpZOD.js.map → TransactionsPage-DrH53pVS.js.map} +1 -1
- package/dist/{TransferCreatePage-DtkAlP9l.js → TransferCreatePage-CuvoMrYH.js} +4 -4
- package/dist/{TransferCreatePage-DtkAlP9l.js.map → TransferCreatePage-CuvoMrYH.js.map} +1 -1
- package/dist/{TransfersPage-BaEjbvnj.js → TransfersPage-Cf701t8s.js} +4 -4
- package/dist/{TransfersPage-BaEjbvnj.js.map → TransfersPage-Cf701t8s.js.map} +1 -1
- package/dist/{VialsPage-vo9Of9oC.js → VialsPage-8oAc1yFv.js} +5 -5
- package/dist/{VialsPage-vo9Of9oC.js.map → VialsPage-8oAc1yFv.js.map} +1 -1
- package/dist/constants-ClZJY2x1.js.map +1 -1
- package/dist/format-UOyOu75i.js.map +1 -1
- package/dist/index.js +253 -240
- package/dist/index.js.map +1 -1
- package/dist/{settingsStore-BlA2GIhl.js → settingsStore-BifOsjlB.js} +2 -2
- package/dist/{settingsStore-BlA2GIhl.js.map → settingsStore-BifOsjlB.js.map} +1 -1
- package/dist/{validation-B6Kl5Xf9.js → validation-BzlHnL-r.js} +16 -15
- package/dist/{validation-B6Kl5Xf9.js.map → validation-BzlHnL-r.js.map} +1 -1
- package/package.json +1 -1
- 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-
|
|
2
|
-
import { a as n, c as r, i, l as a, s as o, t as s } from "./PmTable-
|
|
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-
|
|
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-
|
|
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":";;;;;;;;;;;;AAiCA,SAAwB,IAAe;CACpB,EAAY;CAC7B,IAAM,CAAC,GAAU,KAAe,EAAS,CAAC,CAAC,GAIrC,CAAC,GAAa,KAAkB,EAAS,CAAC,CAAC,GAC3C,CAAC,GAAS,KAAc,EAAS,EAAK,GACtC,CAAC,GAAO,KAAY,EAAS,EAAE;CAErC,eAAe,IAAO;EAEpB,AADA,EAAW,EAAI,GACf,EAAS,EAAE;EACX,IAAI;GACF,IAAM,IAAO,MAAM,EAAa,GAAG,EAAE;GACrC,EAAY,CAAI;GAChB,IAAM,IAAM,MAAM,KAChB,IAAI,IAAI,EAAK,KAAK,MAAM,EAAE,QAAQ,EAAE,OAAO,OAAO,CAAC,CACrD;GACA,IAAI,EAAI,WAAW,GACjB,EAAe,CAAC,CAAC;QAEjB,IAAI;IACF,IAAM,IAAO,MAAM,EAAgB,CAAG,GAChC,IAAM,CAAC;IAIb,AAHA,EAAK,SAAS,MAAM;KAClB,EAAI,EAAE,MAAM,EAAE;IAChB,CAAC,GACD,EAAe,CAAG;GACpB,QAAQ;IACN,EAAe,CAAC,CAAC;GACnB;EAEJ,SAAS,GAAK;GACZ,IAAM,IACJ,GAAK,UAAU,MAAM,WAAW,GAAK,WAAW;GAElD,AADA,EAAS,CAAO,GAChB,EAAU;IAAE;IAAS,MAAM;GAAQ,CAAC;EACtC,UAAU;GACR,EAAW,EAAK;EAClB;CACF;CAUA,OARA,EACE,+CACM;EACJ,EAAU;CACZ,GACA,CAAC,CACH,GAGE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,CAAQ,CAAA,GACR,kBAAC,GAAD;EAAS,MAAM;YACb,kBAAC,GAAD;GACE,OAAM;GACN,UAAS;GACT,SACE,kBAAC,GAAD;IAAO,WAAU;IAAM,SAAS;cAAhC,CACE,kBAAC,GAAD;KACE,SAAQ;KACR,WAAW,kBAAC,GAAD,CAAqB,CAAA;KAChC,eAAe,KAAK,EAAK;eAC1B;IAEO,CAAA,GAIP,EASI;;aAxBX,CA2BG,IACC,kBAAC,GAAD;IAAO,UAAS;IAAQ,IAAI,EAAE,IAAI,EAAE;cACjC;GACI,CAAA,IACL,MAEJ,kBAAC,GAAD;IACE,SAAQ;IACR,OAAM;IACN,UACE,IACI,aACA,GAAG,EAAS,OAAO,GAAG,EAAS,WAAW,IAAI,YAAY,WAAW;cAG3E,kBAAC,GAAD;KAAS,OAAA;eAAT,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAA;MACE,kBAAC,GAAD,EAAA,UAAW,MAAc,CAAA;MACzB,kBAAC,GAAD,EAAA,UAAW,OAAe,CAAA;MAC1B,kBAAC,GAAD,EAAA,UAAW,SAAiB,CAAA;MAC5B,kBAAC,GAAD,EAAA,UAAW,OAAe,CAAA;MAC1B,kBAAC,GAAD;OAAW,OAAM;iBAAQ;MAAiB,CAAA;MAC1C,kBAAC,GAAD;OAAW,OAAM;iBAAQ;MAAsB,CAAA;KACvC,EAAA,CAAA,EACD,CAAA,GACX,kBAAC,GAAD,EAAA,UACG,IACC,MAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,GAAG,MAChC,kBAAC,GAAD,EAAA,UACG,MAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,GAAI,MAClC,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAU,QAAQ,GAAK,CAAA,EACd,GAFK,CAEL,CACZ,EACO,GANK,CAML,CACX,IACC,EAAS,WAAW,IACtB,kBAAC,GAAD;MACE,SAAS;MACT,MAAM;MACN,OAAM;MACN,MAAK;KACN,CAAA,IAED,EAAS,KAAK,MAAM;MAClB,IAAM,IAAa,EAAY,EAAE;MACjC,OACE,kBAAC,GAAD;OAAqB,OAAA;iBAArB;QACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAO,IAAI,EAAE,SAAW,CAAA,EACf,CAAA;QACX,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;SAAY,SAAQ;SAAQ,IAAI,EAAE,YAAY,IAAI;mBAC/C,EAAW,EAAE,WAAW;QACf,CAAA,EACH,CAAA;QACX,kBAAC,GAAD,EAAA,UACG,IACC,kBAAC,GAAD;SACE,SAAQ;SACR,IAAI,EAAE,YAAY,IAAI;mBAErB;QACS,CAAA,IAEZ,kBAAC,GAAD;SACE,SAAQ;SACR,IAAI;UACF,YAAY;UACZ,OAAO;SACT;mBALF,CAOG,EAAE,UAAU,MAAM,GAAG,CAAC,GAAE,GACf;WAEL,CAAA;QACX,kBAAC,GAAD,EAAA,UACG,EAAE,cACD,kBAAC,GAAD;SACE,MAAK;SACL,OAAO,EAAE;SACT,IAAI;UACF,YAAY;UACZ,cAAc;UACd,QAAQ;SACV;QACD,CAAA,IAED,kBAAC,GAAD;SAAY,SAAQ;SAAU,OAAM;mBAAgB;QAExC,CAAA,EAEL,CAAA;QACX,kBAAC,GAAD;SAAW,OAAM;mBACf,kBAAC,GAAD;UAAS,OAAO,EAAE;UAAQ,MAAK;SAAW,CAAA;QACjC,CAAA;QACX,kBAAC,GAAD;SAAW,OAAM;mBACf,kBAAC,GAAD;UACE,WAAU;UACV,IAAI;WACF,SAAS;WACT,IAAI;WACJ,IAAI;WACJ,cAAc;WACd,SAAS;WACT,YAAY;WACZ,oBAAoB;WACpB,OAAO;UACT;qBAEE,EAAE,eAAe,CAAC,GAAG;SACpB,CAAA;QACI,CAAA;OACH;SAlEK,EAAE,EAkEP;KAEd,CAAC,EAEM,CAAA,CACJ;;GACE,CAAA,CACF;;CACN,CAAA,CACN,EAAA,CAAA;AAET"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { o as e } from "./PmTable-
|
|
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-
|
|
116
|
+
//# sourceMappingURL=PickupBatchLinesEditor-DHmcAG23.js.map
|
package/dist/{PickupBatchLinesEditor-B2fLx1lU.js.map → PickupBatchLinesEditor-DHmcAG23.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PickupBatchLinesEditor-
|
|
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":"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"}
|
|
@@ -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-
|
|
2
|
-
import { l as o, r as s } from "./PmTable-
|
|
3
|
-
import { a as c, n as l, r as u, t as d } from "./PmGuard-
|
|
4
|
-
import { i as f, n as p, r as m, t as h } from "./PickupBatchLinesEditor-
|
|
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
|
|
8
|
-
import { v4 as
|
|
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
|
|
14
|
-
import { AdapterDayjs as
|
|
15
|
-
import
|
|
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
|
|
18
|
-
if (t && typeof t == "object" || typeof t == "function") for (var i =
|
|
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 =
|
|
20
|
+
enumerable: !(r = le(t, s)) || r.enumerable
|
|
21
21
|
});
|
|
22
22
|
return e;
|
|
23
|
-
},
|
|
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__ */
|
|
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 = /\[([^\]]+)]|
|
|
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
|
|
322
|
-
return p(
|
|
321
|
+
function V() {
|
|
322
|
+
return p(re);
|
|
323
323
|
}
|
|
324
|
-
function
|
|
325
|
-
let p = ae(),
|
|
326
|
-
id:
|
|
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: [
|
|
330
|
+
lines: [V()],
|
|
331
331
|
notes: "",
|
|
332
332
|
sessionName: "",
|
|
333
333
|
sessionDescription: "",
|
|
334
|
-
sessionStartTime: (0,
|
|
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
|
-
|
|
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
|
-
|
|
350
|
+
fe(!1);
|
|
351
351
|
}
|
|
352
352
|
}
|
|
353
353
|
e();
|
|
354
354
|
}, []), g(() => {
|
|
355
355
|
let t = !0;
|
|
356
356
|
if (!G.facilityId) {
|
|
357
|
-
|
|
357
|
+
R([]);
|
|
358
358
|
return;
|
|
359
359
|
}
|
|
360
360
|
return e(G.facilityId).then((e) => {
|
|
361
|
-
t &&
|
|
361
|
+
t && R(e);
|
|
362
362
|
}).catch(() => {
|
|
363
|
-
t &&
|
|
363
|
+
t && R([]);
|
|
364
364
|
}), () => {
|
|
365
365
|
t = !1;
|
|
366
366
|
};
|
|
367
367
|
}, [G.facilityId]);
|
|
368
|
-
let he =
|
|
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: [
|
|
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,
|
|
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 &&
|
|
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
|
-
|
|
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
|
-
|
|
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 ||
|
|
454
|
+
disabled: !we || U,
|
|
455
455
|
onClick: () => void Te(),
|
|
456
|
-
children:
|
|
456
|
+
children: U ? "Starting…" : "Start Session"
|
|
457
457
|
})]
|
|
458
458
|
}),
|
|
459
459
|
children: [
|
|
460
|
-
|
|
460
|
+
me ? /* @__PURE__ */ y(x, {
|
|
461
461
|
severity: "error",
|
|
462
462
|
sx: { mb: 2 },
|
|
463
|
-
children:
|
|
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:
|
|
494
|
-
hint:
|
|
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
|
-
|
|
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(
|
|
506
|
+
children: [/* @__PURE__ */ b(A, {
|
|
507
507
|
value: "INDIVIDUAL",
|
|
508
|
-
children: [/* @__PURE__ */ y(
|
|
508
|
+
children: [/* @__PURE__ */ y(ce, {
|
|
509
509
|
fontSize: "small",
|
|
510
510
|
sx: { mr: .75 }
|
|
511
511
|
}), "Individual"]
|
|
512
|
-
}), /* @__PURE__ */ b(
|
|
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:
|
|
529
|
+
options: F,
|
|
530
530
|
getOptionLabel: (e) => e?.name ?? "",
|
|
531
531
|
isOptionEqualToValue: (e, t) => e?.id === t?.id,
|
|
532
|
-
value:
|
|
532
|
+
value: F.find((e) => e.id === G.facilityId) ?? null,
|
|
533
533
|
onChange: (e, t) => _e(t?.id ?? ""),
|
|
534
|
-
loading:
|
|
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:
|
|
550
|
+
options: L,
|
|
551
551
|
getOptionLabel: (e) => e?.name ?? String(e?.id ?? ""),
|
|
552
552
|
isOptionEqualToValue: (e, t) => e?.id === t?.id,
|
|
553
|
-
value:
|
|
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(
|
|
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(
|
|
666
|
-
dateAdapter:
|
|
665
|
+
children: /* @__PURE__ */ y(M, {
|
|
666
|
+
dateAdapter: N,
|
|
667
667
|
adapterLocale: "en",
|
|
668
|
-
children: /* @__PURE__ */ y(
|
|
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,
|
|
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(
|
|
692
|
-
dateAdapter:
|
|
691
|
+
children: /* @__PURE__ */ y(M, {
|
|
692
|
+
dateAdapter: N,
|
|
693
693
|
adapterLocale: "en",
|
|
694
|
-
children: /* @__PURE__ */ y(
|
|
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 {
|
|
748
|
+
export { H as default };
|
|
749
749
|
|
|
750
|
-
//# sourceMappingURL=PickupCreatePage-
|
|
750
|
+
//# sourceMappingURL=PickupCreatePage-CB0Sl0Hb.js.map
|