@argusoft/medplat-product-management 1.0.0 → 1.0.2

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 (77) hide show
  1. package/dist/BrandsPage-CSA3meke.js +385 -0
  2. package/dist/BrandsPage-CSA3meke.js.map +1 -0
  3. package/dist/CategoriesPage-BrspzkJL.js +340 -0
  4. package/dist/CategoriesPage-BrspzkJL.js.map +1 -0
  5. package/dist/{DashboardPage-BNKUQj46.js → DashboardPage-CqaquOs2.js} +21 -22
  6. package/dist/{DashboardPage-BNKUQj46.js.map → DashboardPage-CqaquOs2.js.map} +1 -1
  7. package/dist/{FacilityPicker-Coi8I3yE.js → FacilityPicker-Dv_H95WW.js} +13 -13
  8. package/dist/{FacilityPicker-Coi8I3yE.js.map → FacilityPicker-Dv_H95WW.js.map} +1 -1
  9. package/dist/{InventoryPage-BR6jOzg2.js → InventoryPage-CPbzfDMR.js} +12 -12
  10. package/dist/{InventoryPage-BR6jOzg2.js.map → InventoryPage-CPbzfDMR.js.map} +1 -1
  11. package/dist/{MemberProfileCard-DbHZCS5n.js → MemberProfileCard-0vjO3Gzd.js} +2 -2
  12. package/dist/{MemberProfileCard-DbHZCS5n.js.map → MemberProfileCard-0vjO3Gzd.js.map} +1 -1
  13. package/dist/{PaymentCreatePage-Ci3ERnby.js → PaymentCreatePage-BYmDZAIB.js} +9 -10
  14. package/dist/{PaymentCreatePage-Ci3ERnby.js.map → PaymentCreatePage-BYmDZAIB.js.map} +1 -1
  15. package/dist/{PaymentsPage-sdg902zX.js → PaymentsPage-BXPvKon-.js} +16 -16
  16. package/dist/{PaymentsPage-sdg902zX.js.map → PaymentsPage-BXPvKon-.js.map} +1 -1
  17. package/dist/PickupCreatePage-CMGwoAXj.js +426 -0
  18. package/dist/PickupCreatePage-CMGwoAXj.js.map +1 -0
  19. package/dist/{PickupsPage-Ci2Ll0Kn.js → PickupsPage-D66_Wta4.js} +84 -39
  20. package/dist/PickupsPage-D66_Wta4.js.map +1 -0
  21. package/dist/PmTable-B9970kPY.js +375 -0
  22. package/dist/PmTable-B9970kPY.js.map +1 -0
  23. package/dist/{ProductEditPage-DL8gy85Y.js → ProductEditPage-B8qFTCW9.js} +226 -243
  24. package/dist/ProductEditPage-B8qFTCW9.js.map +1 -0
  25. package/dist/ProductsPage-C7_r9cKn.js +254 -0
  26. package/dist/ProductsPage-C7_r9cKn.js.map +1 -0
  27. package/dist/{PurchaseCreatePage-C3KMfBxJ.js → PurchaseCreatePage-CDfNDcKG.js} +150 -149
  28. package/dist/PurchaseCreatePage-CDfNDcKG.js.map +1 -0
  29. package/dist/{PurchaseRequestDetailPage-C0GYFJDl.js → PurchaseRequestDetailPage-C7aAwEqw.js} +15 -15
  30. package/dist/{PurchaseRequestDetailPage-C0GYFJDl.js.map → PurchaseRequestDetailPage-C7aAwEqw.js.map} +1 -1
  31. package/dist/{PurchaseRequestsPage-DvFH_tWe.js → PurchaseRequestsPage-BwCkbpaX.js} +14 -14
  32. package/dist/{PurchaseRequestsPage-DvFH_tWe.js.map → PurchaseRequestsPage-BwCkbpaX.js.map} +1 -1
  33. package/dist/{PurchasesPage-BCvLvSp4.js → PurchasesPage-CvaZouVy.js} +11 -12
  34. package/dist/{PurchasesPage-BCvLvSp4.js.map → PurchasesPage-CvaZouVy.js.map} +1 -1
  35. package/dist/{SaleCreatePage-DpkQMoTq.js → SaleCreatePage-DP1Qmltu.js} +30 -31
  36. package/dist/{SaleCreatePage-DpkQMoTq.js.map → SaleCreatePage-DP1Qmltu.js.map} +1 -1
  37. package/dist/{SalesPage-DUwgkEO-.js → SalesPage-CO3cdYX5.js} +18 -19
  38. package/dist/{SalesPage-DUwgkEO-.js.map → SalesPage-CO3cdYX5.js.map} +1 -1
  39. package/dist/{SettingsPage-CusC0jqJ.js → SettingsPage-DvVRwSFw.js} +104 -103
  40. package/dist/SettingsPage-DvVRwSFw.js.map +1 -0
  41. package/dist/StorageUnitsPage-B9Hr_RkW.js +470 -0
  42. package/dist/StorageUnitsPage-B9Hr_RkW.js.map +1 -0
  43. package/dist/{TransactionsPage-DDaK4VyY.js → TransactionsPage-HKIGwEZN.js} +127 -123
  44. package/dist/TransactionsPage-HKIGwEZN.js.map +1 -0
  45. package/dist/{TransferCreatePage-BxudLfhS.js → TransferCreatePage-DMuZqQ3c.js} +9 -9
  46. package/dist/{TransferCreatePage-BxudLfhS.js.map → TransferCreatePage-DMuZqQ3c.js.map} +1 -1
  47. package/dist/{TransfersPage-zgmt7teZ.js → TransfersPage-COIyouL4.js} +16 -16
  48. package/dist/{TransfersPage-zgmt7teZ.js.map → TransfersPage-COIyouL4.js.map} +1 -1
  49. package/dist/{VialsPage-CjqPfgpV.js → VialsPage-BNPUwGCU.js} +291 -224
  50. package/dist/VialsPage-BNPUwGCU.js.map +1 -0
  51. package/dist/{constants-BrA_hfAI.js → constants-5ZCZo-Zm.js} +5 -2
  52. package/dist/{constants-BrA_hfAI.js.map → constants-5ZCZo-Zm.js.map} +1 -1
  53. package/dist/{PmGuard-CjJBisaN.js → currency-ClRLIEg2.js} +186 -9
  54. package/dist/currency-ClRLIEg2.js.map +1 -0
  55. package/dist/index.js +1 -1
  56. package/package.json +1 -1
  57. package/dist/BrandsPage-DCMCVvDY.js +0 -334
  58. package/dist/BrandsPage-DCMCVvDY.js.map +0 -1
  59. package/dist/CategoriesPage-BpRhwfrc.js +0 -284
  60. package/dist/CategoriesPage-BpRhwfrc.js.map +0 -1
  61. package/dist/PickupCreatePage-CieMsgWV.js +0 -310
  62. package/dist/PickupCreatePage-CieMsgWV.js.map +0 -1
  63. package/dist/PickupsPage-Ci2Ll0Kn.js.map +0 -1
  64. package/dist/PmGuard-CjJBisaN.js.map +0 -1
  65. package/dist/PmTable-BuXZQZCU.js +0 -302
  66. package/dist/PmTable-BuXZQZCU.js.map +0 -1
  67. package/dist/ProductEditPage-DL8gy85Y.js.map +0 -1
  68. package/dist/ProductsPage-BANTKxLb.js +0 -221
  69. package/dist/ProductsPage-BANTKxLb.js.map +0 -1
  70. package/dist/PurchaseCreatePage-C3KMfBxJ.js.map +0 -1
  71. package/dist/SettingsPage-CusC0jqJ.js.map +0 -1
  72. package/dist/StorageUnitsPage-BlC2AgrJ.js +0 -469
  73. package/dist/StorageUnitsPage-BlC2AgrJ.js.map +0 -1
  74. package/dist/TransactionsPage-DDaK4VyY.js.map +0 -1
  75. package/dist/VialsPage-CjqPfgpV.js.map +0 -1
  76. package/dist/currency-BDDCDgeE.js +0 -169
  77. package/dist/currency-BDDCDgeE.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TransactionsPage-HKIGwEZN.js","names":[],"sources":["../src/views/TransactionsPage.jsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport {\n Alert,\n Autocomplete,\n Box,\n Button,\n Chip,\n FormControl,\n IconButton,\n InputLabel,\n MenuItem,\n Select,\n Skeleton,\n Stack,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n TextField,\n Tooltip,\n Typography,\n} from '@mui/material';\nimport { alpha, useTheme } from '@mui/material/styles';\nimport RefreshRoundedIcon from '@mui/icons-material/RefreshRounded';\nimport ReceiptLongRoundedIcon from '@mui/icons-material/ReceiptLongRounded';\nimport ChevronLeftRoundedIcon from '@mui/icons-material/ChevronLeftRounded';\nimport ChevronRightRoundedIcon from '@mui/icons-material/ChevronRightRounded';\nimport CallMadeRoundedIcon from '@mui/icons-material/CallMadeRounded';\nimport CallReceivedRoundedIcon from '@mui/icons-material/CallReceivedRounded';\nimport SwapHorizRoundedIcon from '@mui/icons-material/SwapHorizRounded';\nimport VaccinesRoundedIcon from '@mui/icons-material/VaccinesRounded';\nimport ShoppingCartRoundedIcon from '@mui/icons-material/ShoppingCartRounded';\nimport PointOfSaleRoundedIcon from '@mui/icons-material/PointOfSaleRounded';\nimport PaymentsRoundedIcon from '@mui/icons-material/PaymentsRounded';\nimport ReportRoundedIcon from '@mui/icons-material/ReportRounded';\nimport BlockRoundedIcon from '@mui/icons-material/BlockRounded';\nimport LockOpenRoundedIcon from '@mui/icons-material/LockOpenRounded';\nimport MoveDownRoundedIcon from '@mui/icons-material/MoveDownRounded';\nimport FactCheckRoundedIcon from '@mui/icons-material/FactCheckRounded';\nimport CancelRoundedIcon from '@mui/icons-material/CancelRounded';\nimport CheckCircleRoundedIcon from '@mui/icons-material/CheckCircleRounded';\nimport HourglassEmptyRoundedIcon from '@mui/icons-material/HourglassEmptyRounded';\nimport SearchRoundedIcon from '@mui/icons-material/SearchRounded';\nimport PictureAsPdfRoundedIcon from '@mui/icons-material/PictureAsPdfRounded';\nimport InsertDriveFileRoundedIcon from '@mui/icons-material/InsertDriveFileRounded';\nimport { showToast } from '@/common/toaster/toaster';\nimport useDownloadPdf from '@/hooks/useDownloadPdf';\nimport { useDownloadXlsx } from '@/hooks/useDownloadXlsx';\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 PmTable,\n PmTableCard,\n} from '@pm/components/PmTable';\nimport { queryTransactions } from '@pm/services/pmApi';\nimport { formatDateTime, formatNumber } from '@pm/utils/format';\nimport { SYNC_STATUSES, labelOf } from '@pm/utils/constants';\n\n// Per-type visual: chip colour + icon. The icon turns the type column from a\n// flat text label into something the operator can scan with peripheral vision.\nconst TYPE_META = {\n RECEIPT: { color: 'success', icon: CallReceivedRoundedIcon, label: 'Receipt' },\n VIAL_OPENED: { color: 'info', icon: VaccinesRoundedIcon, label: 'Vial opened' },\n ADMINISTRATION: { color: 'primary', icon: VaccinesRoundedIcon, label: 'Administration' },\n WASTAGE: { color: 'warning', icon: ReportRoundedIcon, label: 'Wastage' },\n EXPIRY: { color: 'warning', icon: ReportRoundedIcon, label: 'Expiry' },\n SALE: { color: 'success', icon: PointOfSaleRoundedIcon, label: 'Sale' },\n PAYMENT: { color: 'success', icon: PaymentsRoundedIcon, label: 'Payment' },\n QUARANTINE: { color: 'error', icon: BlockRoundedIcon, label: 'Quarantine' },\n RECALL: { color: 'error', icon: BlockRoundedIcon, label: 'Recall' },\n UNQUARANTINE: { color: 'info', icon: LockOpenRoundedIcon, label: 'Unquarantine' },\n TRANSFER_OUT: { color: 'default', icon: CallMadeRoundedIcon, label: 'Transfer out' },\n TRANSFER_IN: { color: 'default', icon: SwapHorizRoundedIcon, label: 'Transfer in' },\n PICKUP_OUT: { color: 'default', icon: MoveDownRoundedIcon, label: 'Pickup — out' },\n PICKUP_IN: { color: 'default', icon: MoveDownRoundedIcon, label: 'Pickup — in' },\n TOPUP_OUT: { color: 'default', icon: MoveDownRoundedIcon, label: 'Top-up — out' },\n TOPUP_IN: { color: 'default', icon: MoveDownRoundedIcon, label: 'Top-up — in' },\n RETURN_OUT: { color: 'default', icon: MoveDownRoundedIcon, label: 'Return — out' },\n RETURN_IN: { color: 'default', icon: MoveDownRoundedIcon, label: 'Return — in' },\n PURCHASE_REQUEST_SUBMITTED: { color: 'info', icon: HourglassEmptyRoundedIcon, label: 'Request submitted' },\n PURCHASE_REQUEST_APPROVED: { color: 'success', icon: CheckCircleRoundedIcon, label: 'Request approved' },\n PURCHASE_REQUEST_PARTIAL: { color: 'warning', icon: FactCheckRoundedIcon, label: 'Request partial' },\n PURCHASE_REQUEST_REJECTED: { color: 'error', icon: CancelRoundedIcon, label: 'Request rejected' },\n PURCHASE_REQUEST_CANCELLED: { color: 'default', icon: CancelRoundedIcon, label: 'Request cancelled' },\n};\n\nfunction TypeChip({ type }) {\n const meta = TYPE_META[type] || { color: 'default', icon: ShoppingCartRoundedIcon, label: type };\n const Icon = meta.icon;\n return (\n <Chip\n size=\"small\"\n color={meta.color}\n icon={<Icon sx={{ fontSize: '1rem !important' }} />}\n label={meta.label}\n sx={{\n fontWeight: 700,\n height: 24,\n borderRadius: 1.5,\n '& .MuiChip-icon': { ml: 0.75, mr: -0.25 },\n }}\n />\n );\n}\n\nfunction SyncChip({ status }) {\n const color = status === 'COMPLETED' ? 'success' : status === 'FAILED' ? 'error' : 'warning';\n return (\n <Chip\n size=\"small\"\n label={labelOf(SYNC_STATUSES, status)}\n color={color}\n variant=\"outlined\"\n sx={{ fontWeight: 700, height: 22, borderRadius: 1.5, fontSize: '0.7rem' }}\n />\n );\n}\n\n// Type options for the filter Autocomplete — pulled from TYPE_META so any\n// new types automatically show up in the dropdown without extra wiring.\nconst TYPE_OPTIONS = Object.keys(TYPE_META).map((value) => ({\n value,\n label: TYPE_META[value].label,\n}));\n\nexport default function TransactionsPage() {\n const theme = useTheme();\n const downloadPdf = useDownloadPdf();\n const downloadXlsx = useDownloadXlsx();\n const [items, setItems] = useState([]);\n const [totalElements, setTotalElements] = useState(0);\n const [page, setPage] = useState(0);\n const [pageSize, setPageSize] = useState(50);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState('');\n // Filter state — fed into the query on every load. The \"applied\" snapshot\n // is what was last submitted; the \"draft\" version is the in-progress\n // values bound to the inputs so typing doesn't fire a request per\n // keystroke.\n const [filters, setFilters] = useState({\n dateFrom: '', dateTo: '', types: [], search: '', ownerType: '',\n });\n\n async function load(p = page, size = pageSize, f = filters) {\n setLoading(true);\n setError('');\n try {\n const data = await queryTransactions({\n page: p,\n size,\n dateFrom: f.dateFrom ? new Date(f.dateFrom).toISOString() : undefined,\n // Inclusive end-of-day: send the end timestamp at 23:59:59 so the\n // user's \"today\" filter captures everything that happened today.\n dateTo: f.dateTo ? new Date(`${f.dateTo}T23:59:59`).toISOString() : undefined,\n types: f.types.length > 0 ? f.types : undefined,\n ownerType: f.ownerType || undefined,\n search: f.search?.trim() || undefined,\n });\n setItems(data.content ?? []);\n setTotalElements(data.totalElements ?? 0);\n setPage(data.page ?? 0);\n setPageSize(data.size ?? size);\n } catch (err) {\n const message = err?.response?.data?.message ?? err?.message ?? 'Failed to load ledger';\n setError(message);\n showToast({ message, type: 'error' });\n } finally {\n setLoading(false);\n }\n }\n\n usePermissionedEffect('view.manage.productManagement.ledger', () => {\n void load(0, pageSize, filters);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const startIdx = totalElements === 0 ? 0 : page * pageSize + 1;\n const endIdx = page * pageSize + items.length;\n const totalPages = pageSize > 0 ? Math.ceil(totalElements / pageSize) : 0;\n\n // ISO yyyy-mm-dd strings compare lexicographically, so a plain string compare\n // is enough to catch a To date that lands before the From date.\n const dateRangeError = filters.dateFrom && filters.dateTo && filters.dateTo < filters.dateFrom\n ? 'To date cannot be before From date.'\n : '';\n\n function applyFilters(next) {\n if (next.dateFrom && next.dateTo && next.dateTo < next.dateFrom) return;\n setFilters(next);\n void load(0, pageSize, next);\n }\n\n function resetFilters() {\n const blank = { dateFrom: '', dateTo: '', types: [], search: '', ownerType: '' };\n setFilters(blank);\n void load(0, pageSize, blank);\n }\n\n // Flatten the current page into a column-mapped shape the download\n // hooks can consume. Strings only — both hooks call toString() on values\n // for cell rendering, so we pre-format here so the file matches the UI.\n const exportColumns = ['Time', 'Type', 'Owner', 'Product', 'Vaccine', 'Lot', 'Qty', 'Volume', 'Money', 'Notes'];\n const exportKeys = ['time', 'type', 'owner', 'product', 'vaccine', 'lot', 'qty', 'volume', 'money', 'notes'];\n const exportData = useMemo(() => items.map((t) => ({\n time: t.transactionTime ? formatDateTime(t.transactionTime) : '',\n type: TYPE_META[t.transactionType]?.label ?? t.transactionType ?? '',\n owner: `${t.ownerName ?? (t.ownerType === 'USER' ? 'Personal' : 'Facility')} (${t.ownerType ?? '—'})`,\n product: t.productName ?? '',\n vaccine: t.vaccineCode ?? '',\n lot: t.lotNumber ?? '',\n qty: t.quantity ?? '',\n volume: t.volumeMl != null ? `${formatNumber(t.volumeMl)} ml` : '',\n money: t.monetaryAmount != null ? formatNumber(t.monetaryAmount) : '',\n notes: t.notes ?? '',\n })), [items]);\n\n function buildFileName(extension) {\n const stamp = new Date().toISOString().replace(/[:T]/g, '-').slice(0, 16);\n return `pm-ledger-${stamp}.${extension}`;\n }\n\n function doDownloadPdf() {\n if (exportData.length === 0) {\n showToast({ message: 'Nothing to export on this page.', type: 'info' });\n return;\n }\n downloadPdf({\n title: 'PM Stock Ledger',\n columns: exportColumns,\n keys: exportKeys,\n data: exportData,\n fileName: buildFileName('pdf'),\n headerText: 'Product Management — Stock Ledger',\n footerText: 'Generated by MEDplat PM',\n orientation: 'landscape',\n });\n }\n\n function doDownloadXlsx() {\n if (exportData.length === 0) {\n showToast({ message: 'Nothing to export on this page.', type: 'info' });\n return;\n }\n void downloadXlsx({\n columns: exportColumns,\n keys: exportKeys,\n data: exportData,\n filename: buildFileName('xlsx'),\n });\n }\n\n return (\n <Box>\n <PmNav />\n <PmGuard perm={'view.manage.productManagement.ledger'}>\n <PmPageShell\n title=\"Stock Ledger\"\n subtitle=\"Complete record of all stock and money movements. Balances always match this ledger.\"\n actions={\n <Stack direction=\"row\" spacing={1}>\n <Button variant=\"outlined\" startIcon={<PictureAsPdfRoundedIcon />} onClick={doDownloadPdf} disabled={loading || items.length === 0}>PDF</Button>\n <Button variant=\"outlined\" startIcon={<InsertDriveFileRoundedIcon />} onClick={doDownloadXlsx} disabled={loading || items.length === 0}>Excel</Button>\n <Button variant=\"outlined\" startIcon={<RefreshRoundedIcon />} onClick={() => void load(0, pageSize, filters)}>Refresh</Button>\n </Stack>\n }\n >\n {error ? <Alert severity=\"error\" sx={{ mb: 2 }}>{error}</Alert> : null}\n\n {/* ---------- Filter panel ---------- */}\n <Box sx={{ mb: 2, p: 2, borderRadius: 3, border: '1px solid', borderColor: 'divider' }}>\n <Stack direction={{ xs: 'column', md: 'row' }} spacing={1.5} alignItems={{ md: 'center' }}>\n <TextField\n size=\"small\" type=\"date\" label=\"From\"\n InputLabelProps={{ shrink: true }}\n value={filters.dateFrom}\n onChange={(e) => setFilters((f) => ({ ...f, dateFrom: e.target.value }))}\n inputProps={{ max: filters.dateTo || undefined }}\n sx={{ minWidth: 160 }}\n />\n <TextField\n size=\"small\" type=\"date\" label=\"To\"\n InputLabelProps={{ shrink: true }}\n value={filters.dateTo}\n onChange={(e) => setFilters((f) => ({ ...f, dateTo: e.target.value }))}\n inputProps={{ min: filters.dateFrom || undefined }}\n error={!!dateRangeError}\n helperText={dateRangeError || undefined}\n sx={{ minWidth: 160 }}\n />\n <Autocomplete\n size=\"small\" multiple disableCloseOnSelect\n options={TYPE_OPTIONS}\n getOptionLabel={(o) => o.label}\n isOptionEqualToValue={(a, b) => a.value === b.value}\n value={TYPE_OPTIONS.filter((o) => filters.types.includes(o.value))}\n onChange={(_, next) => setFilters((f) => ({ ...f, types: next.map((o) => o.value) }))}\n renderInput={(params) => <TextField {...params} label=\"Types\" placeholder=\"Any\" />}\n sx={{ minWidth: 240, flexGrow: 1 }}\n />\n <FormControl size=\"small\" sx={{ minWidth: 140 }}>\n <InputLabel>Owner</InputLabel>\n <Select label=\"Owner\" value={filters.ownerType}\n onChange={(e) => setFilters((f) => ({ ...f, ownerType: e.target.value }))}>\n <MenuItem value=\"\">Any</MenuItem>\n <MenuItem value=\"FACILITY\">Facility</MenuItem>\n <MenuItem value=\"USER\">Personal</MenuItem>\n </Select>\n </FormControl>\n <TextField\n size=\"small\" label=\"Search\"\n placeholder=\"Lot, vaccine code, notes…\"\n value={filters.search}\n onChange={(e) => setFilters((f) => ({ ...f, search: e.target.value }))}\n onKeyDown={(e) => { if (e.key === 'Enter') applyFilters(filters); }}\n sx={{ minWidth: 220, flexGrow: 1 }}\n InputProps={{ startAdornment: <SearchRoundedIcon fontSize=\"small\" sx={{ color: 'text.secondary', mr: 1 }} /> }}\n />\n <Button variant=\"contained\" onClick={() => applyFilters(filters)} disabled={loading || !!dateRangeError}>Apply</Button>\n <Button variant=\"text\" onClick={resetFilters} disabled={loading}>Clear</Button>\n </Stack>\n </Box>\n\n <PmTableCard\n eyebrow=\"Audit feed\"\n title=\"Transactions\"\n subtitle={loading\n ? 'Loading…'\n : totalElements === 0\n ? 'No transactions in this window'\n : `Showing ${startIdx}–${endIdx} of ${totalElements} · page ${page + 1} of ${totalPages}`}\n actions={\n <Stack direction=\"row\" spacing={0.5} alignItems=\"center\">\n <FormControl size=\"small\" variant=\"outlined\" sx={{ minWidth: 88, mr: 1 }}>\n <InputLabel>Size</InputLabel>\n <Select label=\"Size\" value={pageSize}\n onChange={(e) => { const v = Number(e.target.value); setPageSize(v); void load(0, v, filters); }}>\n {[25, 50, 100, 200].map((s) => <MenuItem key={s} value={s}>{s}</MenuItem>)}\n </Select>\n </FormControl>\n <Tooltip title=\"Previous page\">\n <span>\n <IconButton\n size=\"small\"\n disabled={page === 0 || loading}\n onClick={() => void load(page - 1, pageSize, filters)}\n sx={{ border: '1px solid', borderColor: 'divider' }}\n >\n <ChevronLeftRoundedIcon fontSize=\"small\" />\n </IconButton>\n </span>\n </Tooltip>\n <Box sx={{ px: 1, minWidth: 64, textAlign: 'center' }}>\n <Typography variant=\"caption\" sx={{ fontWeight: 800, color: 'text.secondary', fontVariantNumeric: 'tabular-nums' }}>\n {totalElements === 0 ? '—' : `${startIdx}–${endIdx}`}\n </Typography>\n </Box>\n <Tooltip title=\"Next page\">\n <span>\n <IconButton\n size=\"small\"\n disabled={page + 1 >= totalPages || loading}\n onClick={() => void load(page + 1, pageSize, filters)}\n sx={{ border: '1px solid', borderColor: 'divider' }}\n >\n <ChevronRightRoundedIcon fontSize=\"small\" />\n </IconButton>\n </span>\n </Tooltip>\n </Stack>\n }\n >\n <PmTable dense>\n <TableHead>\n <TableRow>\n <TableCell>Time</TableCell>\n <TableCell>Type</TableCell>\n <TableCell>Owner</TableCell>\n <TableCell>Product · Lot</TableCell>\n <TableCell align=\"right\">Qty</TableCell>\n <TableCell align=\"right\">Volume</TableCell>\n <TableCell align=\"right\">Money</TableCell>\n <TableCell>Sync</TableCell>\n <TableCell>Notes</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {loading ? (\n Array.from({ length: 6 }).map((_, i) => (\n <TableRow key={i}>\n {Array.from({ length: 9 }).map((__, j) => (\n <TableCell key={j}><Skeleton height={22} /></TableCell>\n ))}\n </TableRow>\n ))\n ) : items.length === 0 ? (\n <PmEmptyRow\n colSpan={9}\n icon={ReceiptLongRoundedIcon}\n title=\"No transactions in this window\"\n hint=\"Record a purchase, sale, vial open, or payment. Every stock and money movement lands here.\"\n />\n ) : items.map((t) => (\n <TableRow key={t.id} hover>\n <TableCell>\n <Typography variant=\"body2\" sx={{ fontWeight: 700, lineHeight: 1.2 }}>\n {formatDateTime(t.transactionTime)}\n </Typography>\n </TableCell>\n <TableCell><TypeChip type={t.transactionType} /></TableCell>\n <TableCell>\n <Typography variant=\"body2\" sx={{ fontWeight: 700 }}>\n {t.ownerName || (t.ownerType === 'USER' ? 'Personal' : 'Facility')}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {t.ownerType}\n </Typography>\n </TableCell>\n <TableCell>\n <Stack direction=\"row\" alignItems=\"baseline\" spacing={1} sx={{ minWidth: 0 }}>\n <Typography variant=\"body2\" sx={{ fontWeight: 700, lineHeight: 1.2 }} noWrap>\n {t.productName || '—'}\n </Typography>\n {t.vaccineCode ? (\n <Box\n component=\"span\"\n sx={{\n px: 0.6,\n py: 0.05,\n borderRadius: 1,\n bgcolor: alpha(theme.palette.info.main, 0.1),\n color: 'info.dark',\n fontFamily: 'monospace',\n fontSize: '0.65rem',\n fontWeight: 700,\n }}\n >\n {t.vaccineCode}\n </Box>\n ) : null}\n {t.lotNumber ? (\n <Box\n component=\"span\"\n sx={{\n display: 'inline-flex',\n px: 0.7,\n py: 0.1,\n borderRadius: 1,\n bgcolor: alpha(theme.palette.primary.main, 0.06),\n color: 'primary.dark',\n fontFamily: 'monospace',\n fontSize: '0.7rem',\n fontWeight: 700,\n }}\n >\n {t.lotNumber}\n </Box>\n ) : null}\n </Stack>\n </TableCell>\n <TableCell align=\"right\">\n {t.quantity != null\n ? <Typography variant=\"body2\" sx={{ fontWeight: 700, fontVariantNumeric: 'tabular-nums' }}>{t.quantity}</Typography>\n : <Typography variant=\"caption\" color=\"text.disabled\">—</Typography>}\n </TableCell>\n <TableCell align=\"right\">\n {t.volumeMl != null\n ? <Typography variant=\"body2\" sx={{ fontWeight: 700, fontVariantNumeric: 'tabular-nums' }}>{formatNumber(t.volumeMl)} ml</Typography>\n : <Typography variant=\"caption\" color=\"text.disabled\">—</Typography>}\n </TableCell>\n <TableCell align=\"right\">\n <PmMoney value={t.monetaryAmount} />\n </TableCell>\n <TableCell><SyncChip status={t.syncStatus} /></TableCell>\n <TableCell sx={{ maxWidth: 240 }}>\n {t.notes ? (\n <Tooltip title={t.notes}>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>\n {t.notes}\n </Typography>\n </Tooltip>\n ) : <Typography variant=\"caption\" color=\"text.disabled\">—</Typography>}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </PmTable>\n </PmTableCard>\n </PmPageShell>\n </PmGuard>\n </Box>\n );\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { I as e, N as t, P as n, a as r, n as i, nt as a, r as ee, t as o } from "./PmGuard-CjJBisaN.js";
