@argusoft/medplat-product-management 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/BrandsPage-DCMCVvDY.js +334 -0
  2. package/dist/BrandsPage-DCMCVvDY.js.map +1 -0
  3. package/dist/CategoriesPage-BpRhwfrc.js +284 -0
  4. package/dist/CategoriesPage-BpRhwfrc.js.map +1 -0
  5. package/dist/DashboardPage-BNKUQj46.js +436 -0
  6. package/dist/DashboardPage-BNKUQj46.js.map +1 -0
  7. package/dist/FacilityPicker-Coi8I3yE.js +79 -0
  8. package/dist/FacilityPicker-Coi8I3yE.js.map +1 -0
  9. package/dist/InventoryPage-BR6jOzg2.js +517 -0
  10. package/dist/InventoryPage-BR6jOzg2.js.map +1 -0
  11. package/dist/MemberProfileCard-DbHZCS5n.js +272 -0
  12. package/dist/MemberProfileCard-DbHZCS5n.js.map +1 -0
  13. package/dist/PaymentCreatePage-Ci3ERnby.js +487 -0
  14. package/dist/PaymentCreatePage-Ci3ERnby.js.map +1 -0
  15. package/dist/PaymentsPage-sdg902zX.js +157 -0
  16. package/dist/PaymentsPage-sdg902zX.js.map +1 -0
  17. package/dist/PickupCreatePage-CieMsgWV.js +310 -0
  18. package/dist/PickupCreatePage-CieMsgWV.js.map +1 -0
  19. package/dist/PickupsPage-Ci2Ll0Kn.js +566 -0
  20. package/dist/PickupsPage-Ci2Ll0Kn.js.map +1 -0
  21. package/dist/PmGuard-CjJBisaN.js +1195 -0
  22. package/dist/PmGuard-CjJBisaN.js.map +1 -0
  23. package/dist/PmTable-BuXZQZCU.js +302 -0
  24. package/dist/PmTable-BuXZQZCU.js.map +1 -0
  25. package/dist/ProductEditPage-DL8gy85Y.js +666 -0
  26. package/dist/ProductEditPage-DL8gy85Y.js.map +1 -0
  27. package/dist/ProductsPage-BANTKxLb.js +221 -0
  28. package/dist/ProductsPage-BANTKxLb.js.map +1 -0
  29. package/dist/PurchaseCreatePage-C3KMfBxJ.js +626 -0
  30. package/dist/PurchaseCreatePage-C3KMfBxJ.js.map +1 -0
  31. package/dist/PurchaseRequestDetailPage-C0GYFJDl.js +586 -0
  32. package/dist/PurchaseRequestDetailPage-C0GYFJDl.js.map +1 -0
  33. package/dist/PurchaseRequestsPage-DvFH_tWe.js +265 -0
  34. package/dist/PurchaseRequestsPage-DvFH_tWe.js.map +1 -0
  35. package/dist/PurchasesPage-BCvLvSp4.js +295 -0
  36. package/dist/PurchasesPage-BCvLvSp4.js.map +1 -0
  37. package/dist/SaleCreatePage-DpkQMoTq.js +548 -0
  38. package/dist/SaleCreatePage-DpkQMoTq.js.map +1 -0
  39. package/dist/SalesPage-DUwgkEO-.js +315 -0
  40. package/dist/SalesPage-DUwgkEO-.js.map +1 -0
  41. package/dist/SettingsPage-CusC0jqJ.js +710 -0
  42. package/dist/SettingsPage-CusC0jqJ.js.map +1 -0
  43. package/dist/StorageUnitsPage-BlC2AgrJ.js +469 -0
  44. package/dist/StorageUnitsPage-BlC2AgrJ.js.map +1 -0
  45. package/dist/TransactionsPage-DDaK4VyY.js +714 -0
  46. package/dist/TransactionsPage-DDaK4VyY.js.map +1 -0
  47. package/dist/TransferCreatePage-BxudLfhS.js +363 -0
  48. package/dist/TransferCreatePage-BxudLfhS.js.map +1 -0
  49. package/dist/TransfersPage-zgmt7teZ.js +480 -0
  50. package/dist/TransfersPage-zgmt7teZ.js.map +1 -0
  51. package/dist/VialsPage-CjqPfgpV.js +855 -0
  52. package/dist/VialsPage-CjqPfgpV.js.map +1 -0
  53. package/dist/constants-BrA_hfAI.js +254 -0
  54. package/dist/constants-BrA_hfAI.js.map +1 -0
  55. package/dist/currency-BDDCDgeE.js +169 -0
  56. package/dist/currency-BDDCDgeE.js.map +1 -0
  57. package/dist/format-UOyOu75i.js +52 -0
  58. package/dist/format-UOyOu75i.js.map +1 -0
  59. package/dist/index.js +45 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/useFieldErrors-hDG8ox_x.js +29 -0
  62. package/dist/useFieldErrors-hDG8ox_x.js.map +1 -0
  63. package/dist/validation-Ba7puFIO.js +109 -0
  64. package/dist/validation-Ba7puFIO.js.map +1 -0
  65. package/package.json +36 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TransactionsPage-DDaK4VyY.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 function applyFilters(next) {\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 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 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}>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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"}
