@argusoft/medplat-product-management 1.0.8 → 1.0.9
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-DmRW5bhm.js → BrandsPage-DMw2vT0u.js} +4 -4
- package/dist/{BrandsPage-DmRW5bhm.js.map → BrandsPage-DMw2vT0u.js.map} +1 -1
- package/dist/CategoriesPage-D3ihx9Gi.js +398 -0
- package/dist/CategoriesPage-D3ihx9Gi.js.map +1 -0
- package/dist/{DashboardPage-C3bKc5na.js → DashboardPage-asr2XDRu.js} +13 -13
- package/dist/{DashboardPage-C3bKc5na.js.map → DashboardPage-asr2XDRu.js.map} +1 -1
- package/dist/{FacilityPicker-BiZeupmP.js → FacilityPicker-DYl_PDyt.js} +2 -2
- package/dist/{FacilityPicker-BiZeupmP.js.map → FacilityPicker-DYl_PDyt.js.map} +1 -1
- package/dist/{InventoryPage-C_AxSy7A.js → InventoryPage-DOotGZrj.js} +11 -11
- package/dist/{InventoryPage-C_AxSy7A.js.map → InventoryPage-DOotGZrj.js.map} +1 -1
- package/dist/{MemberProfileCard-BdUNgHRB.js → MemberProfileCard-D5CgkTdJ.js} +3 -3
- package/dist/{MemberProfileCard-BdUNgHRB.js.map → MemberProfileCard-D5CgkTdJ.js.map} +1 -1
- package/dist/{PaymentCreatePage-CIVe0P0p.js → PaymentCreatePage-DfvSZ-kB.js} +6 -6
- package/dist/{PaymentCreatePage-CIVe0P0p.js.map → PaymentCreatePage-DfvSZ-kB.js.map} +1 -1
- package/dist/{PaymentsPage-BvPe5Q9F.js → PaymentsPage-DMNjYWAJ.js} +7 -7
- package/dist/{PaymentsPage-BvPe5Q9F.js.map → PaymentsPage-DMNjYWAJ.js.map} +1 -1
- package/dist/{PickupBatchLinesEditor-DHmcAG23.js → PickupBatchLinesEditor-CE2RuyJT.js} +2 -2
- package/dist/{PickupBatchLinesEditor-DHmcAG23.js.map → PickupBatchLinesEditor-CE2RuyJT.js.map} +1 -1
- package/dist/{PickupCreatePage-CB0Sl0Hb.js → PickupCreatePage-B4O_-vE5.js} +16 -16
- package/dist/{PickupCreatePage-CB0Sl0Hb.js.map → PickupCreatePage-B4O_-vE5.js.map} +1 -1
- package/dist/{PickupsPage-Ctpghavs.js → PickupsPage-D7zyioJB.js} +13 -13
- package/dist/{PickupsPage-Ctpghavs.js.map → PickupsPage-D7zyioJB.js.map} +1 -1
- package/dist/{PmGuard-b10TGXEi.js → PmGuard-BZE-y4In.js} +2 -2
- package/dist/{PmGuard-b10TGXEi.js.map → PmGuard-BZE-y4In.js.map} +1 -1
- package/dist/{PmTable-_GbScaa4.js → PmTable-CwKORZGg.js} +2 -2
- package/dist/{PmTable-_GbScaa4.js.map → PmTable-CwKORZGg.js.map} +1 -1
- package/dist/ProductEditPage-BVlVUCtD.js +1296 -0
- package/dist/ProductEditPage-BVlVUCtD.js.map +1 -0
- package/dist/ProductsPage-DvNHIeZt.js +253 -0
- package/dist/ProductsPage-DvNHIeZt.js.map +1 -0
- package/dist/{PurchaseCreatePage-YD3NmhPQ.js → PurchaseCreatePage-Cq_i9snz.js} +213 -186
- package/dist/PurchaseCreatePage-Cq_i9snz.js.map +1 -0
- package/dist/{PurchaseRequestDetailPage-Dg_MRY_N.js → PurchaseRequestDetailPage-CA9KFOfE.js} +16 -16
- package/dist/{PurchaseRequestDetailPage-Dg_MRY_N.js.map → PurchaseRequestDetailPage-CA9KFOfE.js.map} +1 -1
- package/dist/{PurchaseRequestsPage-DPAPzpmm.js → PurchaseRequestsPage-DS9i4o0-.js} +12 -12
- package/dist/{PurchaseRequestsPage-DPAPzpmm.js.map → PurchaseRequestsPage-DS9i4o0-.js.map} +1 -1
- package/dist/{PurchasesPage-It1GHiXl.js → PurchasesPage-DgL5T6BY.js} +4 -4
- package/dist/{PurchasesPage-It1GHiXl.js.map → PurchasesPage-DgL5T6BY.js.map} +1 -1
- package/dist/{SaleCreatePage-C9kFmTvm.js → SaleCreatePage-CZnIOydv.js} +13 -13
- package/dist/{SaleCreatePage-C9kFmTvm.js.map → SaleCreatePage-CZnIOydv.js.map} +1 -1
- package/dist/{SalesPage-D18DCseD.js → SalesPage-DPIRrC_O.js} +13 -13
- package/dist/{SalesPage-D18DCseD.js.map → SalesPage-DPIRrC_O.js.map} +1 -1
- package/dist/SettingsPage-BC_R6Z-Q.js +674 -0
- package/dist/SettingsPage-BC_R6Z-Q.js.map +1 -0
- package/dist/{StorageUnitsPage-7EqwuMOI.js → StorageUnitsPage-BDRkdCjW.js} +209 -205
- package/dist/StorageUnitsPage-BDRkdCjW.js.map +1 -0
- package/dist/{TransactionsPage-DrH53pVS.js → TransactionsPage-CqWTMNU8.js} +5 -5
- package/dist/{TransactionsPage-DrH53pVS.js.map → TransactionsPage-CqWTMNU8.js.map} +1 -1
- package/dist/{TransferCreatePage-CuvoMrYH.js → TransferCreatePage-DF7FZaTJ.js} +14 -14
- package/dist/{TransferCreatePage-CuvoMrYH.js.map → TransferCreatePage-DF7FZaTJ.js.map} +1 -1
- package/dist/{TransfersPage-Cf701t8s.js → TransfersPage-CGrRFaBF.js} +105 -105
- package/dist/{TransfersPage-Cf701t8s.js.map → TransfersPage-CGrRFaBF.js.map} +1 -1
- package/dist/{VialsPage-8oAc1yFv.js → VialsPage-rvvXjgZG.js} +11 -11
- package/dist/{VialsPage-8oAc1yFv.js.map → VialsPage-rvvXjgZG.js.map} +1 -1
- package/dist/{constants-ClZJY2x1.js → constants-DpXnLsAB.js} +34 -27
- package/dist/constants-DpXnLsAB.js.map +1 -0
- package/dist/index.js +122 -99
- package/dist/index.js.map +1 -1
- package/dist/listValueStore-BFQtDYIR.js +36 -0
- package/dist/listValueStore-BFQtDYIR.js.map +1 -0
- package/dist/{settingsStore-BifOsjlB.js → settingsStore-BHHOmcCP.js} +68 -71
- package/dist/settingsStore-BHHOmcCP.js.map +1 -0
- package/package.json +1 -1
- package/dist/CategoriesPage-BsS5IQh3.js +0 -391
- package/dist/CategoriesPage-BsS5IQh3.js.map +0 -1
- package/dist/ProductEditPage-C1thoKHu.js +0 -1294
- package/dist/ProductEditPage-C1thoKHu.js.map +0 -1
- package/dist/ProductsPage-CupVmOD4.js +0 -252
- package/dist/ProductsPage-CupVmOD4.js.map +0 -1
- package/dist/PurchaseCreatePage-YD3NmhPQ.js.map +0 -1
- package/dist/SettingsPage-VsxI-ano.js +0 -746
- package/dist/SettingsPage-VsxI-ano.js.map +0 -1
- package/dist/StorageUnitsPage-7EqwuMOI.js.map +0 -1
- package/dist/constants-ClZJY2x1.js.map +0 -1
- package/dist/settingsStore-BifOsjlB.js.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { g as e,
|
|
2
|
-
import { c as ee, l as r, n as i, s as te, t as ne } from "./PmTable-
|
|
1
|
+
import { g as e, it as t, r as n } from "./settingsStore-BHHOmcCP.js";
|
|
2
|
+
import { c as ee, l as r, n as i, s as te, t as ne } from "./PmTable-CwKORZGg.js";
|
|
3
3
|
import { i as re, m as a, t as o } from "./validation-BzlHnL-r.js";
|
|
4
4
|
import { t as ie } from "./useFieldErrors-hDG8ox_x.js";
|
|
5
|
-
import { a as ae, i as oe, n as s, r as c, t as l } from "./PmGuard-
|
|
5
|
+
import { a as ae, i as oe, n as s, r as c, t as l } from "./PmGuard-BZE-y4In.js";
|
|
6
6
|
import { useState as u } from "react";
|
|
7
7
|
import { jsx as d, jsxs as f } from "react/jsx-runtime";
|
|
8
8
|
import { Alert as se, Box as p, Button as m, Checkbox as ce, Chip as le, Dialog as ue, DialogActions as h, DialogContent as de, DialogTitle as g, FormControlLabel as _, InputAdornment as fe, Skeleton as v, Stack as y, TableBody as b, TableCell as x, TableHead as pe, TableRow as S, TextField as C, Typography as w } from "@mui/material";
|
|
@@ -383,4 +383,4 @@ function j() {
|
|
|
383
383
|
//#endregion
|
|
384
384
|
export { j as default };
|
|
385
385
|
|
|
386
|
-
//# sourceMappingURL=BrandsPage-
|
|
386
|
+
//# sourceMappingURL=BrandsPage-DMw2vT0u.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BrandsPage-DmRW5bhm.js","names":[],"sources":["../src/views/BrandsPage.jsx"],"sourcesContent":["import { useState } from 'react';\nimport { v4 as uuidv4 } from 'uuid';\nimport {\n Alert,\n Box,\n Button,\n Checkbox,\n Chip,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\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 SellRoundedIcon from '@mui/icons-material/SellRounded';\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 { usePermissionedEffect, usePmPermissions } from '@pm/utils/permissions';\nimport { PmEmptyRow, PmFieldHelp, PmTable, PmTableCard } from '@pm/components/PmTable';\nimport { getBrands, upsertBrand } from '@pm/services/pmApi';\nimport { isClean, validateEmail, validateRequired } from '@pm/utils/validation';\nimport { findCountry, validatePhoneForCountry } from '@/common/constants/countries';\nimport { usePmSettings } from '@pm/utils/settingsStore';\nimport { useFieldErrors } from '@pm/utils/useFieldErrors';\n\n// Backend stores contact_info as a JSON-encoded string. We keep the discrete\n// fields here so the UI is form-friendly, and only ever round-trip the JSON.\nfunction parseContactInfo(raw) {\n if (!raw) return { phone: '', email: '' };\n try {\n const obj = JSON.parse(raw);\n return {\n phone: typeof obj?.phone === 'string' ? obj.phone : '',\n email: typeof obj?.email === 'string' ? obj.email : '',\n };\n } catch {\n return { phone: '', email: '' };\n }\n}\n\nfunction serializeContactInfo({ phone, email }) {\n const out = {};\n if (phone?.trim()) out.phone = phone.trim();\n if (email?.trim()) out.email = email.trim();\n return Object.keys(out).length ? JSON.stringify(out) : null;\n}\n\nexport default function BrandsPage() {\n const perms = usePmPermissions();\n const canWrite = perms.has('update.manage.productManagement.brand');\n const settings = usePmSettings();\n const country = findCountry(settings?.countryCode);\n const [items, setItems] = useState([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState('');\n const [openDialog, setOpenDialog] = useState(false);\n const [editing, setEditing] = useState(null);\n // Default to active-only; the toggle above the table reveals inactive rows.\n const [showInactive, setShowInactive] = useState(false);\n const [form, setForm] = useState(emptyForm());\n const fieldErrors = useFieldErrors();\n\n function emptyForm() {\n return {\n id: '',\n name: '',\n manufacturerCode: '',\n contactPhone: '',\n contactEmail: '',\n isActive: true,\n };\n }\n\n async function load() {\n setLoading(true);\n setError('');\n try {\n const data = await getBrands(undefined, true);\n setItems(data);\n } catch (err) {\n const message = err?.response?.data?.message ?? err?.message ?? 'Failed to load brands';\n setError(message);\n showToast({ message, type: 'error' });\n } finally {\n setLoading(false);\n }\n }\n\n usePermissionedEffect('view.manage.productManagement.brand', () => {\n void load();\n }, []);\n\n function openCreate() {\n setEditing(null);\n setForm({ ...emptyForm(), id: uuidv4() });\n fieldErrors.reset();\n setError('');\n setOpenDialog(true);\n }\n\n function openEdit(item) {\n const { phone, email } = parseContactInfo(item.contactInfo);\n setEditing(item);\n fieldErrors.reset();\n setError('');\n setForm({\n id: item.id,\n name: item.name ?? '',\n manufacturerCode: item.manufacturerCode ?? '',\n contactPhone: phone,\n contactEmail: email,\n isActive: item.isActive !== false,\n });\n setOpenDialog(true);\n }\n\n const mfrCodeBase = validateRequired(form.manufacturerCode, 'Manufacturer code');\n const mfrNorm = form.manufacturerCode.trim().toUpperCase();\n const mfrClash = !mfrCodeBase\n && mfrNorm\n && items.some((b) => b.id !== form.id && (b.manufacturerCode || '').toUpperCase() === mfrNorm);\n const formErrors = {\n name: validateRequired(form.name, 'Name'),\n manufacturerCode: mfrCodeBase || (mfrClash ? 'Code is already in use — edit it manually to make it unique.' : ''),\n contactPhone: validatePhoneForCountry(form.contactPhone, country),\n contactEmail: validateEmail(form.contactEmail),\n };\n const formIsValid = isClean(formErrors);\n\n async function save() {\n if (!formIsValid) {\n fieldErrors.markAllTouched();\n setError('Please fix the highlighted fields.');\n return;\n }\n try {\n await upsertBrand({\n id: form.id,\n name: form.name.trim(),\n manufacturerCode: form.manufacturerCode.trim().toUpperCase(),\n contactInfo: serializeContactInfo({\n phone: form.contactPhone,\n email: form.contactEmail,\n }),\n isActive: form.isActive,\n });\n showToast({ message: 'Brand saved.', type: 'success' });\n setOpenDialog(false);\n await load();\n } catch (err) {\n const message = err?.response?.data?.message ?? err?.message ?? 'Failed to save brand';\n setError(message);\n showToast({ message, type: 'error' });\n }\n }\n\n const visible = showInactive ? items : items.filter((b) => b.isActive !== false);\n\n return (\n <Box>\n <PmNav />\n <PmGuard perm={'view.manage.productManagement.brand'}>\n <PmPageShell\n title=\"Brands\"\n subtitle=\"The manufacturer or supplier of each product.\"\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={openCreate}>New Brand</Button>\n ) : null}\n </Stack>\n }\n >\n {error ? <Alert severity=\"error\" sx={{ mb: 2 }}>{error}</Alert> : null}\n\n <PmTableCard\n eyebrow=\"Master data\"\n title=\"Brands\"\n subtitle={loading ? 'Loading…' : `${visible.length} ${visible.length === 1 ? 'brand' : 'brands'}`}\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 >\n <PmTable>\n <TableHead>\n <TableRow>\n <TableCell>Name</TableCell>\n <TableCell>Manufacturer Code</TableCell>\n <TableCell>Contact</TableCell>\n <TableCell>Status</TableCell>\n <TableCell align=\"right\">Action</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {loading ? (\n Array.from({ length: 4 }).map((_, i) => (\n <TableRow key={i}>\n {Array.from({ length: 5 }).map((__, j) => (\n <TableCell key={j}><Skeleton height={22} /></TableCell>\n ))}\n </TableRow>\n ))\n ) : visible.length === 0 ? (\n <PmEmptyRow\n colSpan={5}\n icon={SellRoundedIcon}\n title={items.length === 0 ? 'No brands yet' : 'No active brands'}\n hint={items.length === 0\n ? 'Add manufacturers so you can link them to your products.'\n : 'Turn on “Show inactive” to see deactivated brands.'}\n action={items.length === 0 && canWrite ? (\n <Button variant=\"contained\" size=\"small\" startIcon={<AddRoundedIcon />} onClick={openCreate}>\n Create first brand\n </Button>\n ) : null}\n />\n ) : visible.map((b) => {\n const { phone, email } = parseContactInfo(b.contactInfo);\n return (\n <TableRow key={b.id} hover>\n <TableCell sx={{ maxWidth: 240 }}>\n <Typography variant=\"body2\" sx={{ fontWeight: 700, wordBreak: 'break-word' }}>{b.name}</Typography>\n </TableCell>\n <TableCell sx={{ maxWidth: 160 }}>\n <Box component=\"span\" sx={{\n display: 'inline-block', px: 0.85, py: 0.25, borderRadius: 1,\n bgcolor: 'grey.100', fontFamily: 'monospace', fontSize: '0.72rem', fontWeight: 800,\n maxWidth: '100%', wordBreak: 'break-all',\n }}>\n {b.manufacturerCode}\n </Box>\n </TableCell>\n <TableCell>\n {phone || email ? (\n <Stack spacing={0.25}>\n {phone ? <Typography variant=\"caption\" sx={{ fontWeight: 600 }}>{phone}</Typography> : null}\n {email ? <Typography variant=\"caption\" color=\"text.secondary\">{email}</Typography> : null}\n </Stack>\n ) : <Typography variant=\"caption\" color=\"text.disabled\">—</Typography>}\n </TableCell>\n <TableCell>\n <Chip\n size=\"small\"\n label={b.isActive ? 'Active' : 'Inactive'}\n color={b.isActive ? 'success' : 'default'}\n variant={b.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\" onClick={() => openEdit(b)}>Edit</Button>\n ) : null}\n </TableCell>\n </TableRow>\n );\n })}\n </TableBody>\n </PmTable>\n </PmTableCard>\n </PmPageShell>\n\n <Dialog open={openDialog} onClose={() => setOpenDialog(false)} fullWidth maxWidth=\"sm\">\n <DialogTitle>{editing ? 'Edit Brand' : 'New Brand'}</DialogTitle>\n <DialogContent dividers>\n <Stack spacing={2} sx={{ pt: 1 }}>\n <TextField\n required\n label=\"Name\" size=\"small\" fullWidth\n value={form.name}\n inputProps={{ maxLength: 255 }}\n onChange={(e) => {\n const nextName = e.target.value;\n // Auto-derive manufacturer code from initials of every word — but\n // only on create (when editing an existing brand we never overwrite\n // a code the user has already curated).\n const initialsFromName = nextName\n .split(/\\s+/)\n .filter(Boolean)\n .map((w) => w[0])\n .join('')\n .toUpperCase();\n setForm((f) => ({\n ...f,\n name: nextName,\n manufacturerCode: editing ? f.manufacturerCode : initialsFromName,\n }));\n }}\n onBlur={fieldErrors.onBlur('name')}\n error={fieldErrors.show('name') && !!formErrors.name}\n FormHelperTextProps={{ component: 'div' }}\n helperText={<PmFieldHelp message={fieldErrors.show('name') ? formErrors.name : ''} value={form.name} max={255} />}\n />\n <TextField\n required\n label=\"Manufacturer code\" size=\"small\" fullWidth\n value={form.manufacturerCode}\n inputProps={{ maxLength: 100 }}\n onChange={(e) => setForm({ ...form, manufacturerCode: e.target.value.toUpperCase() })}\n onBlur={fieldErrors.onBlur('manufacturerCode')}\n error={fieldErrors.show('manufacturerCode') && !!formErrors.manufacturerCode}\n FormHelperTextProps={{ component: 'div' }}\n helperText={\n <PmFieldHelp\n message={fieldErrors.show('manufacturerCode') && formErrors.manufacturerCode\n ? formErrors.manufacturerCode\n : 'Auto-generated from the name as initials. Edit if needed to make it unique.'}\n value={form.manufacturerCode}\n max={100}\n />\n }\n />\n <TextField\n label=\"Contact Number\"\n size=\"small\"\n fullWidth\n type=\"tel\"\n placeholder={country\n ? (country.phoneMin === country.phoneMax\n ? `${country.phoneMin}-digit local number`\n : `${country.phoneMin}–${country.phoneMax} digit local number`)\n : 'Local number'}\n value={form.contactPhone}\n // Keep only digits and spaces — the dial code lives in the\n // adornment, not in the value.\n onChange={(e) => setForm({ ...form, contactPhone: e.target.value.replace(/[^\\d\\s]/g, '') })}\n onBlur={fieldErrors.onBlur('contactPhone')}\n error={fieldErrors.show('contactPhone') && !!formErrors.contactPhone}\n helperText={\n fieldErrors.show('contactPhone') && formErrors.contactPhone\n ? formErrors.contactPhone\n : country\n ? `Format for ${country.name}: ${country.phoneCode} followed by ${country.phoneMin}${country.phoneMin === country.phoneMax ? '' : `–${country.phoneMax}`} digits.`\n : 'Local number, digits only.'\n }\n InputProps={country ? {\n startAdornment: (\n <InputAdornment position=\"start\">\n <Box component=\"span\" sx={{ fontWeight: 700, color: 'text.secondary' }}>{country.phoneCode}</Box>\n </InputAdornment>\n ),\n } : undefined}\n />\n <TextField\n label=\"Email\"\n size=\"small\"\n fullWidth\n type=\"email\"\n placeholder=\"e.g. contact@manufacturer.example\"\n value={form.contactEmail}\n onChange={(e) => setForm({ ...form, contactEmail: e.target.value })}\n onBlur={fieldErrors.onBlur('contactEmail')}\n error={fieldErrors.show('contactEmail') && !!formErrors.contactEmail}\n helperText={fieldErrors.show('contactEmail') ? formErrors.contactEmail : ''}\n />\n <FormControlLabel\n control={<Checkbox checked={form.isActive}\n onChange={(e) => setForm({ ...form, isActive: e.target.checked })} />}\n label=\"Active\" />\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setOpenDialog(false)}>Cancel</Button>\n <Button variant=\"contained\" disabled={!formIsValid} onClick={() => void save()}>Save</Button>\n </DialogActions>\n </Dialog>\n </PmGuard>\n </Box>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BrandsPage-DMw2vT0u.js","names":[],"sources":["../src/views/BrandsPage.jsx"],"sourcesContent":["import { useState } from 'react';\nimport { v4 as uuidv4 } from 'uuid';\nimport {\n Alert,\n Box,\n Button,\n Checkbox,\n Chip,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\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 SellRoundedIcon from '@mui/icons-material/SellRounded';\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 { usePermissionedEffect, usePmPermissions } from '@pm/utils/permissions';\nimport { PmEmptyRow, PmFieldHelp, PmTable, PmTableCard } from '@pm/components/PmTable';\nimport { getBrands, upsertBrand } from '@pm/services/pmApi';\nimport { isClean, validateEmail, validateRequired } from '@pm/utils/validation';\nimport { findCountry, validatePhoneForCountry } from '@/common/constants/countries';\nimport { usePmSettings } from '@pm/utils/settingsStore';\nimport { useFieldErrors } from '@pm/utils/useFieldErrors';\n\n// Backend stores contact_info as a JSON-encoded string. We keep the discrete\n// fields here so the UI is form-friendly, and only ever round-trip the JSON.\nfunction parseContactInfo(raw) {\n if (!raw) return { phone: '', email: '' };\n try {\n const obj = JSON.parse(raw);\n return {\n phone: typeof obj?.phone === 'string' ? obj.phone : '',\n email: typeof obj?.email === 'string' ? obj.email : '',\n };\n } catch {\n return { phone: '', email: '' };\n }\n}\n\nfunction serializeContactInfo({ phone, email }) {\n const out = {};\n if (phone?.trim()) out.phone = phone.trim();\n if (email?.trim()) out.email = email.trim();\n return Object.keys(out).length ? JSON.stringify(out) : null;\n}\n\nexport default function BrandsPage() {\n const perms = usePmPermissions();\n const canWrite = perms.has('update.manage.productManagement.brand');\n const settings = usePmSettings();\n const country = findCountry(settings?.countryCode);\n const [items, setItems] = useState([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState('');\n const [openDialog, setOpenDialog] = useState(false);\n const [editing, setEditing] = useState(null);\n // Default to active-only; the toggle above the table reveals inactive rows.\n const [showInactive, setShowInactive] = useState(false);\n const [form, setForm] = useState(emptyForm());\n const fieldErrors = useFieldErrors();\n\n function emptyForm() {\n return {\n id: '',\n name: '',\n manufacturerCode: '',\n contactPhone: '',\n contactEmail: '',\n isActive: true,\n };\n }\n\n async function load() {\n setLoading(true);\n setError('');\n try {\n const data = await getBrands(undefined, true);\n setItems(data);\n } catch (err) {\n const message = err?.response?.data?.message ?? err?.message ?? 'Failed to load brands';\n setError(message);\n showToast({ message, type: 'error' });\n } finally {\n setLoading(false);\n }\n }\n\n usePermissionedEffect('view.manage.productManagement.brand', () => {\n void load();\n }, []);\n\n function openCreate() {\n setEditing(null);\n setForm({ ...emptyForm(), id: uuidv4() });\n fieldErrors.reset();\n setError('');\n setOpenDialog(true);\n }\n\n function openEdit(item) {\n const { phone, email } = parseContactInfo(item.contactInfo);\n setEditing(item);\n fieldErrors.reset();\n setError('');\n setForm({\n id: item.id,\n name: item.name ?? '',\n manufacturerCode: item.manufacturerCode ?? '',\n contactPhone: phone,\n contactEmail: email,\n isActive: item.isActive !== false,\n });\n setOpenDialog(true);\n }\n\n const mfrCodeBase = validateRequired(form.manufacturerCode, 'Manufacturer code');\n const mfrNorm = form.manufacturerCode.trim().toUpperCase();\n const mfrClash = !mfrCodeBase\n && mfrNorm\n && items.some((b) => b.id !== form.id && (b.manufacturerCode || '').toUpperCase() === mfrNorm);\n const formErrors = {\n name: validateRequired(form.name, 'Name'),\n manufacturerCode: mfrCodeBase || (mfrClash ? 'Code is already in use — edit it manually to make it unique.' : ''),\n contactPhone: validatePhoneForCountry(form.contactPhone, country),\n contactEmail: validateEmail(form.contactEmail),\n };\n const formIsValid = isClean(formErrors);\n\n async function save() {\n if (!formIsValid) {\n fieldErrors.markAllTouched();\n setError('Please fix the highlighted fields.');\n return;\n }\n try {\n await upsertBrand({\n id: form.id,\n name: form.name.trim(),\n manufacturerCode: form.manufacturerCode.trim().toUpperCase(),\n contactInfo: serializeContactInfo({\n phone: form.contactPhone,\n email: form.contactEmail,\n }),\n isActive: form.isActive,\n });\n showToast({ message: 'Brand saved.', type: 'success' });\n setOpenDialog(false);\n await load();\n } catch (err) {\n const message = err?.response?.data?.message ?? err?.message ?? 'Failed to save brand';\n setError(message);\n showToast({ message, type: 'error' });\n }\n }\n\n const visible = showInactive ? items : items.filter((b) => b.isActive !== false);\n\n return (\n <Box>\n <PmNav />\n <PmGuard perm={'view.manage.productManagement.brand'}>\n <PmPageShell\n title=\"Brands\"\n subtitle=\"The manufacturer or supplier of each product.\"\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={openCreate}>New Brand</Button>\n ) : null}\n </Stack>\n }\n >\n {error ? <Alert severity=\"error\" sx={{ mb: 2 }}>{error}</Alert> : null}\n\n <PmTableCard\n eyebrow=\"Master data\"\n title=\"Brands\"\n subtitle={loading ? 'Loading…' : `${visible.length} ${visible.length === 1 ? 'brand' : 'brands'}`}\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 >\n <PmTable>\n <TableHead>\n <TableRow>\n <TableCell>Name</TableCell>\n <TableCell>Manufacturer Code</TableCell>\n <TableCell>Contact</TableCell>\n <TableCell>Status</TableCell>\n <TableCell align=\"right\">Action</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {loading ? (\n Array.from({ length: 4 }).map((_, i) => (\n <TableRow key={i}>\n {Array.from({ length: 5 }).map((__, j) => (\n <TableCell key={j}><Skeleton height={22} /></TableCell>\n ))}\n </TableRow>\n ))\n ) : visible.length === 0 ? (\n <PmEmptyRow\n colSpan={5}\n icon={SellRoundedIcon}\n title={items.length === 0 ? 'No brands yet' : 'No active brands'}\n hint={items.length === 0\n ? 'Add manufacturers so you can link them to your products.'\n : 'Turn on “Show inactive” to see deactivated brands.'}\n action={items.length === 0 && canWrite ? (\n <Button variant=\"contained\" size=\"small\" startIcon={<AddRoundedIcon />} onClick={openCreate}>\n Create first brand\n </Button>\n ) : null}\n />\n ) : visible.map((b) => {\n const { phone, email } = parseContactInfo(b.contactInfo);\n return (\n <TableRow key={b.id} hover>\n <TableCell sx={{ maxWidth: 240 }}>\n <Typography variant=\"body2\" sx={{ fontWeight: 700, wordBreak: 'break-word' }}>{b.name}</Typography>\n </TableCell>\n <TableCell sx={{ maxWidth: 160 }}>\n <Box component=\"span\" sx={{\n display: 'inline-block', px: 0.85, py: 0.25, borderRadius: 1,\n bgcolor: 'grey.100', fontFamily: 'monospace', fontSize: '0.72rem', fontWeight: 800,\n maxWidth: '100%', wordBreak: 'break-all',\n }}>\n {b.manufacturerCode}\n </Box>\n </TableCell>\n <TableCell>\n {phone || email ? (\n <Stack spacing={0.25}>\n {phone ? <Typography variant=\"caption\" sx={{ fontWeight: 600 }}>{phone}</Typography> : null}\n {email ? <Typography variant=\"caption\" color=\"text.secondary\">{email}</Typography> : null}\n </Stack>\n ) : <Typography variant=\"caption\" color=\"text.disabled\">—</Typography>}\n </TableCell>\n <TableCell>\n <Chip\n size=\"small\"\n label={b.isActive ? 'Active' : 'Inactive'}\n color={b.isActive ? 'success' : 'default'}\n variant={b.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\" onClick={() => openEdit(b)}>Edit</Button>\n ) : null}\n </TableCell>\n </TableRow>\n );\n })}\n </TableBody>\n </PmTable>\n </PmTableCard>\n </PmPageShell>\n\n <Dialog open={openDialog} onClose={() => setOpenDialog(false)} fullWidth maxWidth=\"sm\">\n <DialogTitle>{editing ? 'Edit Brand' : 'New Brand'}</DialogTitle>\n <DialogContent dividers>\n <Stack spacing={2} sx={{ pt: 1 }}>\n <TextField\n required\n label=\"Name\" size=\"small\" fullWidth\n value={form.name}\n inputProps={{ maxLength: 255 }}\n onChange={(e) => {\n const nextName = e.target.value;\n // Auto-derive manufacturer code from initials of every word — but\n // only on create (when editing an existing brand we never overwrite\n // a code the user has already curated).\n const initialsFromName = nextName\n .split(/\\s+/)\n .filter(Boolean)\n .map((w) => w[0])\n .join('')\n .toUpperCase();\n setForm((f) => ({\n ...f,\n name: nextName,\n manufacturerCode: editing ? f.manufacturerCode : initialsFromName,\n }));\n }}\n onBlur={fieldErrors.onBlur('name')}\n error={fieldErrors.show('name') && !!formErrors.name}\n FormHelperTextProps={{ component: 'div' }}\n helperText={<PmFieldHelp message={fieldErrors.show('name') ? formErrors.name : ''} value={form.name} max={255} />}\n />\n <TextField\n required\n label=\"Manufacturer code\" size=\"small\" fullWidth\n value={form.manufacturerCode}\n inputProps={{ maxLength: 100 }}\n onChange={(e) => setForm({ ...form, manufacturerCode: e.target.value.toUpperCase() })}\n onBlur={fieldErrors.onBlur('manufacturerCode')}\n error={fieldErrors.show('manufacturerCode') && !!formErrors.manufacturerCode}\n FormHelperTextProps={{ component: 'div' }}\n helperText={\n <PmFieldHelp\n message={fieldErrors.show('manufacturerCode') && formErrors.manufacturerCode\n ? formErrors.manufacturerCode\n : 'Auto-generated from the name as initials. Edit if needed to make it unique.'}\n value={form.manufacturerCode}\n max={100}\n />\n }\n />\n <TextField\n label=\"Contact Number\"\n size=\"small\"\n fullWidth\n type=\"tel\"\n placeholder={country\n ? (country.phoneMin === country.phoneMax\n ? `${country.phoneMin}-digit local number`\n : `${country.phoneMin}–${country.phoneMax} digit local number`)\n : 'Local number'}\n value={form.contactPhone}\n // Keep only digits and spaces — the dial code lives in the\n // adornment, not in the value.\n onChange={(e) => setForm({ ...form, contactPhone: e.target.value.replace(/[^\\d\\s]/g, '') })}\n onBlur={fieldErrors.onBlur('contactPhone')}\n error={fieldErrors.show('contactPhone') && !!formErrors.contactPhone}\n helperText={\n fieldErrors.show('contactPhone') && formErrors.contactPhone\n ? formErrors.contactPhone\n : country\n ? `Format for ${country.name}: ${country.phoneCode} followed by ${country.phoneMin}${country.phoneMin === country.phoneMax ? '' : `–${country.phoneMax}`} digits.`\n : 'Local number, digits only.'\n }\n InputProps={country ? {\n startAdornment: (\n <InputAdornment position=\"start\">\n <Box component=\"span\" sx={{ fontWeight: 700, color: 'text.secondary' }}>{country.phoneCode}</Box>\n </InputAdornment>\n ),\n } : undefined}\n />\n <TextField\n label=\"Email\"\n size=\"small\"\n fullWidth\n type=\"email\"\n placeholder=\"e.g. contact@manufacturer.example\"\n value={form.contactEmail}\n onChange={(e) => setForm({ ...form, contactEmail: e.target.value })}\n onBlur={fieldErrors.onBlur('contactEmail')}\n error={fieldErrors.show('contactEmail') && !!formErrors.contactEmail}\n helperText={fieldErrors.show('contactEmail') ? formErrors.contactEmail : ''}\n />\n <FormControlLabel\n control={<Checkbox checked={form.isActive}\n onChange={(e) => setForm({ ...form, isActive: e.target.checked })} />}\n label=\"Active\" />\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setOpenDialog(false)}>Cancel</Button>\n <Button variant=\"contained\" disabled={!formIsValid} onClick={() => void save()}>Save</Button>\n </DialogActions>\n </Dialog>\n </PmGuard>\n </Box>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
import { _ as e, at as t } from "./settingsStore-BHHOmcCP.js";
|
|
2
|
+
import { c as ee, l as n, n as r, s as i, t as te } from "./PmTable-CwKORZGg.js";
|
|
3
|
+
import { E as a, b as ne, r as re } from "./constants-DpXnLsAB.js";
|
|
4
|
+
import { m as ie, r as o, t as s } from "./validation-BzlHnL-r.js";
|
|
5
|
+
import { t as c } from "./useFieldErrors-hDG8ox_x.js";
|
|
6
|
+
import { a as ae, i as oe, n as se, r as ce, t as le } from "./PmGuard-BZE-y4In.js";
|
|
7
|
+
import { useState as l } from "react";
|
|
8
|
+
import { jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
9
|
+
import { Alert as ue, Autocomplete as de, Box as f, Button as p, Checkbox as fe, Chip as m, Dialog as h, DialogActions as g, DialogContent as _, DialogTitle as v, FormControlLabel as y, InputAdornment as pe, Skeleton as me, Stack as b, TableBody as he, TableCell as x, TableHead as ge, TableRow as S, TextField as C, Typography as w } from "@mui/material";
|
|
10
|
+
import { v4 as T } from "uuid";
|
|
11
|
+
import E from "@mui/icons-material/AddRounded";
|
|
12
|
+
import D from "@mui/icons-material/RefreshRounded";
|
|
13
|
+
import O from "@/views/custom-components/CustomSwitch";
|
|
14
|
+
import k from "@mui/icons-material/CategoryRounded";
|
|
15
|
+
import A from "@/common/fontAwesomeIcons/FontAwesomeIcons";
|
|
16
|
+
//#region src/views/CategoriesPage.jsx
|
|
17
|
+
function j() {
|
|
18
|
+
let j = oe().has("update.manage.productManagement.category"), [M, N] = l([]), [P, F] = l(!1), [I, L] = l(""), [_e, R] = l(!1), [z, B] = l(null), [V, H] = l(G()), [U, ve] = l(!1), W = c();
|
|
19
|
+
function G() {
|
|
20
|
+
return {
|
|
21
|
+
id: "",
|
|
22
|
+
name: "",
|
|
23
|
+
code: "",
|
|
24
|
+
description: "",
|
|
25
|
+
icon: "",
|
|
26
|
+
isActive: !0
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
async function K() {
|
|
30
|
+
F(!0), L("");
|
|
31
|
+
try {
|
|
32
|
+
N(await e(void 0, !0));
|
|
33
|
+
} catch (e) {
|
|
34
|
+
let t = e?.response?.data?.message ?? e?.message ?? "Failed to load categories";
|
|
35
|
+
L(t), n({
|
|
36
|
+
message: t,
|
|
37
|
+
type: "error"
|
|
38
|
+
});
|
|
39
|
+
} finally {
|
|
40
|
+
F(!1);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
ce("view.manage.productManagement.category", () => {
|
|
44
|
+
K();
|
|
45
|
+
}, []);
|
|
46
|
+
function q() {
|
|
47
|
+
B(null), H({
|
|
48
|
+
...G(),
|
|
49
|
+
id: T()
|
|
50
|
+
}), W.reset(), L(""), R(!0);
|
|
51
|
+
}
|
|
52
|
+
function ye(e) {
|
|
53
|
+
B(e), W.reset(), L(""), H({
|
|
54
|
+
id: e.id,
|
|
55
|
+
name: e.name ?? "",
|
|
56
|
+
code: e.code ?? "",
|
|
57
|
+
description: e.description ?? "",
|
|
58
|
+
icon: e.icon ?? "",
|
|
59
|
+
isActive: e.isActive !== !1
|
|
60
|
+
}), R(!0);
|
|
61
|
+
}
|
|
62
|
+
let J = (z?.code || "").toUpperCase() === ne, Y = o(V.code, { required: !0 }), X = V.code.trim().toUpperCase(), be = !Y && X && M.some((e) => e.id !== V.id && (e.code || "").toUpperCase() === X), xe = !Y && !J && X === "VACCINES", Z = {
|
|
63
|
+
name: ie(V.name, "Name"),
|
|
64
|
+
code: Y || (xe ? "This code is reserved for the Vaccines category." : "") || (be ? "Code is already in use — pick a different one." : "")
|
|
65
|
+
}, Q = s(Z);
|
|
66
|
+
async function Se() {
|
|
67
|
+
if (!Q) {
|
|
68
|
+
W.markAllTouched(), L("Please fix the highlighted fields.");
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
await t({
|
|
73
|
+
id: V.id,
|
|
74
|
+
name: V.name.trim(),
|
|
75
|
+
code: V.code.trim().toUpperCase(),
|
|
76
|
+
description: V.description || null,
|
|
77
|
+
icon: V.icon || null,
|
|
78
|
+
isActive: V.isActive
|
|
79
|
+
}), n({
|
|
80
|
+
message: "Category saved.",
|
|
81
|
+
type: "success"
|
|
82
|
+
}), R(!1), await K();
|
|
83
|
+
} catch (e) {
|
|
84
|
+
let t = e?.response?.data?.message ?? e?.message ?? "Failed to save category";
|
|
85
|
+
L(t), n({
|
|
86
|
+
message: t,
|
|
87
|
+
type: "error"
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
let $ = U ? M : M.filter((e) => e.isActive !== !1);
|
|
92
|
+
return /* @__PURE__ */ d(f, { children: [/* @__PURE__ */ u(se, {}), /* @__PURE__ */ d(le, {
|
|
93
|
+
perm: "view.manage.productManagement.category",
|
|
94
|
+
children: [/* @__PURE__ */ d(ae, {
|
|
95
|
+
title: "Product Categories",
|
|
96
|
+
subtitle: "Groups of products with similar handling requirements.",
|
|
97
|
+
chips: ["Catalog"],
|
|
98
|
+
actions: /* @__PURE__ */ d(b, {
|
|
99
|
+
direction: "row",
|
|
100
|
+
spacing: 1,
|
|
101
|
+
children: [/* @__PURE__ */ u(p, {
|
|
102
|
+
variant: "outlined",
|
|
103
|
+
startIcon: /* @__PURE__ */ u(D, {}),
|
|
104
|
+
onClick: () => void K(),
|
|
105
|
+
children: "Refresh"
|
|
106
|
+
}), j ? /* @__PURE__ */ u(p, {
|
|
107
|
+
variant: "contained",
|
|
108
|
+
startIcon: /* @__PURE__ */ u(E, {}),
|
|
109
|
+
onClick: q,
|
|
110
|
+
children: "New Category"
|
|
111
|
+
}) : null]
|
|
112
|
+
}),
|
|
113
|
+
children: [I ? /* @__PURE__ */ u(ue, {
|
|
114
|
+
severity: "error",
|
|
115
|
+
sx: { mb: 2 },
|
|
116
|
+
children: I
|
|
117
|
+
}) : null, /* @__PURE__ */ u(ee, {
|
|
118
|
+
eyebrow: "Master data",
|
|
119
|
+
title: "Product categories",
|
|
120
|
+
subtitle: P ? "Loading…" : `${$.length} ${$.length === 1 ? "category" : "categories"}`,
|
|
121
|
+
actions: /* @__PURE__ */ u(y, {
|
|
122
|
+
control: /* @__PURE__ */ u(O, {
|
|
123
|
+
checked: U,
|
|
124
|
+
onChange: (e) => ve(e.target.checked)
|
|
125
|
+
}),
|
|
126
|
+
label: /* @__PURE__ */ u(w, {
|
|
127
|
+
variant: "body2",
|
|
128
|
+
sx: { fontWeight: 600 },
|
|
129
|
+
children: "Show inactive"
|
|
130
|
+
}),
|
|
131
|
+
labelPlacement: "start",
|
|
132
|
+
sx: {
|
|
133
|
+
mr: .5,
|
|
134
|
+
ml: 0
|
|
135
|
+
}
|
|
136
|
+
}),
|
|
137
|
+
children: /* @__PURE__ */ d(i, { children: [/* @__PURE__ */ u(ge, { children: /* @__PURE__ */ d(S, { children: [
|
|
138
|
+
/* @__PURE__ */ u(x, { children: "Code" }),
|
|
139
|
+
/* @__PURE__ */ u(x, { children: "Name" }),
|
|
140
|
+
/* @__PURE__ */ u(x, { children: "Description" }),
|
|
141
|
+
/* @__PURE__ */ u(x, { children: "Status" }),
|
|
142
|
+
/* @__PURE__ */ u(x, {
|
|
143
|
+
align: "right",
|
|
144
|
+
children: "Action"
|
|
145
|
+
})
|
|
146
|
+
] }) }), /* @__PURE__ */ u(he, { children: P ? Array.from({ length: 4 }).map((e, t) => /* @__PURE__ */ u(S, { children: Array.from({ length: 5 }).map((e, t) => /* @__PURE__ */ u(x, { children: /* @__PURE__ */ u(me, { height: 22 }) }, t)) }, t)) : $.length === 0 ? /* @__PURE__ */ u(te, {
|
|
147
|
+
colSpan: 5,
|
|
148
|
+
icon: k,
|
|
149
|
+
title: M.length === 0 ? "No categories yet" : "No active categories",
|
|
150
|
+
hint: M.length === 0 ? "Categories control how products are managed. For example, vaccines need special configuration." : "Turn on “Show inactive” to see deactivated categories.",
|
|
151
|
+
action: M.length === 0 && j ? /* @__PURE__ */ u(p, {
|
|
152
|
+
variant: "contained",
|
|
153
|
+
size: "small",
|
|
154
|
+
startIcon: /* @__PURE__ */ u(E, {}),
|
|
155
|
+
onClick: q,
|
|
156
|
+
children: "Create first category"
|
|
157
|
+
}) : null
|
|
158
|
+
}) : $.map((e) => /* @__PURE__ */ d(S, {
|
|
159
|
+
hover: !0,
|
|
160
|
+
children: [
|
|
161
|
+
/* @__PURE__ */ u(x, {
|
|
162
|
+
sx: { maxWidth: 160 },
|
|
163
|
+
children: /* @__PURE__ */ u(f, {
|
|
164
|
+
component: "span",
|
|
165
|
+
sx: {
|
|
166
|
+
display: "inline-block",
|
|
167
|
+
px: .85,
|
|
168
|
+
py: .25,
|
|
169
|
+
borderRadius: 1,
|
|
170
|
+
bgcolor: "grey.100",
|
|
171
|
+
fontFamily: "monospace",
|
|
172
|
+
fontSize: "0.72rem",
|
|
173
|
+
fontWeight: 800,
|
|
174
|
+
letterSpacing: .4,
|
|
175
|
+
maxWidth: "100%",
|
|
176
|
+
wordBreak: "break-all"
|
|
177
|
+
},
|
|
178
|
+
children: e.code
|
|
179
|
+
})
|
|
180
|
+
}),
|
|
181
|
+
/* @__PURE__ */ u(x, {
|
|
182
|
+
sx: { maxWidth: 220 },
|
|
183
|
+
children: /* @__PURE__ */ d(b, {
|
|
184
|
+
direction: "row",
|
|
185
|
+
spacing: 1,
|
|
186
|
+
alignItems: "center",
|
|
187
|
+
children: [e.icon ? /* @__PURE__ */ u(f, {
|
|
188
|
+
sx: {
|
|
189
|
+
color: "primary.main",
|
|
190
|
+
width: 18,
|
|
191
|
+
textAlign: "center",
|
|
192
|
+
flexShrink: 0
|
|
193
|
+
},
|
|
194
|
+
children: /* @__PURE__ */ u(A, { iconName: e.icon })
|
|
195
|
+
}) : null, /* @__PURE__ */ u(w, {
|
|
196
|
+
variant: "body2",
|
|
197
|
+
sx: {
|
|
198
|
+
fontWeight: 700,
|
|
199
|
+
wordBreak: "break-word"
|
|
200
|
+
},
|
|
201
|
+
children: e.name
|
|
202
|
+
})]
|
|
203
|
+
})
|
|
204
|
+
}),
|
|
205
|
+
/* @__PURE__ */ u(x, {
|
|
206
|
+
sx: { maxWidth: 360 },
|
|
207
|
+
children: e.description ? /* @__PURE__ */ u(w, {
|
|
208
|
+
variant: "caption",
|
|
209
|
+
color: "text.secondary",
|
|
210
|
+
sx: {
|
|
211
|
+
display: "block",
|
|
212
|
+
wordBreak: "break-word"
|
|
213
|
+
},
|
|
214
|
+
children: e.description
|
|
215
|
+
}) : /* @__PURE__ */ u(w, {
|
|
216
|
+
variant: "caption",
|
|
217
|
+
color: "text.disabled",
|
|
218
|
+
children: "—"
|
|
219
|
+
})
|
|
220
|
+
}),
|
|
221
|
+
/* @__PURE__ */ u(x, { children: /* @__PURE__ */ u(m, {
|
|
222
|
+
size: "small",
|
|
223
|
+
label: e.isActive ? "Active" : "Inactive",
|
|
224
|
+
color: e.isActive ? "success" : "default",
|
|
225
|
+
variant: e.isActive ? "filled" : "outlined",
|
|
226
|
+
sx: {
|
|
227
|
+
fontWeight: 700,
|
|
228
|
+
borderRadius: 1.5,
|
|
229
|
+
height: 22
|
|
230
|
+
}
|
|
231
|
+
}) }),
|
|
232
|
+
/* @__PURE__ */ u(x, {
|
|
233
|
+
align: "right",
|
|
234
|
+
children: j ? /* @__PURE__ */ u(p, {
|
|
235
|
+
size: "small",
|
|
236
|
+
variant: "outlined",
|
|
237
|
+
onClick: () => ye(e),
|
|
238
|
+
children: "Edit"
|
|
239
|
+
}) : null
|
|
240
|
+
})
|
|
241
|
+
]
|
|
242
|
+
}, e.id)) })] })
|
|
243
|
+
})]
|
|
244
|
+
}), /* @__PURE__ */ d(h, {
|
|
245
|
+
open: _e,
|
|
246
|
+
onClose: () => R(!1),
|
|
247
|
+
fullWidth: !0,
|
|
248
|
+
maxWidth: "sm",
|
|
249
|
+
children: [
|
|
250
|
+
/* @__PURE__ */ u(v, { children: z ? "Edit Category" : "New Category" }),
|
|
251
|
+
/* @__PURE__ */ u(_, {
|
|
252
|
+
dividers: !0,
|
|
253
|
+
children: /* @__PURE__ */ d(b, {
|
|
254
|
+
spacing: 2,
|
|
255
|
+
sx: { pt: 1 },
|
|
256
|
+
children: [
|
|
257
|
+
/* @__PURE__ */ u(C, {
|
|
258
|
+
required: !0,
|
|
259
|
+
label: "Name",
|
|
260
|
+
size: "small",
|
|
261
|
+
fullWidth: !0,
|
|
262
|
+
value: V.name,
|
|
263
|
+
inputProps: { maxLength: 255 },
|
|
264
|
+
onChange: (e) => H({
|
|
265
|
+
...V,
|
|
266
|
+
name: e.target.value
|
|
267
|
+
}),
|
|
268
|
+
onBlur: W.onBlur("name"),
|
|
269
|
+
error: W.show("name") && !!Z.name,
|
|
270
|
+
FormHelperTextProps: { component: "div" },
|
|
271
|
+
helperText: /* @__PURE__ */ u(r, {
|
|
272
|
+
message: W.show("name") ? Z.name : "",
|
|
273
|
+
value: V.name,
|
|
274
|
+
max: 255
|
|
275
|
+
})
|
|
276
|
+
}),
|
|
277
|
+
/* @__PURE__ */ u(C, {
|
|
278
|
+
required: !0,
|
|
279
|
+
label: "Code (uppercase, A-Z, 0-9, _)",
|
|
280
|
+
size: "small",
|
|
281
|
+
fullWidth: !0,
|
|
282
|
+
value: V.code,
|
|
283
|
+
disabled: J,
|
|
284
|
+
inputProps: { maxLength: 100 },
|
|
285
|
+
onChange: (e) => H({
|
|
286
|
+
...V,
|
|
287
|
+
code: e.target.value.toUpperCase()
|
|
288
|
+
}),
|
|
289
|
+
onBlur: W.onBlur("code"),
|
|
290
|
+
error: W.show("code") && !!Z.code,
|
|
291
|
+
FormHelperTextProps: { component: "div" },
|
|
292
|
+
helperText: J ? "This code is fixed. Vaccine products are found by it." : /* @__PURE__ */ u(r, {
|
|
293
|
+
message: W.show("code") ? Z.code : "Must be unique.",
|
|
294
|
+
value: V.code,
|
|
295
|
+
max: 100
|
|
296
|
+
})
|
|
297
|
+
}),
|
|
298
|
+
/* @__PURE__ */ u(C, {
|
|
299
|
+
label: "Description (optional)",
|
|
300
|
+
size: "small",
|
|
301
|
+
multiline: !0,
|
|
302
|
+
minRows: 2,
|
|
303
|
+
fullWidth: !0,
|
|
304
|
+
value: V.description,
|
|
305
|
+
inputProps: { maxLength: 500 },
|
|
306
|
+
onChange: (e) => H({
|
|
307
|
+
...V,
|
|
308
|
+
description: e.target.value
|
|
309
|
+
}),
|
|
310
|
+
FormHelperTextProps: { component: "div" },
|
|
311
|
+
helperText: /* @__PURE__ */ u(r, {
|
|
312
|
+
message: "",
|
|
313
|
+
value: V.description,
|
|
314
|
+
max: 500
|
|
315
|
+
})
|
|
316
|
+
}),
|
|
317
|
+
/* @__PURE__ */ u(de, {
|
|
318
|
+
size: "small",
|
|
319
|
+
options: re,
|
|
320
|
+
value: V.icon || null,
|
|
321
|
+
onChange: (e, t) => H({
|
|
322
|
+
...V,
|
|
323
|
+
icon: t ?? ""
|
|
324
|
+
}),
|
|
325
|
+
getOptionLabel: (e) => a(e),
|
|
326
|
+
renderOption: (e, t) => /* @__PURE__ */ d(f, {
|
|
327
|
+
component: "li",
|
|
328
|
+
...e,
|
|
329
|
+
sx: {
|
|
330
|
+
display: "flex",
|
|
331
|
+
alignItems: "center",
|
|
332
|
+
gap: 1.25
|
|
333
|
+
},
|
|
334
|
+
children: [/* @__PURE__ */ u(f, {
|
|
335
|
+
sx: {
|
|
336
|
+
width: 20,
|
|
337
|
+
textAlign: "center",
|
|
338
|
+
color: "primary.main"
|
|
339
|
+
},
|
|
340
|
+
children: /* @__PURE__ */ u(A, { iconName: t })
|
|
341
|
+
}), /* @__PURE__ */ u("span", { children: a(t) })]
|
|
342
|
+
}),
|
|
343
|
+
renderInput: (e) => /* @__PURE__ */ u(C, {
|
|
344
|
+
...e,
|
|
345
|
+
label: "Icon (optional)",
|
|
346
|
+
placeholder: "Search icons…",
|
|
347
|
+
helperText: "Shown next to the category across the app.",
|
|
348
|
+
InputProps: {
|
|
349
|
+
...e.InputProps,
|
|
350
|
+
startAdornment: V.icon ? /* @__PURE__ */ u(pe, {
|
|
351
|
+
position: "start",
|
|
352
|
+
children: /* @__PURE__ */ u(f, {
|
|
353
|
+
sx: {
|
|
354
|
+
color: "primary.main",
|
|
355
|
+
display: "flex"
|
|
356
|
+
},
|
|
357
|
+
children: /* @__PURE__ */ u(A, { iconName: V.icon })
|
|
358
|
+
})
|
|
359
|
+
}) : null
|
|
360
|
+
}
|
|
361
|
+
})
|
|
362
|
+
}),
|
|
363
|
+
/* @__PURE__ */ d(f, { children: [/* @__PURE__ */ u(y, {
|
|
364
|
+
control: /* @__PURE__ */ u(fe, {
|
|
365
|
+
checked: V.isActive,
|
|
366
|
+
disabled: J,
|
|
367
|
+
onChange: (e) => H({
|
|
368
|
+
...V,
|
|
369
|
+
isActive: e.target.checked
|
|
370
|
+
})
|
|
371
|
+
}),
|
|
372
|
+
label: "Active"
|
|
373
|
+
}), J ? /* @__PURE__ */ u(w, {
|
|
374
|
+
variant: "caption",
|
|
375
|
+
color: "text.secondary",
|
|
376
|
+
sx: { display: "block" },
|
|
377
|
+
children: "The Vaccines category is always available."
|
|
378
|
+
}) : null] })
|
|
379
|
+
]
|
|
380
|
+
})
|
|
381
|
+
}),
|
|
382
|
+
/* @__PURE__ */ d(g, { children: [/* @__PURE__ */ u(p, {
|
|
383
|
+
onClick: () => R(!1),
|
|
384
|
+
children: "Cancel"
|
|
385
|
+
}), /* @__PURE__ */ u(p, {
|
|
386
|
+
variant: "contained",
|
|
387
|
+
disabled: !Q,
|
|
388
|
+
onClick: () => void Se(),
|
|
389
|
+
children: "Save"
|
|
390
|
+
})] })
|
|
391
|
+
]
|
|
392
|
+
})]
|
|
393
|
+
})] });
|
|
394
|
+
}
|
|
395
|
+
//#endregion
|
|
396
|
+
export { j as default };
|
|
397
|
+
|
|
398
|
+
//# sourceMappingURL=CategoriesPage-D3ihx9Gi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CategoriesPage-D3ihx9Gi.js","names":[],"sources":["../src/views/CategoriesPage.jsx"],"sourcesContent":["import { useState } from 'react';\nimport { v4 as uuidv4 } from 'uuid';\nimport {\n Alert,\n Autocomplete,\n Box,\n Button,\n Checkbox,\n Chip,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\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 CategoryRoundedIcon from '@mui/icons-material/CategoryRounded';\nimport { showToast } from '@pm/utils/pmToast';\nimport CustomSwitch from '@/views/custom-components/CustomSwitch';\nimport FontAwesomeIcons from '@/common/fontAwesomeIcons/FontAwesomeIcons';\nimport PmPageShell from '@pm/components/PmPageShell';\nimport PmNav from '@pm/components/PmNav';\nimport PmGuard from '@pm/components/PmGuard';\nimport { usePermissionedEffect, usePmPermissions } from '@pm/utils/permissions';\nimport { PmEmptyRow, PmFieldHelp, PmTable, PmTableCard } from '@pm/components/PmTable';\nimport { getCategories, upsertCategory } from '@pm/services/pmApi';\nimport { CATEGORY_ICONS, VACCINES_CATEGORY_CODE, iconLabel } from '@pm/utils/constants';\nimport { isClean, validateCode, validateRequired } from '@pm/utils/validation';\nimport { useFieldErrors } from '@pm/utils/useFieldErrors';\n\nexport default function CategoriesPage() {\n const perms = usePmPermissions();\n const canWrite = perms.has('update.manage.productManagement.category');\n const [items, setItems] = useState([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState('');\n const [openDialog, setOpenDialog] = useState(false);\n const [editing, setEditing] = useState(null);\n const [form, setForm] = useState(emptyForm());\n // Default to active-only; the toggle above the table reveals inactive rows.\n const [showInactive, setShowInactive] = useState(false);\n const fieldErrors = useFieldErrors();\n\n function emptyForm() {\n return { id: '', name: '', code: '', description: '', icon: '', isActive: true };\n }\n\n async function load() {\n setLoading(true);\n setError('');\n try {\n const data = await getCategories(undefined, true);\n setItems(data);\n } catch (err) {\n const message = err?.response?.data?.message ?? err?.message ?? 'Failed to load categories';\n setError(message);\n showToast({ message, type: 'error' });\n } finally {\n setLoading(false);\n }\n }\n\n usePermissionedEffect('view.manage.productManagement.category', () => {\n void load();\n }, []);\n\n function openCreate() {\n setEditing(null);\n setForm({ ...emptyForm(), id: uuidv4() });\n fieldErrors.reset();\n setError('');\n setOpenDialog(true);\n }\n\n function openEdit(item) {\n setEditing(item);\n fieldErrors.reset();\n setError('');\n setForm({\n id: item.id,\n name: item.name ?? '',\n code: item.code ?? '',\n description: item.description ?? '',\n icon: item.icon ?? '',\n isActive: item.isActive !== false,\n });\n setOpenDialog(true);\n }\n\n // Every vaccine product is found by this code, so the row that owns it cannot\n // be renamed or retired. Keyed on the SAVED code, not the one in the form, so\n // the lock survives a stray edit. The backend enforces the same rule.\n const isVaccinesCategory = (editing?.code || '').toUpperCase() === VACCINES_CATEGORY_CODE;\n\n const codeBase = validateCode(form.code, { required: true });\n const codeNorm = form.code.trim().toUpperCase();\n const codeClash = !codeBase\n && codeNorm\n && items.some((c) => c.id !== form.id && (c.code || '').toUpperCase() === codeNorm);\n // The protected row is excluded from the reserved-code check, otherwise\n // editing its own name would trip on its own code.\n const codeReserved = !codeBase && !isVaccinesCategory && codeNorm === VACCINES_CATEGORY_CODE;\n const formErrors = {\n name: validateRequired(form.name, 'Name'),\n code: codeBase\n || (codeReserved ? 'This code is reserved for the Vaccines category.' : '')\n || (codeClash ? 'Code is already in use — pick a different one.' : ''),\n };\n const formIsValid = isClean(formErrors);\n\n async function save() {\n if (!formIsValid) {\n fieldErrors.markAllTouched();\n setError('Please fix the highlighted fields.');\n return;\n }\n try {\n await upsertCategory({\n id: form.id,\n name: form.name.trim(),\n code: form.code.trim().toUpperCase(),\n description: form.description || null,\n icon: form.icon || null,\n isActive: form.isActive,\n });\n showToast({ message: 'Category saved.', type: 'success' });\n setOpenDialog(false);\n await load();\n } catch (err) {\n const message = err?.response?.data?.message ?? err?.message ?? 'Failed to save category';\n setError(message);\n showToast({ message, type: 'error' });\n }\n }\n\n const visible = showInactive ? items : items.filter((c) => c.isActive !== false);\n\n return (\n <Box>\n <PmNav />\n <PmGuard perm={'view.manage.productManagement.category'}>\n <PmPageShell\n title=\"Product Categories\"\n subtitle=\"Groups of products with similar handling requirements.\"\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={openCreate}>New Category</Button>\n ) : null}\n </Stack>\n }\n >\n {error ? <Alert severity=\"error\" sx={{ mb: 2 }}>{error}</Alert> : null}\n\n <PmTableCard\n eyebrow=\"Master data\"\n title=\"Product categories\"\n subtitle={loading ? 'Loading…' : `${visible.length} ${visible.length === 1 ? 'category' : 'categories'}`}\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 >\n <PmTable>\n <TableHead>\n <TableRow>\n <TableCell>Code</TableCell>\n <TableCell>Name</TableCell>\n <TableCell>Description</TableCell>\n <TableCell>Status</TableCell>\n <TableCell align=\"right\">Action</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {loading ? (\n Array.from({ length: 4 }).map((_, i) => (\n <TableRow key={i}>\n {Array.from({ length: 5 }).map((__, j) => (\n <TableCell key={j}><Skeleton height={22} /></TableCell>\n ))}\n </TableRow>\n ))\n ) : visible.length === 0 ? (\n <PmEmptyRow\n colSpan={5}\n icon={CategoryRoundedIcon}\n title={items.length === 0 ? 'No categories yet' : 'No active categories'}\n hint={items.length === 0\n ? 'Categories control how products are managed. For example, vaccines need special configuration.'\n : 'Turn on “Show inactive” to see deactivated categories.'}\n action={items.length === 0 && canWrite ? (\n <Button variant=\"contained\" size=\"small\" startIcon={<AddRoundedIcon />} onClick={openCreate}>\n Create first category\n </Button>\n ) : null}\n />\n ) : visible.map((c) => (\n <TableRow key={c.id} hover>\n <TableCell sx={{ maxWidth: 160 }}>\n <Box component=\"span\" sx={{\n display: 'inline-block', px: 0.85, py: 0.25, borderRadius: 1,\n bgcolor: 'grey.100', fontFamily: 'monospace', fontSize: '0.72rem', fontWeight: 800, letterSpacing: 0.4,\n maxWidth: '100%', wordBreak: 'break-all',\n }}>\n {c.code}\n </Box>\n </TableCell>\n <TableCell sx={{ maxWidth: 220 }}>\n <Stack direction=\"row\" spacing={1} alignItems=\"center\">\n {c.icon ? (\n <Box sx={{ color: 'primary.main', width: 18, textAlign: 'center', flexShrink: 0 }}>\n <FontAwesomeIcons iconName={c.icon} />\n </Box>\n ) : null}\n <Typography variant=\"body2\" sx={{ fontWeight: 700, wordBreak: 'break-word' }}>{c.name}</Typography>\n </Stack>\n </TableCell>\n <TableCell sx={{ maxWidth: 360 }}>\n {c.description\n ? <Typography variant=\"caption\" color=\"text.secondary\"\n sx={{ display: 'block', wordBreak: 'break-word' }}>\n {c.description}\n </Typography>\n : <Typography variant=\"caption\" color=\"text.disabled\">—</Typography>}\n </TableCell>\n <TableCell>\n <Chip\n size=\"small\"\n label={c.isActive ? 'Active' : 'Inactive'}\n color={c.isActive ? 'success' : 'default'}\n variant={c.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\" onClick={() => openEdit(c)}>Edit</Button>\n ) : null}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </PmTable>\n </PmTableCard>\n </PmPageShell>\n\n <Dialog open={openDialog} onClose={() => setOpenDialog(false)} fullWidth maxWidth=\"sm\">\n <DialogTitle>{editing ? 'Edit Category' : 'New Category'}</DialogTitle>\n <DialogContent dividers>\n <Stack spacing={2} sx={{ pt: 1 }}>\n <TextField\n required\n label=\"Name\" size=\"small\" fullWidth\n value={form.name}\n inputProps={{ maxLength: 255 }}\n onChange={(e) => setForm({ ...form, name: e.target.value })}\n onBlur={fieldErrors.onBlur('name')}\n error={fieldErrors.show('name') && !!formErrors.name}\n FormHelperTextProps={{ component: 'div' }}\n helperText={<PmFieldHelp message={fieldErrors.show('name') ? formErrors.name : ''} value={form.name} max={255} />}\n />\n <TextField\n required\n label=\"Code (uppercase, A-Z, 0-9, _)\"\n size=\"small\" fullWidth\n value={form.code}\n disabled={isVaccinesCategory}\n inputProps={{ maxLength: 100 }}\n onChange={(e) => setForm({ ...form, code: e.target.value.toUpperCase() })}\n onBlur={fieldErrors.onBlur('code')}\n error={fieldErrors.show('code') && !!formErrors.code}\n FormHelperTextProps={{ component: 'div' }}\n helperText={isVaccinesCategory\n ? 'This code is fixed. Vaccine products are found by it.'\n : <PmFieldHelp message={fieldErrors.show('code') ? formErrors.code : 'Must be unique.'} value={form.code} max={100} />}\n />\n <TextField label=\"Description (optional)\" size=\"small\" multiline minRows={2} fullWidth value={form.description}\n inputProps={{ maxLength: 500 }}\n onChange={(e) => setForm({ ...form, description: e.target.value })}\n FormHelperTextProps={{ component: 'div' }}\n helperText={<PmFieldHelp message=\"\" value={form.description} max={500} />} />\n <Autocomplete\n size=\"small\"\n options={CATEGORY_ICONS}\n value={form.icon || null}\n onChange={(_, next) => setForm({ ...form, icon: next ?? '' })}\n getOptionLabel={(opt) => iconLabel(opt)}\n renderOption={(props, opt) => (\n <Box component=\"li\" {...props} sx={{ display: 'flex', alignItems: 'center', gap: 1.25 }}>\n <Box sx={{ width: 20, textAlign: 'center', color: 'primary.main' }}>\n <FontAwesomeIcons iconName={opt} />\n </Box>\n <span>{iconLabel(opt)}</span>\n </Box>\n )}\n renderInput={(params) => (\n <TextField\n {...params}\n label=\"Icon (optional)\"\n placeholder=\"Search icons…\"\n helperText=\"Shown next to the category across the app.\"\n InputProps={{\n ...params.InputProps,\n startAdornment: form.icon ? (\n <InputAdornment position=\"start\">\n <Box sx={{ color: 'primary.main', display: 'flex' }}>\n <FontAwesomeIcons iconName={form.icon} />\n </Box>\n </InputAdornment>\n ) : null,\n }}\n />\n )}\n />\n <Box>\n <FormControlLabel\n control={<Checkbox checked={form.isActive}\n disabled={isVaccinesCategory}\n onChange={(e) => setForm({ ...form, isActive: e.target.checked })} />}\n label=\"Active\" />\n {isVaccinesCategory ? (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block' }}>\n The Vaccines category is always available.\n </Typography>\n ) : null}\n </Box>\n </Stack>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setOpenDialog(false)}>Cancel</Button>\n <Button variant=\"contained\" disabled={!formIsValid} onClick={() => void save()}>Save</Button>\n </DialogActions>\n </Dialog>\n </PmGuard>\n </Box>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { E as e, H as t, L as n, M as r, R as i, U as a, _ as o, g as s, i as c, r as l } from "./settingsStore-BHHOmcCP.js";
|
|
2
2
|
import { n as u, r as d } from "./format-UOyOu75i.js";
|
|
3
|
-
import { a as f, i as p, n as m, o as h, r as g, t as _ } from "./PmGuard-
|
|
3
|
+
import { a as f, i as p, n as m, o as h, r as g, t as _ } from "./PmGuard-BZE-y4In.js";
|
|
4
4
|
import { useState as v } from "react";
|
|
5
5
|
import { jsx as y, jsxs as b } from "react/jsx-runtime";
|
|
6
6
|
import x from "prop-types";
|
|
@@ -187,7 +187,7 @@ R.propTypes = {
|
|
|
187
187
|
onItemClick: x.func.isRequired
|
|
188
188
|
};
|
|
189
189
|
function z() {
|
|
190
|
-
let x = P(), L = N(), z = l(), B = p(), V =
|
|
190
|
+
let x = P(), L = N(), z = l(), B = p(), V = c(z?.currencyCode), H = h(B, z), U = B.has("view.manage.productManagement.ledger"), [W, G] = v(!0), [K, q] = v({
|
|
191
191
|
categories: 0,
|
|
192
192
|
brands: 0,
|
|
193
193
|
products: 0,
|
|
@@ -200,15 +200,15 @@ function z() {
|
|
|
200
200
|
async function J() {
|
|
201
201
|
G(!0);
|
|
202
202
|
try {
|
|
203
|
-
let
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
203
|
+
let c = (e, t) => B.has(e) ? t().catch(() => []) : Promise.resolve([]), [l, u, d, f, p, m, h, g] = await Promise.all([
|
|
204
|
+
c("view.manage.productManagement.category", () => o()),
|
|
205
|
+
c("view.manage.productManagement.brand", () => s()),
|
|
206
|
+
c("view.manage.productManagement.product", () => e()),
|
|
207
|
+
c("view.manage.productManagement.inventory", () => r()),
|
|
208
|
+
c("view.manage.productManagement.vial", () => n()),
|
|
209
|
+
c("view.manage.productManagement.sale", () => t(0, 100)),
|
|
210
|
+
c("view.manage.productManagement.payment", () => i(0, 100)),
|
|
211
|
+
c("view.manage.productManagement.ledger", () => a(0, 8))
|
|
212
212
|
]);
|
|
213
213
|
q({
|
|
214
214
|
categories: l.length,
|
|
@@ -433,4 +433,4 @@ function z() {
|
|
|
433
433
|
//#endregion
|
|
434
434
|
export { z as default };
|
|
435
435
|
|
|
436
|
-
//# sourceMappingURL=DashboardPage-
|
|
436
|
+
//# sourceMappingURL=DashboardPage-asr2XDRu.js.map
|