2
- import { n as s } from "./PmTable-BuXZQZCU.js";
1
+ import { F as e, L as t, P as n, i as r, n as i, o as a, r as ee, rt as o } from "./currency-ClRLIEg2.js";
2
+ import { r as s } from "./PmTable-B9970kPY.js";
3
3
  import { t as c } from "./format-UOyOu75i.js";
4
4
  import { useMemo as l, useState as u } from "react";
5
5
  import { jsx as d, jsxs as f } from "react/jsx-runtime";
@@ -22,13 +22,13 @@ function M() {
22
22
  qty: 1,
23
23
  notes: ""
24
24
  });
25
- ee("update.manage.productManagement.transfer", () => {
25
+ r("update.manage.productManagement.transfer", () => {
26
26
  async function r() {
27
27
  try {
28
28
  let [r, i, a] = await Promise.all([
29
+ t(),
29
30
  e(),
30
- n(),
31
- t({ activeOnly: !0 })
31
+ n({ activeOnly: !0 })
32
32
  ]);
33
33
  P(r), I(i), re(a);
34
34
  } catch (e) {
@@ -64,7 +64,7 @@ function M() {
64
64
  if ($) {
65
65
  z(!0), V("");
66
66
  try {
67
- let e = await a({
67
+ let e = await o({
68
68
  id: H.id,
69
69
  sourceBatchId: H.sourceBatchId,
70
70
  destFacilityId: H.destFacilityId,
@@ -83,10 +83,10 @@ function M() {
83
83
  }
84
84
  }
85
85
  }
86
- return /* @__PURE__ */ f(h, { children: [/* @__PURE__ */ d(i, {}), /* @__PURE__ */ d(o, {
86
+ return /* @__PURE__ */ f(h, { children: [/* @__PURE__ */ d(ee, {}), /* @__PURE__ */ d(i, {
87
87
  perm: "update.manage.productManagement.transfer",
88
88
  title: "You don’t have permission to ship transfers",
89
- children: /* @__PURE__ */ f(r, {
89
+ children: /* @__PURE__ */ f(a, {
90
90
  title: "Ship Stock Transfer",
91
91
  subtitle: "Send stock between facilities. The sender loses stock right away. The receiver creates the batch when they confirm receipt.",
92
92
  actions: /* @__PURE__ */ f(E, {
@@ -360,4 +360,4 @@ function M() {
360
360
  //#endregion
361
361
  export { M as default };
362
362
 
363
- //# sourceMappingURL=TransferCreatePage-BxudLfhS.js.map
363
+ //# sourceMappingURL=TransferCreatePage-DMuZqQ3c.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TransferCreatePage-BxudLfhS.js","names":[],"sources":["../src/views/TransferCreatePage.jsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { v4 as uuidv4 } from 'uuid';\nimport {\n Alert,\n Autocomplete,\n Box,\n Button,\n Card,\n CardContent,\n Chip,\n FormControl,\n FormHelperText,\n Grid,\n InputLabel,\n MenuItem,\n Select,\n Stack,\n TextField,\n Typography,\n} from '@mui/material';\nimport SaveRoundedIcon from '@mui/icons-material/SaveRounded';\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 } from '@pm/utils/permissions';\nimport { PmFormSection } from '@pm/components/PmTable';\nimport {\n getStorageUnits,\n listBatches,\n listFacilities,\n shipTransfer,\n} from '@pm/services/pmApi';\nimport { formatDate } from '@pm/utils/format';\n\n// Only facility-owned, in-stock, non-quarantined, non-terminal batches are\n// shippable. Mirrors the backend's check so the dropdown stays actionable.\nfunction isShippable(batch) {\n if (batch.ownerType !== 'FACILITY') return false;\n if (Number(batch.qtyRemaining ?? 0) <= 0) return false;\n if (batch.status === 'EXPIRED' || batch.status === 'EXHAUSTED' || batch.status === 'QUARANTINED') return false;\n return true;\n}\n\nexport default function TransferCreatePage() {\n const navigate = useNavigate();\n const [facilities, setFacilities] = useState([]);\n const [batches, setBatches] = useState([]);\n const [storageUnits, setStorageUnits] = useState([]);\n const [loading, setLoading] = useState(true);\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState('');\n const [form, setForm] = useState({\n id: uuidv4(),\n sourceFacilityId: '',\n sourceBatchId: '',\n destFacilityId: '',\n destStorageUnitId: '',\n qty: 1,\n notes: '',\n });\n\n usePermissionedEffect('update.manage.productManagement.transfer', () => {\n async function load() {\n try {\n const [f, b, su] = await Promise.all([\n listFacilities(),\n listBatches(),\n getStorageUnits({ activeOnly: true }),\n ]);\n setFacilities(f);\n setBatches(b);\n setStorageUnits(su);\n } catch (err) {\n setError(err?.response?.data?.message ?? err?.message ?? 'Failed to load reference data');\n } finally {\n setLoading(false);\n }\n }\n void load();\n }, []);\n\n function patch(k, v) {\n setForm((f) => ({ ...f, [k]: v }));\n }\n\n function patchSourceFacility(id) {\n setForm((f) => ({ ...f, sourceFacilityId: id, sourceBatchId: '' }));\n }\n\n function patchDestFacility(id) {\n setForm((f) => ({ ...f, destFacilityId: id, destStorageUnitId: '' }));\n }\n\n const eligibleBatches = useMemo(() => {\n if (!form.sourceFacilityId) return [];\n return batches.filter(isShippable).filter((b) => b.ownerId === form.sourceFacilityId);\n }, [batches, form.sourceFacilityId]);\n\n const selectedBatch = useMemo(\n () => batches.find((b) => b.id === form.sourceBatchId) ?? null,\n [batches, form.sourceBatchId],\n );\n\n // Storage units belonging to the chosen destination facility. Receiver can\n // override at confirm time so we keep the dropdown optional.\n const destUnits = useMemo(() => {\n if (!form.destFacilityId) return [];\n return storageUnits.filter((u) => u.ownerId === form.destFacilityId);\n }, [storageUnits, form.destFacilityId]);\n\n // Destination facility list excludes the source — the schema rejects\n // self-transfers (the CHECK constraint enforces source != dest).\n const destFacilities = useMemo(\n () => facilities.filter((f) => f.id !== form.sourceFacilityId),\n [facilities, form.sourceFacilityId],\n );\n\n const qty = Number(form.qty);\n const remaining = Number(selectedBatch?.qtyRemaining ?? 0);\n const qtyError = !selectedBatch\n ? ''\n : !Number.isInteger(qty) || qty <= 0\n ? 'Enter a whole number greater than 0.'\n : qty > remaining\n ? `Only ${remaining} available in this batch.`\n : '';\n const formIsValid =\n !!form.sourceFacilityId\n && !!form.sourceBatchId\n && !!form.destFacilityId\n && !qtyError;\n\n async function save() {\n if (!formIsValid) return;\n setSubmitting(true);\n setError('');\n try {\n const created = await shipTransfer({\n id: form.id,\n sourceBatchId: form.sourceBatchId,\n destFacilityId: form.destFacilityId,\n destStorageUnitId: form.destStorageUnitId || null,\n qty,\n notes: form.notes || null,\n });\n showToast({ message: `Shipped ${created.qty} ${created.qty === 1 ? 'unit' : 'units'} to ${created.destFacilityName ?? 'destination'}.`, type: 'success' });\n navigate('/ui/medplat/manage/pm/transfers');\n } catch (err) {\n setError(err?.response?.data?.message ?? err?.message ?? 'Failed to ship transfer');\n } finally {\n setSubmitting(false);\n }\n }\n\n return (\n <Box>\n <PmNav />\n <PmGuard perm={'update.manage.productManagement.transfer'} title=\"You don’t have permission to ship transfers\">\n <PmPageShell\n title=\"Ship Stock Transfer\"\n subtitle=\"Send stock between facilities. The sender loses stock right away. The receiver creates the batch when they confirm receipt.\"\n actions={\n <Stack direction=\"row\" spacing={1}>\n <Button variant=\"outlined\" onClick={() => navigate('/ui/medplat/manage/pm/transfers')}>Cancel</Button>\n <Button variant=\"contained\" startIcon={<SaveRoundedIcon />}\n disabled={!formIsValid || submitting}\n onClick={() => void save()}>\n {submitting ? 'Shipping…' : 'Ship Transfer'}\n </Button>\n </Stack>\n }\n >\n {error ? <Alert severity=\"error\" sx={{ mb: 2 }}>{error}</Alert> : null}\n\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 <PmFormSection\n eyebrow=\"Step 1\"\n title=\"Source\"\n hint=\"Select the sending facility and the batch.\"\n sx={{ mb: 2 }}\n />\n <Grid container spacing={2}>\n <Grid item xs={12} md={5}>\n <Autocomplete\n size=\"small\"\n options={facilities}\n getOptionLabel={(f) => f?.name ?? ''}\n isOptionEqualToValue={(a, b) => a?.id === b?.id}\n value={facilities.find((f) => f.id === form.sourceFacilityId) ?? null}\n onChange={(_, next) => patchSourceFacility(next?.id ?? '')}\n loading={loading}\n renderInput={(params) => (\n <TextField {...params} required label=\"Source Facility\" placeholder=\"Pick the shipping facility\" />\n )}\n />\n </Grid>\n <Grid item xs={12} md={7}>\n <FormControl required fullWidth size=\"small\" disabled={!form.sourceFacilityId}>\n <InputLabel>Source Batch</InputLabel>\n <Select\n label=\"Source Batch\"\n value={form.sourceBatchId}\n onChange={(e) => patch('sourceBatchId', e.target.value)}\n >\n {eligibleBatches.length === 0 ? (\n <MenuItem disabled value=\"\">\n <em>No shippable stock at this facility</em>\n </MenuItem>\n ) : (\n eligibleBatches.map((b) => (\n <MenuItem key={b.id} value={b.id}>\n <Box component=\"span\" sx={{ fontWeight: 700, mr: 1 }}>{b.productName}</Box>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ mr: 1 }}>\n qty {b.qtyRemaining}\n </Typography>\n {b.lotNumber ? (\n <Typography variant=\"caption\" sx={{ fontFamily: 'monospace', mr: 1 }}>\n {b.lotNumber}\n </Typography>\n ) : null}\n {b.expiryDate ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n exp {formatDate(b.expiryDate)}\n </Typography>\n ) : null}\n </MenuItem>\n ))\n )}\n </Select>\n <FormHelperText>\n {!form.sourceFacilityId\n ? 'Pick a source facility first.'\n : eligibleBatches.length === 0\n ? 'This facility has no shippable batches.'\n : 'Active facility batches only — quarantined / expired / exhausted stock is hidden.'}\n </FormHelperText>\n </FormControl>\n </Grid>\n </Grid>\n </CardContent>\n </Card>\n\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 <PmFormSection\n eyebrow=\"Step 2\"\n title=\"Destination\"\n hint=\"Choose the receiving facility and where to store it. The receiver can change the storage location when they confirm.\"\n sx={{ mb: 2 }}\n />\n <Grid container spacing={2}>\n <Grid item xs={12} md={6}>\n <Autocomplete\n size=\"small\"\n options={destFacilities}\n getOptionLabel={(f) => f?.name ?? ''}\n isOptionEqualToValue={(a, b) => a?.id === b?.id}\n value={facilities.find((f) => f.id === form.destFacilityId) ?? null}\n onChange={(_, next) => patchDestFacility(next?.id ?? '')}\n renderInput={(params) => (\n <TextField {...params} required label=\"Destination Facility\"\n placeholder=\"Pick the receiving facility\"\n helperText=\"The sending facility is not shown. You can only transfer between different facilities.\" />\n )}\n />\n </Grid>\n <Grid item xs={12} md={6}>\n <FormControl fullWidth size=\"small\" disabled={!form.destFacilityId || destUnits.length === 0}>\n <InputLabel>Suggested Storage</InputLabel>\n <Select\n label=\"Suggested Storage\"\n value={form.destStorageUnitId}\n onChange={(e) => patch('destStorageUnitId', e.target.value)}\n >\n <MenuItem value=\"\"><em>— No suggestion —</em></MenuItem>\n {destUnits.map((u) => (\n <MenuItem key={u.id} value={u.id}>{u.unitName}</MenuItem>\n ))}\n </Select>\n <FormHelperText>\n {!form.destFacilityId\n ? 'Pick a destination facility first.'\n : destUnits.length === 0\n ? 'No storage units configured at this facility.'\n : 'The receiver can override on confirm.'}\n </FormHelperText>\n </FormControl>\n </Grid>\n </Grid>\n </CardContent>\n </Card>\n\n {selectedBatch ? (\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 <PmFormSection\n eyebrow=\"Step 3\"\n title=\"Quantity\"\n hint={`Available: ${remaining}. You can send up to this amount.`}\n sx={{ mb: 2 }}\n />\n <Grid container spacing={2}>\n <Grid item xs={12} md={4}>\n <TextField\n required fullWidth size=\"small\" type=\"number\"\n label=\"Ship Quantity\"\n inputProps={{ min: 1, max: remaining }}\n value={form.qty}\n onChange={(e) => patch('qty', e.target.value)}\n error={!!qtyError}\n helperText={qtyError || `Out of ${remaining} available`}\n />\n </Grid>\n <Grid item xs={12} md={8}>\n <TextField\n fullWidth size=\"small\"\n label=\"Notes (optional)\"\n placeholder=\"Tracking number, courier, anything worth recording\"\n value={form.notes}\n onChange={(e) => patch('notes', e.target.value)}\n />\n </Grid>\n </Grid>\n <Stack direction=\"row\" spacing={1} sx={{ mt: 2 }} flexWrap=\"wrap\" useFlexGap>\n <Chip size=\"small\" label={`Product · ${selectedBatch.productName}`} />\n {selectedBatch.lotNumber ? <Chip size=\"small\" label={`Lot · ${selectedBatch.lotNumber}`} /> : null}\n {selectedBatch.expiryDate ? <Chip size=\"small\" label={`Expiry · ${formatDate(selectedBatch.expiryDate)}`} /> : null}\n {selectedBatch.storageUnitName ? <Chip size=\"small\" label={`From · ${selectedBatch.storageUnitName}`} /> : null}\n </Stack>\n </CardContent>\n </Card>\n ) : null}\n </PmPageShell>\n </PmGuard>\n </Box>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"TransferCreatePage-DMuZqQ3c.js","names":[],"sources":["../src/views/TransferCreatePage.jsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { v4 as uuidv4 } from 'uuid';\nimport {\n Alert,\n Autocomplete,\n Box,\n Button,\n Card,\n CardContent,\n Chip,\n FormControl,\n FormHelperText,\n Grid,\n InputLabel,\n MenuItem,\n Select,\n Stack,\n TextField,\n Typography,\n} from '@mui/material';\nimport SaveRoundedIcon from '@mui/icons-material/SaveRounded';\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 } from '@pm/utils/permissions';\nimport { PmFormSection } from '@pm/components/PmTable';\nimport {\n getStorageUnits,\n listBatches,\n listFacilities,\n shipTransfer,\n} from '@pm/services/pmApi';\nimport { formatDate } from '@pm/utils/format';\n\n// Only facility-owned, in-stock, non-quarantined, non-terminal batches are\n// shippable. Mirrors the backend's check so the dropdown stays actionable.\nfunction isShippable(batch) {\n if (batch.ownerType !== 'FACILITY') return false;\n if (Number(batch.qtyRemaining ?? 0) <= 0) return false;\n if (batch.status === 'EXPIRED' || batch.status === 'EXHAUSTED' || batch.status === 'QUARANTINED') return false;\n return true;\n}\n\nexport default function TransferCreatePage() {\n const navigate = useNavigate();\n const [facilities, setFacilities] = useState([]);\n const [batches, setBatches] = useState([]);\n const [storageUnits, setStorageUnits] = useState([]);\n const [loading, setLoading] = useState(true);\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState('');\n const [form, setForm] = useState({\n id: uuidv4(),\n sourceFacilityId: '',\n sourceBatchId: '',\n destFacilityId: '',\n destStorageUnitId: '',\n qty: 1,\n notes: '',\n });\n\n usePermissionedEffect('update.manage.productManagement.transfer', () => {\n async function load() {\n try {\n const [f, b, su] = await Promise.all([\n listFacilities(),\n listBatches(),\n getStorageUnits({ activeOnly: true }),\n ]);\n setFacilities(f);\n setBatches(b);\n setStorageUnits(su);\n } catch (err) {\n setError(err?.response?.data?.message ?? err?.message ?? 'Failed to load reference data');\n } finally {\n setLoading(false);\n }\n }\n void load();\n }, []);\n\n function patch(k, v) {\n setForm((f) => ({ ...f, [k]: v }));\n }\n\n function patchSourceFacility(id) {\n setForm((f) => ({ ...f, sourceFacilityId: id, sourceBatchId: '' }));\n }\n\n function patchDestFacility(id) {\n setForm((f) => ({ ...f, destFacilityId: id, destStorageUnitId: '' }));\n }\n\n const eligibleBatches = useMemo(() => {\n if (!form.sourceFacilityId) return [];\n return batches.filter(isShippable).filter((b) => b.ownerId === form.sourceFacilityId);\n }, [batches, form.sourceFacilityId]);\n\n const selectedBatch = useMemo(\n () => batches.find((b) => b.id === form.sourceBatchId) ?? null,\n [batches, form.sourceBatchId],\n );\n\n // Storage units belonging to the chosen destination facility. Receiver can\n // override at confirm time so we keep the dropdown optional.\n const destUnits = useMemo(() => {\n if (!form.destFacilityId) return [];\n return storageUnits.filter((u) => u.ownerId === form.destFacilityId);\n }, [storageUnits, form.destFacilityId]);\n\n // Destination facility list excludes the source — the schema rejects\n // self-transfers (the CHECK constraint enforces source != dest).\n const destFacilities = useMemo(\n () => facilities.filter((f) => f.id !== form.sourceFacilityId),\n [facilities, form.sourceFacilityId],\n );\n\n const qty = Number(form.qty);\n const remaining = Number(selectedBatch?.qtyRemaining ?? 0);\n const qtyError = !selectedBatch\n ? ''\n : !Number.isInteger(qty) || qty <= 0\n ? 'Enter a whole number greater than 0.'\n : qty > remaining\n ? `Only ${remaining} available in this batch.`\n : '';\n const formIsValid =\n !!form.sourceFacilityId\n && !!form.sourceBatchId\n && !!form.destFacilityId\n && !qtyError;\n\n async function save() {\n if (!formIsValid) return;\n setSubmitting(true);\n setError('');\n try {\n const created = await shipTransfer({\n id: form.id,\n sourceBatchId: form.sourceBatchId,\n destFacilityId: form.destFacilityId,\n destStorageUnitId: form.destStorageUnitId || null,\n qty,\n notes: form.notes || null,\n });\n showToast({ message: `Shipped ${created.qty} ${created.qty === 1 ? 'unit' : 'units'} to ${created.destFacilityName ?? 'destination'}.`, type: 'success' });\n navigate('/ui/medplat/manage/pm/transfers');\n } catch (err) {\n setError(err?.response?.data?.message ?? err?.message ?? 'Failed to ship transfer');\n } finally {\n setSubmitting(false);\n }\n }\n\n return (\n <Box>\n <PmNav />\n <PmGuard perm={'update.manage.productManagement.transfer'} title=\"You don’t have permission to ship transfers\">\n <PmPageShell\n title=\"Ship Stock Transfer\"\n subtitle=\"Send stock between facilities. The sender loses stock right away. The receiver creates the batch when they confirm receipt.\"\n actions={\n <Stack direction=\"row\" spacing={1}>\n <Button variant=\"outlined\" onClick={() => navigate('/ui/medplat/manage/pm/transfers')}>Cancel</Button>\n <Button variant=\"contained\" startIcon={<SaveRoundedIcon />}\n disabled={!formIsValid || submitting}\n onClick={() => void save()}>\n {submitting ? 'Shipping…' : 'Ship Transfer'}\n </Button>\n </Stack>\n }\n >\n {error ? <Alert severity=\"error\" sx={{ mb: 2 }}>{error}</Alert> : null}\n\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 <PmFormSection\n eyebrow=\"Step 1\"\n title=\"Source\"\n hint=\"Select the sending facility and the batch.\"\n sx={{ mb: 2 }}\n />\n <Grid container spacing={2}>\n <Grid item xs={12} md={5}>\n <Autocomplete\n size=\"small\"\n options={facilities}\n getOptionLabel={(f) => f?.name ?? ''}\n isOptionEqualToValue={(a, b) => a?.id === b?.id}\n value={facilities.find((f) => f.id === form.sourceFacilityId) ?? null}\n onChange={(_, next) => patchSourceFacility(next?.id ?? '')}\n loading={loading}\n renderInput={(params) => (\n <TextField {...params} required label=\"Source Facility\" placeholder=\"Pick the shipping facility\" />\n )}\n />\n </Grid>\n <Grid item xs={12} md={7}>\n <FormControl required fullWidth size=\"small\" disabled={!form.sourceFacilityId}>\n <InputLabel>Source Batch</InputLabel>\n <Select\n label=\"Source Batch\"\n value={form.sourceBatchId}\n onChange={(e) => patch('sourceBatchId', e.target.value)}\n >\n {eligibleBatches.length === 0 ? (\n <MenuItem disabled value=\"\">\n <em>No shippable stock at this facility</em>\n </MenuItem>\n ) : (\n eligibleBatches.map((b) => (\n <MenuItem key={b.id} value={b.id}>\n <Box component=\"span\" sx={{ fontWeight: 700, mr: 1 }}>{b.productName}</Box>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ mr: 1 }}>\n qty {b.qtyRemaining}\n </Typography>\n {b.lotNumber ? (\n <Typography variant=\"caption\" sx={{ fontFamily: 'monospace', mr: 1 }}>\n {b.lotNumber}\n </Typography>\n ) : null}\n {b.expiryDate ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n exp {formatDate(b.expiryDate)}\n </Typography>\n ) : null}\n </MenuItem>\n ))\n )}\n </Select>\n <FormHelperText>\n {!form.sourceFacilityId\n ? 'Pick a source facility first.'\n : eligibleBatches.length === 0\n ? 'This facility has no shippable batches.'\n : 'Active facility batches only — quarantined / expired / exhausted stock is hidden.'}\n </FormHelperText>\n </FormControl>\n </Grid>\n </Grid>\n </CardContent>\n </Card>\n\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 <PmFormSection\n eyebrow=\"Step 2\"\n title=\"Destination\"\n hint=\"Choose the receiving facility and where to store it. The receiver can change the storage location when they confirm.\"\n sx={{ mb: 2 }}\n />\n <Grid container spacing={2}>\n <Grid item xs={12} md={6}>\n <Autocomplete\n size=\"small\"\n options={destFacilities}\n getOptionLabel={(f) => f?.name ?? ''}\n isOptionEqualToValue={(a, b) => a?.id === b?.id}\n value={facilities.find((f) => f.id === form.destFacilityId) ?? null}\n onChange={(_, next) => patchDestFacility(next?.id ?? '')}\n renderInput={(params) => (\n <TextField {...params} required label=\"Destination Facility\"\n placeholder=\"Pick the receiving facility\"\n helperText=\"The sending facility is not shown. You can only transfer between different facilities.\" />\n )}\n />\n </Grid>\n <Grid item xs={12} md={6}>\n <FormControl fullWidth size=\"small\" disabled={!form.destFacilityId || destUnits.length === 0}>\n <InputLabel>Suggested Storage</InputLabel>\n <Select\n label=\"Suggested Storage\"\n value={form.destStorageUnitId}\n onChange={(e) => patch('destStorageUnitId', e.target.value)}\n >\n <MenuItem value=\"\"><em>— No suggestion —</em></MenuItem>\n {destUnits.map((u) => (\n <MenuItem key={u.id} value={u.id}>{u.unitName}</MenuItem>\n ))}\n </Select>\n <FormHelperText>\n {!form.destFacilityId\n ? 'Pick a destination facility first.'\n : destUnits.length === 0\n ? 'No storage units configured at this facility.'\n : 'The receiver can override on confirm.'}\n </FormHelperText>\n </FormControl>\n </Grid>\n </Grid>\n </CardContent>\n </Card>\n\n {selectedBatch ? (\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 <PmFormSection\n eyebrow=\"Step 3\"\n title=\"Quantity\"\n hint={`Available: ${remaining}. You can send up to this amount.`}\n sx={{ mb: 2 }}\n />\n <Grid container spacing={2}>\n <Grid item xs={12} md={4}>\n <TextField\n required fullWidth size=\"small\" type=\"number\"\n label=\"Ship Quantity\"\n inputProps={{ min: 1, max: remaining }}\n value={form.qty}\n onChange={(e) => patch('qty', e.target.value)}\n error={!!qtyError}\n helperText={qtyError || `Out of ${remaining} available`}\n />\n </Grid>\n <Grid item xs={12} md={8}>\n <TextField\n fullWidth size=\"small\"\n label=\"Notes (optional)\"\n placeholder=\"Tracking number, courier, anything worth recording\"\n value={form.notes}\n onChange={(e) => patch('notes', e.target.value)}\n />\n </Grid>\n </Grid>\n <Stack direction=\"row\" spacing={1} sx={{ mt: 2 }} flexWrap=\"wrap\" useFlexGap>\n <Chip size=\"small\" label={`Product · ${selectedBatch.productName}`} />\n {selectedBatch.lotNumber ? <Chip size=\"small\" label={`Lot · ${selectedBatch.lotNumber}`} /> : null}\n {selectedBatch.expiryDate ? <Chip size=\"small\" label={`Expiry · ${formatDate(selectedBatch.expiryDate)}`} /> : null}\n {selectedBatch.storageUnitName ? <Chip size=\"small\" label={`From · ${selectedBatch.storageUnitName}`} /> : null}\n </Stack>\n </CardContent>\n </Card>\n ) : null}\n </PmPageShell>\n </PmGuard>\n </Box>\n );\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
- import { I as e, J as t, N as n, a as ee, g as r, i, m as te, n as ne, r as re, t as ie } from "./PmGuard-CjJBisaN.js";
2
- import { a as ae, i as oe, o as se, t as ce } from "./PmTable-BuXZQZCU.js";
1
+ import { L as e, P as t, Y as n, _ as ee, a as r, h as i, i as te, n as ne, o as re, r as ie } from "./currency-ClRLIEg2.js";
2
+ import { a as ae, c as oe, s as se, t as ce } from "./PmTable-B9970kPY.js";
3
3
  import { n as le, t as a } from "./format-UOyOu75i.js";
4
- import { c as ue, p as de } from "./constants-BrA_hfAI.js";
4
+ import { c as ue, p as de } from "./constants-5ZCZo-Zm.js";
5
5
  import { useMemo as o, useState as s } from "react";
6
6
  import { jsx as c, jsxs as l } from "react/jsx-runtime";
7
7
  import { Alert as u, Box as d, Button as f, Chip as fe, Dialog as p, DialogActions as m, DialogContent as h, DialogTitle as g, FormControl as pe, FormHelperText as me, InputAdornment as he, InputLabel as ge, MenuItem as _, Select as _e, Skeleton as ve, Stack as v, Tab as y, TableBody as ye, TableCell as b, TableHead as be, TableRow as x, Tabs as xe, TextField as S, Typography as C } from "@mui/material";
@@ -24,7 +24,7 @@ function Ee(e) {
24
24
  }
25
25
  }
26
26
  function k() {
27
- let k = Ce(), A = i().has("update.manage.productManagement.transfer"), [j, De] = s([]), [Oe, ke] = s([]), [M, Ae] = s(() => /* @__PURE__ */ new Set()), [N, P] = s(!0), [F, I] = s(""), [L, je] = s("all"), [R, Me] = s(""), [z, B] = s({
27
+ let k = Ce(), A = r().has("update.manage.productManagement.transfer"), [j, De] = s([]), [Oe, ke] = s([]), [M, Ae] = s(() => /* @__PURE__ */ new Set()), [N, P] = s(!0), [F, I] = s(""), [L, je] = s("all"), [R, Me] = s(""), [z, B] = s({
28
28
  open: !1,
29
29
  transfer: null
30
30
  }), [V, H] = s({
@@ -38,8 +38,8 @@ function k() {
38
38
  P(!0), I("");
39
39
  try {
40
40
  let [ee, r, i] = await Promise.all([
41
- t(),
42
- n({ activeOnly: !0 }).catch(() => []),
41
+ n(),
42
+ t({ activeOnly: !0 }).catch(() => []),
43
43
  e().catch(() => [])
44
44
  ]);
45
45
  De(ee), ke(r), Ae(new Set(i.map((e) => e.id)));
@@ -53,7 +53,7 @@ function k() {
53
53
  P(!1);
54
54
  }
55
55
  }
56
- re("view.manage.productManagement.transfer", () => {
56
+ te("view.manage.productManagement.transfer", () => {
57
57
  Y();
58
58
  }, []);
59
59
  let Ne = o(() => ({
@@ -101,7 +101,7 @@ function k() {
101
101
  if (z.transfer) {
102
102
  J(!0);
103
103
  try {
104
- await r(z.transfer.id, {
104
+ await ee(z.transfer.id, {
105
105
  destStorageUnitId: V.destStorageUnitId || null,
106
106
  notes: V.notes || null
107
107
  }), T({
@@ -122,7 +122,7 @@ function k() {
122
122
  if (U.transfer) {
123
123
  J(!0);
124
124
  try {
125
- await te(U.transfer.id, { notes: G || null }), T({
125
+ await i(U.transfer.id, { notes: G || null }), T({
126
126
  message: "Transfer cancelled — stock returned to the source.",
127
127
  type: "success"
128
128
  }), Q(), await Y();
@@ -137,10 +137,10 @@ function k() {
137
137
  }
138
138
  }
139
139
  return /* @__PURE__ */ l(d, { children: [
140
- /* @__PURE__ */ c(ne, {}),
141
- /* @__PURE__ */ c(ie, {
140
+ /* @__PURE__ */ c(ie, {}),
141
+ /* @__PURE__ */ c(ne, {
142
142
  perm: "view.manage.productManagement.transfer",
143
- children: /* @__PURE__ */ l(ee, {
143
+ children: /* @__PURE__ */ l(re, {
144
144
  title: "Stock Transfers",
145
145
  subtitle: "Stock movements between facilities. The sender loses stock when shipping. The receiver gains it when they confirm.",
146
146
  actions: /* @__PURE__ */ l(v, {
@@ -162,7 +162,7 @@ function k() {
162
162
  severity: "error",
163
163
  sx: { mb: 2 },
164
164
  children: F
165
- }) : null, /* @__PURE__ */ l(se, {
165
+ }) : null, /* @__PURE__ */ l(oe, {
166
166
  eyebrow: "Operations",
167
167
  title: "Transfers",
168
168
  subtitle: N ? "Loading…" : `${X.length} ${X.length === 1 ? "transfer" : "transfers"}`,
@@ -211,7 +211,7 @@ function k() {
211
211
  }) }
212
212
  })
213
213
  ]
214
- }), /* @__PURE__ */ l(ae, {
214
+ }), /* @__PURE__ */ l(se, {
215
215
  dense: !0,
216
216
  children: [/* @__PURE__ */ c(be, { children: /* @__PURE__ */ l(x, { children: [
217
217
  /* @__PURE__ */ c(b, { children: "Ref" }),
@@ -243,7 +243,7 @@ function k() {
243
243
  }) : X.map((e) => /* @__PURE__ */ l(x, {
244
244
  hover: !0,
245
245
  children: [
246
- /* @__PURE__ */ c(b, { children: /* @__PURE__ */ c(oe, { id: e.serialId }) }),
246
+ /* @__PURE__ */ c(b, { children: /* @__PURE__ */ c(ae, { id: e.serialId }) }),
247
247
  /* @__PURE__ */ l(b, { children: [/* @__PURE__ */ c(C, {
248
248
  variant: "body2",
249
249
  sx: { fontWeight: 700 },
@@ -477,4 +477,4 @@ function k() {
477
477
  //#endregion
478
478
  export { k as default };
479
479
 
480
- //# sourceMappingURL=TransfersPage-zgmt7teZ.js.map
480
+ //# sourceMappingURL=TransfersPage-COIyouL4.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TransfersPage-zgmt7teZ.js","names":[],"sources":["../src/views/TransfersPage.jsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n Alert,\n Box,\n Button,\n Chip,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n FormControl,\n FormHelperText,\n InputAdornment,\n InputLabel,\n MenuItem,\n Select,\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 } 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 SwapHorizRoundedIcon from '@mui/icons-material/SwapHorizRounded';\nimport CheckCircleRoundedIcon from '@mui/icons-material/CheckCircleRounded';\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 { usePermissionedEffect, usePmPermissions } from '@pm/utils/permissions';\nimport {\n PmEmptyRow,\n PmRef,\n PmTable,\n PmTableCard,\n} from '@pm/components/PmTable';\nimport {\n cancelTransfer,\n confirmTransfer,\n getStorageUnits,\n listFacilities,\n listTransfers,\n} from '@pm/services/pmApi';\nimport { formatDate, formatDateTime } from '@pm/utils/format';\nimport { TRANSFER_STATUSES, labelOf } from '@pm/utils/constants';\n\nfunction statusChipColor(status) {\n switch (status) {\n case 'PENDING': return 'info';\n case 'COMPLETED': return 'success';\n case 'CANCELLED': return 'default';\n default: return 'default';\n }\n}\n\nexport default function TransfersPage() {\n const navigate = useNavigate();\n const perms = usePmPermissions();\n const canWrite = perms.has('update.manage.productManagement.transfer');\n const [rows, setRows] = useState([]);\n const [storageUnits, setStorageUnits] = useState([]);\n // UUIDs of facilities the current user is assigned to — controls which\n // per-row action buttons render. Confirm is reserved for users at the\n // destination facility; cancel is reserved for users at the source.\n const [assignedFacilityIds, setAssignedFacilityIds] = useState(() => new Set());\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState('');\n const [tab, setTab] = useState('all');\n const [search, setSearch] = useState('');\n const [confirmDialog, setConfirmDialog] = useState({ open: false, transfer: null });\n const [confirmForm, setConfirmForm] = useState({ destStorageUnitId: '', notes: '' });\n const [cancelDialog, setCancelDialog] = useState({ open: false, transfer: null });\n const [cancelNotes, setCancelNotes] = useState('');\n const [submitting, setSubmitting] = useState(false);\n\n async function load() {\n setLoading(true);\n setError('');\n try {\n const [t, su, fac] = await Promise.all([\n listTransfers(),\n getStorageUnits({ activeOnly: true }).catch(() => []),\n listFacilities().catch(() => []),\n ]);\n setRows(t);\n setStorageUnits(su);\n setAssignedFacilityIds(new Set(fac.map((f) => f.id)));\n } catch (err) {\n const message = err?.response?.data?.message ?? err?.message ?? 'Failed to load transfers';\n setError(message);\n showToast({ message, type: 'error' });\n } finally {\n setLoading(false);\n }\n }\n\n usePermissionedEffect('view.manage.productManagement.transfer', () => { void load(); }, []);\n\n const counts = useMemo(() => ({\n incoming: rows.filter((r) => r.status === 'PENDING').length,\n outgoing: rows.filter((r) => r.status === 'PENDING').length,\n }), [rows]);\n\n const filtered = useMemo(() => {\n let base = rows;\n if (tab === 'incoming') base = base.filter((r) => r.status === 'PENDING');\n if (tab === 'outgoing') base = base.filter((r) => r.status === 'PENDING');\n const q = search.trim().toLowerCase();\n if (q) {\n base = base.filter((r) => {\n const hay = `${r.productName ?? ''} ${r.sourceFacilityName ?? ''} ${r.destFacilityName ?? ''} ${r.lotNumber ?? ''} ${r.notes ?? ''}`.toLowerCase();\n return hay.includes(q);\n });\n }\n return base;\n }, [rows, tab, search]);\n\n function openConfirm(t) {\n setConfirmForm({\n destStorageUnitId: t.destStorageUnitId ?? '',\n notes: '',\n });\n setConfirmDialog({ open: true, transfer: t });\n }\n\n function closeConfirm() {\n if (submitting) return;\n setConfirmDialog({ open: false, transfer: null });\n }\n\n function openCancel(t) {\n setCancelNotes('');\n setCancelDialog({ open: true, transfer: t });\n }\n\n function closeCancel() {\n if (submitting) return;\n setCancelDialog({ open: false, transfer: null });\n }\n\n // Storage units belonging to the receiver's facility — receiver picks one\n // (or accepts the sender's suggestion).\n const destUnits = useMemo(() => {\n if (!confirmDialog.transfer) return [];\n return storageUnits.filter((u) => u.ownerId === confirmDialog.transfer.destFacilityId);\n }, [storageUnits, confirmDialog.transfer]);\n\n async function submitConfirm() {\n if (!confirmDialog.transfer) return;\n setSubmitting(true);\n try {\n await confirmTransfer(confirmDialog.transfer.id, {\n destStorageUnitId: confirmForm.destStorageUnitId || null,\n notes: confirmForm.notes || null,\n });\n showToast({ message: 'Transfer confirmed — stock landed at the destination.', type: 'success' });\n closeConfirm();\n await load();\n } catch (err) {\n showToast({ message: err?.response?.data?.message ?? err?.message ?? 'Failed to confirm transfer', type: 'error' });\n } finally {\n setSubmitting(false);\n }\n }\n\n async function submitCancel() {\n if (!cancelDialog.transfer) return;\n setSubmitting(true);\n try {\n await cancelTransfer(cancelDialog.transfer.id, { notes: cancelNotes || null });\n showToast({ message: 'Transfer cancelled — stock returned to the source.', type: 'success' });\n closeCancel();\n await load();\n } catch (err) {\n showToast({ message: err?.response?.data?.message ?? err?.message ?? 'Failed to cancel transfer', type: 'error' });\n } finally {\n setSubmitting(false);\n }\n }\n\n return (\n <Box>\n <PmNav />\n <PmGuard perm={'view.manage.productManagement.transfer'}>\n <PmPageShell\n title=\"Stock Transfers\"\n subtitle=\"Stock movements between facilities. The sender loses stock when shipping. The receiver gains it when they confirm.\"\n actions={\n <Stack direction=\"row\" spacing={1}>\n <Button variant=\"outlined\" startIcon={<RefreshRoundedIcon />} onClick={() => void load()}>Refresh</Button>\n {canWrite ? (\n <Button variant=\"contained\" startIcon={<AddRoundedIcon />}\n onClick={() => navigate('/ui/medplat/manage/pm/transfers/new')}>\n New Transfer\n </Button>\n ) : null}\n </Stack>\n }\n >\n {error ? <Alert severity=\"error\" sx={{ mb: 2 }}>{error}</Alert> : null}\n\n <PmTableCard\n eyebrow=\"Operations\"\n title=\"Transfers\"\n subtitle={loading ? 'Loading…' : `${filtered.length} ${filtered.length === 1 ? 'transfer' : 'transfers'}`}\n >\n <Stack direction={{ xs: 'column', md: 'row' }} spacing={1.5} sx={{ mb: 2 }} alignItems={{ md: 'center' }}>\n <Tabs value={tab} onChange={(_, v) => setTab(v)} sx={{ minHeight: 40 }}>\n <Tab value=\"all\" label={`All${rows.length ? ` (${rows.length})` : ''}`} sx={{ minHeight: 40, textTransform: 'none', fontWeight: 700 }} />\n <Tab value=\"incoming\" label={`Pending${counts.incoming ? ` (${counts.incoming})` : ''}`} sx={{ minHeight: 40, textTransform: 'none', fontWeight: 700 }} />\n </Tabs>\n <Box sx={{ flexGrow: 1 }} />\n <TextField\n size=\"small\" fullWidth\n placeholder=\"Search by product, facility, lot, notes…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n sx={{ maxWidth: { md: 360 } }}\n InputProps={{\n startAdornment: <InputAdornment position=\"start\"><SearchRoundedIcon fontSize=\"small\" /></InputAdornment>,\n }}\n />\n </Stack>\n\n <PmTable dense>\n <TableHead>\n <TableRow>\n <TableCell>Ref</TableCell>\n <TableCell>Product</TableCell>\n <TableCell>From</TableCell>\n <TableCell>To</TableCell>\n <TableCell align=\"right\">Qty</TableCell>\n <TableCell>Shipped</TableCell>\n <TableCell>Status</TableCell>\n <TableCell align=\"right\">Action</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {loading ? (\n Array.from({ length: 4 }).map((_, i) => (\n <TableRow key={i}>\n {Array.from({ length: 8 }).map((__, j) => (\n <TableCell key={j}><Skeleton height={22} /></TableCell>\n ))}\n </TableRow>\n ))\n ) : filtered.length === 0 ? (\n <PmEmptyRow\n colSpan={8}\n icon={SwapHorizRoundedIcon}\n title={search.trim() !== ''\n ? 'No transfers match your search'\n : tab === 'incoming'\n ? 'No pending transfers'\n : 'No transfers yet'}\n hint=\"Create a transfer to move stock between facilities.\"\n action={canWrite ? (\n <Button variant=\"contained\" size=\"small\" startIcon={<AddRoundedIcon />}\n onClick={() => navigate('/ui/medplat/manage/pm/transfers/new')}>\n Ship first transfer\n </Button>\n ) : null}\n />\n ) : filtered.map((r) => (\n <TableRow key={r.id} hover>\n <TableCell><PmRef id={r.serialId} /></TableCell>\n <TableCell>\n <Typography variant=\"body2\" sx={{ fontWeight: 700 }}>{r.productName ?? '—'}</Typography>\n {r.lotNumber ? (\n <Typography variant=\"caption\" sx={{ fontFamily: 'monospace', color: 'text.secondary' }}>\n {r.lotNumber}\n </Typography>\n ) : null}\n </TableCell>\n <TableCell>{r.sourceFacilityName ?? '—'}</TableCell>\n <TableCell>{r.destFacilityName ?? '—'}</TableCell>\n <TableCell align=\"right\">\n <Typography sx={{ fontWeight: 700, fontVariantNumeric: 'tabular-nums' }}>{r.qty}</Typography>\n </TableCell>\n <TableCell>\n <Typography variant=\"body2\">{formatDate(r.shippedOn)}</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">{r.shippedByName ?? `#${r.shippedBy}`}</Typography>\n </TableCell>\n <TableCell>\n <Chip size=\"small\" label={labelOf(TRANSFER_STATUSES, r.status)} color={statusChipColor(r.status)} />\n </TableCell>\n <TableCell align=\"right\">\n {(() => {\n // Two-party rule: only destination-facility users can\n // confirm; only source-facility users can cancel. The\n // backend enforces both checks too — this just hides\n // the buttons a user couldn't act on. A user assigned\n // to both ends sees both buttons.\n if (r.status !== 'PENDING' || !canWrite) {\n return <Typography variant=\"caption\" color=\"text.disabled\">—</Typography>;\n }\n const canConfirm = assignedFacilityIds.has(r.destFacilityId);\n const canCancel = assignedFacilityIds.has(r.sourceFacilityId);\n if (!canConfirm && !canCancel) {\n return <Typography variant=\"caption\" color=\"text.disabled\">—</Typography>;\n }\n return (\n <Stack direction=\"row\" spacing={1} justifyContent=\"flex-end\">\n {canConfirm ? (\n <Button size=\"small\" variant=\"outlined\" startIcon={<CheckCircleRoundedIcon />}\n onClick={() => openConfirm(r)}>\n Confirm\n </Button>\n ) : null}\n {canCancel ? (\n <Button size=\"small\" variant=\"outlined\" color=\"error\" startIcon={<DoNotDisturbRoundedIcon />}\n onClick={() => openCancel(r)}>\n Cancel\n </Button>\n ) : null}\n </Stack>\n );\n })()}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </PmTable>\n </PmTableCard>\n </PmPageShell>\n </PmGuard>\n\n {/* ---------- Confirm dialog ---------- */}\n <Dialog open={confirmDialog.open} onClose={closeConfirm} maxWidth=\"sm\" fullWidth>\n <DialogTitle>Confirm transfer #{confirmDialog.transfer?.serialId}</DialogTitle>\n <DialogContent>\n {confirmDialog.transfer ? (\n <Stack spacing={2} sx={{ mt: 1 }}>\n <Box sx={(t) => ({\n p: 1.5, borderRadius: 3,\n bgcolor: alpha(t.palette.primary.main, 0.04),\n border: `1px solid ${alpha(t.palette.primary.main, 0.12)}`,\n })}>\n <Typography variant=\"body2\"><strong>{confirmDialog.transfer.productName}</strong> · qty {confirmDialog.transfer.qty}</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block' }}>\n Shipped {formatDateTime(confirmDialog.transfer.shippedOn)} by {confirmDialog.transfer.shippedByName ?? `#${confirmDialog.transfer.shippedBy}`} from {confirmDialog.transfer.sourceFacilityName}\n </Typography>\n {confirmDialog.transfer.lotNumber ? (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', mt: 0.5 }}>\n Lot {confirmDialog.transfer.lotNumber}\n {confirmDialog.transfer.expiryDate ? ` · expires ${formatDate(confirmDialog.transfer.expiryDate)}` : ''}\n </Typography>\n ) : null}\n </Box>\n\n <FormControl required size=\"small\" disabled={destUnits.length === 0}\n error={!confirmForm.destStorageUnitId}>\n <InputLabel>Landing Storage</InputLabel>\n <Select\n label=\"Landing Storage\"\n value={confirmForm.destStorageUnitId}\n onChange={(e) => setConfirmForm((f) => ({ ...f, destStorageUnitId: e.target.value }))}\n >\n <MenuItem value=\"\" disabled><em>— Pick a storage unit —</em></MenuItem>\n {destUnits.map((u) => (\n <MenuItem key={u.id} value={u.id}>{u.unitName}</MenuItem>\n ))}\n </Select>\n <FormHelperText>\n {destUnits.length === 0\n ? 'No storage units at this facility — add one on the Storage Units page first.'\n : confirmDialog.transfer?.destStorageUnitId\n ? 'Sender suggested a unit (pre-filled). You can change it; cold-chain compatibility is checked server-side.'\n : 'Required. Cold-chain compatibility is checked server-side against the product.'}\n </FormHelperText>\n </FormControl>\n\n <TextField\n size=\"small\" multiline minRows={2}\n label=\"Notes (optional)\"\n value={confirmForm.notes}\n onChange={(e) => setConfirmForm((f) => ({ ...f, notes: e.target.value }))}\n />\n </Stack>\n ) : null}\n </DialogContent>\n <DialogActions>\n <Button onClick={closeConfirm} disabled={submitting}>Close</Button>\n <Button variant=\"contained\" startIcon={<CheckCircleRoundedIcon />}\n onClick={() => void submitConfirm()}\n disabled={submitting || !confirmForm.destStorageUnitId || destUnits.length === 0}>\n {submitting ? 'Confirming…' : 'Confirm Receipt'}\n </Button>\n </DialogActions>\n </Dialog>\n\n {/* ---------- Cancel dialog ---------- */}\n <Dialog open={cancelDialog.open} onClose={closeCancel} maxWidth=\"sm\" fullWidth>\n <DialogTitle>Cancel transfer #{cancelDialog.transfer?.serialId}</DialogTitle>\n <DialogContent>\n {cancelDialog.transfer ? (\n <Stack spacing={2} sx={{ mt: 1 }}>\n <Alert severity=\"warning\">\n Cancelling will credit {cancelDialog.transfer.qty} {cancelDialog.transfer.qty === 1 ? 'unit' : 'units'} back to <strong>{cancelDialog.transfer.sourceFacilityName}</strong>.\n </Alert>\n <TextField\n size=\"small\" multiline minRows={2}\n label=\"Reason (optional)\"\n value={cancelNotes}\n onChange={(e) => setCancelNotes(e.target.value)}\n />\n </Stack>\n ) : null}\n </DialogContent>\n <DialogActions>\n <Button onClick={closeCancel} disabled={submitting}>Close</Button>\n <Button variant=\"contained\" color=\"error\" startIcon={<DoNotDisturbRoundedIcon />}\n onClick={() => void submitCancel()} disabled={submitting}>\n {submitting ? 'Cancelling…' : 'Cancel Transfer'}\n </Button>\n </DialogActions>\n </Dialog>\n </Box>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"TransfersPage-COIyouL4.js","names":[],"sources":["../src/views/TransfersPage.jsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n Alert,\n Box,\n Button,\n Chip,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n FormControl,\n FormHelperText,\n InputAdornment,\n InputLabel,\n MenuItem,\n Select,\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 } 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 SwapHorizRoundedIcon from '@mui/icons-material/SwapHorizRounded';\nimport CheckCircleRoundedIcon from '@mui/icons-material/CheckCircleRounded';\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 { usePermissionedEffect, usePmPermissions } from '@pm/utils/permissions';\nimport {\n PmEmptyRow,\n PmRef,\n PmTable,\n PmTableCard,\n} from '@pm/components/PmTable';\nimport {\n cancelTransfer,\n confirmTransfer,\n getStorageUnits,\n listFacilities,\n listTransfers,\n} from '@pm/services/pmApi';\nimport { formatDate, formatDateTime } from '@pm/utils/format';\nimport { TRANSFER_STATUSES, labelOf } from '@pm/utils/constants';\n\nfunction statusChipColor(status) {\n switch (status) {\n case 'PENDING': return 'info';\n case 'COMPLETED': return 'success';\n case 'CANCELLED': return 'default';\n default: return 'default';\n }\n}\n\nexport default function TransfersPage() {\n const navigate = useNavigate();\n const perms = usePmPermissions();\n const canWrite = perms.has('update.manage.productManagement.transfer');\n const [rows, setRows] = useState([]);\n const [storageUnits, setStorageUnits] = useState([]);\n // UUIDs of facilities the current user is assigned to — controls which\n // per-row action buttons render. Confirm is reserved for users at the\n // destination facility; cancel is reserved for users at the source.\n const [assignedFacilityIds, setAssignedFacilityIds] = useState(() => new Set());\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState('');\n const [tab, setTab] = useState('all');\n const [search, setSearch] = useState('');\n const [confirmDialog, setConfirmDialog] = useState({ open: false, transfer: null });\n const [confirmForm, setConfirmForm] = useState({ destStorageUnitId: '', notes: '' });\n const [cancelDialog, setCancelDialog] = useState({ open: false, transfer: null });\n const [cancelNotes, setCancelNotes] = useState('');\n const [submitting, setSubmitting] = useState(false);\n\n async function load() {\n setLoading(true);\n setError('');\n try {\n const [t, su, fac] = await Promise.all([\n listTransfers(),\n getStorageUnits({ activeOnly: true }).catch(() => []),\n listFacilities().catch(() => []),\n ]);\n setRows(t);\n setStorageUnits(su);\n setAssignedFacilityIds(new Set(fac.map((f) => f.id)));\n } catch (err) {\n const message = err?.response?.data?.message ?? err?.message ?? 'Failed to load transfers';\n setError(message);\n showToast({ message, type: 'error' });\n } finally {\n setLoading(false);\n }\n }\n\n usePermissionedEffect('view.manage.productManagement.transfer', () => { void load(); }, []);\n\n const counts = useMemo(() => ({\n incoming: rows.filter((r) => r.status === 'PENDING').length,\n outgoing: rows.filter((r) => r.status === 'PENDING').length,\n }), [rows]);\n\n const filtered = useMemo(() => {\n let base = rows;\n if (tab === 'incoming') base = base.filter((r) => r.status === 'PENDING');\n if (tab === 'outgoing') base = base.filter((r) => r.status === 'PENDING');\n const q = search.trim().toLowerCase();\n if (q) {\n base = base.filter((r) => {\n const hay = `${r.productName ?? ''} ${r.sourceFacilityName ?? ''} ${r.destFacilityName ?? ''} ${r.lotNumber ?? ''} ${r.notes ?? ''}`.toLowerCase();\n return hay.includes(q);\n });\n }\n return base;\n }, [rows, tab, search]);\n\n function openConfirm(t) {\n setConfirmForm({\n destStorageUnitId: t.destStorageUnitId ?? '',\n notes: '',\n });\n setConfirmDialog({ open: true, transfer: t });\n }\n\n function closeConfirm() {\n if (submitting) return;\n setConfirmDialog({ open: false, transfer: null });\n }\n\n function openCancel(t) {\n setCancelNotes('');\n setCancelDialog({ open: true, transfer: t });\n }\n\n function closeCancel() {\n if (submitting) return;\n setCancelDialog({ open: false, transfer: null });\n }\n\n // Storage units belonging to the receiver's facility — receiver picks one\n // (or accepts the sender's suggestion).\n const destUnits = useMemo(() => {\n if (!confirmDialog.transfer) return [];\n return storageUnits.filter((u) => u.ownerId === confirmDialog.transfer.destFacilityId);\n }, [storageUnits, confirmDialog.transfer]);\n\n async function submitConfirm() {\n if (!confirmDialog.transfer) return;\n setSubmitting(true);\n try {\n await confirmTransfer(confirmDialog.transfer.id, {\n destStorageUnitId: confirmForm.destStorageUnitId || null,\n notes: confirmForm.notes || null,\n });\n showToast({ message: 'Transfer confirmed — stock landed at the destination.', type: 'success' });\n closeConfirm();\n await load();\n } catch (err) {\n showToast({ message: err?.response?.data?.message ?? err?.message ?? 'Failed to confirm transfer', type: 'error' });\n } finally {\n setSubmitting(false);\n }\n }\n\n async function submitCancel() {\n if (!cancelDialog.transfer) return;\n setSubmitting(true);\n try {\n await cancelTransfer(cancelDialog.transfer.id, { notes: cancelNotes || null });\n showToast({ message: 'Transfer cancelled — stock returned to the source.', type: 'success' });\n closeCancel();\n await load();\n } catch (err) {\n showToast({ message: err?.response?.data?.message ?? err?.message ?? 'Failed to cancel transfer', type: 'error' });\n } finally {\n setSubmitting(false);\n }\n }\n\n return (\n <Box>\n <PmNav />\n <PmGuard perm={'view.manage.productManagement.transfer'}>\n <PmPageShell\n title=\"Stock Transfers\"\n subtitle=\"Stock movements between facilities. The sender loses stock when shipping. The receiver gains it when they confirm.\"\n actions={\n <Stack direction=\"row\" spacing={1}>\n <Button variant=\"outlined\" startIcon={<RefreshRoundedIcon />} onClick={() => void load()}>Refresh</Button>\n {canWrite ? (\n <Button variant=\"contained\" startIcon={<AddRoundedIcon />}\n onClick={() => navigate('/ui/medplat/manage/pm/transfers/new')}>\n New Transfer\n </Button>\n ) : null}\n </Stack>\n }\n >\n {error ? <Alert severity=\"error\" sx={{ mb: 2 }}>{error}</Alert> : null}\n\n <PmTableCard\n eyebrow=\"Operations\"\n title=\"Transfers\"\n subtitle={loading ? 'Loading…' : `${filtered.length} ${filtered.length === 1 ? 'transfer' : 'transfers'}`}\n >\n <Stack direction={{ xs: 'column', md: 'row' }} spacing={1.5} sx={{ mb: 2 }} alignItems={{ md: 'center' }}>\n <Tabs value={tab} onChange={(_, v) => setTab(v)} sx={{ minHeight: 40 }}>\n <Tab value=\"all\" label={`All${rows.length ? ` (${rows.length})` : ''}`} sx={{ minHeight: 40, textTransform: 'none', fontWeight: 700 }} />\n <Tab value=\"incoming\" label={`Pending${counts.incoming ? ` (${counts.incoming})` : ''}`} sx={{ minHeight: 40, textTransform: 'none', fontWeight: 700 }} />\n </Tabs>\n <Box sx={{ flexGrow: 1 }} />\n <TextField\n size=\"small\" fullWidth\n placeholder=\"Search by product, facility, lot, notes…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n sx={{ maxWidth: { md: 360 } }}\n InputProps={{\n startAdornment: <InputAdornment position=\"start\"><SearchRoundedIcon fontSize=\"small\" /></InputAdornment>,\n }}\n />\n </Stack>\n\n <PmTable dense>\n <TableHead>\n <TableRow>\n <TableCell>Ref</TableCell>\n <TableCell>Product</TableCell>\n <TableCell>From</TableCell>\n <TableCell>To</TableCell>\n <TableCell align=\"right\">Qty</TableCell>\n <TableCell>Shipped</TableCell>\n <TableCell>Status</TableCell>\n <TableCell align=\"right\">Action</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {loading ? (\n Array.from({ length: 4 }).map((_, i) => (\n <TableRow key={i}>\n {Array.from({ length: 8 }).map((__, j) => (\n <TableCell key={j}><Skeleton height={22} /></TableCell>\n ))}\n </TableRow>\n ))\n ) : filtered.length === 0 ? (\n <PmEmptyRow\n colSpan={8}\n icon={SwapHorizRoundedIcon}\n title={search.trim() !== ''\n ? 'No transfers match your search'\n : tab === 'incoming'\n ? 'No pending transfers'\n : 'No transfers yet'}\n hint=\"Create a transfer to move stock between facilities.\"\n action={canWrite ? (\n <Button variant=\"contained\" size=\"small\" startIcon={<AddRoundedIcon />}\n onClick={() => navigate('/ui/medplat/manage/pm/transfers/new')}>\n Ship first transfer\n </Button>\n ) : null}\n />\n ) : filtered.map((r) => (\n <TableRow key={r.id} hover>\n <TableCell><PmRef id={r.serialId} /></TableCell>\n <TableCell>\n <Typography variant=\"body2\" sx={{ fontWeight: 700 }}>{r.productName ?? '—'}</Typography>\n {r.lotNumber ? (\n <Typography variant=\"caption\" sx={{ fontFamily: 'monospace', color: 'text.secondary' }}>\n {r.lotNumber}\n </Typography>\n ) : null}\n </TableCell>\n <TableCell>{r.sourceFacilityName ?? '—'}</TableCell>\n <TableCell>{r.destFacilityName ?? '—'}</TableCell>\n <TableCell align=\"right\">\n <Typography sx={{ fontWeight: 700, fontVariantNumeric: 'tabular-nums' }}>{r.qty}</Typography>\n </TableCell>\n <TableCell>\n <Typography variant=\"body2\">{formatDate(r.shippedOn)}</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">{r.shippedByName ?? `#${r.shippedBy}`}</Typography>\n </TableCell>\n <TableCell>\n <Chip size=\"small\" label={labelOf(TRANSFER_STATUSES, r.status)} color={statusChipColor(r.status)} />\n </TableCell>\n <TableCell align=\"right\">\n {(() => {\n // Two-party rule: only destination-facility users can\n // confirm; only source-facility users can cancel. The\n // backend enforces both checks too — this just hides\n // the buttons a user couldn't act on. A user assigned\n // to both ends sees both buttons.\n if (r.status !== 'PENDING' || !canWrite) {\n return <Typography variant=\"caption\" color=\"text.disabled\">—</Typography>;\n }\n const canConfirm = assignedFacilityIds.has(r.destFacilityId);\n const canCancel = assignedFacilityIds.has(r.sourceFacilityId);\n if (!canConfirm && !canCancel) {\n return <Typography variant=\"caption\" color=\"text.disabled\">—</Typography>;\n }\n return (\n <Stack direction=\"row\" spacing={1} justifyContent=\"flex-end\">\n {canConfirm ? (\n <Button size=\"small\" variant=\"outlined\" startIcon={<CheckCircleRoundedIcon />}\n onClick={() => openConfirm(r)}>\n Confirm\n </Button>\n ) : null}\n {canCancel ? (\n <Button size=\"small\" variant=\"outlined\" color=\"error\" startIcon={<DoNotDisturbRoundedIcon />}\n onClick={() => openCancel(r)}>\n Cancel\n </Button>\n ) : null}\n </Stack>\n );\n })()}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </PmTable>\n </PmTableCard>\n </PmPageShell>\n </PmGuard>\n\n {/* ---------- Confirm dialog ---------- */}\n <Dialog open={confirmDialog.open} onClose={closeConfirm} maxWidth=\"sm\" fullWidth>\n <DialogTitle>Confirm transfer #{confirmDialog.transfer?.serialId}</DialogTitle>\n <DialogContent>\n {confirmDialog.transfer ? (\n <Stack spacing={2} sx={{ mt: 1 }}>\n <Box sx={(t) => ({\n p: 1.5, borderRadius: 3,\n bgcolor: alpha(t.palette.primary.main, 0.04),\n border: `1px solid ${alpha(t.palette.primary.main, 0.12)}`,\n })}>\n <Typography variant=\"body2\"><strong>{confirmDialog.transfer.productName}</strong> · qty {confirmDialog.transfer.qty}</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block' }}>\n Shipped {formatDateTime(confirmDialog.transfer.shippedOn)} by {confirmDialog.transfer.shippedByName ?? `#${confirmDialog.transfer.shippedBy}`} from {confirmDialog.transfer.sourceFacilityName}\n </Typography>\n {confirmDialog.transfer.lotNumber ? (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', mt: 0.5 }}>\n Lot {confirmDialog.transfer.lotNumber}\n {confirmDialog.transfer.expiryDate ? ` · expires ${formatDate(confirmDialog.transfer.expiryDate)}` : ''}\n </Typography>\n ) : null}\n </Box>\n\n <FormControl required size=\"small\" disabled={destUnits.length === 0}\n error={!confirmForm.destStorageUnitId}>\n <InputLabel>Landing Storage</InputLabel>\n <Select\n label=\"Landing Storage\"\n value={confirmForm.destStorageUnitId}\n onChange={(e) => setConfirmForm((f) => ({ ...f, destStorageUnitId: e.target.value }))}\n >\n <MenuItem value=\"\" disabled><em>— Pick a storage unit —</em></MenuItem>\n {destUnits.map((u) => (\n <MenuItem key={u.id} value={u.id}>{u.unitName}</MenuItem>\n ))}\n </Select>\n <FormHelperText>\n {destUnits.length === 0\n ? 'No storage units at this facility — add one on the Storage Units page first.'\n : confirmDialog.transfer?.destStorageUnitId\n ? 'Sender suggested a unit (pre-filled). You can change it; cold-chain compatibility is checked server-side.'\n : 'Required. Cold-chain compatibility is checked server-side against the product.'}\n </FormHelperText>\n </FormControl>\n\n <TextField\n size=\"small\" multiline minRows={2}\n label=\"Notes (optional)\"\n value={confirmForm.notes}\n onChange={(e) => setConfirmForm((f) => ({ ...f, notes: e.target.value }))}\n />\n </Stack>\n ) : null}\n </DialogContent>\n <DialogActions>\n <Button onClick={closeConfirm} disabled={submitting}>Close</Button>\n <Button variant=\"contained\" startIcon={<CheckCircleRoundedIcon />}\n onClick={() => void submitConfirm()}\n disabled={submitting || !confirmForm.destStorageUnitId || destUnits.length === 0}>\n {submitting ? 'Confirming…' : 'Confirm Receipt'}\n </Button>\n </DialogActions>\n </Dialog>\n\n {/* ---------- Cancel dialog ---------- */}\n <Dialog open={cancelDialog.open} onClose={closeCancel} maxWidth=\"sm\" fullWidth>\n <DialogTitle>Cancel transfer #{cancelDialog.transfer?.serialId}</DialogTitle>\n <DialogContent>\n {cancelDialog.transfer ? (\n <Stack spacing={2} sx={{ mt: 1 }}>\n <Alert severity=\"warning\">\n Cancelling will credit {cancelDialog.transfer.qty} {cancelDialog.transfer.qty === 1 ? 'unit' : 'units'} back to <strong>{cancelDialog.transfer.sourceFacilityName}</strong>.\n </Alert>\n <TextField\n size=\"small\" multiline minRows={2}\n label=\"Reason (optional)\"\n value={cancelNotes}\n onChange={(e) => setCancelNotes(e.target.value)}\n />\n </Stack>\n ) : null}\n </DialogContent>\n <DialogActions>\n <Button onClick={closeCancel} disabled={submitting}>Close</Button>\n <Button variant=\"contained\" color=\"error\" startIcon={<DoNotDisturbRoundedIcon />}\n onClick={() => void submitCancel()} disabled={submitting}>\n {submitting ? 'Cancelling…' : 'Cancel Transfer'}\n </Button>\n </DialogActions>\n </Dialog>\n </Box>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAwDA,SAAS,GAAgB,GAAQ;CAC/B,QAAQ,GAAR;EACE,KAAK,WAAW,OAAO;EACvB,KAAK,aAAa,OAAO;EACzB,KAAK,aAAa,OAAO;EACzB,SAAS,OAAO;CAClB;AACF;AAEA,SAAwB,IAAgB;CACtC,IAAM,IAAW,GAAY,GAEvB,IADQ,EACG,EAAM,IAAI,0CAA0C,GAC/D,CAAC,GAAM,MAAW,EAAS,CAAC,CAAC,GAC7B,CAAC,IAAc,MAAmB,EAAS,CAAC,CAAC,GAI7C,CAAC,GAAqB,MAA0B,wBAAe,IAAI,IAAI,CAAC,GACxE,CAAC,GAAS,KAAc,EAAS,EAAI,GACrC,CAAC,GAAO,KAAY,EAAS,EAAE,GAC/B,CAAC,GAAK,MAAU,EAAS,KAAK,GAC9B,CAAC,GAAQ,MAAa,EAAS,EAAE,GACjC,CAAC,GAAe,KAAoB,EAAS;EAAE,MAAM;EAAO,UAAU;CAAK,CAAC,GAC5E,CAAC,GAAa,KAAkB,EAAS;EAAE,mBAAmB;EAAI,OAAO;CAAG,CAAC,GAC7E,CAAC,GAAc,KAAmB,EAAS;EAAE,MAAM;EAAO,UAAU;CAAK,CAAC,GAC1E,CAAC,GAAa,KAAkB,EAAS,EAAE,GAC3C,CAAC,GAAY,KAAiB,EAAS,EAAK;CAElD,eAAe,IAAO;EAEpB,AADA,EAAW,EAAI,GACf,EAAS,EAAE;EACX,IAAI;GACF,IAAM,CAAC,IAAG,GAAI,KAAO,MAAM,QAAQ,IAAI;IACrC,EAAc;IACd,EAAgB,EAAE,YAAY,GAAK,CAAC,EAAE,YAAY,CAAC,CAAC;IACpD,EAAe,EAAE,YAAY,CAAC,CAAC;GACjC,CAAC;GAGD,AAFA,GAAQ,EAAC,GACT,GAAgB,CAAE,GAClB,GAAuB,IAAI,IAAI,EAAI,KAAK,MAAM,EAAE,EAAE,CAAC,CAAC;EACtD,SAAS,GAAK;GACZ,IAAM,IAAU,GAAK,UAAU,MAAM,WAAW,GAAK,WAAW;GAEhE,AADA,EAAS,CAAO,GAChB,EAAU;IAAE;IAAS,MAAM;GAAQ,CAAC;EACtC,UAAU;GACR,EAAW,EAAK;EAClB;CACF;CAEA,GAAsB,gDAAgD;EAAE,EAAU;CAAG,GAAG,CAAC,CAAC;CAE1F,IAAM,KAAS,SAAe;EAC5B,UAAU,EAAK,QAAQ,MAAM,EAAE,WAAW,SAAS,EAAE;EACrD,UAAU,EAAK,QAAQ,MAAM,EAAE,WAAW,SAAS,EAAE;CACvD,IAAI,CAAC,CAAI,CAAC,GAEJ,IAAW,QAAc;EAC7B,IAAI,IAAO;EAEX,AADI,MAAQ,eAAY,IAAO,EAAK,QAAQ,MAAM,EAAE,WAAW,SAAS,IACpE,MAAQ,eAAY,IAAO,EAAK,QAAQ,MAAM,EAAE,WAAW,SAAS;EACxE,IAAM,IAAI,EAAO,KAAK,EAAE,YAAY;EAOpC,OANI,MACF,IAAO,EAAK,QAAQ,MACN,GAAG,EAAE,eAAe,GAAG,GAAG,EAAE,sBAAsB,GAAG,GAAG,EAAE,oBAAoB,GAAG,GAAG,EAAE,aAAa,GAAG,GAAG,EAAE,SAAS,KAAK,YAC9H,EAAI,SAAS,CAAC,CACtB,IAEI;CACT,GAAG;EAAC;EAAM;EAAK;CAAM,CAAC;CAEtB,SAAS,GAAY,GAAG;EAKtB,AAJA,EAAe;GACb,mBAAmB,EAAE,qBAAqB;GAC1C,OAAO;EACT,CAAC,GACD,EAAiB;GAAE,MAAM;GAAM,UAAU;EAAE,CAAC;CAC9C;CAEA,SAAS,IAAe;EAClB,KACJ,EAAiB;GAAE,MAAM;GAAO,UAAU;EAAK,CAAC;CAClD;CAEA,SAAS,GAAW,GAAG;EAErB,AADA,EAAe,EAAE,GACjB,EAAgB;GAAE,MAAM;GAAM,UAAU;EAAE,CAAC;CAC7C;CAEA,SAAS,IAAc;EACjB,KACJ,EAAgB;GAAE,MAAM;GAAO,UAAU;EAAK,CAAC;CACjD;CAIA,IAAM,IAAY,QACX,EAAc,WACZ,GAAa,QAAQ,MAAM,EAAE,YAAY,EAAc,SAAS,cAAc,IADjD,CAAC,GAEpC,CAAC,IAAc,EAAc,QAAQ,CAAC;CAEzC,eAAe,KAAgB;EACxB,MAAc,UACnB;KAAc,EAAI;GAClB,IAAI;IAOF,AANA,MAAM,GAAgB,EAAc,SAAS,IAAI;KAC/C,mBAAmB,EAAY,qBAAqB;KACpD,OAAO,EAAY,SAAS;IAC9B,CAAC,GACD,EAAU;KAAE,SAAS;KAAyD,MAAM;IAAU,CAAC,GAC/F,EAAa,GACb,MAAM,EAAK;GACb,SAAS,GAAK;IACZ,EAAU;KAAE,SAAS,GAAK,UAAU,MAAM,WAAW,GAAK,WAAW;KAA8B,MAAM;IAAQ,CAAC;GACpH,UAAU;IACR,EAAc,EAAK;GACrB;EAbkB;CAcpB;CAEA,eAAe,KAAe;EACvB,MAAa,UAClB;KAAc,EAAI;GAClB,IAAI;IAIF,AAHA,MAAM,EAAe,EAAa,SAAS,IAAI,EAAE,OAAO,KAAe,KAAK,CAAC,GAC7E,EAAU;KAAE,SAAS;KAAsD,MAAM;IAAU,CAAC,GAC5F,EAAY,GACZ,MAAM,EAAK;GACb,SAAS,GAAK;IACZ,EAAU;KAAE,SAAS,GAAK,UAAU,MAAM,WAAW,GAAK,WAAW;KAA6B,MAAM;IAAQ,CAAC;GACnH,UAAU;IACR,EAAc,EAAK;GACrB;EAVkB;CAWpB;CAEA,OACE,kBAAC,GAAD,EAAA,UAAA;EACE,kBAAC,IAAD,CAAQ,CAAA;EACR,kBAAC,IAAD;GAAS,MAAM;aACf,kBAAC,IAAD;IACE,OAAM;IACN,UAAS;IACT,SACE,kBAAC,GAAD;KAAO,WAAU;KAAM,SAAS;eAAhC,CACE,kBAAC,GAAD;MAAQ,SAAQ;MAAW,WAAW,kBAAC,IAAD,CAAqB,CAAA;MAAG,eAAe,KAAK,EAAK;gBAAG;KAAe,CAAA,GACxG,IACC,kBAAC,GAAD;MAAQ,SAAQ;MAAY,WAAW,kBAAC,GAAD,CAAiB,CAAA;MACtD,eAAe,EAAS,qCAAqC;gBAAG;KAE1D,CAAA,IACN,IACC;;cAZX,CAeG,IAAQ,kBAAC,GAAD;KAAO,UAAS;KAAQ,IAAI,EAAE,IAAI,EAAE;eAAI;IAAa,CAAA,IAAI,MAElE,kBAAC,IAAD;KACE,SAAQ;KACR,OAAM;KACN,UAAU,IAAU,aAAa,GAAG,EAAS,OAAO,GAAG,EAAS,WAAW,IAAI,aAAa;eAH9F,CAKE,kBAAC,GAAD;MAAO,WAAW;OAAE,IAAI;OAAU,IAAI;MAAM;MAAG,SAAS;MAAK,IAAI,EAAE,IAAI,EAAE;MAAG,YAAY,EAAE,IAAI,SAAS;gBAAvG;OACE,kBAAC,IAAD;QAAM,OAAO;QAAK,WAAW,GAAG,MAAM,GAAO,CAAC;QAAG,IAAI,EAAE,WAAW,GAAG;kBAArE,CACE,kBAAC,GAAD;SAAK,OAAM;SAAW,OAAO,MAAM,EAAK,SAAS,KAAK,EAAK,OAAO,KAAK;SAAM,IAAI;UAAE,WAAW;UAAI,eAAe;UAAQ,YAAY;SAAI;QAAI,CAAA,GAC7I,kBAAC,GAAD;SAAK,OAAM;SAAW,OAAO,UAAU,GAAO,WAAW,KAAK,GAAO,SAAS,KAAK;SAAM,IAAI;UAAE,WAAW;UAAI,eAAe;UAAQ,YAAY;SAAI;QAAI,CAAA,CACrJ;;OACN,kBAAC,GAAD,EAAK,IAAI,EAAE,UAAU,EAAE,EAAI,CAAA;OAC3B,kBAAC,GAAD;QACE,MAAK;QAAQ,WAAA;QACb,aAAY;QACZ,OAAO;QACP,WAAW,MAAM,GAAU,EAAE,OAAO,KAAK;QACzC,IAAI,EAAE,UAAU,EAAE,IAAI,IAAI,EAAE;QAC5B,YAAY,EACV,gBAAgB,kBAAC,IAAD;SAAgB,UAAS;mBAAQ,kBAAC,IAAD,EAAmB,UAAS,QAAS,CAAA;QAAiB,CAAA,EACzG;OACD,CAAA;MACI;SAEP,kBAAC,IAAD;MAAS,OAAA;gBAAT,CACE,kBAAC,IAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAA;OACE,kBAAC,GAAD,EAAA,UAAW,MAAc,CAAA;OACzB,kBAAC,GAAD,EAAA,UAAW,UAAkB,CAAA;OAC7B,kBAAC,GAAD,EAAA,UAAW,OAAe,CAAA;OAC1B,kBAAC,GAAD,EAAA,UAAW,KAAa,CAAA;OACxB,kBAAC,GAAD;QAAW,OAAM;kBAAQ;OAAc,CAAA;OACvC,kBAAC,GAAD,EAAA,UAAW,UAAkB,CAAA;OAC7B,kBAAC,GAAD,EAAA,UAAW,SAAiB,CAAA;OAC5B,kBAAC,GAAD;QAAW,OAAM;kBAAQ;OAAiB,CAAA;MAClC,EAAA,CAAA,EACD,CAAA,GACX,kBAAC,IAAD,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,UAAmB,kBAAC,IAAD,EAAU,QAAQ,GAAK,CAAA,EAAY,GAAtC,CAAsC,CACvD,EACO,GAJK,CAIL,CACX,IACC,EAAS,WAAW,IACtB,kBAAC,IAAD;OACE,SAAS;OACT,MAAM;OACN,OAAO,EAAO,KAAK,MAAM,KAErB,MAAQ,aACN,yBACA,qBAHF;OAIJ,MAAK;OACL,QAAQ,IACN,kBAAC,GAAD;QAAQ,SAAQ;QAAY,MAAK;QAAQ,WAAW,kBAAC,GAAD,CAAiB,CAAA;QACnE,eAAe,EAAS,qCAAqC;kBAAG;OAE1D,CAAA,IACN;MACL,CAAA,IACC,EAAS,KAAK,MAChB,kBAAC,GAAD;OAAqB,OAAA;iBAArB;QACE,kBAAC,GAAD,EAAA,UAAW,kBAAC,IAAD,EAAO,IAAI,EAAE,SAAW,CAAA,EAAY,CAAA;QAC/C,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;SAAY,SAAQ;SAAQ,IAAI,EAAE,YAAY,IAAI;mBAAI,EAAE,eAAe;QAAgB,CAAA,GACtF,EAAE,YACD,kBAAC,GAAD;SAAY,SAAQ;SAAU,IAAI;UAAE,YAAY;UAAa,OAAO;SAAiB;mBAClF,EAAE;QACO,CAAA,IACV,IACK,EAAA,CAAA;QACX,kBAAC,GAAD,EAAA,UAAY,EAAE,sBAAsB,IAAe,CAAA;QACnD,kBAAC,GAAD,EAAA,UAAY,EAAE,oBAAoB,IAAe,CAAA;QACjD,kBAAC,GAAD;SAAW,OAAM;mBACf,kBAAC,GAAD;UAAY,IAAI;WAAE,YAAY;WAAK,oBAAoB;UAAe;oBAAI,EAAE;SAAgB,CAAA;QACnF,CAAA;QACX,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;SAAY,SAAQ;mBAAS,EAAW,EAAE,SAAS;QAAc,CAAA,GACjE,kBAAC,GAAD;SAAY,SAAQ;SAAU,OAAM;mBAAkB,EAAE,iBAAiB,IAAI,EAAE;QAAwB,CAAA,CAC9F,EAAA,CAAA;QACX,kBAAC,GAAD,EAAA,UACE,kBAAC,IAAD;SAAM,MAAK;SAAQ,OAAO,GAAQ,IAAmB,EAAE,MAAM;SAAG,OAAO,GAAgB,EAAE,MAAM;QAAI,CAAA,EAC1F,CAAA;QACX,kBAAC,GAAD;SAAW,OAAM;0BACP;UAMN,IAAI,EAAE,WAAW,aAAa,CAAC,GAC7B,OAAO,kBAAC,GAAD;WAAY,SAAQ;WAAU,OAAM;qBAAgB;UAAa,CAAA;UAE1E,IAAM,IAAa,EAAoB,IAAI,EAAE,cAAc,GACrD,IAAY,EAAoB,IAAI,EAAE,gBAAgB;UAI5D,OAHI,CAAC,KAAc,CAAC,IACX,kBAAC,GAAD;WAAY,SAAQ;WAAU,OAAM;qBAAgB;UAAa,CAAA,IAGxE,kBAAC,GAAD;WAAO,WAAU;WAAM,SAAS;WAAG,gBAAe;qBAAlD,CACG,IACC,kBAAC,GAAD;YAAQ,MAAK;YAAQ,SAAQ;YAAW,WAAW,kBAAC,GAAD,CAAyB,CAAA;YAC1E,eAAe,GAAY,CAAC;sBAAG;WAEzB,CAAA,IACN,MACH,IACC,kBAAC,GAAD;YAAQ,MAAK;YAAQ,SAAQ;YAAW,OAAM;YAAQ,WAAW,kBAAC,GAAD,CAA0B,CAAA;YACzF,eAAe,GAAW,CAAC;sBAAG;WAExB,CAAA,IACN,IACC;;SAEX,GAAG;QACM,CAAA;OACH;SAvDK,EAAE,EAuDP,CACX,EACQ,CAAA,CACJ;OACE;MACF;;EACJ,CAAA;EAGT,kBAAC,GAAD;GAAQ,MAAM,EAAc;GAAM,SAAS;GAAc,UAAS;GAAK,WAAA;aAAvE;IACE,kBAAC,GAAD,EAAA,UAAA,CAAa,sBAAmB,EAAc,UAAU,QAAsB,EAAA,CAAA;IAC9E,kBAAC,GAAD,EAAA,UACG,EAAc,WACb,kBAAC,GAAD;KAAO,SAAS;KAAG,IAAI,EAAE,IAAI,EAAE;eAA/B;MACE,kBAAC,GAAD;OAAK,KAAK,OAAO;QACf,GAAG;QAAK,cAAc;QACtB,SAAS,EAAM,EAAE,QAAQ,QAAQ,MAAM,GAAI;QAC3C,QAAQ,aAAa,EAAM,EAAE,QAAQ,QAAQ,MAAM,GAAI;OACzD;iBAJA;QAKE,kBAAC,GAAD;SAAY,SAAQ;mBAApB;UAA4B,kBAAC,UAAD,EAAA,UAAS,EAAc,SAAS,YAAoB,CAAA;UAAC;UAAQ,EAAc,SAAS;SAAgB;;QAChI,kBAAC,GAAD;SAAY,SAAQ;SAAU,OAAM;SAAiB,IAAI,EAAE,SAAS,QAAQ;mBAA5E;UAA+E;UACpE,GAAe,EAAc,SAAS,SAAS;UAAE;UAAK,EAAc,SAAS,iBAAiB,IAAI,EAAc,SAAS;UAAY;UAAO,EAAc,SAAS;SAClK;;QACX,EAAc,SAAS,YACtB,kBAAC,GAAD;SAAY,SAAQ;SAAU,OAAM;SAAiB,IAAI;UAAE,SAAS;UAAS,IAAI;SAAI;mBAArF;UAAwF;UACjF,EAAc,SAAS;UAC3B,EAAc,SAAS,aAAa,cAAc,EAAW,EAAc,SAAS,UAAU,MAAM;SAC3F;aACV;OACD;;MAEL,kBAAC,IAAD;OAAa,UAAA;OAAS,MAAK;OAAQ,UAAU,EAAU,WAAW;OAChE,OAAO,CAAC,EAAY;iBADtB;QAEE,kBAAC,IAAD,EAAA,UAAY,kBAA2B,CAAA;QACvC,kBAAC,IAAD;SACE,OAAM;SACN,OAAO,EAAY;SACnB,WAAW,MAAM,GAAgB,OAAO;UAAE,GAAG;UAAG,mBAAmB,EAAE,OAAO;SAAM,EAAE;mBAHtF,CAKE,kBAAC,GAAD;UAAU,OAAM;UAAG,UAAA;oBAAS,kBAAC,MAAD,EAAA,UAAI,0BAA2B,CAAA;SAAW,CAAA,GACrE,EAAU,KAAK,MACd,kBAAC,GAAD;UAAqB,OAAO,EAAE;oBAAK,EAAE;SAAmB,GAAzC,EAAE,EAAuC,CACzD,CACK;;QACR,kBAAC,IAAD,EAAA,UACG,EAAU,WAAW,IAClB,iFACA,EAAc,UAAU,oBACtB,8GACA,iFACQ,CAAA;OACL;;MAEb,kBAAC,GAAD;OACE,MAAK;OAAQ,WAAA;OAAU,SAAS;OAChC,OAAM;OACN,OAAO,EAAY;OACnB,WAAW,MAAM,GAAgB,OAAO;QAAE,GAAG;QAAG,OAAO,EAAE,OAAO;OAAM,EAAE;MACzE,CAAA;KACI;SACL,KACS,CAAA;IACf,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;KAAQ,SAAS;KAAc,UAAU;eAAY;IAAa,CAAA,GAClE,kBAAC,GAAD;KAAQ,SAAQ;KAAY,WAAW,kBAAC,GAAD,CAAyB,CAAA;KAC9D,eAAe,KAAK,GAAc;KAClC,UAAU,KAAc,CAAC,EAAY,qBAAqB,EAAU,WAAW;eAC9E,IAAa,gBAAgB;IACxB,CAAA,CACK,EAAA,CAAA;GACT;;EAGR,kBAAC,GAAD;GAAQ,MAAM,EAAa;GAAM,SAAS;GAAa,UAAS;GAAK,WAAA;aAArE;IACE,kBAAC,GAAD,EAAA,UAAA,CAAa,qBAAkB,EAAa,UAAU,QAAsB,EAAA,CAAA;IAC5E,kBAAC,GAAD,EAAA,UACG,EAAa,WACZ,kBAAC,GAAD;KAAO,SAAS;KAAG,IAAI,EAAE,IAAI,EAAE;eAA/B,CACE,kBAAC,GAAD;MAAO,UAAS;gBAAhB;OAA0B;OACA,EAAa,SAAS;OAAI;OAAE,EAAa,SAAS,QAAQ,IAAI,SAAS;OAAQ;OAAS,kBAAC,UAAD,EAAA,UAAS,EAAa,SAAS,mBAA2B,CAAA;OAAC;MACtK;SACP,kBAAC,GAAD;MACE,MAAK;MAAQ,WAAA;MAAU,SAAS;MAChC,OAAM;MACN,OAAO;MACP,WAAW,MAAM,EAAe,EAAE,OAAO,KAAK;KAC/C,CAAA,CACI;SACL,KACS,CAAA;IACf,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;KAAQ,SAAS;KAAa,UAAU;eAAY;IAAa,CAAA,GACjE,kBAAC,GAAD;KAAQ,SAAQ;KAAY,OAAM;KAAQ,WAAW,kBAAC,GAAD,CAA0B,CAAA;KAC7E,eAAe,KAAK,GAAa;KAAG,UAAU;eAC7C,IAAa,gBAAgB;IACxB,CAAA,CACK,EAAA,CAAA;GACT;;CACL,EAAA,CAAA;AAET"}