@argusoft/medplat-product-management 1.0.2 → 1.0.4

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 (83) hide show
  1. package/dist/{BrandsPage-CSA3meke.js → BrandsPage-BE3kn-8b.js} +77 -75
  2. package/dist/BrandsPage-BE3kn-8b.js.map +1 -0
  3. package/dist/{CategoriesPage-BrspzkJL.js → CategoriesPage-COqi3pMi.js} +71 -70
  4. package/dist/{CategoriesPage-BrspzkJL.js.map → CategoriesPage-COqi3pMi.js.map} +1 -1
  5. package/dist/{DashboardPage-CqaquOs2.js → DashboardPage-C_H1Jrey.js} +90 -89
  6. package/dist/DashboardPage-C_H1Jrey.js.map +1 -0
  7. package/dist/{FacilityPicker-Dv_H95WW.js → FacilityPicker-Diq2hnYg.js} +2 -2
  8. package/dist/{FacilityPicker-Dv_H95WW.js.map → FacilityPicker-Diq2hnYg.js.map} +1 -1
  9. package/dist/{InventoryPage-CPbzfDMR.js → InventoryPage-Bjpw6vTz.js} +106 -115
  10. package/dist/InventoryPage-Bjpw6vTz.js.map +1 -0
  11. package/dist/{MemberProfileCard-0vjO3Gzd.js → MemberProfileCard-BLUVRILO.js} +10 -9
  12. package/dist/MemberProfileCard-BLUVRILO.js.map +1 -0
  13. package/dist/{PaymentCreatePage-BYmDZAIB.js → PaymentCreatePage-B5VOgTx9.js} +173 -177
  14. package/dist/PaymentCreatePage-B5VOgTx9.js.map +1 -0
  15. package/dist/{PaymentsPage-BXPvKon-.js → PaymentsPage-DY6BclkN.js} +24 -23
  16. package/dist/{PaymentsPage-BXPvKon-.js.map → PaymentsPage-DY6BclkN.js.map} +1 -1
  17. package/dist/PickupCreatePage-CCSiyFQF.js +706 -0
  18. package/dist/PickupCreatePage-CCSiyFQF.js.map +1 -0
  19. package/dist/{PickupsPage-D66_Wta4.js → PickupsPage-DGi6T5Of.js} +83 -90
  20. package/dist/PickupsPage-DGi6T5Of.js.map +1 -0
  21. package/dist/PmGuard-C90yhpsN.js +592 -0
  22. package/dist/PmGuard-C90yhpsN.js.map +1 -0
  23. package/dist/{PmTable-B9970kPY.js → PmTable-BkK65bJQ.js} +98 -98
  24. package/dist/PmTable-BkK65bJQ.js.map +1 -0
  25. package/dist/{ProductEditPage-B8qFTCW9.js → ProductEditPage-CQj9egzW.js} +138 -137
  26. package/dist/ProductEditPage-CQj9egzW.js.map +1 -0
  27. package/dist/{ProductsPage-C7_r9cKn.js → ProductsPage-i8QVw_Jm.js} +65 -64
  28. package/dist/{ProductsPage-C7_r9cKn.js.map → ProductsPage-i8QVw_Jm.js.map} +1 -1
  29. package/dist/PurchaseCreatePage-Bp6bl9n8.js +591 -0
  30. package/dist/PurchaseCreatePage-Bp6bl9n8.js.map +1 -0
  31. package/dist/{PurchaseRequestDetailPage-C7aAwEqw.js → PurchaseRequestDetailPage-CNAqIFef.js} +216 -215
  32. package/dist/PurchaseRequestDetailPage-CNAqIFef.js.map +1 -0
  33. package/dist/{PurchaseRequestsPage-BwCkbpaX.js → PurchaseRequestsPage-BJqDlNrc.js} +57 -56
  34. package/dist/{PurchaseRequestsPage-BwCkbpaX.js.map → PurchaseRequestsPage-BJqDlNrc.js.map} +1 -1
  35. package/dist/{PurchasesPage-CvaZouVy.js → PurchasesPage-BQEToymQ.js} +76 -75
  36. package/dist/{PurchasesPage-CvaZouVy.js.map → PurchasesPage-BQEToymQ.js.map} +1 -1
  37. package/dist/{SaleCreatePage-DP1Qmltu.js → SaleCreatePage-DbfBK4PH.js} +149 -173
  38. package/dist/SaleCreatePage-DbfBK4PH.js.map +1 -0
  39. package/dist/{SalesPage-CO3cdYX5.js → SalesPage-CTBJMxZe.js} +50 -49
  40. package/dist/SalesPage-CTBJMxZe.js.map +1 -0
  41. package/dist/SettingsPage-CiwVmzM3.js +663 -0
  42. package/dist/SettingsPage-CiwVmzM3.js.map +1 -0
  43. package/dist/{StorageUnitsPage-B9Hr_RkW.js → StorageUnitsPage-BV7nK_iE.js} +57 -56
  44. package/dist/{StorageUnitsPage-B9Hr_RkW.js.map → StorageUnitsPage-BV7nK_iE.js.map} +1 -1
  45. package/dist/{TransactionsPage-HKIGwEZN.js → TransactionsPage-Cocn4901.js} +55 -54
  46. package/dist/TransactionsPage-Cocn4901.js.map +1 -0
  47. package/dist/TransferCreatePage-DbjcjuOg.js +316 -0
  48. package/dist/TransferCreatePage-DbjcjuOg.js.map +1 -0
  49. package/dist/TransfersPage-BFVF7Xvc.js +471 -0
  50. package/dist/TransfersPage-BFVF7Xvc.js.map +1 -0
  51. package/dist/VialsPage-BNzYTLVd.js +321 -0
  52. package/dist/VialsPage-BNzYTLVd.js.map +1 -0
  53. package/dist/index.js +652 -34
  54. package/dist/index.js.map +1 -1
  55. package/dist/settingsStore-KW217unV.js +417 -0
  56. package/dist/settingsStore-KW217unV.js.map +1 -0
  57. package/package.json +1 -1
  58. package/dist/BrandsPage-CSA3meke.js.map +0 -1
  59. package/dist/DashboardPage-CqaquOs2.js.map +0 -1
  60. package/dist/InventoryPage-CPbzfDMR.js.map +0 -1
  61. package/dist/MemberProfileCard-0vjO3Gzd.js.map +0 -1
  62. package/dist/PaymentCreatePage-BYmDZAIB.js.map +0 -1
  63. package/dist/PickupCreatePage-CMGwoAXj.js +0 -426
  64. package/dist/PickupCreatePage-CMGwoAXj.js.map +0 -1
  65. package/dist/PickupsPage-D66_Wta4.js.map +0 -1
  66. package/dist/PmTable-B9970kPY.js.map +0 -1
  67. package/dist/ProductEditPage-B8qFTCW9.js.map +0 -1
  68. package/dist/PurchaseCreatePage-CDfNDcKG.js +0 -627
  69. package/dist/PurchaseCreatePage-CDfNDcKG.js.map +0 -1
  70. package/dist/PurchaseRequestDetailPage-C7aAwEqw.js.map +0 -1
  71. package/dist/SaleCreatePage-DP1Qmltu.js.map +0 -1
  72. package/dist/SalesPage-CO3cdYX5.js.map +0 -1
  73. package/dist/SettingsPage-DvVRwSFw.js +0 -711
  74. package/dist/SettingsPage-DvVRwSFw.js.map +0 -1
  75. package/dist/TransactionsPage-HKIGwEZN.js.map +0 -1
  76. package/dist/TransferCreatePage-DMuZqQ3c.js +0 -363
  77. package/dist/TransferCreatePage-DMuZqQ3c.js.map +0 -1
  78. package/dist/TransfersPage-COIyouL4.js +0 -480
  79. package/dist/TransfersPage-COIyouL4.js.map +0 -1
  80. package/dist/VialsPage-BNPUwGCU.js +0 -922
  81. package/dist/VialsPage-BNPUwGCU.js.map +0 -1
  82. package/dist/currency-ClRLIEg2.js +0 -1372
  83. package/dist/currency-ClRLIEg2.js.map +0 -1
