@pisell/private-materials 6.3.220 → 6.3.222

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 (125) hide show
  1. package/build/lowcode/assets-daily.json +11 -11
  2. package/build/lowcode/assets-dev.json +2 -2
  3. package/build/lowcode/assets-prod.json +11 -11
  4. package/build/lowcode/meta.js +1 -1
  5. package/build/lowcode/render/default/view.css +1 -1
  6. package/build/lowcode/render/default/view.js +13 -13
  7. package/build/lowcode/view.css +1 -1
  8. package/build/lowcode/view.js +13 -13
  9. package/es/components/kioskSkuDetail/index.js +7 -7
  10. package/es/components/pay/toC/PaymentMethods/MWCreditCard/tds2.js +53 -26
  11. package/es/components/scanOrder/components/Content/index.js +14 -2
  12. package/es/components/scanOrder/components/ExitConfirmModal/index.js +84 -0
  13. package/es/components/scanOrder/components/ExitConfirmModal/index.less +182 -0
  14. package/es/components/scanOrder/locales.js +20 -0
  15. package/es/index.d.ts +9 -1
  16. package/es/index.js +6 -2
  17. package/es/plus/inventory/BindingModal.js +94 -0
  18. package/es/plus/inventory/InventoryItemManagement.d.ts +7 -0
  19. package/es/plus/inventory/InventoryItemManagement.js +204 -0
  20. package/es/plus/inventory/InventoryLocationManagement.d.ts +7 -0
  21. package/es/plus/inventory/InventoryLocationManagement.js +296 -0
  22. package/es/plus/inventory/InventoryUnitManagement.d.ts +7 -0
  23. package/es/plus/inventory/InventoryUnitManagement.js +144 -0
  24. package/es/plus/inventory/ItemDrawer.js +266 -0
  25. package/es/plus/inventory/RecordDialog.js +141 -0
  26. package/es/plus/inventory/StockList.js +132 -0
  27. package/es/plus/inventory/api.js +66 -0
  28. package/es/plus/inventory/components.js +172 -0
  29. package/es/plus/inventory/context.js +118 -0
  30. package/es/plus/inventory/forms.js +46 -0
  31. package/es/plus/inventory/hooks.js +235 -0
  32. package/es/plus/inventory/index.less +559 -0
  33. package/es/plus/inventory/locales.js +277 -0
  34. package/es/plus/inventory/types.d.ts +10 -0
  35. package/es/plus/inventory/utils.js +24 -0
  36. package/es/plus/panpacificTask/JobCard.js +22 -0
  37. package/es/plus/panpacificTask/JobDrawer.js +366 -0
  38. package/es/plus/panpacificTask/JobForm.js +312 -0
  39. package/es/plus/panpacificTask/JobStatus.js +29 -0
  40. package/es/plus/panpacificTask/PanpacificTask.d.ts +7 -0
  41. package/es/plus/panpacificTask/PanpacificTask.js +552 -0
  42. package/es/plus/panpacificTask/PhotoPreview.js +37 -0
  43. package/es/plus/panpacificTask/README.md +114 -0
  44. package/es/plus/panpacificTask/attachments.js +64 -0
  45. package/es/plus/panpacificTask/index.d.ts +2 -0
  46. package/es/plus/panpacificTask/index.less +539 -0
  47. package/es/plus/panpacificTask/locales.js +586 -0
  48. package/es/plus/panpacificTask/model.js +260 -0
  49. package/es/plus/panpacificTask/saveJob.js +68 -0
  50. package/es/plus/panpacificTask/serve.js +243 -0
  51. package/es/plus/panpacificTask/tenant.js +16 -0
  52. package/es/plus/panpacificTask/types.d.ts +19 -0
  53. package/es/plus/pisellReservation/data/bookingToReservationTables.js +1 -1
  54. package/es/plus/pisellReservation/floorMap/floorPlanApi.js +1 -1
  55. package/es/plus/pisellReservation/floorMap/reservationMock.js +1 -1
  56. package/es/plus/pisellSupersetDashboard/README.md +291 -0
  57. package/es/plus/pisellSupersetDashboard/index.d.ts +15 -0
  58. package/es/plus/pisellSupersetDashboard/index.js +187 -0
  59. package/es/plus/pisellSupersetDashboard/index.less +83 -0
  60. package/es/plus/pisellSupersetDashboard/locales.js +36 -0
  61. package/es/plus/pisellSupersetDashboard/serve.js +51 -0
  62. package/es/plus/pisellSupersetDashboard/types.d.ts +17 -0
  63. package/es/plus/skuOptionsSelection/store/createStore.js +2 -2
  64. package/es/private-materials/lowcode/authmodal/meta.d.ts +1 -0
  65. package/es/pro/Login2.0/AuthModal.d.ts +1 -1
  66. package/es/pro/Login2.0/index.d.ts +1 -2
  67. package/es/pro/Login2.0/shared/types.d.ts +1 -1
  68. package/lib/components/kioskSkuDetail/index.js +7 -7
  69. package/lib/components/pay/toC/PaymentMethods/MWCreditCard/tds2.js +53 -26
  70. package/lib/components/scanOrder/components/Content/index.js +14 -2
  71. package/lib/components/scanOrder/components/ExitConfirmModal/index.js +86 -0
  72. package/lib/components/scanOrder/components/ExitConfirmModal/index.less +182 -0
  73. package/lib/components/scanOrder/locales.js +20 -0
  74. package/lib/index.d.ts +9 -1
  75. package/lib/index.js +136 -126
  76. package/lib/plus/inventory/BindingModal.js +96 -0
  77. package/lib/plus/inventory/InventoryItemManagement.d.ts +7 -0
  78. package/lib/plus/inventory/InventoryItemManagement.js +206 -0
  79. package/lib/plus/inventory/InventoryLocationManagement.d.ts +7 -0
  80. package/lib/plus/inventory/InventoryLocationManagement.js +298 -0
  81. package/lib/plus/inventory/InventoryUnitManagement.d.ts +7 -0
  82. package/lib/plus/inventory/InventoryUnitManagement.js +146 -0
  83. package/lib/plus/inventory/ItemDrawer.js +268 -0
  84. package/lib/plus/inventory/RecordDialog.js +143 -0
  85. package/lib/plus/inventory/StockList.js +134 -0
  86. package/lib/plus/inventory/api.js +66 -0
  87. package/lib/plus/inventory/components.js +181 -0
  88. package/lib/plus/inventory/context.js +121 -0
  89. package/lib/plus/inventory/forms.js +50 -0
  90. package/lib/plus/inventory/hooks.js +240 -0
  91. package/lib/plus/inventory/index.less +559 -0
  92. package/lib/plus/inventory/locales.js +277 -0
  93. package/lib/plus/inventory/types.d.ts +10 -0
  94. package/lib/plus/inventory/utils.js +30 -0
  95. package/lib/plus/panpacificTask/JobCard.js +24 -0
  96. package/lib/plus/panpacificTask/JobDrawer.js +368 -0
  97. package/lib/plus/panpacificTask/JobForm.js +314 -0
  98. package/lib/plus/panpacificTask/JobStatus.js +33 -0
  99. package/lib/plus/panpacificTask/PanpacificTask.d.ts +7 -0
  100. package/lib/plus/panpacificTask/PanpacificTask.js +555 -0
  101. package/lib/plus/panpacificTask/PhotoPreview.js +39 -0
  102. package/lib/plus/panpacificTask/README.md +114 -0
  103. package/lib/plus/panpacificTask/attachments.js +66 -0
  104. package/lib/plus/panpacificTask/index.d.ts +2 -0
  105. package/lib/plus/panpacificTask/index.less +539 -0
  106. package/lib/plus/panpacificTask/locales.js +586 -0
  107. package/lib/plus/panpacificTask/model.js +289 -0
  108. package/lib/plus/panpacificTask/saveJob.js +68 -0
  109. package/lib/plus/panpacificTask/serve.js +260 -0
  110. package/lib/plus/panpacificTask/tenant.js +17 -0
  111. package/lib/plus/panpacificTask/types.d.ts +19 -0
  112. package/lib/plus/pisellSupersetDashboard/README.md +291 -0
  113. package/lib/plus/pisellSupersetDashboard/index.d.ts +15 -0
  114. package/lib/plus/pisellSupersetDashboard/index.js +189 -0
  115. package/lib/plus/pisellSupersetDashboard/index.less +83 -0
  116. package/lib/plus/pisellSupersetDashboard/locales.js +36 -0
  117. package/lib/plus/pisellSupersetDashboard/serve.js +52 -0
  118. package/lib/plus/pisellSupersetDashboard/types.d.ts +17 -0
  119. package/lowcode/inventory-item-management/meta.ts +20 -0
  120. package/lowcode/inventory-location-management/meta.ts +20 -0
  121. package/lowcode/inventory-unit-management/meta.ts +20 -0
  122. package/lowcode/panpacific-task/meta.ts +51 -0
  123. package/lowcode/pisell-superset-dashboard/meta.ts +75 -0
  124. package/package.json +4 -2
  125. package/es/plus/pisellReservation/index.js +0 -17
