@argusoft/medplat-product-management 1.0.7 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/{BrandsPage-CdqGFmGf.js → BrandsPage-DmRW5bhm.js} +77 -78
  2. package/dist/{BrandsPage-CdqGFmGf.js.map → BrandsPage-DmRW5bhm.js.map} +1 -1
  3. package/dist/{CategoriesPage-DJM0Nalw.js → CategoriesPage-BsS5IQh3.js} +6 -7
  4. package/dist/{CategoriesPage-DJM0Nalw.js.map → CategoriesPage-BsS5IQh3.js.map} +1 -1
  5. package/dist/{DashboardPage-BASkXr00.js → DashboardPage-C3bKc5na.js} +3 -3
  6. package/dist/{DashboardPage-BASkXr00.js.map → DashboardPage-C3bKc5na.js.map} +1 -1
  7. package/dist/{FacilityPicker-jV-qXp1k.js → FacilityPicker-BiZeupmP.js} +6 -8
  8. package/dist/{FacilityPicker-jV-qXp1k.js.map → FacilityPicker-BiZeupmP.js.map} +1 -1
  9. package/dist/{InventoryPage-CTdq6txa.js → InventoryPage-C_AxSy7A.js} +9 -12
  10. package/dist/{InventoryPage-CTdq6txa.js.map → InventoryPage-C_AxSy7A.js.map} +1 -1
  11. package/dist/{MemberProfileCard-DwWda-tS.js → MemberProfileCard-BdUNgHRB.js} +3 -3
  12. package/dist/{MemberProfileCard-DwWda-tS.js.map → MemberProfileCard-BdUNgHRB.js.map} +1 -1
  13. package/dist/{PaymentCreatePage-B3bP-K01.js → PaymentCreatePage-CIVe0P0p.js} +114 -114
  14. package/dist/{PaymentCreatePage-B3bP-K01.js.map → PaymentCreatePage-CIVe0P0p.js.map} +1 -1
  15. package/dist/{PaymentsPage-Dh8bqXVE.js → PaymentsPage-BvPe5Q9F.js} +4 -4
  16. package/dist/{PaymentsPage-Dh8bqXVE.js.map → PaymentsPage-BvPe5Q9F.js.map} +1 -1
  17. package/dist/{PickupBatchLinesEditor-B2fLx1lU.js → PickupBatchLinesEditor-DHmcAG23.js} +2 -2
  18. package/dist/{PickupBatchLinesEditor-B2fLx1lU.js.map → PickupBatchLinesEditor-DHmcAG23.js.map} +1 -1
  19. package/dist/{PickupCreatePage-BeYhR45k.js → PickupCreatePage-CB0Sl0Hb.js} +58 -58
  20. package/dist/PickupCreatePage-CB0Sl0Hb.js.map +1 -0
  21. package/dist/{PickupsPage-C6lBtAoQ.js → PickupsPage-Ctpghavs.js} +7 -9
  22. package/dist/{PickupsPage-C6lBtAoQ.js.map → PickupsPage-Ctpghavs.js.map} +1 -1
  23. package/dist/{PmGuard-DrIl1sHL.js → PmGuard-b10TGXEi.js} +3 -3
  24. package/dist/{PmGuard-DrIl1sHL.js.map → PmGuard-b10TGXEi.js.map} +1 -1
  25. package/dist/{PmTable-BSV_bMJZ.js → PmTable-_GbScaa4.js} +3 -4
  26. package/dist/{PmTable-BSV_bMJZ.js.map → PmTable-_GbScaa4.js.map} +1 -1
  27. package/dist/{ProductEditPage-DZTUH95T.js → ProductEditPage-C1thoKHu.js} +8 -9
  28. package/dist/{ProductEditPage-DZTUH95T.js.map → ProductEditPage-C1thoKHu.js.map} +1 -1
  29. package/dist/{ProductsPage-CqOsah4_.js → ProductsPage-CupVmOD4.js} +4 -4
  30. package/dist/{ProductsPage-CqOsah4_.js.map → ProductsPage-CupVmOD4.js.map} +1 -1
  31. package/dist/{PurchaseCreatePage-D6os7srp.js → PurchaseCreatePage-YD3NmhPQ.js} +6 -6
  32. package/dist/{PurchaseCreatePage-D6os7srp.js.map → PurchaseCreatePage-YD3NmhPQ.js.map} +1 -1
  33. package/dist/{PurchaseRequestDetailPage-DErqGKiq.js → PurchaseRequestDetailPage-Dg_MRY_N.js} +6 -7
  34. package/dist/{PurchaseRequestDetailPage-DErqGKiq.js.map → PurchaseRequestDetailPage-Dg_MRY_N.js.map} +1 -1
  35. package/dist/{PurchaseRequestsPage-CHBoRzzH.js → PurchaseRequestsPage-DPAPzpmm.js} +4 -4
  36. package/dist/{PurchaseRequestsPage-CHBoRzzH.js.map → PurchaseRequestsPage-DPAPzpmm.js.map} +1 -1
  37. package/dist/{PurchasesPage-C-2K7wH6.js → PurchasesPage-It1GHiXl.js} +4 -4
  38. package/dist/{PurchasesPage-C-2K7wH6.js.map → PurchasesPage-It1GHiXl.js.map} +1 -1
  39. package/dist/{SaleCreatePage-DB3_UEgy.js → SaleCreatePage-C9kFmTvm.js} +20 -20
  40. package/dist/{SaleCreatePage-DB3_UEgy.js.map → SaleCreatePage-C9kFmTvm.js.map} +1 -1
  41. package/dist/{SalesPage-BhBGG426.js → SalesPage-D18DCseD.js} +74 -74
  42. package/dist/{SalesPage-BhBGG426.js.map → SalesPage-D18DCseD.js.map} +1 -1
  43. package/dist/{SettingsPage-CBUu9DZK.js → SettingsPage-VsxI-ano.js} +4 -4
  44. package/dist/{SettingsPage-CBUu9DZK.js.map → SettingsPage-VsxI-ano.js.map} +1 -1
  45. package/dist/{StorageUnitsPage-oe0lXLd1.js → StorageUnitsPage-7EqwuMOI.js} +7 -8
  46. package/dist/{StorageUnitsPage-oe0lXLd1.js.map → StorageUnitsPage-7EqwuMOI.js.map} +1 -1
  47. package/dist/{TransactionsPage-7dRZpZOD.js → TransactionsPage-DrH53pVS.js} +4 -4
  48. package/dist/{TransactionsPage-7dRZpZOD.js.map → TransactionsPage-DrH53pVS.js.map} +1 -1
  49. package/dist/{TransferCreatePage-DtkAlP9l.js → TransferCreatePage-CuvoMrYH.js} +4 -4
  50. package/dist/{TransferCreatePage-DtkAlP9l.js.map → TransferCreatePage-CuvoMrYH.js.map} +1 -1
  51. package/dist/{TransfersPage-BaEjbvnj.js → TransfersPage-Cf701t8s.js} +4 -4
  52. package/dist/{TransfersPage-BaEjbvnj.js.map → TransfersPage-Cf701t8s.js.map} +1 -1
  53. package/dist/{VialsPage-vo9Of9oC.js → VialsPage-8oAc1yFv.js} +5 -5
  54. package/dist/{VialsPage-vo9Of9oC.js.map → VialsPage-8oAc1yFv.js.map} +1 -1
  55. package/dist/constants-ClZJY2x1.js.map +1 -1
  56. package/dist/format-UOyOu75i.js.map +1 -1
  57. package/dist/index.js +253 -240
  58. package/dist/index.js.map +1 -1
  59. package/dist/{settingsStore-BlA2GIhl.js → settingsStore-BifOsjlB.js} +2 -2
  60. package/dist/{settingsStore-BlA2GIhl.js.map → settingsStore-BifOsjlB.js.map} +1 -1
  61. package/dist/{validation-B6Kl5Xf9.js → validation-BzlHnL-r.js} +16 -15
  62. package/dist/{validation-B6Kl5Xf9.js.map → validation-BzlHnL-r.js.map} +1 -1
  63. package/package.json +1 -1
  64. package/dist/PickupCreatePage-BeYhR45k.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ProductEditPage-DZTUH95T.js","names":[],"sources":["../src/views/ProductEditPage.jsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from 'react';\nimport PropTypes from 'prop-types';\nimport { useNavigate, useParams } from 'react-router-dom';\nimport { v4 as uuidv4 } from 'uuid';\nimport { usePermissionedEffect } from '@pm/utils/permissions';\nimport {\n Alert,\n Box,\n Button,\n Card,\n CardContent,\n Checkbox,\n CircularProgress,\n Divider,\n FormControlLabel,\n Grid,\n IconButton,\n Stack,\n TextField,\n Typography,\n} from '@mui/material';\nimport SaveRoundedIcon from '@mui/icons-material/SaveRounded';\nimport AddRoundedIcon from '@mui/icons-material/AddRounded';\nimport AddPhotoAlternateRoundedIcon from '@mui/icons-material/AddPhotoAlternateRounded';\nimport CloseRoundedIcon from '@mui/icons-material/CloseRounded';\nimport DeleteOutlineRoundedIcon from '@mui/icons-material/DeleteOutlineRounded';\nimport { showToast } from '@pm/utils/pmToast';\nimport PmPageShell from '@pm/components/PmPageShell';\nimport PmNav from '@pm/components/PmNav';\nimport PmGuard from '@pm/components/PmGuard';\nimport {\n fetchProductImage,\n getBrands,\n getCategories,\n getImmunizationMaster,\n getProduct,\n uploadProductImages,\n upsertProduct,\n} from '@pm/services/pmApi';\nimport { AGE_UNITS, PRODUCT_UNITS, SALE_PRICE_MODES, VACCINES_CATEGORY_CODE, VACCINE_ROUTES, VACCINE_UNITS, VALIDITY_UNITS } from '@pm/utils/constants';\nimport {\n isClean,\n validateMaxConcurrentVials,\n validateOpenVialValidity,\n validateReconstitutedValidity,\n validateRequired,\n validateTempRange,\n validateVialVolume,\n} from '@pm/utils/validation';\nimport { useFieldErrors } from '@pm/utils/useFieldErrors';\nimport { usePmSettings } from '@pm/utils/settingsStore';\nimport { PmFieldHelp, PmSelect } from '@pm/components/PmTable';\n\n// Backend caps a product at 5 images (see updateProductImageMappings); mirror\n// that here so the UI blocks the 6th before an upload round-trip.\nconst MAX_PRODUCT_IMAGES = 5;\nconst MAX_IMAGE_BYTES = 5 * 1024 * 1024; // 5 MB per file\n\n// Shared style for the sub-section headers inside the Vaccine Configuration card.\nconst VC_SUBHEAD = {\n display: 'block',\n fontWeight: 800,\n letterSpacing: 0.6,\n color: 'text.secondary',\n};\n\n// One age-based administration profile in the form. The band runs from\n// [fromAge fromUnit] (inclusive) up to [toAge toUnit] (exclusive), measured from\n// the patient's reference date; dose is a single amount.\nfunction emptyProfile() {\n return {\n key: uuidv4(), profileType: 'AGE_BASED',\n fromAge: '', fromUnit: 'YEARS', toAge: '', toUnit: 'YEARS', doseAmount: '',\n };\n}\n\nconst EMPTY_VACCINE = {\n vaccineCode: '',\n vialVolumeMl: '',\n singleDose: false,\n profiles: [emptyProfile()],\n openVialValidityHours: 6,\n openVialValidityUnit: 'HOURS',\n maxConcurrentOpenVials: 2,\n requiresReconstitution: false,\n reconstitutedValidityHours: '',\n reconstitutedValidityUnit: 'HOURS',\n route: '',\n storageTempMinCelsius: '',\n storageTempMaxCelsius: '',\n comments: '',\n};\n\nfunction buildVaccinePayload(v, isDrops) {\n const single = !isDrops && !!v.singleDose;\n const num = (x) => (x === '' || x == null ? null : Number(x));\n return {\n vaccineCode: v.vaccineCode?.trim().toUpperCase(),\n vialVolumeMl: Number(v.vialVolumeMl),\n // Single-dose vial: one dose = vial volume, so no profiles are sent.\n singleDose: single,\n profiles: single ? [] : (v.profiles ?? []).map((p) => {\n const toAge = num(p.toAge);\n return {\n profileType: p.profileType || 'AGE_BASED',\n fromAge: num(p.fromAge),\n fromUnit: p.fromUnit || 'YEARS',\n toAge,\n toUnit: toAge == null ? null : (p.toUnit || 'YEARS'),\n doseAmount: num(p.doseAmount),\n };\n }),\n openVialValidityHours: Number(v.openVialValidityHours ?? 6),\n openVialValidityUnit: v.openVialValidityUnit || 'HOURS',\n maxConcurrentOpenVials: single ? null : Number(v.maxConcurrentOpenVials ?? 2),\n requiresReconstitution: !!v.requiresReconstitution,\n reconstitutedValidityHours: num(v.reconstitutedValidityHours),\n reconstitutedValidityUnit: v.reconstitutedValidityUnit || 'HOURS',\n route: v.route || null,\n storageTempMinCelsius: num(v.storageTempMinCelsius),\n storageTempMaxCelsius: num(v.storageTempMaxCelsius),\n comments: v.comments || null,\n };\n}\n\nexport default function ProductEditPage() {\n const { productId } = useParams();\n const navigate = useNavigate();\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState('');\n // Whether this page is creating a brand-new product (no existing row) vs\n // editing an existing one. Drives the \"Add\" vs \"Edit\" header. The route\n // always carries a product id (even for new), so we can't infer it from\n // the id alone — it's resolved by whether getProduct found a record.\n const [isNew, setIsNew] = useState(false);\n const [categories, setCategories] = useState([]);\n const [brands, setBrands] = useState([]);\n const [vaccineMaster, setVaccineMaster] = useState([]);\n const fieldErrors = useFieldErrors();\n const settings = usePmSettings();\n const manageSales = settings?.manageSales !== false;\n const [form, setForm] = useState({\n id: productId,\n name: '',\n categoryId: '',\n brandId: '',\n description: '',\n unit: '',\n unitOther: '',\n hasExpiry: true,\n needsStorageUnit: false,\n notForSale: false,\n canBeQuarantined: true,\n salePriceMode: 'FREE',\n salePrice: '',\n isActive: true,\n imageUuids: [],\n vaccineConfig: null,\n });\n\n const selectedCategory = useMemo(\n () => categories.find((c) => c.id === form.categoryId),\n [categories, form.categoryId]\n );\n const isVaccine = selectedCategory?.code?.toUpperCase() === VACCINES_CATEGORY_CODE;\n // A vaccine is measured either in ml (unit VIAL) or in drops (unit DROPS).\n const isDrops = isVaccine && form.unit === 'DROPS';\n\n usePermissionedEffect('update.manage.productManagement.product', () => {\n async function load() {\n setLoading(true);\n try {\n const [cats, brandList, vaccines] = await Promise.all([\n getCategories(),\n getBrands(),\n getImmunizationMaster().catch(() => []),\n ]);\n setCategories(cats);\n setBrands(brandList);\n setVaccineMaster(vaccines);\n\n // Try fetching existing product; if it returns 404 we treat it as new.\n try {\n const existing = await getProduct(productId);\n setIsNew(false);\n setForm({\n id: existing.id,\n name: existing.name ?? '',\n categoryId: existing.categoryId ?? '',\n brandId: existing.brandId ?? '',\n description: existing.description ?? '',\n unit: existing.unit ?? 'PIECE',\n unitOther: existing.unitOther ?? '',\n hasExpiry: existing.hasExpiry ?? false,\n needsStorageUnit: existing.needsStorageUnit ?? false,\n notForSale: existing.notForSale ?? false,\n canBeQuarantined: existing.canBeQuarantined ?? true,\n salePriceMode: existing.salePriceMode ?? 'FREE',\n salePrice: existing.salePrice ?? '',\n isActive: existing.isActive ?? true,\n imageUuids: existing.imageUuids ?? [],\n vaccineConfig: existing.vaccineConfig\n ? {\n vaccineCode: existing.vaccineConfig.vaccineCode ?? '',\n vialVolumeMl: existing.vaccineConfig.vialVolumeMl ?? '',\n singleDose: existing.vaccineConfig.singleDose ?? false,\n profiles: (existing.vaccineConfig.profiles ?? []).length > 0\n ? existing.vaccineConfig.profiles.map((p) => ({\n key: uuidv4(),\n profileType: p.profileType ?? 'AGE_BASED',\n fromAge: p.fromAge ?? '',\n fromUnit: p.fromUnit ?? 'YEARS',\n toAge: p.toAge ?? '',\n toUnit: p.toUnit ?? 'YEARS',\n doseAmount: p.doseAmount ?? '',\n }))\n : [emptyProfile()],\n openVialValidityHours: existing.vaccineConfig.openVialValidityHours ?? 6,\n openVialValidityUnit: existing.vaccineConfig.openVialValidityUnit ?? 'HOURS',\n maxConcurrentOpenVials: existing.vaccineConfig.maxConcurrentOpenVials ?? 2,\n requiresReconstitution: existing.vaccineConfig.requiresReconstitution ?? false,\n reconstitutedValidityHours: existing.vaccineConfig.reconstitutedValidityHours ?? '',\n reconstitutedValidityUnit: existing.vaccineConfig.reconstitutedValidityUnit ?? 'HOURS',\n route: existing.vaccineConfig.route ?? '',\n storageTempMinCelsius: existing.vaccineConfig.storageTempMinCelsius ?? '',\n storageTempMaxCelsius: existing.vaccineConfig.storageTempMaxCelsius ?? '',\n comments: existing.vaccineConfig.comments ?? '',\n }\n : null,\n });\n } catch {\n // new product – fall through with default form\n setIsNew(true);\n }\n } catch (err) {\n setError(err?.response?.data?.message ?? err?.message ?? 'Failed to load product');\n } finally {\n setLoading(false);\n }\n }\n void load();\n }, [productId]);\n\n useEffect(() => {\n if (isVaccine) {\n // Vaccines are dispensed per vial and live in cold-chain storage — pin both\n // the unit and needsStorageUnit so they can't drift away from those rules.\n setForm((f) => ({\n ...f,\n // Vaccines use VIAL (ml) or DROPS; keep whichever is already chosen.\n unit: (f.unit === 'VIAL' || f.unit === 'DROPS') ? f.unit : 'VIAL',\n needsStorageUnit: true,\n vaccineConfig: f.vaccineConfig ?? { ...EMPTY_VACCINE },\n }));\n } else {\n // Switched to (or loaded as) a non-vaccine category — drop any vaccine\n // config so it isn't sent on save. Persisting half-filled config for a\n // non-vaccine product would error on the backend.\n setForm((f) => (f.vaccineConfig ? { ...f, vaccineConfig: null } : f));\n }\n }, [isVaccine]);\n\n function patch(k, v) {\n setForm((f) => ({ ...f, [k]: v }));\n }\n\n function patchVaccine(k, v) {\n setForm((f) => ({ ...f, vaccineConfig: { ...(f.vaccineConfig ?? EMPTY_VACCINE), [k]: v } }));\n }\n\n // -------------------- Administration profiles --------------------\n function patchProfile(idx, k, val) {\n setForm((f) => {\n const cfg = f.vaccineConfig ?? EMPTY_VACCINE;\n const profiles = (cfg.profiles ?? []).slice();\n profiles[idx] = { ...profiles[idx], [k]: val };\n return { ...f, vaccineConfig: { ...cfg, profiles } };\n });\n }\n function addProfile() {\n setForm((f) => {\n const cfg = f.vaccineConfig ?? EMPTY_VACCINE;\n return { ...f, vaccineConfig: { ...cfg, profiles: [...(cfg.profiles ?? []), emptyProfile()] } };\n });\n }\n function removeProfile(idx) {\n setForm((f) => {\n const cfg = f.vaccineConfig ?? EMPTY_VACCINE;\n return { ...f, vaccineConfig: { ...cfg, profiles: (cfg.profiles ?? []).filter((_, i) => i !== idx) } };\n });\n }\n\n // Repeatable editor for the vaccine's age-based dose profiles (multi-dose\n // vaccines). Each profile = an age band + one dose; the matching profile is\n // picked automatically at administration from the patient's reference date.\n function renderProfilesEditor() {\n const v = form.vaccineConfig ?? {};\n const profiles = v.profiles ?? [];\n const unitLbl = isDrops ? 'drops' : 'ml';\n const numProps = isDrops ? { min: 0, step: 1 } : { step: '0.01', min: 0 };\n return (\n <Box>\n <Stack direction=\"row\" justifyContent=\"space-between\" alignItems=\"center\" sx={{ mb: 0.5 }}>\n <Typography variant=\"body2\" sx={{ fontWeight: 700 }}>Dose profiles</Typography>\n <Button size=\"small\" variant=\"outlined\" startIcon={<AddRoundedIcon />} onClick={addProfile}>Add profile</Button>\n </Stack>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', mb: 1.5 }}>\n Each band sets one dose. It is measured from the patient&apos;s reference date, so the right dose is chosen automatically when giving the vaccine.\n <br />\n <strong>From</strong> is included and <strong>To</strong> is not — a patient exactly at a To value falls into the next band. Leave To blank for no upper limit.\n </Typography>\n <Stack spacing={1.5}>\n {profiles.map((p, idx) => {\n const kf = `profiles.${idx}.fromAge`;\n const kt = `profiles.${idx}.toAge`;\n const kd = `profiles.${idx}.doseAmount`;\n const hasTo = p.toAge !== '' && p.toAge != null;\n return (\n <Box key={p.key} sx={{ p: 1.5, border: '1px solid', borderColor: 'divider', borderRadius: 1.5 }}>\n <Grid container spacing={1.5} alignItems=\"flex-start\">\n <Grid item xs={6} md={2}>\n <TextField required fullWidth size=\"small\" type=\"number\" inputProps={{ min: 0, step: 1 }}\n label=\"From\"\n value={p.fromAge ?? ''}\n onChange={(e) => patchProfile(idx, 'fromAge', e.target.value)}\n onBlur={fieldErrors.onBlur(kf)}\n error={fieldErrors.show(kf) && !!errors[kf]}\n helperText={fieldErrors.show(kf) ? errors[kf] : ''} />\n </Grid>\n <Grid item xs={6} md={2}>\n <PmSelect label=\"From unit\" value={p.fromUnit || 'YEARS'}\n onChange={(val) => patchProfile(idx, 'fromUnit', val)} options={AGE_UNITS} />\n </Grid>\n <Grid item xs={6} md={2}>\n <TextField fullWidth size=\"small\" type=\"number\" inputProps={{ min: 0, step: 1 }}\n label=\"To\"\n value={p.toAge ?? ''}\n onChange={(e) => patchProfile(idx, 'toAge', e.target.value)}\n onBlur={fieldErrors.onBlur(kt)}\n error={fieldErrors.show(kt) && !!errors[kt]}\n helperText={fieldErrors.show(kt) && errors[kt] ? errors[kt] : 'Blank = no limit'} />\n </Grid>\n <Grid item xs={6} md={2}>\n <PmSelect label=\"To unit\" disabled={!hasTo} value={hasTo ? (p.toUnit || 'YEARS') : ''}\n onChange={(val) => patchProfile(idx, 'toUnit', val)} options={AGE_UNITS} />\n </Grid>\n <Grid item xs={8} md={3}>\n <TextField required fullWidth size=\"small\" type=\"number\" inputProps={numProps}\n label={`Dose (${unitLbl})`}\n value={p.doseAmount ?? ''}\n onChange={(e) => patchProfile(idx, 'doseAmount', e.target.value)}\n onBlur={fieldErrors.onBlur(kd)}\n error={fieldErrors.show(kd) && !!errors[kd]}\n helperText={fieldErrors.show(kd) ? errors[kd] : ''} />\n </Grid>\n <Grid item xs={4} md={1} sx={{ textAlign: 'right' }}>\n <IconButton color=\"error\" onClick={() => removeProfile(idx)} disabled={profiles.length === 1}>\n <DeleteOutlineRoundedIcon />\n </IconButton>\n </Grid>\n </Grid>\n </Box>\n );\n })}\n </Stack>\n {fieldErrors.show('profiles') && errors.profiles ? (\n <Typography variant=\"caption\" color=\"error\" sx={{ display: 'block', mt: 1 }}>{errors.profiles}</Typography>\n ) : null}\n </Box>\n );\n }\n\n // -------------------- Field-level error map --------------------\n const errors = useMemo(() => {\n const base = {\n name: validateRequired(form.name, 'Product name'),\n categoryId: validateRequired(form.categoryId, 'Category'),\n brandId: validateRequired(form.brandId, 'Brand'),\n unit: validateRequired(form.unit, 'Unit'),\n // Custom unit label is required only when unit is OTHER.\n unitOther: form.unit === 'OTHER' ? validateRequired(form.unitOther, 'Custom unit') : '',\n // Sale price required (>0) when a fixed/capped mode is chosen on a sellable product.\n salePrice: (manageSales && !form.notForSale && form.salePriceMode !== 'FREE')\n ? (validateRequired(form.salePrice, 'Sale price')\n || (Number(form.salePrice) > 0 ? '' : 'Sale price must be greater than 0.'))\n : '',\n };\n if (isVaccine && form.vaccineConfig) {\n const v = form.vaccineConfig;\n const singleDose = !isDrops && v.singleDose;\n const temps = validateTempRange(v.storageTempMinCelsius, v.storageTempMaxCelsius);\n Object.assign(base, {\n vaccineCode: validateRequired(v.vaccineCode, 'Vaccine'),\n vialVolumeMl: validateVialVolume(v.vialVolumeMl),\n // A single-dose vial is closed the instant it's opened, so an open-vial\n // validity window doesn't apply — only validate it for multi-dose vials.\n openVialValidityHours: singleDose ? '' : validateOpenVialValidity(v.openVialValidityHours),\n reconstitutedValidityHours: validateReconstitutedValidity(\n v.reconstitutedValidityHours,\n v.requiresReconstitution\n ),\n storageTempMinCelsius: temps.min,\n storageTempMaxCelsius: temps.max,\n });\n if (singleDose) {\n // Single-dose: one dose = vial volume, no profiles and no concurrency cap.\n } else {\n // Multi-dose (ml or drops): validate each age-based profile.\n const vol = Number(v.vialVolumeMl);\n const unitLbl = isDrops ? 'drops' : 'ml';\n const profiles = v.profiles ?? [];\n if (profiles.length === 0) {\n base.profiles = 'Add at least one administration profile.';\n }\n // Approximate days per unit, to compare From/To across different units.\n const UNIT_DAYS = { DAYS: 1, WEEKS: 7, MONTHS: 30, YEARS: 365 };\n const approxDays = (n, u) => Number(n) * (UNIT_DAYS[u] || 1);\n profiles.forEach((p, idx) => {\n // From: required, whole number >= 0.\n const from = Number(p.fromAge);\n if (p.fromAge === '' || p.fromAge == null) base[`profiles.${idx}.fromAge`] = 'Required';\n else if (!Number.isInteger(from) || from < 0) base[`profiles.${idx}.fromAge`] = 'Whole number, 0 or more';\n // To: optional; if present must be a whole number and after From\n // (compared across each bound's own unit).\n if (p.toAge !== '' && p.toAge != null) {\n const to = Number(p.toAge);\n if (!Number.isInteger(to) || to < 0) base[`profiles.${idx}.toAge`] = 'Whole number, 0 or more';\n else if (approxDays(to, p.toUnit) <= approxDays(from, p.fromUnit)) {\n base[`profiles.${idx}.toAge`] = 'Must be greater than From';\n }\n }\n // Dose: required, > 0, <= vial volume, whole for drops.\n const dose = Number(p.doseAmount);\n if (p.doseAmount === '' || p.doseAmount == null) base[`profiles.${idx}.doseAmount`] = 'Required';\n else if (!Number.isFinite(dose) || dose <= 0) base[`profiles.${idx}.doseAmount`] = 'Must be greater than 0';\n else if (isDrops && !Number.isInteger(dose)) base[`profiles.${idx}.doseAmount`] = 'Whole number';\n else if (Number.isFinite(vol) && vol > 0 && dose > vol) base[`profiles.${idx}.doseAmount`] = `At most ${vol} ${unitLbl}`;\n });\n base.maxConcurrentOpenVials = validateMaxConcurrentVials(v.maxConcurrentOpenVials);\n }\n }\n return base;\n }, [form, isVaccine, isDrops, manageSales]);\n\n const formIsValid = isClean(errors);\n\n async function save() {\n if (!formIsValid) {\n fieldErrors.markAllTouched();\n setError('Please fix the highlighted fields and try again.');\n return;\n }\n try {\n const payload = {\n id: form.id,\n name: form.name.trim(),\n categoryId: form.categoryId,\n brandId: form.brandId,\n description: form.description || null,\n unit: form.unit,\n unitOther: form.unit === 'OTHER' ? (form.unitOther?.trim() || null) : null,\n hasExpiry: !!form.hasExpiry,\n needsStorageUnit: !!form.needsStorageUnit,\n notForSale: manageSales ? !!form.notForSale : false,\n canBeQuarantined: !!form.canBeQuarantined,\n // Sale pricing only applies to sellable products in a money-managed\n // deployment; otherwise force FREE with no price.\n salePriceMode: (manageSales && !form.notForSale) ? form.salePriceMode : 'FREE',\n salePrice: (manageSales && !form.notForSale && form.salePriceMode !== 'FREE' && form.salePrice !== '')\n ? Number(form.salePrice) : null,\n isActive: !!form.isActive,\n imageUuids: form.imageUuids ?? [],\n vaccineConfig: form.vaccineConfig\n ? buildVaccinePayload(form.vaccineConfig, isDrops)\n : null,\n };\n await upsertProduct(payload);\n showToast({ message: 'Product saved.', type: 'success' });\n navigate('/ui/medplat/manage/pm/products');\n } catch (err) {\n setError(err?.response?.data?.message ?? err?.message ?? 'Failed to save product');\n }\n }\n\n return (\n <Box>\n <PmNav />\n <PmGuard perm={'update.manage.productManagement.product'} title=\"You don’t have permission to create or edit products\">\n <PmPageShell\n title={isNew ? 'Add Product' : 'Edit Product'}\n subtitle={`Category: ${selectedCategory?.code ?? '—'}`}\n actions={\n <Stack direction=\"row\" spacing={1}>\n <Button variant=\"outlined\" onClick={() => navigate('/ui/medplat/manage/pm/products')}>Cancel</Button>\n <Button variant=\"contained\" startIcon={<SaveRoundedIcon />}\n disabled={!formIsValid}\n onClick={() => void save()}>Save</Button>\n </Stack>\n }\n >\n {loading ? <Alert severity=\"info\">Loading…</Alert> : null}\n {error ? <Alert severity=\"error\" sx={{ mb: 2 }}>{error}</Alert> : null}\n\n <Card sx={{ borderRadius: 1.5, mb: 2 }}>\n <CardContent>\n <Typography variant=\"h6\" sx={{ fontWeight: 800, mb: 2 }}>Basic Details</Typography>\n <Grid container spacing={2}>\n <Grid item xs={12} md={6}>\n <TextField\n required\n fullWidth size=\"small\" label=\"Product Name\"\n value={form.name}\n inputProps={{ maxLength: 255 }}\n onChange={(e) => patch('name', e.target.value)}\n onBlur={fieldErrors.onBlur('name')}\n error={fieldErrors.show('name') && !!errors.name}\n FormHelperTextProps={{ component: 'div' }}\n helperText={<PmFieldHelp message={fieldErrors.show('name') ? errors.name : ''} value={form.name} max={255} />}\n />\n </Grid>\n <Grid item xs={12} md={3}>\n <PmSelect\n label=\"Category\"\n required\n value={form.categoryId}\n onChange={(v) => patch('categoryId', v)}\n onBlur={fieldErrors.onBlur('categoryId')}\n error={fieldErrors.show('categoryId') && !!errors.categoryId}\n helperText={fieldErrors.show('categoryId') ? errors.categoryId : ''}\n options={categories.map((c) => ({ value: c.id, label: `${c.name} (${c.code})` }))}\n />\n </Grid>\n <Grid item xs={12} md={3}>\n <PmSelect\n label=\"Brand\"\n required\n value={form.brandId}\n onChange={(v) => patch('brandId', v)}\n onBlur={fieldErrors.onBlur('brandId')}\n error={fieldErrors.show('brandId') && !!errors.brandId}\n helperText={fieldErrors.show('brandId') ? errors.brandId : ''}\n options={brands.map((b) => ({ value: b.id, label: b.name }))}\n />\n </Grid>\n {/* For vaccines the unit (Vial/Drops) is chosen in the Vaccine\n Configuration section below (\"Measured in\"), so it's hidden here. */}\n {isVaccine ? null : (\n <Grid item xs={12} md={3}>\n <PmSelect\n label=\"Unit\"\n required\n value={form.unit}\n onChange={(v) => patch('unit', v)}\n onBlur={fieldErrors.onBlur('unit')}\n error={fieldErrors.show('unit') && !!errors.unit}\n helperText={fieldErrors.show('unit') && errors.unit ? errors.unit : ''}\n options={PRODUCT_UNITS}\n />\n </Grid>\n )}\n {!isVaccine && form.unit === 'OTHER' ? (\n <Grid item xs={12} md={3}>\n <TextField\n required fullWidth size=\"small\" label=\"Custom unit name\"\n value={form.unitOther}\n inputProps={{ maxLength: 50 }}\n onChange={(e) => patch('unitOther', e.target.value)}\n onBlur={fieldErrors.onBlur('unitOther')}\n error={fieldErrors.show('unitOther') && !!errors.unitOther}\n FormHelperTextProps={{ component: 'div' }}\n helperText={<PmFieldHelp\n message={fieldErrors.show('unitOther') && errors.unitOther ? errors.unitOther : 'e.g. Strip, Ampoule, Sachet'}\n value={form.unitOther} max={50} />}\n />\n </Grid>\n ) : null}\n <Grid item xs={6} md={3}>\n <FormControlLabel\n control={<Checkbox\n checked={!!form.hasExpiry}\n disabled={isVaccine}\n onChange={(e) => patch('hasExpiry', e.target.checked)} />}\n label={isVaccine ? 'Has expiry (vaccine)' : 'Has expiry'} />\n </Grid>\n <Grid item xs={6} md={3}>\n <FormControlLabel\n control={<Checkbox\n checked={!!form.needsStorageUnit}\n disabled={isVaccine}\n onChange={(e) => patch('needsStorageUnit', e.target.checked)} />}\n label={isVaccine ? 'Needs storage unit (vaccine)' : 'Needs storage unit'} />\n </Grid>\n {manageSales ? (\n <Grid item xs={6} md={3}>\n <FormControlLabel control={<Checkbox checked={!!form.notForSale}\n onChange={(e) => patch('notForSale', e.target.checked)} />} label=\"Not for sale\" />\n </Grid>\n ) : null}\n <Grid item xs={6} md={3}>\n <FormControlLabel control={<Checkbox checked={!!form.canBeQuarantined}\n onChange={(e) => patch('canBeQuarantined', e.target.checked)} />} label=\"Can be quarantined\" />\n </Grid>\n <Grid item xs={6} md={3}>\n <FormControlLabel control={<Checkbox checked={!!form.isActive}\n onChange={(e) => patch('isActive', e.target.checked)} />} label=\"Active\" />\n </Grid>\n\n {/* Sale pricing — only for sellable products in a money-managed deployment. */}\n {manageSales && !form.notForSale ? (\n <>\n <Grid item xs={12} md={4}>\n <PmSelect\n label=\"Sale price mode\"\n value={form.salePriceMode}\n onChange={(v) => patch('salePriceMode', v)}\n options={SALE_PRICE_MODES}\n helperText=\"Fixed shows a locked price at sale time; MRP caps the entered price.\"\n />\n </Grid>\n {form.salePriceMode !== 'FREE' ? (\n <Grid item xs={12} md={4}>\n <TextField\n required fullWidth size=\"small\" type=\"number\"\n inputProps={{ step: '0.01', min: 0 }}\n label={form.salePriceMode === 'FIXED' ? 'Fixed sale price' : 'Price cap (MRP)'}\n value={form.salePrice}\n onChange={(e) => patch('salePrice', e.target.value)}\n onBlur={fieldErrors.onBlur('salePrice')}\n error={fieldErrors.show('salePrice') && !!errors.salePrice}\n helperText={fieldErrors.show('salePrice') ? errors.salePrice : ''}\n />\n </Grid>\n ) : null}\n </>\n ) : null}\n\n <Grid item xs={12}>\n <TextField fullWidth size=\"small\" multiline minRows={2} label=\"Description\" value={form.description}\n onChange={(e) => patch('description', e.target.value)} />\n </Grid>\n </Grid>\n </CardContent>\n </Card>\n\n <Card sx={{ borderRadius: 1.5, mb: 2 }}>\n <CardContent>\n <Stack direction=\"row\" justifyContent=\"space-between\" alignItems=\"center\" sx={{ mb: 0.5 }}>\n <Typography variant=\"h6\" sx={{ fontWeight: 800 }}>Product Images</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">Optional · up to {MAX_PRODUCT_IMAGES} images</Typography>\n </Stack>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', mb: 2 }}>\n Add photos of the product or its packaging. The first image is used as the main picture.\n </Typography>\n <ProductImagesField\n value={form.imageUuids}\n onChange={(next) => patch('imageUuids', next)}\n />\n </CardContent>\n </Card>\n\n {isVaccine ? (\n <Card sx={{ borderRadius: 1.5 }}>\n <CardContent>\n <Stack direction=\"row\" justifyContent=\"space-between\" alignItems=\"center\" sx={{ mb: 2 }}>\n <Typography variant=\"h6\" sx={{ fontWeight: 800 }}>Vaccine Configuration</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n Required for vaccine products. Controls vial size, dosing, and shelf life rules.\n </Typography>\n </Stack>\n <Divider sx={{ mb: 2 }} />\n <Grid container spacing={2}>\n {/* ---- Vaccine & measure ---- */}\n <Grid item xs={12}>\n <Typography variant=\"overline\" sx={VC_SUBHEAD}>Vaccine &amp; measure</Typography>\n </Grid>\n <Grid item xs={12} md={4}>\n <PmSelect\n label=\"Vaccine\"\n required\n value={form.vaccineConfig?.vaccineCode || ''}\n onChange={(v) => patchVaccine('vaccineCode', v)}\n onBlur={fieldErrors.onBlur('vaccineCode')}\n error={fieldErrors.show('vaccineCode') && !!errors.vaccineCode}\n helperText={fieldErrors.show('vaccineCode') && errors.vaccineCode\n ? errors.vaccineCode\n : ''}\n noOptionsText=\"No vaccines configured in immunization master\"\n options={vaccineMaster.map((v) => ({ value: v.vaccineCode, label: `${v.vaccineName} (${v.vaccineCode})` }))}\n />\n </Grid>\n <Grid item xs={12} md={4}>\n <PmSelect\n label=\"Measured in\"\n value={form.unit}\n onChange={(v) => patch('unit', v)}\n options={VACCINE_UNITS}\n helperText=\"Vials are dosed in millilitres; drops are counted.\"\n />\n </Grid>\n <Grid item xs={12} md={4}>\n <TextField required fullWidth size=\"small\" type=\"number\"\n inputProps={isDrops ? { min: 1, step: 1 } : { step: '0.01', min: 0 }}\n label={isDrops ? 'Drops per vial' : 'Vial volume (ml)'}\n value={form.vaccineConfig?.vialVolumeMl ?? ''}\n onChange={(e) => patchVaccine('vialVolumeMl', e.target.value)}\n onBlur={fieldErrors.onBlur('vialVolumeMl')}\n error={fieldErrors.show('vialVolumeMl') && !!errors.vialVolumeMl}\n helperText={fieldErrors.show('vialVolumeMl') ? errors.vialVolumeMl\n : (isDrops ? 'Total drops in a fresh vial' : '')}\n />\n </Grid>\n\n {/* ---- Dosing ---- */}\n <Grid item xs={12}>\n <Typography variant=\"overline\" sx={{ ...VC_SUBHEAD, mt: 1 }}>Dosing</Typography>\n </Grid>\n {!isDrops ? (\n <Grid item xs={12}>\n <FormControlLabel\n control={<Checkbox checked={!!form.vaccineConfig?.singleDose}\n onChange={(e) => patchVaccine('singleDose', e.target.checked)} />}\n label=\"Single dose vial\" />\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', ml: 4, mt: -0.5 }}>\n One dose per vial — used up the moment it&apos;s opened, so there&apos;s no limit on how many can be open at once.\n </Typography>\n </Grid>\n ) : null}\n <Grid item xs={12}>\n {(!isDrops && form.vaccineConfig?.singleDose) ? (\n <Box sx={{ p: 1.5, border: '1px solid', borderColor: 'divider', borderRadius: 1.5 }}>\n <Typography variant=\"body2\" sx={{ fontWeight: 700 }}>Single dose</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n Each vial is one dose of {form.vaccineConfig?.vialVolumeMl || '—'} ml, given to any patient. No dose profiles are needed.\n </Typography>\n </Box>\n ) : (\n renderProfilesEditor()\n )}\n </Grid>\n\n {/* ---- Open vial & reconstitution ---- */}\n <Grid item xs={12}>\n <Typography variant=\"overline\" sx={{ ...VC_SUBHEAD, mt: 1 }}>Open vial &amp; reconstitution</Typography>\n </Grid>\n {(!isDrops && form.vaccineConfig?.singleDose) ? null : (\n <Grid item xs={12} md={4}>\n <Stack direction=\"row\" spacing={1}>\n <TextField required fullWidth size=\"small\" type=\"number\" inputProps={{ min: 1 }}\n label=\"Open vial validity\"\n value={form.vaccineConfig?.openVialValidityHours ?? ''}\n onChange={(e) => patchVaccine('openVialValidityHours', e.target.value)}\n onBlur={fieldErrors.onBlur('openVialValidityHours')}\n error={fieldErrors.show('openVialValidityHours') && !!errors.openVialValidityHours}\n helperText={fieldErrors.show('openVialValidityHours') ? errors.openVialValidityHours : 'How long the vial stays usable once opened'}\n />\n <Box sx={{ minWidth: 132, flexShrink: 0 }}>\n <PmSelect label=\"Unit\" value={form.vaccineConfig?.openVialValidityUnit || 'HOURS'}\n onChange={(v) => patchVaccine('openVialValidityUnit', v)} options={VALIDITY_UNITS} />\n </Box>\n </Stack>\n </Grid>\n )}\n {(!isDrops && form.vaccineConfig?.singleDose) ? null : (\n <Grid item xs={12} md={4}>\n <TextField required fullWidth size=\"small\" type=\"number\" inputProps={{ min: 1, max: 20 }}\n label=\"Max concurrent open vials\"\n value={form.vaccineConfig?.maxConcurrentOpenVials ?? ''}\n onChange={(e) => patchVaccine('maxConcurrentOpenVials', e.target.value)}\n onBlur={fieldErrors.onBlur('maxConcurrentOpenVials')}\n error={fieldErrors.show('maxConcurrentOpenVials') && !!errors.maxConcurrentOpenVials}\n helperText={fieldErrors.show('maxConcurrentOpenVials') ? errors.maxConcurrentOpenVials : ''}\n />\n </Grid>\n )}\n <Grid item xs={12}>\n <FormControlLabel control={<Checkbox checked={!!form.vaccineConfig?.requiresReconstitution}\n onChange={(e) => patchVaccine('requiresReconstitution', e.target.checked)} />} label=\"Requires reconstitution\" />\n </Grid>\n {form.vaccineConfig?.requiresReconstitution ? (\n <Grid item xs={12} md={4}>\n <Stack direction=\"row\" spacing={1}>\n <TextField fullWidth size=\"small\" type=\"number\" inputProps={{ min: 1 }}\n required\n label=\"Reconstituted validity\"\n value={form.vaccineConfig?.reconstitutedValidityHours ?? ''}\n onChange={(e) => patchVaccine('reconstitutedValidityHours', e.target.value)}\n onBlur={fieldErrors.onBlur('reconstitutedValidityHours')}\n error={fieldErrors.show('reconstitutedValidityHours') && !!errors.reconstitutedValidityHours}\n helperText={fieldErrors.show('reconstitutedValidityHours') ? errors.reconstitutedValidityHours : ''}\n />\n <Box sx={{ minWidth: 132, flexShrink: 0 }}>\n <PmSelect label=\"Unit\"\n value={form.vaccineConfig?.reconstitutedValidityUnit || 'HOURS'}\n onChange={(v) => patchVaccine('reconstitutedValidityUnit', v)} options={VALIDITY_UNITS} />\n </Box>\n </Stack>\n </Grid>\n ) : null}\n\n {/* ---- Storage & route ---- */}\n <Grid item xs={12}>\n <Typography variant=\"overline\" sx={{ ...VC_SUBHEAD, mt: 1 }}>Storage &amp; route</Typography>\n </Grid>\n <Grid item xs={12} md={4}>\n <PmSelect\n label=\"Route of administration\"\n value={form.vaccineConfig?.route || ''}\n onChange={(v) => patchVaccine('route', v)}\n options={VACCINE_ROUTES}\n />\n </Grid>\n <Grid item xs={6} md={4}>\n <TextField fullWidth size=\"small\" type=\"number\" inputProps={{ step: '0.1', min: -90, max: 30 }}\n label=\"Storage temp min (°C)\"\n value={form.vaccineConfig?.storageTempMinCelsius ?? ''}\n onChange={(e) => patchVaccine('storageTempMinCelsius', e.target.value)}\n onBlur={fieldErrors.onBlur('storageTempMinCelsius')}\n error={fieldErrors.show('storageTempMinCelsius') && !!errors.storageTempMinCelsius}\n helperText={\n fieldErrors.show('storageTempMinCelsius') && errors.storageTempMinCelsius\n ? errors.storageTempMinCelsius\n : '−90°C to +30°C'\n }\n />\n </Grid>\n <Grid item xs={6} md={4}>\n <TextField fullWidth size=\"small\" type=\"number\" inputProps={{ step: '0.1', min: -90, max: 30 }}\n label=\"Storage temp max (°C)\"\n value={form.vaccineConfig?.storageTempMaxCelsius ?? ''}\n onChange={(e) => patchVaccine('storageTempMaxCelsius', e.target.value)}\n onBlur={fieldErrors.onBlur('storageTempMaxCelsius')}\n error={fieldErrors.show('storageTempMaxCelsius') && !!errors.storageTempMaxCelsius}\n helperText={\n fieldErrors.show('storageTempMaxCelsius') && errors.storageTempMaxCelsius\n ? errors.storageTempMaxCelsius\n : '−90°C to +30°C'\n }\n />\n </Grid>\n\n {/* ---- Notes ---- */}\n <Grid item xs={12}>\n <Typography variant=\"overline\" sx={{ ...VC_SUBHEAD, mt: 1 }}>Notes</Typography>\n </Grid>\n <Grid item xs={12}>\n <TextField fullWidth size=\"small\" multiline minRows={2}\n label=\"Comments\" value={form.vaccineConfig?.comments || ''}\n onChange={(e) => patchVaccine('comments', e.target.value)} />\n </Grid>\n </Grid>\n </CardContent>\n </Card>\n ) : null}\n </PmPageShell>\n </PmGuard>\n </Box>\n );\n}\n\n// Image manager for a product. Holds the list of stored image uuids in the\n// parent form; uploads picked files immediately (so each gets a persisted\n// uuid) and renders thumbnails. Newly picked files preview from a local object\n// URL; images loaded on edit are fetched (authenticated) as blobs. All object\n// URLs are revoked on unmount to avoid leaks.\nfunction ProductImagesField({ value, onChange }) {\n const uuids = value ?? [];\n const inputRef = useRef(null);\n const [uploading, setUploading] = useState(false);\n // uuid -> object URL for preview. Object URLs are tracked here and revoked\n // when the field unmounts.\n const [previews, setPreviews] = useState({});\n const previewsRef = useRef({});\n previewsRef.current = previews;\n\n function setPreview(uuid, url) {\n setPreviews((p) => (p[uuid] ? p : { ...p, [uuid]: url }));\n }\n\n // Fetch previews for any uuid we don't yet have a URL for (edit mode: images\n // arrive as uuids only). Skips ones already cached (e.g. just-uploaded files).\n useEffect(() => {\n let cancelled = false;\n uuids.forEach((uuid) => {\n if (previewsRef.current[uuid]) return;\n fetchProductImage(uuid)\n .then((blob) => {\n if (cancelled) return;\n setPreview(uuid, URL.createObjectURL(blob));\n })\n .catch(() => {});\n });\n return () => { cancelled = true; };\n }, [uuids]);\n\n // Revoke every object URL on unmount.\n useEffect(() => () => {\n Object.values(previewsRef.current).forEach((url) => {\n try { URL.revokeObjectURL(url); } catch { /* ignore */ }\n });\n }, []);\n\n async function handleFiles(fileList) {\n const picked = Array.from(fileList || []);\n if (picked.length === 0) return;\n const room = MAX_PRODUCT_IMAGES - uuids.length;\n if (room <= 0) {\n showToast({ message: `You can add at most ${MAX_PRODUCT_IMAGES} images.`, type: 'warning' });\n return;\n }\n const invalid = picked.find((f) => !f.type.startsWith('image/') || f.size > MAX_IMAGE_BYTES);\n if (invalid) {\n showToast({\n message: invalid.type.startsWith('image/')\n ? 'Each image must be 5 MB or smaller.'\n : 'Only image files can be uploaded.',\n type: 'error',\n });\n return;\n }\n const toUpload = picked.slice(0, room);\n if (picked.length > room) {\n showToast({ message: `Only ${room} more image${room === 1 ? '' : 's'} can be added.`, type: 'warning' });\n }\n const newUuids = toUpload.map(() => uuidv4());\n setUploading(true);\n try {\n await uploadProductImages(toUpload, newUuids);\n // Preview from the local files — no need to round-trip for images we\n // already hold in memory.\n toUpload.forEach((file, i) => setPreview(newUuids[i], URL.createObjectURL(file)));\n onChange([...uuids, ...newUuids]);\n } catch (err) {\n showToast({ message: err?.response?.data?.message ?? err?.message ?? 'Failed to upload images', type: 'error' });\n } finally {\n setUploading(false);\n }\n }\n\n function removeImage(uuid) {\n onChange(uuids.filter((u) => u !== uuid));\n // Keep the object URL around until unmount; re-adding the same uuid is not\n // possible from the UI, so there's nothing to reconcile.\n }\n\n const full = uuids.length >= MAX_PRODUCT_IMAGES;\n\n return (\n <Box>\n <input\n ref={inputRef}\n type=\"file\"\n accept=\"image/*\"\n multiple\n hidden\n onChange={(e) => { void handleFiles(e.target.files); e.target.value = ''; }}\n />\n <Stack direction=\"row\" spacing={1.5} sx={{ flexWrap: 'wrap', gap: 1.5 }}>\n {uuids.map((uuid, idx) => (\n <Box\n key={uuid}\n sx={{\n position: 'relative', width: 104, height: 104, borderRadius: 1.5,\n border: '1px solid', borderColor: 'divider', overflow: 'hidden',\n bgcolor: 'grey.50', display: 'flex', alignItems: 'center', justifyContent: 'center',\n }}\n >\n {previews[uuid] ? (\n <Box component=\"img\" src={previews[uuid]} alt={`Product image ${idx + 1}`}\n sx={{ width: '100%', height: '100%', objectFit: 'cover' }} />\n ) : (\n <CircularProgress size={20} />\n )}\n {idx === 0 ? (\n <Box sx={{\n position: 'absolute', left: 0, bottom: 0, right: 0,\n bgcolor: 'rgba(0,0,0,0.55)', color: '#fff', fontSize: '0.6rem',\n fontWeight: 800, letterSpacing: 0.5, textAlign: 'center', py: 0.25,\n }}>\n MAIN\n </Box>\n ) : null}\n <IconButton\n size=\"small\"\n onClick={() => removeImage(uuid)}\n sx={{\n position: 'absolute', top: 2, right: 2, p: 0.25,\n bgcolor: 'rgba(0,0,0,0.5)', color: '#fff',\n '&:hover': { bgcolor: 'rgba(0,0,0,0.7)' },\n }}\n aria-label=\"Remove image\"\n >\n <CloseRoundedIcon sx={{ fontSize: 16 }} />\n </IconButton>\n </Box>\n ))}\n {!full ? (\n <Button\n variant=\"outlined\"\n onClick={() => inputRef.current?.click()}\n disabled={uploading}\n sx={{\n width: 104, height: 104, borderStyle: 'dashed', flexDirection: 'column',\n gap: 0.5, color: 'text.secondary',\n }}\n >\n {uploading ? <CircularProgress size={22} /> : <AddPhotoAlternateRoundedIcon />}\n <Typography variant=\"caption\" sx={{ fontWeight: 700 }}>\n {uploading ? 'Uploading…' : 'Add'}\n </Typography>\n </Button>\n ) : null}\n </Stack>\n {uuids.length === 0 && !uploading ? (\n <Typography variant=\"caption\" color=\"text.disabled\" sx={{ display: 'block', mt: 1 }}>\n No images added yet.\n </Typography>\n ) : null}\n </Box>\n );\n}\n\nProductImagesField.propTypes = {\n value: PropTypes.arrayOf(PropTypes.string),\n onChange: PropTypes.func.isRequired,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"ProductEditPage-C1thoKHu.js","names":[],"sources":["../src/views/ProductEditPage.jsx"],"sourcesContent":["import { useEffect, useMemo, useRef, useState } from 'react';\nimport PropTypes from 'prop-types';\nimport { useNavigate, useParams } from 'react-router-dom';\nimport { v4 as uuidv4 } from 'uuid';\nimport { usePermissionedEffect } from '@pm/utils/permissions';\nimport {\n Alert,\n Box,\n Button,\n Card,\n CardContent,\n Checkbox,\n CircularProgress,\n Divider,\n FormControlLabel,\n Grid,\n IconButton,\n Stack,\n TextField,\n Typography,\n} from '@mui/material';\nimport SaveRoundedIcon from '@mui/icons-material/SaveRounded';\nimport AddRoundedIcon from '@mui/icons-material/AddRounded';\nimport AddPhotoAlternateRoundedIcon from '@mui/icons-material/AddPhotoAlternateRounded';\nimport CloseRoundedIcon from '@mui/icons-material/CloseRounded';\nimport DeleteOutlineRoundedIcon from '@mui/icons-material/DeleteOutlineRounded';\nimport { showToast } from '@pm/utils/pmToast';\nimport PmPageShell from '@pm/components/PmPageShell';\nimport PmNav from '@pm/components/PmNav';\nimport PmGuard from '@pm/components/PmGuard';\nimport {\n fetchProductImage,\n getBrands,\n getCategories,\n getImmunizationMaster,\n getProduct,\n uploadProductImages,\n upsertProduct,\n} from '@pm/services/pmApi';\nimport { AGE_UNITS, PRODUCT_UNITS, SALE_PRICE_MODES, VACCINES_CATEGORY_CODE, VACCINE_ROUTES, VACCINE_UNITS, VALIDITY_UNITS } from '@pm/utils/constants';\nimport {\n isClean,\n validateMaxConcurrentVials,\n validateOpenVialValidity,\n validateReconstitutedValidity,\n validateRequired,\n validateTempRange,\n validateVialVolume,\n} from '@pm/utils/validation';\nimport { useFieldErrors } from '@pm/utils/useFieldErrors';\nimport { usePmSettings } from '@pm/utils/settingsStore';\nimport { PmFieldHelp, PmSelect } from '@pm/components/PmTable';\n\n// Backend caps a product at 5 images (see updateProductImageMappings); mirror\n// that here so the UI blocks the 6th before an upload round-trip.\nconst MAX_PRODUCT_IMAGES = 5;\nconst MAX_IMAGE_BYTES = 5 * 1024 * 1024; // 5 MB per file\n\n// Shared style for the sub-section headers inside the Vaccine Configuration card.\nconst VC_SUBHEAD = {\n display: 'block',\n fontWeight: 800,\n letterSpacing: 0.6,\n color: 'text.secondary',\n};\n\n// One age-based administration profile in the form. The band runs from\n// [fromAge fromUnit] (inclusive) up to [toAge toUnit] (exclusive), measured from\n// the patient's reference date; dose is a single amount.\nfunction emptyProfile() {\n return {\n key: uuidv4(), profileType: 'AGE_BASED',\n fromAge: '', fromUnit: 'YEARS', toAge: '', toUnit: 'YEARS', doseAmount: '',\n };\n}\n\nconst EMPTY_VACCINE = {\n vaccineCode: '',\n vialVolumeMl: '',\n singleDose: false,\n profiles: [emptyProfile()],\n openVialValidityHours: 6,\n openVialValidityUnit: 'HOURS',\n maxConcurrentOpenVials: 2,\n requiresReconstitution: false,\n reconstitutedValidityHours: '',\n reconstitutedValidityUnit: 'HOURS',\n route: '',\n storageTempMinCelsius: '',\n storageTempMaxCelsius: '',\n comments: '',\n};\n\nfunction buildVaccinePayload(v, isDrops) {\n const single = !isDrops && !!v.singleDose;\n const num = (x) => (x === '' || x == null ? null : Number(x));\n return {\n vaccineCode: v.vaccineCode?.trim().toUpperCase(),\n vialVolumeMl: Number(v.vialVolumeMl),\n // Single-dose vial: one dose = vial volume, so no profiles are sent.\n singleDose: single,\n profiles: single ? [] : (v.profiles ?? []).map((p) => {\n const toAge = num(p.toAge);\n return {\n profileType: p.profileType || 'AGE_BASED',\n fromAge: num(p.fromAge),\n fromUnit: p.fromUnit || 'YEARS',\n toAge,\n toUnit: toAge == null ? null : (p.toUnit || 'YEARS'),\n doseAmount: num(p.doseAmount),\n };\n }),\n openVialValidityHours: Number(v.openVialValidityHours ?? 6),\n openVialValidityUnit: v.openVialValidityUnit || 'HOURS',\n maxConcurrentOpenVials: single ? null : Number(v.maxConcurrentOpenVials ?? 2),\n requiresReconstitution: !!v.requiresReconstitution,\n reconstitutedValidityHours: num(v.reconstitutedValidityHours),\n reconstitutedValidityUnit: v.reconstitutedValidityUnit || 'HOURS',\n route: v.route || null,\n storageTempMinCelsius: num(v.storageTempMinCelsius),\n storageTempMaxCelsius: num(v.storageTempMaxCelsius),\n comments: v.comments || null,\n };\n}\n\nexport default function ProductEditPage() {\n const { productId } = useParams();\n const navigate = useNavigate();\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState('');\n // Whether this page is creating a brand-new product (no existing row) vs\n // editing an existing one. Drives the \"Add\" vs \"Edit\" header. The route\n // always carries a product id (even for new), so we can't infer it from\n // the id alone — it's resolved by whether getProduct found a record.\n const [isNew, setIsNew] = useState(false);\n const [categories, setCategories] = useState([]);\n const [brands, setBrands] = useState([]);\n const [vaccineMaster, setVaccineMaster] = useState([]);\n const fieldErrors = useFieldErrors();\n const settings = usePmSettings();\n const manageSales = settings?.manageSales !== false;\n const [form, setForm] = useState({\n id: productId,\n name: '',\n categoryId: '',\n brandId: '',\n description: '',\n unit: '',\n unitOther: '',\n hasExpiry: true,\n needsStorageUnit: false,\n notForSale: false,\n canBeQuarantined: true,\n salePriceMode: 'FREE',\n salePrice: '',\n isActive: true,\n imageUuids: [],\n vaccineConfig: null,\n });\n\n const selectedCategory = useMemo(\n () => categories.find((c) => c.id === form.categoryId),\n [categories, form.categoryId]\n );\n const isVaccine = selectedCategory?.code?.toUpperCase() === VACCINES_CATEGORY_CODE;\n // A vaccine is measured either in ml (unit VIAL) or in drops (unit DROPS).\n const isDrops = isVaccine && form.unit === 'DROPS';\n\n usePermissionedEffect('update.manage.productManagement.product', () => {\n async function load() {\n setLoading(true);\n try {\n const [cats, brandList, vaccines] = await Promise.all([\n getCategories(),\n getBrands(),\n getImmunizationMaster().catch(() => []),\n ]);\n setCategories(cats);\n setBrands(brandList);\n setVaccineMaster(vaccines);\n\n // Try fetching existing product; if it returns 404 we treat it as new.\n try {\n const existing = await getProduct(productId);\n setIsNew(false);\n setForm({\n id: existing.id,\n name: existing.name ?? '',\n categoryId: existing.categoryId ?? '',\n brandId: existing.brandId ?? '',\n description: existing.description ?? '',\n unit: existing.unit ?? 'PIECE',\n unitOther: existing.unitOther ?? '',\n hasExpiry: existing.hasExpiry ?? false,\n needsStorageUnit: existing.needsStorageUnit ?? false,\n notForSale: existing.notForSale ?? false,\n canBeQuarantined: existing.canBeQuarantined ?? true,\n salePriceMode: existing.salePriceMode ?? 'FREE',\n salePrice: existing.salePrice ?? '',\n isActive: existing.isActive ?? true,\n imageUuids: existing.imageUuids ?? [],\n vaccineConfig: existing.vaccineConfig\n ? {\n vaccineCode: existing.vaccineConfig.vaccineCode ?? '',\n vialVolumeMl: existing.vaccineConfig.vialVolumeMl ?? '',\n singleDose: existing.vaccineConfig.singleDose ?? false,\n profiles: (existing.vaccineConfig.profiles ?? []).length > 0\n ? existing.vaccineConfig.profiles.map((p) => ({\n key: uuidv4(),\n profileType: p.profileType ?? 'AGE_BASED',\n fromAge: p.fromAge ?? '',\n fromUnit: p.fromUnit ?? 'YEARS',\n toAge: p.toAge ?? '',\n toUnit: p.toUnit ?? 'YEARS',\n doseAmount: p.doseAmount ?? '',\n }))\n : [emptyProfile()],\n openVialValidityHours: existing.vaccineConfig.openVialValidityHours ?? 6,\n openVialValidityUnit: existing.vaccineConfig.openVialValidityUnit ?? 'HOURS',\n maxConcurrentOpenVials: existing.vaccineConfig.maxConcurrentOpenVials ?? 2,\n requiresReconstitution: existing.vaccineConfig.requiresReconstitution ?? false,\n reconstitutedValidityHours: existing.vaccineConfig.reconstitutedValidityHours ?? '',\n reconstitutedValidityUnit: existing.vaccineConfig.reconstitutedValidityUnit ?? 'HOURS',\n route: existing.vaccineConfig.route ?? '',\n storageTempMinCelsius: existing.vaccineConfig.storageTempMinCelsius ?? '',\n storageTempMaxCelsius: existing.vaccineConfig.storageTempMaxCelsius ?? '',\n comments: existing.vaccineConfig.comments ?? '',\n }\n : null,\n });\n } catch {\n // new product – fall through with default form\n setIsNew(true);\n }\n } catch (err) {\n setError(err?.response?.data?.message ?? err?.message ?? 'Failed to load product');\n } finally {\n setLoading(false);\n }\n }\n void load();\n }, [productId]);\n\n useEffect(() => {\n if (isVaccine) {\n // Vaccines are dispensed per vial and live in cold-chain storage — pin both\n // the unit and needsStorageUnit so they can't drift away from those rules.\n setForm((f) => ({\n ...f,\n // Vaccines use VIAL (ml) or DROPS; keep whichever is already chosen.\n unit: (f.unit === 'VIAL' || f.unit === 'DROPS') ? f.unit : 'VIAL',\n needsStorageUnit: true,\n vaccineConfig: f.vaccineConfig ?? { ...EMPTY_VACCINE },\n }));\n } else {\n // Switched to (or loaded as) a non-vaccine category — drop any vaccine\n // config so it isn't sent on save. Persisting half-filled config for a\n // non-vaccine product would error on the backend.\n setForm((f) => (f.vaccineConfig ? { ...f, vaccineConfig: null } : f));\n }\n }, [isVaccine]);\n\n function patch(k, v) {\n setForm((f) => ({ ...f, [k]: v }));\n }\n\n function patchVaccine(k, v) {\n setForm((f) => ({ ...f, vaccineConfig: { ...(f.vaccineConfig ?? EMPTY_VACCINE), [k]: v } }));\n }\n\n // -------------------- Administration profiles --------------------\n function patchProfile(idx, k, val) {\n setForm((f) => {\n const cfg = f.vaccineConfig ?? EMPTY_VACCINE;\n const profiles = (cfg.profiles ?? []).slice();\n profiles[idx] = { ...profiles[idx], [k]: val };\n return { ...f, vaccineConfig: { ...cfg, profiles } };\n });\n }\n function addProfile() {\n setForm((f) => {\n const cfg = f.vaccineConfig ?? EMPTY_VACCINE;\n return { ...f, vaccineConfig: { ...cfg, profiles: [...(cfg.profiles ?? []), emptyProfile()] } };\n });\n }\n function removeProfile(idx) {\n setForm((f) => {\n const cfg = f.vaccineConfig ?? EMPTY_VACCINE;\n return { ...f, vaccineConfig: { ...cfg, profiles: (cfg.profiles ?? []).filter((_, i) => i !== idx) } };\n });\n }\n\n // Repeatable editor for the vaccine's age-based dose profiles (multi-dose\n // vaccines). Each profile = an age band + one dose; the matching profile is\n // picked automatically at administration from the patient's reference date.\n function renderProfilesEditor() {\n const v = form.vaccineConfig ?? {};\n const profiles = v.profiles ?? [];\n const unitLbl = isDrops ? 'drops' : 'ml';\n const numProps = isDrops ? { min: 0, step: 1 } : { step: '0.01', min: 0 };\n return (\n <Box>\n <Stack direction=\"row\" justifyContent=\"space-between\" alignItems=\"center\" sx={{ mb: 0.5 }}>\n <Typography variant=\"body2\" sx={{ fontWeight: 700 }}>Dose profiles</Typography>\n <Button size=\"small\" variant=\"outlined\" startIcon={<AddRoundedIcon />} onClick={addProfile}>Add profile</Button>\n </Stack>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', mb: 1.5 }}>\n Each band sets one dose. It is measured from the patient&apos;s reference date, so the right dose is chosen automatically when giving the vaccine.\n <br />\n <strong>From</strong> is included and <strong>To</strong> is not — a patient exactly at a To value falls into the next band. Leave To blank for no upper limit.\n </Typography>\n <Stack spacing={1.5}>\n {profiles.map((p, idx) => {\n const kf = `profiles.${idx}.fromAge`;\n const kt = `profiles.${idx}.toAge`;\n const kd = `profiles.${idx}.doseAmount`;\n const hasTo = p.toAge !== '' && p.toAge != null;\n return (\n <Box key={p.key} sx={{ p: 1.5, border: '1px solid', borderColor: 'divider', borderRadius: 1.5 }}>\n <Grid container spacing={1.5} alignItems=\"flex-start\">\n <Grid item xs={6} md={2}>\n <TextField required fullWidth size=\"small\" type=\"number\" inputProps={{ min: 0, step: 1 }}\n label=\"From\"\n value={p.fromAge ?? ''}\n onChange={(e) => patchProfile(idx, 'fromAge', e.target.value)}\n onBlur={fieldErrors.onBlur(kf)}\n error={fieldErrors.show(kf) && !!errors[kf]}\n helperText={fieldErrors.show(kf) ? errors[kf] : ''} />\n </Grid>\n <Grid item xs={6} md={2}>\n <PmSelect label=\"From unit\" value={p.fromUnit || 'YEARS'}\n onChange={(val) => patchProfile(idx, 'fromUnit', val)} options={AGE_UNITS} />\n </Grid>\n <Grid item xs={6} md={2}>\n <TextField fullWidth size=\"small\" type=\"number\" inputProps={{ min: 0, step: 1 }}\n label=\"To\"\n value={p.toAge ?? ''}\n onChange={(e) => patchProfile(idx, 'toAge', e.target.value)}\n onBlur={fieldErrors.onBlur(kt)}\n error={fieldErrors.show(kt) && !!errors[kt]}\n helperText={fieldErrors.show(kt) && errors[kt] ? errors[kt] : 'Blank = no limit'} />\n </Grid>\n <Grid item xs={6} md={2}>\n <PmSelect label=\"To unit\" disabled={!hasTo} value={hasTo ? (p.toUnit || 'YEARS') : ''}\n onChange={(val) => patchProfile(idx, 'toUnit', val)} options={AGE_UNITS} />\n </Grid>\n <Grid item xs={8} md={3}>\n <TextField required fullWidth size=\"small\" type=\"number\" inputProps={numProps}\n label={`Dose (${unitLbl})`}\n value={p.doseAmount ?? ''}\n onChange={(e) => patchProfile(idx, 'doseAmount', e.target.value)}\n onBlur={fieldErrors.onBlur(kd)}\n error={fieldErrors.show(kd) && !!errors[kd]}\n helperText={fieldErrors.show(kd) ? errors[kd] : ''} />\n </Grid>\n <Grid item xs={4} md={1} sx={{ textAlign: 'right' }}>\n <IconButton color=\"error\" onClick={() => removeProfile(idx)} disabled={profiles.length === 1}>\n <DeleteOutlineRoundedIcon />\n </IconButton>\n </Grid>\n </Grid>\n </Box>\n );\n })}\n </Stack>\n {fieldErrors.show('profiles') && errors.profiles ? (\n <Typography variant=\"caption\" color=\"error\" sx={{ display: 'block', mt: 1 }}>{errors.profiles}</Typography>\n ) : null}\n </Box>\n );\n }\n\n // -------------------- Field-level error map --------------------\n const errors = useMemo(() => {\n const base = {\n name: validateRequired(form.name, 'Product name'),\n categoryId: validateRequired(form.categoryId, 'Category'),\n brandId: validateRequired(form.brandId, 'Brand'),\n unit: validateRequired(form.unit, 'Unit'),\n // Custom unit label is required only when unit is OTHER.\n unitOther: form.unit === 'OTHER' ? validateRequired(form.unitOther, 'Custom unit') : '',\n // Sale price required (>0) when a fixed/capped mode is chosen on a sellable product.\n salePrice: (manageSales && !form.notForSale && form.salePriceMode !== 'FREE')\n ? (validateRequired(form.salePrice, 'Sale price')\n || (Number(form.salePrice) > 0 ? '' : 'Sale price must be greater than 0.'))\n : '',\n };\n if (isVaccine && form.vaccineConfig) {\n const v = form.vaccineConfig;\n const singleDose = !isDrops && v.singleDose;\n const temps = validateTempRange(v.storageTempMinCelsius, v.storageTempMaxCelsius);\n Object.assign(base, {\n vaccineCode: validateRequired(v.vaccineCode, 'Vaccine'),\n vialVolumeMl: validateVialVolume(v.vialVolumeMl),\n // A single-dose vial is closed the instant it's opened, so an open-vial\n // validity window doesn't apply — only validate it for multi-dose vials.\n openVialValidityHours: singleDose ? '' : validateOpenVialValidity(v.openVialValidityHours),\n reconstitutedValidityHours: validateReconstitutedValidity(\n v.reconstitutedValidityHours,\n v.requiresReconstitution\n ),\n storageTempMinCelsius: temps.min,\n storageTempMaxCelsius: temps.max,\n });\n if (singleDose) {\n // Single-dose: one dose = vial volume, no profiles and no concurrency cap.\n } else {\n // Multi-dose (ml or drops): validate each age-based profile.\n const vol = Number(v.vialVolumeMl);\n const unitLbl = isDrops ? 'drops' : 'ml';\n const profiles = v.profiles ?? [];\n if (profiles.length === 0) {\n base.profiles = 'Add at least one administration profile.';\n }\n // Approximate days per unit, to compare From/To across different units.\n const UNIT_DAYS = { DAYS: 1, WEEKS: 7, MONTHS: 30, YEARS: 365 };\n const approxDays = (n, u) => Number(n) * (UNIT_DAYS[u] || 1);\n profiles.forEach((p, idx) => {\n // From: required, whole number >= 0.\n const from = Number(p.fromAge);\n if (p.fromAge === '' || p.fromAge == null) base[`profiles.${idx}.fromAge`] = 'Required';\n else if (!Number.isInteger(from) || from < 0) base[`profiles.${idx}.fromAge`] = 'Whole number, 0 or more';\n // To: optional; if present must be a whole number and after From\n // (compared across each bound's own unit).\n if (p.toAge !== '' && p.toAge != null) {\n const to = Number(p.toAge);\n if (!Number.isInteger(to) || to < 0) base[`profiles.${idx}.toAge`] = 'Whole number, 0 or more';\n else if (approxDays(to, p.toUnit) <= approxDays(from, p.fromUnit)) {\n base[`profiles.${idx}.toAge`] = 'Must be greater than From';\n }\n }\n // Dose: required, > 0, <= vial volume, whole for drops.\n const dose = Number(p.doseAmount);\n if (p.doseAmount === '' || p.doseAmount == null) base[`profiles.${idx}.doseAmount`] = 'Required';\n else if (!Number.isFinite(dose) || dose <= 0) base[`profiles.${idx}.doseAmount`] = 'Must be greater than 0';\n else if (isDrops && !Number.isInteger(dose)) base[`profiles.${idx}.doseAmount`] = 'Whole number';\n else if (Number.isFinite(vol) && vol > 0 && dose > vol) base[`profiles.${idx}.doseAmount`] = `At most ${vol} ${unitLbl}`;\n });\n base.maxConcurrentOpenVials = validateMaxConcurrentVials(v.maxConcurrentOpenVials);\n }\n }\n return base;\n }, [form, isVaccine, isDrops, manageSales]);\n\n const formIsValid = isClean(errors);\n\n async function save() {\n if (!formIsValid) {\n fieldErrors.markAllTouched();\n setError('Please fix the highlighted fields and try again.');\n return;\n }\n try {\n const payload = {\n id: form.id,\n name: form.name.trim(),\n categoryId: form.categoryId,\n brandId: form.brandId,\n description: form.description || null,\n unit: form.unit,\n unitOther: form.unit === 'OTHER' ? (form.unitOther?.trim() || null) : null,\n hasExpiry: !!form.hasExpiry,\n needsStorageUnit: !!form.needsStorageUnit,\n notForSale: manageSales ? !!form.notForSale : false,\n canBeQuarantined: !!form.canBeQuarantined,\n // Sale pricing only applies to sellable products in a money-managed\n // deployment; otherwise force FREE with no price.\n salePriceMode: (manageSales && !form.notForSale) ? form.salePriceMode : 'FREE',\n salePrice: (manageSales && !form.notForSale && form.salePriceMode !== 'FREE' && form.salePrice !== '')\n ? Number(form.salePrice) : null,\n isActive: !!form.isActive,\n imageUuids: form.imageUuids ?? [],\n vaccineConfig: form.vaccineConfig\n ? buildVaccinePayload(form.vaccineConfig, isDrops)\n : null,\n };\n await upsertProduct(payload);\n showToast({ message: 'Product saved.', type: 'success' });\n navigate('/ui/medplat/manage/pm/products');\n } catch (err) {\n setError(err?.response?.data?.message ?? err?.message ?? 'Failed to save product');\n }\n }\n\n return (\n <Box>\n <PmNav />\n <PmGuard perm={'update.manage.productManagement.product'} title=\"You don’t have permission to create or edit products\">\n <PmPageShell\n title={isNew ? 'Add Product' : 'Edit Product'}\n subtitle={`Category: ${selectedCategory?.code ?? '—'}`}\n actions={\n <Stack direction=\"row\" spacing={1}>\n <Button variant=\"outlined\" onClick={() => navigate('/ui/medplat/manage/pm/products')}>Cancel</Button>\n <Button variant=\"contained\" startIcon={<SaveRoundedIcon />}\n disabled={!formIsValid}\n onClick={() => void save()}>Save</Button>\n </Stack>\n }\n >\n {loading ? <Alert severity=\"info\">Loading…</Alert> : null}\n {error ? <Alert severity=\"error\" sx={{ mb: 2 }}>{error}</Alert> : null}\n\n <Card sx={{ borderRadius: 1.5, mb: 2 }}>\n <CardContent>\n <Typography variant=\"h6\" sx={{ fontWeight: 800, mb: 2 }}>Basic Details</Typography>\n <Grid container spacing={2}>\n <Grid item xs={12} md={6}>\n <TextField\n required\n fullWidth size=\"small\" label=\"Product Name\"\n value={form.name}\n inputProps={{ maxLength: 255 }}\n onChange={(e) => patch('name', e.target.value)}\n onBlur={fieldErrors.onBlur('name')}\n error={fieldErrors.show('name') && !!errors.name}\n FormHelperTextProps={{ component: 'div' }}\n helperText={<PmFieldHelp message={fieldErrors.show('name') ? errors.name : ''} value={form.name} max={255} />}\n />\n </Grid>\n <Grid item xs={12} md={3}>\n <PmSelect\n label=\"Category\"\n required\n value={form.categoryId}\n onChange={(v) => patch('categoryId', v)}\n onBlur={fieldErrors.onBlur('categoryId')}\n error={fieldErrors.show('categoryId') && !!errors.categoryId}\n helperText={fieldErrors.show('categoryId') ? errors.categoryId : ''}\n options={categories.map((c) => ({ value: c.id, label: `${c.name} (${c.code})` }))}\n />\n </Grid>\n <Grid item xs={12} md={3}>\n <PmSelect\n label=\"Brand\"\n required\n value={form.brandId}\n onChange={(v) => patch('brandId', v)}\n onBlur={fieldErrors.onBlur('brandId')}\n error={fieldErrors.show('brandId') && !!errors.brandId}\n helperText={fieldErrors.show('brandId') ? errors.brandId : ''}\n options={brands.map((b) => ({ value: b.id, label: b.name }))}\n />\n </Grid>\n {/* For vaccines the unit (Vial/Drops) is chosen in the Vaccine\n Configuration section below (\"Measured in\"), so it's hidden here. */}\n {isVaccine ? null : (\n <Grid item xs={12} md={3}>\n <PmSelect\n label=\"Unit\"\n required\n value={form.unit}\n onChange={(v) => patch('unit', v)}\n onBlur={fieldErrors.onBlur('unit')}\n error={fieldErrors.show('unit') && !!errors.unit}\n helperText={fieldErrors.show('unit') && errors.unit ? errors.unit : ''}\n options={PRODUCT_UNITS}\n />\n </Grid>\n )}\n {!isVaccine && form.unit === 'OTHER' ? (\n <Grid item xs={12} md={3}>\n <TextField\n required fullWidth size=\"small\" label=\"Custom unit name\"\n value={form.unitOther}\n inputProps={{ maxLength: 50 }}\n onChange={(e) => patch('unitOther', e.target.value)}\n onBlur={fieldErrors.onBlur('unitOther')}\n error={fieldErrors.show('unitOther') && !!errors.unitOther}\n FormHelperTextProps={{ component: 'div' }}\n helperText={<PmFieldHelp\n message={fieldErrors.show('unitOther') && errors.unitOther ? errors.unitOther : 'e.g. Strip, Ampoule, Sachet'}\n value={form.unitOther} max={50} />}\n />\n </Grid>\n ) : null}\n <Grid item xs={6} md={3}>\n <FormControlLabel\n control={<Checkbox\n checked={!!form.hasExpiry}\n disabled={isVaccine}\n onChange={(e) => patch('hasExpiry', e.target.checked)} />}\n label={isVaccine ? 'Has expiry (vaccine)' : 'Has expiry'} />\n </Grid>\n <Grid item xs={6} md={3}>\n <FormControlLabel\n control={<Checkbox\n checked={!!form.needsStorageUnit}\n disabled={isVaccine}\n onChange={(e) => patch('needsStorageUnit', e.target.checked)} />}\n label={isVaccine ? 'Needs storage unit (vaccine)' : 'Needs storage unit'} />\n </Grid>\n {manageSales ? (\n <Grid item xs={6} md={3}>\n <FormControlLabel control={<Checkbox checked={!!form.notForSale}\n onChange={(e) => patch('notForSale', e.target.checked)} />} label=\"Not for sale\" />\n </Grid>\n ) : null}\n <Grid item xs={6} md={3}>\n <FormControlLabel control={<Checkbox checked={!!form.canBeQuarantined}\n onChange={(e) => patch('canBeQuarantined', e.target.checked)} />} label=\"Can be quarantined\" />\n </Grid>\n <Grid item xs={6} md={3}>\n <FormControlLabel control={<Checkbox checked={!!form.isActive}\n onChange={(e) => patch('isActive', e.target.checked)} />} label=\"Active\" />\n </Grid>\n\n {/* Sale pricing — only for sellable products in a money-managed deployment. */}\n {manageSales && !form.notForSale ? (\n <>\n <Grid item xs={12} md={4}>\n <PmSelect\n label=\"Sale price mode\"\n value={form.salePriceMode}\n onChange={(v) => patch('salePriceMode', v)}\n options={SALE_PRICE_MODES}\n helperText=\"Fixed shows a locked price at sale time; MRP caps the entered price.\"\n />\n </Grid>\n {form.salePriceMode !== 'FREE' ? (\n <Grid item xs={12} md={4}>\n <TextField\n required fullWidth size=\"small\" type=\"number\"\n inputProps={{ step: '0.01', min: 0 }}\n label={form.salePriceMode === 'FIXED' ? 'Fixed sale price' : 'Price cap (MRP)'}\n value={form.salePrice}\n onChange={(e) => patch('salePrice', e.target.value)}\n onBlur={fieldErrors.onBlur('salePrice')}\n error={fieldErrors.show('salePrice') && !!errors.salePrice}\n helperText={fieldErrors.show('salePrice') ? errors.salePrice : ''}\n />\n </Grid>\n ) : null}\n </>\n ) : null}\n\n <Grid item xs={12}>\n <TextField fullWidth size=\"small\" multiline minRows={2} label=\"Description\" value={form.description}\n onChange={(e) => patch('description', e.target.value)} />\n </Grid>\n </Grid>\n </CardContent>\n </Card>\n\n <Card sx={{ borderRadius: 1.5, mb: 2 }}>\n <CardContent>\n <Stack direction=\"row\" justifyContent=\"space-between\" alignItems=\"center\" sx={{ mb: 0.5 }}>\n <Typography variant=\"h6\" sx={{ fontWeight: 800 }}>Product Images</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">Optional · up to {MAX_PRODUCT_IMAGES} images</Typography>\n </Stack>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', mb: 2 }}>\n Add photos of the product or its packaging. The first image is used as the main picture.\n </Typography>\n <ProductImagesField\n value={form.imageUuids}\n onChange={(next) => patch('imageUuids', next)}\n />\n </CardContent>\n </Card>\n\n {isVaccine ? (\n <Card sx={{ borderRadius: 1.5 }}>\n <CardContent>\n <Stack direction=\"row\" justifyContent=\"space-between\" alignItems=\"center\" sx={{ mb: 2 }}>\n <Typography variant=\"h6\" sx={{ fontWeight: 800 }}>Vaccine Configuration</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n Required for vaccine products. Controls vial size, dosing, and shelf life rules.\n </Typography>\n </Stack>\n <Divider sx={{ mb: 2 }} />\n <Grid container spacing={2}>\n {/* ---- Vaccine & measure ---- */}\n <Grid item xs={12}>\n <Typography variant=\"overline\" sx={VC_SUBHEAD}>Vaccine &amp; measure</Typography>\n </Grid>\n <Grid item xs={12} md={4}>\n <PmSelect\n label=\"Vaccine\"\n required\n value={form.vaccineConfig?.vaccineCode || ''}\n onChange={(v) => patchVaccine('vaccineCode', v)}\n onBlur={fieldErrors.onBlur('vaccineCode')}\n error={fieldErrors.show('vaccineCode') && !!errors.vaccineCode}\n helperText={fieldErrors.show('vaccineCode') && errors.vaccineCode\n ? errors.vaccineCode\n : ''}\n noOptionsText=\"No vaccines configured in immunization master\"\n options={vaccineMaster.map((v) => ({ value: v.vaccineCode, label: `${v.vaccineName} (${v.vaccineCode})` }))}\n />\n </Grid>\n <Grid item xs={12} md={4}>\n <PmSelect\n label=\"Measured in\"\n value={form.unit}\n onChange={(v) => patch('unit', v)}\n options={VACCINE_UNITS}\n helperText=\"Vials are dosed in millilitres; drops are counted.\"\n />\n </Grid>\n <Grid item xs={12} md={4}>\n <TextField required fullWidth size=\"small\" type=\"number\"\n inputProps={isDrops ? { min: 1, step: 1 } : { step: '0.01', min: 0 }}\n label={isDrops ? 'Drops per vial' : 'Vial volume (ml)'}\n value={form.vaccineConfig?.vialVolumeMl ?? ''}\n onChange={(e) => patchVaccine('vialVolumeMl', e.target.value)}\n onBlur={fieldErrors.onBlur('vialVolumeMl')}\n error={fieldErrors.show('vialVolumeMl') && !!errors.vialVolumeMl}\n helperText={fieldErrors.show('vialVolumeMl') ? errors.vialVolumeMl\n : (isDrops ? 'Total drops in a fresh vial' : '')}\n />\n </Grid>\n\n {/* ---- Dosing ---- */}\n <Grid item xs={12}>\n <Typography variant=\"overline\" sx={{ ...VC_SUBHEAD, mt: 1 }}>Dosing</Typography>\n </Grid>\n {!isDrops ? (\n <Grid item xs={12}>\n <FormControlLabel\n control={<Checkbox checked={!!form.vaccineConfig?.singleDose}\n onChange={(e) => patchVaccine('singleDose', e.target.checked)} />}\n label=\"Single dose vial\" />\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', ml: 4, mt: -0.5 }}>\n One dose per vial — used up the moment it&apos;s opened, so there&apos;s no limit on how many can be open at once.\n </Typography>\n </Grid>\n ) : null}\n <Grid item xs={12}>\n {(!isDrops && form.vaccineConfig?.singleDose) ? (\n <Box sx={{ p: 1.5, border: '1px solid', borderColor: 'divider', borderRadius: 1.5 }}>\n <Typography variant=\"body2\" sx={{ fontWeight: 700 }}>Single dose</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n Each vial is one dose of {form.vaccineConfig?.vialVolumeMl || '—'} ml, given to any patient. No dose profiles are needed.\n </Typography>\n </Box>\n ) : (\n renderProfilesEditor()\n )}\n </Grid>\n\n {/* ---- Open vial & reconstitution ---- */}\n <Grid item xs={12}>\n <Typography variant=\"overline\" sx={{ ...VC_SUBHEAD, mt: 1 }}>Open vial &amp; reconstitution</Typography>\n </Grid>\n {(!isDrops && form.vaccineConfig?.singleDose) ? null : (\n <Grid item xs={12} md={4}>\n <Stack direction=\"row\" spacing={1}>\n <TextField required fullWidth size=\"small\" type=\"number\" inputProps={{ min: 1 }}\n label=\"Open vial validity\"\n value={form.vaccineConfig?.openVialValidityHours ?? ''}\n onChange={(e) => patchVaccine('openVialValidityHours', e.target.value)}\n onBlur={fieldErrors.onBlur('openVialValidityHours')}\n error={fieldErrors.show('openVialValidityHours') && !!errors.openVialValidityHours}\n helperText={fieldErrors.show('openVialValidityHours') ? errors.openVialValidityHours : 'How long the vial stays usable once opened'}\n />\n <Box sx={{ minWidth: 132, flexShrink: 0 }}>\n <PmSelect label=\"Unit\" value={form.vaccineConfig?.openVialValidityUnit || 'HOURS'}\n onChange={(v) => patchVaccine('openVialValidityUnit', v)} options={VALIDITY_UNITS} />\n </Box>\n </Stack>\n </Grid>\n )}\n {(!isDrops && form.vaccineConfig?.singleDose) ? null : (\n <Grid item xs={12} md={4}>\n <TextField required fullWidth size=\"small\" type=\"number\" inputProps={{ min: 1, max: 20 }}\n label=\"Max concurrent open vials\"\n value={form.vaccineConfig?.maxConcurrentOpenVials ?? ''}\n onChange={(e) => patchVaccine('maxConcurrentOpenVials', e.target.value)}\n onBlur={fieldErrors.onBlur('maxConcurrentOpenVials')}\n error={fieldErrors.show('maxConcurrentOpenVials') && !!errors.maxConcurrentOpenVials}\n helperText={fieldErrors.show('maxConcurrentOpenVials') ? errors.maxConcurrentOpenVials : ''}\n />\n </Grid>\n )}\n <Grid item xs={12}>\n <FormControlLabel control={<Checkbox checked={!!form.vaccineConfig?.requiresReconstitution}\n onChange={(e) => patchVaccine('requiresReconstitution', e.target.checked)} />} label=\"Requires reconstitution\" />\n </Grid>\n {form.vaccineConfig?.requiresReconstitution ? (\n <Grid item xs={12} md={4}>\n <Stack direction=\"row\" spacing={1}>\n <TextField fullWidth size=\"small\" type=\"number\" inputProps={{ min: 1 }}\n required\n label=\"Reconstituted validity\"\n value={form.vaccineConfig?.reconstitutedValidityHours ?? ''}\n onChange={(e) => patchVaccine('reconstitutedValidityHours', e.target.value)}\n onBlur={fieldErrors.onBlur('reconstitutedValidityHours')}\n error={fieldErrors.show('reconstitutedValidityHours') && !!errors.reconstitutedValidityHours}\n helperText={fieldErrors.show('reconstitutedValidityHours') ? errors.reconstitutedValidityHours : ''}\n />\n <Box sx={{ minWidth: 132, flexShrink: 0 }}>\n <PmSelect label=\"Unit\"\n value={form.vaccineConfig?.reconstitutedValidityUnit || 'HOURS'}\n onChange={(v) => patchVaccine('reconstitutedValidityUnit', v)} options={VALIDITY_UNITS} />\n </Box>\n </Stack>\n </Grid>\n ) : null}\n\n {/* ---- Storage & route ---- */}\n <Grid item xs={12}>\n <Typography variant=\"overline\" sx={{ ...VC_SUBHEAD, mt: 1 }}>Storage &amp; route</Typography>\n </Grid>\n <Grid item xs={12} md={4}>\n <PmSelect\n label=\"Route of administration\"\n value={form.vaccineConfig?.route || ''}\n onChange={(v) => patchVaccine('route', v)}\n options={VACCINE_ROUTES}\n />\n </Grid>\n <Grid item xs={6} md={4}>\n <TextField fullWidth size=\"small\" type=\"number\" inputProps={{ step: '0.1', min: -90, max: 30 }}\n label=\"Storage temp min (°C)\"\n value={form.vaccineConfig?.storageTempMinCelsius ?? ''}\n onChange={(e) => patchVaccine('storageTempMinCelsius', e.target.value)}\n onBlur={fieldErrors.onBlur('storageTempMinCelsius')}\n error={fieldErrors.show('storageTempMinCelsius') && !!errors.storageTempMinCelsius}\n helperText={\n fieldErrors.show('storageTempMinCelsius') && errors.storageTempMinCelsius\n ? errors.storageTempMinCelsius\n : '−90°C to +30°C'\n }\n />\n </Grid>\n <Grid item xs={6} md={4}>\n <TextField fullWidth size=\"small\" type=\"number\" inputProps={{ step: '0.1', min: -90, max: 30 }}\n label=\"Storage temp max (°C)\"\n value={form.vaccineConfig?.storageTempMaxCelsius ?? ''}\n onChange={(e) => patchVaccine('storageTempMaxCelsius', e.target.value)}\n onBlur={fieldErrors.onBlur('storageTempMaxCelsius')}\n error={fieldErrors.show('storageTempMaxCelsius') && !!errors.storageTempMaxCelsius}\n helperText={\n fieldErrors.show('storageTempMaxCelsius') && errors.storageTempMaxCelsius\n ? errors.storageTempMaxCelsius\n : '−90°C to +30°C'\n }\n />\n </Grid>\n\n {/* ---- Notes ---- */}\n <Grid item xs={12}>\n <Typography variant=\"overline\" sx={{ ...VC_SUBHEAD, mt: 1 }}>Notes</Typography>\n </Grid>\n <Grid item xs={12}>\n <TextField fullWidth size=\"small\" multiline minRows={2}\n label=\"Comments\" value={form.vaccineConfig?.comments || ''}\n onChange={(e) => patchVaccine('comments', e.target.value)} />\n </Grid>\n </Grid>\n </CardContent>\n </Card>\n ) : null}\n </PmPageShell>\n </PmGuard>\n </Box>\n );\n}\n\n// Image manager for a product. Holds the list of stored image uuids in the\n// parent form; uploads picked files immediately (so each gets a persisted\n// uuid) and renders thumbnails. Newly picked files preview from a local object\n// URL; images loaded on edit are fetched (authenticated) as blobs. All object\n// URLs are revoked on unmount to avoid leaks.\nfunction ProductImagesField({ value, onChange }) {\n const uuids = value ?? [];\n const inputRef = useRef(null);\n const [uploading, setUploading] = useState(false);\n // uuid -> object URL for preview. Object URLs are tracked here and revoked\n // when the field unmounts.\n const [previews, setPreviews] = useState({});\n const previewsRef = useRef({});\n previewsRef.current = previews;\n\n function setPreview(uuid, url) {\n setPreviews((p) => (p[uuid] ? p : { ...p, [uuid]: url }));\n }\n\n // Fetch previews for any uuid we don't yet have a URL for (edit mode: images\n // arrive as uuids only). Skips ones already cached (e.g. just-uploaded files).\n useEffect(() => {\n let cancelled = false;\n uuids.forEach((uuid) => {\n if (previewsRef.current[uuid]) return;\n fetchProductImage(uuid)\n .then((blob) => {\n if (cancelled) return;\n setPreview(uuid, URL.createObjectURL(blob));\n })\n .catch(() => {});\n });\n return () => { cancelled = true; };\n }, [uuids]);\n\n // Revoke every object URL on unmount.\n useEffect(() => () => {\n Object.values(previewsRef.current).forEach((url) => {\n try { URL.revokeObjectURL(url); } catch { /* ignore */ }\n });\n }, []);\n\n async function handleFiles(fileList) {\n const picked = Array.from(fileList || []);\n if (picked.length === 0) return;\n const room = MAX_PRODUCT_IMAGES - uuids.length;\n if (room <= 0) {\n showToast({ message: `You can add at most ${MAX_PRODUCT_IMAGES} images.`, type: 'warning' });\n return;\n }\n const invalid = picked.find((f) => !f.type.startsWith('image/') || f.size > MAX_IMAGE_BYTES);\n if (invalid) {\n showToast({\n message: invalid.type.startsWith('image/')\n ? 'Each image must be 5 MB or smaller.'\n : 'Only image files can be uploaded.',\n type: 'error',\n });\n return;\n }\n const toUpload = picked.slice(0, room);\n if (picked.length > room) {\n showToast({ message: `Only ${room} more image${room === 1 ? '' : 's'} can be added.`, type: 'warning' });\n }\n const newUuids = toUpload.map(() => uuidv4());\n setUploading(true);\n try {\n await uploadProductImages(toUpload, newUuids);\n // Preview from the local files — no need to round-trip for images we\n // already hold in memory.\n toUpload.forEach((file, i) => setPreview(newUuids[i], URL.createObjectURL(file)));\n onChange([...uuids, ...newUuids]);\n } catch (err) {\n showToast({ message: err?.response?.data?.message ?? err?.message ?? 'Failed to upload images', type: 'error' });\n } finally {\n setUploading(false);\n }\n }\n\n function removeImage(uuid) {\n onChange(uuids.filter((u) => u !== uuid));\n // Keep the object URL around until unmount; re-adding the same uuid is not\n // possible from the UI, so there's nothing to reconcile.\n }\n\n const full = uuids.length >= MAX_PRODUCT_IMAGES;\n\n return (\n <Box>\n <input\n ref={inputRef}\n type=\"file\"\n accept=\"image/*\"\n multiple\n hidden\n onChange={(e) => { void handleFiles(e.target.files); e.target.value = ''; }}\n />\n <Stack direction=\"row\" spacing={1.5} sx={{ flexWrap: 'wrap', gap: 1.5 }}>\n {uuids.map((uuid, idx) => (\n <Box\n key={uuid}\n sx={{\n position: 'relative', width: 104, height: 104, borderRadius: 1.5,\n border: '1px solid', borderColor: 'divider', overflow: 'hidden',\n bgcolor: 'grey.50', display: 'flex', alignItems: 'center', justifyContent: 'center',\n }}\n >\n {previews[uuid] ? (\n <Box component=\"img\" src={previews[uuid]} alt={`Product image ${idx + 1}`}\n sx={{ width: '100%', height: '100%', objectFit: 'cover' }} />\n ) : (\n <CircularProgress size={20} />\n )}\n {idx === 0 ? (\n <Box sx={{\n position: 'absolute', left: 0, bottom: 0, right: 0,\n bgcolor: 'rgba(0,0,0,0.55)', color: '#fff', fontSize: '0.6rem',\n fontWeight: 800, letterSpacing: 0.5, textAlign: 'center', py: 0.25,\n }}>\n MAIN\n </Box>\n ) : null}\n <IconButton\n size=\"small\"\n onClick={() => removeImage(uuid)}\n sx={{\n position: 'absolute', top: 2, right: 2, p: 0.25,\n bgcolor: 'rgba(0,0,0,0.5)', color: '#fff',\n '&:hover': { bgcolor: 'rgba(0,0,0,0.7)' },\n }}\n aria-label=\"Remove image\"\n >\n <CloseRoundedIcon sx={{ fontSize: 16 }} />\n </IconButton>\n </Box>\n ))}\n {!full ? (\n <Button\n variant=\"outlined\"\n onClick={() => inputRef.current?.click()}\n disabled={uploading}\n sx={{\n width: 104, height: 104, borderStyle: 'dashed', flexDirection: 'column',\n gap: 0.5, color: 'text.secondary',\n }}\n >\n {uploading ? <CircularProgress size={22} /> : <AddPhotoAlternateRoundedIcon />}\n <Typography variant=\"caption\" sx={{ fontWeight: 700 }}>\n {uploading ? 'Uploading…' : 'Add'}\n </Typography>\n </Button>\n ) : null}\n </Stack>\n {uuids.length === 0 && !uploading ? (\n <Typography variant=\"caption\" color=\"text.disabled\" sx={{ display: 'block', mt: 1 }}>\n No images added yet.\n </Typography>\n ) : null}\n </Box>\n );\n}\n\nProductImagesField.propTypes = {\n value: PropTypes.arrayOf(PropTypes.string),\n onChange: PropTypes.func.isRequired,\n};\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
