@argusoft/medplat-product-management 1.0.10 → 1.0.11

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 (117) hide show
  1. package/dist/BrandsPage-DBFBor6L.js +384 -0
  2. package/dist/{BrandsPage-CdcAvaml.js.map → BrandsPage-DBFBor6L.js.map} +1 -1
  3. package/dist/CategoriesPage-DbR56Dxb.js +396 -0
  4. package/dist/{CategoriesPage-BprQEYJw.js.map → CategoriesPage-DbR56Dxb.js.map} +1 -1
  5. package/dist/DashboardPage-Dw_xutHp.js +435 -0
  6. package/dist/DashboardPage-Dw_xutHp.js.map +1 -0
  7. package/dist/FacilityPicker-DoN5Uorg.js +132 -0
  8. package/dist/FacilityPicker-DoN5Uorg.js.map +1 -0
  9. package/dist/InventoryPage-BETRRdVj.js +1004 -0
  10. package/dist/{InventoryPage-JadYMCzU.js.map → InventoryPage-BETRRdVj.js.map} +1 -1
  11. package/dist/LocationPicker-DNg0iSZm.js +321 -0
  12. package/dist/LocationPicker-DNg0iSZm.js.map +1 -0
  13. package/dist/PaymentCreatePage--WFg0fgT.js +513 -0
  14. package/dist/PaymentCreatePage--WFg0fgT.js.map +1 -0
  15. package/dist/PaymentsPage-CYSXziah.js +168 -0
  16. package/dist/PaymentsPage-CYSXziah.js.map +1 -0
  17. package/dist/PickupBatchLinesEditor-CR_5BIOa.js +114 -0
  18. package/dist/{PickupBatchLinesEditor-QPaqFtUO.js.map → PickupBatchLinesEditor-CR_5BIOa.js.map} +1 -1
  19. package/dist/{PickupCreatePage-C7_67u_u.js → PickupCreatePage-BNK2p8Wj.js} +187 -189
  20. package/dist/PickupCreatePage-BNK2p8Wj.js.map +1 -0
  21. package/dist/PickupsPage-cIBMy6kz.js +810 -0
  22. package/dist/{PickupsPage-BWblMlic.js.map → PickupsPage-cIBMy6kz.js.map} +1 -1
  23. package/dist/PmDocumentDownload-B1zLnOPX.js +46 -0
  24. package/dist/PmDocumentDownload-B1zLnOPX.js.map +1 -0
  25. package/dist/PmGuard-DzOloo0T.js +624 -0
  26. package/dist/{PmGuard-BvUUbU80.js.map → PmGuard-DzOloo0T.js.map} +1 -1
  27. package/dist/PmTable-nWK5C3ew.js +542 -0
  28. package/dist/{PmTable-COZEuDAr.js.map → PmTable-nWK5C3ew.js.map} +1 -1
  29. package/dist/ProductEditPage-mCCCmDyz.js +1512 -0
  30. package/dist/{ProductEditPage-Dbq4vUAA.js.map → ProductEditPage-mCCCmDyz.js.map} +1 -1
  31. package/dist/ProductsPage-Cr-Ay4tP.js +303 -0
  32. package/dist/ProductsPage-Cr-Ay4tP.js.map +1 -0
  33. package/dist/PurchaseCreatePage-djceX_Mi.js +723 -0
  34. package/dist/PurchaseCreatePage-djceX_Mi.js.map +1 -0
  35. package/dist/{PurchaseRequestDetailPage-DhBuOGHZ.js → PurchaseRequestDetailPage-Cc3vdQ33.js} +504 -506
  36. package/dist/{PurchaseRequestDetailPage-DhBuOGHZ.js.map → PurchaseRequestDetailPage-Cc3vdQ33.js.map} +1 -1
  37. package/dist/PurchaseRequestsPage-dQDeAWYz.js +278 -0
  38. package/dist/{PurchaseRequestsPage-Bj9HUMxb.js.map → PurchaseRequestsPage-dQDeAWYz.js.map} +1 -1
  39. package/dist/PurchasesPage-DpMPd8JH.js +305 -0
  40. package/dist/PurchasesPage-DpMPd8JH.js.map +1 -0
  41. package/dist/SaleCreatePage-DDedCbwe.js +575 -0
  42. package/dist/SaleCreatePage-DDedCbwe.js.map +1 -0
  43. package/dist/SalesPage-CelCu5Tw.js +325 -0
  44. package/dist/SalesPage-CelCu5Tw.js.map +1 -0
  45. package/dist/SettingsPage-BEyiYNFC.js +1163 -0
  46. package/dist/SettingsPage-BEyiYNFC.js.map +1 -0
  47. package/dist/StorageUnitsPage-CqlGFV83.js +987 -0
  48. package/dist/StorageUnitsPage-CqlGFV83.js.map +1 -0
  49. package/dist/TransactionsPage-CdidHnRk.js +763 -0
  50. package/dist/TransactionsPage-CdidHnRk.js.map +1 -0
  51. package/dist/TransferCreatePage-C84ze-RN.js +638 -0
  52. package/dist/TransferCreatePage-C84ze-RN.js.map +1 -0
  53. package/dist/TransfersPage-Pvjid97y.js +591 -0
  54. package/dist/{TransfersPage-DqaSvHda.js.map → TransfersPage-Pvjid97y.js.map} +1 -1
  55. package/dist/VialsPage-VjNQ4SGI.js +452 -0
  56. package/dist/{VialsPage-LoDaUqVv.js.map → VialsPage-VjNQ4SGI.js.map} +1 -1
  57. package/dist/{constants-BTpJFQe_.js → constants-Dvu1Zd5X.js} +67 -69
  58. package/dist/{constants-BTpJFQe_.js.map → constants-Dvu1Zd5X.js.map} +1 -1
  59. package/dist/format-qqBoZCqP.js +50 -0
  60. package/dist/{format-UOyOu75i.js.map → format-qqBoZCqP.js.map} +1 -1
  61. package/dist/index.js +362 -368
  62. package/dist/index.js.map +1 -1
  63. package/dist/listValueStore-BW6BS4BN.js +41 -0
  64. package/dist/{listValueStore-5d4vNGQM.js.map → listValueStore-BW6BS4BN.js.map} +1 -1
  65. package/dist/settingsStore-C1aUfwS9.js +558 -0
  66. package/dist/settingsStore-C1aUfwS9.js.map +1 -0
  67. package/dist/useFieldErrors-Dh04ptYj.js +27 -0
  68. package/dist/{useFieldErrors-hDG8ox_x.js.map → useFieldErrors-Dh04ptYj.js.map} +1 -1
  69. package/dist/validation-CKx4Zzpx.js +108 -0
  70. package/dist/{validation-BzlHnL-r.js.map → validation-CKx4Zzpx.js.map} +1 -1
  71. package/package.json +11 -5
  72. package/dist/BrandsPage-CdcAvaml.js +0 -386
  73. package/dist/CategoriesPage-BprQEYJw.js +0 -398
  74. package/dist/DashboardPage-CTiGSx71.js +0 -436
  75. package/dist/DashboardPage-CTiGSx71.js.map +0 -1
  76. package/dist/FacilityPicker-BXa2VF7i.js +0 -112
  77. package/dist/FacilityPicker-BXa2VF7i.js.map +0 -1
  78. package/dist/InventoryPage-JadYMCzU.js +0 -1005
  79. package/dist/MemberProfileCard-01d_jz3w.js +0 -273
  80. package/dist/MemberProfileCard-01d_jz3w.js.map +0 -1
  81. package/dist/PaymentCreatePage-D6NZBUC3.js +0 -481
  82. package/dist/PaymentCreatePage-D6NZBUC3.js.map +0 -1
  83. package/dist/PaymentsPage-CHieGNrn.js +0 -157
  84. package/dist/PaymentsPage-CHieGNrn.js.map +0 -1
  85. package/dist/PickupBatchLinesEditor-QPaqFtUO.js +0 -116
  86. package/dist/PickupCreatePage-C7_67u_u.js.map +0 -1
  87. package/dist/PickupsPage-BWblMlic.js +0 -812
  88. package/dist/PmGuard-BvUUbU80.js +0 -634
  89. package/dist/PmTable-COZEuDAr.js +0 -546
  90. package/dist/ProductEditPage-Dbq4vUAA.js +0 -1514
  91. package/dist/ProductsPage-BI22nPb4.js +0 -253
  92. package/dist/ProductsPage-BI22nPb4.js.map +0 -1
  93. package/dist/PurchaseCreatePage-C0EK9z4w.js +0 -723
  94. package/dist/PurchaseCreatePage-C0EK9z4w.js.map +0 -1
  95. package/dist/PurchaseRequestsPage-Bj9HUMxb.js +0 -280
  96. package/dist/PurchasesPage-Djl1AqD_.js +0 -294
  97. package/dist/PurchasesPage-Djl1AqD_.js.map +0 -1
  98. package/dist/SaleCreatePage-DHBLmlBr.js +0 -543
  99. package/dist/SaleCreatePage-DHBLmlBr.js.map +0 -1
  100. package/dist/SalesPage-eF9Yr42z.js +0 -314
  101. package/dist/SalesPage-eF9Yr42z.js.map +0 -1
  102. package/dist/SettingsPage-Cre-UE3r.js +0 -739
  103. package/dist/SettingsPage-Cre-UE3r.js.map +0 -1
  104. package/dist/StorageUnitsPage-CTEVuemZ.js +0 -745
  105. package/dist/StorageUnitsPage-CTEVuemZ.js.map +0 -1
  106. package/dist/TransactionsPage-Zuu7sjID.js +0 -759
  107. package/dist/TransactionsPage-Zuu7sjID.js.map +0 -1
  108. package/dist/TransferCreatePage-DlT0nCDj.js +0 -635
  109. package/dist/TransferCreatePage-DlT0nCDj.js.map +0 -1
  110. package/dist/TransfersPage-DqaSvHda.js +0 -593
  111. package/dist/VialsPage-LoDaUqVv.js +0 -454
  112. package/dist/format-UOyOu75i.js +0 -52
  113. package/dist/listValueStore-5d4vNGQM.js +0 -43
  114. package/dist/settingsStore-Df_wGo55.js +0 -478
  115. package/dist/settingsStore-Df_wGo55.js.map +0 -1
  116. package/dist/useFieldErrors-hDG8ox_x.js +0 -29
  117. package/dist/validation-BzlHnL-r.js +0 -110