@@ -0,0 +1,366 @@
1
+ import { _objectSpread2 } from "../../_virtual/_@oxc-project_runtime@0.122.0/helpers/objectSpread2.js";
2
+ import { _asyncToGenerator } from "../../_virtual/_@oxc-project_runtime@0.122.0/helpers/asyncToGenerator.js";
3
+ import { attachments, preparePhoto } from "./attachments.js";
4
+ import { dateText, draftFor, jobLineGroups, jobLineText, nextStatus, paymentTerm, scheduleText, statusPayload, statuses } from "./model.js";
5
+ import { createJobPayment, createJobPickupPhoto, errorText, getJobDetail, getJobRelated, removeJob, removeJobPickupPhoto, updateJob } from "./serve.js";
6
+ import { JobForm } from "./JobForm.js";
7
+ import { PhotoPreview } from "./PhotoPreview.js";
8
+ import { JobStatus } from "./JobStatus.js";
9
+ import React, { useEffect, useRef, useState } from "react";
10
+ import { Alert, Button, Drawer, Dropdown, Input, InputNumber, Radio, Spin } from "antd";
11
+ import { CloseOutlined } from "@ant-design/icons";
12
+ //#region src/plus/panpacificTask/JobDrawer.tsx
13
+ function JobDrawer({ id, request, jobs, base, getText, uploadPhoto, confirm, onClose, onChanged, onDuplicate, startEditing }) {
14
+ var _base$categories$find, _related$photos, _related$payments;
15
+ const [job, setJob] = useState();
16
+ const [related, setRelated] = useState({});
17
+ const [loading, setLoading] = useState(true);
18
+ const [editing, setEditing] = useState(!!startEditing);
19
+ const [busy, setBusy] = useState(false);
20
+ const [error, setError] = useState("");
21
+ const [recordUncertain, setRecordUncertain] = useState(false);
22
+ const locked = useRef(false);
23
+ const formRef = useRef(null);
24
+ const [direction, setDirection] = useState("payment");
25
+ const [amount, setAmount] = useState(null);
26
+ const [reference, setReference] = useState("");
27
+ const [photo, setPhoto] = useState();
28
+ const pendingPhoto = useRef();
29
+ const mounted = useRef(true);
30
+ const sequence = useRef(0);
31
+ const dirtyPayment = !!amount || !!reference || !!photo;
32
+ const refresh = function() {
33
+ var _ref = _asyncToGenerator(function* () {
34
+ const token = ++sequence.current;
35
+ setLoading(true);
36
+ try {
37
+ const result = yield getJobDetail(request, id);
38
+ if (!mounted.current || token !== sequence.current) return;
39
+ setJob(result);
40
+ const records = yield getJobRelated(request, id);
41
+ if (mounted.current && token === sequence.current) setRelated((previous) => {
42
+ var _records$photos, _records$payments;
43
+ return {
44
+ photos: (_records$photos = records.photos) !== null && _records$photos !== void 0 ? _records$photos : previous.photos,
45
+ payments: (_records$payments = records.payments) !== null && _records$payments !== void 0 ? _records$payments : previous.payments
46
+ };
47
+ });
48
+ } catch (cause) {
49
+ console.warn("[PanpacificTask] Detail load failed", cause);
50
+ } finally {
51
+ if (mounted.current && token === sequence.current) setLoading(false);
52
+ }
53
+ });
54
+ return function refresh() {
55
+ return _ref.apply(this, arguments);
56
+ };
57
+ }();
58
+ useEffect(() => {
59
+ mounted.current = true;
60
+ refresh();
61
+ return () => {
62
+ mounted.current = false;
63
+ sequence.current++;
64
+ };
65
+ }, [id, request]);
66
+ const close = function() {
67
+ var _ref2 = _asyncToGenerator(function* () {
68
+ if (locked.current) return;
69
+ if (editing && job) {
70
+ var _formRef$current;
71
+ (_formRef$current = formRef.current) === null || _formRef$current === void 0 || _formRef$current.close();
72
+ return;
73
+ }
74
+ if (dirtyPayment && !(yield confirm("discardConfirm"))) return;
75
+ onClose();
76
+ });
77
+ return function close() {
78
+ return _ref2.apply(this, arguments);
79
+ };
80
+ }();
81
+ const run = function() {
82
+ var _ref3 = _asyncToGenerator(function* (operation) {
83
+ if (locked.current) return;
84
+ locked.current = true;
85
+ setBusy(true);
86
+ setError("");
87
+ try {
88
+ yield operation();
89
+ } catch (cause) {
90
+ if (mounted.current) {
91
+ if (cause === null || cause === void 0 ? void 0 : cause.uncertainCreate) setRecordUncertain(true);
92
+ setError((cause === null || cause === void 0 ? void 0 : cause.uncertainCreate) ? getText("pisell2.panpacific.task.uncertain") : getText(errorText(cause)));
93
+ }
94
+ } finally {
95
+ locked.current = false;
96
+ if (mounted.current) setBusy(false);
97
+ }
98
+ });
99
+ return function run(_x) {
100
+ return _ref3.apply(this, arguments);
101
+ };
102
+ }();
103
+ const mark = (status) => run(_asyncToGenerator(function* () {
104
+ if (status === "cancel" && !(yield confirm("cancelConfirm"))) return;
105
+ if (!job) return;
106
+ yield updateJob(request, id, statusPayload(job, status));
107
+ onChanged(id);
108
+ yield refresh();
109
+ }));
110
+ const remove = () => run(_asyncToGenerator(function* () {
111
+ if (!(yield confirm("removeConfirm"))) return;
112
+ yield removeJob(request, id);
113
+ onChanged(id);
114
+ onClose();
115
+ }));
116
+ const section = (title, children) => /* @__PURE__ */ React.createElement("section", { className: "pp-task-section" }, /* @__PURE__ */ React.createElement("h3", null, getText(`pisell2.panpacific.task.${title}`)), children);
117
+ const details = (rows) => /* @__PURE__ */ React.createElement("dl", { className: "pp-task-details" }, rows.map(([key, value]) => /* @__PURE__ */ React.createElement("div", { key }, /* @__PURE__ */ React.createElement("dt", null, getText(`pisell2.panpacific.task.${key}`)), /* @__PURE__ */ React.createElement("dd", null, value || "—"))));
118
+ const groups = jobLineGroups(job || {});
119
+ const lines = (kind, status) => {
120
+ const rows = groups[kind][status];
121
+ return rows.length ? /* @__PURE__ */ React.createElement("ul", { className: "pp-task-item-summary" }, rows.map((row, i) => {
122
+ var _row$id;
123
+ return /* @__PURE__ */ React.createElement("li", { key: String((_row$id = row.id) !== null && _row$id !== void 0 ? _row$id : i) }, jobLineText(row, kind, base));
124
+ })) : "—";
125
+ };
126
+ const chooseFile = (event, receipt) => {
127
+ var _event$target$files;
128
+ const file = (_event$target$files = event.target.files) === null || _event$target$files === void 0 ? void 0 : _event$target$files[0];
129
+ event.target.value = "";
130
+ if (!file) return;
131
+ run(_asyncToGenerator(function* () {
132
+ const image = yield uploadPhoto(preparePhoto(file));
133
+ if (!attachments(image).length) throw new Error("pisell2.panpacific.task.uploadFailed");
134
+ if (receipt) {
135
+ if (mounted.current) setPhoto(image);
136
+ } else {
137
+ pendingPhoto.current = image;
138
+ yield savePickup(image);
139
+ }
140
+ }));
141
+ };
142
+ const savePickup = function() {
143
+ var _ref4 = _asyncToGenerator(function* (image) {
144
+ const prefix = `${String((job === null || job === void 0 ? void 0 : job.job_number) || id).replace(/[^a-zA-Z0-9]+/g, "_")}_pickup_`;
145
+ const next = (related.photos || []).reduce((max, row) => {
146
+ const suffix = String(row.name || "").startsWith(prefix) ? row.name.slice(prefix.length) : "";
147
+ return /^\d+$/.test(suffix) ? Math.max(max, Number(suffix)) : max;
148
+ }, 0) + 1;
149
+ yield createJobPickupPhoto(request, {
150
+ job_id: id,
151
+ name: prefix + (related.photos ? String(next).padStart(2, "0") : String(Date.now())),
152
+ photo: image
153
+ });
154
+ pendingPhoto.current = void 0;
155
+ yield refresh();
156
+ onChanged(id);
157
+ });
158
+ return function savePickup(_x2) {
159
+ return _ref4.apply(this, arguments);
160
+ };
161
+ }();
162
+ const savePayment = () => run(_asyncToGenerator(function* () {
163
+ if (recordUncertain) return;
164
+ if (!amount || !/^\d+(\.\d{1,2})?$/.test(amount) || Number(amount) <= 0 || Number(amount) >= 0xe8d4a51000) throw new Error("pisell2.panpacific.task.invalidAmount");
165
+ yield createJobPayment(request, {
166
+ job_id: id,
167
+ direction,
168
+ amount,
169
+ ref_number: reference.trim() || null,
170
+ photo: photo || null
171
+ });
172
+ if (mounted.current) {
173
+ setAmount(null);
174
+ setReference("");
175
+ setPhoto(void 0);
176
+ }
177
+ yield refresh();
178
+ onChanged(id);
179
+ }));
180
+ const primary = job && nextStatus(job.status);
181
+ const menus = job ? [
182
+ ...statuses.filter((status) => status !== job.status && status !== primary && status !== "cancel").map((status) => ({
183
+ key: status,
184
+ label: `${getText("pisell2.panpacific.task.mark")} ${getText(`pisell2.panpacific.task.${status}`)}`
185
+ })),
186
+ ...job.status === "cancel" ? [] : [{
187
+ key: "cancel",
188
+ label: getText("pisell2.panpacific.task.cancelJob")
189
+ }],
190
+ {
191
+ key: "duplicate",
192
+ label: getText("pisell2.panpacific.task.duplicate")
193
+ },
194
+ {
195
+ key: "remove",
196
+ label: getText("pisell2.panpacific.task.remove"),
197
+ danger: true
198
+ }
199
+ ] : [];
200
+ return /* @__PURE__ */ React.createElement(Drawer, {
201
+ open: true,
202
+ width: editing ? "min(820px, 96vw)" : "min(520px, 96vw)",
203
+ rootClassName: "pp-task-overlay pp-task-drawer",
204
+ closable: false,
205
+ destroyOnClose: true,
206
+ title: /* @__PURE__ */ React.createElement("div", null, editing ? getText("pisell2.panpacific.task.editJob") : (job === null || job === void 0 ? void 0 : job.supplier_name) || getText("pisell2.panpacific.task.job"), /* @__PURE__ */ React.createElement("small", null, job === null || job === void 0 ? void 0 : job.job_number)),
207
+ onClose: close,
208
+ extra: /* @__PURE__ */ React.createElement("div", { className: "pp-task-drawer-head-actions" }, !editing && job && /* @__PURE__ */ React.createElement(Button, {
209
+ type: "primary",
210
+ disabled: busy || loading,
211
+ onClick: _asyncToGenerator(function* () {
212
+ if (dirtyPayment && !(yield confirm("discardConfirm"))) return;
213
+ setAmount(null);
214
+ setReference("");
215
+ setPhoto(void 0);
216
+ setEditing(true);
217
+ })
218
+ }, getText("pisell2.panpacific.task.edit")), /* @__PURE__ */ React.createElement(Button, {
219
+ "aria-label": getText("pisell2.panpacific.task.close"),
220
+ icon: /* @__PURE__ */ React.createElement(CloseOutlined, null),
221
+ disabled: busy,
222
+ onClick: close
223
+ })),
224
+ footer: !editing && job && /* @__PURE__ */ React.createElement("div", { className: "pp-task-drawer-actions" }, primary && /* @__PURE__ */ React.createElement(Button, {
225
+ type: "primary",
226
+ loading: busy,
227
+ disabled: loading,
228
+ onClick: () => mark(primary)
229
+ }, getText("pisell2.panpacific.task.mark"), " ", getText(`pisell2.panpacific.task.${primary}`)), /* @__PURE__ */ React.createElement(Dropdown, {
230
+ trigger: ["click"],
231
+ disabled: busy || loading,
232
+ menu: {
233
+ items: menus,
234
+ onClick: function() {
235
+ var _ref5 = _asyncToGenerator(function* ({ key }) {
236
+ if (key === "remove") {
237
+ yield remove();
238
+ return;
239
+ }
240
+ if (key === "duplicate") {
241
+ if (dirtyPayment && !(yield confirm("discardConfirm"))) return;
242
+ onDuplicate(draftFor(job, void 0, true));
243
+ return;
244
+ }
245
+ yield mark(key);
246
+ });
247
+ return function onClick(_x3) {
248
+ return _ref5.apply(this, arguments);
249
+ };
250
+ }()
251
+ }
252
+ }, /* @__PURE__ */ React.createElement(Button, null, getText("pisell2.panpacific.task.more"), " ▾")))
253
+ }, /* @__PURE__ */ React.createElement(Spin, { spinning: loading }, !job && /* @__PURE__ */ React.createElement(Button, { onClick: refresh }, getText("pisell2.panpacific.task.refresh")), job && editing ? /* @__PURE__ */ React.createElement(JobForm, {
254
+ ref: formRef,
255
+ key: String(job.id),
256
+ initial: draftFor(job),
257
+ jobs,
258
+ base,
259
+ request,
260
+ getText,
261
+ confirmDiscard: () => confirm("discardConfirm"),
262
+ onCancel: () => setEditing(false),
263
+ onSaved: () => {
264
+ setEditing(false);
265
+ onChanged(id);
266
+ refresh();
267
+ }
268
+ }) : job && /* @__PURE__ */ React.createElement("div", { className: "pp-task-drawer-view" }, /* @__PURE__ */ React.createElement("div", { className: "pp-task-section pp-task-drawer-hero" }, /* @__PURE__ */ React.createElement(JobStatus, {
269
+ job,
270
+ getText
271
+ })), section("supplier", details([
272
+ ["state", job.supplier_state],
273
+ ["supplier", job.supplier_name],
274
+ ["branchPostcode", job.supplier_sub_name],
275
+ ["contact", job.company_contact],
276
+ ["phone", job.supplier_phone],
277
+ ["email", job.supplier_email],
278
+ ["lead", job.lead_source]
279
+ ])), section("basicInfo", details([
280
+ ["category", ((_base$categories$find = base.categories.find((row) => String(row.id) === String(job.task_category_id))) === null || _base$categories$find === void 0 ? void 0 : _base$categories$find.name) || job.task_category_id],
281
+ ["created", dateText(job.job_created_date)],
282
+ ["dateRange", scheduleText(job)],
283
+ ["due", dateText(job.due_date)],
284
+ ["pickupDate", dateText(job.pickup_date)],
285
+ ["invoiceDate", dateText(job.invoice_date)]
286
+ ])), section("logistics", details([["logisticType", job.logistic_type && getText(`pisell2.panpacific.task.${job.logistic_type}`)], ["logisticsNote", job.logistics_note]])), section("materials", details([["scheduledMaterials", lines("materials", "scheduled")], ["confirmedMaterials", lines("materials", "confirmed")]])), section("products", details([["scheduledItems", lines("products", "scheduled")], ["confirmedItems", lines("products", "confirmed")]])), section("paymentTerm", details([["paymentTerm", [paymentTerm(job, base), job.payment_term_days != null ? `${job.payment_term_days} ${getText("pisell2.panpacific.task.dayUnit")}` : ""].filter(Boolean).join(" · ")], ["termsNote", job.terms_note]])), section("pickupPhotos", /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "pp-task-photos" }, ((_related$photos = related.photos) === null || _related$photos === void 0 ? void 0 : _related$photos.length) ? related.photos.map((row) => /* @__PURE__ */ React.createElement(PhotoPreview, {
287
+ key: String(row.id),
288
+ value: row.photo,
289
+ label: row.name,
290
+ getText,
291
+ disabled: busy || loading,
292
+ onRemove: (index) => run(_asyncToGenerator(function* () {
293
+ yield removeJobPickupPhoto(request, row, index);
294
+ const remaining = attachments(row.photo).filter((_, i) => i !== index);
295
+ if (mounted.current) setRelated((previous) => {
296
+ var _previous$photos;
297
+ return _objectSpread2(_objectSpread2({}, previous), {}, { photos: (_previous$photos = previous.photos) === null || _previous$photos === void 0 ? void 0 : _previous$photos.flatMap((item) => String(item.id) !== String(row.id) ? [item] : remaining.length ? [_objectSpread2(_objectSpread2({}, item), {}, { photo: remaining })] : []) });
298
+ });
299
+ onChanged(id);
300
+ yield refresh();
301
+ }))
302
+ })) : "—"), /* @__PURE__ */ React.createElement("label", { className: `pp-task-upload${busy || recordUncertain ? " is-disabled" : ""}` }, /* @__PURE__ */ React.createElement("input", {
303
+ type: "file",
304
+ accept: "image/*",
305
+ capture: "environment",
306
+ disabled: busy || recordUncertain,
307
+ onChange: (event) => chooseFile(event, false)
308
+ }), getText("pisell2.panpacific.task.uploadPickup")), pendingPhoto.current && !recordUncertain && /* @__PURE__ */ React.createElement(Button, {
309
+ disabled: busy,
310
+ onClick: () => run(() => savePickup(pendingPhoto.current))
311
+ }, getText("pisell2.panpacific.task.save")))), section("records", /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "pp-task-payment-records" }, ((_related$payments = related.payments) === null || _related$payments === void 0 ? void 0 : _related$payments.length) ? related.payments.map((row) => /* @__PURE__ */ React.createElement("div", { key: String(row.id) }, /* @__PURE__ */ React.createElement("strong", null, getText(`pisell2.panpacific.task.${row.direction === "receive" ? "receive" : "payment"}`), " ", "· $", row.amount), row.ref_number && /* @__PURE__ */ React.createElement("span", null, " · ", row.ref_number), /* @__PURE__ */ React.createElement("small", null, row.created_at && dateText(row.created_at), " ", row.operator_name), /* @__PURE__ */ React.createElement("div", { className: "pp-task-photos" }, /* @__PURE__ */ React.createElement(PhotoPreview, {
312
+ value: row.photo,
313
+ getText
314
+ })))) : "—"), /* @__PURE__ */ React.createElement("p", { className: "pp-task-payment-caption" }, getText("pisell2.panpacific.task.createRecord")), /* @__PURE__ */ React.createElement(Radio.Group, {
315
+ value: direction,
316
+ disabled: busy || recordUncertain,
317
+ onChange: (event) => setDirection(event.target.value),
318
+ optionType: "button",
319
+ options: [{
320
+ label: getText("pisell2.panpacific.task.payment"),
321
+ value: "payment"
322
+ }, {
323
+ label: getText("pisell2.panpacific.task.receive"),
324
+ value: "receive"
325
+ }]
326
+ }), /* @__PURE__ */ React.createElement("div", { className: "pp-task-payment-inputs" }, photo ? /* @__PURE__ */ React.createElement("div", { className: "pp-task-photos pp-task-receipt-preview" }, /* @__PURE__ */ React.createElement(PhotoPreview, {
327
+ value: photo,
328
+ compact: true,
329
+ getText,
330
+ disabled: busy || recordUncertain,
331
+ onRemove: () => setPhoto(void 0)
332
+ })) : /* @__PURE__ */ React.createElement("label", { className: `pp-task-upload${busy || recordUncertain ? " is-disabled" : ""}` }, /* @__PURE__ */ React.createElement("input", {
333
+ type: "file",
334
+ accept: "image/*",
335
+ disabled: busy || recordUncertain,
336
+ onChange: (event) => chooseFile(event, true)
337
+ }), getText("pisell2.panpacific.task.photo")), /* @__PURE__ */ React.createElement(InputNumber, {
338
+ stringMode: true,
339
+ min: "0.01",
340
+ max: "999999999999.99",
341
+ precision: 2,
342
+ value: amount,
343
+ onChange: setAmount,
344
+ placeholder: getText("pisell2.panpacific.task.amount"),
345
+ "aria-label": getText("pisell2.panpacific.task.amount"),
346
+ disabled: busy || recordUncertain
347
+ }), /* @__PURE__ */ React.createElement(Input, {
348
+ value: reference,
349
+ maxLength: 255,
350
+ onChange: (event) => setReference(event.target.value),
351
+ placeholder: getText("pisell2.panpacific.task.reference"),
352
+ "aria-label": getText("pisell2.panpacific.task.reference"),
353
+ disabled: busy || recordUncertain
354
+ })), /* @__PURE__ */ React.createElement(Button, {
355
+ type: "primary",
356
+ loading: busy,
357
+ disabled: recordUncertain,
358
+ onClick: savePayment
359
+ }, getText("pisell2.panpacific.task.saveRecord")))), error && /* @__PURE__ */ React.createElement(Alert, {
360
+ type: "error",
361
+ showIcon: true,
362
+ message: error
363
+ }))));
364
+ }
365
+ //#endregion
366
+ export { JobDrawer };
@@ -0,0 +1,312 @@
1
+ import { _objectSpread2 } from "../../_virtual/_@oxc-project_runtime@0.122.0/helpers/objectSpread2.js";
2
+ import { _asyncToGenerator } from "../../_virtual/_@oxc-project_runtime@0.122.0/helpers/asyncToGenerator.js";
3
+ import useEngineContext from "../../hooks/useEngineContext.js";
4
+ import { newLine, nextJobCode, sessionFor, supplierSnapshot } from "./model.js";
5
+ import { errorText } from "./serve.js";
6
+ import { getCurrentTenantId } from "./tenant.js";
7
+ import { saveJob } from "./saveJob.js";
8
+ import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react";
9
+ import { Alert, Button, DatePicker, Form, Input, InputNumber, Select } from "antd";
10
+ import { CloseOutlined } from "@ant-design/icons";
11
+ //#region src/plus/panpacificTask/JobForm.tsx
12
+ const popupContainer = (trigger) => trigger.closest(".pp-task-overlay .ant-modal-body, .pp-task-overlay .ant-drawer-body, .pp-task-overlay .pisell-lowcode-modal-body, .pp-task-overlay .pisell-lowcode-drawer-body") || trigger.parentElement;
13
+ const selectProps = {
14
+ size: "small",
15
+ allowClear: true,
16
+ showSearch: true,
17
+ optionFilterProp: "label",
18
+ getPopupContainer: popupContainer
19
+ };
20
+ function optionsFor(rows, current, label) {
21
+ const options = rows.filter((row) => row.is_active !== false && row.is_active !== 0 || String(row.id) === String(current)).map((row) => ({
22
+ value: current != null && String(row.id) === String(current) ? current : row.id,
23
+ label: String(row.name || row.title || row.description || row.id)
24
+ }));
25
+ if (current != null && !options.some((option) => String(option.value) === String(current))) options.push({
26
+ value: current,
27
+ label: label || String(current)
28
+ });
29
+ return options;
30
+ }
31
+ const JobForm = forwardRef(({ initial, jobs, base, request, getText, onSaved, onCancel, confirmDiscard }, ref) => {
32
+ const context = useEngineContext();
33
+ const [form] = Form.useForm();
34
+ const session = useRef(sessionFor(initial));
35
+ const manualCode = useRef(Boolean(initial.job_number));
36
+ const dirty = useRef(false);
37
+ const saving = useRef(false);
38
+ const [busy, setBusy] = useState(false);
39
+ const [error, setError] = useState("");
40
+ const [uncertain, setUncertain] = useState(false);
41
+ const mounted = useRef(true);
42
+ useEffect(() => {
43
+ mounted.current = true;
44
+ return () => {
45
+ mounted.current = false;
46
+ };
47
+ }, []);
48
+ const close = function() {
49
+ var _ref = _asyncToGenerator(function* () {
50
+ if (saving.current) return;
51
+ if (dirty.current && !(yield confirmDiscard())) return;
52
+ onCancel();
53
+ });
54
+ return function close() {
55
+ return _ref.apply(this, arguments);
56
+ };
57
+ }();
58
+ useImperativeHandle(ref, () => ({ close }));
59
+ const syncCode = () => {
60
+ if (!manualCode.current && !saving.current) form.setFieldValue("job_number", nextJobCode(form.getFieldValue("supplier_state"), form.getFieldValue("supplier_name"), jobs));
61
+ };
62
+ useEffect(syncCode, [jobs]);
63
+ const change = (changed) => {
64
+ var _changed$job_number;
65
+ dirty.current = true;
66
+ if ("job_number" in changed) manualCode.current = !!((_changed$job_number = changed.job_number) === null || _changed$job_number === void 0 ? void 0 : _changed$job_number.trim());
67
+ if ("supplier_id" in changed) {
68
+ const supplier = base.suppliers.find((row) => String(row.id) === String(changed.supplier_id));
69
+ if (supplier) form.setFieldsValue(supplierSnapshot(supplier));
70
+ }
71
+ if ("payment_term_id" in changed) {
72
+ const term = base.paymentTerms.find((row) => String(row.id) === String(changed.payment_term_id));
73
+ form.setFieldValue("payment_term_days", (term === null || term === void 0 ? void 0 : term.days) == null ? null : Number(term.days));
74
+ }
75
+ if ([
76
+ "supplier_id",
77
+ "supplier_name",
78
+ "supplier_state",
79
+ "job_number"
80
+ ].some((key) => key in changed)) syncCode();
81
+ };
82
+ const save = function() {
83
+ var _ref2 = _asyncToGenerator(function* (values) {
84
+ if (saving.current || uncertain) return;
85
+ saving.current = true;
86
+ setBusy(true);
87
+ setError("");
88
+ try {
89
+ var _context$appHelper;
90
+ const tenantId = getCurrentTenantId(context === null || context === void 0 || (_context$appHelper = context.appHelper) === null || _context$appHelper === void 0 || (_context$appHelper = _context$appHelper.utils) === null || _context$appHelper === void 0 ? void 0 : _context$appHelper.store);
91
+ const id = yield saveJob(request, values, session.current, tenantId);
92
+ dirty.current = false;
93
+ if (mounted.current) onSaved(id, values);
94
+ } catch (cause) {
95
+ manualCode.current = session.current.id != null || manualCode.current;
96
+ if (mounted.current) {
97
+ setUncertain(!!session.current.uncertain);
98
+ setError([
99
+ session.current.id != null ? getText("pisell2.panpacific.task.partialSave") : "",
100
+ getText(errorText(cause)),
101
+ session.current.uncertain ? getText("pisell2.panpacific.task.uncertain") : ""
102
+ ].filter(Boolean).join(" "));
103
+ }
104
+ } finally {
105
+ saving.current = false;
106
+ if (mounted.current) setBusy(false);
107
+ }
108
+ });
109
+ return function save(_x) {
110
+ return _ref2.apply(this, arguments);
111
+ };
112
+ }();
113
+ const text = (name, label, required = false, max = 255) => /* @__PURE__ */ React.createElement(Form.Item, {
114
+ key: name,
115
+ name,
116
+ label: getText(`pisell2.panpacific.task.${label}`),
117
+ rules: [{
118
+ required,
119
+ message: getText("pisell2.panpacific.task.required")
120
+ }]
121
+ }, /* @__PURE__ */ React.createElement(Input, { maxLength: max }));
122
+ const date = (name, label, required = false) => /* @__PURE__ */ React.createElement(Form.Item, {
123
+ key: name,
124
+ name,
125
+ label: getText(`pisell2.panpacific.task.${label}`),
126
+ rules: [{
127
+ required,
128
+ message: getText("pisell2.panpacific.task.required")
129
+ }]
130
+ }, /* @__PURE__ */ React.createElement(DatePicker, {
131
+ format: "YYYY-MM-DD",
132
+ style: { width: "100%" },
133
+ getPopupContainer: popupContainer
134
+ }));
135
+ const select = (name, label, rows) => /* @__PURE__ */ React.createElement(Form.Item, {
136
+ key: name,
137
+ noStyle: true,
138
+ shouldUpdate: true
139
+ }, () => /* @__PURE__ */ React.createElement(Form.Item, {
140
+ name,
141
+ label: getText(`pisell2.panpacific.task.${label}`)
142
+ }, /* @__PURE__ */ React.createElement(Select, _objectSpread2(_objectSpread2({}, selectProps), {}, { options: optionsFor(rows, form.getFieldValue(name), name === "supplier_id" ? form.getFieldValue("supplier_name") : void 0) }))));
143
+ const enumField = (name, label, values) => /* @__PURE__ */ React.createElement(Form.Item, {
144
+ key: name,
145
+ name,
146
+ label: getText(`pisell2.panpacific.task.${label}`)
147
+ }, /* @__PURE__ */ React.createElement(Select, _objectSpread2(_objectSpread2({}, selectProps), {}, { options: values.map((value) => ({
148
+ value,
149
+ label: name === "supplier_state" ? value : getText(`pisell2.panpacific.task.${value}`)
150
+ })) })));
151
+ const section = (title, children) => /* @__PURE__ */ React.createElement("section", {
152
+ key: title,
153
+ className: "pp-task-section"
154
+ }, /* @__PURE__ */ React.createElement("h3", null, getText(`pisell2.panpacific.task.${title}`)), children);
155
+ const lines = (kind) => /* @__PURE__ */ React.createElement(Form.List, {
156
+ key: kind,
157
+ name: kind
158
+ }, (fields, { add, remove }) => /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "pp-task-lines-scroll" }, /* @__PURE__ */ React.createElement("div", { className: "pp-task-lines" }, /* @__PURE__ */ React.createElement("div", { className: "pp-task-line-head" }, [
159
+ "item",
160
+ "quantity",
161
+ "unit",
162
+ "price",
163
+ "status",
164
+ ""
165
+ ].map((key, i) => /* @__PURE__ */ React.createElement("span", { key: i }, key && getText(`pisell2.panpacific.task.${key}`)))), fields.map((field) => /* @__PURE__ */ React.createElement("div", {
166
+ className: "pp-task-line-wrap",
167
+ key: field.key
168
+ }, /* @__PURE__ */ React.createElement(Form.Item, {
169
+ name: [field.name, "_key"],
170
+ hidden: true
171
+ }, /* @__PURE__ */ React.createElement(Input, null)), /* @__PURE__ */ React.createElement("div", { className: "pp-task-line" }, /* @__PURE__ */ React.createElement(Form.Item, {
172
+ noStyle: true,
173
+ shouldUpdate: true
174
+ }, () => {
175
+ const relation = kind === "materials" ? "material_item_id" : "product_id";
176
+ const snapshot = kind === "materials" ? "material_name" : "product_name";
177
+ const current = form.getFieldValue([
178
+ kind,
179
+ field.name,
180
+ relation
181
+ ]);
182
+ return /* @__PURE__ */ React.createElement(Form.Item, {
183
+ name: [field.name, relation],
184
+ rules: [{
185
+ required: kind === "materials",
186
+ message: getText("pisell2.panpacific.task.required")
187
+ }]
188
+ }, /* @__PURE__ */ React.createElement(Select, _objectSpread2(_objectSpread2({}, selectProps), {}, {
189
+ placeholder: getText("pisell2.panpacific.task.item"),
190
+ options: optionsFor(base[kind], current, form.getFieldValue([
191
+ kind,
192
+ field.name,
193
+ snapshot
194
+ ])),
195
+ onChange: (id) => {
196
+ const item = base[kind].find((row) => String(row.id) === String(id));
197
+ form.setFieldValue([
198
+ kind,
199
+ field.name,
200
+ snapshot
201
+ ], (item === null || item === void 0 ? void 0 : item.name) || "");
202
+ }
203
+ })));
204
+ }), /* @__PURE__ */ React.createElement(Form.Item, {
205
+ name: [field.name, "quantity"],
206
+ rules: [{
207
+ required: kind === "materials",
208
+ message: getText("pisell2.panpacific.task.required")
209
+ }]
210
+ }, /* @__PURE__ */ React.createElement(InputNumber, {
211
+ stringMode: true,
212
+ min: "0",
213
+ max: "999999999999.99",
214
+ precision: 2,
215
+ placeholder: getText("pisell2.panpacific.task.quantity")
216
+ })), /* @__PURE__ */ React.createElement(Form.Item, { name: [field.name, "price_unit"] }, /* @__PURE__ */ React.createElement(Select, _objectSpread2(_objectSpread2({}, selectProps), {}, {
217
+ allowClear: false,
218
+ showSearch: false,
219
+ options: ["piece", "kg"].map((value) => ({
220
+ value,
221
+ label: getText(`pisell2.panpacific.task.${value}`)
222
+ }))
223
+ }))), /* @__PURE__ */ React.createElement(Form.Item, { name: [field.name, "unit_price"] }, /* @__PURE__ */ React.createElement(InputNumber, {
224
+ stringMode: true,
225
+ min: "0",
226
+ max: "999999999999.99",
227
+ precision: 2,
228
+ placeholder: getText("pisell2.panpacific.task.price")
229
+ })), /* @__PURE__ */ React.createElement(Form.Item, { name: [field.name, "item_status"] }, /* @__PURE__ */ React.createElement(Select, _objectSpread2(_objectSpread2({}, selectProps), {}, {
230
+ allowClear: false,
231
+ showSearch: false,
232
+ options: ["scheduled", "confirmed"].map((value) => ({
233
+ value,
234
+ label: getText(`pisell2.panpacific.task.${value}`)
235
+ }))
236
+ }))), /* @__PURE__ */ React.createElement(Button, {
237
+ "aria-label": getText("pisell2.panpacific.task.removeLine"),
238
+ icon: /* @__PURE__ */ React.createElement(CloseOutlined, null),
239
+ onClick: () => {
240
+ dirty.current = true;
241
+ remove(field.name);
242
+ }
243
+ })))))), /* @__PURE__ */ React.createElement(Button, {
244
+ block: true,
245
+ onClick: () => {
246
+ dirty.current = true;
247
+ add(newLine());
248
+ }
249
+ }, "+ ", getText("pisell2.panpacific.task.addItem"))));
250
+ return /* @__PURE__ */ React.createElement(Form, {
251
+ className: "pp-task-form",
252
+ form,
253
+ layout: "vertical",
254
+ size: "middle",
255
+ initialValues: initial,
256
+ disabled: busy || uncertain,
257
+ onValuesChange: change,
258
+ onFinish: save,
259
+ scrollToFirstError: true
260
+ }, section("basicInfo", /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "pp-task-form-grid" }, select("task_category_id", "category", base.categories), date("job_created_date", "created", true), date("due_date", "due", true), date("pickup_date", "pickupDate"), enumField("logistic_type", "logisticType", [
261
+ "dropoff",
262
+ "pickup",
263
+ "walkin"
264
+ ])), /* @__PURE__ */ React.createElement(Form.Item, {
265
+ name: "logistics_note",
266
+ label: getText("pisell2.panpacific.task.logisticsNote")
267
+ }, /* @__PURE__ */ React.createElement(Input.TextArea, { autoSize: {
268
+ minRows: 2,
269
+ maxRows: 5
270
+ } })))), section("supplierInfo", /* @__PURE__ */ React.createElement("div", { className: "pp-task-form-grid" }, select("supplier_id", "supplier", base.suppliers), text("supplier_name", "supplierName"), enumField("supplier_state", "state", [
271
+ "QLD",
272
+ "NSW",
273
+ "VIC",
274
+ "SA",
275
+ "WA",
276
+ "TAS",
277
+ "NT",
278
+ "ACT"
279
+ ]), text("supplier_sub_name", "branchPostcode"), text("company_contact", "contact"), text("supplier_phone", "phone", false, 64), text("supplier_email", "email"), text("lead_source", "lead"), /* @__PURE__ */ React.createElement("div", { className: "pp-task-code" }, text("job_number", "code", true, 100), /* @__PURE__ */ React.createElement(Button, { onClick: () => {
280
+ manualCode.current = false;
281
+ dirty.current = true;
282
+ syncCode();
283
+ } }, getText("pisell2.panpacific.task.reset"))))), section("materials", lines("materials")), section("products", lines("products")), section("paymentTerm", /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "pp-task-form-grid" }, select("payment_term_id", "paymentTerm", base.paymentTerms), /* @__PURE__ */ React.createElement(Form.Item, {
284
+ name: "payment_term_days",
285
+ label: getText("pisell2.panpacific.task.days")
286
+ }, /* @__PURE__ */ React.createElement(InputNumber, {
287
+ min: 0,
288
+ max: 4294967295,
289
+ precision: 0
290
+ }))), /* @__PURE__ */ React.createElement(Form.Item, {
291
+ name: "terms_note",
292
+ label: getText("pisell2.panpacific.task.termsNote")
293
+ }, /* @__PURE__ */ React.createElement(Input.TextArea, { autoSize: {
294
+ minRows: 2,
295
+ maxRows: 5
296
+ } })))), /* @__PURE__ */ React.createElement("div", { className: "pp-task-form-footer" }, error && /* @__PURE__ */ React.createElement(Alert, {
297
+ type: "error",
298
+ message: error,
299
+ showIcon: true
300
+ }), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(Button, {
301
+ disabled: busy,
302
+ onClick: close
303
+ }, getText("pisell2.panpacific.task.cancelAction")), /* @__PURE__ */ React.createElement(Button, {
304
+ type: "primary",
305
+ htmlType: "submit",
306
+ loading: busy,
307
+ disabled: uncertain
308
+ }, getText(`pisell2.panpacific.task.${initial.id == null ? "createAction" : "save"}`)))));
309
+ });
310
+ JobForm.displayName = "PanpacificJobForm";
311
+ //#endregion
312
+ export { JobForm };