@@ -1,426 +0,0 @@
1
- import { F as e, L as t, R as n, et as r, i, n as a, o, r as s } from "./currency-ClRLIEg2.js";
2
- import { r as c } from "./PmTable-B9970kPY.js";
3
- import { t as l } from "./format-UOyOu75i.js";
4
- import { useMemo as u, useState as d } from "react";
5
- import { jsx as f, jsxs as p } from "react/jsx-runtime";
6
- import { v4 as m } from "uuid";
7
- import { Alert as h, Autocomplete as g, Box as _, Button as v, Card as y, CardContent as b, Chip as x, FormControl as ee, FormHelperText as te, Grid as S, InputLabel as ne, MenuItem as C, Select as re, Stack as w, TextField as T, Typography as E } from "@mui/material";
8
- import { showToast as ie } from "@/common/toaster/toaster";
9
- import { useNavigate as ae } from "react-router-dom";
10
- import D from "@mui/icons-material/SaveRounded";
11
- //#region src/views/PickupCreatePage.jsx
12
- function O(e) {
13
- return !(e.ownerType !== "FACILITY" || Number(e.qtyRemaining ?? 0) <= 0 || e.status === "EXPIRED" || e.status === "EXHAUSTED" || e.status === "QUARANTINED");
14
- }
15
- function k() {
16
- let e = /* @__PURE__ */ new Date(), t = (e) => String(e).padStart(2, "0");
17
- return `${e.getFullYear()}-${t(e.getMonth() + 1)}-${t(e.getDate())}T${t(e.getHours())}:${t(e.getMinutes())}`;
18
- }
19
- function A() {
20
- let A = ae(), [j, M] = d([]), [N, P] = d([]), [F, I] = d([]), [oe, se] = d(!0), [L, R] = d(!1), [z, B] = d(""), [V, H] = d({
21
- id: m(),
22
- personalBatchId: m(),
23
- facilityId: "",
24
- sourceBatchId: "",
25
- pickedQty: 1,
26
- notes: "",
27
- sessionName: "",
28
- sessionDescription: "",
29
- sessionStartTime: k(),
30
- sessionExpectedEndTime: "",
31
- sessionSite: ""
32
- });
33
- i("update.manage.productManagement.pickup", () => {
34
- async function r() {
35
- try {
36
- let [r, i, a] = await Promise.all([
37
- t(),
38
- e(),
39
- n().catch(() => [])
40
- ]);
41
- M(r), P(i), I(a);
42
- } catch (e) {
43
- B(e?.response?.data?.message ?? e?.message ?? "Failed to load reference data");
44
- } finally {
45
- se(!1);
46
- }
47
- }
48
- r();
49
- }, []);
50
- let U = F.length > 0, W = u(() => V.facilityId ? N.filter(O).filter((e) => e.ownerId === V.facilityId) : [], [N, V.facilityId]), G = u(() => N.find((e) => e.id === V.sourceBatchId) ?? null, [N, V.sourceBatchId]);
51
- function K(e, t) {
52
- H((n) => ({
53
- ...n,
54
- [e]: t
55
- }));
56
- }
57
- function ce(e) {
58
- H((t) => ({
59
- ...t,
60
- facilityId: e,
61
- sourceBatchId: ""
62
- }));
63
- }
64
- let q = Number(V.pickedQty), J = Number(G?.qtyRemaining ?? 0), Y = G ? !Number.isInteger(q) || q <= 0 ? "Enter a whole number greater than 0." : q > J ? `Only ${J} available in this batch.` : "" : "", X = V.sessionName.trim() ? "" : "Session name is required.", le = V.sessionStartTime ? new Date(V.sessionStartTime).getTime() : NaN, Z = V.sessionStartTime ? le < Date.now() - 300 * 1e3 ? "Start time cannot be in the past." : "" : "Start time is required.", Q = V.sessionExpectedEndTime ? V.sessionStartTime && V.sessionExpectedEndTime <= V.sessionStartTime ? "Expected end must be after the start time." : "" : "Expected end time is required.", $ = !!V.facilityId && !!V.sourceBatchId && !Y && !U && !X && !Z && !Q;
65
- async function ue() {
66
- if ($) {
67
- R(!0), B("");
68
- try {
69
- let e = await r({
70
- id: V.id,
71
- personalBatchId: V.personalBatchId,
72
- sourceBatchId: V.sourceBatchId,
73
- pickedQty: q,
74
- notes: V.notes || null,
75
- sessionName: V.sessionName.trim(),
76
- sessionDescription: V.sessionDescription.trim() || null,
77
- sessionStartTime: V.sessionStartTime ? new Date(V.sessionStartTime).toISOString() : null,
78
- sessionExpectedEndTime: V.sessionExpectedEndTime ? new Date(V.sessionExpectedEndTime).toISOString() : null,
79
- sessionSite: V.sessionSite.trim() || null
80
- });
81
- ie({
82
- message: `Picked up ${e.pickedQty} unit${e.pickedQty === 1 ? "" : "s"}.`,
83
- type: "success"
84
- }), A("/ui/medplat/manage/pm/pickups");
85
- } catch (e) {
86
- B(e?.response?.data?.message ?? e?.message ?? "Failed to record pickup");
87
- } finally {
88
- R(!1);
89
- }
90
- }
91
- }
92
- return /* @__PURE__ */ p(_, { children: [/* @__PURE__ */ f(s, {}), /* @__PURE__ */ f(a, {
93
- perm: "update.manage.productManagement.pickup",
94
- title: "You don’t have permission to record pickups",
95
- children: /* @__PURE__ */ p(o, {
96
- title: "Record Pickup",
97
- subtitle: "Check out stock from a facility for your field work. Record returns and wastage when you bring stock back.",
98
- actions: /* @__PURE__ */ p(w, {
99
- direction: "row",
100
- spacing: 1,
101
- children: [/* @__PURE__ */ f(v, {
102
- variant: "outlined",
103
- onClick: () => A("/ui/medplat/manage/pm/pickups"),
104
- children: "Cancel"
105
- }), /* @__PURE__ */ f(v, {
106
- variant: "contained",
107
- startIcon: /* @__PURE__ */ f(D, {}),
108
- disabled: !$ || L,
109
- onClick: () => void ue(),
110
- children: L ? "Recording…" : "Record Pickup"
111
- })]
112
- }),
113
- children: [
114
- z ? /* @__PURE__ */ f(h, {
115
- severity: "error",
116
- sx: { mb: 2 },
117
- children: z
118
- }) : null,
119
- U ? /* @__PURE__ */ p(h, {
120
- severity: "warning",
121
- sx: { mb: 2 },
122
- action: /* @__PURE__ */ f(v, {
123
- color: "inherit",
124
- size: "small",
125
- onClick: () => A("/ui/medplat/manage/pm/pickups"),
126
- children: "Go to Pickups"
127
- }),
128
- children: [
129
- "You already have ",
130
- /* @__PURE__ */ f("strong", { children: F.length }),
131
- " open outreach session",
132
- F.length === 1 ? "" : "s",
133
- ". End the active session",
134
- F.length === 1 ? "" : "s",
135
- " before starting a new pickup, or use ",
136
- /* @__PURE__ */ f("strong", { children: "Top Up" }),
137
- " on the Pickups page to add more stock to an active session."
138
- ]
139
- }) : null,
140
- /* @__PURE__ */ f(y, {
141
- sx: {
142
- borderRadius: 4,
143
- mb: 2,
144
- border: "1px solid",
145
- borderColor: "divider",
146
- boxShadow: "0 12px 32px rgba(15, 23, 42, 0.045)"
147
- },
148
- children: /* @__PURE__ */ p(b, {
149
- sx: { p: 2.5 },
150
- children: [/* @__PURE__ */ f(c, {
151
- eyebrow: "Step 1",
152
- title: "Source",
153
- hint: "Select a facility and then the batch to pick up.",
154
- sx: { mb: 2 }
155
- }), /* @__PURE__ */ p(S, {
156
- container: !0,
157
- spacing: 2,
158
- children: [/* @__PURE__ */ f(S, {
159
- item: !0,
160
- xs: 12,
161
- md: 5,
162
- children: /* @__PURE__ */ f(g, {
163
- size: "small",
164
- options: j,
165
- getOptionLabel: (e) => e?.name ?? "",
166
- isOptionEqualToValue: (e, t) => e?.id === t?.id,
167
- value: j.find((e) => e.id === V.facilityId) ?? null,
168
- onChange: (e, t) => ce(t?.id ?? ""),
169
- loading: oe,
170
- renderInput: (e) => /* @__PURE__ */ f(T, {
171
- ...e,
172
- required: !0,
173
- label: "Source Facility",
174
- placeholder: "Pick a facility you're assigned to"
175
- })
176
- })
177
- }), /* @__PURE__ */ f(S, {
178
- item: !0,
179
- xs: 12,
180
- md: 7,
181
- children: /* @__PURE__ */ p(ee, {
182
- required: !0,
183
- fullWidth: !0,
184
- size: "small",
185
- disabled: !V.facilityId,
186
- children: [
187
- /* @__PURE__ */ f(ne, { children: "Source Batch" }),
188
- /* @__PURE__ */ f(re, {
189
- label: "Source Batch",
190
- value: V.sourceBatchId,
191
- onChange: (e) => K("sourceBatchId", e.target.value),
192
- children: W.length === 0 ? /* @__PURE__ */ f(C, {
193
- disabled: !0,
194
- value: "",
195
- children: /* @__PURE__ */ f("em", { children: "No pickable stock in this facility" })
196
- }) : W.map((e) => /* @__PURE__ */ p(C, {
197
- value: e.id,
198
- children: [
199
- /* @__PURE__ */ f(_, {
200
- component: "span",
201
- sx: {
202
- fontWeight: 700,
203
- mr: 1
204
- },
205
- children: e.productName
206
- }),
207
- /* @__PURE__ */ p(E, {
208
- variant: "caption",
209
- color: "text.secondary",
210
- sx: { mr: 1 },
211
- children: ["qty ", e.qtyRemaining]
212
- }),
213
- e.lotNumber ? /* @__PURE__ */ f(E, {
214
- variant: "caption",
215
- sx: {
216
- fontFamily: "monospace",
217
- mr: 1
218
- },
219
- children: e.lotNumber
220
- }) : null,
221
- e.expiryDate ? /* @__PURE__ */ p(E, {
222
- variant: "caption",
223
- color: "text.secondary",
224
- children: ["exp ", l(e.expiryDate)]
225
- }) : null
226
- ]
227
- }, e.id))
228
- }),
229
- /* @__PURE__ */ f(te, { children: V.facilityId ? W.length === 0 ? "This facility has no in-stock batches you can pick up right now." : "Active facility batches only — quarantined / expired / exhausted stock is hidden." : "Pick a facility first." })
230
- ]
231
- })
232
- })]
233
- })]
234
- })
235
- }),
236
- /* @__PURE__ */ f(y, {
237
- sx: {
238
- borderRadius: 4,
239
- mb: 2,
240
- border: "1px solid",
241
- borderColor: "divider",
242
- boxShadow: "0 12px 32px rgba(15, 23, 42, 0.045)"
243
- },
244
- children: /* @__PURE__ */ p(b, {
245
- sx: { p: 2.5 },
246
- children: [/* @__PURE__ */ f(c, {
247
- eyebrow: "Session",
248
- title: "Outreach session details",
249
- hint: "Records the purpose, timing and location of this outreach session. Shown when administering from this stock.",
250
- sx: { mb: 2 }
251
- }), /* @__PURE__ */ p(S, {
252
- container: !0,
253
- spacing: 2,
254
- children: [
255
- /* @__PURE__ */ f(S, {
256
- item: !0,
257
- xs: 12,
258
- md: 6,
259
- children: /* @__PURE__ */ f(T, {
260
- required: !0,
261
- fullWidth: !0,
262
- size: "small",
263
- label: "Session name",
264
- inputProps: { maxLength: 150 },
265
- value: V.sessionName,
266
- onChange: (e) => K("sessionName", e.target.value),
267
- error: !!X && V.sessionName !== "",
268
- helperText: V.sessionName === "" ? "e.g. Anganwadi camp – Ward 4" : X
269
- })
270
- }),
271
- /* @__PURE__ */ f(S, {
272
- item: !0,
273
- xs: 12,
274
- md: 6,
275
- children: /* @__PURE__ */ f(T, {
276
- fullWidth: !0,
277
- size: "small",
278
- label: "Session site (optional)",
279
- placeholder: "Location / site reference",
280
- inputProps: { maxLength: 200 },
281
- value: V.sessionSite,
282
- onChange: (e) => K("sessionSite", e.target.value)
283
- })
284
- }),
285
- /* @__PURE__ */ f(S, {
286
- item: !0,
287
- xs: 12,
288
- md: 6,
289
- children: /* @__PURE__ */ f(T, {
290
- required: !0,
291
- fullWidth: !0,
292
- size: "small",
293
- type: "datetime-local",
294
- label: "Start time",
295
- InputLabelProps: { shrink: !0 },
296
- inputProps: { min: k() },
297
- value: V.sessionStartTime,
298
- onChange: (e) => K("sessionStartTime", e.target.value),
299
- error: !!Z,
300
- helperText: Z || "Cannot be in the past. (5 minutes buffer allowed)"
301
- })
302
- }),
303
- /* @__PURE__ */ f(S, {
304
- item: !0,
305
- xs: 12,
306
- md: 6,
307
- children: /* @__PURE__ */ f(T, {
308
- required: !0,
309
- fullWidth: !0,
310
- size: "small",
311
- type: "datetime-local",
312
- label: "Expected end",
313
- InputLabelProps: { shrink: !0 },
314
- inputProps: { min: V.sessionStartTime || void 0 },
315
- value: V.sessionExpectedEndTime,
316
- onChange: (e) => K("sessionExpectedEndTime", e.target.value),
317
- error: !!Q,
318
- helperText: Q || "When the session is expected to end."
319
- })
320
- }),
321
- /* @__PURE__ */ f(S, {
322
- item: !0,
323
- xs: 12,
324
- children: /* @__PURE__ */ f(T, {
325
- fullWidth: !0,
326
- size: "small",
327
- multiline: !0,
328
- minRows: 2,
329
- label: "Purpose / description (optional)",
330
- value: V.sessionDescription,
331
- onChange: (e) => K("sessionDescription", e.target.value)
332
- })
333
- })
334
- ]
335
- })]
336
- })
337
- }),
338
- G ? /* @__PURE__ */ f(y, {
339
- sx: {
340
- borderRadius: 4,
341
- mb: 2,
342
- border: "1px solid",
343
- borderColor: "divider",
344
- boxShadow: "0 12px 32px rgba(15, 23, 42, 0.045)"
345
- },
346
- children: /* @__PURE__ */ p(b, {
347
- sx: { p: 2.5 },
348
- children: [
349
- /* @__PURE__ */ f(c, {
350
- eyebrow: "Step 2",
351
- title: "Quantity",
352
- hint: `Available: ${J}. You can pick up to this amount.`,
353
- sx: { mb: 2 }
354
- }),
355
- /* @__PURE__ */ p(S, {
356
- container: !0,
357
- spacing: 2,
358
- children: [/* @__PURE__ */ f(S, {
359
- item: !0,
360
- xs: 12,
361
- md: 4,
362
- children: /* @__PURE__ */ f(T, {
363
- required: !0,
364
- fullWidth: !0,
365
- size: "small",
366
- type: "number",
367
- label: "Pick Quantity",
368
- inputProps: {
369
- min: 1,
370
- max: J
371
- },
372
- value: V.pickedQty,
373
- onChange: (e) => K("pickedQty", e.target.value),
374
- error: !!Y,
375
- helperText: Y || `Out of ${J} available`
376
- })
377
- }), /* @__PURE__ */ f(S, {
378
- item: !0,
379
- xs: 12,
380
- md: 8,
381
- children: /* @__PURE__ */ f(T, {
382
- fullWidth: !0,
383
- size: "small",
384
- label: "Notes (optional)",
385
- placeholder: "Anything worth recording about this pickup",
386
- value: V.notes,
387
- onChange: (e) => K("notes", e.target.value)
388
- })
389
- })]
390
- }),
391
- /* @__PURE__ */ p(w, {
392
- direction: "row",
393
- spacing: 1,
394
- sx: { mt: 2 },
395
- flexWrap: "wrap",
396
- useFlexGap: !0,
397
- children: [
398
- /* @__PURE__ */ f(x, {
399
- size: "small",
400
- label: `Product · ${G.productName}`
401
- }),
402
- G.lotNumber ? /* @__PURE__ */ f(x, {
403
- size: "small",
404
- label: `Lot · ${G.lotNumber}`
405
- }) : null,
406
- G.expiryDate ? /* @__PURE__ */ f(x, {
407
- size: "small",
408
- label: `Expiry · ${l(G.expiryDate)}`
409
- }) : null,
410
- G.storageUnitName ? /* @__PURE__ */ f(x, {
411
- size: "small",
412
- label: `From · ${G.storageUnitName}`
413
- }) : null
414
- ]
415
- })
416
- ]
417
- })
418
- }) : null
419
- ]
420
- })
421
- })] });
422
- }
423
- //#endregion
424
- export { A as default };
425
-
426
- //# sourceMappingURL=PickupCreatePage-CMGwoAXj.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"PickupCreatePage-CMGwoAXj.js","names":[],"sources":["../src/views/PickupCreatePage.jsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { v4 as uuidv4 } from 'uuid';\nimport {\n Alert,\n Autocomplete,\n Box,\n Button,\n Card,\n CardContent,\n Chip,\n FormControl,\n FormHelperText,\n Grid,\n InputLabel,\n MenuItem,\n Select,\n Stack,\n TextField,\n Typography,\n} from '@mui/material';\nimport SaveRoundedIcon from '@mui/icons-material/SaveRounded';\nimport { showToast } from '@/common/toaster/toaster';\nimport PmPageShell from '@pm/components/PmPageShell';\nimport PmNav from '@pm/components/PmNav';\nimport PmGuard from '@pm/components/PmGuard';\nimport { usePermissionedEffect } from '@pm/utils/permissions';\nimport { PmFormSection } from '@pm/components/PmTable';\nimport {\n listBatches,\n listFacilities,\n listMyOpenPickups,\n recordPickup,\n} from '@pm/services/pmApi';\nimport { formatDate } from '@pm/utils/format';\n\n// Only facility-owned, in-stock, non-quarantined, non-terminal batches are\n// candidates for pickup. The backend enforces the same rules; filtering here\n// keeps the dropdown free of unactionable rows.\nfunction isPickable(batch) {\n if (batch.ownerType !== 'FACILITY') return false;\n if (Number(batch.qtyRemaining ?? 0) <= 0) return false;\n if (batch.status === 'EXPIRED' || batch.status === 'EXHAUSTED' || batch.status === 'QUARANTINED') return false;\n return true;\n}\n\n// Current local time as a value for <input type=\"datetime-local\"> (YYYY-MM-DDTHH:mm).\nfunction nowLocalInput() {\n const d = new Date();\n const pad = (n) => String(n).padStart(2, '0');\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;\n}\n\nexport default function PickupCreatePage() {\n const navigate = useNavigate();\n const [facilities, setFacilities] = useState([]);\n const [batches, setBatches] = useState([]);\n // OPEN pickups already on this user — one-session-per-user rule means\n // any open session blocks a new pickup. The user has to end the session\n // or top it up instead.\n const [openSessions, setOpenSessions] = useState([]);\n const [loading, setLoading] = useState(true);\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState('');\n const [form, setForm] = useState({\n id: uuidv4(),\n personalBatchId: uuidv4(),\n facilityId: '',\n sourceBatchId: '',\n pickedQty: 1,\n notes: '',\n // Outreach session metadata.\n sessionName: '',\n sessionDescription: '',\n sessionStartTime: nowLocalInput(),\n sessionExpectedEndTime: '',\n sessionSite: '',\n });\n\n usePermissionedEffect('update.manage.productManagement.pickup', () => {\n async function load() {\n try {\n const [f, b, open] = await Promise.all([\n listFacilities(),\n listBatches(),\n listMyOpenPickups().catch(() => []),\n ]);\n setFacilities(f);\n setBatches(b);\n setOpenSessions(open);\n } catch (err) {\n setError(err?.response?.data?.message ?? err?.message ?? 'Failed to load reference data');\n } finally {\n setLoading(false);\n }\n }\n void load();\n }, []);\n\n const hasOpenSession = openSessions.length > 0;\n\n // Batches limited to the picked facility (when one is selected). Reset\n // when the facility changes so the user can't carry over a stale batch.\n const eligibleBatches = useMemo(() => {\n if (!form.facilityId) return [];\n return batches.filter(isPickable).filter((b) => b.ownerId === form.facilityId);\n }, [batches, form.facilityId]);\n\n const selectedBatch = useMemo(\n () => batches.find((b) => b.id === form.sourceBatchId) ?? null,\n [batches, form.sourceBatchId],\n );\n\n function patch(k, v) {\n setForm((f) => ({ ...f, [k]: v }));\n }\n\n function patchFacility(id) {\n setForm((f) => ({ ...f, facilityId: id, sourceBatchId: '' }));\n }\n\n const qty = Number(form.pickedQty);\n const remaining = Number(selectedBatch?.qtyRemaining ?? 0);\n const qtyError = !selectedBatch\n ? ''\n : !Number.isInteger(qty) || qty <= 0\n ? 'Enter a whole number greater than 0.'\n : qty > remaining\n ? `Only ${remaining} available in this batch.`\n : '';\n const sessionNameError = form.sessionName.trim() ? '' : 'Session name is required.';\n // Start time can't be in the past. A small grace (5 min) tolerates the lag\n // between the prefilled \"now\" and submission; the backend re-checks against\n // server time so a tampered client clock can't bypass it.\n const startMs = form.sessionStartTime ? new Date(form.sessionStartTime).getTime() : NaN;\n const sessionStartError = !form.sessionStartTime\n ? 'Start time is required.'\n : startMs < Date.now() - 5 * 60 * 1000\n ? 'Start time cannot be in the past.'\n : '';\n // End time is required and must be after the start.\n const sessionEndError = !form.sessionExpectedEndTime\n ? 'Expected end time is required.'\n : (form.sessionStartTime && form.sessionExpectedEndTime <= form.sessionStartTime)\n ? 'Expected end must be after the start time.'\n : '';\n const formIsValid = !!form.facilityId && !!form.sourceBatchId && !qtyError && !hasOpenSession\n && !sessionNameError && !sessionStartError && !sessionEndError;\n\n async function save() {\n if (!formIsValid) return;\n setSubmitting(true);\n setError('');\n try {\n const created = await recordPickup({\n id: form.id,\n personalBatchId: form.personalBatchId,\n sourceBatchId: form.sourceBatchId,\n pickedQty: qty,\n notes: form.notes || null,\n sessionName: form.sessionName.trim(),\n sessionDescription: form.sessionDescription.trim() || null,\n sessionStartTime: form.sessionStartTime ? new Date(form.sessionStartTime).toISOString() : null,\n sessionExpectedEndTime: form.sessionExpectedEndTime ? new Date(form.sessionExpectedEndTime).toISOString() : null,\n sessionSite: form.sessionSite.trim() || null,\n });\n showToast({ message: `Picked up ${created.pickedQty} unit${created.pickedQty === 1 ? '' : 's'}.`, type: 'success' });\n navigate('/ui/medplat/manage/pm/pickups');\n } catch (err) {\n setError(err?.response?.data?.message ?? err?.message ?? 'Failed to record pickup');\n } finally {\n setSubmitting(false);\n }\n }\n\n return (\n <Box>\n <PmNav />\n <PmGuard perm={'update.manage.productManagement.pickup'} title=\"You don’t have permission to record pickups\">\n <PmPageShell\n title=\"Record Pickup\"\n subtitle=\"Check out stock from a facility for your field work. Record returns and wastage when you bring stock back.\"\n actions={\n <Stack direction=\"row\" spacing={1}>\n <Button variant=\"outlined\" onClick={() => navigate('/ui/medplat/manage/pm/pickups')}>Cancel</Button>\n <Button variant=\"contained\" startIcon={<SaveRoundedIcon />}\n disabled={!formIsValid || submitting}\n onClick={() => void save()}>\n {submitting ? 'Recording…' : 'Record Pickup'}\n </Button>\n </Stack>\n }\n >\n {error ? <Alert severity=\"error\" sx={{ mb: 2 }}>{error}</Alert> : null}\n\n {hasOpenSession ? (\n <Alert\n severity=\"warning\"\n sx={{ mb: 2 }}\n action={\n <Button color=\"inherit\" size=\"small\"\n onClick={() => navigate('/ui/medplat/manage/pm/pickups')}>\n Go to Pickups\n </Button>\n }\n >\n You already have <strong>{openSessions.length}</strong> open outreach session{openSessions.length === 1 ? '' : 's'}.\n End the active session{openSessions.length === 1 ? '' : 's'} before starting a new pickup,\n or use <strong>Top Up</strong> on the Pickups page to add more stock to an active session.\n </Alert>\n ) : null}\n\n <Card sx={{ borderRadius: 4, mb: 2, border: '1px solid', borderColor: 'divider', boxShadow: '0 12px 32px rgba(15, 23, 42, 0.045)' }}>\n <CardContent sx={{ p: 2.5 }}>\n <PmFormSection\n eyebrow=\"Step 1\"\n title=\"Source\"\n hint=\"Select a facility and then the batch to pick up.\"\n sx={{ mb: 2 }}\n />\n <Grid container spacing={2}>\n <Grid item xs={12} md={5}>\n <Autocomplete\n size=\"small\"\n options={facilities}\n getOptionLabel={(f) => f?.name ?? ''}\n isOptionEqualToValue={(a, b) => a?.id === b?.id}\n value={facilities.find((f) => f.id === form.facilityId) ?? null}\n onChange={(_, next) => patchFacility(next?.id ?? '')}\n loading={loading}\n renderInput={(params) => (\n <TextField {...params} required label=\"Source Facility\" placeholder=\"Pick a facility you're assigned to\" />\n )}\n />\n </Grid>\n <Grid item xs={12} md={7}>\n <FormControl required fullWidth size=\"small\" disabled={!form.facilityId}>\n <InputLabel>Source Batch</InputLabel>\n <Select\n label=\"Source Batch\"\n value={form.sourceBatchId}\n onChange={(e) => patch('sourceBatchId', e.target.value)}\n >\n {eligibleBatches.length === 0 ? (\n <MenuItem disabled value=\"\">\n <em>No pickable stock in this facility</em>\n </MenuItem>\n ) : (\n eligibleBatches.map((b) => (\n <MenuItem key={b.id} value={b.id}>\n <Box component=\"span\" sx={{ fontWeight: 700, mr: 1 }}>{b.productName}</Box>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ mr: 1 }}>\n qty {b.qtyRemaining}\n </Typography>\n {b.lotNumber ? (\n <Typography variant=\"caption\" sx={{ fontFamily: 'monospace', mr: 1 }}>\n {b.lotNumber}\n </Typography>\n ) : null}\n {b.expiryDate ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n exp {formatDate(b.expiryDate)}\n </Typography>\n ) : null}\n </MenuItem>\n ))\n )}\n </Select>\n <FormHelperText>\n {!form.facilityId\n ? 'Pick a facility first.'\n : eligibleBatches.length === 0\n ? 'This facility has no in-stock batches you can pick up right now.'\n : 'Active facility batches only — quarantined / expired / exhausted stock is hidden.'}\n </FormHelperText>\n </FormControl>\n </Grid>\n </Grid>\n </CardContent>\n </Card>\n\n <Card sx={{ borderRadius: 4, mb: 2, border: '1px solid', borderColor: 'divider', boxShadow: '0 12px 32px rgba(15, 23, 42, 0.045)' }}>\n <CardContent sx={{ p: 2.5 }}>\n <PmFormSection\n eyebrow=\"Session\"\n title=\"Outreach session details\"\n hint=\"Records the purpose, timing and location of this outreach session. Shown when administering from this stock.\"\n sx={{ mb: 2 }}\n />\n <Grid container spacing={2}>\n <Grid item xs={12} md={6}>\n <TextField\n required fullWidth size=\"small\"\n label=\"Session name\"\n inputProps={{ maxLength: 150 }}\n value={form.sessionName}\n onChange={(e) => patch('sessionName', e.target.value)}\n error={!!sessionNameError && form.sessionName !== ''}\n helperText={form.sessionName === '' ? 'e.g. Anganwadi camp – Ward 4' : sessionNameError}\n />\n </Grid>\n <Grid item xs={12} md={6}>\n <TextField\n fullWidth size=\"small\"\n label=\"Session site (optional)\"\n placeholder=\"Location / site reference\"\n inputProps={{ maxLength: 200 }}\n value={form.sessionSite}\n onChange={(e) => patch('sessionSite', e.target.value)}\n />\n </Grid>\n <Grid item xs={12} md={6}>\n <TextField\n required\n fullWidth size=\"small\" type=\"datetime-local\"\n label=\"Start time\"\n InputLabelProps={{ shrink: true }}\n inputProps={{ min: nowLocalInput() }}\n value={form.sessionStartTime}\n onChange={(e) => patch('sessionStartTime', e.target.value)}\n error={!!sessionStartError}\n helperText={sessionStartError || 'Cannot be in the past. (5 minutes buffer allowed)'}\n />\n </Grid>\n <Grid item xs={12} md={6}>\n <TextField\n required\n fullWidth size=\"small\" type=\"datetime-local\"\n label=\"Expected end\"\n InputLabelProps={{ shrink: true }}\n inputProps={{ min: form.sessionStartTime || undefined }}\n value={form.sessionExpectedEndTime}\n onChange={(e) => patch('sessionExpectedEndTime', e.target.value)}\n error={!!sessionEndError}\n helperText={sessionEndError || 'When the session is expected to end.'}\n />\n </Grid>\n <Grid item xs={12}>\n <TextField\n fullWidth size=\"small\" multiline minRows={2}\n label=\"Purpose / description (optional)\"\n value={form.sessionDescription}\n onChange={(e) => patch('sessionDescription', e.target.value)}\n />\n </Grid>\n </Grid>\n </CardContent>\n </Card>\n\n {selectedBatch ? (\n <Card sx={{ borderRadius: 4, mb: 2, border: '1px solid', borderColor: 'divider', boxShadow: '0 12px 32px rgba(15, 23, 42, 0.045)' }}>\n <CardContent sx={{ p: 2.5 }}>\n <PmFormSection\n eyebrow=\"Step 2\"\n title=\"Quantity\"\n hint={`Available: ${remaining}. You can pick up to this amount.`}\n sx={{ mb: 2 }}\n />\n <Grid container spacing={2}>\n <Grid item xs={12} md={4}>\n <TextField\n required fullWidth size=\"small\" type=\"number\"\n label=\"Pick Quantity\"\n inputProps={{ min: 1, max: remaining }}\n value={form.pickedQty}\n onChange={(e) => patch('pickedQty', e.target.value)}\n error={!!qtyError}\n helperText={qtyError || `Out of ${remaining} available`}\n />\n </Grid>\n <Grid item xs={12} md={8}>\n <TextField\n fullWidth size=\"small\"\n label=\"Notes (optional)\"\n placeholder=\"Anything worth recording about this pickup\"\n value={form.notes}\n onChange={(e) => patch('notes', e.target.value)}\n />\n </Grid>\n </Grid>\n <Stack direction=\"row\" spacing={1} sx={{ mt: 2 }} flexWrap=\"wrap\" useFlexGap>\n <Chip size=\"small\" label={`Product · ${selectedBatch.productName}`} />\n {selectedBatch.lotNumber ? <Chip size=\"small\" label={`Lot · ${selectedBatch.lotNumber}`} /> : null}\n {selectedBatch.expiryDate ? <Chip size=\"small\" label={`Expiry · ${formatDate(selectedBatch.expiryDate)}`} /> : null}\n {selectedBatch.storageUnitName ? <Chip size=\"small\" label={`From · ${selectedBatch.storageUnitName}`} /> : null}\n </Stack>\n </CardContent>\n </Card>\n ) : null}\n </PmPageShell>\n </PmGuard>\n </Box>\n );\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"PickupsPage-D66_Wta4.js","names":[],"sources":["../src/views/PickupsPage.jsx"],"sourcesContent":["import { useMemo, useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n Alert,\n Box,\n Button,\n Chip,\n Dialog,\n DialogActions,\n DialogContent,\n DialogTitle,\n FormControl,\n FormHelperText,\n InputAdornment,\n InputLabel,\n MenuItem,\n Select,\n Skeleton,\n Stack,\n TableBody,\n TableCell,\n TableHead,\n TableRow,\n TextField,\n Typography,\n} from '@mui/material';\nimport { alpha } from '@mui/material/styles';\nimport AddRoundedIcon from '@mui/icons-material/AddRounded';\nimport RefreshRoundedIcon from '@mui/icons-material/RefreshRounded';\nimport SearchRoundedIcon from '@mui/icons-material/SearchRounded';\nimport MoveDownRoundedIcon from '@mui/icons-material/MoveDownRounded';\nimport AssignmentReturnRoundedIcon from '@mui/icons-material/AssignmentReturnRounded';\nimport { showToast } from '@/common/toaster/toaster';\nimport PmPageShell from '@pm/components/PmPageShell';\nimport PmNav from '@pm/components/PmNav';\nimport PmGuard from '@pm/components/PmGuard';\nimport { usePermissionedEffect, usePmPermissions } from '@pm/utils/permissions';\nimport {\n PmEmptyRow,\n PmRef,\n PmTable,\n PmTableCard,\n} from '@pm/components/PmTable';\nimport { v4 as uuidv4 } from 'uuid';\nimport {\n listPickups,\n recordPickupReturn,\n recordPickupTopup,\n} from '@pm/services/pmApi';\nimport { formatDate, formatDateTime } from '@pm/utils/format';\nimport { PICKUP_STATUSES, WASTAGE_REASONS, labelOf } from '@pm/utils/constants';\n\nfunction statusChipColor(status) {\n switch (status) {\n case 'OPEN': return 'info';\n case 'RETURNED': return 'success';\n case 'CANCELLED': return 'default';\n default: return 'default';\n }\n}\n\nexport default function PickupsPage() {\n const navigate = useNavigate();\n const perms = usePmPermissions();\n const canCreate = perms.has('update.manage.productManagement.pickup');\n const [rows, setRows] = useState([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState('');\n const [search, setSearch] = useState('');\n const [returnDialog, setReturnDialog] = useState({ open: false, pickup: null });\n const [returnForm, setReturnForm] = useState({ returnedQty: '', wastageReason: '', notes: '' });\n const [topupDialog, setTopupDialog] = useState({ open: false, pickup: null });\n const [topupForm, setTopupForm] = useState({ additionalQty: '', notes: '' });\n const [submitting, setSubmitting] = useState(false);\n\n async function load() {\n setLoading(true);\n setError('');\n try {\n setRows(await listPickups());\n } catch (err) {\n const message = err?.response?.data?.message ?? err?.message ?? 'Failed to load pickups';\n setError(message);\n showToast({ message, type: 'error' });\n } finally {\n setLoading(false);\n }\n }\n\n usePermissionedEffect('view.manage.productManagement.pickup', () => { void load(); }, []);\n\n const filtered = useMemo(() => {\n const q = search.trim().toLowerCase();\n if (!q) return rows;\n return rows.filter((r) => {\n const hay = `${r.sessionName ?? ''} ${r.sessionSite ?? ''} ${r.productName ?? ''} ${r.facilityName ?? ''} ${r.userName ?? ''} ${r.lotNumber ?? ''} ${r.notes ?? ''}`.toLowerCase();\n return hay.includes(q);\n });\n }, [rows, search]);\n\n function openReturn(p) {\n const expected = p.expectedRemainingQty ?? 0;\n setReturnForm({\n // Default to \"return everything that's expected to remain\" — no wastage.\n returnedQty: String(expected),\n wastageReason: '',\n notes: '',\n });\n setReturnDialog({ open: true, pickup: p });\n }\n\n function closeReturn() {\n if (submitting) return;\n setReturnDialog({ open: false, pickup: null });\n }\n\n function openTopup(p) {\n setTopupForm({ additionalQty: '1', notes: '' });\n setTopupDialog({ open: true, pickup: p });\n }\n\n function closeTopup() {\n if (submitting) return;\n setTopupDialog({ open: false, pickup: null });\n }\n\n // Ceiling for a top-up is whatever the source (facility) batch still has —\n // the backend rejects more than this, so cap it here for a friendly UX.\n const topupSourceAvailable = topupDialog.pickup?.sourceBatchQtyRemaining ?? null;\n const topupAdditionalQty = Number(topupForm.additionalQty);\n const topupQtyError = !Number.isInteger(topupAdditionalQty) || topupAdditionalQty <= 0\n ? 'Enter a whole number greater than 0.'\n : (topupSourceAvailable != null && topupAdditionalQty > topupSourceAvailable)\n ? `Only ${topupSourceAvailable} available at the source facility.`\n : '';\n\n async function submitTopup() {\n if (topupQtyError || !topupDialog.pickup) return;\n setSubmitting(true);\n try {\n await recordPickupTopup(topupDialog.pickup.id, {\n id: uuidv4(),\n additionalQty: topupAdditionalQty,\n notes: topupForm.notes || null,\n });\n showToast({\n message: `Topped up ${topupAdditionalQty} unit${topupAdditionalQty === 1 ? '' : 's'}.`,\n type: 'success',\n });\n closeTopup();\n await load();\n } catch (err) {\n const message = err?.response?.data?.message ?? err?.message ?? 'Failed to top up';\n showToast({ message, type: 'error' });\n } finally {\n setSubmitting(false);\n }\n }\n\n const expectedRemaining = returnDialog.pickup?.expectedRemainingQty ?? 0;\n const returnedQty = Number(returnForm.returnedQty);\n const wastedQty = Number.isFinite(returnedQty) && returnedQty >= 0 && returnedQty <= expectedRemaining\n ? expectedRemaining - returnedQty\n : null;\n const returnedQtyError = !Number.isInteger(returnedQty) || returnedQty < 0\n ? 'Enter a whole number from 0 to the expected remaining.'\n : returnedQty > expectedRemaining\n ? `At most ${expectedRemaining} can be returned.`\n : '';\n // Reason is required whenever ANY wastage will be written — either the\n // sealed-units gap is > 0, or there are open vials to close (their\n // remaining volume becomes wastage).\n const reasonRequired = (wastedQty != null && wastedQty > 0)\n || ((returnDialog.pickup?.openVials ?? []).length > 0);\n const reasonError = reasonRequired && !returnForm.wastageReason\n ? 'A reason is required for the wastage being recorded.'\n : '';\n const returnFormValid = !returnedQtyError && !reasonError;\n\n async function submitReturn() {\n if (!returnFormValid || !returnDialog.pickup) return;\n setSubmitting(true);\n try {\n await recordPickupReturn(returnDialog.pickup.id, {\n returnedQty,\n wastageReason: reasonRequired ? returnForm.wastageReason : null,\n notes: returnForm.notes || null,\n });\n showToast({\n message: wastedQty > 0\n ? `Returned ${returnedQty}, wasted ${wastedQty}.`\n : `Returned ${returnedQty} unit${returnedQty === 1 ? '' : 's'}.`,\n type: 'success',\n });\n closeReturn();\n await load();\n } catch (err) {\n const message = err?.response?.data?.message ?? err?.message ?? 'Failed to record return';\n showToast({ message, type: 'error' });\n } finally {\n setSubmitting(false);\n }\n }\n\n return (\n <Box>\n <PmNav />\n <PmGuard perm={'view.manage.productManagement.pickup'}>\n <PmPageShell\n title=\"Stock Pickups\"\n subtitle=\"Stock you're carrying for field work. Record returns and any items lost or used.\"\n actions={\n <Stack direction=\"row\" spacing={1}>\n <Button variant=\"outlined\" startIcon={<RefreshRoundedIcon />} onClick={() => void load()}>Refresh</Button>\n {canCreate ? (\n <Button variant=\"contained\" startIcon={<AddRoundedIcon />}\n onClick={() => navigate('/ui/medplat/manage/pm/pickups/new')}>\n New Pickup\n </Button>\n ) : null}\n </Stack>\n }\n >\n {error ? <Alert severity=\"error\" sx={{ mb: 2 }}>{error}</Alert> : null}\n\n <PmTableCard\n eyebrow=\"Operations\"\n title=\"Pickups\"\n subtitle={loading ? 'Loading…' : `${filtered.length} ${filtered.length === 1 ? 'pickup' : 'pickups'}`}\n >\n <Stack direction={{ xs: 'column', md: 'row' }} spacing={1.5} sx={{ mb: 2 }}>\n <TextField\n size=\"small\" fullWidth\n placeholder=\"Search by product, facility, user, lot, notes…\"\n value={search}\n onChange={(e) => setSearch(e.target.value)}\n InputProps={{\n startAdornment: <InputAdornment position=\"start\"><SearchRoundedIcon fontSize=\"small\" /></InputAdornment>,\n }}\n />\n </Stack>\n\n <PmTable dense>\n <TableHead>\n <TableRow>\n <TableCell>Ref</TableCell>\n <TableCell>Session</TableCell>\n <TableCell>Product</TableCell>\n <TableCell>Facility</TableCell>\n <TableCell>User</TableCell>\n <TableCell align=\"right\">Qty</TableCell>\n <TableCell>Picked</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: 9 }).map((__, j) => (\n <TableCell key={j}><Skeleton height={22} /></TableCell>\n ))}\n </TableRow>\n ))\n ) : filtered.length === 0 ? (\n <PmEmptyRow\n colSpan={9}\n icon={MoveDownRoundedIcon}\n title={search.trim() !== '' ? 'No pickups match your search' : 'No pickups yet'}\n hint=\"Check out stock from a facility to use in the field.\"\n action={canCreate ? (\n <Button variant=\"contained\" size=\"small\" startIcon={<AddRoundedIcon />}\n onClick={() => navigate('/ui/medplat/manage/pm/pickups/new')}>\n Record first pickup\n </Button>\n ) : null}\n />\n ) : filtered.map((r) => (\n <TableRow key={r.id} hover>\n <TableCell><PmRef id={r.serialId} /></TableCell>\n <TableCell sx={{ maxWidth: 220 }}>\n <Typography variant=\"body2\" sx={{ fontWeight: 700, wordBreak: 'break-word' }}>\n {r.sessionName ?? '—'}\n </Typography>\n {r.sessionSite ? (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', wordBreak: 'break-word' }}>\n {r.sessionSite}\n </Typography>\n ) : null}\n {r.sessionStartTime ? (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', fontVariantNumeric: 'tabular-nums' }}>\n {formatDateTime(r.sessionStartTime)}\n {r.sessionExpectedEndTime ? ` → ${formatDateTime(r.sessionExpectedEndTime)}` : ''}\n </Typography>\n ) : null}\n </TableCell>\n <TableCell>\n <Typography variant=\"body2\" sx={{ fontWeight: 700 }}>{r.productName ?? '—'}</Typography>\n {r.lotNumber ? (\n <Typography variant=\"caption\" sx={{ fontFamily: 'monospace', color: 'text.secondary' }}>\n {r.lotNumber}\n </Typography>\n ) : null}\n </TableCell>\n <TableCell>{r.facilityName ?? '—'}</TableCell>\n <TableCell>{r.userName ?? '—'}</TableCell>\n <TableCell align=\"right\">\n <Typography sx={{ fontWeight: 700, fontVariantNumeric: 'tabular-nums' }}>{r.pickedQty}</Typography>\n {r.status === 'OPEN' && r.expectedRemainingQty != null ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {r.expectedRemainingQty} left on user\n </Typography>\n ) : r.status === 'RETURNED' ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {r.returnedQty} returned{r.wastedQty > 0 ? ` · ${r.wastedQty} wasted` : ''}\n </Typography>\n ) : null}\n </TableCell>\n <TableCell>\n <Typography variant=\"body2\">{formatDate(r.pickedOn)}</Typography>\n </TableCell>\n <TableCell>\n {r.status === 'OPEN' && r.sessionExpectedEndTime\n && new Date(r.sessionExpectedEndTime).getTime() < Date.now() ? (\n <Chip size=\"small\" label=\"Overdue\" color=\"error\" />\n ) : (\n <Chip size=\"small\" label={labelOf(PICKUP_STATUSES, r.status)} color={statusChipColor(r.status)} />\n )}\n </TableCell>\n <TableCell align=\"right\">\n {r.status === 'OPEN' && canCreate ? (\n <Stack direction=\"row\" spacing={1} justifyContent=\"flex-end\">\n <Button size=\"small\" variant=\"outlined\" startIcon={<AddRoundedIcon />}\n onClick={() => openTopup(r)}>\n Top Up\n </Button>\n <Button size=\"small\" variant=\"outlined\" startIcon={<AssignmentReturnRoundedIcon />}\n onClick={() => openReturn(r)}>\n End Session\n </Button>\n </Stack>\n ) : (\n <Typography variant=\"caption\" color=\"text.disabled\">—</Typography>\n )}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </PmTable>\n </PmTableCard>\n </PmPageShell>\n </PmGuard>\n\n {/* ---------- End Outreach Session dialog ---------- */}\n <Dialog open={returnDialog.open} onClose={closeReturn} maxWidth=\"sm\" fullWidth>\n <DialogTitle>End outreach session #{returnDialog.pickup?.serialId}</DialogTitle>\n <DialogContent>\n {returnDialog.pickup ? (\n <Stack spacing={2} sx={{ mt: 1 }}>\n <Box sx={(t) => ({\n p: 1.5, borderRadius: 3,\n bgcolor: alpha(t.palette.primary.main, 0.04),\n border: `1px solid ${alpha(t.palette.primary.main, 0.12)}`,\n })}>\n <Typography variant=\"body2\"><strong>{returnDialog.pickup.productName}</strong></Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block' }}>\n Picked {returnDialog.pickup.pickedQty} on {formatDateTime(returnDialog.pickup.pickedOn)} from {returnDialog.pickup.facilityName}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', mt: 0.5 }}>\n Sealed units expected on user: <strong>{expectedRemaining}</strong>\n {' '}({(returnDialog.pickup.pickedQty ?? 0) - expectedRemaining - ((returnDialog.pickup.openVials ?? []).length)} already administered / wasted during the day)\n </Typography>\n </Box>\n\n <TextField\n required size=\"small\" type=\"number\"\n label=\"Sealed Units Returned\"\n inputProps={{ min: 0, max: expectedRemaining }}\n value={returnForm.returnedQty}\n onChange={(e) => setReturnForm((f) => ({ ...f, returnedQty: e.target.value }))}\n error={!!returnedQtyError}\n helperText={returnedQtyError || `Out of ${expectedRemaining} sealed units expected to remain`}\n />\n\n {wastedQty != null && wastedQty > 0 ? (\n <Alert severity=\"warning\" variant=\"outlined\">\n <strong>{wastedQty}</strong> sealed {wastedQty === 1 ? 'unit' : 'units'} unaccounted for — will be marked as wastage.\n </Alert>\n ) : null}\n\n {/* Open-vial wastage preview. Any vial opened during outreach\n does not return to the facility — it's closed with wastage\n as part of this end-session action. Volume shown so the\n operator knows what's being written off. */}\n {(returnDialog.pickup.openVials ?? []).length > 0 ? (\n <Alert severity=\"info\" variant=\"outlined\">\n <Typography variant=\"body2\" sx={{ fontWeight: 700, mb: 0.5 }}>\n {returnDialog.pickup.openVials.length} open vial{returnDialog.pickup.openVials.length === 1 ? '' : 's'} on you will be closed with wastage\n </Typography>\n <Stack spacing={0.25} sx={{ mt: 0.5 }}>\n {returnDialog.pickup.openVials.map((v) => (\n <Typography key={v.id} variant=\"caption\" color=\"text.secondary\">\n Lot {v.lotNumber || '—'} · {Number(v.volumeRemainingMl ?? 0).toFixed(2)} ml remaining\n </Typography>\n ))}\n </Stack>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', mt: 0.75 }}>\n These volumes will be recorded as wastage using the reason picked below.\n </Typography>\n </Alert>\n ) : null}\n\n <FormControl size=\"small\" disabled={!reasonRequired} error={!!reasonError}>\n <InputLabel>Wastage Reason{reasonRequired ? ' *' : ''}</InputLabel>\n <Select\n label={`Wastage Reason${reasonRequired ? ' *' : ''}`}\n value={returnForm.wastageReason}\n onChange={(e) => setReturnForm((f) => ({ ...f, wastageReason: e.target.value }))}\n >\n <MenuItem value=\"\"><em>—</em></MenuItem>\n {WASTAGE_REASONS.map((r) => (\n <MenuItem key={r.value} value={r.value}>{r.label}</MenuItem>\n ))}\n </Select>\n <FormHelperText>\n {reasonError\n || (reasonRequired\n ? 'Required — same reason covers both unaccounted sealed units and any open-vial remaining volume.'\n : 'Not needed — nothing being wasted.')}\n </FormHelperText>\n </FormControl>\n\n <TextField\n size=\"small\" multiline minRows={2}\n label=\"Notes (optional)\"\n value={returnForm.notes}\n onChange={(e) => setReturnForm((f) => ({ ...f, notes: e.target.value }))}\n />\n </Stack>\n ) : null}\n </DialogContent>\n <DialogActions>\n <Button onClick={closeReturn} disabled={submitting}>Cancel</Button>\n <Button variant=\"contained\" onClick={() => void submitReturn()}\n disabled={!returnFormValid || submitting}>\n {submitting ? 'Submitting…' : 'End Session'}\n </Button>\n </DialogActions>\n </Dialog>\n\n {/* ---------- Top Up dialog ---------- */}\n <Dialog open={topupDialog.open} onClose={closeTopup} maxWidth=\"xs\" fullWidth>\n <DialogTitle>Top up session #{topupDialog.pickup?.serialId}</DialogTitle>\n <DialogContent>\n {topupDialog.pickup ? (\n <Stack spacing={2} sx={{ mt: 1 }}>\n <Box sx={(t) => ({\n p: 1.5, borderRadius: 3,\n bgcolor: alpha(t.palette.primary.main, 0.04),\n border: `1px solid ${alpha(t.palette.primary.main, 0.12)}`,\n })}>\n <Typography variant=\"body2\"><strong>{topupDialog.pickup.productName}</strong></Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block' }}>\n Source: {topupDialog.pickup.facilityName} · Lot {topupDialog.pickup.lotNumber || '—'}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block' }}>\n Currently picked: {topupDialog.pickup.pickedQty} · remaining sealed on user: {topupDialog.pickup.expectedRemainingQty ?? 0}\n </Typography>\n {topupSourceAvailable != null ? (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block' }}>\n Available at source: <strong>{topupSourceAvailable}</strong>\n </Typography>\n ) : null}\n </Box>\n\n <Alert severity=\"info\" variant=\"outlined\">\n Top-ups come from the same source batch as the original pickup so lot / expiry stays consistent. To pick from a different batch, end this session first.\n </Alert>\n\n <TextField\n required size=\"small\" type=\"number\"\n label=\"Additional Quantity\"\n inputProps={{ min: 1, max: topupSourceAvailable ?? undefined }}\n value={topupForm.additionalQty}\n onChange={(e) => setTopupForm((f) => ({ ...f, additionalQty: e.target.value }))}\n error={!!topupQtyError}\n helperText={topupQtyError\n || (topupSourceAvailable != null\n ? `Sealed units to add. Up to ${topupSourceAvailable} available at the source.`\n : 'Sealed units to add to this session.')}\n />\n\n <TextField\n size=\"small\" multiline minRows={2}\n label=\"Notes (optional)\"\n value={topupForm.notes}\n onChange={(e) => setTopupForm((f) => ({ ...f, notes: e.target.value }))}\n />\n </Stack>\n ) : null}\n </DialogContent>\n <DialogActions>\n <Button onClick={closeTopup} disabled={submitting}>Cancel</Button>\n <Button variant=\"contained\" onClick={() => void submitTopup()}\n disabled={!!topupQtyError || submitting}>\n {submitting ? 'Submitting…' : 'Top Up'}\n </Button>\n </DialogActions>\n </Dialog>\n </Box>\n );\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"PmTable-B9970kPY.js","names":[],"sources":["../src/components/PmTable.jsx"],"sourcesContent":["import PropTypes from 'prop-types';\nimport {\n Autocomplete,\n Box,\n Card,\n CardContent,\n Stack,\n Table,\n TableCell,\n TableContainer,\n TableRow,\n TextField,\n Typography,\n} from '@mui/material';\nimport { alpha, useTheme } from '@mui/material/styles';\nimport { currencySymbol } from '@pm/utils/currency';\nimport { usePmSettings } from '@pm/utils/settingsStore';\n\n// Shared building blocks for the data-heavy PM tables. The goal is one\n// consistent look: gradient-headed table, soft hover, eyebrow + title card\n// chrome, semantic empty state, tabular-figure money cell. Every list page\n// is built from these so the visual rhythm is identical everywhere.\n\n// -------- Table -----------------------------------------------------------\n\nexport function PmTable({ children, dense = false, sx = {}, ...props }) {\n const theme = useTheme();\n return (\n <TableContainer\n sx={{\n borderRadius: 2.5,\n border: `1px solid ${alpha(theme.palette.divider, 0.55)}`,\n backgroundColor: theme.palette.background.paper,\n overflow: 'auto',\n ...sx,\n }}\n >\n <Table\n size={dense ? 'small' : 'medium'}\n {...props}\n sx={{\n '& thead .MuiTableRow-root': {\n background: `linear-gradient(180deg, ${alpha(theme.palette.grey[50], 1)} 0%, ${alpha(theme.palette.grey[100], 1)} 100%)`,\n },\n '& thead .MuiTableCell-root': {\n fontWeight: 800,\n fontSize: '0.7rem',\n textTransform: 'uppercase',\n letterSpacing: '0.65px',\n color: theme.palette.text.secondary,\n borderBottom: `1px solid ${theme.palette.divider}`,\n py: 1.25,\n whiteSpace: 'nowrap',\n position: 'sticky',\n top: 0,\n zIndex: 1,\n },\n '& tbody .MuiTableRow-root': {\n transition: 'background-color 140ms ease',\n },\n '& tbody .MuiTableRow-root:hover': {\n backgroundColor: alpha(theme.palette.primary.main, 0.04),\n },\n '& tbody .MuiTableCell-root': {\n py: 1.4,\n borderBottom: `1px solid ${alpha(theme.palette.divider, 0.5)}`,\n verticalAlign: 'middle',\n },\n '& tbody .MuiTableRow-root:last-of-type .MuiTableCell-root': {\n borderBottom: 'none',\n },\n }}\n >\n {children}\n </Table>\n </TableContainer>\n );\n}\nPmTable.propTypes = {\n children: PropTypes.node,\n dense: PropTypes.bool,\n sx: PropTypes.object,\n};\n\n// -------- Section card chrome --------------------------------------------\n\n/**\n * Card with a consistent eyebrow + title + actions header, ready to hold a\n * PmTable (or any other content). The table renders flush against the card\n * because the container handles borders/radius. Toolbar slot is for filters\n * or search inputs that sit between the title and the table.\n */\nexport function PmTableCard({\n eyebrow,\n title,\n subtitle,\n actions,\n toolbar,\n children,\n sx = {},\n}) {\n return (\n <Card\n sx={{\n borderRadius: 4,\n border: '1px solid',\n borderColor: 'divider',\n boxShadow: '0 12px 32px rgba(15, 23, 42, 0.045)',\n overflow: 'hidden',\n ...sx,\n }}\n >\n <CardContent sx={{ p: 0, '&:last-child': { pb: 0 } }}>\n {(title || actions) ? (\n <Box sx={{ px: 2.5, pt: 2, pb: 1.5 }}>\n <Stack\n direction={{ xs: 'column', md: 'row' }}\n justifyContent=\"space-between\"\n alignItems={{ xs: 'flex-start', md: 'center' }}\n spacing={1.5}\n >\n <Box sx={{ minWidth: 0 }}>\n {eyebrow ? (\n <Typography\n variant=\"overline\"\n sx={{ color: 'text.secondary', fontWeight: 800, letterSpacing: 1, lineHeight: 1 }}\n >\n {eyebrow}\n </Typography>\n ) : null}\n {title ? (\n <Typography variant=\"h6\" sx={{ fontWeight: 800, lineHeight: 1.2 }}>\n {title}\n </Typography>\n ) : null}\n {subtitle ? (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {subtitle}\n </Typography>\n ) : null}\n </Box>\n {actions ? <Box>{actions}</Box> : null}\n </Stack>\n </Box>\n ) : null}\n {toolbar ? <Box sx={{ px: 2.5, pb: 1.5 }}>{toolbar}</Box> : null}\n <Box sx={{ p: 2.5, pt: title || toolbar ? 0 : 2.5 }}>{children}</Box>\n </CardContent>\n </Card>\n );\n}\nPmTableCard.propTypes = {\n eyebrow: PropTypes.node,\n title: PropTypes.node,\n subtitle: PropTypes.node,\n actions: PropTypes.node,\n toolbar: PropTypes.node,\n children: PropTypes.node,\n sx: PropTypes.object,\n};\n\n// -------- Empty state row -------------------------------------------------\n\nexport function PmEmptyRow({ colSpan, title, hint, icon: Icon, action }) {\n return (\n <TableRow hover={false}>\n <TableCell colSpan={colSpan} sx={{ py: 5, textAlign: 'center', borderBottom: 'none !important' }}>\n <Stack alignItems=\"center\" spacing={1.25}>\n {Icon ? <Icon sx={{ fontSize: 44, color: 'text.disabled', opacity: 0.7 }} /> : null}\n <Typography variant=\"body2\" sx={{ fontWeight: 700 }}>{title}</Typography>\n {hint ? (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ maxWidth: 360 }}>{hint}</Typography>\n ) : null}\n {action ? <Box>{action}</Box> : null}\n </Stack>\n </TableCell>\n </TableRow>\n );\n}\nPmEmptyRow.propTypes = {\n colSpan: PropTypes.number.isRequired,\n title: PropTypes.node,\n hint: PropTypes.node,\n icon: PropTypes.elementType,\n action: PropTypes.node,\n};\n\n// -------- Money cell ------------------------------------------------------\n\n/**\n * Currency display with tabular figures so numbers don't shift between\n * rows. {@code tone} can semantically colour the value — useful for\n * paid/due splits in the Sales table.\n */\nexport function PmMoney({ value, fallback = '—', size = 'normal', tone, bold = true, prefix, sx = {} }) {\n const theme = useTheme();\n const settings = usePmSettings();\n // When the caller doesn't override the prefix, pull the symbol from the\n // module settings — every PmMoney across the module then renders with the\n // currency configured for the deployment.\n const effectivePrefix = prefix ?? currencySymbol(settings?.currencyCode);\n if (value == null || value === '') {\n return <Box component=\"span\" sx={{ color: 'text.disabled', fontVariantNumeric: 'tabular-nums' }}>{fallback}</Box>;\n }\n const n = Number(value);\n if (Number.isNaN(n)) {\n return <Box component=\"span\" sx={{ color: 'text.disabled', fontVariantNumeric: 'tabular-nums' }}>{fallback}</Box>;\n }\n const color = tone === 'warning' ? theme.palette.warning.dark\n : tone === 'success' ? theme.palette.success.dark\n : tone === 'error' ? theme.palette.error.dark\n : tone === 'muted' ? theme.palette.text.secondary\n : 'inherit';\n return (\n <Box\n component=\"span\"\n sx={{\n fontWeight: bold ? (size === 'big' ? 800 : 700) : 500,\n fontSize: size === 'big' ? '1.05rem' : 'inherit',\n fontVariantNumeric: 'tabular-nums',\n color,\n ...sx,\n }}\n >\n {effectivePrefix}{n.toFixed(2)}\n </Box>\n );\n}\nPmMoney.propTypes = {\n value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n fallback: PropTypes.node,\n size: PropTypes.oneOf(['normal', 'big']),\n tone: PropTypes.oneOf(['warning', 'success', 'error', 'muted']),\n bold: PropTypes.bool,\n prefix: PropTypes.string,\n sx: PropTypes.object,\n};\n\n// -------- Reference chip --------------------------------------------------\n\n/** Monospace `#1234` chip used in left-most \"Ref\" columns. */\nexport function PmRef({ id }) {\n return (\n <Box\n component=\"span\"\n sx={{\n display: 'inline-flex',\n alignItems: 'center',\n px: 0.85,\n py: 0.25,\n borderRadius: 1,\n backgroundColor: 'grey.100',\n color: 'text.secondary',\n fontFamily: 'monospace',\n fontSize: '0.72rem',\n fontWeight: 700,\n letterSpacing: 0.4,\n lineHeight: 1.5,\n }}\n >\n #{id}\n </Box>\n );\n}\nPmRef.propTypes = {\n id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n};\n\n// -------- Field helper text with character counter -----------------------\n\n/**\n * Helper-text content that pairs a message (validation error or hint) on the\n * left with a live \"remaining/allowed\" character counter on the right. Pass\n * as a TextField's `helperText`. Renders only spans so it's valid inside the\n * FormHelperText <p>.\n */\nexport function PmFieldHelp({ message, value, max }) {\n const used = (value ?? '').length;\n const remaining = Math.max(0, max - used);\n return (\n <Box component=\"span\" sx={{ display: 'flex', width: '100%', gap: 1 }}>\n <Box component=\"span\" sx={{ flexGrow: 1 }}>{message || ''}</Box>\n <Box\n component=\"span\"\n sx={{ flexShrink: 0, fontVariantNumeric: 'tabular-nums', color: 'text.secondary' }}\n >\n {remaining}/{max}\n </Box>\n </Box>\n );\n}\nPmFieldHelp.propTypes = {\n message: PropTypes.node,\n value: PropTypes.string,\n max: PropTypes.number.isRequired,\n};\n\n// -------- Select (dropdown) ----------------------------------------------\n\n/**\n * Standard PM dropdown. Wraps MUI Autocomplete (the app-wide dropdown\n * pattern, same as FacilityPicker / CustomDropdown) so every select in the\n * module looks and behaves identically and sizes like the themed text\n * fields. Options are plain `{ value, label }`; `value`/`onChange` work with\n * the raw value so callers don't deal with option objects.\n */\nexport function PmSelect({\n label,\n value,\n onChange,\n onBlur,\n options,\n required = false,\n disabled = false,\n error = false,\n helperText = '',\n fullWidth = true,\n size = 'small',\n noOptionsText,\n sx = {},\n}) {\n const selected = options.find((o) => o.value === value) ?? null;\n return (\n <Autocomplete\n size={size}\n fullWidth={fullWidth}\n disabled={disabled}\n options={options}\n value={selected}\n onChange={(_, opt) => onChange(opt ? opt.value : '')}\n getOptionLabel={(o) => o?.label ?? ''}\n isOptionEqualToValue={(o, v) => o?.value === v?.value}\n disableClearable={required}\n noOptionsText={noOptionsText}\n sx={sx}\n renderInput={(params) => (\n <TextField\n {...params}\n label={label}\n required={required}\n error={error}\n helperText={helperText}\n onBlur={onBlur}\n />\n )}\n />\n );\n}\nPmSelect.propTypes = {\n label: PropTypes.node,\n value: PropTypes.any,\n onChange: PropTypes.func.isRequired,\n onBlur: PropTypes.func,\n options: PropTypes.arrayOf(PropTypes.shape({\n value: PropTypes.any,\n label: PropTypes.node,\n })).isRequired,\n required: PropTypes.bool,\n disabled: PropTypes.bool,\n error: PropTypes.bool,\n helperText: PropTypes.node,\n fullWidth: PropTypes.bool,\n size: PropTypes.string,\n noOptionsText: PropTypes.node,\n sx: PropTypes.object,\n};\n\n// -------- Form section helper --------------------------------------------\n\n/**\n * Wraps a chunk of form fields with a consistent eyebrow + title + hint\n * header. Used inside create/edit pages so every section has the same\n * vertical rhythm.\n */\nexport function PmFormSection({ eyebrow, title, hint, children, sx = {} }) {\n return (\n <Box sx={sx}>\n {(eyebrow || title || hint) ? (\n <Box sx={{ mb: 1.75 }}>\n {eyebrow ? (\n <Typography\n variant=\"overline\"\n sx={{ color: 'text.secondary', fontWeight: 800, letterSpacing: 1, lineHeight: 1, display: 'block' }}\n >\n {eyebrow}\n </Typography>\n ) : null}\n {title ? (\n <Typography variant=\"h6\" sx={{ fontWeight: 800, lineHeight: 1.25 }}>{title}</Typography>\n ) : null}\n {hint ? (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', mt: 0.5 }}>\n {hint}\n </Typography>\n ) : null}\n </Box>\n ) : null}\n {children}\n </Box>\n );\n}\nPmFormSection.propTypes = {\n eyebrow: PropTypes.node,\n title: PropTypes.node,\n hint: PropTypes.node,\n children: PropTypes.node,\n sx: PropTypes.object,\n};\n"],"mappings":"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"}