@argusoft/medplat-product-management 1.0.0

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 (65) hide show
  1. package/dist/BrandsPage-DCMCVvDY.js +334 -0
  2. package/dist/BrandsPage-DCMCVvDY.js.map +1 -0
  3. package/dist/CategoriesPage-BpRhwfrc.js +284 -0
  4. package/dist/CategoriesPage-BpRhwfrc.js.map +1 -0
  5. package/dist/DashboardPage-BNKUQj46.js +436 -0
  6. package/dist/DashboardPage-BNKUQj46.js.map +1 -0
  7. package/dist/FacilityPicker-Coi8I3yE.js +79 -0
  8. package/dist/FacilityPicker-Coi8I3yE.js.map +1 -0
  9. package/dist/InventoryPage-BR6jOzg2.js +517 -0
  10. package/dist/InventoryPage-BR6jOzg2.js.map +1 -0
  11. package/dist/MemberProfileCard-DbHZCS5n.js +272 -0
  12. package/dist/MemberProfileCard-DbHZCS5n.js.map +1 -0
  13. package/dist/PaymentCreatePage-Ci3ERnby.js +487 -0
  14. package/dist/PaymentCreatePage-Ci3ERnby.js.map +1 -0
  15. package/dist/PaymentsPage-sdg902zX.js +157 -0
  16. package/dist/PaymentsPage-sdg902zX.js.map +1 -0
  17. package/dist/PickupCreatePage-CieMsgWV.js +310 -0
  18. package/dist/PickupCreatePage-CieMsgWV.js.map +1 -0
  19. package/dist/PickupsPage-Ci2Ll0Kn.js +566 -0
  20. package/dist/PickupsPage-Ci2Ll0Kn.js.map +1 -0
  21. package/dist/PmGuard-CjJBisaN.js +1195 -0
  22. package/dist/PmGuard-CjJBisaN.js.map +1 -0
  23. package/dist/PmTable-BuXZQZCU.js +302 -0
  24. package/dist/PmTable-BuXZQZCU.js.map +1 -0
  25. package/dist/ProductEditPage-DL8gy85Y.js +666 -0
  26. package/dist/ProductEditPage-DL8gy85Y.js.map +1 -0
  27. package/dist/ProductsPage-BANTKxLb.js +221 -0
  28. package/dist/ProductsPage-BANTKxLb.js.map +1 -0
  29. package/dist/PurchaseCreatePage-C3KMfBxJ.js +626 -0
  30. package/dist/PurchaseCreatePage-C3KMfBxJ.js.map +1 -0
  31. package/dist/PurchaseRequestDetailPage-C0GYFJDl.js +586 -0
  32. package/dist/PurchaseRequestDetailPage-C0GYFJDl.js.map +1 -0
  33. package/dist/PurchaseRequestsPage-DvFH_tWe.js +265 -0
  34. package/dist/PurchaseRequestsPage-DvFH_tWe.js.map +1 -0
  35. package/dist/PurchasesPage-BCvLvSp4.js +295 -0
  36. package/dist/PurchasesPage-BCvLvSp4.js.map +1 -0
  37. package/dist/SaleCreatePage-DpkQMoTq.js +548 -0
  38. package/dist/SaleCreatePage-DpkQMoTq.js.map +1 -0
  39. package/dist/SalesPage-DUwgkEO-.js +315 -0
  40. package/dist/SalesPage-DUwgkEO-.js.map +1 -0
  41. package/dist/SettingsPage-CusC0jqJ.js +710 -0
  42. package/dist/SettingsPage-CusC0jqJ.js.map +1 -0
  43. package/dist/StorageUnitsPage-BlC2AgrJ.js +469 -0
  44. package/dist/StorageUnitsPage-BlC2AgrJ.js.map +1 -0
  45. package/dist/TransactionsPage-DDaK4VyY.js +714 -0
  46. package/dist/TransactionsPage-DDaK4VyY.js.map +1 -0
  47. package/dist/TransferCreatePage-BxudLfhS.js +363 -0
  48. package/dist/TransferCreatePage-BxudLfhS.js.map +1 -0
  49. package/dist/TransfersPage-zgmt7teZ.js +480 -0
  50. package/dist/TransfersPage-zgmt7teZ.js.map +1 -0
  51. package/dist/VialsPage-CjqPfgpV.js +855 -0
  52. package/dist/VialsPage-CjqPfgpV.js.map +1 -0
  53. package/dist/constants-BrA_hfAI.js +254 -0
  54. package/dist/constants-BrA_hfAI.js.map +1 -0
  55. package/dist/currency-BDDCDgeE.js +169 -0
  56. package/dist/currency-BDDCDgeE.js.map +1 -0
  57. package/dist/format-UOyOu75i.js +52 -0
  58. package/dist/format-UOyOu75i.js.map +1 -0
  59. package/dist/index.js +45 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/useFieldErrors-hDG8ox_x.js +29 -0
  62. package/dist/useFieldErrors-hDG8ox_x.js.map +1 -0
  63. package/dist/validation-Ba7puFIO.js +109 -0
  64. package/dist/validation-Ba7puFIO.js.map +1 -0
  65. package/package.json +36 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PurchaseRequestDetailPage-C0GYFJDl.js","names":[],"sources":["../src/views/PurchaseRequestDetailPage.jsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useNavigate, useParams } from 'react-router-dom';\nimport {\n Alert,\n Box,\n Button,\n Card,\n CardContent,\n Chip,\n Divider,\n Stack,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n TextField,\n Typography,\n} from '@mui/material';\nimport { alpha } from '@mui/material/styles';\nimport RefreshRoundedIcon from '@mui/icons-material/RefreshRounded';\nimport ArrowBackRoundedIcon from '@mui/icons-material/ArrowBackRounded';\nimport CheckCircleRoundedIcon from '@mui/icons-material/CheckCircleRounded';\nimport CancelRoundedIcon from '@mui/icons-material/CancelRounded';\nimport DoNotDisturbRoundedIcon from '@mui/icons-material/DoNotDisturbRounded';\nimport { showToast } from '@/common/toaster/toaster';\nimport PmPageShell from '@pm/components/PmPageShell';\nimport PmNav from '@pm/components/PmNav';\nimport PmGuard from '@pm/components/PmGuard';\nimport { PmFormSection, PmMoney, PmRef } from '@pm/components/PmTable';\nimport { usePermissionedEffect, usePmPermissions } from '@pm/utils/permissions';\nimport {\n cancelPurchaseRequest,\n decidePurchaseRequest,\n getPurchaseRequest,\n} from '@pm/services/pmApi';\nimport { formatDate, formatDateTime } from '@pm/utils/format';\nimport { usePmSettings } from '@pm/utils/settingsStore';\n\nfunction statusChipColor(status) {\n switch (status) {\n case 'PENDING': return 'info';\n case 'APPROVED': return 'success';\n case 'PARTIALLY_APPROVED': return 'warning';\n case 'REJECTED': return 'error';\n case 'CANCELLED': return 'default';\n default: return 'default';\n }\n}\n\nfunction prettyStatus(status) {\n if (!status) return '';\n return status\n .toLowerCase()\n .split('_')\n .map((p) => p.charAt(0).toUpperCase() + p.slice(1))\n .join(' ');\n}\n\nexport default function PurchaseRequestDetailPage() {\n const navigate = useNavigate();\n const { requestId } = useParams();\n const perms = usePmPermissions();\n const canDecide = perms.has('approve.manage.productManagement.purchase');\n const settings = usePmSettings();\n const manageAmounts = settings?.managePurchaseAmounts !== false;\n\n const [request, setRequest] = useState(null);\n const [loading, setLoading] = useState(true);\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState('');\n // Per-line approved quantities the approver is currently editing. Keyed by\n // item.id so the controls stay decoupled from order in the source list.\n const [approvedDraft, setApprovedDraft] = useState({});\n // Per-line lot numbers the approver fills at decision time — the requester\n // doesn't have the goods yet, so they don't know what lot will be shipped.\n // The approver enters this when confirming receipt.\n const [lotDraft, setLotDraft] = useState({});\n // Same logic for expiry — the requester can't read the expiry off a vial\n // they don't have. Captured by the approver.\n const [expiryDraft, setExpiryDraft] = useState({});\n const [decisionNotes, setDecisionNotes] = useState('');\n\n async function load() {\n setLoading(true);\n setError('');\n try {\n const data = await getPurchaseRequest(requestId);\n setRequest(data);\n // Seed the draft with full approval — the typical case is \"approve everything\".\n const draft = {};\n const lots = {};\n const expiries = {};\n (data?.items ?? []).forEach((it) => {\n draft[it.id] = String(it.approvedQuantity != null ? it.approvedQuantity : it.requestedQuantity);\n lots[it.id] = it.lotNumber ?? '';\n // Expiry from the existing item, normalized to yyyy-MM-dd for the date input.\n expiries[it.id] = it.expiryDate ? new Date(it.expiryDate).toISOString().substring(0, 10) : '';\n });\n setApprovedDraft(draft);\n setLotDraft(lots);\n setExpiryDraft(expiries);\n setDecisionNotes(data?.decisionNotes ?? '');\n } catch (err) {\n setError(err?.response?.data?.message ?? err?.message ?? 'Failed to load purchase request');\n } finally {\n setLoading(false);\n }\n }\n\n usePermissionedEffect(\n ['view.manage.productManagement.purchase', 'approve.manage.productManagement.purchase'],\n () => { void load(); },\n [requestId],\n );\n\n const isPending = request?.status === 'PENDING';\n\n // Sum the *approved* dollars for the in-flight decision so the approver\n // can see the cost of what they're about to confirm.\n const approvedTotal = useMemo(() => {\n if (!request || !manageAmounts) return null;\n let total = 0;\n let priced = false;\n (request.items ?? []).forEach((it) => {\n const qty = Number(approvedDraft[it.id] ?? 0);\n if (!Number.isFinite(qty) || qty <= 0) return;\n if (it.buyPrice == null) return;\n total += Number(it.buyPrice) * qty;\n priced = true;\n });\n return priced ? total : null;\n }, [request, approvedDraft, manageAmounts]);\n\n function patchDraft(itemId, value) {\n setApprovedDraft((d) => ({ ...d, [itemId]: value }));\n }\n\n function patchLot(itemId, value) {\n setLotDraft((d) => ({ ...d, [itemId]: value }));\n }\n\n function patchExpiry(itemId, value) {\n setExpiryDraft((d) => ({ ...d, [itemId]: value }));\n }\n\n function setAllToRequested() {\n if (!request) return;\n const draft = {};\n request.items.forEach((it) => { draft[it.id] = String(it.requestedQuantity); });\n setApprovedDraft(draft);\n }\n\n function setAllToZero() {\n if (!request) return;\n const draft = {};\n request.items.forEach((it) => { draft[it.id] = '0'; });\n setApprovedDraft(draft);\n }\n\n // Validates each line's approved qty is an integer in [0, requestedQty].\n // Returns a per-id error map; empty means \"ready to submit\".\n const draftErrors = useMemo(() => {\n if (!request) return {};\n const errs = {};\n (request.items ?? []).forEach((it) => {\n const raw = approvedDraft[it.id];\n if (raw == null || raw === '') {\n errs[it.id] = 'Required';\n return;\n }\n const n = Number(raw);\n if (!Number.isInteger(n) || n < 0) errs[it.id] = 'Must be 0 or a positive whole number';\n else if (n > it.requestedQuantity) errs[it.id] = `At most ${it.requestedQuantity}`;\n });\n return errs;\n }, [request, approvedDraft]);\n // Lot is required on every line the approver is approving (>0). Rejected\n // lines don't need a lot since no stock lands.\n const lotErrors = useMemo(() => {\n if (!request) return {};\n const errs = {};\n (request.items ?? []).forEach((it) => {\n const qty = Number(approvedDraft[it.id] ?? 0);\n if (!Number.isFinite(qty) || qty <= 0) return;\n const lot = (lotDraft[it.id] ?? '').trim();\n if (!lot) errs[it.id] = 'Lot is required when approving this line';\n });\n return errs;\n }, [request, approvedDraft, lotDraft]);\n // Expiry mirrors lot — required for any approved line, must be in the future.\n const expiryErrors = useMemo(() => {\n if (!request) return {};\n const errs = {};\n const todayStr = new Date().toISOString().substring(0, 10);\n (request.items ?? []).forEach((it) => {\n const qty = Number(approvedDraft[it.id] ?? 0);\n if (!Number.isFinite(qty) || qty <= 0) return;\n const exp = (expiryDraft[it.id] ?? '').trim();\n if (!exp) {\n errs[it.id] = 'Expiry is required when approving this line';\n } else if (exp < todayStr) {\n errs[it.id] = 'Expiry must be today or later';\n }\n });\n return errs;\n }, [request, approvedDraft, expiryDraft]);\n const draftIsClean = Object.keys(draftErrors).length === 0\n && Object.keys(lotErrors).length === 0\n && Object.keys(expiryErrors).length === 0;\n\n async function submit() {\n if (!draftIsClean || !request) return;\n setSubmitting(true);\n setError('');\n try {\n const updated = await decidePurchaseRequest(request.id, {\n decisionNotes: decisionNotes || null,\n items: request.items.map((it) => {\n const lot = (lotDraft[it.id] ?? '').trim();\n const exp = (expiryDraft[it.id] ?? '').trim();\n return {\n itemId: it.id,\n approvedQuantity: Number(approvedDraft[it.id]),\n lotNumber: lot ? lot : null,\n expiryDate: exp ? exp : null,\n };\n }),\n });\n setRequest(updated);\n showToast({ message: `Request ${prettyStatus(updated.status).toLowerCase()}.`, type: 'success' });\n } catch (err) {\n setError(err?.response?.data?.message ?? err?.message ?? 'Failed to submit decision');\n } finally {\n setSubmitting(false);\n }\n }\n\n async function cancel() {\n if (!request) return;\n setSubmitting(true);\n setError('');\n try {\n const updated = await cancelPurchaseRequest(request.id);\n setRequest(updated);\n showToast({ message: 'Request cancelled.', type: 'success' });\n } catch (err) {\n setError(err?.response?.data?.message ?? err?.message ?? 'Failed to cancel request');\n } finally {\n setSubmitting(false);\n }\n }\n\n // Coarse-grained UI states for the approver: clean PENDING + decide perm →\n // show the editable decision form. Otherwise the same table is shown\n // read-only with the historical approved quantities.\n const showDecisionForm = isPending && canDecide;\n\n return (\n <Box>\n <PmNav />\n <PmGuard anyOf={['view.manage.productManagement.purchase', 'approve.manage.productManagement.purchase']}>\n <PmPageShell\n title={request?.serialId ? `Purchase Request #${request.serialId}` : 'Purchase Request'}\n subtitle=\"Approve or reject each item. Your decision closes the entire request.\"\n chips={request?.status ? [prettyStatus(request.status)] : []}\n actions={\n <Stack direction=\"row\" spacing={1}>\n <Button variant=\"outlined\" startIcon={<ArrowBackRoundedIcon />} onClick={() => navigate('/ui/medplat/manage/pm/purchase-requests')}>Back</Button>\n <Button variant=\"outlined\" startIcon={<RefreshRoundedIcon />} onClick={() => void load()}>Refresh</Button>\n </Stack>\n }\n >\n {error ? <Alert severity=\"error\" sx={{ mb: 2 }}>{error}</Alert> : null}\n\n {!loading && request ? (\n <>\n {/* ---------- Summary ---------- */}\n <Card sx={{ borderRadius: 4, mb: 2, border: '1px solid', borderColor: 'divider', boxShadow: '0 12px 32px rgba(15, 23, 42, 0.045)' }}>\n <CardContent sx={{ p: 2.5 }}>\n <Stack direction={{ xs: 'column', md: 'row' }} spacing={2} alignItems={{ md: 'flex-start' }}>\n <Box sx={{ flexGrow: 1, minWidth: 0 }}>\n <Stack direction=\"row\" alignItems=\"center\" spacing={1.5} sx={{ mb: 0.5 }}>\n <PmRef id={request.serialId} />\n <Chip size=\"small\" label={prettyStatus(request.status)} color={statusChipColor(request.status)} />\n <Typography variant=\"caption\" color=\"text.secondary\">{request.ownerType}</Typography>\n </Stack>\n <Typography variant=\"h6\" sx={{ fontWeight: 800 }}>\n {request.ownerName || (request.ownerType === 'USER' ? 'Personal' : 'Facility')}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block' }}>\n For purchase date {formatDate(request.purchaseDate)}\n </Typography>\n </Box>\n <Stack spacing={0.25} sx={{ minWidth: 260 }}>\n <Row label=\"Requested by\">{request.requestedByName || `#${request.requestedBy}`}</Row>\n <Row label=\"Requested on\">{formatDateTime(request.requestedOn)}</Row>\n {request.decidedBy ? (\n <>\n <Row label=\"Decided by\">{request.decidedByName || `#${request.decidedBy}`}</Row>\n <Row label=\"Decided on\">{formatDateTime(request.decidedOn)}</Row>\n </>\n ) : null}\n {request.paymentMode ? <Row label=\"Payment\">{request.paymentMode}</Row> : null}\n </Stack>\n </Stack>\n {request.notes ? (\n <>\n <Divider sx={{ my: 1.5 }} />\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', mb: 0.5, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.6 }}>\n Requester notes\n </Typography>\n <Typography variant=\"body2\">{request.notes}</Typography>\n </>\n ) : null}\n {request.decisionNotes ? (\n <>\n <Divider sx={{ my: 1.5 }} />\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', mb: 0.5, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.6 }}>\n Decision notes\n </Typography>\n <Typography variant=\"body2\">{request.decisionNotes}</Typography>\n </>\n ) : null}\n </CardContent>\n </Card>\n\n {/* ---------- Line items ---------- */}\n <Card sx={{ borderRadius: 4, mb: 2, border: '1px solid', borderColor: 'divider', boxShadow: '0 12px 32px rgba(15, 23, 42, 0.045)' }}>\n <CardContent sx={{ p: 2.5 }}>\n <Stack direction={{ xs: 'column', md: 'row' }} alignItems={{ md: 'flex-end' }} justifyContent=\"space-between\" sx={{ mb: 1.5 }}>\n <PmFormSection\n eyebrow=\"Lines\"\n title={showDecisionForm ? 'Decide per-line quantities' : 'Requested items'}\n hint={showDecisionForm\n ? 'Enter 0 to reject an item, or less than requested to partially approve.'\n : null}\n />\n {showDecisionForm ? (\n <Stack direction=\"row\" spacing={1}>\n <Button size=\"small\" variant=\"outlined\" onClick={setAllToRequested}>Approve all</Button>\n <Button size=\"small\" variant=\"outlined\" color=\"error\" onClick={setAllToZero}>Reject all</Button>\n </Stack>\n ) : null}\n </Stack>\n\n <Table size=\"small\">\n <TableHead>\n <TableRow>\n <TableCell>Product</TableCell>\n <TableCell>Lot</TableCell>\n <TableCell>Expiry</TableCell>\n {manageAmounts ? <TableCell align=\"right\">Buy Price</TableCell> : null}\n <TableCell align=\"right\">Requested</TableCell>\n <TableCell align=\"right\">{showDecisionForm ? 'Approve' : 'Approved'}</TableCell>\n {request.ownerType === 'FACILITY' ? <TableCell>Storage</TableCell> : null}\n </TableRow>\n </TableHead>\n <TableBody>\n {request.items.map((it) => {\n const lineErr = draftErrors[it.id];\n const lotErr = lotErrors[it.id];\n const expiryErr = expiryErrors[it.id];\n const approveQty = Number(approvedDraft[it.id] ?? 0);\n const lotInputActive = showDecisionForm && Number.isFinite(approveQty) && approveQty > 0;\n return (\n <TableRow key={it.id}>\n <TableCell sx={{ fontWeight: 700 }}>{it.productName}</TableCell>\n <TableCell sx={{ fontFamily: 'monospace', fontSize: '0.78rem' }}>\n {showDecisionForm ? (\n <TextField\n size=\"small\"\n placeholder=\"Enter lot\"\n value={lotDraft[it.id] ?? ''}\n onChange={(e) => patchLot(it.id, e.target.value)}\n disabled={!lotInputActive}\n error={!!lotErr}\n helperText={lotErr || (lotInputActive ? '' : 'Approve qty > 0 to enter lot')}\n inputProps={{ style: { fontFamily: 'monospace', fontSize: '0.78rem' } }}\n sx={{ minWidth: 140 }}\n />\n ) : (it.lotNumber || '—')}\n </TableCell>\n <TableCell>\n {showDecisionForm ? (\n <TextField\n size=\"small\"\n type=\"date\"\n InputLabelProps={{ shrink: true }}\n value={expiryDraft[it.id] ?? ''}\n onChange={(e) => patchExpiry(it.id, e.target.value)}\n disabled={!lotInputActive}\n error={!!expiryErr}\n helperText={expiryErr || (lotInputActive ? '' : '')}\n sx={{ minWidth: 150 }}\n />\n ) : (it.expiryDate ? formatDate(it.expiryDate) : '—')}\n </TableCell>\n {manageAmounts ? (\n <TableCell align=\"right\">\n {it.buyPrice != null ? <PmMoney value={it.buyPrice} bold={false} /> : <Typography variant=\"caption\" color=\"text.disabled\">—</Typography>}\n </TableCell>\n ) : null}\n <TableCell align=\"right\" sx={{ fontVariantNumeric: 'tabular-nums', fontWeight: 700 }}>\n {it.requestedQuantity}\n </TableCell>\n <TableCell align=\"right\">\n {showDecisionForm ? (\n <TextField\n size=\"small\"\n type=\"number\"\n inputProps={{ min: 0, max: it.requestedQuantity, style: { textAlign: 'right' } }}\n value={approvedDraft[it.id] ?? ''}\n onChange={(e) => patchDraft(it.id, e.target.value)}\n error={!!lineErr}\n helperText={lineErr || ''}\n sx={{ maxWidth: 110 }}\n />\n ) : (\n <Typography sx={{ fontVariantNumeric: 'tabular-nums', fontWeight: 700 }}>\n {it.approvedQuantity == null ? '—' : it.approvedQuantity}\n </Typography>\n )}\n </TableCell>\n {request.ownerType === 'FACILITY' ? (\n <TableCell>{it.storageUnitName || '—'}</TableCell>\n ) : null}\n </TableRow>\n );\n })}\n </TableBody>\n </Table>\n\n {showDecisionForm ? (\n <>\n <Divider sx={{ my: 2 }} />\n <Stack direction={{ xs: 'column', md: 'row' }} spacing={2} alignItems={{ md: 'flex-start' }}>\n <TextField\n fullWidth\n size=\"small\"\n label=\"Decision notes (optional)\"\n placeholder=\"Rationale shown to the requester\"\n value={decisionNotes}\n onChange={(e) => setDecisionNotes(e.target.value)}\n multiline\n minRows={2}\n />\n {manageAmounts && approvedTotal != null ? (\n <Box sx={(t) => ({\n minWidth: 220,\n p: 1.5,\n borderRadius: 3,\n border: '1px solid',\n borderColor: 'divider',\n bgcolor: alpha(t.palette.primary.main, 0.04),\n textAlign: 'right',\n })}>\n <Typography variant=\"caption\" color=\"text.secondary\"\n sx={{ display: 'block', fontWeight: 800, textTransform: 'uppercase', letterSpacing: 0.6 }}>\n Total if approved\n </Typography>\n <PmMoney value={Number(approvedTotal.toFixed(2))} size=\"big\" />\n </Box>\n ) : null}\n </Stack>\n <Stack direction=\"row\" spacing={1} justifyContent=\"flex-end\" sx={{ mt: 2 }}>\n <Button\n variant=\"outlined\" color=\"error\" startIcon={<CancelRoundedIcon />}\n disabled={submitting}\n onClick={() => { setAllToZero(); }}\n >\n Set all to 0\n </Button>\n <Button\n variant=\"contained\" startIcon={<CheckCircleRoundedIcon />}\n disabled={submitting || !draftIsClean}\n onClick={() => void submit()}\n >\n {submitting ? 'Submitting…' : 'Submit Decision'}\n </Button>\n </Stack>\n </>\n ) : null}\n\n {/* Requester withdrawal — only on PENDING + only when the\n current user is the original requester. The backend\n enforces this too; the UI just hides the button when it's\n not applicable. */}\n {isPending && !canDecide ? (\n <Stack direction=\"row\" spacing={1} justifyContent=\"flex-end\" sx={{ mt: 2 }}>\n <Button\n variant=\"outlined\" color=\"error\" startIcon={<DoNotDisturbRoundedIcon />}\n disabled={submitting} onClick={() => void cancel()}\n >\n {submitting ? 'Cancelling…' : 'Cancel Request'}\n </Button>\n </Stack>\n ) : null}\n\n {request.approvedPurchaseId ? (\n <Alert severity=\"success\" sx={{ mt: 2 }}>\n Stock was added to inventory under purchase id <strong>{request.approvedPurchaseId}</strong>.\n </Alert>\n ) : null}\n </CardContent>\n </Card>\n </>\n ) : null}\n </PmPageShell>\n </PmGuard>\n </Box>\n );\n}\n\nfunction Row({ label, children }) {\n return (\n <Stack direction=\"row\" spacing={1} sx={{ minWidth: 0 }}>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ minWidth: 100, fontWeight: 700, textTransform: 'uppercase', letterSpacing: 0.5 }}>\n {label}\n </Typography>\n <Typography variant=\"caption\" sx={{ minWidth: 0, fontWeight: 700 }}>\n {children}\n </Typography>\n </Stack>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,265 @@
1
+ import { R as e, V as t, a as n, i as r, n as i, r as ee, t as te } from "./PmGuard-CjJBisaN.js";
2
+ import { a, i as o, o as s, t as c } from "./PmTable-BuXZQZCU.js";
3
+ import { t as l } from "./format-UOyOu75i.js";
4
+ import { useMemo as u, useState as d } from "react";
5
+ import { Fragment as ne, jsx as f, jsxs as p } from "react/jsx-runtime";
6
+ import { Alert as m, Box as h, Button as g, Chip as _, InputAdornment as v, Skeleton as y, Stack as b, Tab as x, TableBody as S, TableCell as C, TableHead as re, TableRow as w, Tabs as ie, TextField as ae, Typography as T } from "@mui/material";
7
+ import oe from "@mui/icons-material/AddRounded";
8
+ import se from "@mui/icons-material/RefreshRounded";
9
+ import { showToast as E } from "@/common/toaster/toaster";
10
+ import { useNavigate as D } from "react-router-dom";
11
+ import { alpha as O, useTheme as k } from "@mui/material/styles";
12
+ import A from "@mui/icons-material/FactCheckRounded";
13
+ import j from "@mui/icons-material/SearchRounded";
14
+ //#region src/views/PurchaseRequestsPage.jsx
15
+ var M = 3;
16
+ function N(e) {
17
+ switch (e) {
18
+ case "PENDING": return "info";
19
+ case "APPROVED": return "success";
20
+ case "PARTIALLY_APPROVED": return "warning";
21
+ case "REJECTED": return "error";
22
+ case "CANCELLED": return "default";
23
+ default: return "default";
24
+ }
25
+ }
26
+ function P(e) {
27
+ return e ? e.toLowerCase().split("_").map((e) => e.charAt(0).toUpperCase() + e.slice(1)).join(" ") : "";
28
+ }
29
+ function F() {
30
+ let F = D(), I = k(), L = r(), R = L.has("update.manage.productManagement.purchase"), z = L.has("approve.manage.productManagement.purchase"), B = L.has("view.manage.productManagement.purchase"), [V, H] = d(z && !B ? "pending" : "mine"), [U, W] = d([]), [G, ce] = d([]), [K, q] = d(!0), [J, Y] = d(""), [X, le] = d("");
31
+ async function Z() {
32
+ q(!0), Y("");
33
+ try {
34
+ let n = [];
35
+ B ? n.push(e()) : n.push(Promise.resolve([])), z ? n.push(t()) : n.push(Promise.resolve([]));
36
+ let r = await Promise.all(n);
37
+ W(r[0] ?? []), ce(r[1] ?? []);
38
+ } catch (e) {
39
+ let t = e?.response?.data?.message ?? e?.message ?? "Failed to load purchase requests";
40
+ Y(t), E({
41
+ message: t,
42
+ type: "error"
43
+ });
44
+ } finally {
45
+ q(!1);
46
+ }
47
+ }
48
+ ee(["view.manage.productManagement.purchase", "approve.manage.productManagement.purchase"], () => {
49
+ Z();
50
+ }, []);
51
+ let Q = V === "pending" ? G : U, $ = u(() => {
52
+ let e = X.trim().toLowerCase();
53
+ return e ? Q.filter((t) => {
54
+ let n = (t.items ?? []).map((e) => e.productName ?? "").join(" ");
55
+ return `${t.notes ?? ""} ${t.ownerName ?? ""} ${t.requestedByName ?? ""} ${n}`.toLowerCase().includes(e);
56
+ }) : Q;
57
+ }, [Q, X]);
58
+ return /* @__PURE__ */ p(h, { children: [/* @__PURE__ */ f(i, {}), /* @__PURE__ */ f(te, {
59
+ anyOf: ["view.manage.productManagement.purchase", "approve.manage.productManagement.purchase"],
60
+ children: /* @__PURE__ */ p(n, {
61
+ title: "Purchase Requests",
62
+ subtitle: "Purchase requests waiting for approval. A manager must confirm them before stock is added.",
63
+ actions: /* @__PURE__ */ p(b, {
64
+ direction: "row",
65
+ spacing: 1,
66
+ children: [/* @__PURE__ */ f(g, {
67
+ variant: "outlined",
68
+ startIcon: /* @__PURE__ */ f(se, {}),
69
+ onClick: () => void Z(),
70
+ children: "Refresh"
71
+ }), R ? /* @__PURE__ */ f(g, {
72
+ variant: "contained",
73
+ startIcon: /* @__PURE__ */ f(oe, {}),
74
+ onClick: () => F("/ui/medplat/manage/pm/purchases/new"),
75
+ children: "New Request"
76
+ }) : null]
77
+ }),
78
+ children: [J ? /* @__PURE__ */ f(m, {
79
+ severity: "error",
80
+ sx: { mb: 2 },
81
+ children: J
82
+ }) : null, /* @__PURE__ */ p(s, {
83
+ eyebrow: "Approvals",
84
+ title: V === "pending" ? "Pending approvals" : "My requests",
85
+ subtitle: K ? "Loading…" : `${$.length} ${$.length === 1 ? "request" : "requests"}`,
86
+ children: [/* @__PURE__ */ p(b, {
87
+ direction: {
88
+ xs: "column",
89
+ md: "row"
90
+ },
91
+ spacing: 1.5,
92
+ sx: { mb: 2 },
93
+ alignItems: { md: "center" },
94
+ children: [
95
+ /* @__PURE__ */ p(ie, {
96
+ value: V,
97
+ onChange: (e, t) => H(t),
98
+ slotProps: { indicator: { sx: { backgroundColor: I.palette.primary.main } } },
99
+ sx: { minHeight: 40 },
100
+ children: [B ? /* @__PURE__ */ f(x, {
101
+ value: "mine",
102
+ label: `My requests${U.length ? ` (${U.length})` : ""}`,
103
+ sx: {
104
+ minHeight: 40,
105
+ textTransform: "none",
106
+ fontWeight: 700
107
+ }
108
+ }) : null, z ? /* @__PURE__ */ f(x, {
109
+ value: "pending",
110
+ label: `Pending${G.length ? ` (${G.length})` : ""}`,
111
+ sx: {
112
+ minHeight: 40,
113
+ textTransform: "none",
114
+ fontWeight: 700
115
+ }
116
+ }) : null]
117
+ }),
118
+ /* @__PURE__ */ f(h, { sx: { flexGrow: 1 } }),
119
+ /* @__PURE__ */ f(ae, {
120
+ size: "small",
121
+ fullWidth: !0,
122
+ placeholder: "Search by owner, requester, item, notes…",
123
+ value: X,
124
+ onChange: (e) => le(e.target.value),
125
+ sx: { maxWidth: { md: 360 } },
126
+ InputProps: { startAdornment: /* @__PURE__ */ f(v, {
127
+ position: "start",
128
+ children: /* @__PURE__ */ f(j, { fontSize: "small" })
129
+ }) }
130
+ })
131
+ ]
132
+ }), /* @__PURE__ */ p(a, {
133
+ dense: !0,
134
+ children: [/* @__PURE__ */ f(re, { children: /* @__PURE__ */ p(w, { children: [
135
+ /* @__PURE__ */ f(C, { children: "Ref" }),
136
+ /* @__PURE__ */ f(C, { children: "Date" }),
137
+ /* @__PURE__ */ f(C, { children: "Owner" }),
138
+ /* @__PURE__ */ f(C, { children: "Items" }),
139
+ /* @__PURE__ */ f(C, { children: "Requester" }),
140
+ /* @__PURE__ */ f(C, { children: "Decision" }),
141
+ /* @__PURE__ */ f(C, { children: "Status" })
142
+ ] }) }), /* @__PURE__ */ f(S, { children: K ? Array.from({ length: 4 }).map((e, t) => /* @__PURE__ */ f(w, { children: Array.from({ length: 7 }).map((e, t) => /* @__PURE__ */ f(C, { children: /* @__PURE__ */ f(y, { height: 22 }) }, t)) }, t)) : $.length === 0 ? /* @__PURE__ */ f(c, {
143
+ colSpan: 7,
144
+ icon: A,
145
+ title: X.trim() === "" ? V === "pending" ? "No pending approvals" : "No requests yet" : "No requests match your search",
146
+ hint: V === "pending" ? "Purchases needing your approval will appear here." : "Your submitted requests will appear here."
147
+ }) : $.map((e) => {
148
+ let t = e.items ?? [], n = t.slice(0, M), r = t.length - n.length;
149
+ return /* @__PURE__ */ p(w, {
150
+ hover: !0,
151
+ sx: { cursor: "pointer" },
152
+ onClick: () => F(`/ui/medplat/manage/pm/purchase-requests/${e.id}`),
153
+ children: [
154
+ /* @__PURE__ */ f(C, { children: /* @__PURE__ */ f(o, { id: e.serialId }) }),
155
+ /* @__PURE__ */ p(C, { children: [/* @__PURE__ */ f(T, {
156
+ variant: "body2",
157
+ sx: { fontWeight: 700 },
158
+ children: l(e.purchaseDate)
159
+ }), /* @__PURE__ */ p(T, {
160
+ variant: "caption",
161
+ color: "text.secondary",
162
+ children: ["Submitted ", l(e.requestedOn)]
163
+ })] }),
164
+ /* @__PURE__ */ p(C, { children: [/* @__PURE__ */ f(T, {
165
+ variant: "body2",
166
+ sx: { fontWeight: 700 },
167
+ children: e.ownerName || (e.ownerType === "USER" ? "Personal" : "Facility")
168
+ }), /* @__PURE__ */ f(T, {
169
+ variant: "caption",
170
+ color: "text.secondary",
171
+ children: e.ownerType
172
+ })] }),
173
+ /* @__PURE__ */ f(C, {
174
+ sx: { maxWidth: 360 },
175
+ children: t.length === 0 ? /* @__PURE__ */ f(T, {
176
+ variant: "caption",
177
+ color: "text.disabled",
178
+ children: "—"
179
+ }) : /* @__PURE__ */ p(b, {
180
+ direction: "row",
181
+ spacing: .5,
182
+ flexWrap: "wrap",
183
+ useFlexGap: !0,
184
+ children: [n.map((e) => /* @__PURE__ */ f(_, {
185
+ size: "small",
186
+ label: /* @__PURE__ */ p(h, {
187
+ component: "span",
188
+ sx: {
189
+ display: "inline-flex",
190
+ alignItems: "baseline",
191
+ gap: .5
192
+ },
193
+ children: [/* @__PURE__ */ f(h, {
194
+ component: "span",
195
+ sx: { fontWeight: 700 },
196
+ children: e.productName ?? "—"
197
+ }), /* @__PURE__ */ p(h, {
198
+ component: "span",
199
+ sx: {
200
+ fontWeight: 700,
201
+ fontVariantNumeric: "tabular-nums",
202
+ color: "text.secondary"
203
+ },
204
+ children: ["×", e.approvedQuantity == null ? e.requestedQuantity : e.approvedQuantity]
205
+ })]
206
+ }),
207
+ sx: {
208
+ height: 22,
209
+ borderRadius: 1.5,
210
+ bgcolor: O(I.palette.primary.main, .06),
211
+ color: "text.primary",
212
+ border: `1px solid ${O(I.palette.primary.main, .16)}`,
213
+ "& .MuiChip-label": { px: .85 }
214
+ }
215
+ }, e.id)), r > 0 ? /* @__PURE__ */ f(_, {
216
+ size: "small",
217
+ label: `+${r} more`,
218
+ sx: {
219
+ height: 22,
220
+ borderRadius: 1.5,
221
+ bgcolor: "transparent",
222
+ color: "text.secondary",
223
+ border: `1px dashed ${I.palette.divider}`,
224
+ "& .MuiChip-label": {
225
+ px: .85,
226
+ fontWeight: 700
227
+ }
228
+ }
229
+ }) : null]
230
+ })
231
+ }),
232
+ /* @__PURE__ */ f(C, { children: /* @__PURE__ */ f(T, {
233
+ variant: "body2",
234
+ children: e.requestedByName || `#${e.requestedBy}`
235
+ }) }),
236
+ /* @__PURE__ */ f(C, { children: e.decidedOn ? /* @__PURE__ */ p(ne, { children: [/* @__PURE__ */ f(T, {
237
+ variant: "body2",
238
+ sx: { fontWeight: 700 },
239
+ children: e.decidedByName || `#${e.decidedBy}`
240
+ }), /* @__PURE__ */ f(T, {
241
+ variant: "caption",
242
+ color: "text.secondary",
243
+ children: l(e.decidedOn)
244
+ })] }) : /* @__PURE__ */ f(T, {
245
+ variant: "caption",
246
+ color: "text.disabled",
247
+ children: "—"
248
+ }) }),
249
+ /* @__PURE__ */ f(C, { children: /* @__PURE__ */ f(_, {
250
+ size: "small",
251
+ label: P(e.status),
252
+ color: N(e.status)
253
+ }) })
254
+ ]
255
+ }, e.id);
256
+ }) })]
257
+ })]
258
+ })]
259
+ })
260
+ })] });
261
+ }
262
+ //#endregion
263
+ export { F as default };
264
+
265
+ //# sourceMappingURL=PurchaseRequestsPage-DvFH_tWe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PurchaseRequestsPage-DvFH_tWe.js","names":[],"sources":["../src/views/PurchaseRequestsPage.jsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n Alert,\n Box,\n Button,\n Chip,\n InputAdornment,\n Skeleton,\n Stack,\n Tab,\n Tabs,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n TextField,\n Typography,\n} from '@mui/material';\nimport { alpha, useTheme } from '@mui/material/styles';\nimport AddRoundedIcon from '@mui/icons-material/AddRounded';\nimport RefreshRoundedIcon from '@mui/icons-material/RefreshRounded';\nimport SearchRoundedIcon from '@mui/icons-material/SearchRounded';\nimport FactCheckRoundedIcon from '@mui/icons-material/FactCheckRounded';\nimport { showToast } from '@/common/toaster/toaster';\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 PmEmptyRow,\n PmRef,\n PmTable,\n PmTableCard,\n} from '@pm/components/PmTable';\nimport {\n listMyPurchaseRequests,\n listPendingPurchaseRequests,\n} from '@pm/services/pmApi';\nimport { formatDate } from '@pm/utils/format';\n\n// Compact one-liner of items + qty for the table. Up to MAX_ITEMS_INLINE\n// items render as inline pills; anything beyond gets a \"+N more\" pill so\n// the row height stays stable.\nconst MAX_ITEMS_INLINE = 3;\n\n// Visual mapping for the lifecycle states. Pending sits in info-blue while a\n// decision is awaited; approved/partial use success/warning to signal the\n// terminal verdict; rejected/cancelled drop to muted defaults.\nfunction statusChipColor(status) {\n switch (status) {\n case 'PENDING': return 'info';\n case 'APPROVED': return 'success';\n case 'PARTIALLY_APPROVED': return 'warning';\n case 'REJECTED': return 'error';\n case 'CANCELLED': return 'default';\n default: return 'default';\n }\n}\n\nfunction prettyStatus(status) {\n if (!status) return '';\n return status\n .toLowerCase()\n .split('_')\n .map((p) => p.charAt(0).toUpperCase() + p.slice(1))\n .join(' ');\n}\n\nexport default function PurchaseRequestsPage() {\n const navigate = useNavigate();\n const theme = useTheme();\n const perms = usePmPermissions();\n const canSubmit = perms.has('update.manage.productManagement.purchase');\n const canApprove = perms.has('approve.manage.productManagement.purchase');\n const canView = perms.has('view.manage.productManagement.purchase');\n // Default tab follows the user's role:\n // - Approver-only (no view perm) lands directly on Pending — they don't\n // have a \"My Requests\" tab to see anyway.\n // - Anyone else (view perm, or both) lands on My Requests.\n const [tab, setTab] = useState(canApprove && !canView ? 'pending' : 'mine');\n const [mine, setMine] = useState([]);\n const [pending, setPending] = useState([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState('');\n const [search, setSearch] = useState('');\n\n async function load() {\n setLoading(true);\n setError('');\n try {\n // Mine fetched when the user has view perm; Pending when they have\n // approve perm. Each side is independent — an approver-only role\n // never fetches /mine, a viewer-only role never fetches /pending.\n const calls = [];\n if (canView) calls.push(listMyPurchaseRequests());\n else calls.push(Promise.resolve([]));\n if (canApprove) calls.push(listPendingPurchaseRequests());\n else calls.push(Promise.resolve([]));\n const results = await Promise.all(calls);\n setMine(results[0] ?? []);\n setPending(results[1] ?? []);\n } catch (err) {\n const message = err?.response?.data?.message ?? err?.message ?? 'Failed to load purchase requests';\n setError(message);\n showToast({ message, type: 'error' });\n } finally {\n setLoading(false);\n }\n }\n\n usePermissionedEffect(\n ['view.manage.productManagement.purchase', 'approve.manage.productManagement.purchase'],\n () => { void load(); },\n [],\n );\n\n const rows = tab === 'pending' ? pending : mine;\n const filteredRows = useMemo(() => {\n const q = search.trim().toLowerCase();\n if (!q) return rows;\n return rows.filter((r) => {\n const itemNames = (r.items ?? []).map((i) => i.productName ?? '').join(' ');\n const hay = `${r.notes ?? ''} ${r.ownerName ?? ''} ${r.requestedByName ?? ''} ${itemNames}`.toLowerCase();\n return hay.includes(q);\n });\n }, [rows, search]);\n\n return (\n <Box>\n <PmNav />\n <PmGuard anyOf={['view.manage.productManagement.purchase', 'approve.manage.productManagement.purchase']}>\n <PmPageShell\n title=\"Purchase Requests\"\n subtitle=\"Purchase requests waiting for approval. A manager must confirm them before stock is added.\"\n actions={\n <Stack direction=\"row\" spacing={1}>\n <Button variant=\"outlined\" startIcon={<RefreshRoundedIcon />} onClick={() => void load()}>Refresh</Button>\n {canSubmit ? (\n <Button variant=\"contained\" startIcon={<AddRoundedIcon />}\n onClick={() => navigate('/ui/medplat/manage/pm/purchases/new')}>\n New Request\n </Button>\n ) : null}\n </Stack>\n }\n >\n {error ? <Alert severity=\"error\" sx={{ mb: 2 }}>{error}</Alert> : null}\n\n <PmTableCard\n eyebrow=\"Approvals\"\n title={tab === 'pending' ? 'Pending approvals' : 'My requests'}\n subtitle={loading\n ? 'Loading…'\n : `${filteredRows.length} ${filteredRows.length === 1 ? 'request' : 'requests'}`}\n >\n <Stack direction={{ xs: 'column', md: 'row' }} spacing={1.5} sx={{ mb: 2 }} alignItems={{ md: 'center' }}>\n <Tabs\n value={tab}\n onChange={(_, v) => setTab(v)}\n slotProps={{ indicator: { sx: { backgroundColor: theme.palette.primary.main } } }}\n sx={{ minHeight: 40 }}\n >\n {/* Tabs follow perms:\n - My Requests: only when the user has the view perm.\n - Pending: only when the user has the approve perm.\n An approver-only role sees just the Pending tab. */}\n {canView ? (\n <Tab value=\"mine\" label={`My requests${mine.length ? ` (${mine.length})` : ''}`} sx={{ minHeight: 40, textTransform: 'none', fontWeight: 700 }} />\n ) : null}\n {canApprove ? (\n <Tab value=\"pending\" label={`Pending${pending.length ? ` (${pending.length})` : ''}`} sx={{ minHeight: 40, textTransform: 'none', fontWeight: 700 }} />\n ) : null}\n </Tabs>\n <Box sx={{ flexGrow: 1 }} />\n <TextField\n size=\"small\"\n fullWidth\n placeholder=\"Search by owner, requester, item, notes…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n sx={{ maxWidth: { md: 360 } }}\n InputProps={{\n startAdornment: (\n <InputAdornment position=\"start\">\n <SearchRoundedIcon fontSize=\"small\" />\n </InputAdornment>\n ),\n }}\n />\n </Stack>\n\n <PmTable dense>\n <TableHead>\n <TableRow>\n <TableCell>Ref</TableCell>\n <TableCell>Date</TableCell>\n <TableCell>Owner</TableCell>\n <TableCell>Items</TableCell>\n <TableCell>Requester</TableCell>\n <TableCell>Decision</TableCell>\n <TableCell>Status</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {loading ? (\n Array.from({ length: 4 }).map((_, i) => (\n <TableRow key={i}>\n {Array.from({ length: 7 }).map((__, j) => (\n <TableCell key={j}><Skeleton height={22} /></TableCell>\n ))}\n </TableRow>\n ))\n ) : filteredRows.length === 0 ? (\n <PmEmptyRow\n colSpan={7}\n icon={FactCheckRoundedIcon}\n title={search.trim() !== ''\n ? 'No requests match your search'\n : tab === 'pending'\n ? 'No pending approvals'\n : 'No requests yet'}\n hint={tab === 'pending'\n ? 'Purchases needing your approval will appear here.'\n : 'Your submitted requests will appear here.'}\n />\n ) : filteredRows.map((r) => {\n const items = r.items ?? [];\n const visibleItems = items.slice(0, MAX_ITEMS_INLINE);\n const overflow = items.length - visibleItems.length;\n return (\n <TableRow\n key={r.id}\n hover\n sx={{ cursor: 'pointer' }}\n onClick={() => navigate(`/ui/medplat/manage/pm/purchase-requests/${r.id}`)}\n >\n <TableCell><PmRef id={r.serialId} /></TableCell>\n <TableCell>\n <Typography variant=\"body2\" sx={{ fontWeight: 700 }}>{formatDate(r.purchaseDate)}</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n Submitted {formatDate(r.requestedOn)}\n </Typography>\n </TableCell>\n <TableCell>\n <Typography variant=\"body2\" sx={{ fontWeight: 700 }}>\n {r.ownerName || (r.ownerType === 'USER' ? 'Personal' : 'Facility')}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {r.ownerType}\n </Typography>\n </TableCell>\n <TableCell sx={{ maxWidth: 360 }}>\n {items.length === 0 ? (\n <Typography variant=\"caption\" color=\"text.disabled\">—</Typography>\n ) : (\n <Stack direction=\"row\" spacing={0.5} flexWrap=\"wrap\" useFlexGap>\n {visibleItems.map((it) => (\n <Chip\n key={it.id}\n size=\"small\"\n label={\n <Box component=\"span\" sx={{ display: 'inline-flex', alignItems: 'baseline', gap: 0.5 }}>\n <Box component=\"span\" sx={{ fontWeight: 700 }}>{it.productName ?? '—'}</Box>\n <Box component=\"span\" sx={{ fontWeight: 700, fontVariantNumeric: 'tabular-nums', color: 'text.secondary' }}>\n ×{it.approvedQuantity != null ? it.approvedQuantity : it.requestedQuantity}\n </Box>\n </Box>\n }\n sx={{\n height: 22,\n borderRadius: 1.5,\n bgcolor: alpha(theme.palette.primary.main, 0.06),\n color: 'text.primary',\n border: `1px solid ${alpha(theme.palette.primary.main, 0.16)}`,\n '& .MuiChip-label': { px: 0.85 },\n }}\n />\n ))}\n {overflow > 0 ? (\n <Chip\n size=\"small\"\n label={`+${overflow} more`}\n sx={{\n height: 22,\n borderRadius: 1.5,\n bgcolor: 'transparent',\n color: 'text.secondary',\n border: `1px dashed ${theme.palette.divider}`,\n '& .MuiChip-label': { px: 0.85, fontWeight: 700 },\n }}\n />\n ) : null}\n </Stack>\n )}\n </TableCell>\n <TableCell>\n <Typography variant=\"body2\">{r.requestedByName || `#${r.requestedBy}`}</Typography>\n </TableCell>\n <TableCell>\n {r.decidedOn ? (\n <>\n <Typography variant=\"body2\" sx={{ fontWeight: 700 }}>\n {r.decidedByName || `#${r.decidedBy}`}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {formatDate(r.decidedOn)}\n </Typography>\n </>\n ) : (\n <Typography variant=\"caption\" color=\"text.disabled\">—</Typography>\n )}\n </TableCell>\n <TableCell>\n <Chip size=\"small\" label={prettyStatus(r.status)} color={statusChipColor(r.status)} />\n </TableCell>\n </TableRow>\n );\n })}\n </TableBody>\n </PmTable>\n </PmTableCard>\n </PmPageShell>\n </PmGuard>\n </Box>\n );\n}\n"],"mappings":"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"}