@rytass/bpm-core-react 0.17.7 → 0.17.9

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 (64) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/chunks/{compose-DjEJi5Dv.cjs → compose-Cock_B2Q.cjs} +2 -2
  3. package/dist/chunks/{compose-DjEJi5Dv.cjs.map → compose-Cock_B2Q.cjs.map} +1 -1
  4. package/dist/chunks/{compose-WekGZj74.js → compose-jnvnnVfN.js} +2 -2
  5. package/dist/chunks/{compose-WekGZj74.js.map → compose-jnvnnVfN.js.map} +1 -1
  6. package/dist/chunks/{designer-D87ILhjz.js → designer-B8Gvew_k.js} +6 -2
  7. package/dist/chunks/designer-B8Gvew_k.js.map +1 -0
  8. package/dist/chunks/{designer-DESS0CMl.cjs → designer-CAEFV1ve.cjs} +2 -2
  9. package/dist/chunks/designer-CAEFV1ve.cjs.map +1 -0
  10. package/dist/chunks/{detail-URwxkcro.js → detail-CExpbazF.js} +926 -873
  11. package/dist/chunks/detail-CExpbazF.js.map +1 -0
  12. package/dist/chunks/detail-DIY-L4i-.cjs +2 -0
  13. package/dist/chunks/detail-DIY-L4i-.cjs.map +1 -0
  14. package/dist/chunks/{orgs-Lg7tXv2u.js → orgs-8hje_l2n.js} +9 -4
  15. package/dist/chunks/orgs-8hje_l2n.js.map +1 -0
  16. package/dist/chunks/{orgs-C8usknWb.cjs → orgs-BeeDDWL1.cjs} +2 -2
  17. package/dist/chunks/orgs-BeeDDWL1.cjs.map +1 -0
  18. package/dist/chunks/users-O2L_M3BK.cjs +2 -0
  19. package/dist/chunks/users-O2L_M3BK.cjs.map +1 -0
  20. package/dist/chunks/{users-DRbuDYF1.js → users-Pl6hY5Y5.js} +160 -93
  21. package/dist/chunks/users-Pl6hY5Y5.js.map +1 -0
  22. package/dist/pages/admin/orgs/index.cjs +1 -1
  23. package/dist/pages/admin/orgs/index.js +1 -1
  24. package/dist/pages/admin/users/index.cjs +1 -1
  25. package/dist/pages/admin/users/index.js +1 -1
  26. package/dist/pages/instances/detail/index.cjs +1 -1
  27. package/dist/pages/instances/detail/index.js +1 -1
  28. package/dist/pages/templates/compose/index.cjs +1 -1
  29. package/dist/pages/templates/compose/index.js +1 -1
  30. package/dist/pages/templates/designer/index.cjs +1 -1
  31. package/dist/pages/templates/designer/index.js +1 -1
  32. package/dist/views/admin/index.cjs +1 -1
  33. package/dist/views/admin/index.js +2 -2
  34. package/dist/views/admin/orgs/index.cjs +1 -1
  35. package/dist/views/admin/orgs/index.js +1 -1
  36. package/dist/views/admin/users/index.cjs +1 -1
  37. package/dist/views/admin/users/index.js +1 -1
  38. package/dist/views/inbox/index.cjs +1 -1
  39. package/dist/views/inbox/index.cjs.map +1 -1
  40. package/dist/views/inbox/index.js +159 -78
  41. package/dist/views/inbox/index.js.map +1 -1
  42. package/dist/views/instances/detail/index.cjs +1 -1
  43. package/dist/views/instances/detail/index.js +1 -1
  44. package/dist/views/instances/detail/sections/InstanceFormSection.d.cts +9 -1
  45. package/dist/views/instances/detail/sections/InstanceFormSection.d.ts +9 -1
  46. package/dist/views/instances/detail/sections/InstanceTasksSection.d.cts +7 -0
  47. package/dist/views/instances/detail/sections/InstanceTasksSection.d.ts +7 -0
  48. package/dist/views/instances/detail/use-resubmit-comment-draft.d.cts +18 -0
  49. package/dist/views/instances/detail/use-resubmit-comment-draft.d.ts +18 -0
  50. package/dist/views/templates/compose/index.cjs +1 -1
  51. package/dist/views/templates/compose/index.js +1 -1
  52. package/dist/views/templates/designer/index.cjs +1 -1
  53. package/dist/views/templates/designer/index.js +1 -1
  54. package/package.json +3 -3
  55. package/dist/chunks/designer-D87ILhjz.js.map +0 -1
  56. package/dist/chunks/designer-DESS0CMl.cjs.map +0 -1
  57. package/dist/chunks/detail-D49NuNCn.cjs +0 -2
  58. package/dist/chunks/detail-D49NuNCn.cjs.map +0 -1
  59. package/dist/chunks/detail-URwxkcro.js.map +0 -1
  60. package/dist/chunks/orgs-C8usknWb.cjs.map +0 -1
  61. package/dist/chunks/orgs-Lg7tXv2u.js.map +0 -1
  62. package/dist/chunks/users-DRbuDYF1.js.map +0 -1
  63. package/dist/chunks/users-DVQicZIo.cjs +0 -2
  64. package/dist/chunks/users-DVQicZIo.cjs.map +0 -1
@@ -7,16 +7,21 @@ import { t as i } from "../../chunks/task-node-label-CWZgOBj0.js";
7
7
  import { useEffect as a, useMemo as o, useState as s } from "react";
8
8
  import { Badge as c, Button as l, PageHeader as u, Section as d, SectionGroup as f, Tab as p, TabItem as m, Table as h, Typography as g } from "@mezzanine-ui/react";
9
9
  import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
10
- import { listApprovalHistoryTasks as b, listInboxTasks as x, listTaskDecisions as S, readApprovalInstance as C, readApprovalInstanceCaseTitle as w } from "@rytass/bpm-core-client/workflow";
10
+ import { listApprovalHistoryTasks as b, listApprovalInstancesPage as x, listInboxTasks as ee, listTaskDecisions as S, readApprovalInstance as C, readApprovalInstanceCaseTitle as w } from "@rytass/bpm-core-client/workflow";
11
11
  import T from "@mezzanine-ui/react/ContentHeader";
12
12
  import { PlusIcon as E } from "@mezzanine-ui/icons";
13
13
  //#region src/views/inbox/InboxView.tsx