- import { T as e } from "./settingsStore-BlA2GIhl.js";
2
- import { c as t, l as n, s as r, t as i } from "./PmTable-BSV_bMJZ.js";
1
+ import { T as e } from "./settingsStore-BifOsjlB.js";
2
+ import { c as t, l as n, s as r, t as i } from "./PmTable-_GbScaa4.js";
3
3
  import { T as a } from "./constants-ClZJY2x1.js";
4
- import { a as o, i as s, n as c, r as l, t as u } from "./PmGuard-DrIl1sHL.js";
4
+ import { a as o, i as s, n as c, r as l, t as u } from "./PmGuard-b10TGXEi.js";
5
5
  import { useState as d } from "react";
6
6
  import { jsx as f, jsxs as p } from "react/jsx-runtime";
7
7
  import { Alert as m, Box as h, Button as g, Chip as _, FormControlLabel as v, InputAdornment as y, Skeleton as b, Stack as x, TableBody as S, TableCell as C, TableHead as w, TableRow as T, TextField as E, Typography as D } from "@mui/material";
@@ -249,4 +249,4 @@ function I() {
249
249
  //#endregion
250
250
  export { I as default };
251
251
 
252
- //# sourceMappingURL=ProductsPage-CqOsah4_.js.map
252
+ //# sourceMappingURL=ProductsPage-CupVmOD4.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ProductsPage-CqOsah4_.js","names":[],"sources":["../src/views/ProductsPage.jsx"],"sourcesContent":["import { useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { v4 as uuidv4 } from 'uuid';\nimport {\n Alert,\n Box,\n Button,\n Chip,\n FormControlLabel,\n InputAdornment,\n Skeleton,\n Stack,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n TextField,\n Typography,\n} from '@mui/material';\nimport AddRoundedIcon from '@mui/icons-material/AddRounded';\nimport RefreshRoundedIcon from '@mui/icons-material/RefreshRounded';\nimport SearchRoundedIcon from '@mui/icons-material/SearchRounded';\nimport Inventory2RoundedIcon from '@mui/icons-material/Inventory2Rounded';\nimport VaccinesRoundedIcon from '@mui/icons-material/VaccinesRounded';\nimport { showToast } from '@pm/utils/pmToast';\nimport CustomSwitch from '@/views/custom-components/CustomSwitch';\nimport PmPageShell from '@pm/components/PmPageShell';\nimport PmNav from '@pm/components/PmNav';\nimport PmGuard from '@pm/components/PmGuard';\nimport { PmEmptyRow, PmTable, PmTableCard } from '@pm/components/PmTable';\nimport { getProducts } from '@pm/services/pmApi';\nimport { unitLabel } from '@pm/utils/constants';\nimport { usePermissionedEffect, usePmPermissions } from '@pm/utils/permissions';\n\nexport default function ProductsPage() {\n const navigate = useNavigate();\n const perms = usePmPermissions();\n const canWrite = perms.has('update.manage.productManagement.product');\n const [items, setItems] = useState([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState('');\n const [search, setSearch] = useState('');\n // Default to active-only; the toggle above the table reveals inactive rows.\n const [showInactive, setShowInactive] = useState(false);\n\n async function load() {\n setLoading(true);\n setError('');\n try {\n setItems(await getProducts(undefined, true));\n } catch (err) {\n const message = err?.response?.data?.message ?? err?.message ?? 'Failed to load products';\n setError(message);\n showToast({ message, type: 'error' });\n } finally {\n setLoading(false);\n }\n }\n\n usePermissionedEffect('view.manage.productManagement.product', () => {\n void load();\n }, []);\n\n const filtered = items.filter((p) => {\n if (!showInactive && p.isActive === false) return false;\n if (!search.trim()) return true;\n const q = search.toLowerCase();\n return (p.name?.toLowerCase().includes(q))\n || (p.categoryName?.toLowerCase().includes(q))\n || (p.brandName?.toLowerCase().includes(q))\n || (p.vaccineConfig?.vaccineCode?.toLowerCase().includes(q));\n });\n\n function createNew() {\n navigate(`/ui/medplat/manage/pm/products/${uuidv4()}`);\n }\n\n return (\n <Box>\n <PmNav />\n <PmGuard perm={'view.manage.productManagement.product'}>\n <PmPageShell\n title=\"Products\"\n subtitle=\"Each product is tracked separately. Vaccines need additional setup for vial size and dosing.\"\n chips={['Catalog']}\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 />} onClick={createNew}>New Product</Button>\n ) : null}\n </Stack>\n }\n >\n {error ? <Alert severity=\"error\" sx={{ mb: 2 }}>{error}</Alert> : null}\n\n <PmTableCard\n eyebrow=\"Catalog\"\n title=\"Products\"\n subtitle={loading\n ? 'Loading…'\n : `${filtered.length} of ${items.length} ${items.length === 1 ? 'product' : 'products'}${search.trim() ? ` matching \"${search.trim()}\"` : ''}`}\n actions={\n <FormControlLabel\n control={<CustomSwitch checked={showInactive}\n onChange={(e) => setShowInactive(e.target.checked)} />}\n label={<Typography variant=\"body2\" sx={{ fontWeight: 600 }}>Show inactive</Typography>}\n labelPlacement=\"start\"\n sx={{ mr: 0.5, ml: 0 }}\n />\n }\n toolbar={\n <TextField\n size=\"small\"\n fullWidth\n placeholder=\"Search by name, category, brand, or vaccine code\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n InputProps={{\n startAdornment: (\n <InputAdornment position=\"start\">\n <SearchRoundedIcon fontSize=\"small\" color=\"action\" />\n </InputAdornment>\n ),\n }}\n sx={{ maxWidth: 540 }}\n />\n }\n >\n <PmTable>\n <TableHead>\n <TableRow>\n <TableCell>Product</TableCell>\n <TableCell>Category</TableCell>\n <TableCell>Brand</TableCell>\n <TableCell>Unit</TableCell>\n <TableCell>Expiry</TableCell>\n <TableCell>Vaccine config</TableCell>\n <TableCell>Status</TableCell>\n <TableCell align=\"right\">Action</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {loading ? (\n Array.from({ length: 5 }).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={Inventory2RoundedIcon}\n title={items.length === 0 ? 'No products yet' : 'No matches'}\n hint={items.length === 0\n ? 'Create categories and brands first, then add products.'\n : 'Try a different search term.'}\n action={items.length === 0 && canWrite ? (\n <Button variant=\"contained\" size=\"small\" startIcon={<AddRoundedIcon />} onClick={createNew}>\n Create first product\n </Button>\n ) : null}\n />\n ) : filtered.map((p) => (\n <TableRow key={p.id} hover>\n <TableCell sx={{ maxWidth: 240 }}>\n <Typography variant=\"body2\" sx={{ fontWeight: 700, wordBreak: 'break-word' }}>{p.name}</Typography>\n </TableCell>\n <TableCell sx={{ maxWidth: 160 }}>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ wordBreak: 'break-word' }}>{p.categoryName}</Typography>\n </TableCell>\n <TableCell sx={{ maxWidth: 160 }}>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ wordBreak: 'break-word' }}>{p.brandName}</Typography>\n </TableCell>\n <TableCell>\n <Chip size=\"small\" label={unitLabel(p.unit, p.unitOther)} variant=\"outlined\" sx={{ fontWeight: 700, borderRadius: 1.5, height: 22 }} />\n </TableCell>\n <TableCell>\n {p.hasExpiry\n ? <Chip size=\"small\" label=\"Yes\" color=\"warning\" variant=\"outlined\" sx={{ fontWeight: 700, borderRadius: 1.5, height: 22 }} />\n : <Chip size=\"small\" label=\"No\" variant=\"outlined\" sx={{ fontWeight: 700, borderRadius: 1.5, height: 22 }} />}\n </TableCell>\n <TableCell>\n {p.vaccineConfig ? (\n <Stack direction=\"row\" alignItems=\"center\" spacing={1}>\n <VaccinesRoundedIcon sx={{ fontSize: 18, color: 'info.main' }} />\n <Box>\n <Typography variant=\"caption\" sx={{ fontFamily: 'monospace', fontWeight: 800, display: 'block', lineHeight: 1.2 }}>\n {p.vaccineConfig.vaccineCode}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {p.vaccineConfig.vialVolumeMl}{p.unit === 'DROPS' ? ' drops' : ' ml'}\n {' · '}\n {p.vaccineConfig.singleDose\n ? 'single dose'\n : `${(p.vaccineConfig.profiles ?? []).length} dose profile${(p.vaccineConfig.profiles ?? []).length === 1 ? '' : 's'}`}\n </Typography>\n </Box>\n </Stack>\n ) : <Typography variant=\"caption\" color=\"text.disabled\">—</Typography>}\n </TableCell>\n <TableCell>\n <Chip\n size=\"small\"\n label={p.isActive ? 'Active' : 'Inactive'}\n color={p.isActive ? 'success' : 'default'}\n variant={p.isActive ? 'filled' : 'outlined'}\n sx={{ fontWeight: 700, borderRadius: 1.5, height: 22 }}\n />\n </TableCell>\n <TableCell align=\"right\">\n {canWrite ? (\n <Button size=\"small\" variant=\"outlined\"\n onClick={() => navigate(`/ui/medplat/manage/pm/products/${p.id}`)}>Edit</Button>\n ) : null}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </PmTable>\n </PmTableCard>\n </PmPageShell>\n </PmGuard>\n </Box>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAkCA,SAAwB,IAAe;CACrC,IAAM,IAAW,EAAY,GAEvB,IADQ,EACG,CAAA,CAAM,IAAI,yCAAyC,GAC9D,CAAC,GAAO,KAAY,EAAS,CAAC,CAAC,GAC/B,CAAC,GAAS,KAAc,EAAS,EAAK,GACtC,CAAC,GAAO,KAAY,EAAS,EAAE,GAC/B,CAAC,GAAQ,KAAa,EAAS,EAAE,GAEjC,CAAC,GAAc,KAAmB,EAAS,EAAK;CAEtD,eAAe,IAAO;EAEpB,AADA,EAAW,EAAI,GACf,EAAS,EAAE;EACX,IAAI;GACF,EAAS,MAAM,EAAY,KAAA,GAAW,EAAI,CAAC;EAC7C,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,EAAsB,+CAA+C;EACnE,EAAU;CACZ,GAAG,CAAC,CAAC;CAEL,IAAM,IAAW,EAAM,QAAQ,MAAM;EACnC,IAAI,CAAC,KAAgB,EAAE,aAAa,IAAO,OAAO;EAClD,IAAI,CAAC,EAAO,KAAK,GAAG,OAAO;EAC3B,IAAM,IAAI,EAAO,YAAY;EAC7B,OAAQ,EAAE,MAAM,YAAY,CAAC,CAAC,SAAS,CAAC,KAClC,EAAE,cAAc,YAAY,CAAC,CAAC,SAAS,CAAC,KACxC,EAAE,WAAW,YAAY,CAAC,CAAC,SAAS,CAAC,KACrC,EAAE,eAAe,aAAa,YAAY,CAAC,CAAC,SAAS,CAAC;CAC9D,CAAC;CAED,SAAS,IAAY;EACnB,EAAS,kCAAkC,EAAO,GAAG;CACvD;CAEA,OACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,CAAQ,CAAA,GACR,kBAAC,GAAD;EAAS,MAAM;EACf,UAAA,kBAAC,GAAD;GACE,OAAM;GACN,UAAS;GACT,OAAO,CAAC,SAAS;GACjB,SACE,kBAAC,GAAD;IAAO,WAAU;IAAM,SAAS;IAAhC,UAAA,CACE,kBAAC,GAAD;KAAQ,SAAQ;KAAW,WAAW,kBAAC,GAAD,CAAqB,CAAA;KAAG,eAAe,KAAK,EAAK;KAAG,UAAA;IAAe,CAAA,GACxG,IACC,kBAAC,GAAD;KAAQ,SAAQ;KAAY,WAAW,kBAAC,GAAD,CAAiB,CAAA;KAAG,SAAS;KAAW,UAAA;IAAmB,CAAA,IAChG,IACC;;GAVX,UAAA,CAaG,IAAQ,kBAAC,GAAD;IAAO,UAAS;IAAQ,IAAI,EAAE,IAAI,EAAE;IAAI,UAAA;GAAa,CAAA,IAAI,MAElE,kBAAC,GAAD;IACE,SAAQ;IACR,OAAM;IACN,UAAU,IACN,aACA,GAAG,EAAS,OAAO,MAAM,EAAM,OAAO,GAAG,EAAM,WAAW,IAAI,YAAY,aAAa,EAAO,KAAK,IAAI,cAAc,EAAO,KAAK,EAAE,KAAK;IAC5I,SACE,kBAAC,GAAD;KACE,SAAS,kBAAC,GAAD;MAAc,SAAS;MAC9B,WAAW,MAAM,EAAgB,EAAE,OAAO,OAAO;KAAI,CAAA;KACvD,OAAO,kBAAC,GAAD;MAAY,SAAQ;MAAQ,IAAI,EAAE,YAAY,IAAI;MAAG,UAAA;KAAyB,CAAA;KACrF,gBAAe;KACf,IAAI;MAAE,IAAI;MAAK,IAAI;KAAE;IACtB,CAAA;IAEH,SACE,kBAAC,GAAD;KACE,MAAK;KACL,WAAA;KACA,aAAY;KACZ,OAAO;KACP,WAAW,MAAM,EAAU,EAAE,OAAO,KAAK;KACzC,YAAY,EACV,gBACE,kBAAC,GAAD;MAAgB,UAAS;MACvB,UAAA,kBAAC,GAAD;OAAmB,UAAS;OAAQ,OAAM;MAAU,CAAA;KACtC,CAAA,EAEpB;KACA,IAAI,EAAE,UAAU,IAAI;IACrB,CAAA;IAGH,UAAA,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UAAA;KACE,kBAAC,GAAD,EAAA,UAAW,UAAkB,CAAA;KAC7B,kBAAC,GAAD,EAAA,UAAW,WAAmB,CAAA;KAC9B,kBAAC,GAAD,EAAA,UAAW,QAAgB,CAAA;KAC3B,kBAAC,GAAD,EAAA,UAAW,OAAe,CAAA;KAC1B,kBAAC,GAAD,EAAA,UAAW,SAAiB,CAAA;KAC5B,kBAAC,GAAD,EAAA,UAAW,iBAAyB,CAAA;KACpC,kBAAC,GAAD,EAAA,UAAW,SAAiB,CAAA;KAC5B,kBAAC,GAAD;MAAW,OAAM;MAAQ,UAAA;KAAiB,CAAA;IAClC,EAAA,CAAA,EACD,CAAA,GACX,kBAAC,GAAD,EAAA,UACG,IACC,MAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,MAChC,kBAAC,GAAD,EAAA,UACG,MAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,GAAI,MAClC,kBAAC,GAAD,EAAA,UAAmB,kBAAC,GAAD,EAAU,QAAQ,GAAK,CAAA,EAAY,GAAtC,CAAsC,CACvD,EACO,GAJK,CAIL,CACX,IACC,EAAS,WAAW,IACtB,kBAAC,GAAD;KACE,SAAS;KACT,MAAM;KACN,OAAO,EAAM,WAAW,IAAI,oBAAoB;KAChD,MAAM,EAAM,WAAW,IACnB,2DACA;KACJ,QAAQ,EAAM,WAAW,KAAK,IAC5B,kBAAC,GAAD;MAAQ,SAAQ;MAAY,MAAK;MAAQ,WAAW,kBAAC,GAAD,CAAiB,CAAA;MAAG,SAAS;MAAW,UAAA;KAEpF,CAAA,IACN;IACL,CAAA,IACC,EAAS,KAAK,MAChB,kBAAC,GAAD;KAAqB,OAAA;KAArB,UAAA;MACE,kBAAC,GAAD;OAAW,IAAI,EAAE,UAAU,IAAI;OAC7B,UAAA,kBAAC,GAAD;QAAY,SAAQ;QAAQ,IAAI;SAAE,YAAY;SAAK,WAAW;QAAa;QAAI,UAAA,EAAE;OAAiB,CAAA;MACzF,CAAA;MACX,kBAAC,GAAD;OAAW,IAAI,EAAE,UAAU,IAAI;OAC7B,UAAA,kBAAC,GAAD;QAAY,SAAQ;QAAU,OAAM;QAAiB,IAAI,EAAE,WAAW,aAAa;QAAI,UAAA,EAAE;OAAyB,CAAA;MACzG,CAAA;MACX,kBAAC,GAAD;OAAW,IAAI,EAAE,UAAU,IAAI;OAC7B,UAAA,kBAAC,GAAD;QAAY,SAAQ;QAAU,OAAM;QAAiB,IAAI,EAAE,WAAW,aAAa;QAAI,UAAA,EAAE;OAAsB,CAAA;MACtG,CAAA;MACX,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;OAAM,MAAK;OAAQ,OAAO,EAAU,EAAE,MAAM,EAAE,SAAS;OAAG,SAAQ;OAAW,IAAI;QAAE,YAAY;QAAK,cAAc;QAAK,QAAQ;OAAG;MAAI,CAAA,EAC7H,CAAA;MACX,kBAAC,GAAD,EAAA,UACG,EAAE,YACC,kBAAC,GAAD;OAAM,MAAK;OAAQ,OAAM;OAAM,OAAM;OAAU,SAAQ;OAAW,IAAI;QAAE,YAAY;QAAK,cAAc;QAAK,QAAQ;OAAG;MAAI,CAAA,IAC3H,kBAAC,GAAD;OAAM,MAAK;OAAQ,OAAM;OAAK,SAAQ;OAAW,IAAI;QAAE,YAAY;QAAK,cAAc;QAAK,QAAQ;OAAG;MAAI,CAAA,EACrG,CAAA;MACX,kBAAC,GAAD,EAAA,UACG,EAAE,gBACD,kBAAC,GAAD;OAAO,WAAU;OAAM,YAAW;OAAS,SAAS;OAApD,UAAA,CACE,kBAAC,GAAD,EAAqB,IAAI;QAAE,UAAU;QAAI,OAAO;OAAY,EAAI,CAAA,GAChE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD;QAAY,SAAQ;QAAU,IAAI;SAAE,YAAY;SAAa,YAAY;SAAK,SAAS;SAAS,YAAY;QAAI;QAC7G,UAAA,EAAE,cAAc;OACP,CAAA,GACZ,kBAAC,GAAD;QAAY,SAAQ;QAAU,OAAM;QAAiB,IAAI,EAAE,oBAAoB,eAAe;QAA9F,UAAA;SACG,EAAE,cAAc;SAAc,EAAE,SAAS,UAAU,WAAW;SAC9D;SACA,EAAE,cAAc,aACb,gBACA,IAAI,EAAE,cAAc,YAAY,CAAC,EAAA,CAAG,OAAO,gBAAgB,EAAE,cAAc,YAAY,CAAC,EAAA,CAAG,WAAW,IAAI,KAAK;QACzG;OACT,CAAA,CAAA,EAAA,CAAA,CACA;MACL,CAAA,IAAA,kBAAC,GAAD;OAAY,SAAQ;OAAU,OAAM;OAAgB,UAAA;MAAa,CAAA,EAC5D,CAAA;MACX,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;OACE,MAAK;OACL,OAAO,EAAE,WAAW,WAAW;OAC/B,OAAO,EAAE,WAAW,YAAY;OAChC,SAAS,EAAE,WAAW,WAAW;OACjC,IAAI;QAAE,YAAY;QAAK,cAAc;QAAK,QAAQ;OAAG;MACtD,CAAA,EACQ,CAAA;MACX,kBAAC,GAAD;OAAW,OAAM;OACd,UAAA,IACC,kBAAC,GAAD;QAAQ,MAAK;QAAQ,SAAQ;QAC3B,eAAe,EAAS,kCAAkC,EAAE,IAAI;QAAG,UAAA;OAAY,CAAA,IAC/E;MACK,CAAA;KACH;IApDK,GAAA,EAAE,EAoDP,CACX,EACQ,CAAA,CACJ,EAAA,CAAA;GACE,CAAA,CACF;;CACJ,CAAA,CACN,EAAA,CAAA;AAET"}
1
+ {"version":3,"file":"ProductsPage-CupVmOD4.js","names":[],"sources":["../src/views/ProductsPage.jsx"],"sourcesContent":["import { useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { v4 as uuidv4 } from 'uuid';\nimport {\n Alert,\n Box,\n Button,\n Chip,\n FormControlLabel,\n InputAdornment,\n Skeleton,\n Stack,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n TextField,\n Typography,\n} from '@mui/material';\nimport AddRoundedIcon from '@mui/icons-material/AddRounded';\nimport RefreshRoundedIcon from '@mui/icons-material/RefreshRounded';\nimport SearchRoundedIcon from '@mui/icons-material/SearchRounded';\nimport Inventory2RoundedIcon from '@mui/icons-material/Inventory2Rounded';\nimport VaccinesRoundedIcon from '@mui/icons-material/VaccinesRounded';\nimport { showToast } from '@pm/utils/pmToast';\nimport CustomSwitch from '@/views/custom-components/CustomSwitch';\nimport PmPageShell from '@pm/components/PmPageShell';\nimport PmNav from '@pm/components/PmNav';\nimport PmGuard from '@pm/components/PmGuard';\nimport { PmEmptyRow, PmTable, PmTableCard } from '@pm/components/PmTable';\nimport { getProducts } from '@pm/services/pmApi';\nimport { unitLabel } from '@pm/utils/constants';\nimport { usePermissionedEffect, usePmPermissions } from '@pm/utils/permissions';\n\nexport default function ProductsPage() {\n const navigate = useNavigate();\n const perms = usePmPermissions();\n const canWrite = perms.has('update.manage.productManagement.product');\n const [items, setItems] = useState([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState('');\n const [search, setSearch] = useState('');\n // Default to active-only; the toggle above the table reveals inactive rows.\n const [showInactive, setShowInactive] = useState(false);\n\n async function load() {\n setLoading(true);\n setError('');\n try {\n setItems(await getProducts(undefined, true));\n } catch (err) {\n const message = err?.response?.data?.message ?? err?.message ?? 'Failed to load products';\n setError(message);\n showToast({ message, type: 'error' });\n } finally {\n setLoading(false);\n }\n }\n\n usePermissionedEffect('view.manage.productManagement.product', () => {\n void load();\n }, []);\n\n const filtered = items.filter((p) => {\n if (!showInactive && p.isActive === false) return false;\n if (!search.trim()) return true;\n const q = search.toLowerCase();\n return (p.name?.toLowerCase().includes(q))\n || (p.categoryName?.toLowerCase().includes(q))\n || (p.brandName?.toLowerCase().includes(q))\n || (p.vaccineConfig?.vaccineCode?.toLowerCase().includes(q));\n });\n\n function createNew() {\n navigate(`/ui/medplat/manage/pm/products/${uuidv4()}`);\n }\n\n return (\n <Box>\n <PmNav />\n <PmGuard perm={'view.manage.productManagement.product'}>\n <PmPageShell\n title=\"Products\"\n subtitle=\"Each product is tracked separately. Vaccines need additional setup for vial size and dosing.\"\n chips={['Catalog']}\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 />} onClick={createNew}>New Product</Button>\n ) : null}\n </Stack>\n }\n >\n {error ? <Alert severity=\"error\" sx={{ mb: 2 }}>{error}</Alert> : null}\n\n <PmTableCard\n eyebrow=\"Catalog\"\n title=\"Products\"\n subtitle={loading\n ? 'Loading…'\n : `${filtered.length} of ${items.length} ${items.length === 1 ? 'product' : 'products'}${search.trim() ? ` matching \"${search.trim()}\"` : ''}`}\n actions={\n <FormControlLabel\n control={<CustomSwitch checked={showInactive}\n onChange={(e) => setShowInactive(e.target.checked)} />}\n label={<Typography variant=\"body2\" sx={{ fontWeight: 600 }}>Show inactive</Typography>}\n labelPlacement=\"start\"\n sx={{ mr: 0.5, ml: 0 }}\n />\n }\n toolbar={\n <TextField\n size=\"small\"\n fullWidth\n placeholder=\"Search by name, category, brand, or vaccine code\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n InputProps={{\n startAdornment: (\n <InputAdornment position=\"start\">\n <SearchRoundedIcon fontSize=\"small\" color=\"action\" />\n </InputAdornment>\n ),\n }}\n sx={{ maxWidth: 540 }}\n />\n }\n >\n <PmTable>\n <TableHead>\n <TableRow>\n <TableCell>Product</TableCell>\n <TableCell>Category</TableCell>\n <TableCell>Brand</TableCell>\n <TableCell>Unit</TableCell>\n <TableCell>Expiry</TableCell>\n <TableCell>Vaccine config</TableCell>\n <TableCell>Status</TableCell>\n <TableCell align=\"right\">Action</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {loading ? (\n Array.from({ length: 5 }).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={Inventory2RoundedIcon}\n title={items.length === 0 ? 'No products yet' : 'No matches'}\n hint={items.length === 0\n ? 'Create categories and brands first, then add products.'\n : 'Try a different search term.'}\n action={items.length === 0 && canWrite ? (\n <Button variant=\"contained\" size=\"small\" startIcon={<AddRoundedIcon />} onClick={createNew}>\n Create first product\n </Button>\n ) : null}\n />\n ) : filtered.map((p) => (\n <TableRow key={p.id} hover>\n <TableCell sx={{ maxWidth: 240 }}>\n <Typography variant=\"body2\" sx={{ fontWeight: 700, wordBreak: 'break-word' }}>{p.name}</Typography>\n </TableCell>\n <TableCell sx={{ maxWidth: 160 }}>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ wordBreak: 'break-word' }}>{p.categoryName}</Typography>\n </TableCell>\n <TableCell sx={{ maxWidth: 160 }}>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ wordBreak: 'break-word' }}>{p.brandName}</Typography>\n </TableCell>\n <TableCell>\n <Chip size=\"small\" label={unitLabel(p.unit, p.unitOther)} variant=\"outlined\" sx={{ fontWeight: 700, borderRadius: 1.5, height: 22 }} />\n </TableCell>\n <TableCell>\n {p.hasExpiry\n ? <Chip size=\"small\" label=\"Yes\" color=\"warning\" variant=\"outlined\" sx={{ fontWeight: 700, borderRadius: 1.5, height: 22 }} />\n : <Chip size=\"small\" label=\"No\" variant=\"outlined\" sx={{ fontWeight: 700, borderRadius: 1.5, height: 22 }} />}\n </TableCell>\n <TableCell>\n {p.vaccineConfig ? (\n <Stack direction=\"row\" alignItems=\"center\" spacing={1}>\n <VaccinesRoundedIcon sx={{ fontSize: 18, color: 'info.main' }} />\n <Box>\n <Typography variant=\"caption\" sx={{ fontFamily: 'monospace', fontWeight: 800, display: 'block', lineHeight: 1.2 }}>\n {p.vaccineConfig.vaccineCode}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {p.vaccineConfig.vialVolumeMl}{p.unit === 'DROPS' ? ' drops' : ' ml'}\n {' · '}\n {p.vaccineConfig.singleDose\n ? 'single dose'\n : `${(p.vaccineConfig.profiles ?? []).length} dose profile${(p.vaccineConfig.profiles ?? []).length === 1 ? '' : 's'}`}\n </Typography>\n </Box>\n </Stack>\n ) : <Typography variant=\"caption\" color=\"text.disabled\">—</Typography>}\n </TableCell>\n <TableCell>\n <Chip\n size=\"small\"\n label={p.isActive ? 'Active' : 'Inactive'}\n color={p.isActive ? 'success' : 'default'}\n variant={p.isActive ? 'filled' : 'outlined'}\n sx={{ fontWeight: 700, borderRadius: 1.5, height: 22 }}\n />\n </TableCell>\n <TableCell align=\"right\">\n {canWrite ? (\n <Button size=\"small\" variant=\"outlined\"\n onClick={() => navigate(`/ui/medplat/manage/pm/products/${p.id}`)}>Edit</Button>\n ) : null}\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,11 +1,11 @@
1
- import { O as e, T as t, d as n, j as r, r as i, rt as a } from "./settingsStore-BlA2GIhl.js";
2
- import { l as o, o as s, r as c } from "./PmTable-BSV_bMJZ.js";
1
+ import { O as e, T as t, d as n, j as r, r as i, rt as a } from "./settingsStore-BifOsjlB.js";
2
+ import { l as o, o as s, r as c } from "./PmTable-_GbScaa4.js";
3
3
  import { C as ee, n as te, o as l } from "./constants-ClZJY2x1.js";
4
4
  import { a as ne, r as u, t as re } from "./format-UOyOu75i.js";
5
- import { a as ie, d, f as ae, l as oe, m as f, t as p } from "./validation-B6Kl5Xf9.js";
5
+ import { a as ie, d, f as ae, l as oe, m as f, t as p } from "./validation-BzlHnL-r.js";
6
6
  import { t as se } from "./useFieldErrors-hDG8ox_x.js";
7
- import { a as ce, n as le, r as ue, t as de } from "./PmGuard-DrIl1sHL.js";
8
- import { t as fe } from "./FacilityPicker-jV-qXp1k.js";
7
+ import { a as ce, n as le, r as ue, t as de } from "./PmGuard-b10TGXEi.js";
8
+ import { t as fe } from "./FacilityPicker-BiZeupmP.js";
9
9
  import { useEffect as pe, useMemo as m, useState as h } from "react";
10
10
  import { Fragment as me, jsx as g, jsxs as _ } from "react/jsx-runtime";
11
11
  import { Alert as he, Box as ge, Button as v, Card as y, CardContent as b, Chip as _e, Divider as x, Grid as S, IconButton as ve, Stack as C, Table as ye, TableBody as be, TableCell as w, TableHead as xe, TableRow as T, TextField as E, Typography as D } from "@mui/material";
@@ -645,4 +645,4 @@ function M() {
645
645
  //#endregion
646
646
  export { M as default };
647
647
 
648
- //# sourceMappingURL=PurchaseCreatePage-D6os7srp.js.map
648
+ //# sourceMappingURL=PurchaseCreatePage-YD3NmhPQ.js.map