@argusoft/medplat-product-management 1.0.10 → 1.0.12

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 (118) 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-B9DfGUJ_.js +465 -0
  20. package/dist/PickupCreatePage-B9DfGUJ_.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 +0 -770
  87. package/dist/PickupCreatePage-C7_67u_u.js.map +0 -1
  88. package/dist/PickupsPage-BWblMlic.js +0 -812
  89. package/dist/PmGuard-BvUUbU80.js +0 -634
  90. package/dist/PmTable-COZEuDAr.js +0 -546
  91. package/dist/ProductEditPage-Dbq4vUAA.js +0 -1514
  92. package/dist/ProductsPage-BI22nPb4.js +0 -253
  93. package/dist/ProductsPage-BI22nPb4.js.map +0 -1
  94. package/dist/PurchaseCreatePage-C0EK9z4w.js +0 -723
  95. package/dist/PurchaseCreatePage-C0EK9z4w.js.map +0 -1
  96. package/dist/PurchaseRequestsPage-Bj9HUMxb.js +0 -280
  97. package/dist/PurchasesPage-Djl1AqD_.js +0 -294
  98. package/dist/PurchasesPage-Djl1AqD_.js.map +0 -1
  99. package/dist/SaleCreatePage-DHBLmlBr.js +0 -543
  100. package/dist/SaleCreatePage-DHBLmlBr.js.map +0 -1
  101. package/dist/SalesPage-eF9Yr42z.js +0 -314
  102. package/dist/SalesPage-eF9Yr42z.js.map +0 -1
  103. package/dist/SettingsPage-Cre-UE3r.js +0 -739
  104. package/dist/SettingsPage-Cre-UE3r.js.map +0 -1
  105. package/dist/StorageUnitsPage-CTEVuemZ.js +0 -745
  106. package/dist/StorageUnitsPage-CTEVuemZ.js.map +0 -1
  107. package/dist/TransactionsPage-Zuu7sjID.js +0 -759
  108. package/dist/TransactionsPage-Zuu7sjID.js.map +0 -1
  109. package/dist/TransferCreatePage-DlT0nCDj.js +0 -635
  110. package/dist/TransferCreatePage-DlT0nCDj.js.map +0 -1
  111. package/dist/TransfersPage-DqaSvHda.js +0 -593
  112. package/dist/VialsPage-LoDaUqVv.js +0 -454
  113. package/dist/format-UOyOu75i.js +0 -52
  114. package/dist/listValueStore-5d4vNGQM.js +0 -43
  115. package/dist/settingsStore-Df_wGo55.js +0 -478
  116. package/dist/settingsStore-Df_wGo55.js.map +0 -1
  117. package/dist/useFieldErrors-hDG8ox_x.js +0 -29
  118. 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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"}