@argusoft/medplat-product-management 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/BrandsPage-DCMCVvDY.js +334 -0
  2. package/dist/BrandsPage-DCMCVvDY.js.map +1 -0
  3. package/dist/CategoriesPage-BpRhwfrc.js +284 -0
  4. package/dist/CategoriesPage-BpRhwfrc.js.map +1 -0
  5. package/dist/DashboardPage-BNKUQj46.js +436 -0
  6. package/dist/DashboardPage-BNKUQj46.js.map +1 -0
  7. package/dist/FacilityPicker-Coi8I3yE.js +79 -0
  8. package/dist/FacilityPicker-Coi8I3yE.js.map +1 -0
  9. package/dist/InventoryPage-BR6jOzg2.js +517 -0
  10. package/dist/InventoryPage-BR6jOzg2.js.map +1 -0
  11. package/dist/MemberProfileCard-DbHZCS5n.js +272 -0
  12. package/dist/MemberProfileCard-DbHZCS5n.js.map +1 -0
  13. package/dist/PaymentCreatePage-Ci3ERnby.js +487 -0
  14. package/dist/PaymentCreatePage-Ci3ERnby.js.map +1 -0
  15. package/dist/PaymentsPage-sdg902zX.js +157 -0
  16. package/dist/PaymentsPage-sdg902zX.js.map +1 -0
  17. package/dist/PickupCreatePage-CieMsgWV.js +310 -0
  18. package/dist/PickupCreatePage-CieMsgWV.js.map +1 -0
  19. package/dist/PickupsPage-Ci2Ll0Kn.js +566 -0
  20. package/dist/PickupsPage-Ci2Ll0Kn.js.map +1 -0
  21. package/dist/PmGuard-CjJBisaN.js +1195 -0
  22. package/dist/PmGuard-CjJBisaN.js.map +1 -0
  23. package/dist/PmTable-BuXZQZCU.js +302 -0
  24. package/dist/PmTable-BuXZQZCU.js.map +1 -0
  25. package/dist/ProductEditPage-DL8gy85Y.js +666 -0
  26. package/dist/ProductEditPage-DL8gy85Y.js.map +1 -0
  27. package/dist/ProductsPage-BANTKxLb.js +221 -0
  28. package/dist/ProductsPage-BANTKxLb.js.map +1 -0
  29. package/dist/PurchaseCreatePage-C3KMfBxJ.js +626 -0
  30. package/dist/PurchaseCreatePage-C3KMfBxJ.js.map +1 -0
  31. package/dist/PurchaseRequestDetailPage-C0GYFJDl.js +586 -0
  32. package/dist/PurchaseRequestDetailPage-C0GYFJDl.js.map +1 -0
  33. package/dist/PurchaseRequestsPage-DvFH_tWe.js +265 -0
  34. package/dist/PurchaseRequestsPage-DvFH_tWe.js.map +1 -0
  35. package/dist/PurchasesPage-BCvLvSp4.js +295 -0
  36. package/dist/PurchasesPage-BCvLvSp4.js.map +1 -0
  37. package/dist/SaleCreatePage-DpkQMoTq.js +548 -0
  38. package/dist/SaleCreatePage-DpkQMoTq.js.map +1 -0
  39. package/dist/SalesPage-DUwgkEO-.js +315 -0
  40. package/dist/SalesPage-DUwgkEO-.js.map +1 -0
  41. package/dist/SettingsPage-CusC0jqJ.js +710 -0
  42. package/dist/SettingsPage-CusC0jqJ.js.map +1 -0
  43. package/dist/StorageUnitsPage-BlC2AgrJ.js +469 -0
  44. package/dist/StorageUnitsPage-BlC2AgrJ.js.map +1 -0
  45. package/dist/TransactionsPage-DDaK4VyY.js +714 -0
  46. package/dist/TransactionsPage-DDaK4VyY.js.map +1 -0
  47. package/dist/TransferCreatePage-BxudLfhS.js +363 -0
  48. package/dist/TransferCreatePage-BxudLfhS.js.map +1 -0
  49. package/dist/TransfersPage-zgmt7teZ.js +480 -0
  50. package/dist/TransfersPage-zgmt7teZ.js.map +1 -0
  51. package/dist/VialsPage-CjqPfgpV.js +855 -0
  52. package/dist/VialsPage-CjqPfgpV.js.map +1 -0
  53. package/dist/constants-BrA_hfAI.js +254 -0
  54. package/dist/constants-BrA_hfAI.js.map +1 -0
  55. package/dist/currency-BDDCDgeE.js +169 -0
  56. package/dist/currency-BDDCDgeE.js.map +1 -0
  57. package/dist/format-UOyOu75i.js +52 -0
  58. package/dist/format-UOyOu75i.js.map +1 -0
  59. package/dist/index.js +45 -0
  60. package/dist/index.js.map +1 -0
  61. package/dist/useFieldErrors-hDG8ox_x.js +29 -0
  62. package/dist/useFieldErrors-hDG8ox_x.js.map +1 -0
  63. package/dist/validation-Ba7puFIO.js +109 -0
  64. package/dist/validation-Ba7puFIO.js.map +1 -0
  65. package/package.json +36 -0