@@ -0,0 +1,384 @@
1
+ import { r as usePmSettings, x as getBrands, xt as upsertBrand } from "./settingsStore-C1aUfwS9.js";
2
+ import { c as PmTableCard, l as showToast, n as PmFieldHelp, s as PmTable, t as PmEmptyRow } from "./PmTable-nWK5C3ew.js";
3
+ import { i as validateEmail, m as validateRequired, t as isClean } from "./validation-CKx4Zzpx.js";
4
+ import { t as useFieldErrors } from "./useFieldErrors-Dh04ptYj.js";
5
+ import { a as PmPageShell, i as usePmPermissions, n as PmNav, r as usePermissionedEffect, t as PmGuard } from "./PmGuard-DzOloo0T.js";
6
+ import { useState } from "react";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ import { Alert, Box, Button, Checkbox, Chip, Dialog, DialogActions, DialogContent, DialogTitle, FormControlLabel, InputAdornment, Skeleton, Stack, TableBody, TableCell, TableHead, TableRow, TextField, Typography } from "@mui/material";
9
+ import { findCountry, validatePhoneForCountry } from "@/common/constants/countries";
10
+ import { v4 } from "uuid";
11
+ import AddRoundedIcon from "@mui/icons-material/AddRounded";
12
+ import RefreshRoundedIcon from "@mui/icons-material/RefreshRounded";
13
+ import SellRoundedIcon from "@mui/icons-material/SellRounded";
14
+ import CustomSwitch from "@/views/custom-components/CustomSwitch";
15
+ function parseContactInfo(e) {
16
+ if (!e) return {
17
+ phone: "",
18
+ email: ""
19
+ };
20
+ try {
21
+ let w = JSON.parse(e);
22
+ return {
23
+ phone: typeof w?.phone == "string" ? w.phone : "",
24
+ email: typeof w?.email == "string" ? w.email : ""
25
+ };
26
+ } catch {
27
+ return {
28
+ phone: "",
29
+ email: ""
30
+ };
31
+ }
32
+ }
33
+ function serializeContactInfo({ phone: e, email: w }) {
34
+ let T = {};
35
+ return e?.trim() && (T.phone = e.trim()), w?.trim() && (T.email = w.trim()), Object.keys(T).length ? JSON.stringify(T) : null;
36
+ }
37
+ function BrandsPage() {
38
+ let E = usePmPermissions().has("update.manage.productManagement.brand"), D = findCountry(usePmSettings()?.countryCode), [O, k] = useState([]), [A, j] = useState(!1), [M, N] = useState(""), [P, F] = useState(!1), [I, L] = useState(null), [R, z] = useState(!1), [B, V] = useState(U()), H = useFieldErrors();
39
+ function U() {
40
+ return {
41
+ id: "",
42
+ name: "",
43
+ manufacturerCode: "",
44
+ contactPhone: "",
45
+ contactEmail: "",
46
+ isActive: !0
47
+ };
48
+ }
49
+ async function W() {
50
+ j(!0), N("");
51
+ try {
52
+ k(await getBrands(void 0, !0));
53
+ } catch (e) {
54
+ let w = e?.response?.data?.message ?? e?.message ?? "Failed to load brands";
55
+ N(w), showToast({
56
+ message: w,
57
+ type: "error"
58
+ });
59
+ } finally {
60
+ j(!1);
61
+ }
62
+ }
63
+ usePermissionedEffect("view.manage.productManagement.brand", () => {
64
+ W();
65
+ }, []);
66
+ function G() {
67
+ L(null), V({
68
+ ...U(),
69
+ id: v4()
70
+ }), H.reset(), N(""), F(!0);
71
+ }
72
+ function K(e) {
73
+ let { phone: w, email: T } = parseContactInfo(e.contactInfo);
74
+ L(e), H.reset(), N(""), V({
75
+ id: e.id,
76
+ name: e.name ?? "",
77
+ manufacturerCode: e.manufacturerCode ?? "",
78
+ contactPhone: w,
79
+ contactEmail: T,
80
+ isActive: e.isActive !== !1
81
+ }), F(!0);
82
+ }
83
+ let q = validateRequired(B.manufacturerCode, "Manufacturer code"), J = B.manufacturerCode.trim().toUpperCase(), Y = !q && J && O.some((e) => e.id !== B.id && (e.manufacturerCode || "").toUpperCase() === J), X = {
84
+ name: validateRequired(B.name, "Name"),
85
+ manufacturerCode: q || (Y ? "Code is already in use — edit it manually to make it unique." : ""),
86
+ contactPhone: validatePhoneForCountry(B.contactPhone, D),
87
+ contactEmail: validateEmail(B.contactEmail)
88
+ }, Z = isClean(X);
89
+ async function Q() {
90
+ if (!Z) {
91
+ H.markAllTouched(), N("Please fix the highlighted fields.");
92
+ return;
93
+ }
94
+ try {
95
+ await upsertBrand({
96
+ id: B.id,
97
+ name: B.name.trim(),
98
+ manufacturerCode: B.manufacturerCode.trim().toUpperCase(),
99
+ contactInfo: serializeContactInfo({
100
+ phone: B.contactPhone,
101
+ email: B.contactEmail
102
+ }),
103
+ isActive: B.isActive
104
+ }), showToast({
105
+ message: "Brand saved.",
106
+ type: "success"
107
+ }), F(!1), await W();
108
+ } catch (e) {
109
+ let w = e?.response?.data?.message ?? e?.message ?? "Failed to save brand";
110
+ N(w), showToast({
111
+ message: w,
112
+ type: "error"
113
+ });
114
+ }
115
+ }
116
+ let $ = R ? O : O.filter((e) => e.isActive !== !1);
117
+ return /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx(PmNav, {}), /* @__PURE__ */ jsxs(PmGuard, {
118
+ perm: "view.manage.productManagement.brand",
119
+ children: [/* @__PURE__ */ jsxs(PmPageShell, {
120
+ title: "Brands",
121
+ subtitle: "The manufacturer or supplier of each product.",
122
+ chips: ["Catalog"],
123
+ actions: /* @__PURE__ */ jsxs(Stack, {
124
+ direction: "row",
125
+ spacing: 1,
126
+ children: [/* @__PURE__ */ jsx(Button, {
127
+ variant: "outlined",
128
+ startIcon: /* @__PURE__ */ jsx(RefreshRoundedIcon, {}),
129
+ onClick: () => void W(),
130
+ children: "Refresh"
131
+ }), E ? /* @__PURE__ */ jsx(Button, {
132
+ variant: "contained",
133
+ startIcon: /* @__PURE__ */ jsx(AddRoundedIcon, {}),
134
+ onClick: G,
135
+ children: "New Brand"
136
+ }) : null]
137
+ }),
138
+ children: [M ? /* @__PURE__ */ jsx(Alert, {
139
+ severity: "error",
140
+ sx: { mb: 2 },
141
+ children: M
142
+ }) : null, /* @__PURE__ */ jsx(PmTableCard, {
143
+ eyebrow: "Master data",
144
+ title: "Brands",
145
+ subtitle: A ? "Loading…" : `${$.length} ${$.length === 1 ? "brand" : "brands"}`,
146
+ actions: /* @__PURE__ */ jsx(FormControlLabel, {
147
+ control: /* @__PURE__ */ jsx(CustomSwitch, {
148
+ checked: R,
149
+ onChange: (e) => z(e.target.checked)
150
+ }),
151
+ label: /* @__PURE__ */ jsx(Typography, {
152
+ variant: "body2",
153
+ sx: { fontWeight: 600 },
154
+ children: "Show inactive"
155
+ }),
156
+ labelPlacement: "start",
157
+ sx: {
158
+ mr: .5,
159
+ ml: 0
160
+ }
161
+ }),
162
+ children: /* @__PURE__ */ jsxs(PmTable, { children: [/* @__PURE__ */ jsx(TableHead, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
163
+ /* @__PURE__ */ jsx(TableCell, { children: "Name" }),
164
+ /* @__PURE__ */ jsx(TableCell, { children: "Manufacturer Code" }),
165
+ /* @__PURE__ */ jsx(TableCell, { children: "Contact" }),
166
+ /* @__PURE__ */ jsx(TableCell, { children: "Status" }),
167
+ /* @__PURE__ */ jsx(TableCell, {
168
+ align: "right",
169
+ children: "Action"
170
+ })
171
+ ] }) }), /* @__PURE__ */ jsx(TableBody, { children: A ? Array.from({ length: 4 }).map((e, w) => /* @__PURE__ */ jsx(TableRow, { children: Array.from({ length: 5 }).map((e, w) => /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(Skeleton, { height: 22 }) }, w)) }, w)) : $.length === 0 ? /* @__PURE__ */ jsx(PmEmptyRow, {
172
+ colSpan: 5,
173
+ icon: SellRoundedIcon,
174
+ title: O.length === 0 ? "No brands yet" : "No active brands",
175
+ hint: O.length === 0 ? "Add manufacturers so you can link them to your products." : "Turn on “Show inactive” to see deactivated brands.",
176
+ action: O.length === 0 && E ? /* @__PURE__ */ jsx(Button, {
177
+ variant: "contained",
178
+ size: "small",
179
+ startIcon: /* @__PURE__ */ jsx(AddRoundedIcon, {}),
180
+ onClick: G,
181
+ children: "Create first brand"
182
+ }) : null
183
+ }) : $.map((e) => {
184
+ let { phone: w, email: T } = parseContactInfo(e.contactInfo);
185
+ return /* @__PURE__ */ jsxs(TableRow, {
186
+ hover: !0,
187
+ children: [
188
+ /* @__PURE__ */ jsx(TableCell, {
189
+ sx: { maxWidth: 240 },
190
+ children: /* @__PURE__ */ jsx(Typography, {
191
+ variant: "body2",
192
+ sx: {
193
+ fontWeight: 700,
194
+ wordBreak: "break-word"
195
+ },
196
+ children: e.name
197
+ })
198
+ }),
199
+ /* @__PURE__ */ jsx(TableCell, {
200
+ sx: { maxWidth: 160 },
201
+ children: /* @__PURE__ */ jsx(Box, {
202
+ component: "span",
203
+ sx: {
204
+ display: "inline-block",
205
+ px: .85,
206
+ py: .25,
207
+ borderRadius: 1,
208
+ bgcolor: "grey.100",
209
+ fontFamily: "monospace",
210
+ fontSize: "0.72rem",
211
+ fontWeight: 800,
212
+ maxWidth: "100%",
213
+ wordBreak: "break-all"
214
+ },
215
+ children: e.manufacturerCode
216
+ })
217
+ }),
218
+ /* @__PURE__ */ jsx(TableCell, { children: w || T ? /* @__PURE__ */ jsxs(Stack, {
219
+ spacing: .25,
220
+ children: [w ? /* @__PURE__ */ jsx(Typography, {
221
+ variant: "caption",
222
+ sx: { fontWeight: 600 },
223
+ children: w
224
+ }) : null, T ? /* @__PURE__ */ jsx(Typography, {
225
+ variant: "caption",
226
+ color: "text.secondary",
227
+ children: T
228
+ }) : null]
229
+ }) : /* @__PURE__ */ jsx(Typography, {
230
+ variant: "caption",
231
+ color: "text.disabled",
232
+ children: "—"
233
+ }) }),
234
+ /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(Chip, {
235
+ size: "small",
236
+ label: e.isActive ? "Active" : "Inactive",
237
+ color: e.isActive ? "success" : "default",
238
+ variant: e.isActive ? "filled" : "outlined",
239
+ sx: {
240
+ fontWeight: 700,
241
+ borderRadius: 1.5,
242
+ height: 22
243
+ }
244
+ }) }),
245
+ /* @__PURE__ */ jsx(TableCell, {
246
+ align: "right",
247
+ children: E ? /* @__PURE__ */ jsx(Button, {
248
+ size: "small",
249
+ variant: "outlined",
250
+ onClick: () => K(e),
251
+ children: "Edit"
252
+ }) : null
253
+ })
254
+ ]
255
+ }, e.id);
256
+ }) })] })
257
+ })]
258
+ }), /* @__PURE__ */ jsxs(Dialog, {
259
+ open: P,
260
+ onClose: () => F(!1),
261
+ fullWidth: !0,
262
+ maxWidth: "sm",
263
+ children: [
264
+ /* @__PURE__ */ jsx(DialogTitle, { children: I ? "Edit Brand" : "New Brand" }),
265
+ /* @__PURE__ */ jsx(DialogContent, {
266
+ dividers: !0,
267
+ children: /* @__PURE__ */ jsxs(Stack, {
268
+ spacing: 2,
269
+ sx: { pt: 1 },
270
+ children: [
271
+ /* @__PURE__ */ jsx(TextField, {
272
+ required: !0,
273
+ label: "Name",
274
+ size: "small",
275
+ fullWidth: !0,
276
+ value: B.name,
277
+ inputProps: { maxLength: 255 },
278
+ onChange: (e) => {
279
+ let w = e.target.value, T = w.split(/\s+/).filter(Boolean).map((e) => e[0]).join("").toUpperCase();
280
+ V((e) => ({
281
+ ...e,
282
+ name: w,
283
+ manufacturerCode: I ? e.manufacturerCode : T
284
+ }));
285
+ },
286
+ onBlur: H.onBlur("name"),
287
+ error: H.show("name") && !!X.name,
288
+ FormHelperTextProps: { component: "div" },
289
+ helperText: /* @__PURE__ */ jsx(PmFieldHelp, {
290
+ message: H.show("name") ? X.name : "",
291
+ value: B.name,
292
+ max: 255
293
+ })
294
+ }),
295
+ /* @__PURE__ */ jsx(TextField, {
296
+ required: !0,
297
+ label: "Manufacturer code",
298
+ size: "small",
299
+ fullWidth: !0,
300
+ value: B.manufacturerCode,
301
+ inputProps: { maxLength: 100 },
302
+ onChange: (e) => V({
303
+ ...B,
304
+ manufacturerCode: e.target.value.toUpperCase()
305
+ }),
306
+ onBlur: H.onBlur("manufacturerCode"),
307
+ error: H.show("manufacturerCode") && !!X.manufacturerCode,
308
+ FormHelperTextProps: { component: "div" },
309
+ helperText: /* @__PURE__ */ jsx(PmFieldHelp, {
310
+ message: H.show("manufacturerCode") && X.manufacturerCode ? X.manufacturerCode : "Auto-generated from the name as initials. Edit if needed to make it unique.",
311
+ value: B.manufacturerCode,
312
+ max: 100
313
+ })
314
+ }),
315
+ /* @__PURE__ */ jsx(TextField, {
316
+ label: "Contact Number",
317
+ size: "small",
318
+ fullWidth: !0,
319
+ type: "tel",
320
+ placeholder: D ? D.phoneMin === D.phoneMax ? `${D.phoneMin}-digit local number` : `${D.phoneMin}–${D.phoneMax} digit local number` : "Local number",
321
+ value: B.contactPhone,
322
+ onChange: (e) => V({
323
+ ...B,
324
+ contactPhone: e.target.value.replace(/[^\d\s]/g, "")
325
+ }),
326
+ onBlur: H.onBlur("contactPhone"),
327
+ error: H.show("contactPhone") && !!X.contactPhone,
328
+ helperText: H.show("contactPhone") && X.contactPhone ? X.contactPhone : D ? `Format for ${D.name}: ${D.phoneCode} followed by ${D.phoneMin}${D.phoneMin === D.phoneMax ? "" : `–${D.phoneMax}`} digits.` : "Local number, digits only.",
329
+ InputProps: D ? { startAdornment: /* @__PURE__ */ jsx(InputAdornment, {
330
+ position: "start",
331
+ children: /* @__PURE__ */ jsx(Box, {
332
+ component: "span",
333
+ sx: {
334
+ fontWeight: 700,
335
+ color: "text.secondary"
336
+ },
337
+ children: D.phoneCode
338
+ })
339
+ }) } : void 0
340
+ }),
341
+ /* @__PURE__ */ jsx(TextField, {
342
+ label: "Email",
343
+ size: "small",
344
+ fullWidth: !0,
345
+ type: "email",
346
+ placeholder: "e.g. contact@manufacturer.example",
347
+ value: B.contactEmail,
348
+ onChange: (e) => V({
349
+ ...B,
350
+ contactEmail: e.target.value
351
+ }),
352
+ onBlur: H.onBlur("contactEmail"),
353
+ error: H.show("contactEmail") && !!X.contactEmail,
354
+ helperText: H.show("contactEmail") ? X.contactEmail : ""
355
+ }),
356
+ /* @__PURE__ */ jsx(FormControlLabel, {
357
+ control: /* @__PURE__ */ jsx(Checkbox, {
358
+ checked: B.isActive,
359
+ onChange: (e) => V({
360
+ ...B,
361
+ isActive: e.target.checked
362
+ })
363
+ }),
364
+ label: "Active"
365
+ })
366
+ ]
367
+ })
368
+ }),
369
+ /* @__PURE__ */ jsxs(DialogActions, { children: [/* @__PURE__ */ jsx(Button, {
370
+ onClick: () => F(!1),
371
+ children: "Cancel"
372
+ }), /* @__PURE__ */ jsx(Button, {
373
+ variant: "contained",
374
+ disabled: !Z,
375
+ onClick: () => void Q(),
376
+ children: "Save"
377
+ })] })
378
+ ]
379
+ })]
380
+ })] });
381
+ }
382
+ export { BrandsPage as default };
383
+
384
+ //# sourceMappingURL=BrandsPage-DBFBor6L.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"BrandsPage-CdcAvaml.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-DBFBor6L.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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"}