@argusoft/medplat-product-management 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BrandsPage-DCMCVvDY.js +334 -0
- package/dist/BrandsPage-DCMCVvDY.js.map +1 -0
- package/dist/CategoriesPage-BpRhwfrc.js +284 -0
- package/dist/CategoriesPage-BpRhwfrc.js.map +1 -0
- package/dist/DashboardPage-BNKUQj46.js +436 -0
- package/dist/DashboardPage-BNKUQj46.js.map +1 -0
- package/dist/FacilityPicker-Coi8I3yE.js +79 -0
- package/dist/FacilityPicker-Coi8I3yE.js.map +1 -0
- package/dist/InventoryPage-BR6jOzg2.js +517 -0
- package/dist/InventoryPage-BR6jOzg2.js.map +1 -0
- package/dist/MemberProfileCard-DbHZCS5n.js +272 -0
- package/dist/MemberProfileCard-DbHZCS5n.js.map +1 -0
- package/dist/PaymentCreatePage-Ci3ERnby.js +487 -0
- package/dist/PaymentCreatePage-Ci3ERnby.js.map +1 -0
- package/dist/PaymentsPage-sdg902zX.js +157 -0
- package/dist/PaymentsPage-sdg902zX.js.map +1 -0
- package/dist/PickupCreatePage-CieMsgWV.js +310 -0
- package/dist/PickupCreatePage-CieMsgWV.js.map +1 -0
- package/dist/PickupsPage-Ci2Ll0Kn.js +566 -0
- package/dist/PickupsPage-Ci2Ll0Kn.js.map +1 -0
- package/dist/PmGuard-CjJBisaN.js +1195 -0
- package/dist/PmGuard-CjJBisaN.js.map +1 -0
- package/dist/PmTable-BuXZQZCU.js +302 -0
- package/dist/PmTable-BuXZQZCU.js.map +1 -0
- package/dist/ProductEditPage-DL8gy85Y.js +666 -0
- package/dist/ProductEditPage-DL8gy85Y.js.map +1 -0
- package/dist/ProductsPage-BANTKxLb.js +221 -0
- package/dist/ProductsPage-BANTKxLb.js.map +1 -0
- package/dist/PurchaseCreatePage-C3KMfBxJ.js +626 -0
- package/dist/PurchaseCreatePage-C3KMfBxJ.js.map +1 -0
- package/dist/PurchaseRequestDetailPage-C0GYFJDl.js +586 -0
- package/dist/PurchaseRequestDetailPage-C0GYFJDl.js.map +1 -0
- package/dist/PurchaseRequestsPage-DvFH_tWe.js +265 -0
- package/dist/PurchaseRequestsPage-DvFH_tWe.js.map +1 -0
- package/dist/PurchasesPage-BCvLvSp4.js +295 -0
- package/dist/PurchasesPage-BCvLvSp4.js.map +1 -0
- package/dist/SaleCreatePage-DpkQMoTq.js +548 -0
- package/dist/SaleCreatePage-DpkQMoTq.js.map +1 -0
- package/dist/SalesPage-DUwgkEO-.js +315 -0
- package/dist/SalesPage-DUwgkEO-.js.map +1 -0
- package/dist/SettingsPage-CusC0jqJ.js +710 -0
- package/dist/SettingsPage-CusC0jqJ.js.map +1 -0
- package/dist/StorageUnitsPage-BlC2AgrJ.js +469 -0
- package/dist/StorageUnitsPage-BlC2AgrJ.js.map +1 -0
- package/dist/TransactionsPage-DDaK4VyY.js +714 -0
- package/dist/TransactionsPage-DDaK4VyY.js.map +1 -0
- package/dist/TransferCreatePage-BxudLfhS.js +363 -0
- package/dist/TransferCreatePage-BxudLfhS.js.map +1 -0
- package/dist/TransfersPage-zgmt7teZ.js +480 -0
- package/dist/TransfersPage-zgmt7teZ.js.map +1 -0
- package/dist/VialsPage-CjqPfgpV.js +855 -0
- package/dist/VialsPage-CjqPfgpV.js.map +1 -0
- package/dist/constants-BrA_hfAI.js +254 -0
- package/dist/constants-BrA_hfAI.js.map +1 -0
- package/dist/currency-BDDCDgeE.js +169 -0
- package/dist/currency-BDDCDgeE.js.map +1 -0
- package/dist/format-UOyOu75i.js +52 -0
- package/dist/format-UOyOu75i.js.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/useFieldErrors-hDG8ox_x.js +29 -0
- package/dist/useFieldErrors-hDG8ox_x.js.map +1 -0
- package/dist/validation-Ba7puFIO.js +109 -0
- package/dist/validation-Ba7puFIO.js.map +1 -0
- package/package.json +36 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProductEditPage-DL8gy85Y.js","names":[],"sources":["../src/views/ProductEditPage.jsx"],"sourcesContent":["import { useEffect, useMemo, useState } from 'react';\nimport { useNavigate, useParams } from 'react-router-dom';\nimport { usePermissionedEffect } from '@pm/utils/permissions';\nimport {\n Alert,\n Box,\n Button,\n Card,\n CardContent,\n Checkbox,\n Divider,\n FormControl,\n FormControlLabel,\n FormHelperText,\n Grid,\n InputLabel,\n MenuItem,\n Select,\n Stack,\n TextField,\n Typography,\n} from '@mui/material';\nimport SaveRoundedIcon from '@mui/icons-material/SaveRounded';\nimport { showToast } from '@/common/toaster/toaster';\nimport PmPageShell from '@pm/components/PmPageShell';\nimport PmNav from '@pm/components/PmNav';\nimport PmGuard from '@pm/components/PmGuard';\nimport {\n getBrands,\n getCategories,\n getImmunizationMaster,\n getProduct,\n upsertProduct,\n} from '@pm/services/pmApi';\nimport { PRODUCT_UNITS, VACCINES_CATEGORY_CODE, VACCINE_ROUTES } from '@pm/utils/constants';\nimport {\n isClean,\n validateDose,\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';\n\nconst EMPTY_VACCINE = {\n vaccineCode: '',\n vialVolumeMl: '',\n adultDoseMl: '',\n childDoseMl: '',\n openVialValidityHours: 6,\n maxConcurrentOpenVials: 2,\n requiresReconstitution: false,\n reconstitutedValidityHours: '',\n route: '',\n storageTempMinCelsius: '',\n storageTempMaxCelsius: '',\n comments: '',\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 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 hasExpiry: true,\n needsStorageUnit: false,\n notForSale: false,\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\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 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 hasExpiry: existing.hasExpiry ?? false,\n needsStorageUnit: existing.needsStorageUnit ?? false,\n notForSale: existing.notForSale ?? false,\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 adultDoseMl: existing.vaccineConfig.adultDoseMl ?? '',\n childDoseMl: existing.vaccineConfig.childDoseMl ?? '',\n openVialValidityHours: existing.vaccineConfig.openVialValidityHours ?? 6,\n maxConcurrentOpenVials: existing.vaccineConfig.maxConcurrentOpenVials ?? 2,\n requiresReconstitution: existing.vaccineConfig.requiresReconstitution ?? false,\n reconstitutedValidityHours: existing.vaccineConfig.reconstitutedValidityHours ?? '',\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 }\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 unit: 'VIAL',\n needsStorageUnit: true,\n vaccineConfig: f.vaccineConfig ?? { ...EMPTY_VACCINE },\n }));\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 // -------------------- 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 };\n if (isVaccine && form.vaccineConfig) {\n const v = form.vaccineConfig;\n const temps = validateTempRange(v.storageTempMinCelsius, v.storageTempMaxCelsius);\n Object.assign(base, {\n vaccineCode: validateRequired(v.vaccineCode, 'Vaccine'),\n vialVolumeMl: validateVialVolume(v.vialVolumeMl),\n adultDoseMl: validateDose(v.adultDoseMl, 'Adult dose', v.vialVolumeMl),\n childDoseMl: validateDose(v.childDoseMl, 'Child dose', v.vialVolumeMl),\n openVialValidityHours: validateOpenVialValidity(v.openVialValidityHours),\n maxConcurrentOpenVials: validateMaxConcurrentVials(v.maxConcurrentOpenVials),\n reconstitutedValidityHours: validateReconstitutedValidity(\n v.reconstitutedValidityHours,\n v.requiresReconstitution\n ),\n storageTempMinCelsius: temps.min,\n storageTempMaxCelsius: temps.max,\n });\n // Either an adult or a child dose must be configured.\n if (!v.adultDoseMl && !v.childDoseMl) {\n base.adultDoseMl = base.adultDoseMl || 'Provide at least one dose (adult or child)';\n base.childDoseMl = base.childDoseMl || 'Provide at least one dose (adult or child)';\n }\n }\n return base;\n }, [form, isVaccine]);\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 hasExpiry: !!form.hasExpiry,\n needsStorageUnit: !!form.needsStorageUnit,\n notForSale: manageSales ? !!form.notForSale : false,\n isActive: !!form.isActive,\n imageUuids: form.imageUuids ?? [],\n vaccineConfig: form.vaccineConfig\n ? {\n vaccineCode: form.vaccineConfig.vaccineCode?.trim().toUpperCase(),\n vialVolumeMl: Number(form.vaccineConfig.vialVolumeMl),\n adultDoseMl: form.vaccineConfig.adultDoseMl === '' ? null : Number(form.vaccineConfig.adultDoseMl),\n childDoseMl: form.vaccineConfig.childDoseMl === '' ? null : Number(form.vaccineConfig.childDoseMl),\n openVialValidityHours: Number(form.vaccineConfig.openVialValidityHours ?? 6),\n maxConcurrentOpenVials: Number(form.vaccineConfig.maxConcurrentOpenVials ?? 2),\n requiresReconstitution: !!form.vaccineConfig.requiresReconstitution,\n reconstitutedValidityHours: form.vaccineConfig.reconstitutedValidityHours === ''\n ? null\n : Number(form.vaccineConfig.reconstitutedValidityHours),\n route: form.vaccineConfig.route || null,\n storageTempMinCelsius: form.vaccineConfig.storageTempMinCelsius === ''\n ? null\n : Number(form.vaccineConfig.storageTempMinCelsius),\n storageTempMaxCelsius: form.vaccineConfig.storageTempMaxCelsius === ''\n ? null\n : Number(form.vaccineConfig.storageTempMaxCelsius),\n comments: form.vaccineConfig.comments || null,\n }\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={form.id ? 'Edit Product' : 'New Product'}\n subtitle={`Category: ${selectedCategory?.code ?? '—'}`}\n chips={isVaccine ? ['Vaccine'] : ['Generic']}\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: 4, 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 onChange={(e) => patch('name', e.target.value)}\n onBlur={fieldErrors.onBlur('name')}\n error={fieldErrors.show('name') && !!errors.name}\n helperText={fieldErrors.show('name') ? errors.name : ''}\n />\n </Grid>\n <Grid item xs={12} md={3}>\n <FormControl required fullWidth size=\"small\"\n error={fieldErrors.show('categoryId') && !!errors.categoryId}>\n <InputLabel>Category</InputLabel>\n <Select label=\"Category\" value={form.categoryId}\n onChange={(e) => patch('categoryId', e.target.value)}\n onBlur={fieldErrors.onBlur('categoryId')}>\n {categories.map((c) => <MenuItem key={c.id} value={c.id}>{c.name} ({c.code})</MenuItem>)}\n </Select>\n {fieldErrors.show('categoryId') && errors.categoryId\n ? <FormHelperText>{errors.categoryId}</FormHelperText> : null}\n </FormControl>\n </Grid>\n <Grid item xs={12} md={3}>\n <FormControl required fullWidth size=\"small\"\n error={fieldErrors.show('brandId') && !!errors.brandId}>\n <InputLabel>Brand</InputLabel>\n <Select label=\"Brand\" value={form.brandId}\n onChange={(e) => patch('brandId', e.target.value)}\n onBlur={fieldErrors.onBlur('brandId')}>\n {brands.map((b) => <MenuItem key={b.id} value={b.id}>{b.name}</MenuItem>)}\n </Select>\n {fieldErrors.show('brandId') && errors.brandId\n ? <FormHelperText>{errors.brandId}</FormHelperText> : null}\n </FormControl>\n </Grid>\n <Grid item xs={12} md={3}>\n <FormControl required fullWidth size=\"small\"\n disabled={isVaccine}\n error={fieldErrors.show('unit') && !!errors.unit}>\n <InputLabel>Unit</InputLabel>\n <Select label=\"Unit\" value={form.unit}\n onChange={(e) => patch('unit', e.target.value)}\n onBlur={fieldErrors.onBlur('unit')}>\n {PRODUCT_UNITS.map((u) => <MenuItem key={u.value} value={u.value}>{u.label}</MenuItem>)}\n </Select>\n <FormHelperText>\n {fieldErrors.show('unit') && errors.unit\n ? errors.unit\n : isVaccine ? 'Vaccines must use VIAL' : ''}\n </FormHelperText>\n </FormControl>\n </Grid>\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.isActive}\n onChange={(e) => patch('isActive', e.target.checked)} />} label=\"Active\" />\n </Grid>\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 {isVaccine ? (\n <Card sx={{ borderRadius: 4 }}>\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 <Grid item xs={12} md={3}>\n <FormControl required fullWidth size=\"small\"\n error={fieldErrors.show('vaccineCode') && !!errors.vaccineCode}>\n <InputLabel>Vaccine</InputLabel>\n <Select\n label=\"Vaccine\"\n value={form.vaccineConfig?.vaccineCode || ''}\n onChange={(e) => patchVaccine('vaccineCode', e.target.value)}\n onBlur={fieldErrors.onBlur('vaccineCode')}\n >\n {vaccineMaster.length === 0 ? (\n <MenuItem value=\"\" disabled>\n <em>No vaccines configured in immunization master</em>\n </MenuItem>\n ) : null}\n {vaccineMaster.map((v) => (\n <MenuItem key={v.id} value={v.vaccineCode}>\n {v.vaccineName} ({v.vaccineCode})\n </MenuItem>\n ))}\n </Select>\n <FormHelperText>\n {fieldErrors.show('vaccineCode') && errors.vaccineCode\n ? errors.vaccineCode\n : 'Sourced from medplat_immunization_master'}\n </FormHelperText>\n </FormControl>\n </Grid>\n <Grid item xs={12} md={3}>\n <TextField required fullWidth size=\"small\" type=\"number\" inputProps={{ step: '0.01', min: 0 }}\n label=\"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 />\n </Grid>\n <Grid item xs={12} md={3}>\n <TextField fullWidth size=\"small\" type=\"number\" inputProps={{ step: '0.01', min: 0 }}\n label=\"Adult Dose (ml)\"\n value={form.vaccineConfig?.adultDoseMl ?? ''}\n onChange={(e) => patchVaccine('adultDoseMl', e.target.value)}\n onBlur={fieldErrors.onBlur('adultDoseMl')}\n error={fieldErrors.show('adultDoseMl') && !!errors.adultDoseMl}\n helperText={fieldErrors.show('adultDoseMl') ? errors.adultDoseMl : ''}\n />\n </Grid>\n <Grid item xs={12} md={3}>\n <TextField fullWidth size=\"small\" type=\"number\" inputProps={{ step: '0.01', min: 0 }}\n label=\"Child Dose (ml)\"\n value={form.vaccineConfig?.childDoseMl ?? ''}\n onChange={(e) => patchVaccine('childDoseMl', e.target.value)}\n onBlur={fieldErrors.onBlur('childDoseMl')}\n error={fieldErrors.show('childDoseMl') && !!errors.childDoseMl}\n helperText={fieldErrors.show('childDoseMl') ? errors.childDoseMl : ''}\n />\n </Grid>\n\n <Grid item xs={12} md={3}>\n <TextField required fullWidth size=\"small\" type=\"number\" inputProps={{ min: 0, max: 720 }}\n label=\"Open vial validity (hours)\"\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={\n fieldErrors.show('openVialValidityHours') && errors.openVialValidityHours\n ? errors.openVialValidityHours\n : '0 = single-use; max 720 (~30 days)'\n }\n />\n </Grid>\n <Grid item xs={12} md={3}>\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 <Grid item xs={12} md={3}>\n <FormControlLabel control={<Checkbox checked={!!form.vaccineConfig?.requiresReconstitution}\n onChange={(e) => patchVaccine('requiresReconstitution', e.target.checked)} />} label=\"Requires reconstitution\" />\n </Grid>\n <Grid item xs={12} md={3}>\n <TextField fullWidth size=\"small\" type=\"number\" inputProps={{ min: 1, max: 720 }}\n required={!!form.vaccineConfig?.requiresReconstitution}\n disabled={!form.vaccineConfig?.requiresReconstitution}\n label=\"Reconstituted validity (hours)\"\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 </Grid>\n\n <Grid item xs={12} md={3}>\n <FormControl fullWidth size=\"small\">\n <InputLabel>Route of Administration</InputLabel>\n <Select label=\"Route of Administration\" value={form.vaccineConfig?.route || ''}\n onChange={(e) => patchVaccine('route', e.target.value)}>\n <MenuItem value=\"\"><em>—</em></MenuItem>\n {VACCINE_ROUTES.map((r) => (\n <MenuItem key={r.value} value={r.value}>{r.label}</MenuItem>\n ))}\n </Select>\n </FormControl>\n </Grid>\n <Grid item xs={12} md={3}>\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 : 'Allowed range: −90°C to +30°C'\n }\n />\n </Grid>\n <Grid item xs={12} md={3}>\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 : 'Allowed range: −90°C to +30°C'\n }\n />\n </Grid>\n\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"],"mappings":"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"}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { A as e, a as t, i as n, n as r, r as i, t as a } from "./PmGuard-CjJBisaN.js";
|
|
2
|
+
import { a as o, o as s, t as c } from "./PmTable-BuXZQZCU.js";
|
|
3
|
+
import { useState as l } from "react";
|
|
4
|
+
import { jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
5
|
+
import { v4 as f } from "uuid";
|
|
6
|
+
import { Alert as p, Box as m, Button as h, Chip as g, InputAdornment as _, Skeleton as v, Stack as y, TableBody as b, TableCell as x, TableHead as S, TableRow as C, TextField as w, Typography as T } from "@mui/material";
|
|
7
|
+
import E from "@mui/icons-material/AddRounded";
|
|
8
|
+
import D from "@mui/icons-material/RefreshRounded";
|
|
9
|
+
import { showToast as O } from "@/common/toaster/toaster";
|
|
10
|
+
import { useNavigate as k } from "react-router-dom";
|
|
11
|
+
import A from "@mui/icons-material/Inventory2Rounded";
|
|
12
|
+
import j from "@mui/icons-material/VaccinesRounded";
|
|
13
|
+
import M from "@mui/icons-material/SearchRounded";
|
|
14
|
+
//#region src/views/ProductsPage.jsx
|
|
15
|
+
function N() {
|
|
16
|
+
let N = k(), P = n().has("update.manage.productManagement.product"), [F, I] = l([]), [L, R] = l(!1), [z, B] = l(""), [V, H] = l("");
|
|
17
|
+
async function U() {
|
|
18
|
+
R(!0), B("");
|
|
19
|
+
try {
|
|
20
|
+
I(await e());
|
|
21
|
+
} catch (e) {
|
|
22
|
+
let t = e?.response?.data?.message ?? e?.message ?? "Failed to load products";
|
|
23
|
+
B(t), O({
|
|
24
|
+
message: t,
|
|
25
|
+
type: "error"
|
|
26
|
+
});
|
|
27
|
+
} finally {
|
|
28
|
+
R(!1);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
i("view.manage.productManagement.product", () => {
|
|
32
|
+
U();
|
|
33
|
+
}, []);
|
|
34
|
+
let W = F.filter((e) => {
|
|
35
|
+
if (!V.trim()) return !0;
|
|
36
|
+
let t = V.toLowerCase();
|
|
37
|
+
return e.name?.toLowerCase().includes(t) || e.categoryName?.toLowerCase().includes(t) || e.brandName?.toLowerCase().includes(t) || e.vaccineConfig?.vaccineCode?.toLowerCase().includes(t);
|
|
38
|
+
});
|
|
39
|
+
function G() {
|
|
40
|
+
N(`/ui/medplat/manage/pm/products/${f()}`);
|
|
41
|
+
}
|
|
42
|
+
return /* @__PURE__ */ d(m, { children: [/* @__PURE__ */ u(r, {}), /* @__PURE__ */ u(a, {
|
|
43
|
+
perm: "view.manage.productManagement.product",
|
|
44
|
+
children: /* @__PURE__ */ d(t, {
|
|
45
|
+
title: "Products",
|
|
46
|
+
subtitle: "Each product is tracked separately. Vaccines need additional setup for vial size and dosing.",
|
|
47
|
+
chips: ["Catalog"],
|
|
48
|
+
actions: /* @__PURE__ */ d(y, {
|
|
49
|
+
direction: "row",
|
|
50
|
+
spacing: 1,
|
|
51
|
+
children: [/* @__PURE__ */ u(h, {
|
|
52
|
+
variant: "outlined",
|
|
53
|
+
startIcon: /* @__PURE__ */ u(D, {}),
|
|
54
|
+
onClick: () => void U(),
|
|
55
|
+
children: "Refresh"
|
|
56
|
+
}), P ? /* @__PURE__ */ u(h, {
|
|
57
|
+
variant: "contained",
|
|
58
|
+
startIcon: /* @__PURE__ */ u(E, {}),
|
|
59
|
+
onClick: G,
|
|
60
|
+
children: "New Product"
|
|
61
|
+
}) : null]
|
|
62
|
+
}),
|
|
63
|
+
children: [z ? /* @__PURE__ */ u(p, {
|
|
64
|
+
severity: "error",
|
|
65
|
+
sx: { mb: 2 },
|
|
66
|
+
children: z
|
|
67
|
+
}) : null, /* @__PURE__ */ u(s, {
|
|
68
|
+
eyebrow: "Catalog",
|
|
69
|
+
title: "Products",
|
|
70
|
+
subtitle: L ? "Loading…" : `${W.length} of ${F.length} ${F.length === 1 ? "product" : "products"}${V.trim() ? ` matching "${V.trim()}"` : ""}`,
|
|
71
|
+
toolbar: /* @__PURE__ */ u(w, {
|
|
72
|
+
size: "small",
|
|
73
|
+
fullWidth: !0,
|
|
74
|
+
placeholder: "Search by name, category, brand, or vaccine code",
|
|
75
|
+
value: V,
|
|
76
|
+
onChange: (e) => H(e.target.value),
|
|
77
|
+
InputProps: { startAdornment: /* @__PURE__ */ u(_, {
|
|
78
|
+
position: "start",
|
|
79
|
+
children: /* @__PURE__ */ u(M, {
|
|
80
|
+
fontSize: "small",
|
|
81
|
+
color: "action"
|
|
82
|
+
})
|
|
83
|
+
}) },
|
|
84
|
+
sx: { maxWidth: 540 }
|
|
85
|
+
}),
|
|
86
|
+
children: /* @__PURE__ */ d(o, { children: [/* @__PURE__ */ u(S, { children: /* @__PURE__ */ d(C, { children: [
|
|
87
|
+
/* @__PURE__ */ u(x, { children: "Product" }),
|
|
88
|
+
/* @__PURE__ */ u(x, { children: "Category" }),
|
|
89
|
+
/* @__PURE__ */ u(x, { children: "Brand" }),
|
|
90
|
+
/* @__PURE__ */ u(x, { children: "Unit" }),
|
|
91
|
+
/* @__PURE__ */ u(x, { children: "Expiry" }),
|
|
92
|
+
/* @__PURE__ */ u(x, { children: "Vaccine config" }),
|
|
93
|
+
/* @__PURE__ */ u(x, { children: "Status" }),
|
|
94
|
+
/* @__PURE__ */ u(x, {
|
|
95
|
+
align: "right",
|
|
96
|
+
children: "Action"
|
|
97
|
+
})
|
|
98
|
+
] }) }), /* @__PURE__ */ u(b, { children: L ? Array.from({ length: 5 }).map((e, t) => /* @__PURE__ */ u(C, { children: Array.from({ length: 8 }).map((e, t) => /* @__PURE__ */ u(x, { children: /* @__PURE__ */ u(v, { height: 22 }) }, t)) }, t)) : W.length === 0 ? /* @__PURE__ */ u(c, {
|
|
99
|
+
colSpan: 8,
|
|
100
|
+
icon: A,
|
|
101
|
+
title: F.length === 0 ? "No products yet" : "No matches",
|
|
102
|
+
hint: F.length === 0 ? "Create categories and brands first, then add products." : "Try a different search term.",
|
|
103
|
+
action: F.length === 0 && P ? /* @__PURE__ */ u(h, {
|
|
104
|
+
variant: "contained",
|
|
105
|
+
size: "small",
|
|
106
|
+
startIcon: /* @__PURE__ */ u(E, {}),
|
|
107
|
+
onClick: G,
|
|
108
|
+
children: "Create first product"
|
|
109
|
+
}) : null
|
|
110
|
+
}) : W.map((e) => /* @__PURE__ */ d(C, {
|
|
111
|
+
hover: !0,
|
|
112
|
+
children: [
|
|
113
|
+
/* @__PURE__ */ u(x, { children: /* @__PURE__ */ u(T, {
|
|
114
|
+
variant: "body2",
|
|
115
|
+
sx: { fontWeight: 700 },
|
|
116
|
+
children: e.name
|
|
117
|
+
}) }),
|
|
118
|
+
/* @__PURE__ */ u(x, { children: /* @__PURE__ */ u(T, {
|
|
119
|
+
variant: "caption",
|
|
120
|
+
color: "text.secondary",
|
|
121
|
+
children: e.categoryName
|
|
122
|
+
}) }),
|
|
123
|
+
/* @__PURE__ */ u(x, { children: /* @__PURE__ */ u(T, {
|
|
124
|
+
variant: "caption",
|
|
125
|
+
color: "text.secondary",
|
|
126
|
+
children: e.brandName
|
|
127
|
+
}) }),
|
|
128
|
+
/* @__PURE__ */ u(x, { children: /* @__PURE__ */ u(g, {
|
|
129
|
+
size: "small",
|
|
130
|
+
label: e.unit,
|
|
131
|
+
variant: "outlined",
|
|
132
|
+
sx: {
|
|
133
|
+
fontWeight: 700,
|
|
134
|
+
borderRadius: 1.5,
|
|
135
|
+
height: 22
|
|
136
|
+
}
|
|
137
|
+
}) }),
|
|
138
|
+
/* @__PURE__ */ u(x, { children: e.hasExpiry ? /* @__PURE__ */ u(g, {
|
|
139
|
+
size: "small",
|
|
140
|
+
label: "Yes",
|
|
141
|
+
color: "warning",
|
|
142
|
+
variant: "outlined",
|
|
143
|
+
sx: {
|
|
144
|
+
fontWeight: 700,
|
|
145
|
+
borderRadius: 1.5,
|
|
146
|
+
height: 22
|
|
147
|
+
}
|
|
148
|
+
}) : /* @__PURE__ */ u(g, {
|
|
149
|
+
size: "small",
|
|
150
|
+
label: "No",
|
|
151
|
+
variant: "outlined",
|
|
152
|
+
sx: {
|
|
153
|
+
fontWeight: 700,
|
|
154
|
+
borderRadius: 1.5,
|
|
155
|
+
height: 22
|
|
156
|
+
}
|
|
157
|
+
}) }),
|
|
158
|
+
/* @__PURE__ */ u(x, { children: e.vaccineConfig ? /* @__PURE__ */ d(y, {
|
|
159
|
+
direction: "row",
|
|
160
|
+
alignItems: "center",
|
|
161
|
+
spacing: 1,
|
|
162
|
+
children: [/* @__PURE__ */ u(j, { sx: {
|
|
163
|
+
fontSize: 18,
|
|
164
|
+
color: "info.main"
|
|
165
|
+
} }), /* @__PURE__ */ d(m, { children: [/* @__PURE__ */ u(T, {
|
|
166
|
+
variant: "caption",
|
|
167
|
+
sx: {
|
|
168
|
+
fontFamily: "monospace",
|
|
169
|
+
fontWeight: 800,
|
|
170
|
+
display: "block",
|
|
171
|
+
lineHeight: 1.2
|
|
172
|
+
},
|
|
173
|
+
children: e.vaccineConfig.vaccineCode
|
|
174
|
+
}), /* @__PURE__ */ d(T, {
|
|
175
|
+
variant: "caption",
|
|
176
|
+
color: "text.secondary",
|
|
177
|
+
sx: { fontVariantNumeric: "tabular-nums" },
|
|
178
|
+
children: [
|
|
179
|
+
e.vaccineConfig.vialVolumeMl,
|
|
180
|
+
"ml · ",
|
|
181
|
+
e.vaccineConfig.adultDoseMl ?? "—",
|
|
182
|
+
"/",
|
|
183
|
+
e.vaccineConfig.childDoseMl ?? "—",
|
|
184
|
+
" ml"
|
|
185
|
+
]
|
|
186
|
+
})] })]
|
|
187
|
+
}) : /* @__PURE__ */ u(T, {
|
|
188
|
+
variant: "caption",
|
|
189
|
+
color: "text.disabled",
|
|
190
|
+
children: "—"
|
|
191
|
+
}) }),
|
|
192
|
+
/* @__PURE__ */ u(x, { children: /* @__PURE__ */ u(g, {
|
|
193
|
+
size: "small",
|
|
194
|
+
label: e.isActive ? "Active" : "Inactive",
|
|
195
|
+
color: e.isActive ? "success" : "default",
|
|
196
|
+
variant: e.isActive ? "filled" : "outlined",
|
|
197
|
+
sx: {
|
|
198
|
+
fontWeight: 700,
|
|
199
|
+
borderRadius: 1.5,
|
|
200
|
+
height: 22
|
|
201
|
+
}
|
|
202
|
+
}) }),
|
|
203
|
+
/* @__PURE__ */ u(x, {
|
|
204
|
+
align: "right",
|
|
205
|
+
children: P ? /* @__PURE__ */ u(h, {
|
|
206
|
+
size: "small",
|
|
207
|
+
variant: "outlined",
|
|
208
|
+
onClick: () => N(`/ui/medplat/manage/pm/products/${e.id}`),
|
|
209
|
+
children: "Edit"
|
|
210
|
+
}) : null
|
|
211
|
+
})
|
|
212
|
+
]
|
|
213
|
+
}, e.id)) })] })
|
|
214
|
+
})]
|
|
215
|
+
})
|
|
216
|
+
})] });
|
|
217
|
+
}
|
|
218
|
+
//#endregion
|
|
219
|
+
export { N as default };
|
|
220
|
+
|
|
221
|
+
//# sourceMappingURL=ProductsPage-BANTKxLb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProductsPage-BANTKxLb.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 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 '@/common/toaster/toaster';\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 { 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\n async function load() {\n setLoading(true);\n setError('');\n try {\n setItems(await getProducts());\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 (!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 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>\n <Typography variant=\"body2\" sx={{ fontWeight: 700 }}>{p.name}</Typography>\n </TableCell>\n <TableCell>\n <Typography variant=\"caption\" color=\"text.secondary\">{p.categoryName}</Typography>\n </TableCell>\n <TableCell>\n <Typography variant=\"caption\" color=\"text.secondary\">{p.brandName}</Typography>\n </TableCell>\n <TableCell>\n <Chip size=\"small\" label={p.unit} 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}ml · {p.vaccineConfig.adultDoseMl ?? '—'}/{p.vaccineConfig.childDoseMl ?? '—'} ml\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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"}
|