@@ -0,0 +1,334 @@
1
+ import { a as e, at as t, c as n, d as r, i, n as a, r as o, t as s, u as c, x as ee } from "./PmGuard-CjJBisaN.js";
2
+ import { a as te, o as ne, t as re } from "./PmTable-BuXZQZCU.js";
3
+ import { i as ie, m as l, t as u } from "./validation-Ba7puFIO.js";
4
+ import { t as d } from "./useFieldErrors-hDG8ox_x.js";
5
+ import { useState as f } from "react";
6
+ import { jsx as p, jsxs as m } from "react/jsx-runtime";
7
+ import { v4 as h } from "uuid";
8
+ import { Alert as g, Box as _, Button as v, Chip as y, Dialog as b, DialogActions as ae, DialogContent as oe, DialogTitle as se, InputAdornment as ce, Skeleton as le, Stack as x, TableBody as ue, TableCell as S, TableHead as de, TableRow as C, TextField as w, Typography as T } from "@mui/material";
9
+ import E from "@mui/icons-material/AddRounded";
10
+ import D from "@mui/icons-material/RefreshRounded";
11
+ import O from "@mui/icons-material/SellRounded";
12
+ import { showToast as k } from "@/common/toaster/toaster";
13
+ //#region src/views/BrandsPage.jsx
14
+ function A(e) {
15
+ if (!e) return {
16
+ phone: "",
17
+ email: ""
18
+ };
19
+ try {
20
+ let t = JSON.parse(e);
21
+ return {
22
+ phone: typeof t?.phone == "string" ? t.phone : "",
23
+ email: typeof t?.email == "string" ? t.email : ""
24
+ };
25
+ } catch {
26
+ return {
27
+ phone: "",
28
+ email: ""
29
+ };
30
+ }
31
+ }
32
+ function j({ phone: e, email: t }) {
33
+ let n = {};
34
+ return e?.trim() && (n.phone = e.trim()), t?.trim() && (n.email = t.trim()), Object.keys(n).length ? JSON.stringify(n) : null;
35
+ }
36
+ function M() {
37
+ let M = i().has("update.manage.productManagement.brand"), N = c(n()?.countryCode), [P, F] = f([]), [I, L] = f(!1), [R, z] = f(""), [B, V] = f(!1), [H, U] = f(null), [W, G] = f(q()), K = d();
38
+ function q() {
39
+ return {
40
+ id: "",
41
+ name: "",
42
+ manufacturerCode: "",
43
+ contactPhone: "",
44
+ contactEmail: "",
45
+ isActive: !0
46
+ };
47
+ }
48
+ async function J() {
49
+ L(!0), z("");
50
+ try {
51
+ F(await ee());
52
+ } catch (e) {
53
+ let t = e?.response?.data?.message ?? e?.message ?? "Failed to load brands";
54
+ z(t), k({
55
+ message: t,
56
+ type: "error"
57
+ });
58
+ } finally {
59
+ L(!1);
60
+ }
61
+ }
62
+ o("view.manage.productManagement.brand", () => {
63
+ J();
64
+ }, []);
65
+ function Y() {
66
+ U(null), G({
67
+ ...q(),
68
+ id: h()
69
+ }), K.reset(), z(""), V(!0);
70
+ }
71
+ function fe(e) {
72
+ let { phone: t, email: n } = A(e.contactInfo);
73
+ U(e), K.reset(), z(""), G({
74
+ id: e.id,
75
+ name: e.name ?? "",
76
+ manufacturerCode: e.manufacturerCode ?? "",
77
+ contactPhone: t,
78
+ contactEmail: n,
79
+ isActive: e.isActive !== !1
80
+ }), V(!0);
81
+ }
82
+ let X = l(W.manufacturerCode, "Manufacturer code"), Z = W.manufacturerCode.trim().toUpperCase(), pe = !X && Z && P.some((e) => e.id !== W.id && (e.manufacturerCode || "").toUpperCase() === Z), Q = {
83
+ name: l(W.name, "Name"),
84
+ manufacturerCode: X || (pe ? "Code is already in use — edit it manually to make it unique." : ""),
85
+ contactPhone: r(W.contactPhone, N),
86
+ contactEmail: ie(W.contactEmail)
87
+ }, $ = u(Q);
88
+ async function me() {
89
+ if (!$) {
90
+ K.markAllTouched(), z("Please fix the highlighted fields.");
91
+ return;
92
+ }
93
+ try {
94
+ await t({
95
+ id: W.id,
96
+ name: W.name.trim(),
97
+ manufacturerCode: W.manufacturerCode.trim().toUpperCase(),
98
+ contactInfo: j({
99
+ phone: W.contactPhone,
100
+ email: W.contactEmail
101
+ }),
102
+ isActive: W.isActive
103
+ }), k({
104
+ message: "Brand saved.",
105
+ type: "success"
106
+ }), V(!1), await J();
107
+ } catch (e) {
108
+ let t = e?.response?.data?.message ?? e?.message ?? "Failed to save brand";
109
+ z(t), k({
110
+ message: t,
111
+ type: "error"
112
+ });
113
+ }
114
+ }
115
+ return /* @__PURE__ */ m(_, { children: [/* @__PURE__ */ p(a, {}), /* @__PURE__ */ m(s, {
116
+ perm: "view.manage.productManagement.brand",
117
+ children: [/* @__PURE__ */ m(e, {
118
+ title: "Brands",
119
+ subtitle: "The manufacturer or supplier of each product.",
120
+ chips: ["Catalog"],
121
+ actions: /* @__PURE__ */ m(x, {
122
+ direction: "row",
123
+ spacing: 1,
124
+ children: [/* @__PURE__ */ p(v, {
125
+ variant: "outlined",
126
+ startIcon: /* @__PURE__ */ p(D, {}),
127
+ onClick: () => void J(),
128
+ children: "Refresh"
129
+ }), M ? /* @__PURE__ */ p(v, {
130
+ variant: "contained",
131
+ startIcon: /* @__PURE__ */ p(E, {}),
132
+ onClick: Y,
133
+ children: "New Brand"
134
+ }) : null]
135
+ }),
136
+ children: [R ? /* @__PURE__ */ p(g, {
137
+ severity: "error",
138
+ sx: { mb: 2 },
139
+ children: R
140
+ }) : null, /* @__PURE__ */ p(ne, {
141
+ eyebrow: "Master data",
142
+ title: "Brands",
143
+ subtitle: I ? "Loading…" : `${P.length} ${P.length === 1 ? "brand" : "brands"}`,
144
+ children: /* @__PURE__ */ m(te, { children: [/* @__PURE__ */ p(de, { children: /* @__PURE__ */ m(C, { children: [
145
+ /* @__PURE__ */ p(S, { children: "Name" }),
146
+ /* @__PURE__ */ p(S, { children: "Manufacturer Code" }),
147
+ /* @__PURE__ */ p(S, { children: "Contact" }),
148
+ /* @__PURE__ */ p(S, { children: "Status" }),
149
+ /* @__PURE__ */ p(S, {
150
+ align: "right",
151
+ children: "Action"
152
+ })
153
+ ] }) }), /* @__PURE__ */ p(ue, { children: I ? Array.from({ length: 4 }).map((e, t) => /* @__PURE__ */ p(C, { children: Array.from({ length: 5 }).map((e, t) => /* @__PURE__ */ p(S, { children: /* @__PURE__ */ p(le, { height: 22 }) }, t)) }, t)) : P.length === 0 ? /* @__PURE__ */ p(re, {
154
+ colSpan: 5,
155
+ icon: O,
156
+ title: "No brands yet",
157
+ hint: "Add manufacturers so you can link them to your products.",
158
+ action: M ? /* @__PURE__ */ p(v, {
159
+ variant: "contained",
160
+ size: "small",
161
+ startIcon: /* @__PURE__ */ p(E, {}),
162
+ onClick: Y,
163
+ children: "Create first brand"
164
+ }) : null
165
+ }) : P.map((e) => {
166
+ let { phone: t, email: n } = A(e.contactInfo);
167
+ return /* @__PURE__ */ m(C, {
168
+ hover: !0,
169
+ children: [
170
+ /* @__PURE__ */ p(S, { children: /* @__PURE__ */ p(T, {
171
+ variant: "body2",
172
+ sx: { fontWeight: 700 },
173
+ children: e.name
174
+ }) }),
175
+ /* @__PURE__ */ p(S, { children: /* @__PURE__ */ p(_, {
176
+ component: "span",
177
+ sx: {
178
+ display: "inline-flex",
179
+ px: .85,
180
+ py: .25,
181
+ borderRadius: 1,
182
+ bgcolor: "grey.100",
183
+ fontFamily: "monospace",
184
+ fontSize: "0.72rem",
185
+ fontWeight: 800
186
+ },
187
+ children: e.manufacturerCode
188
+ }) }),
189
+ /* @__PURE__ */ p(S, { children: t || n ? /* @__PURE__ */ m(x, {
190
+ spacing: .25,
191
+ children: [t ? /* @__PURE__ */ p(T, {
192
+ variant: "caption",
193
+ sx: { fontWeight: 600 },
194
+ children: t
195
+ }) : null, n ? /* @__PURE__ */ p(T, {
196
+ variant: "caption",
197
+ color: "text.secondary",
198
+ children: n
199
+ }) : null]
200
+ }) : /* @__PURE__ */ p(T, {
201
+ variant: "caption",
202
+ color: "text.disabled",
203
+ children: "—"
204
+ }) }),
205
+ /* @__PURE__ */ p(S, { children: /* @__PURE__ */ p(y, {
206
+ size: "small",
207
+ label: e.isActive ? "Active" : "Inactive",
208
+ color: e.isActive ? "success" : "default",
209
+ variant: e.isActive ? "filled" : "outlined",
210
+ sx: {
211
+ fontWeight: 700,
212
+ borderRadius: 1.5,
213
+ height: 22
214
+ }
215
+ }) }),
216
+ /* @__PURE__ */ p(S, {
217
+ align: "right",
218
+ children: M ? /* @__PURE__ */ p(v, {
219
+ size: "small",
220
+ variant: "outlined",
221
+ onClick: () => fe(e),
222
+ children: "Edit"
223
+ }) : null
224
+ })
225
+ ]
226
+ }, e.id);
227
+ }) })] })
228
+ })]
229
+ }), /* @__PURE__ */ m(b, {
230
+ open: B,
231
+ onClose: () => V(!1),
232
+ fullWidth: !0,
233
+ maxWidth: "sm",
234
+ children: [
235
+ /* @__PURE__ */ p(se, { children: H ? "Edit Brand" : "New Brand" }),
236
+ /* @__PURE__ */ p(oe, {
237
+ dividers: !0,
238
+ children: /* @__PURE__ */ m(x, {
239
+ spacing: 2,
240
+ sx: { pt: 1 },
241
+ children: [
242
+ /* @__PURE__ */ p(w, {
243
+ required: !0,
244
+ label: "Name",
245
+ size: "small",
246
+ fullWidth: !0,
247
+ value: W.name,
248
+ onChange: (e) => {
249
+ let t = e.target.value, n = t.split(/\s+/).filter(Boolean).map((e) => e[0]).join("").toUpperCase();
250
+ G((e) => ({
251
+ ...e,
252
+ name: t,
253
+ manufacturerCode: H ? e.manufacturerCode : n
254
+ }));
255
+ },
256
+ onBlur: K.onBlur("name"),
257
+ error: K.show("name") && !!Q.name,
258
+ helperText: K.show("name") ? Q.name : ""
259
+ }),
260
+ /* @__PURE__ */ p(w, {
261
+ required: !0,
262
+ label: "Manufacturer code",
263
+ size: "small",
264
+ fullWidth: !0,
265
+ value: W.manufacturerCode,
266
+ onChange: (e) => G({
267
+ ...W,
268
+ manufacturerCode: e.target.value.toUpperCase()
269
+ }),
270
+ onBlur: K.onBlur("manufacturerCode"),
271
+ error: K.show("manufacturerCode") && !!Q.manufacturerCode,
272
+ helperText: K.show("manufacturerCode") && Q.manufacturerCode ? Q.manufacturerCode : "Auto-generated from the name as initials. Edit if needed to make it unique."
273
+ }),
274
+ /* @__PURE__ */ p(w, {
275
+ label: "Contact Number",
276
+ size: "small",
277
+ fullWidth: !0,
278
+ type: "tel",
279
+ placeholder: N ? N.phoneMin === N.phoneMax ? `${N.phoneMin}-digit local number` : `${N.phoneMin}–${N.phoneMax} digit local number` : "Local number",
280
+ value: W.contactPhone,
281
+ onChange: (e) => G({
282
+ ...W,
283
+ contactPhone: e.target.value.replace(/[^\d\s]/g, "")
284
+ }),
285
+ onBlur: K.onBlur("contactPhone"),
286
+ error: K.show("contactPhone") && !!Q.contactPhone,
287
+ helperText: K.show("contactPhone") && Q.contactPhone ? Q.contactPhone : N ? `Format for ${N.name}: ${N.phoneCode} followed by ${N.phoneMin}${N.phoneMin === N.phoneMax ? "" : `–${N.phoneMax}`} digits.` : "Local number, digits only.",
288
+ InputProps: N ? { startAdornment: /* @__PURE__ */ p(ce, {
289
+ position: "start",
290
+ children: /* @__PURE__ */ p(_, {
291
+ component: "span",
292
+ sx: {
293
+ fontWeight: 700,
294
+ color: "text.secondary"
295
+ },
296
+ children: N.phoneCode
297
+ })
298
+ }) } : void 0
299
+ }),
300
+ /* @__PURE__ */ p(w, {
301
+ label: "Email",
302
+ size: "small",
303
+ fullWidth: !0,
304
+ type: "email",
305
+ placeholder: "e.g. contact@manufacturer.example",
306
+ value: W.contactEmail,
307
+ onChange: (e) => G({
308
+ ...W,
309
+ contactEmail: e.target.value
310
+ }),
311
+ onBlur: K.onBlur("contactEmail"),
312
+ error: K.show("contactEmail") && !!Q.contactEmail,
313
+ helperText: K.show("contactEmail") ? Q.contactEmail : ""
314
+ })
315
+ ]
316
+ })
317
+ }),
318
+ /* @__PURE__ */ m(ae, { children: [/* @__PURE__ */ p(v, {
319
+ onClick: () => V(!1),
320
+ children: "Cancel"
321
+ }), /* @__PURE__ */ p(v, {
322
+ variant: "contained",
323
+ disabled: !$,
324
+ onClick: () => void me(),
325
+ children: "Save"
326
+ })] })
327
+ ]
328
+ })]
329
+ })] });
330
+ }
331
+ //#endregion
332
+ export { M as default };
333
+
334
+ //# sourceMappingURL=BrandsPage-DCMCVvDY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BrandsPage-DCMCVvDY.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 Chip,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\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 '@/common/toaster/toaster';\nimport PmPageShell from '@pm/components/PmPageShell';\nimport PmNav from '@pm/components/PmNav';\nimport PmGuard from '@pm/components/PmGuard';\nimport { usePermissionedEffect, usePmPermissions } from '@pm/utils/permissions';\nimport { PmEmptyRow, 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 '@pm/utils/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 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();\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 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…' : `${items.length} ${items.length === 1 ? 'brand' : 'brands'}`}\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 ) : items.length === 0 ? (\n <PmEmptyRow\n colSpan={5}\n icon={SellRoundedIcon}\n title=\"No brands yet\"\n hint=\"Add manufacturers so you can link them to your products.\"\n action={canWrite ? (\n <Button variant=\"contained\" size=\"small\" startIcon={<AddRoundedIcon />} onClick={openCreate}>\n Create first brand\n </Button>\n ) : null}\n />\n ) : items.map((b) => {\n const { phone, email } = parseContactInfo(b.contactInfo);\n return (\n <TableRow key={b.id} hover>\n <TableCell><Typography variant=\"body2\" sx={{ fontWeight: 700 }}>{b.name}</Typography></TableCell>\n <TableCell>\n <Box component=\"span\" sx={{\n display: 'inline-flex', px: 0.85, py: 0.25, borderRadius: 1,\n bgcolor: 'grey.100', fontFamily: 'monospace', fontSize: '0.72rem', fontWeight: 800,\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 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 helperText={fieldErrors.show('name') ? formErrors.name : ''}\n />\n <TextField\n required\n label=\"Manufacturer code\" size=\"small\" fullWidth\n value={form.manufacturerCode}\n onChange={(e) => setForm({ ...form, manufacturerCode: e.target.value.toUpperCase() })}\n onBlur={fieldErrors.onBlur('manufacturerCode')}\n error={fieldErrors.show('manufacturerCode') && !!formErrors.manufacturerCode}\n helperText={\n fieldErrors.show('manufacturerCode') && formErrors.manufacturerCode\n ? formErrors.manufacturerCode\n : 'Auto-generated from the name as initials. Edit if needed to make it unique.'\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 </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,284 @@
1
+ import { S as e, a as t, i as n, n as r, ot as i, r as a, t as o } from "./PmGuard-CjJBisaN.js";
2
+ import { a as s, o as c, t as ee } from "./PmTable-BuXZQZCU.js";
3
+ import { m as te, n as l, t as u } from "./validation-Ba7puFIO.js";
4
+ import { t as d } from "./useFieldErrors-hDG8ox_x.js";
5
+ import { useState as f } from "react";
6
+ import { jsx as p, jsxs as m } from "react/jsx-runtime";
7
+ import { v4 as ne } from "uuid";
8
+ import { Alert as h, Box as g, Button as _, Chip as re, Dialog as v, DialogActions as y, DialogContent as b, DialogTitle as x, Skeleton as S, Stack as C, TableBody as w, TableCell as T, TableHead as ie, TableRow as E, TextField as D, Typography as O } from "@mui/material";
9
+ import k from "@mui/icons-material/AddRounded";
10
+ import A from "@mui/icons-material/RefreshRounded";
11
+ import { showToast as j } from "@/common/toaster/toaster";
12
+ import M from "@mui/icons-material/CategoryRounded";
13
+ //#region src/views/CategoriesPage.jsx
14
+ function N() {
15
+ let N = n().has("update.manage.productManagement.category"), [P, F] = f([]), [I, L] = f(!1), [R, z] = f(""), [B, V] = f(!1), [H, U] = f(null), [W, G] = f(q()), K = d();
16
+ function q() {
17
+ return {
18
+ id: "",
19
+ name: "",
20
+ code: "",
21
+ description: "",
22
+ icon: "",
23
+ isActive: !0
24
+ };
25
+ }
26
+ async function J() {
27
+ L(!0), z("");
28
+ try {
29
+ F(await e());
30
+ } catch (e) {
31
+ let t = e?.response?.data?.message ?? e?.message ?? "Failed to load categories";
32
+ z(t), j({
33
+ message: t,
34
+ type: "error"
35
+ });
36
+ } finally {
37
+ L(!1);
38
+ }
39
+ }
40
+ a("view.manage.productManagement.category", () => {
41
+ J();
42
+ }, []);
43
+ function Y() {
44
+ U(null), G({
45
+ ...q(),
46
+ id: ne()
47
+ }), K.reset(), z(""), V(!0);
48
+ }
49
+ function ae(e) {
50
+ U(e), K.reset(), z(""), G({
51
+ id: e.id,
52
+ name: e.name ?? "",
53
+ code: e.code ?? "",
54
+ description: e.description ?? "",
55
+ icon: e.icon ?? "",
56
+ isActive: e.isActive !== !1
57
+ }), V(!0);
58
+ }
59
+ let X = l(W.code, { required: !0 }), Z = W.code.trim().toUpperCase(), oe = !X && Z && P.some((e) => e.id !== W.id && (e.code || "").toUpperCase() === Z), Q = {
60
+ name: te(W.name, "Name"),
61
+ code: X || (oe ? "Code is already in use — pick a different one." : "")
62
+ }, $ = u(Q);
63
+ async function se() {
64
+ if (!$) {
65
+ K.markAllTouched(), z("Please fix the highlighted fields.");
66
+ return;
67
+ }
68
+ try {
69
+ await i({
70
+ id: W.id,
71
+ name: W.name.trim(),
72
+ code: W.code.trim().toUpperCase(),
73
+ description: W.description || null,
74
+ icon: W.icon || null,
75
+ isActive: W.isActive
76
+ }), j({
77
+ message: "Category saved.",
78
+ type: "success"
79
+ }), V(!1), await J();
80
+ } catch (e) {
81
+ let t = e?.response?.data?.message ?? e?.message ?? "Failed to save category";
82
+ z(t), j({
83
+ message: t,
84
+ type: "error"
85
+ });
86
+ }
87
+ }
88
+ return /* @__PURE__ */ m(g, { children: [/* @__PURE__ */ p(r, {}), /* @__PURE__ */ m(o, {
89
+ perm: "view.manage.productManagement.category",
90
+ children: [/* @__PURE__ */ m(t, {
91
+ title: "Product Categories",
92
+ subtitle: "Groups of products with similar handling requirements.",
93
+ chips: ["Catalog"],
94
+ actions: /* @__PURE__ */ m(C, {
95
+ direction: "row",
96
+ spacing: 1,
97
+ children: [/* @__PURE__ */ p(_, {
98
+ variant: "outlined",
99
+ startIcon: /* @__PURE__ */ p(A, {}),
100
+ onClick: () => void J(),
101
+ children: "Refresh"
102
+ }), N ? /* @__PURE__ */ p(_, {
103
+ variant: "contained",
104
+ startIcon: /* @__PURE__ */ p(k, {}),
105
+ onClick: Y,
106
+ children: "New Category"
107
+ }) : null]
108
+ }),
109
+ children: [R ? /* @__PURE__ */ p(h, {
110
+ severity: "error",
111
+ sx: { mb: 2 },
112
+ children: R
113
+ }) : null, /* @__PURE__ */ p(c, {
114
+ eyebrow: "Master data",
115
+ title: "Product categories",
116
+ subtitle: I ? "Loading…" : `${P.length} ${P.length === 1 ? "category" : "categories"}`,
117
+ children: /* @__PURE__ */ m(s, { children: [/* @__PURE__ */ p(ie, { children: /* @__PURE__ */ m(E, { children: [
118
+ /* @__PURE__ */ p(T, { children: "Code" }),
119
+ /* @__PURE__ */ p(T, { children: "Name" }),
120
+ /* @__PURE__ */ p(T, { children: "Description" }),
121
+ /* @__PURE__ */ p(T, { children: "Status" }),
122
+ /* @__PURE__ */ p(T, {
123
+ align: "right",
124
+ children: "Action"
125
+ })
126
+ ] }) }), /* @__PURE__ */ p(w, { children: I ? Array.from({ length: 4 }).map((e, t) => /* @__PURE__ */ p(E, { children: Array.from({ length: 5 }).map((e, t) => /* @__PURE__ */ p(T, { children: /* @__PURE__ */ p(S, { height: 22 }) }, t)) }, t)) : P.length === 0 ? /* @__PURE__ */ p(ee, {
127
+ colSpan: 5,
128
+ icon: M,
129
+ title: "No categories yet",
130
+ hint: "Categories control how products are managed. For example, vaccines need special configuration.",
131
+ action: N ? /* @__PURE__ */ p(_, {
132
+ variant: "contained",
133
+ size: "small",
134
+ startIcon: /* @__PURE__ */ p(k, {}),
135
+ onClick: Y,
136
+ children: "Create first category"
137
+ }) : null
138
+ }) : P.map((e) => /* @__PURE__ */ m(E, {
139
+ hover: !0,
140
+ children: [
141
+ /* @__PURE__ */ p(T, { children: /* @__PURE__ */ p(g, {
142
+ component: "span",
143
+ sx: {
144
+ display: "inline-flex",
145
+ px: .85,
146
+ py: .25,
147
+ borderRadius: 1,
148
+ bgcolor: "grey.100",
149
+ fontFamily: "monospace",
150
+ fontSize: "0.72rem",
151
+ fontWeight: 800,
152
+ letterSpacing: .4
153
+ },
154
+ children: e.code
155
+ }) }),
156
+ /* @__PURE__ */ p(T, { children: /* @__PURE__ */ p(O, {
157
+ variant: "body2",
158
+ sx: { fontWeight: 700 },
159
+ children: e.name
160
+ }) }),
161
+ /* @__PURE__ */ p(T, {
162
+ sx: { maxWidth: 360 },
163
+ children: e.description ? /* @__PURE__ */ p(O, {
164
+ variant: "caption",
165
+ color: "text.secondary",
166
+ sx: {
167
+ display: "block",
168
+ overflow: "hidden",
169
+ textOverflow: "ellipsis",
170
+ whiteSpace: "nowrap"
171
+ },
172
+ children: e.description
173
+ }) : /* @__PURE__ */ p(O, {
174
+ variant: "caption",
175
+ color: "text.disabled",
176
+ children: "—"
177
+ })
178
+ }),
179
+ /* @__PURE__ */ p(T, { children: /* @__PURE__ */ p(re, {
180
+ size: "small",
181
+ label: e.isActive ? "Active" : "Inactive",
182
+ color: e.isActive ? "success" : "default",
183
+ variant: e.isActive ? "filled" : "outlined",
184
+ sx: {
185
+ fontWeight: 700,
186
+ borderRadius: 1.5,
187
+ height: 22
188
+ }
189
+ }) }),
190
+ /* @__PURE__ */ p(T, {
191
+ align: "right",
192
+ children: N ? /* @__PURE__ */ p(_, {
193
+ size: "small",
194
+ variant: "outlined",
195
+ onClick: () => ae(e),
196
+ children: "Edit"
197
+ }) : null
198
+ })
199
+ ]
200
+ }, e.id)) })] })
201
+ })]
202
+ }), /* @__PURE__ */ m(v, {
203
+ open: B,
204
+ onClose: () => V(!1),
205
+ fullWidth: !0,
206
+ maxWidth: "sm",
207
+ children: [
208
+ /* @__PURE__ */ p(x, { children: H ? "Edit Category" : "New Category" }),
209
+ /* @__PURE__ */ p(b, {
210
+ dividers: !0,
211
+ children: /* @__PURE__ */ m(C, {
212
+ spacing: 2,
213
+ sx: { pt: 1 },
214
+ children: [
215
+ /* @__PURE__ */ p(D, {
216
+ required: !0,
217
+ label: "Name",
218
+ size: "small",
219
+ fullWidth: !0,
220
+ value: W.name,
221
+ onChange: (e) => G({
222
+ ...W,
223
+ name: e.target.value
224
+ }),
225
+ onBlur: K.onBlur("name"),
226
+ error: K.show("name") && !!Q.name,
227
+ helperText: K.show("name") ? Q.name : ""
228
+ }),
229
+ /* @__PURE__ */ p(D, {
230
+ required: !0,
231
+ label: "Code (uppercase, A-Z, 0-9, _)",
232
+ size: "small",
233
+ fullWidth: !0,
234
+ value: W.code,
235
+ onChange: (e) => G({
236
+ ...W,
237
+ code: e.target.value.toUpperCase()
238
+ }),
239
+ onBlur: K.onBlur("code"),
240
+ error: K.show("code") && !!Q.code,
241
+ helperText: K.show("code") ? Q.code : "Must be unique."
242
+ }),
243
+ /* @__PURE__ */ p(D, {
244
+ label: "Description",
245
+ size: "small",
246
+ multiline: !0,
247
+ minRows: 2,
248
+ fullWidth: !0,
249
+ value: W.description,
250
+ onChange: (e) => G({
251
+ ...W,
252
+ description: e.target.value
253
+ })
254
+ }),
255
+ /* @__PURE__ */ p(D, {
256
+ label: "Icon (optional)",
257
+ size: "small",
258
+ fullWidth: !0,
259
+ value: W.icon,
260
+ onChange: (e) => G({
261
+ ...W,
262
+ icon: e.target.value
263
+ })
264
+ })
265
+ ]
266
+ })
267
+ }),
268
+ /* @__PURE__ */ m(y, { children: [/* @__PURE__ */ p(_, {
269
+ onClick: () => V(!1),
270
+ children: "Cancel"
271
+ }), /* @__PURE__ */ p(_, {
272
+ variant: "contained",
273
+ disabled: !$,
274
+ onClick: () => void se(),
275
+ children: "Save"
276
+ })] })
277
+ ]
278
+ })]
279
+ })] });
280
+ }
281
+ //#endregion
282
+ export { N as default };
283
+
284
+ //# sourceMappingURL=CategoriesPage-BpRhwfrc.js.map