14
- function D() {
15
- let i = e(), S = r(), { member: C } = t(), w = C?.memberId ?? null, [D, A] = s("pending"), [j, M] = s(null), [N, P] = s([]), [I, R] = s(!0), [B, V] = s([]);
14
+ var D = 100, O = {
15
+ display: "grid",
16
+ gap: "var(--mzn-spacing-gap-base)",
17
+ marginBottom: "var(--mzn-spacing-padding-vertical-spacious)"
18
+ };
19
+ function k() {
20
+ let i = e(), x = r(), { member: S } = t(), C = S?.memberId ?? null, [w, D] = s("pending"), [k, M] = s(null), [N, P] = s([]), [F, I] = s(!0), [L, z] = s([]), [V, U] = s([]), [W, G] = s(!1);
16
21
  a(() => {
17
- w && Y();
18
- }, [w]);
19
- let H = o(() => [
22
+ C && ie();
23
+ }, [C]);
24
+ let K = o(() => [
20
25
  {
21
26
  dataIndex: "caseTitle",
22
27
  key: "caseTitle",
@@ -66,14 +71,35 @@ function D() {
66
71
  title: "建立時間",
67
72
  width: 220
68
73
  }
69
- ], []), U = o(() => ({
74
+ ], []), J = o(() => ({
70
75
  render: (e) => [{
71
76
  name: "處理",
72
- onClick: () => i.push(S.caseDetail(e.instanceId))
77
+ onClick: () => i.push(x.caseDetail(e.instanceId))
73
78
  }],
74
79
  variant: "base-secondary",
75
80
  width: 88
76
- }), [i, S]), G = o(() => [
81
+ }), [i, x]), Y = o(() => [{
82
+ dataIndex: "caseTitle",
83
+ key: "caseTitle",
84
+ title: "案件",
85
+ width: 280
86
+ }, {
87
+ key: "startedAt",
88
+ render: (e) => /* @__PURE__ */ v(g, {
89
+ component: "span",
90
+ variant: "body",
91
+ children: n(e.startedAt)
92
+ }),
93
+ title: "發起時間",
94
+ width: 220
95
+ }], []), X = o(() => ({
96
+ render: (e) => [{
97
+ name: "重新送出",
98
+ onClick: () => i.push(x.caseDetail(e.id))
99
+ }],
100
+ variant: "base-secondary",
101
+ width: 120
102
+ }), [i, x]), Z = o(() => [
77
103
  {
78
104
  dataIndex: "caseTitle",
79
105
  key: "caseTitle",
@@ -89,7 +115,7 @@ function D() {
89
115
  {
90
116
  key: "decisionLabel",
91
117
  render: (e) => /* @__PURE__ */ v(g, {
92
- color: F(e.decisionAction),
118
+ color: R(e.decisionAction),
93
119
  component: "span",
94
120
  variant: "body",
95
121
  children: e.decisionLabel
@@ -110,7 +136,7 @@ function D() {
110
136
  {
111
137
  key: "instanceStateLabel",
112
138
  render: (e) => /* @__PURE__ */ v(g, {
113
- color: L(e.instanceState),
139
+ color: B(e.instanceState),
114
140
  component: "span",
115
141
  variant: "body",
116
142
  children: e.instanceStateLabel
@@ -123,124 +149,179 @@ function D() {
123
149
  render: (e) => /* @__PURE__ */ v(g, {
124
150
  component: "span",
125
151
  variant: "body",
126
- children: z(e.decidedAt)
152
+ children: H(e.decidedAt)
127
153
  }),
128
154
  title: "簽核時間",
129
155
  width: 220
130
156
  }
131
- ], []), K = o(() => ({
157
+ ], []), Q = o(() => ({
132
158
  render: (e) => [{
133
159
  name: "查看",
134
- onClick: () => i.push(S.caseDetail(e.instanceId))
160
+ onClick: () => i.push(x.caseDetail(e.instanceId))
135
161
  }],
136
162
  variant: "base-secondary",
137
163
  width: 88
138
- }), [i, S]), q = o(() => N.filter((e) => e.instanceState === "RUNNING"), [N]);
139
- function J(e) {
140
- A(e === "history" || e === "pending" || e === "tracking" ? e : "pending");
164
+ }), [i, x]), $ = o(() => N.filter((e) => e.instanceState === "RUNNING"), [N]);
165
+ function re(e) {
166
+ D(e === "history" || e === "pending" || e === "tracking" ? e : "pending");
141
167
  }
142
- async function Y() {
143
- R(!0), M(null);
168
+ async function ie() {
169
+ I(!0), M(null);
144
170
  try {
145
- if (!w) {
146
- V([]), P([]);
171
+ if (!C) {
172
+ z([]), P([]), U([]), G(!1);
147
173
  return;
148
174
  }
149
- let [e, t] = await Promise.all([x(w), b(w)]), [n, r] = await Promise.all([O(e), k(t)]);
150
- V(n), P(r);
175
+ let [e, t, n] = await Promise.all([
176
+ ee(C),
177
+ b(C),
178
+ j(C)
179
+ ]), [r, i] = await Promise.all([te(e), ne(t)]);
180
+ z(r), P(i), U(n?.rows ?? []), G(n?.truncated ?? !1);
151
181
  } catch (e) {
152
- M(W(e));
182
+ M(q(e));
153
183
  } finally {
154
- R(!1);
184
+ I(!1);
155
185
  }
156
186
  }
157
187
  return /* @__PURE__ */ y(_, { children: [/* @__PURE__ */ v(u, { children: /* @__PURE__ */ v(T, {
158
- description: `目前以 ${C?.name ?? w ?? "目前登入會員"} 查詢待處理與歷史簽核任務。`,
188
+ description: `目前以 ${S?.name ?? C ?? "目前登入會員"} 查詢待處理與歷史簽核任務。`,
159
189
  title: "我的待簽",
160
190
  children: /* @__PURE__ */ v(l, {
161
191
  icon: E,
162
192
  iconType: "leading",
163
- onClick: () => i.push(S.caseNew()),
193
+ onClick: () => i.push(x.caseNew()),
164
194
  variant: "base-primary",
165
195
  children: "發起簽核"
166
196
  })
167
197
  }) }), /* @__PURE__ */ v(f, { children: /* @__PURE__ */ y(d, { children: [
168
- j ? /* @__PURE__ */ v(g, {
198
+ k ? /* @__PURE__ */ v(g, {
169
199
  color: "text-error",
170
200
  variant: "body",
171
- children: j
201
+ children: k
172
202
  }) : null,
173
203
  /* @__PURE__ */ y(p, {
174
- activeKey: D,
175
- onChange: J,
204
+ activeKey: w,
205
+ onChange: re,
176
206
  size: "sub",
177
207
  children: [
178
208
  /* @__PURE__ */ v(m, {
179
- badgeCount: I ? void 0 : B.length,
209
+ badgeCount: F ? void 0 : L.length,
180
210
  children: "待簽核"
181
211
  }, "pending"),
182
212
  /* @__PURE__ */ v(m, {
183
- badgeCount: I ? void 0 : q.length,
213
+ badgeCount: F ? void 0 : $.length,
184
214
  children: "已處理未結束"
185
215
  }, "tracking"),
186
216
  /* @__PURE__ */ v(m, { children: "歷史簽核記錄" }, "history")
187
217
  ]
188
218
  }),
189
- D === "pending" ? /* @__PURE__ */ v(h, {
190
- actions: U,
191
- columns: H,
192
- dataSource: B,
219
+ w === "pending" && (V.length > 0 || W) ? /* @__PURE__ */ y("div", {
220
+ "data-returned-instances": "",
221
+ style: O,
222
+ children: [
223
+ V.length > 0 ? /* @__PURE__ */ v(g, {
224
+ component: "h2",
225
+ variant: "label-primary",
226
+ children: "被退回待重送"
227
+ }) : null,
228
+ /* @__PURE__ */ v(g, {
229
+ color: "text-neutral",
230
+ variant: "caption",
231
+ children: A(V.length > 0, W)
232
+ }),
233
+ V.length > 0 ? /* @__PURE__ */ v(h, {
234
+ actions: X,
235
+ columns: Y,
236
+ dataSource: [...V],
237
+ fullWidth: !0
238
+ }) : null
239
+ ]
240
+ }) : null,
241
+ w === "pending" ? /* @__PURE__ */ v(h, {
242
+ actions: J,
243
+ columns: K,
244
+ dataSource: L,
193
245
  fullWidth: !0,
194
- loading: I
246
+ loading: F
195
247
  }) : null,
196
- D === "tracking" ? /* @__PURE__ */ v(h, {
197
- actions: K,
198
- columns: G,
199
- dataSource: q,
248
+ w === "tracking" ? /* @__PURE__ */ v(h, {
249
+ actions: Q,
250
+ columns: Z,
251
+ dataSource: $,
200
252
  fullWidth: !0,
201
- loading: I
253
+ loading: F
202
254
  }) : null,
203
- D === "history" ? /* @__PURE__ */ v(h, {
204
- actions: K,
205
- columns: G,
255
+ w === "history" ? /* @__PURE__ */ v(h, {
256
+ actions: Q,
257
+ columns: Z,
206
258
  dataSource: N,
207
259
  fullWidth: !0,
208
- loading: I
260
+ loading: F
209
261
  }) : null
210
262
  ] }) })] });
211
263
  }
212
- async function O(e) {
213
- let t = await A(e);
264
+ function A(e, t) {
265
+ return e ? t ? "你發起的案件被退回,請修改後重新送出。可能還有其他被退回的案件,請到「我發起的」查看。" : "你發起的案件被退回,請修改後重新送出。" : `前 ${D} 筆被退回的案件中沒有你發起的,可能還有其他被退回的案件,請到「我發起的」查看。`;
266
+ }
267
+ async function j(e) {
268
+ try {
269
+ let t = await x({
270
+ page: 1,
271
+ pageSize: D,
272
+ searchText: null,
273
+ state: "RETURNED",
274
+ templateId: null,
275
+ view: "SENT"
276
+ });
277
+ return {
278
+ rows: M(t.instances, e),
279
+ truncated: t.totalCount > t.instances.length
280
+ };
281
+ } catch {
282
+ return null;
283
+ }
284
+ }
285
+ function M(e, t) {
286
+ return e.filter((e) => e.initiatorMemberId === t).map((e) => ({
287
+ caseTitle: w(e),
288
+ id: e.id,
289
+ key: e.id,
290
+ startedAt: e.startedAt
291
+ }));
292
+ }
293
+ async function te(e) {
294
+ let t = await N(e);
214
295
  return e.map((e, n) => ({
215
296
  ...e,
216
- caseTitle: j(e, t[n] ?? null),
297
+ caseTitle: P(e, t[n] ?? null),
217
298
  key: e.id,
218
299
  nodeText: i(e),
219
- slaStatusColor: V(e.slaDueAt),
220
- slaStatusText: B(e.slaDueAt),
221
- statusLabel: U(e.status)
300
+ slaStatusColor: W(e.slaDueAt),
301
+ slaStatusText: U(e.slaDueAt),
302
+ statusLabel: K(e.status)
222
303
  }));
223
304
  }
224
- async function k(e) {
225
- let [t, n] = await Promise.all([Promise.all(e.map((e) => S(e.id))), A(e)]);
305
+ async function ne(e) {
306
+ let [t, n] = await Promise.all([Promise.all(e.map((e) => S(e.id))), N(e)]);
226
307
  return e.map((e, r) => {
227
- let a = M(t[r] ?? []), o = n[r] ?? null;
308
+ let a = F(t[r] ?? []), o = n[r] ?? null;
228
309
  return {
229
310
  ...e,
230
- caseTitle: j(e, o),
311
+ caseTitle: P(e, o),
231
312
  decisionAction: a?.action ?? null,
232
313
  decisionComment: a?.comment ?? null,
233
- decisionCommentText: R(a?.comment ?? null),
234
- decisionLabel: P(a?.action ?? null),
314
+ decisionCommentText: V(a?.comment ?? null),
315
+ decisionLabel: L(a?.action ?? null),
235
316
  decidedAt: a?.decidedAt ?? e.completedAt,
236
317
  instanceState: o?.state ?? null,
237
- instanceStateLabel: I(o?.state ?? null),
318
+ instanceStateLabel: z(o?.state ?? null),
238
319
  key: e.id,
239
320
  nodeText: i(e)
240
321
  };
241
322
  });
242
323
  }
243
- async function A(e) {
324
+ async function N(e) {
244
325
  return Promise.all(e.map(async (e) => {
245
326
  try {
246
327
  return (await C(e.instanceId)).instance;
@@ -249,52 +330,52 @@ async function A(e) {
249
330
  }
250
331
  }));
251
332
  }
252
- function j(e, t) {
333
+ function P(e, t) {
253
334
  return t ? w(t) : e.instanceId;
254
335
  }
255
- function M(e) {
256
- return [...e].sort(N)[0] ?? null;
336
+ function F(e) {
337
+ return [...e].sort(I)[0] ?? null;
257
338
  }
258
- function N(e, t) {
339
+ function I(e, t) {
259
340
  return new Date(t.decidedAt).getTime() - new Date(e.decidedAt).getTime();
260
341
  }
261
- function P(e) {
342
+ function L(e) {
262
343
  return e === "APPROVED" ? "同意" : e === "REJECTED" ? "拒絕" : e === "RETURNED" ? "退回" : e === "TRANSFERRED" ? "轉派" : "未記錄";
263
344
  }
264
- function F(e) {
345
+ function R(e) {
265
346
  return e === "APPROVED" ? "text-success" : e === "REJECTED" || e === "RETURNED" ? "text-error" : "text-neutral";
266
347
  }
267
- function I(e) {
348
+ function z(e) {
268
349
  return e === "RUNNING" ? "進行中" : e === "APPROVED" ? "已通過" : e === "REJECTED" ? "已拒絕" : e === "RETURNED" ? "已退回" : e === "CANCELLED" ? "已取消" : e === "EXPIRED" ? "已逾期" : e === "DRAFT" ? "草稿" : "-";
269
350
  }
270
- function L(e) {
351
+ function B(e) {
271
352
  return e === "APPROVED" ? "text-success" : e === "REJECTED" || e === "CANCELLED" || e === "EXPIRED" ? "text-error" : "text-neutral";
272
353
  }
273
- function R(e) {
354
+ function V(e) {
274
355
  return (e?.trim() ?? "") || "-";
275
356
  }
276
- function z(e) {
357
+ function H(e) {
277
358
  return n(e);
278
359
  }
279
- function B(e) {
360
+ function U(e) {
280
361
  if (!e) return "-";
281
- let t = new Date(e).getTime(), n = Date.now(), r = H(Math.abs(t - n));
362
+ let t = new Date(e).getTime(), n = Date.now(), r = G(Math.abs(t - n));
282
363
  return t < n ? `已逾期 ${r}` : `剩餘 ${r}`;
283
364
  }
284
- function V(e) {
365
+ function W(e) {
285
366
  return e ? new Date(e).getTime() < Date.now() ? "text-error" : "text-success" : "text-neutral";
286
367
  }
287
- function H(e) {
368
+ function G(e) {
288
369
  let t = Math.max(1, Math.ceil(e / 6e4)), n = Math.floor(t / 1440), r = Math.floor(t % 1440 / 60), i = t % 60;
289
370
  return n > 0 ? `${n}天 ${r}小時` : r > 0 ? `${r}小時 ${i}分鐘` : `${i}分鐘`;
290
371
  }
291
- function U(e) {
372
+ function K(e) {
292
373
  return e === "PENDING" ? "待處理" : e === "IN_PROGRESS" ? "處理中" : e === "COMPLETED" ? "已完成" : e === "TRANSFERRED" ? "已轉派" : e === "CANCELLED" ? "已取消" : e;
293
374
  }
294
- function W(e) {
375
+ function q(e) {
295
376
  return e instanceof Error ? e.message : "發生未知錯誤";
296
377
  }
297
378
  //#endregion
298
- export { D as InboxView };
379
+ export { k as InboxView };
299
380
 
300
381
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["_Fragment","useRouterAdapter","useAuth","formatDateTime","readTaskNodeText","Fragment$1","ContentHeader","InboxView","router","routes","useBPMRoutes","currentMemberId","member","activeTab","setActiveTab","useState","error","setError","historyRows","setHistoryRows","loading","setLoading","pendingRows","setPendingRows","refreshTasks","pendingColumns","useMemo","record","Badge","Typography","pendingTableActions","historyColumns","readTaskDecisionColor","readInstanceStateColor","formatHistoryDateTime","historyTableActions","trackingRows","row","handleTabChange","activeKey","nextPendingTasks","nextHistoryTasks","listInboxTasks","listApprovalHistoryTasks","nextPendingRows","nextHistoryRows","readInboxTaskRows","readApprovalHistoryRows","requestError","readErrorMessage","PageHeader","Button","PlusIcon","SectionGroup","Section","Tab","TabItem","Table","instances","readTaskInstances","tasks","task","readTaskCaseTitle","index","readSlaStatusColor","readSlaStatusText","readTaskStatusLabel","decisionLists","listTaskDecisions","decision","readLatestTaskDecision","instance","readDecisionCommentText","readTaskDecisionLabel","readInstanceStateLabel","readApprovalInstance","readApprovalInstanceCaseTitle","decisions","compareTaskDecisionDesc","right","left","action","state","comment","value","dueAt","now","label","formatDuration","totalMinutes","days","hours","minutes","status"],"sources":["../../../src/views/inbox/InboxView.tsx"],"sourcesContent":["'use client';\n\nimport { type Key, ReactElement, useEffect, useMemo, useState } from 'react';\nimport {\n Badge,\n Button,\n PageHeader,\n Section,\n SectionGroup,\n Tab,\n TabItem,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { PlusIcon } from '@mezzanine-ui/icons';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport {\n ApprovalInstanceRecord,\n listApprovalHistoryTasks,\n listInboxTasks,\n listTaskDecisions,\n readApprovalInstance,\n readApprovalInstanceCaseTitle,\n TaskDecisionRecord,\n TaskRecord,\n} from '@rytass/bpm-core-client/workflow';\nimport { formatDateTime } from '../../lib/format-date-time';\nimport { useAuth } from '../../lib/auth-provider';\nimport { readTaskNodeText } from '../../lib/task-node-label';\nimport { useRouterAdapter } from '../../lib/router-adapter';\nimport { useBPMRoutes } from '../../lib/routes-config';\n\ntype InboxTabKey = 'history' | 'pending' | 'tracking';\n\ntype InboxTaskRow = Readonly<\n Record<string, unknown> &\n TaskRecord & {\n caseTitle: string;\n key: string;\n nodeText: string;\n slaStatusColor: 'text-error' | 'text-neutral' | 'text-success';\n slaStatusText: string;\n statusLabel: string;\n }\n>;\n\ntype ApprovalHistoryRow = Readonly<\n Record<string, unknown> &\n TaskRecord & {\n caseTitle: string;\n decisionAction: TaskDecisionRecord['action'] | null;\n decisionComment: string | null;\n decisionCommentText: string;\n decisionLabel: string;\n decidedAt: string | null;\n instanceState: ApprovalInstanceRecord['state'] | null;\n instanceStateLabel: string;\n key: string;\n nodeText: string;\n }\n>;\n\n\n/**\n * Framework-agnostic view for the BPM \"我的待簽\" inbox. Mechanical port of\n * `apps/client/src/app/inbox/page.tsx` — renders pending tasks, tracking,\n * and history tabs.\n */\nexport function InboxView(): ReactElement {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const { member } = useAuth();\n const currentMemberId = member?.memberId ?? null;\n const [activeTab, setActiveTab] = useState<InboxTabKey>('pending');\n const [error, setError] = useState<string | null>(null);\n const [historyRows, setHistoryRows] = useState<ApprovalHistoryRow[]>([]);\n const [loading, setLoading] = useState(true);\n const [pendingRows, setPendingRows] = useState<InboxTaskRow[]>([]);\n\n useEffect((): void => {\n if (!currentMemberId) {\n return;\n }\n\n void refreshTasks();\n }, [currentMemberId]);\n\n const pendingColumns = useMemo(\n (): TableColumn<InboxTaskRow>[] => [\n { dataIndex: 'caseTitle', key: 'caseTitle', title: '案件', width: 280 },\n { dataIndex: 'nodeText', key: 'nodeText', title: '節點', width: 180 },\n {\n dataIndex: 'statusLabel',\n key: 'statusLabel',\n title: '狀態',\n width: 120,\n },\n {\n key: 'fill',\n // Approving one of these needs the case page, where the fill is entered.\n render: (record: InboxTaskRow): ReactElement | null =>\n record.hasFillableFields ? (\n <Badge size=\"sub\" text=\"需補填\" variant=\"dot-warning\" />\n ) : null,\n title: '補填',\n width: 120,\n },\n {\n key: 'slaDueAt',\n render: (record: InboxTaskRow): ReactElement => (\n <Typography\n color={record.slaStatusColor}\n component=\"span\"\n variant=\"body\"\n >\n {record.slaStatusText}\n </Typography>\n ),\n title: 'SLA',\n width: 180,\n },\n {\n key: 'createdAt',\n render: (record: InboxTaskRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {formatDateTime(record.createdAt)}\n </Typography>\n ),\n title: '建立時間',\n width: 220,\n },\n ],\n [],\n );\n const pendingTableActions = useMemo(\n (): TableActions<InboxTaskRow> => ({\n render: (record): ReturnType<TableActions<InboxTaskRow>['render']> => [\n {\n name: '處理',\n onClick: (): void => router.push(routes.caseDetail(record.instanceId)),\n },\n ],\n variant: 'base-secondary',\n width: 88,\n }),\n [router, routes],\n );\n const historyColumns = useMemo(\n (): TableColumn<ApprovalHistoryRow>[] => [\n { dataIndex: 'caseTitle', key: 'caseTitle', title: '案件', width: 280 },\n { dataIndex: 'nodeText', key: 'nodeText', title: '節點', width: 180 },\n {\n key: 'decisionLabel',\n render: (record: ApprovalHistoryRow): ReactElement => (\n <Typography\n color={readTaskDecisionColor(record.decisionAction)}\n component=\"span\"\n variant=\"body\"\n >\n {record.decisionLabel}\n </Typography>\n ),\n title: '決議',\n width: 120,\n },\n {\n key: 'decisionComment',\n render: (record: ApprovalHistoryRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {record.decisionCommentText}\n </Typography>\n ),\n title: '意見',\n width: 240,\n },\n {\n key: 'instanceStateLabel',\n render: (record: ApprovalHistoryRow): ReactElement => (\n <Typography\n color={readInstanceStateColor(record.instanceState)}\n component=\"span\"\n variant=\"body\"\n >\n {record.instanceStateLabel}\n </Typography>\n ),\n title: '流程狀態',\n width: 140,\n },\n {\n key: 'decidedAt',\n render: (record: ApprovalHistoryRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {formatHistoryDateTime(record.decidedAt)}\n </Typography>\n ),\n title: '簽核時間',\n width: 220,\n },\n ],\n [],\n );\n const historyTableActions = useMemo(\n (): TableActions<ApprovalHistoryRow> => ({\n render: (\n record,\n ): ReturnType<TableActions<ApprovalHistoryRow>['render']> => [\n {\n name: '查看',\n onClick: (): void => router.push(routes.caseDetail(record.instanceId)),\n },\n ],\n variant: 'base-secondary',\n width: 88,\n }),\n [router, routes],\n );\n const trackingRows = useMemo(\n (): ApprovalHistoryRow[] =>\n historyRows.filter((row) => row.instanceState === 'RUNNING'),\n [historyRows],\n );\n\n function handleTabChange(activeKey: Key): void {\n if (\n activeKey === 'history' ||\n activeKey === 'pending' ||\n activeKey === 'tracking'\n ) {\n setActiveTab(activeKey);\n return;\n }\n\n setActiveTab('pending');\n }\n\n async function refreshTasks(): Promise<void> {\n setLoading(true);\n setError(null);\n\n try {\n if (!currentMemberId) {\n setPendingRows([]);\n setHistoryRows([]);\n return;\n }\n\n const [nextPendingTasks, nextHistoryTasks] = await Promise.all([\n listInboxTasks(currentMemberId),\n listApprovalHistoryTasks(currentMemberId),\n ]);\n const [nextPendingRows, nextHistoryRows] = await Promise.all([\n readInboxTaskRows(nextPendingTasks),\n readApprovalHistoryRows(nextHistoryTasks),\n ]);\n\n setPendingRows(nextPendingRows);\n setHistoryRows(nextHistoryRows);\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description={`目前以 ${member?.name ?? currentMemberId ?? '目前登入會員'} 查詢待處理與歷史簽核任務。`}\n title=\"我的待簽\"\n >\n <Button\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={(): void => router.push(routes.caseNew())}\n variant=\"base-primary\"\n >\n 發起簽核\n </Button>\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n <Tab activeKey={activeTab} onChange={handleTabChange} size=\"sub\">\n <TabItem\n badgeCount={loading ? undefined : pendingRows.length}\n key=\"pending\"\n >\n 待簽核\n </TabItem>\n <TabItem\n badgeCount={loading ? undefined : trackingRows.length}\n key=\"tracking\"\n >\n 已處理未結束\n </TabItem>\n <TabItem key=\"history\">歷史簽核記錄</TabItem>\n </Tab>\n\n {activeTab === 'pending' ? (\n <Table\n actions={pendingTableActions}\n columns={pendingColumns}\n dataSource={pendingRows}\n fullWidth\n loading={loading}\n />\n ) : null}\n {activeTab === 'tracking' ? (\n <Table\n actions={historyTableActions}\n columns={historyColumns}\n dataSource={trackingRows}\n fullWidth\n loading={loading}\n />\n ) : null}\n {activeTab === 'history' ? (\n <Table\n actions={historyTableActions}\n columns={historyColumns}\n dataSource={historyRows}\n fullWidth\n loading={loading}\n />\n ) : null}\n </Section>\n </SectionGroup>\n </>\n );\n}\n\nasync function readInboxTaskRows(\n tasks: readonly TaskRecord[],\n): Promise<InboxTaskRow[]> {\n const instances = await readTaskInstances(tasks);\n\n return tasks.map(\n (task, index): InboxTaskRow => ({\n ...task,\n caseTitle: readTaskCaseTitle(task, instances[index] ?? null),\n key: task.id,\n nodeText: readTaskNodeText(task),\n slaStatusColor: readSlaStatusColor(task.slaDueAt),\n slaStatusText: readSlaStatusText(task.slaDueAt),\n statusLabel: readTaskStatusLabel(task.status),\n }),\n );\n}\n\nasync function readApprovalHistoryRows(\n tasks: readonly TaskRecord[],\n): Promise<ApprovalHistoryRow[]> {\n const [decisionLists, instances] = await Promise.all([\n Promise.all(tasks.map((task) => listTaskDecisions(task.id))),\n readTaskInstances(tasks),\n ]);\n\n return tasks.map((task, index): ApprovalHistoryRow => {\n const decision = readLatestTaskDecision(decisionLists[index] ?? []);\n const instance = instances[index] ?? null;\n\n return {\n ...task,\n caseTitle: readTaskCaseTitle(task, instance),\n decisionAction: decision?.action ?? null,\n decisionComment: decision?.comment ?? null,\n decisionCommentText: readDecisionCommentText(decision?.comment ?? null),\n decisionLabel: readTaskDecisionLabel(decision?.action ?? null),\n decidedAt: decision?.decidedAt ?? task.completedAt,\n instanceState: instance?.state ?? null,\n instanceStateLabel: readInstanceStateLabel(instance?.state ?? null),\n key: task.id,\n nodeText: readTaskNodeText(task),\n };\n });\n}\n\nasync function readTaskInstances(\n tasks: readonly TaskRecord[],\n): Promise<readonly (ApprovalInstanceRecord | null)[]> {\n return Promise.all(\n tasks.map(async (task): Promise<ApprovalInstanceRecord | null> => {\n try {\n return (await readApprovalInstance(task.instanceId)).instance;\n } catch {\n return null;\n }\n }),\n );\n}\n\nfunction readTaskCaseTitle(\n task: TaskRecord,\n instance: ApprovalInstanceRecord | null,\n): string {\n return instance ? readApprovalInstanceCaseTitle(instance) : task.instanceId;\n}\n\nfunction readLatestTaskDecision(\n decisions: readonly TaskDecisionRecord[],\n): TaskDecisionRecord | null {\n return [...decisions].sort(compareTaskDecisionDesc)[0] ?? null;\n}\n\nfunction compareTaskDecisionDesc(\n left: TaskDecisionRecord,\n right: TaskDecisionRecord,\n): number {\n return (\n new Date(right.decidedAt).getTime() - new Date(left.decidedAt).getTime()\n );\n}\n\nfunction readTaskDecisionLabel(\n action: TaskDecisionRecord['action'] | null,\n): string {\n if (action === 'APPROVED') {\n return '同意';\n }\n\n if (action === 'REJECTED') {\n return '拒絕';\n }\n\n if (action === 'RETURNED') {\n return '退回';\n }\n\n if (action === 'TRANSFERRED') {\n return '轉派';\n }\n\n return '未記錄';\n}\n\nfunction readTaskDecisionColor(\n action: TaskDecisionRecord['action'] | null,\n): 'text-error' | 'text-neutral' | 'text-success' {\n if (action === 'APPROVED') {\n return 'text-success';\n }\n\n if (action === 'REJECTED' || action === 'RETURNED') {\n return 'text-error';\n }\n\n return 'text-neutral';\n}\n\nfunction readInstanceStateLabel(\n state: ApprovalInstanceRecord['state'] | null,\n): string {\n if (state === 'RUNNING') {\n return '進行中';\n }\n\n if (state === 'APPROVED') {\n return '已通過';\n }\n\n if (state === 'REJECTED') {\n return '已拒絕';\n }\n\n if (state === 'RETURNED') {\n return '已退回';\n }\n\n if (state === 'CANCELLED') {\n return '已取消';\n }\n\n if (state === 'EXPIRED') {\n return '已逾期';\n }\n\n if (state === 'DRAFT') {\n return '草稿';\n }\n\n return '-';\n}\n\nfunction readInstanceStateColor(\n state: ApprovalInstanceRecord['state'] | null,\n): 'text-error' | 'text-neutral' | 'text-success' {\n if (state === 'APPROVED') {\n return 'text-success';\n }\n\n if (state === 'REJECTED' || state === 'CANCELLED' || state === 'EXPIRED') {\n return 'text-error';\n }\n\n return 'text-neutral';\n}\n\nfunction readDecisionCommentText(comment: string | null): string {\n const trimmedComment = comment?.trim() ?? '';\n\n return trimmedComment || '-';\n}\n\nfunction formatHistoryDateTime(value: string | null): string {\n return formatDateTime(value);\n}\n\nfunction readSlaStatusText(value: string | null): string {\n if (!value) {\n return '-';\n }\n\n const dueAt = new Date(value).getTime();\n const now = Date.now();\n const diffMs = Math.abs(dueAt - now);\n const label = formatDuration(diffMs);\n\n return dueAt < now ? `已逾期 ${label}` : `剩餘 ${label}`;\n}\n\nfunction readSlaStatusColor(\n value: string | null,\n): 'text-error' | 'text-neutral' | 'text-success' {\n if (!value) {\n return 'text-neutral';\n }\n\n return new Date(value).getTime() < Date.now() ? 'text-error' : 'text-success';\n}\n\nfunction formatDuration(value: number): string {\n const totalMinutes = Math.max(1, Math.ceil(value / 60_000));\n const days = Math.floor(totalMinutes / 1440);\n const hours = Math.floor((totalMinutes % 1440) / 60);\n const minutes = totalMinutes % 60;\n\n if (days > 0) {\n return `${days}天 ${hours}小時`;\n }\n\n if (hours > 0) {\n return `${hours}小時 ${minutes}分鐘`;\n }\n\n return `${minutes}分鐘`;\n}\n\nfunction readTaskStatusLabel(status: TaskRecord['status']): string {\n if (status === 'PENDING') {\n return '待處理';\n }\n\n if (status === 'IN_PROGRESS') {\n return '處理中';\n }\n\n if (status === 'COMPLETED') {\n return '已完成';\n }\n\n if (status === 'TRANSFERRED') {\n return '已轉派';\n }\n\n if (status === 'CANCELLED') {\n return '已取消';\n }\n\n return status;\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["_Fragment","useRouterAdapter","useAuth","formatDateTime","readTaskNodeText","Fragment$1","ContentHeader","RETURNED_INSTANCE_PAGE_SIZE","RETURNED_SECTION_STYLE","InboxView","router","routes","useBPMRoutes","currentMemberId","member","activeTab","setActiveTab","useState","error","setError","historyRows","setHistoryRows","loading","setLoading","pendingRows","setPendingRows","returnedRows","setReturnedRows","returnedTruncated","setReturnedTruncated","refreshTasks","pendingColumns","useMemo","record","Badge","Typography","pendingTableActions","returnedColumns","returnedTableActions","historyColumns","readTaskDecisionColor","readInstanceStateColor","formatHistoryDateTime","historyTableActions","trackingRows","row","handleTabChange","activeKey","nextPendingTasks","nextHistoryTasks","returned","listInboxTasks","listApprovalHistoryTasks","readReturnedInstances","nextPendingRows","nextHistoryRows","readInboxTaskRows","readApprovalHistoryRows","requestError","readErrorMessage","PageHeader","Button","PlusIcon","SectionGroup","Section","Tab","TabItem","readReturnedSectionHint","Table","hasRows","truncated","page","listApprovalInstancesPage","readReturnedInstanceRows","instances","instance","readApprovalInstanceCaseTitle","readTaskInstances","tasks","task","readTaskCaseTitle","index","readSlaStatusColor","readSlaStatusText","readTaskStatusLabel","decisionLists","listTaskDecisions","decision","readLatestTaskDecision","readDecisionCommentText","readTaskDecisionLabel","readInstanceStateLabel","readApprovalInstance","decisions","compareTaskDecisionDesc","right","left","action","state","comment","value","dueAt","now","label","formatDuration","totalMinutes","days","hours","minutes","status"],"sources":["../../../src/views/inbox/InboxView.tsx"],"sourcesContent":["'use client';\n\nimport {\n type CSSProperties,\n type Key,\n ReactElement,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport {\n Badge,\n Button,\n PageHeader,\n Section,\n SectionGroup,\n Tab,\n TabItem,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { PlusIcon } from '@mezzanine-ui/icons';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport {\n ApprovalInstanceRecord,\n type ApprovalInstancesPageResult,\n listApprovalHistoryTasks,\n listApprovalInstancesPage,\n listInboxTasks,\n listTaskDecisions,\n readApprovalInstance,\n readApprovalInstanceCaseTitle,\n TaskDecisionRecord,\n TaskRecord,\n} from '@rytass/bpm-core-client/workflow';\nimport { formatDateTime } from '../../lib/format-date-time';\nimport { useAuth } from '../../lib/auth-provider';\nimport { readTaskNodeText } from '../../lib/task-node-label';\nimport { useRouterAdapter } from '../../lib/router-adapter';\nimport { useBPMRoutes } from '../../lib/routes-config';\n\ntype InboxTabKey = 'history' | 'pending' | 'tracking';\n\ntype InboxTaskRow = Readonly<\n Record<string, unknown> &\n TaskRecord & {\n caseTitle: string;\n key: string;\n nodeText: string;\n slaStatusColor: 'text-error' | 'text-neutral' | 'text-success';\n slaStatusText: string;\n statusLabel: string;\n }\n>;\n\ntype ReturnedInstanceRow = Readonly<{\n caseTitle: string;\n id: string;\n key: string;\n startedAt: string | null;\n}>;\n\n/** The server caps a page at 100; more than that is left to 我發起的. */\nconst RETURNED_INSTANCE_PAGE_SIZE = 100;\n\nconst RETURNED_SECTION_STYLE: CSSProperties = {\n display: 'grid',\n gap: 'var(--mzn-spacing-gap-base)',\n marginBottom: 'var(--mzn-spacing-padding-vertical-spacious)',\n};\n\ntype ApprovalHistoryRow = Readonly<\n Record<string, unknown> &\n TaskRecord & {\n caseTitle: string;\n decisionAction: TaskDecisionRecord['action'] | null;\n decisionComment: string | null;\n decisionCommentText: string;\n decisionLabel: string;\n decidedAt: string | null;\n instanceState: ApprovalInstanceRecord['state'] | null;\n instanceStateLabel: string;\n key: string;\n nodeText: string;\n }\n>;\n\n\n/**\n * Framework-agnostic view for the BPM \"我的待簽\" inbox. Mechanical port of\n * `apps/client/src/app/inbox/page.tsx` — renders pending tasks, tracking,\n * and history tabs.\n */\nexport function InboxView(): ReactElement {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const { member } = useAuth();\n const currentMemberId = member?.memberId ?? null;\n const [activeTab, setActiveTab] = useState<InboxTabKey>('pending');\n const [error, setError] = useState<string | null>(null);\n const [historyRows, setHistoryRows] = useState<ApprovalHistoryRow[]>([]);\n const [loading, setLoading] = useState(true);\n const [pendingRows, setPendingRows] = useState<InboxTaskRow[]>([]);\n const [returnedRows, setReturnedRows] = useState<\n readonly ReturnedInstanceRow[]\n >([]);\n const [returnedTruncated, setReturnedTruncated] = useState(false);\n\n useEffect((): void => {\n if (!currentMemberId) {\n return;\n }\n\n void refreshTasks();\n }, [currentMemberId]);\n\n const pendingColumns = useMemo(\n (): TableColumn<InboxTaskRow>[] => [\n { dataIndex: 'caseTitle', key: 'caseTitle', title: '案件', width: 280 },\n { dataIndex: 'nodeText', key: 'nodeText', title: '節點', width: 180 },\n {\n dataIndex: 'statusLabel',\n key: 'statusLabel',\n title: '狀態',\n width: 120,\n },\n {\n key: 'fill',\n // Approving one of these needs the case page, where the fill is entered.\n render: (record: InboxTaskRow): ReactElement | null =>\n record.hasFillableFields ? (\n <Badge size=\"sub\" text=\"需補填\" variant=\"dot-warning\" />\n ) : null,\n title: '補填',\n width: 120,\n },\n {\n key: 'slaDueAt',\n render: (record: InboxTaskRow): ReactElement => (\n <Typography\n color={record.slaStatusColor}\n component=\"span\"\n variant=\"body\"\n >\n {record.slaStatusText}\n </Typography>\n ),\n title: 'SLA',\n width: 180,\n },\n {\n key: 'createdAt',\n render: (record: InboxTaskRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {formatDateTime(record.createdAt)}\n </Typography>\n ),\n title: '建立時間',\n width: 220,\n },\n ],\n [],\n );\n const pendingTableActions = useMemo(\n (): TableActions<InboxTaskRow> => ({\n render: (record): ReturnType<TableActions<InboxTaskRow>['render']> => [\n {\n name: '處理',\n onClick: (): void => router.push(routes.caseDetail(record.instanceId)),\n },\n ],\n variant: 'base-secondary',\n width: 88,\n }),\n [router, routes],\n );\n const returnedColumns = useMemo(\n (): TableColumn<ReturnedInstanceRow>[] => [\n { dataIndex: 'caseTitle', key: 'caseTitle', title: '案件', width: 280 },\n {\n key: 'startedAt',\n render: (record: ReturnedInstanceRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {formatDateTime(record.startedAt)}\n </Typography>\n ),\n title: '發起時間',\n width: 220,\n },\n ],\n [],\n );\n const returnedTableActions = useMemo(\n (): TableActions<ReturnedInstanceRow> => ({\n render: (\n record,\n ): ReturnType<TableActions<ReturnedInstanceRow>['render']> => [\n {\n name: '重新送出',\n onClick: (): void => router.push(routes.caseDetail(record.id)),\n },\n ],\n variant: 'base-secondary',\n width: 120,\n }),\n [router, routes],\n );\n const historyColumns = useMemo(\n (): TableColumn<ApprovalHistoryRow>[] => [\n { dataIndex: 'caseTitle', key: 'caseTitle', title: '案件', width: 280 },\n { dataIndex: 'nodeText', key: 'nodeText', title: '節點', width: 180 },\n {\n key: 'decisionLabel',\n render: (record: ApprovalHistoryRow): ReactElement => (\n <Typography\n color={readTaskDecisionColor(record.decisionAction)}\n component=\"span\"\n variant=\"body\"\n >\n {record.decisionLabel}\n </Typography>\n ),\n title: '決議',\n width: 120,\n },\n {\n key: 'decisionComment',\n render: (record: ApprovalHistoryRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {record.decisionCommentText}\n </Typography>\n ),\n title: '意見',\n width: 240,\n },\n {\n key: 'instanceStateLabel',\n render: (record: ApprovalHistoryRow): ReactElement => (\n <Typography\n color={readInstanceStateColor(record.instanceState)}\n component=\"span\"\n variant=\"body\"\n >\n {record.instanceStateLabel}\n </Typography>\n ),\n title: '流程狀態',\n width: 140,\n },\n {\n key: 'decidedAt',\n render: (record: ApprovalHistoryRow): ReactElement => (\n <Typography component=\"span\" variant=\"body\">\n {formatHistoryDateTime(record.decidedAt)}\n </Typography>\n ),\n title: '簽核時間',\n width: 220,\n },\n ],\n [],\n );\n const historyTableActions = useMemo(\n (): TableActions<ApprovalHistoryRow> => ({\n render: (\n record,\n ): ReturnType<TableActions<ApprovalHistoryRow>['render']> => [\n {\n name: '查看',\n onClick: (): void => router.push(routes.caseDetail(record.instanceId)),\n },\n ],\n variant: 'base-secondary',\n width: 88,\n }),\n [router, routes],\n );\n const trackingRows = useMemo(\n (): ApprovalHistoryRow[] =>\n historyRows.filter((row) => row.instanceState === 'RUNNING'),\n [historyRows],\n );\n\n function handleTabChange(activeKey: Key): void {\n if (\n activeKey === 'history' ||\n activeKey === 'pending' ||\n activeKey === 'tracking'\n ) {\n setActiveTab(activeKey);\n return;\n }\n\n setActiveTab('pending');\n }\n\n async function refreshTasks(): Promise<void> {\n setLoading(true);\n setError(null);\n\n try {\n if (!currentMemberId) {\n setPendingRows([]);\n setHistoryRows([]);\n setReturnedRows([]);\n setReturnedTruncated(false);\n return;\n }\n\n const [nextPendingTasks, nextHistoryTasks, returned] =\n await Promise.all([\n listInboxTasks(currentMemberId),\n listApprovalHistoryTasks(currentMemberId),\n readReturnedInstances(currentMemberId),\n ]);\n const [nextPendingRows, nextHistoryRows] = await Promise.all([\n readInboxTaskRows(nextPendingTasks),\n readApprovalHistoryRows(nextHistoryTasks),\n ]);\n\n setPendingRows(nextPendingRows);\n setHistoryRows(nextHistoryRows);\n setReturnedRows(returned?.rows ?? []);\n setReturnedTruncated(returned?.truncated ?? false);\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description={`目前以 ${member?.name ?? currentMemberId ?? '目前登入會員'} 查詢待處理與歷史簽核任務。`}\n title=\"我的待簽\"\n >\n <Button\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={(): void => router.push(routes.caseNew())}\n variant=\"base-primary\"\n >\n 發起簽核\n </Button>\n </ContentHeader>\n </PageHeader>\n\n <SectionGroup>\n <Section>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n <Tab activeKey={activeTab} onChange={handleTabChange} size=\"sub\">\n <TabItem\n badgeCount={loading ? undefined : pendingRows.length}\n key=\"pending\"\n >\n 待簽核\n </TabItem>\n <TabItem\n badgeCount={loading ? undefined : trackingRows.length}\n key=\"tracking\"\n >\n 已處理未結束\n </TabItem>\n <TabItem key=\"history\">歷史簽核記錄</TabItem>\n </Tab>\n\n {/* A truncated page with none of the member's own cases still\n points to 我發起的: theirs may sit past the first page. */}\n {activeTab === 'pending' &&\n (returnedRows.length > 0 || returnedTruncated) ? (\n <div data-returned-instances=\"\" style={RETURNED_SECTION_STYLE}>\n {/* Without rows there is nothing here to resubmit, only the\n pointer to 我發起的. */}\n {returnedRows.length > 0 ? (\n <Typography component=\"h2\" variant=\"label-primary\">\n 被退回待重送\n </Typography>\n ) : null}\n <Typography color=\"text-neutral\" variant=\"caption\">\n {readReturnedSectionHint(\n returnedRows.length > 0,\n returnedTruncated,\n )}\n </Typography>\n {returnedRows.length > 0 ? (\n <Table\n actions={returnedTableActions}\n columns={returnedColumns}\n dataSource={[...returnedRows]}\n fullWidth\n />\n ) : null}\n </div>\n ) : null}\n {activeTab === 'pending' ? (\n <Table\n actions={pendingTableActions}\n columns={pendingColumns}\n dataSource={pendingRows}\n fullWidth\n loading={loading}\n />\n ) : null}\n {activeTab === 'tracking' ? (\n <Table\n actions={historyTableActions}\n columns={historyColumns}\n dataSource={trackingRows}\n fullWidth\n loading={loading}\n />\n ) : null}\n {activeTab === 'history' ? (\n <Table\n actions={historyTableActions}\n columns={historyColumns}\n dataSource={historyRows}\n fullWidth\n loading={loading}\n />\n ) : null}\n </Section>\n </SectionGroup>\n </>\n );\n}\n\nfunction readReturnedSectionHint(\n hasRows: boolean,\n truncated: boolean,\n): string {\n if (!hasRows) {\n return `前 ${RETURNED_INSTANCE_PAGE_SIZE} 筆被退回的案件中沒有你發起的,可能還有其他被退回的案件,請到「我發起的」查看。`;\n }\n\n return truncated\n ? '你發起的案件被退回,請修改後重新送出。可能還有其他被退回的案件,請到「我發起的」查看。'\n : '你發起的案件被退回,請修改後重新送出。';\n}\n\n/**\n * Returned cases are a side list: a failure here, in the request or in reading\n * its rows, hides that section instead of taking the pending and history tasks\n * down with it.\n */\nasync function readReturnedInstances(\n currentMemberId: string,\n): Promise<Readonly<{\n rows: readonly ReturnedInstanceRow[];\n truncated: boolean;\n}> | null> {\n try {\n // SENT also lists cases filed on someone else's behalf; only the\n // initiator may resubmit, so those are filtered out here.\n const page: ApprovalInstancesPageResult = await listApprovalInstancesPage({\n page: 1,\n pageSize: RETURNED_INSTANCE_PAGE_SIZE,\n searchText: null,\n state: 'RETURNED',\n templateId: null,\n view: 'SENT',\n });\n\n return {\n rows: readReturnedInstanceRows(page.instances, currentMemberId),\n // The total includes cases filed for someone else, so compare it with\n // what this page fetched rather than with the rows kept.\n truncated: page.totalCount > page.instances.length,\n };\n } catch {\n return null;\n }\n}\n\nfunction readReturnedInstanceRows(\n instances: readonly ApprovalInstanceRecord[],\n currentMemberId: string,\n): readonly ReturnedInstanceRow[] {\n return instances\n .filter(\n (instance): boolean => instance.initiatorMemberId === currentMemberId,\n )\n .map(\n (instance): ReturnedInstanceRow => ({\n caseTitle: readApprovalInstanceCaseTitle(instance),\n id: instance.id,\n key: instance.id,\n startedAt: instance.startedAt,\n }),\n );\n}\n\nasync function readInboxTaskRows(\n tasks: readonly TaskRecord[],\n): Promise<InboxTaskRow[]> {\n const instances = await readTaskInstances(tasks);\n\n return tasks.map(\n (task, index): InboxTaskRow => ({\n ...task,\n caseTitle: readTaskCaseTitle(task, instances[index] ?? null),\n key: task.id,\n nodeText: readTaskNodeText(task),\n slaStatusColor: readSlaStatusColor(task.slaDueAt),\n slaStatusText: readSlaStatusText(task.slaDueAt),\n statusLabel: readTaskStatusLabel(task.status),\n }),\n );\n}\n\nasync function readApprovalHistoryRows(\n tasks: readonly TaskRecord[],\n): Promise<ApprovalHistoryRow[]> {\n const [decisionLists, instances] = await Promise.all([\n Promise.all(tasks.map((task) => listTaskDecisions(task.id))),\n readTaskInstances(tasks),\n ]);\n\n return tasks.map((task, index): ApprovalHistoryRow => {\n const decision = readLatestTaskDecision(decisionLists[index] ?? []);\n const instance = instances[index] ?? null;\n\n return {\n ...task,\n caseTitle: readTaskCaseTitle(task, instance),\n decisionAction: decision?.action ?? null,\n decisionComment: decision?.comment ?? null,\n decisionCommentText: readDecisionCommentText(decision?.comment ?? null),\n decisionLabel: readTaskDecisionLabel(decision?.action ?? null),\n decidedAt: decision?.decidedAt ?? task.completedAt,\n instanceState: instance?.state ?? null,\n instanceStateLabel: readInstanceStateLabel(instance?.state ?? null),\n key: task.id,\n nodeText: readTaskNodeText(task),\n };\n });\n}\n\nasync function readTaskInstances(\n tasks: readonly TaskRecord[],\n): Promise<readonly (ApprovalInstanceRecord | null)[]> {\n return Promise.all(\n tasks.map(async (task): Promise<ApprovalInstanceRecord | null> => {\n try {\n return (await readApprovalInstance(task.instanceId)).instance;\n } catch {\n return null;\n }\n }),\n );\n}\n\nfunction readTaskCaseTitle(\n task: TaskRecord,\n instance: ApprovalInstanceRecord | null,\n): string {\n return instance ? readApprovalInstanceCaseTitle(instance) : task.instanceId;\n}\n\nfunction readLatestTaskDecision(\n decisions: readonly TaskDecisionRecord[],\n): TaskDecisionRecord | null {\n return [...decisions].sort(compareTaskDecisionDesc)[0] ?? null;\n}\n\nfunction compareTaskDecisionDesc(\n left: TaskDecisionRecord,\n right: TaskDecisionRecord,\n): number {\n return (\n new Date(right.decidedAt).getTime() - new Date(left.decidedAt).getTime()\n );\n}\n\nfunction readTaskDecisionLabel(\n action: TaskDecisionRecord['action'] | null,\n): string {\n if (action === 'APPROVED') {\n return '同意';\n }\n\n if (action === 'REJECTED') {\n return '拒絕';\n }\n\n if (action === 'RETURNED') {\n return '退回';\n }\n\n if (action === 'TRANSFERRED') {\n return '轉派';\n }\n\n return '未記錄';\n}\n\nfunction readTaskDecisionColor(\n action: TaskDecisionRecord['action'] | null,\n): 'text-error' | 'text-neutral' | 'text-success' {\n if (action === 'APPROVED') {\n return 'text-success';\n }\n\n if (action === 'REJECTED' || action === 'RETURNED') {\n return 'text-error';\n }\n\n return 'text-neutral';\n}\n\nfunction readInstanceStateLabel(\n state: ApprovalInstanceRecord['state'] | null,\n): string {\n if (state === 'RUNNING') {\n return '進行中';\n }\n\n if (state === 'APPROVED') {\n return '已通過';\n }\n\n if (state === 'REJECTED') {\n return '已拒絕';\n }\n\n if (state === 'RETURNED') {\n return '已退回';\n }\n\n if (state === 'CANCELLED') {\n return '已取消';\n }\n\n if (state === 'EXPIRED') {\n return '已逾期';\n }\n\n if (state === 'DRAFT') {\n return '草稿';\n }\n\n return '-';\n}\n\nfunction readInstanceStateColor(\n state: ApprovalInstanceRecord['state'] | null,\n): 'text-error' | 'text-neutral' | 'text-success' {\n if (state === 'APPROVED') {\n return 'text-success';\n }\n\n if (state === 'REJECTED' || state === 'CANCELLED' || state === 'EXPIRED') {\n return 'text-error';\n }\n\n return 'text-neutral';\n}\n\nfunction readDecisionCommentText(comment: string | null): string {\n const trimmedComment = comment?.trim() ?? '';\n\n return trimmedComment || '-';\n}\n\nfunction formatHistoryDateTime(value: string | null): string {\n return formatDateTime(value);\n}\n\nfunction readSlaStatusText(value: string | null): string {\n if (!value) {\n return '-';\n }\n\n const dueAt = new Date(value).getTime();\n const now = Date.now();\n const diffMs = Math.abs(dueAt - now);\n const label = formatDuration(diffMs);\n\n return dueAt < now ? `已逾期 ${label}` : `剩餘 ${label}`;\n}\n\nfunction readSlaStatusColor(\n value: string | null,\n): 'text-error' | 'text-neutral' | 'text-success' {\n if (!value) {\n return 'text-neutral';\n }\n\n return new Date(value).getTime() < Date.now() ? 'text-error' : 'text-success';\n}\n\nfunction formatDuration(value: number): string {\n const totalMinutes = Math.max(1, Math.ceil(value / 60_000));\n const days = Math.floor(totalMinutes / 1440);\n const hours = Math.floor((totalMinutes % 1440) / 60);\n const minutes = totalMinutes % 60;\n\n if (days > 0) {\n return `${days}天 ${hours}小時`;\n }\n\n if (hours > 0) {\n return `${hours}小時 ${minutes}分鐘`;\n }\n\n return `${minutes}分鐘`;\n}\n\nfunction readTaskStatusLabel(status: TaskRecord['status']): string {\n if (status === 'PENDING') {\n return '待處理';\n }\n\n if (status === 'IN_PROGRESS') {\n return '處理中';\n }\n\n if (status === 'COMPLETED') {\n return '已完成';\n }\n\n if (status === 'TRANSFERRED') {\n return '已轉派';\n }\n\n if (status === 'CANCELLED') {\n return '已取消';\n }\n\n return status;\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/detail-D49NuNCn.cjs");exports.InstanceAttachmentsSection=e.o,exports.InstanceDetailView=e.t,exports.InstanceFormSection=e.s,exports.InstanceHistorySection=e.r,exports.InstanceSignaturesSection=e.i,exports.InstanceTasksSection=e.a,exports.InstanceWebhookDeliveriesSection=e.n;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../../../chunks/detail-DIY-L4i-.cjs");exports.InstanceAttachmentsSection=e.o,exports.InstanceDetailView=e.t,exports.InstanceFormSection=e.s,exports.InstanceHistorySection=e.r,exports.InstanceSignaturesSection=e.i,exports.InstanceTasksSection=e.a,exports.InstanceWebhookDeliveriesSection=e.n;
@@ -1 +1 @@
1
- export { o as InstanceAttachmentsSection, t as InstanceDetailView, s as InstanceFormSection, r as InstanceHistorySection, i as InstanceSignaturesSection, a as InstanceTasksSection, n as InstanceWebhookDeliveriesSection } from "../../../chunks/detail-URwxkcro.js";
1
+ export { o as InstanceAttachmentsSection, t as InstanceDetailView, s as InstanceFormSection, r as InstanceHistorySection, i as InstanceSignaturesSection, a as InstanceTasksSection, n as InstanceWebhookDeliveriesSection } from "../../../chunks/detail-CExpbazF.js";
@@ -51,6 +51,14 @@ export interface InstanceFormSectionProps {
51
51
  readonly onDataSourceStateChange: (fieldKey: string, state: Pick<FormDataSourceFieldState, 'hasValue' | 'invalidValues' | 'status'>) => void;
52
52
  /** Called when the user clicks "重新送出". */
53
53
  readonly onResubmitInstance: () => void;
54
+ /**
55
+ * The applicant's comment for the resubmission. The comment box shows only
56
+ * when the case can be resubmitted (`canResubmitInstance`) and
57
+ * `onResubmitCommentChange` is given.
58
+ */
59
+ readonly resubmitComment?: string;
60
+ /** Called when the applicant edits the resubmission comment. */
61
+ readonly onResubmitCommentChange?: ((value: string) => void) | null;
54
62
  /** Called when an attachment upload is requested via the form field. */
55
63
  readonly onUploadAttachment: (field: FormFieldDefinition, file: File) => Promise<{
56
64
  readonly id: string;
@@ -61,4 +69,4 @@ export interface InstanceFormSectionProps {
61
69
  * Displays the form in read-only mode normally, or editable mode when the
62
70
  * instance has been returned and the current member can resubmit it.
63
71
  */
64
- export declare function InstanceFormSection({ canResubmitInstance, deciding, error, fieldAccess, fieldLabelMarkers, fill, instance, loading, onDataSourceStateChange, onResubmitFormChange, onReloadAfterConflict, onResubmitInstance, onUploadAttachment, resubmitFormData, resubmitFormErrors, }: InstanceFormSectionProps): ReactElement;
72
+ export declare function InstanceFormSection({ canResubmitInstance, deciding, error, fieldAccess, fieldLabelMarkers, fill, instance, loading, onDataSourceStateChange, onResubmitFormChange, onReloadAfterConflict, onResubmitCommentChange, onResubmitInstance, onUploadAttachment, resubmitComment, resubmitFormData, resubmitFormErrors, }: InstanceFormSectionProps): ReactElement;
@@ -51,6 +51,14 @@ export interface InstanceFormSectionProps {
51
51
  readonly onDataSourceStateChange: (fieldKey: string, state: Pick<FormDataSourceFieldState, 'hasValue' | 'invalidValues' | 'status'>) => void;
52
52
  /** Called when the user clicks "重新送出". */
53
53
  readonly onResubmitInstance: () => void;
54
+ /**
55
+ * The applicant's comment for the resubmission. The comment box shows only
56
+ * when the case can be resubmitted (`canResubmitInstance`) and
57
+ * `onResubmitCommentChange` is given.
58
+ */
59
+ readonly resubmitComment?: string;
60
+ /** Called when the applicant edits the resubmission comment. */
61
+ readonly onResubmitCommentChange?: ((value: string) => void) | null;
54
62
  /** Called when an attachment upload is requested via the form field. */
55
63
  readonly onUploadAttachment: (field: FormFieldDefinition, file: File) => Promise<{
56
64
  readonly id: string;
@@ -61,4 +69,4 @@ export interface InstanceFormSectionProps {
61
69
  * Displays the form in read-only mode normally, or editable mode when the
62
70
  * instance has been returned and the current member can resubmit it.
63
71
  */
64
- export declare function InstanceFormSection({ canResubmitInstance, deciding, error, fieldAccess, fieldLabelMarkers, fill, instance, loading, onDataSourceStateChange, onResubmitFormChange, onReloadAfterConflict, onResubmitInstance, onUploadAttachment, resubmitFormData, resubmitFormErrors, }: InstanceFormSectionProps): ReactElement;
72
+ export declare function InstanceFormSection({ canResubmitInstance, deciding, error, fieldAccess, fieldLabelMarkers, fill, instance, loading, onDataSourceStateChange, onResubmitFormChange, onReloadAfterConflict, onResubmitCommentChange, onResubmitInstance, onUploadAttachment, resubmitComment, resubmitFormData, resubmitFormErrors, }: InstanceFormSectionProps): ReactElement;
@@ -66,6 +66,13 @@ export interface InstanceTasksSectionProps {
66
66
  * transfer) completes successfully. The container should refresh data.
67
67
  */
68
68
  readonly onChanged: () => void | Promise<void>;
69
+ /**
70
+ * Called whenever a task decision starts or settles. A container that puts
71
+ * the decision buttons outside this section keeps them disabled from this,
72
+ * rather than from `InstanceTasksSectionHandle.deciding`: a ref does not
73
+ * re-render the container when the decision settles.
74
+ */
75
+ readonly onDecidingChange?: (deciding: boolean) => void;
69
76
  }
70
77
  /**
71
78
  * Renders the tasks section of the approval instance detail page.
@@ -66,6 +66,13 @@ export interface InstanceTasksSectionProps {
66
66
  * transfer) completes successfully. The container should refresh data.
67
67
  */
68
68
  readonly onChanged: () => void | Promise<void>;
69
+ /**
70
+ * Called whenever a task decision starts or settles. A container that puts
71
+ * the decision buttons outside this section keeps them disabled from this,
72
+ * rather than from `InstanceTasksSectionHandle.deciding`: a ref does not
73
+ * re-render the container when the decision settles.
74
+ */
75
+ readonly onDecidingChange?: (deciding: boolean) => void;
69
76
  }
70
77
  /**
71
78
  * Renders the tasks section of the approval instance detail page.
@@ -0,0 +1,18 @@
1
+ export interface ResubmitCommentDraft {
2
+ /** The applicant's unsent resubmission comment for the current case. */
3
+ readonly comment: string;
4
+ readonly setComment: (value: string) => void;
5
+ /**
6
+ * Clears the draft after `submittedInstanceId` was resubmitted, unless the
7
+ * page has since moved to another case whose draft must stay.
8
+ */
9
+ readonly clearAfterResubmit: (submittedInstanceId: string) => void;
10
+ }
11
+ /**
12
+ * The resubmission comment draft of the case at `instanceId`. One draft is
13
+ * kept, stored with the case it was written for and read back only for that
14
+ * case: another case shows empty from its very first render, a refresh of the
15
+ * same case (an upload, a decision elsewhere) keeps it, and coming back to the
16
+ * case shows it again unless the applicant has typed on another case since.
17
+ */
18
+ export declare function useResubmitCommentDraft(instanceId: string): ResubmitCommentDraft;