@@ -0,0 +1,363 @@
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";
3
+ import { t as c } from "./format-UOyOu75i.js";
4
+ import { useMemo as l, useState as u } from "react";
5
+ import { jsx as d, jsxs as f } from "react/jsx-runtime";
6
+ import { v4 as p } from "uuid";
7
+ import { Alert as te, Autocomplete as m, Box as h, Button as g, Card as _, CardContent as v, Chip as y, FormControl as b, FormHelperText as x, Grid as S, InputLabel as C, MenuItem as w, Select as T, Stack as E, TextField as D, Typography as O } from "@mui/material";
8
+ import { showToast as ne } from "@/common/toaster/toaster";
9
+ import { useNavigate as k } from "react-router-dom";
10
+ import A from "@mui/icons-material/SaveRounded";
11
+ //#region src/views/TransferCreatePage.jsx
12
+ function j(e) {
13
+ return !(e.ownerType !== "FACILITY" || Number(e.qtyRemaining ?? 0) <= 0 || e.status === "EXPIRED" || e.status === "EXHAUSTED" || e.status === "QUARANTINED");
14
+ }
15
+ function M() {
16
+ let M = k(), [N, P] = u([]), [F, I] = u([]), [L, re] = u([]), [ie, ae] = u(!0), [R, z] = u(!1), [B, V] = u(""), [H, U] = u({
17
+ id: p(),
18
+ sourceFacilityId: "",
19
+ sourceBatchId: "",
20
+ destFacilityId: "",
21
+ destStorageUnitId: "",
22
+ qty: 1,
23
+ notes: ""
24
+ });
25
+ ee("update.manage.productManagement.transfer", () => {
26
+ async function r() {
27
+ try {
28
+ let [r, i, a] = await Promise.all([
29
+ e(),
30
+ n(),
31
+ t({ activeOnly: !0 })
32
+ ]);
33
+ P(r), I(i), re(a);
34
+ } catch (e) {
35
+ V(e?.response?.data?.message ?? e?.message ?? "Failed to load reference data");
36
+ } finally {
37
+ ae(!1);
38
+ }
39
+ }
40
+ r();
41
+ }, []);
42
+ function W(e, t) {
43
+ U((n) => ({
44
+ ...n,
45
+ [e]: t
46
+ }));
47
+ }
48
+ function G(e) {
49
+ U((t) => ({
50
+ ...t,
51
+ sourceFacilityId: e,
52
+ sourceBatchId: ""
53
+ }));
54
+ }
55
+ function K(e) {
56
+ U((t) => ({
57
+ ...t,
58
+ destFacilityId: e,
59
+ destStorageUnitId: ""
60
+ }));
61
+ }
62
+ let q = l(() => H.sourceFacilityId ? F.filter(j).filter((e) => e.ownerId === H.sourceFacilityId) : [], [F, H.sourceFacilityId]), J = l(() => F.find((e) => e.id === H.sourceBatchId) ?? null, [F, H.sourceBatchId]), Y = l(() => H.destFacilityId ? L.filter((e) => e.ownerId === H.destFacilityId) : [], [L, H.destFacilityId]), oe = l(() => N.filter((e) => e.id !== H.sourceFacilityId), [N, H.sourceFacilityId]), X = Number(H.qty), Z = Number(J?.qtyRemaining ?? 0), Q = J ? !Number.isInteger(X) || X <= 0 ? "Enter a whole number greater than 0." : X > Z ? `Only ${Z} available in this batch.` : "" : "", $ = !!H.sourceFacilityId && !!H.sourceBatchId && !!H.destFacilityId && !Q;
63
+ async function se() {
64
+ if ($) {
65
+ z(!0), V("");
66
+ try {
67
+ let e = await a({
68
+ id: H.id,
69
+ sourceBatchId: H.sourceBatchId,
70
+ destFacilityId: H.destFacilityId,
71
+ destStorageUnitId: H.destStorageUnitId || null,
72
+ qty: X,
73
+ notes: H.notes || null
74
+ });
75
+ ne({
76
+ message: `Shipped ${e.qty} ${e.qty === 1 ? "unit" : "units"} to ${e.destFacilityName ?? "destination"}.`,
77
+ type: "success"
78
+ }), M("/ui/medplat/manage/pm/transfers");
79
+ } catch (e) {
80
+ V(e?.response?.data?.message ?? e?.message ?? "Failed to ship transfer");
81
+ } finally {
82
+ z(!1);
83
+ }
84
+ }
85
+ }
86
+ return /* @__PURE__ */ f(h, { children: [/* @__PURE__ */ d(i, {}), /* @__PURE__ */ d(o, {
87
+ perm: "update.manage.productManagement.transfer",
88
+ title: "You don’t have permission to ship transfers",
89
+ children: /* @__PURE__ */ f(r, {
90
+ title: "Ship Stock Transfer",
91
+ subtitle: "Send stock between facilities. The sender loses stock right away. The receiver creates the batch when they confirm receipt.",
92
+ actions: /* @__PURE__ */ f(E, {
93
+ direction: "row",
94
+ spacing: 1,
95
+ children: [/* @__PURE__ */ d(g, {
96
+ variant: "outlined",
97
+ onClick: () => M("/ui/medplat/manage/pm/transfers"),
98
+ children: "Cancel"
99
+ }), /* @__PURE__ */ d(g, {
100
+ variant: "contained",
101
+ startIcon: /* @__PURE__ */ d(A, {}),
102
+ disabled: !$ || R,
103
+ onClick: () => void se(),
104
+ children: R ? "Shipping…" : "Ship Transfer"
105
+ })]
106
+ }),
107
+ children: [
108
+ B ? /* @__PURE__ */ d(te, {
109
+ severity: "error",
110
+ sx: { mb: 2 },
111
+ children: B
112
+ }) : null,
113
+ /* @__PURE__ */ d(_, {
114
+ sx: {
115
+ borderRadius: 4,
116
+ mb: 2,
117
+ border: "1px solid",
118
+ borderColor: "divider",
119
+ boxShadow: "0 12px 32px rgba(15, 23, 42, 0.045)"
120
+ },
121
+ children: /* @__PURE__ */ f(v, {
122
+ sx: { p: 2.5 },
123
+ children: [/* @__PURE__ */ d(s, {
124
+ eyebrow: "Step 1",
125
+ title: "Source",
126
+ hint: "Select the sending facility and the batch.",
127
+ sx: { mb: 2 }
128
+ }), /* @__PURE__ */ f(S, {
129
+ container: !0,
130
+ spacing: 2,
131
+ children: [/* @__PURE__ */ d(S, {
132
+ item: !0,
133
+ xs: 12,
134
+ md: 5,
135
+ children: /* @__PURE__ */ d(m, {
136
+ size: "small",
137
+ options: N,
138
+ getOptionLabel: (e) => e?.name ?? "",
139
+ isOptionEqualToValue: (e, t) => e?.id === t?.id,
140
+ value: N.find((e) => e.id === H.sourceFacilityId) ?? null,
141
+ onChange: (e, t) => G(t?.id ?? ""),
142
+ loading: ie,
143
+ renderInput: (e) => /* @__PURE__ */ d(D, {
144
+ ...e,
145
+ required: !0,
146
+ label: "Source Facility",
147
+ placeholder: "Pick the shipping facility"
148
+ })
149
+ })
150
+ }), /* @__PURE__ */ d(S, {
151
+ item: !0,
152
+ xs: 12,
153
+ md: 7,
154
+ children: /* @__PURE__ */ f(b, {
155
+ required: !0,
156
+ fullWidth: !0,
157
+ size: "small",
158
+ disabled: !H.sourceFacilityId,
159
+ children: [
160
+ /* @__PURE__ */ d(C, { children: "Source Batch" }),
161
+ /* @__PURE__ */ d(T, {
162
+ label: "Source Batch",
163
+ value: H.sourceBatchId,
164
+ onChange: (e) => W("sourceBatchId", e.target.value),
165
+ children: q.length === 0 ? /* @__PURE__ */ d(w, {
166
+ disabled: !0,
167
+ value: "",
168
+ children: /* @__PURE__ */ d("em", { children: "No shippable stock at this facility" })
169
+ }) : q.map((e) => /* @__PURE__ */ f(w, {
170
+ value: e.id,
171
+ children: [
172
+ /* @__PURE__ */ d(h, {
173
+ component: "span",
174
+ sx: {
175
+ fontWeight: 700,
176
+ mr: 1
177
+ },
178
+ children: e.productName
179
+ }),
180
+ /* @__PURE__ */ f(O, {
181
+ variant: "caption",
182
+ color: "text.secondary",
183
+ sx: { mr: 1 },
184
+ children: ["qty ", e.qtyRemaining]
185
+ }),
186
+ e.lotNumber ? /* @__PURE__ */ d(O, {
187
+ variant: "caption",
188
+ sx: {
189
+ fontFamily: "monospace",
190
+ mr: 1
191
+ },
192
+ children: e.lotNumber
193
+ }) : null,
194
+ e.expiryDate ? /* @__PURE__ */ f(O, {
195
+ variant: "caption",
196
+ color: "text.secondary",
197
+ children: ["exp ", c(e.expiryDate)]
198
+ }) : null
199
+ ]
200
+ }, e.id))
201
+ }),
202
+ /* @__PURE__ */ d(x, { children: H.sourceFacilityId ? q.length === 0 ? "This facility has no shippable batches." : "Active facility batches only — quarantined / expired / exhausted stock is hidden." : "Pick a source facility first." })
203
+ ]
204
+ })
205
+ })]
206
+ })]
207
+ })
208
+ }),
209
+ /* @__PURE__ */ d(_, {
210
+ sx: {
211
+ borderRadius: 4,
212
+ mb: 2,
213
+ border: "1px solid",
214
+ borderColor: "divider",
215
+ boxShadow: "0 12px 32px rgba(15, 23, 42, 0.045)"
216
+ },
217
+ children: /* @__PURE__ */ f(v, {
218
+ sx: { p: 2.5 },
219
+ children: [/* @__PURE__ */ d(s, {
220
+ eyebrow: "Step 2",
221
+ title: "Destination",
222
+ hint: "Choose the receiving facility and where to store it. The receiver can change the storage location when they confirm.",
223
+ sx: { mb: 2 }
224
+ }), /* @__PURE__ */ f(S, {
225
+ container: !0,
226
+ spacing: 2,
227
+ children: [/* @__PURE__ */ d(S, {
228
+ item: !0,
229
+ xs: 12,
230
+ md: 6,
231
+ children: /* @__PURE__ */ d(m, {
232
+ size: "small",
233
+ options: oe,
234
+ getOptionLabel: (e) => e?.name ?? "",
235
+ isOptionEqualToValue: (e, t) => e?.id === t?.id,
236
+ value: N.find((e) => e.id === H.destFacilityId) ?? null,
237
+ onChange: (e, t) => K(t?.id ?? ""),
238
+ renderInput: (e) => /* @__PURE__ */ d(D, {
239
+ ...e,
240
+ required: !0,
241
+ label: "Destination Facility",
242
+ placeholder: "Pick the receiving facility",
243
+ helperText: "The sending facility is not shown. You can only transfer between different facilities."
244
+ })
245
+ })
246
+ }), /* @__PURE__ */ d(S, {
247
+ item: !0,
248
+ xs: 12,
249
+ md: 6,
250
+ children: /* @__PURE__ */ f(b, {
251
+ fullWidth: !0,
252
+ size: "small",
253
+ disabled: !H.destFacilityId || Y.length === 0,
254
+ children: [
255
+ /* @__PURE__ */ d(C, { children: "Suggested Storage" }),
256
+ /* @__PURE__ */ f(T, {
257
+ label: "Suggested Storage",
258
+ value: H.destStorageUnitId,
259
+ onChange: (e) => W("destStorageUnitId", e.target.value),
260
+ children: [/* @__PURE__ */ d(w, {
261
+ value: "",
262
+ children: /* @__PURE__ */ d("em", { children: "— No suggestion —" })
263
+ }), Y.map((e) => /* @__PURE__ */ d(w, {
264
+ value: e.id,
265
+ children: e.unitName
266
+ }, e.id))]
267
+ }),
268
+ /* @__PURE__ */ d(x, { children: H.destFacilityId ? Y.length === 0 ? "No storage units configured at this facility." : "The receiver can override on confirm." : "Pick a destination facility first." })
269
+ ]
270
+ })
271
+ })]
272
+ })]
273
+ })
274
+ }),
275
+ J ? /* @__PURE__ */ d(_, {
276
+ sx: {
277
+ borderRadius: 4,
278
+ mb: 2,
279
+ border: "1px solid",
280
+ borderColor: "divider",
281
+ boxShadow: "0 12px 32px rgba(15, 23, 42, 0.045)"
282
+ },
283
+ children: /* @__PURE__ */ f(v, {
284
+ sx: { p: 2.5 },
285
+ children: [
286
+ /* @__PURE__ */ d(s, {
287
+ eyebrow: "Step 3",
288
+ title: "Quantity",
289
+ hint: `Available: ${Z}. You can send up to this amount.`,
290
+ sx: { mb: 2 }
291
+ }),
292
+ /* @__PURE__ */ f(S, {
293
+ container: !0,
294
+ spacing: 2,
295
+ children: [/* @__PURE__ */ d(S, {
296
+ item: !0,
297
+ xs: 12,
298
+ md: 4,
299
+ children: /* @__PURE__ */ d(D, {
300
+ required: !0,
301
+ fullWidth: !0,
302
+ size: "small",
303
+ type: "number",
304
+ label: "Ship Quantity",
305
+ inputProps: {
306
+ min: 1,
307
+ max: Z
308
+ },
309
+ value: H.qty,
310
+ onChange: (e) => W("qty", e.target.value),
311
+ error: !!Q,
312
+ helperText: Q || `Out of ${Z} available`
313
+ })
314
+ }), /* @__PURE__ */ d(S, {
315
+ item: !0,
316
+ xs: 12,
317
+ md: 8,
318
+ children: /* @__PURE__ */ d(D, {
319
+ fullWidth: !0,
320
+ size: "small",
321
+ label: "Notes (optional)",
322
+ placeholder: "Tracking number, courier, anything worth recording",
323
+ value: H.notes,
324
+ onChange: (e) => W("notes", e.target.value)
325
+ })
326
+ })]
327
+ }),
328
+ /* @__PURE__ */ f(E, {
329
+ direction: "row",
330
+ spacing: 1,
331
+ sx: { mt: 2 },
332
+ flexWrap: "wrap",
333
+ useFlexGap: !0,
334
+ children: [
335
+ /* @__PURE__ */ d(y, {
336
+ size: "small",
337
+ label: `Product · ${J.productName}`
338
+ }),
339
+ J.lotNumber ? /* @__PURE__ */ d(y, {
340
+ size: "small",
341
+ label: `Lot · ${J.lotNumber}`
342
+ }) : null,
343
+ J.expiryDate ? /* @__PURE__ */ d(y, {
344
+ size: "small",
345
+ label: `Expiry · ${c(J.expiryDate)}`
346
+ }) : null,
347
+ J.storageUnitName ? /* @__PURE__ */ d(y, {
348
+ size: "small",
349
+ label: `From · ${J.storageUnitName}`
350
+ }) : null
351
+ ]
352
+ })
353
+ ]
354
+ })
355
+ }) : null
356
+ ]
357
+ })
358
+ })] });
359
+ }
360
+ //#endregion
361
+ export { M as default };
362
+
363
+ //# sourceMappingURL=TransferCreatePage-BxudLfhS.js.map
@@ -0,0 +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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"}