@rytass/bpm-core-react 0.23.0 → 0.24.0

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 (128) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +1 -0
  3. package/dist/chunks/{FormBuilderView-bm8P55hp.cjs → FormBuilderView-Bg9ftYz-.cjs} +2 -2
  4. package/dist/chunks/{FormBuilderView-bm8P55hp.cjs.map → FormBuilderView-Bg9ftYz-.cjs.map} +1 -1
  5. package/dist/chunks/{FormBuilderView-D_bN9gzT.js → FormBuilderView-CBvdcg_t.js} +2 -2
  6. package/dist/chunks/{FormBuilderView-D_bN9gzT.js.map → FormBuilderView-CBvdcg_t.js.map} +1 -1
  7. package/dist/chunks/FormRendererView-D-p6GDQB.cjs +6 -0
  8. package/dist/chunks/FormRendererView-D-p6GDQB.cjs.map +1 -0
  9. package/dist/chunks/FormRendererView-DHXmekC3.js +1319 -0
  10. package/dist/chunks/FormRendererView-DHXmekC3.js.map +1 -0
  11. package/dist/chunks/{approval-instance-list-page-Cv5I1YPX.cjs → approval-instance-list-page-BqkG9jiR.cjs} +2 -2
  12. package/dist/chunks/{approval-instance-list-page-Cv5I1YPX.cjs.map → approval-instance-list-page-BqkG9jiR.cjs.map} +1 -1
  13. package/dist/chunks/{approval-instance-list-page-BI5fIXc-.js → approval-instance-list-page-CsSpIN4C.js} +2 -2
  14. package/dist/chunks/{approval-instance-list-page-BI5fIXc-.js.map → approval-instance-list-page-CsSpIN4C.js.map} +1 -1
  15. package/dist/chunks/{compose-CdKVQfjB.cjs → compose-B43jtdyL.cjs} +2 -2
  16. package/dist/chunks/{compose-CdKVQfjB.cjs.map → compose-B43jtdyL.cjs.map} +1 -1
  17. package/dist/chunks/{compose-N9657E5u.js → compose-C7yS6bJm.js} +5 -5
  18. package/dist/chunks/{compose-N9657E5u.js.map → compose-C7yS6bJm.js.map} +1 -1
  19. package/dist/chunks/{dashboard-page-BoqNhjT_.js → dashboard-page-DBJCsPya.js} +2 -2
  20. package/dist/chunks/{dashboard-page-BoqNhjT_.js.map → dashboard-page-DBJCsPya.js.map} +1 -1
  21. package/dist/chunks/{dashboard-page-D7YJ3udk.cjs → dashboard-page-lqlLELKs.cjs} +2 -2
  22. package/dist/chunks/{dashboard-page-D7YJ3udk.cjs.map → dashboard-page-lqlLELKs.cjs.map} +1 -1
  23. package/dist/chunks/{designer-CKwG_vM5.js → designer-B9Ut4xze.js} +1736 -1611
  24. package/dist/chunks/designer-B9Ut4xze.js.map +1 -0
  25. package/dist/chunks/designer-eXw7R9ug.cjs +69 -0
  26. package/dist/chunks/designer-eXw7R9ug.cjs.map +1 -0
  27. package/dist/chunks/{detail-fW0vJudE.js → detail-BB_uYaoM.js} +7 -6
  28. package/dist/chunks/detail-BB_uYaoM.js.map +1 -0
  29. package/dist/chunks/detail-DN8pEzUJ.cjs +5 -0
  30. package/dist/chunks/detail-DN8pEzUJ.cjs.map +1 -0
  31. package/dist/chunks/member-profile-resolution-CJlgVdTR.js +44 -0
  32. package/dist/chunks/member-profile-resolution-CJlgVdTR.js.map +1 -0
  33. package/dist/chunks/member-profile-resolution-DiH-P-Vh.cjs +2 -0
  34. package/dist/chunks/member-profile-resolution-DiH-P-Vh.cjs.map +1 -0
  35. package/dist/chunks/{providers-CQWekD7_.js → providers-D35lBOTd.js} +2 -2
  36. package/dist/chunks/{providers-CQWekD7_.js.map → providers-D35lBOTd.js.map} +1 -1
  37. package/dist/chunks/{providers-VUOh6i0i.cjs → providers-Dz4Wqxr6.cjs} +2 -2
  38. package/dist/chunks/{providers-VUOh6i0i.cjs.map → providers-Dz4Wqxr6.cjs.map} +1 -1
  39. package/dist/chunks/{routes-config-C1j_vFKo.cjs → routes-config-BWjZDAU3.cjs} +2 -2
  40. package/dist/chunks/{routes-config-C1j_vFKo.cjs.map → routes-config-BWjZDAU3.cjs.map} +1 -1
  41. package/dist/chunks/{routes-config-BcNaWJWJ.js → routes-config-DjEOE9eP.js} +3 -2
  42. package/dist/chunks/{routes-config-BcNaWJWJ.js.map → routes-config-DjEOE9eP.js.map} +1 -1
  43. package/dist/chunks/users-C_Dtw_sR.cjs +2 -0
  44. package/dist/chunks/users-C_Dtw_sR.cjs.map +1 -0
  45. package/dist/chunks/users-wgM3TqU3.js +513 -0
  46. package/dist/chunks/users-wgM3TqU3.js.map +1 -0
  47. package/dist/index.cjs +1 -1
  48. package/dist/index.js +4 -4
  49. package/dist/lib/routes-config.d.cts +2 -0
  50. package/dist/lib/routes-config.d.ts +2 -0
  51. package/dist/next/index.cjs +1 -1
  52. package/dist/next/index.js +2 -2
  53. package/dist/pages/admin/stuck-instances/index.cjs +2 -0
  54. package/dist/pages/admin/stuck-instances/index.cjs.map +1 -0
  55. package/dist/pages/admin/stuck-instances/index.d.cts +4 -0
  56. package/dist/pages/admin/stuck-instances/index.d.ts +4 -0
  57. package/dist/pages/admin/stuck-instances/index.js +13 -0
  58. package/dist/pages/admin/stuck-instances/index.js.map +1 -0
  59. package/dist/pages/admin/users/index.cjs +1 -1
  60. package/dist/pages/admin/users/index.js +1 -1
  61. package/dist/pages/instances/detail/index.cjs +1 -1
  62. package/dist/pages/instances/detail/index.js +1 -1
  63. package/dist/pages/templates/compose/index.cjs +1 -1
  64. package/dist/pages/templates/compose/index.js +1 -1
  65. package/dist/pages/templates/designer/index.cjs +1 -1
  66. package/dist/pages/templates/designer/index.js +1 -1
  67. package/dist/views/admin/index.cjs +1 -1
  68. package/dist/views/admin/index.d.cts +1 -0
  69. package/dist/views/admin/index.d.ts +1 -0
  70. package/dist/views/admin/index.js +3 -2
  71. package/dist/views/admin/stuck-instances/AdminStuckInstancesView.d.cts +10 -0
  72. package/dist/views/admin/stuck-instances/AdminStuckInstancesView.d.ts +10 -0
  73. package/dist/views/admin/stuck-instances/StuckInstanceCancelModal.d.cts +14 -0
  74. package/dist/views/admin/stuck-instances/StuckInstanceCancelModal.d.ts +14 -0
  75. package/dist/views/admin/stuck-instances/index.cjs +2 -0
  76. package/dist/views/admin/stuck-instances/index.cjs.map +1 -0
  77. package/dist/views/admin/stuck-instances/index.d.cts +2 -0
  78. package/dist/views/admin/stuck-instances/index.d.ts +2 -0
  79. package/dist/views/admin/stuck-instances/index.js +237 -0
  80. package/dist/views/admin/stuck-instances/index.js.map +1 -0
  81. package/dist/views/admin/users/index.cjs +1 -1
  82. package/dist/views/admin/users/index.js +1 -1
  83. package/dist/views/cc/index.cjs +1 -1
  84. package/dist/views/cc/index.js +1 -1
  85. package/dist/views/dashboard/index.cjs +1 -1
  86. package/dist/views/dashboard/index.js +1 -1
  87. package/dist/views/forms/builder/index.cjs +1 -1
  88. package/dist/views/forms/builder/index.js +1 -1
  89. package/dist/views/forms/renderer/index.cjs +1 -1
  90. package/dist/views/forms/renderer/index.js +1 -1
  91. package/dist/views/inbox/index.cjs +1 -1
  92. package/dist/views/inbox/index.js +1 -1
  93. package/dist/views/instances/detail/index.cjs +1 -1
  94. package/dist/views/instances/detail/index.js +1 -1
  95. package/dist/views/instances/new/index.cjs +1 -1
  96. package/dist/views/instances/new/index.js +4 -4
  97. package/dist/views/instances/new/index.js.map +1 -1
  98. package/dist/views/search/index.cjs +1 -1
  99. package/dist/views/search/index.js +1 -1
  100. package/dist/views/sent/index.cjs +1 -1
  101. package/dist/views/sent/index.js +1 -1
  102. package/dist/views/templates/compose/index.cjs +1 -1
  103. package/dist/views/templates/compose/index.js +1 -1
  104. package/dist/views/templates/designer/approver-resolver-model.d.cts +31 -0
  105. package/dist/views/templates/designer/approver-resolver-model.d.ts +31 -0
  106. package/dist/views/templates/designer/index.cjs +1 -1
  107. package/dist/views/templates/designer/index.js +1 -1
  108. package/dist/views/templates/designer/node-actor-resolver-options.d.cts +30 -3
  109. package/dist/views/templates/designer/node-actor-resolver-options.d.ts +30 -3
  110. package/dist/views/templates/index.cjs +1 -1
  111. package/dist/views/templates/index.js +1 -1
  112. package/dist/views/templates/versions/index.cjs +1 -1
  113. package/dist/views/templates/versions/index.js +1 -1
  114. package/package.json +23 -3
  115. package/dist/chunks/FormRendererView-BlQgJOkI.cjs +0 -6
  116. package/dist/chunks/FormRendererView-BlQgJOkI.cjs.map +0 -1
  117. package/dist/chunks/FormRendererView-CemHvfAT.js +0 -1359
  118. package/dist/chunks/FormRendererView-CemHvfAT.js.map +0 -1
  119. package/dist/chunks/designer-CKwG_vM5.js.map +0 -1
  120. package/dist/chunks/designer-JPs7EijM.cjs +0 -69
  121. package/dist/chunks/designer-JPs7EijM.cjs.map +0 -1
  122. package/dist/chunks/detail-Dqu0K9QM.cjs +0 -5
  123. package/dist/chunks/detail-Dqu0K9QM.cjs.map +0 -1
  124. package/dist/chunks/detail-fW0vJudE.js.map +0 -1
  125. package/dist/chunks/users-BBtiZ9QQ.js +0 -486
  126. package/dist/chunks/users-BBtiZ9QQ.js.map +0 -1
  127. package/dist/chunks/users-EqSzDhuj.cjs +0 -2
  128. package/dist/chunks/users-EqSzDhuj.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"providers-VUOh6i0i.cjs","names":["createContext","useState","useCallback","useMemo","useContext","createContext","useAuth","useState","useCallback","readUnreadNotificationCount","useMemo","useContext","useRouterAdapter","useBPMRoutes","useAuth","useState","useCallback","listNotifications","markAllNotificationsRead","markNotificationRead","unarchiveNotifications","archiveNotifications","decideTask","useMemo","_Fragment","Drawer","Fragment","NotificationCenter","Modal","Typography","BPMFormField","Textarea","CalendarLocale","DEFAULT_BPM_LANGUAGE","CalendarConfigProviderMoment","BPMLanguageProvider","BPMOrganizationTimeZoneProvider","AuthProvider","require_rolldown_runtime","require_auth_provider","require_organization_time_zone_provider","require_router_adapter","require_routes_config","require_bpm_form_field","react","_mezzanine_ui_react","react_jsx_runtime","_rytass_bpm_core_client_workflow","_mezzanine_ui_react_moment","_mezzanine_ui_react_Drawer","_mezzanine_ui_react_Modal","_mezzanine_ui_react_NotificationCenter","_mezzanine_ui_react_Textarea","NotificationDrawerContext","NotificationDrawerProvider","isOpen","setIsOpen","open","close","toggle","current","value","useNotificationDrawer","NotificationUnreadContext","NotificationUnreadProvider","currentMemberId","member","unreadCount","setUnreadCount","refreshUnreadCount","next","active","useNotificationUnread","buildNotificationOptions","payload","readNotificationPayload","record","canReject","readNotificationAllowReject","opensToFill","readPayloadFlag","isRecord","key","TIME_GROUP_ORDER","TIME_GROUP_LABEL","PAGE_SIZE","TOGGLE_ARCHIVED_OPTION_ID","RESOLVED_TITLE","resolveDisplayTitle","resolveSeverity","toSeverity","NotificationDrawer","router","routes","rows","setRows","totalCount","setTotalCount","page","setPage","loading","setLoading","bulkLoading","setBulkLoading","error","setError","notice","setNotice","filter","setFilter","includeArchived","setIncludeArchived","approveTarget","setApproveTarget","approveComment","setApproveComment","rejectTarget","setRejectTarget","rejectReason","setRejectReason","deciding","setDeciding","trimmedApproveComment","trimmedRejectReason","loadPage","result","nextPage","append","readErrorMessage","handleFilterChange","event","handleMarkAllRead","handleLoadMore","handleMarkRead","handleArchive","label","handleFilterAreaSelect","option","handleOpenInstance","openApproveModal","closeApproveModal","handleApproveConfirm","target","openRejectModal","closeRejectModal","handleRejectConfirm","handleBadgeSelect","action","isCardActivation","card","handleCardActivate","handleCardKeyDown","filteredRows","row","groupedRows","now","buckets","group","accumulator","resolveTimeGroup","items","hasMore","openable","itemIndex","type","notificationDate","nowStartOfDay","notificationStartOfDay","yesterdayStartOfDay","Providers","organizationTimeZone","children"],"sources":["../../src/lib/notification-drawer-provider.tsx","../../src/lib/notification-unread-provider.tsx","../../src/components/notification-drawer-options.ts","../../src/components/notification-drawer.tsx","../../src/lib/providers.tsx"],"sourcesContent":["'use client';\n\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useState,\n type ReactElement,\n type ReactNode,\n} from 'react';\n\ninterface NotificationDrawerContextValue {\n readonly close: () => void;\n readonly isOpen: boolean;\n readonly open: () => void;\n readonly toggle: () => void;\n}\n\nconst NotificationDrawerContext =\n createContext<NotificationDrawerContextValue | null>(null);\n\ninterface NotificationDrawerProviderProps {\n readonly children: ReactNode;\n}\n\n/**\n * Controls the open/closed state of the BPM notification drawer. Wraps\n * children with a context that `<NotificationDrawer />` reads to mount /\n * hide itself, and that the host navigation reads (via\n * `<BPMNotificationBellButton />` or `useNotificationDrawer().open`) to\n * open the drawer when the bell icon is clicked.\n *\n * When used outside this provider, the returned hook is a safe no-op so\n * components don't crash in test or storybook environments.\n */\nexport function NotificationDrawerProvider({\n children,\n}: NotificationDrawerProviderProps): ReactElement {\n const [isOpen, setIsOpen] = useState(false);\n\n const open = useCallback((): void => {\n setIsOpen(true);\n }, []);\n const close = useCallback((): void => {\n setIsOpen(false);\n }, []);\n const toggle = useCallback((): void => {\n setIsOpen((current) => !current);\n }, []);\n\n const value = useMemo<NotificationDrawerContextValue>(\n () => ({ close, isOpen, open, toggle }),\n [close, isOpen, open, toggle],\n );\n\n return (\n <NotificationDrawerContext.Provider value={value}>\n {children}\n </NotificationDrawerContext.Provider>\n );\n}\n\n/**\n * Read the BPM notification drawer's open state and control helpers.\n * Returns a no-op stub when used outside `<NotificationDrawerProvider>`.\n */\nexport function useNotificationDrawer(): NotificationDrawerContextValue {\n const context = useContext(NotificationDrawerContext);\n if (!context) {\n return {\n close: (): void => undefined,\n isOpen: false,\n open: (): void => undefined,\n toggle: (): void => undefined,\n };\n }\n return context;\n}\n","'use client';\n\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport { readUnreadNotificationCount } from '@rytass/bpm-core-client/workflow';\nimport { useAuth } from './auth-provider';\n\ninterface NotificationUnreadContextValue {\n readonly refreshUnreadCount: () => Promise<number>;\n readonly unreadCount: number;\n}\n\nconst NotificationUnreadContext =\n createContext<NotificationUnreadContextValue | null>(null);\n\ninterface NotificationUnreadProviderProps {\n readonly children: ReactNode;\n}\n\n/**\n * Polls BPM for the current member's unread notification count via\n * `readUnreadNotificationCount` and exposes it through context for the\n * host navigation (`<BPMNotificationBellButton />` badge or any custom\n * trigger using `useNotificationUnread().unreadCount`) and the BPM\n * `<NotificationDrawer />` (header count). Refresh is triggered on\n * mount and whenever the auth member id changes; consumers can call\n * `refreshUnreadCount()` after acknowledging a notification.\n */\nexport function NotificationUnreadProvider({\n children,\n}: NotificationUnreadProviderProps): ReactElement {\n const { member } = useAuth();\n const currentMemberId = member?.memberId ?? null;\n const [unreadCount, setUnreadCount] = useState(0);\n\n const refreshUnreadCount = useCallback(async (): Promise<number> => {\n if (!currentMemberId) {\n setUnreadCount(0);\n return 0;\n }\n const next = await readUnreadNotificationCount(currentMemberId);\n setUnreadCount(next);\n return next;\n }, [currentMemberId]);\n\n useEffect((): (() => void) => {\n let active = true;\n void (async () => {\n try {\n const next = await refreshUnreadCount();\n if (active) setUnreadCount(next);\n } catch {\n if (active) setUnreadCount(0);\n }\n })();\n return (): void => {\n active = false;\n };\n }, [refreshUnreadCount]);\n\n const value = useMemo<NotificationUnreadContextValue>(\n () => ({ refreshUnreadCount, unreadCount }),\n [refreshUnreadCount, unreadCount],\n );\n\n return (\n <NotificationUnreadContext.Provider value={value}>\n {children}\n </NotificationUnreadContext.Provider>\n );\n}\n\n/**\n * Read the current unread-notification count and a manual refresh helper.\n * Returns a zero/no-op stub when used outside\n * `<NotificationUnreadProvider>`.\n */\nexport function useNotificationUnread(): NotificationUnreadContextValue {\n const context = useContext(NotificationUnreadContext);\n if (!context) {\n return {\n refreshUnreadCount: async (): Promise<number> => 0,\n unreadCount: 0,\n };\n }\n return context;\n}\n","import type { DropdownOption } from '@mezzanine-ui/core/dropdown/dropdown';\nimport type { NotificationRecord } from '@rytass/bpm-core-client/workflow';\n\nexport type NotificationAction =\n 'approve' | 'archive' | 'reject' | 'unarchive' | 'view' | 'read';\n\n/**\n * Build the `...` dropdown options for one notification. Approve / reject are\n * offered only while the server still reports the notification as `actionable`\n * (an unresolved task assignment) — once the task is decided / cancelled the\n * backend flips `actionable` to false, so a stale \"同意\" can never appear.\n * A task that fills in form fields (`hasFillableFields`) cannot be approved\n * from here — the fill has to be entered on the case page — so its \"同意\"\n * becomes \"開啟案件\". So does a task at a node that requires an approval\n * comment (`requireApprovalComment`): the drawer has no comment dialog of its\n * own for that, the case page does.\n * \"查看案件\" needs an `instanceId`; \"標為已讀\" only shows while unread.\n * Archiving is independent of read state, so the entry flips between\n * \"封存\" / \"取消封存\" for every notification.\n */\nexport function buildNotificationOptions(\n record: NotificationRecord,\n): readonly DropdownOption[] {\n const payload = readNotificationPayload(record);\n const canReject = readNotificationAllowReject(record, payload) !== false;\n const opensToFill =\n record.actionable &&\n Boolean(record.instanceId) &&\n (readPayloadFlag(payload, 'hasFillableFields') ||\n readPayloadFlag(payload, 'requireApprovalComment'));\n\n return [\n ...(record.actionable\n ? ([\n opensToFill\n ? { id: 'view', name: '開啟案件' }\n : { id: 'approve', name: '同意' },\n ...(canReject ? [{ id: 'reject', name: '拒絕' }] : []),\n ] satisfies DropdownOption[])\n : []),\n ...(record.instanceId && !opensToFill\n ? ([{ id: 'view', name: '查看案件' }] satisfies DropdownOption[])\n : []),\n ...(record.status !== 'READ'\n ? ([{ id: 'read', name: '標為已讀' }] satisfies DropdownOption[])\n : []),\n record.archivedAt\n ? { id: 'unarchive', name: '取消封存' }\n : { id: 'archive', name: '封存' },\n ];\n}\n\n/**\n * The notification's `payloadJson`, parsed once. `null` when it is not a JSON\n * object; every reader below takes this one result.\n */\nfunction readNotificationPayload(\n record: NotificationRecord,\n): Readonly<Record<string, unknown>> | null {\n try {\n const payload: unknown = JSON.parse(record.payloadJson);\n\n return isRecord(payload) ? payload : null;\n } catch {\n return null;\n }\n}\n\nfunction readNotificationAllowReject(\n record: NotificationRecord,\n payload: Readonly<Record<string, unknown>> | null,\n): boolean | null {\n if (payload && typeof payload.allowReject === 'boolean') {\n return payload.allowReject;\n }\n\n return record.allowReject;\n}\n\n/**\n * `true` only when the payload sets the flag to `true`. A missing key, a\n * `false`, or an unparsable payload all read as `false`.\n *\n * `TASK_ASSIGNED` / `TASK_TRANSFERRED` payloads carry `hasFillableFields`, and\n * `requireApprovalComment: true` only when the node asks for a comment on\n * approval. Notifications created before those keys existed read as `false`.\n */\nfunction readPayloadFlag(\n payload: Readonly<Record<string, unknown>> | null,\n key: string,\n): boolean {\n return payload !== null && payload[key] === true;\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","'use client';\n\nimport {\n Fragment,\n useCallback,\n useEffect,\n useMemo,\n useState,\n type ChangeEvent,\n type KeyboardEvent as ReactKeyboardEvent,\n type MouseEvent as ReactMouseEvent,\n type ReactElement,\n} from 'react';\nimport Drawer from '@mezzanine-ui/react/Drawer';\nimport Modal from '@mezzanine-ui/react/Modal';\nimport NotificationCenter from '@mezzanine-ui/react/NotificationCenter';\nimport Textarea from '@mezzanine-ui/react/Textarea';\nimport { Typography } from '@mezzanine-ui/react';\nimport type { NotificationSeverity } from '@mezzanine-ui/core/notification-center';\nimport type { DropdownOption } from '@mezzanine-ui/core/dropdown/dropdown';\nimport {\n archiveNotifications,\n decideTask,\n listNotifications,\n markAllNotificationsRead,\n markNotificationRead,\n unarchiveNotifications,\n type NotificationRecord,\n type NotificationResolution,\n type NotificationType,\n} from '@rytass/bpm-core-client/workflow';\nimport { useAuth } from '../lib/auth-provider';\nimport { useNotificationDrawer } from '../lib/notification-drawer-provider';\nimport { useNotificationUnread } from '../lib/notification-unread-provider';\nimport { useRouterAdapter } from '../lib/router-adapter';\nimport { useBPMRoutes } from '../lib/routes-config';\nimport { BPMFormField } from './bpm-form-field';\nimport {\n buildNotificationOptions,\n type NotificationAction,\n} from './notification-drawer-options';\n\ntype FilterValue = 'all' | 'read' | 'unread';\n\ntype TimeGroup = 'today' | 'yesterday' | 'past7Days' | 'earlier';\n\nconst TIME_GROUP_ORDER: readonly TimeGroup[] = [\n 'today',\n 'yesterday',\n 'past7Days',\n 'earlier',\n];\n\nconst TIME_GROUP_LABEL: Readonly<Record<TimeGroup, string>> = {\n earlier: '更早',\n past7Days: '過去七天',\n today: '今天',\n yesterday: '昨天',\n};\n\nconst PAGE_SIZE = 50;\n\n/** Identifier for the filter-bar dropdown entry toggling the archived view. */\nconst TOGGLE_ARCHIVED_OPTION_ID = 'toggleArchived';\n\n/**\n * Title shown for a resolved task-assignment notification, replacing the\n * stored \"新的待簽任務\" wording so a decided card no longer reads as pending.\n * The stored `body` is kept as historical context (which case / node).\n */\nconst RESOLVED_TITLE: Readonly<Record<NotificationResolution, string>> = {\n APPROVED: '簽核任務已同意',\n REJECTED: '簽核任務已拒絕',\n RETURNED: '簽核任務已退回',\n SUPERSEDED: '簽核任務已結束',\n TRANSFERRED: '簽核任務已轉派',\n};\n\nfunction resolveDisplayTitle(record: NotificationRecord): string {\n return record.resolution ? RESOLVED_TITLE[record.resolution] : record.title;\n}\n\n/**\n * Severity (icon colour) for a notification. Once resolved, it reflects the\n * outcome — green for approved, red for rejected, neutral otherwise — instead\n * of the original by-type colour.\n */\nfunction resolveSeverity(record: NotificationRecord): NotificationSeverity {\n if (record.resolution === 'APPROVED') return 'success';\n if (record.resolution === 'REJECTED') return 'error';\n if (record.resolution) return 'info';\n return toSeverity(record.type);\n}\n\n/**\n * Right-side notification drawer mounted at the root by `<Providers>`.\n * Opens / closes via `useNotificationDrawer()`, polls\n * `listNotifications()` for the current member, supports filter\n * (`all` / `read` / `unread`), per-row mark-read, per-row archive / unarchive,\n * bulk mark-all-read, and load-more pagination. Archived notifications are\n * hidden until the filter-bar menu turns \"顯示已封存\" on. Clicking a row with an\n * `instanceId` navigates to `/instances/<id>` via the host's router adapter.\n */\nexport function NotificationDrawer(): ReactElement | null {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const { member } = useAuth();\n const { close, isOpen } = useNotificationDrawer();\n const { refreshUnreadCount } = useNotificationUnread();\n const currentMemberId = member?.memberId ?? null;\n const [rows, setRows] = useState<readonly NotificationRecord[]>([]);\n const [totalCount, setTotalCount] = useState(0);\n const [page, setPage] = useState(1);\n const [loading, setLoading] = useState(false);\n const [bulkLoading, setBulkLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [notice, setNotice] = useState<string | null>(null);\n const [filter, setFilter] = useState<FilterValue>('all');\n const [includeArchived, setIncludeArchived] = useState(false);\n const [approveTarget, setApproveTarget] = useState<NotificationRecord | null>(\n null,\n );\n const [approveComment, setApproveComment] = useState('');\n const [rejectTarget, setRejectTarget] = useState<NotificationRecord | null>(\n null,\n );\n const [rejectReason, setRejectReason] = useState('');\n const [deciding, setDeciding] = useState(false);\n\n const trimmedApproveComment = approveComment.trim();\n const trimmedRejectReason = rejectReason.trim();\n\n const loadPage = useCallback(\n async (nextPage: number, append: boolean): Promise<boolean> => {\n if (!currentMemberId) return false;\n setLoading(true);\n setError(null);\n try {\n const result = await listNotifications({\n includeArchived,\n includeRead: true,\n page: nextPage,\n pageSize: PAGE_SIZE,\n recipientMemberId: currentMemberId,\n });\n setRows((current): readonly NotificationRecord[] =>\n append ? [...current, ...result.notifications] : result.notifications,\n );\n setTotalCount(result.totalCount);\n setPage(nextPage);\n await refreshUnreadCount();\n return true;\n } catch (e: unknown) {\n setError(readErrorMessage(e));\n return false;\n } finally {\n setLoading(false);\n }\n },\n [currentMemberId, includeArchived, refreshUnreadCount],\n );\n\n useEffect((): void => {\n if (!isOpen || !currentMemberId) return;\n setError(null);\n setNotice(null);\n void loadPage(1, false);\n }, [isOpen, currentMemberId, loadPage]);\n\n const handleFilterChange = useCallback(\n (event: ChangeEvent<HTMLInputElement>): void => {\n const next = event.target.value;\n if (next === 'all' || next === 'read' || next === 'unread') setFilter(next);\n },\n [],\n );\n\n const handleMarkAllRead = useCallback(async (): Promise<void> => {\n if (!currentMemberId || bulkLoading) return;\n setBulkLoading(true);\n setError(null);\n try {\n await markAllNotificationsRead({ recipientMemberId: currentMemberId });\n await loadPage(1, false);\n } catch (e: unknown) {\n setError(readErrorMessage(e));\n } finally {\n setBulkLoading(false);\n }\n }, [bulkLoading, currentMemberId, loadPage]);\n\n const handleLoadMore = useCallback((): void => {\n if (loading) return;\n void loadPage(page + 1, true);\n }, [loading, loadPage, page]);\n\n const handleMarkRead = useCallback(\n async (id: string): Promise<void> => {\n if (!currentMemberId) return;\n try {\n await markNotificationRead({ id, readerMemberId: currentMemberId });\n await loadPage(1, false);\n } catch (e: unknown) {\n setError(readErrorMessage(e));\n }\n },\n [currentMemberId, loadPage],\n );\n\n const handleArchive = useCallback(\n async (record: NotificationRecord): Promise<void> => {\n if (!currentMemberId) return;\n setError(null);\n setNotice(null);\n try {\n // Name the notification the way the row does — `title` is the raw\n // stored title, which can differ from the rendered one.\n const label = resolveDisplayTitle(record);\n\n if (record.archivedAt) {\n await unarchiveNotifications({ ids: [record.id] });\n setNotice(`已將「${label}」移出封存。`);\n } else {\n await archiveNotifications({ ids: [record.id] });\n setNotice(`已封存「${label}」。`);\n }\n await loadPage(1, false);\n } catch (e: unknown) {\n setError(readErrorMessage(e));\n }\n },\n [currentMemberId, loadPage],\n );\n\n const handleFilterAreaSelect = useCallback((option: DropdownOption): void => {\n if (option.id !== TOGGLE_ARCHIVED_OPTION_ID) return;\n setNotice(null);\n setIncludeArchived((current): boolean => !current);\n }, []);\n\n const handleOpenInstance = useCallback(\n async (record: NotificationRecord): Promise<void> => {\n if (!record.instanceId || !currentMemberId) return;\n try {\n if (record.status !== 'READ') {\n await markNotificationRead({\n id: record.id,\n readerMemberId: currentMemberId,\n });\n await refreshUnreadCount();\n }\n close();\n router.push(routes.caseDetail(record.instanceId));\n } catch (e: unknown) {\n setError(readErrorMessage(e));\n }\n },\n [close, currentMemberId, refreshUnreadCount, router, routes],\n );\n\n const openApproveModal = useCallback((record: NotificationRecord): void => {\n setError(null);\n setApproveTarget(record);\n setApproveComment('');\n }, []);\n\n const closeApproveModal = useCallback((): void => {\n if (deciding) return;\n setApproveTarget(null);\n setApproveComment('');\n }, [deciding]);\n\n const handleApproveConfirm = useCallback(async (): Promise<void> => {\n const target = approveTarget;\n if (!target?.taskId || !currentMemberId || deciding) return;\n setDeciding(true);\n setError(null);\n setNotice(null);\n try {\n await decideTask({\n action: 'APPROVED',\n comment: trimmedApproveComment || null,\n decidedByMemberId: currentMemberId,\n taskId: target.taskId,\n });\n const refreshed = await loadPage(1, false);\n if (!refreshed) return;\n setApproveTarget(null);\n setApproveComment('');\n setNotice(`已同意「${target.title}」。`);\n } catch (e: unknown) {\n setError(readErrorMessage(e));\n } finally {\n setDeciding(false);\n }\n }, [\n approveTarget,\n currentMemberId,\n deciding,\n loadPage,\n trimmedApproveComment,\n ]);\n\n const openRejectModal = useCallback((record: NotificationRecord): void => {\n setRejectTarget(record);\n setRejectReason('');\n }, []);\n\n const closeRejectModal = useCallback((): void => {\n setRejectTarget(null);\n setRejectReason('');\n }, []);\n\n const handleRejectConfirm = useCallback(async (): Promise<void> => {\n const target = rejectTarget;\n if (!target?.taskId || !currentMemberId || !trimmedRejectReason || deciding)\n return;\n setDeciding(true);\n setError(null);\n setNotice(null);\n try {\n await decideTask({\n action: 'REJECTED',\n comment: trimmedRejectReason,\n decidedByMemberId: currentMemberId,\n taskId: target.taskId,\n });\n setRejectTarget(null);\n setRejectReason('');\n setNotice(`已拒絕「${target.title}」。`);\n await loadPage(1, false);\n } catch (e: unknown) {\n setError(readErrorMessage(e));\n } finally {\n setDeciding(false);\n }\n }, [currentMemberId, deciding, loadPage, rejectTarget, trimmedRejectReason]);\n\n const handleBadgeSelect = useCallback(\n (record: NotificationRecord, option: DropdownOption): void => {\n const action = option.id as NotificationAction;\n if (action === 'approve') openApproveModal(record);\n else if (action === 'reject') openRejectModal(record);\n else if (action === 'view') void handleOpenInstance(record);\n else if (action === 'read') void handleMarkRead(record.id);\n else if (action === 'archive' || action === 'unarchive')\n void handleArchive(record);\n },\n [\n handleArchive,\n handleMarkRead,\n handleOpenInstance,\n openApproveModal,\n openRejectModal,\n ],\n );\n\n /**\n * Whether an event that reached the card wrapper actually happened inside the\n * card, and not on one of its action controls.\n *\n * Two escape hatches are needed. The `...` menu button (and its `<svg>` icon —\n * hence the `Element` check, SVG nodes are not HTMLElements) sits inside the\n * card and must open the dropdown rather than navigate. The dropdown itself\n * renders into a portal, and React replays events along the component tree\n * rather than the DOM tree, so picking \"封存\" also reaches this handler even\n * though the `<li role=\"option\">` lives outside the card's DOM — and it is not\n * a `<button>`, so the first guard alone misses it.\n */\n const isCardActivation = useCallback(\n (target: EventTarget | null, card: HTMLDivElement): boolean => {\n if (!(target instanceof Node) || !card.contains(target)) return false;\n\n return !(target instanceof Element && target.closest('button'));\n },\n [],\n );\n\n const handleCardActivate = useCallback(\n (record: NotificationRecord, event: ReactMouseEvent<HTMLDivElement>): void => {\n if (!isCardActivation(event.target, event.currentTarget)) return;\n void handleOpenInstance(record);\n },\n [handleOpenInstance, isCardActivation],\n );\n\n const handleCardKeyDown = useCallback(\n (\n record: NotificationRecord,\n event: ReactKeyboardEvent<HTMLDivElement>,\n ): void => {\n if (event.key !== 'Enter' && event.key !== ' ') return;\n if (!isCardActivation(event.target, event.currentTarget)) return;\n event.preventDefault();\n void handleOpenInstance(record);\n },\n [handleOpenInstance, isCardActivation],\n );\n\n const filteredRows = useMemo(\n (): readonly NotificationRecord[] =>\n rows.filter((row): boolean => {\n if (filter === 'all') return true;\n if (filter === 'read') return row.status === 'READ';\n return row.status !== 'READ';\n }),\n [filter, rows],\n );\n\n const groupedRows = useMemo(\n (): ReadonlyArray<readonly [TimeGroup, readonly NotificationRecord[]]> => {\n const now = new Date();\n const buckets = TIME_GROUP_ORDER.reduce<\n Record<TimeGroup, NotificationRecord[]>\n >(\n (accumulator, group) => {\n accumulator[group] = [];\n return accumulator;\n },\n { earlier: [], past7Days: [], today: [], yesterday: [] },\n );\n filteredRows.forEach((row): void => {\n buckets[resolveTimeGroup(row.createdAt, now)].push(row);\n });\n return TIME_GROUP_ORDER.map(\n (group) => [group, buckets[group]] as const,\n ).filter(([, items]) => items.length > 0);\n },\n [filteredRows],\n );\n\n const hasMore = rows.length < totalCount;\n\n if (!currentMemberId) return null;\n\n return (\n <>\n <Drawer\n bottomGhostActionDisabled={bulkLoading || loading}\n bottomGhostActionLoading={bulkLoading}\n bottomGhostActionText=\"全部標為已讀\"\n bottomOnGhostActionClick={(): void => {\n void handleMarkAllRead();\n }}\n bottomOnPrimaryActionClick={(): void => {\n handleLoadMore();\n }}\n bottomPrimaryActionDisabled={!hasMore || loading}\n bottomPrimaryActionLoading={loading && hasMore}\n bottomPrimaryActionText={hasMore ? '載入更多' : '已顯示全部'}\n contentKey={`${filter}:${includeArchived}:${rows.length}`}\n filterAreaAllRadioLabel=\"全部\"\n filterAreaOnRadioChange={handleFilterChange}\n filterAreaOnSelect={handleFilterAreaSelect}\n filterAreaOptions={[\n {\n id: TOGGLE_ARCHIVED_OPTION_ID,\n name: includeArchived ? '隱藏已封存' : '顯示已封存',\n },\n ]}\n filterAreaReadRadioLabel=\"已讀\"\n filterAreaShow\n filterAreaUnreadRadioLabel=\"未讀\"\n filterAreaValue={filter}\n headerTitle=\"通知中心\"\n isBottomDisplay\n isHeaderDisplay\n onClose={close}\n open={isOpen}\n size=\"medium\"\n >\n <div role=\"list\">\n {error ? (\n <p\n role=\"alert\"\n style={{\n color: 'var(--mzn-color-text-error, #d92d20)',\n padding: '12px 16px',\n }}\n >\n {error}\n </p>\n ) : null}\n {notice ? (\n <p\n role=\"status\"\n style={{\n color: 'var(--mzn-color-text-success, #079455)',\n padding: '12px 16px',\n }}\n >\n {notice}\n </p>\n ) : null}\n {groupedRows.length === 0 ? (\n <p\n style={{\n color: 'var(--mzn-color-text-secondary, #6b7280)',\n padding: '24px 16px',\n textAlign: 'center',\n }}\n >\n {loading ? '載入中…' : '目前沒有通知'}\n </p>\n ) : null}\n {groupedRows.map(([group, items]) => (\n <Fragment key={group}>\n {items.map((record, itemIndex) => {\n const openable = record.instanceId !== null;\n\n return (\n <div\n key={record.id}\n onClick={\n openable\n ? (event: ReactMouseEvent<HTMLDivElement>): void => {\n handleCardActivate(record, event);\n }\n : undefined\n }\n onKeyDown={\n openable\n ? (event: ReactKeyboardEvent<HTMLDivElement>): void => {\n handleCardKeyDown(record, event);\n }\n : undefined\n }\n role={openable ? 'button' : undefined}\n style={openable ? { cursor: 'pointer' } : undefined}\n tabIndex={openable ? 0 : undefined}\n >\n <NotificationCenter\n appendTips={record.archivedAt ? '已封存' : undefined}\n description={record.body}\n onBadgeSelect={(option: DropdownOption): void => {\n handleBadgeSelect(record, option);\n }}\n options={[...buildNotificationOptions(record)]}\n prependTips={\n itemIndex === 0 ? TIME_GROUP_LABEL[group] : undefined\n }\n reference={record.id}\n severity={resolveSeverity(record)}\n showBadge={record.status !== 'READ'}\n timeStamp={record.createdAt}\n title={resolveDisplayTitle(record)}\n type=\"drawer\"\n />\n </div>\n );\n })}\n </Fragment>\n ))}\n </div>\n </Drawer>\n <Modal\n cancelText=\"取消\"\n confirmText=\"送出同意\"\n loading={deciding}\n modalType=\"standard\"\n onCancel={closeApproveModal}\n onClose={closeApproveModal}\n onConfirm={(): void => {\n void handleApproveConfirm();\n }}\n open={approveTarget !== null}\n showModalFooter\n showModalHeader\n size=\"regular\"\n supportingText=\"可以留下同意說明,內容會記錄在簽核歷程;不填也可以直接送出。\"\n title=\"簽核意見\"\n >\n {error ? (\n <Typography color=\"text-error\" role=\"alert\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n <BPMFormField label=\"簽核意見\" name=\"notificationApproveComment\">\n <Textarea\n autoFocus\n onChange={(event: ChangeEvent<HTMLTextAreaElement>): void => {\n setApproveComment(event.target.value);\n }}\n placeholder=\"選填,例如補充核准條件或提醒事項\"\n rows={4}\n value={approveComment}\n />\n </BPMFormField>\n </Modal>\n <Modal\n cancelText=\"取消\"\n confirmButtonProps={{\n disabled: !trimmedRejectReason,\n variant: 'destructive-primary',\n }}\n confirmText=\"送出拒絕\"\n loading={deciding}\n modalStatusType=\"error\"\n modalType=\"standard\"\n onCancel={closeRejectModal}\n onClose={closeRejectModal}\n onConfirm={(): void => {\n void handleRejectConfirm();\n }}\n open={rejectTarget !== null}\n showModalFooter\n showModalHeader\n size=\"regular\"\n supportingText=\"拒絕案件時必須留下原因,供發起人與後續追蹤查看。\"\n title=\"拒絕原因\"\n >\n <Textarea\n autoFocus\n onChange={(event: ChangeEvent<HTMLTextAreaElement>): void => {\n setRejectReason(event.target.value);\n }}\n placeholder=\"請輸入拒絕原因\"\n rows={4}\n value={rejectReason}\n />\n </Modal>\n </>\n );\n}\n\nfunction toSeverity(type: NotificationType): NotificationSeverity {\n if (type === 'SLA_OVERDUE') return 'error';\n if (type === 'SLA_WARNING') return 'warning';\n if (type === 'INSTANCE_COMPLETED') return 'success';\n return 'info';\n}\n\nfunction resolveTimeGroup(value: string, now: Date): TimeGroup {\n const notificationDate = new Date(value);\n if (Number.isNaN(notificationDate.getTime())) return 'earlier';\n const nowStartOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const notificationStartOfDay = new Date(\n notificationDate.getFullYear(),\n notificationDate.getMonth(),\n notificationDate.getDate(),\n );\n if (notificationStartOfDay.getTime() === nowStartOfDay.getTime()) return 'today';\n const yesterdayStartOfDay = new Date(nowStartOfDay);\n yesterdayStartOfDay.setDate(yesterdayStartOfDay.getDate() - 1);\n if (notificationStartOfDay.getTime() === yesterdayStartOfDay.getTime())\n return 'yesterday';\n const diffInDays =\n (now.getTime() - notificationDate.getTime()) / (1000 * 60 * 60 * 24);\n if (diffInDays <= 7) return 'past7Days';\n return 'earlier';\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n","'use client';\n\nimport type { ReactElement, ReactNode } from 'react';\nimport {\n CalendarConfigProviderMoment,\n CalendarLocale,\n} from '@mezzanine-ui/react/moment';\nimport { AuthProvider } from './auth-provider';\nimport {\n BPMLanguageProvider,\n DEFAULT_BPM_LANGUAGE,\n type BPMLanguage,\n} from './language-provider';\nimport { BPMOrganizationTimeZoneProvider } from './organization-time-zone-provider';\nimport { NotificationDrawer } from '../components/notification-drawer';\nimport { NotificationDrawerProvider } from './notification-drawer-provider';\nimport { NotificationUnreadProvider } from './notification-unread-provider';\n\ninterface ProvidersProps {\n readonly children: ReactNode;\n /** Override Mezzanine calendar locale. Defaults to `CalendarLocale.ZH_TW`. */\n readonly locale?: CalendarLocale;\n /**\n * Language BPM views write their messages in, such as publish-lint errors.\n * Defaults to `'zh-TW'`. Pass the user's choice as state to let them switch.\n * Independent of `locale`, which only formats calendar dates.\n */\n readonly language?: BPMLanguage;\n /**\n * IANA zone in which BPM views read \"today\" against organization effective\n * dates. Pass the same value given to `BPMRootModule` as\n * `organizationTimeZone`; leave it unset when the API does not set one.\n * Defaults to `DEFAULT_BPM_ORGANIZATION_TIME_ZONE` (`'Asia/Taipei'`); an\n * unknown zone falls back to it with a console warning.\n */\n readonly organizationTimeZone?: string;\n /**\n * Public paths that should not trigger redirect to `/login` when there\n * is no session. Forwarded to `<AuthProvider>`. Defaults to `['/login']`.\n */\n readonly publicPaths?: readonly string[];\n /** Where to send unauthenticated users. Defaults to `'/login'`. */\n readonly loginPath?: string;\n}\n\n/**\n * One-stop BPM admin provider stack. Wires:\n *\n * - Mezzanine UI calendar locale (moment-based, `ZH_TW` by default)\n * - `<BPMLanguageProvider>` (message language, `'zh-TW'` by default)\n * - `<BPMOrganizationTimeZoneProvider>` (organization \"today\" zone)\n * - `<AuthProvider>` (BPM session via REST `/auth/*`)\n * - `<NotificationUnreadProvider>` (polls unread count)\n * - `<NotificationDrawerProvider>` (controls drawer open/close state)\n * - `<NotificationDrawer />` mounted at the root so the host navigation\n * bell (`<BPMNotificationBellButton />` or any custom trigger calling\n * `useNotificationDrawer().open`) can open it.\n *\n * Consumer hosts wrap this **inside** a `<RouterAdapterProvider>` (provided\n * by the `pages/*` subpath shims when consuming via Next.js, or wired by\n * hand for other frameworks).\n */\nexport function Providers({\n children,\n locale = CalendarLocale.ZH_TW,\n language = DEFAULT_BPM_LANGUAGE,\n organizationTimeZone,\n publicPaths,\n loginPath,\n}: ProvidersProps): ReactElement {\n return (\n <CalendarConfigProviderMoment locale={locale}>\n <BPMLanguageProvider language={language}>\n <BPMOrganizationTimeZoneProvider timeZone={organizationTimeZone}>\n <AuthProvider publicPaths={publicPaths} loginPath={loginPath}>\n <NotificationUnreadProvider>\n <NotificationDrawerProvider>\n {children}\n <NotificationDrawer />\n </NotificationDrawerProvider>\n </NotificationUnreadProvider>\n </AuthProvider>\n </BPMOrganizationTimeZoneProvider>\n </BPMLanguageProvider>\n </CalendarConfigProviderMoment>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"providers-Dz4Wqxr6.cjs","names":["createContext","useState","useCallback","useMemo","useContext","createContext","useAuth","useState","useCallback","readUnreadNotificationCount","useMemo","useContext","useRouterAdapter","useBPMRoutes","useAuth","useState","useCallback","listNotifications","markAllNotificationsRead","markNotificationRead","unarchiveNotifications","archiveNotifications","decideTask","useMemo","_Fragment","Drawer","Fragment","NotificationCenter","Modal","Typography","BPMFormField","Textarea","CalendarLocale","DEFAULT_BPM_LANGUAGE","CalendarConfigProviderMoment","BPMLanguageProvider","BPMOrganizationTimeZoneProvider","AuthProvider","require_rolldown_runtime","require_auth_provider","require_organization_time_zone_provider","require_router_adapter","require_routes_config","require_bpm_form_field","react","_mezzanine_ui_react","react_jsx_runtime","_rytass_bpm_core_client_workflow","_mezzanine_ui_react_moment","_mezzanine_ui_react_Drawer","_mezzanine_ui_react_Modal","_mezzanine_ui_react_NotificationCenter","_mezzanine_ui_react_Textarea","NotificationDrawerContext","NotificationDrawerProvider","isOpen","setIsOpen","open","close","toggle","current","value","useNotificationDrawer","NotificationUnreadContext","NotificationUnreadProvider","currentMemberId","member","unreadCount","setUnreadCount","refreshUnreadCount","next","active","useNotificationUnread","buildNotificationOptions","payload","readNotificationPayload","record","canReject","readNotificationAllowReject","opensToFill","readPayloadFlag","isRecord","key","TIME_GROUP_ORDER","TIME_GROUP_LABEL","PAGE_SIZE","TOGGLE_ARCHIVED_OPTION_ID","RESOLVED_TITLE","resolveDisplayTitle","resolveSeverity","toSeverity","NotificationDrawer","router","routes","rows","setRows","totalCount","setTotalCount","page","setPage","loading","setLoading","bulkLoading","setBulkLoading","error","setError","notice","setNotice","filter","setFilter","includeArchived","setIncludeArchived","approveTarget","setApproveTarget","approveComment","setApproveComment","rejectTarget","setRejectTarget","rejectReason","setRejectReason","deciding","setDeciding","trimmedApproveComment","trimmedRejectReason","loadPage","result","nextPage","append","readErrorMessage","handleFilterChange","event","handleMarkAllRead","handleLoadMore","handleMarkRead","handleArchive","label","handleFilterAreaSelect","option","handleOpenInstance","openApproveModal","closeApproveModal","handleApproveConfirm","target","openRejectModal","closeRejectModal","handleRejectConfirm","handleBadgeSelect","action","isCardActivation","card","handleCardActivate","handleCardKeyDown","filteredRows","row","groupedRows","now","buckets","group","accumulator","resolveTimeGroup","items","hasMore","openable","itemIndex","type","notificationDate","nowStartOfDay","notificationStartOfDay","yesterdayStartOfDay","Providers","organizationTimeZone","children"],"sources":["../../src/lib/notification-drawer-provider.tsx","../../src/lib/notification-unread-provider.tsx","../../src/components/notification-drawer-options.ts","../../src/components/notification-drawer.tsx","../../src/lib/providers.tsx"],"sourcesContent":["'use client';\n\nimport {\n createContext,\n useCallback,\n useContext,\n useMemo,\n useState,\n type ReactElement,\n type ReactNode,\n} from 'react';\n\ninterface NotificationDrawerContextValue {\n readonly close: () => void;\n readonly isOpen: boolean;\n readonly open: () => void;\n readonly toggle: () => void;\n}\n\nconst NotificationDrawerContext =\n createContext<NotificationDrawerContextValue | null>(null);\n\ninterface NotificationDrawerProviderProps {\n readonly children: ReactNode;\n}\n\n/**\n * Controls the open/closed state of the BPM notification drawer. Wraps\n * children with a context that `<NotificationDrawer />` reads to mount /\n * hide itself, and that the host navigation reads (via\n * `<BPMNotificationBellButton />` or `useNotificationDrawer().open`) to\n * open the drawer when the bell icon is clicked.\n *\n * When used outside this provider, the returned hook is a safe no-op so\n * components don't crash in test or storybook environments.\n */\nexport function NotificationDrawerProvider({\n children,\n}: NotificationDrawerProviderProps): ReactElement {\n const [isOpen, setIsOpen] = useState(false);\n\n const open = useCallback((): void => {\n setIsOpen(true);\n }, []);\n const close = useCallback((): void => {\n setIsOpen(false);\n }, []);\n const toggle = useCallback((): void => {\n setIsOpen((current) => !current);\n }, []);\n\n const value = useMemo<NotificationDrawerContextValue>(\n () => ({ close, isOpen, open, toggle }),\n [close, isOpen, open, toggle],\n );\n\n return (\n <NotificationDrawerContext.Provider value={value}>\n {children}\n </NotificationDrawerContext.Provider>\n );\n}\n\n/**\n * Read the BPM notification drawer's open state and control helpers.\n * Returns a no-op stub when used outside `<NotificationDrawerProvider>`.\n */\nexport function useNotificationDrawer(): NotificationDrawerContextValue {\n const context = useContext(NotificationDrawerContext);\n if (!context) {\n return {\n close: (): void => undefined,\n isOpen: false,\n open: (): void => undefined,\n toggle: (): void => undefined,\n };\n }\n return context;\n}\n","'use client';\n\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n type ReactElement,\n type ReactNode,\n} from 'react';\nimport { readUnreadNotificationCount } from '@rytass/bpm-core-client/workflow';\nimport { useAuth } from './auth-provider';\n\ninterface NotificationUnreadContextValue {\n readonly refreshUnreadCount: () => Promise<number>;\n readonly unreadCount: number;\n}\n\nconst NotificationUnreadContext =\n createContext<NotificationUnreadContextValue | null>(null);\n\ninterface NotificationUnreadProviderProps {\n readonly children: ReactNode;\n}\n\n/**\n * Polls BPM for the current member's unread notification count via\n * `readUnreadNotificationCount` and exposes it through context for the\n * host navigation (`<BPMNotificationBellButton />` badge or any custom\n * trigger using `useNotificationUnread().unreadCount`) and the BPM\n * `<NotificationDrawer />` (header count). Refresh is triggered on\n * mount and whenever the auth member id changes; consumers can call\n * `refreshUnreadCount()` after acknowledging a notification.\n */\nexport function NotificationUnreadProvider({\n children,\n}: NotificationUnreadProviderProps): ReactElement {\n const { member } = useAuth();\n const currentMemberId = member?.memberId ?? null;\n const [unreadCount, setUnreadCount] = useState(0);\n\n const refreshUnreadCount = useCallback(async (): Promise<number> => {\n if (!currentMemberId) {\n setUnreadCount(0);\n return 0;\n }\n const next = await readUnreadNotificationCount(currentMemberId);\n setUnreadCount(next);\n return next;\n }, [currentMemberId]);\n\n useEffect((): (() => void) => {\n let active = true;\n void (async () => {\n try {\n const next = await refreshUnreadCount();\n if (active) setUnreadCount(next);\n } catch {\n if (active) setUnreadCount(0);\n }\n })();\n return (): void => {\n active = false;\n };\n }, [refreshUnreadCount]);\n\n const value = useMemo<NotificationUnreadContextValue>(\n () => ({ refreshUnreadCount, unreadCount }),\n [refreshUnreadCount, unreadCount],\n );\n\n return (\n <NotificationUnreadContext.Provider value={value}>\n {children}\n </NotificationUnreadContext.Provider>\n );\n}\n\n/**\n * Read the current unread-notification count and a manual refresh helper.\n * Returns a zero/no-op stub when used outside\n * `<NotificationUnreadProvider>`.\n */\nexport function useNotificationUnread(): NotificationUnreadContextValue {\n const context = useContext(NotificationUnreadContext);\n if (!context) {\n return {\n refreshUnreadCount: async (): Promise<number> => 0,\n unreadCount: 0,\n };\n }\n return context;\n}\n","import type { DropdownOption } from '@mezzanine-ui/core/dropdown/dropdown';\nimport type { NotificationRecord } from '@rytass/bpm-core-client/workflow';\n\nexport type NotificationAction =\n 'approve' | 'archive' | 'reject' | 'unarchive' | 'view' | 'read';\n\n/**\n * Build the `...` dropdown options for one notification. Approve / reject are\n * offered only while the server still reports the notification as `actionable`\n * (an unresolved task assignment) — once the task is decided / cancelled the\n * backend flips `actionable` to false, so a stale \"同意\" can never appear.\n * A task that fills in form fields (`hasFillableFields`) cannot be approved\n * from here — the fill has to be entered on the case page — so its \"同意\"\n * becomes \"開啟案件\". So does a task at a node that requires an approval\n * comment (`requireApprovalComment`): the drawer has no comment dialog of its\n * own for that, the case page does.\n * \"查看案件\" needs an `instanceId`; \"標為已讀\" only shows while unread.\n * Archiving is independent of read state, so the entry flips between\n * \"封存\" / \"取消封存\" for every notification.\n */\nexport function buildNotificationOptions(\n record: NotificationRecord,\n): readonly DropdownOption[] {\n const payload = readNotificationPayload(record);\n const canReject = readNotificationAllowReject(record, payload) !== false;\n const opensToFill =\n record.actionable &&\n Boolean(record.instanceId) &&\n (readPayloadFlag(payload, 'hasFillableFields') ||\n readPayloadFlag(payload, 'requireApprovalComment'));\n\n return [\n ...(record.actionable\n ? ([\n opensToFill\n ? { id: 'view', name: '開啟案件' }\n : { id: 'approve', name: '同意' },\n ...(canReject ? [{ id: 'reject', name: '拒絕' }] : []),\n ] satisfies DropdownOption[])\n : []),\n ...(record.instanceId && !opensToFill\n ? ([{ id: 'view', name: '查看案件' }] satisfies DropdownOption[])\n : []),\n ...(record.status !== 'READ'\n ? ([{ id: 'read', name: '標為已讀' }] satisfies DropdownOption[])\n : []),\n record.archivedAt\n ? { id: 'unarchive', name: '取消封存' }\n : { id: 'archive', name: '封存' },\n ];\n}\n\n/**\n * The notification's `payloadJson`, parsed once. `null` when it is not a JSON\n * object; every reader below takes this one result.\n */\nfunction readNotificationPayload(\n record: NotificationRecord,\n): Readonly<Record<string, unknown>> | null {\n try {\n const payload: unknown = JSON.parse(record.payloadJson);\n\n return isRecord(payload) ? payload : null;\n } catch {\n return null;\n }\n}\n\nfunction readNotificationAllowReject(\n record: NotificationRecord,\n payload: Readonly<Record<string, unknown>> | null,\n): boolean | null {\n if (payload && typeof payload.allowReject === 'boolean') {\n return payload.allowReject;\n }\n\n return record.allowReject;\n}\n\n/**\n * `true` only when the payload sets the flag to `true`. A missing key, a\n * `false`, or an unparsable payload all read as `false`.\n *\n * `TASK_ASSIGNED` / `TASK_TRANSFERRED` payloads carry `hasFillableFields`, and\n * `requireApprovalComment: true` only when the node asks for a comment on\n * approval. Notifications created before those keys existed read as `false`.\n */\nfunction readPayloadFlag(\n payload: Readonly<Record<string, unknown>> | null,\n key: string,\n): boolean {\n return payload !== null && payload[key] === true;\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","'use client';\n\nimport {\n Fragment,\n useCallback,\n useEffect,\n useMemo,\n useState,\n type ChangeEvent,\n type KeyboardEvent as ReactKeyboardEvent,\n type MouseEvent as ReactMouseEvent,\n type ReactElement,\n} from 'react';\nimport Drawer from '@mezzanine-ui/react/Drawer';\nimport Modal from '@mezzanine-ui/react/Modal';\nimport NotificationCenter from '@mezzanine-ui/react/NotificationCenter';\nimport Textarea from '@mezzanine-ui/react/Textarea';\nimport { Typography } from '@mezzanine-ui/react';\nimport type { NotificationSeverity } from '@mezzanine-ui/core/notification-center';\nimport type { DropdownOption } from '@mezzanine-ui/core/dropdown/dropdown';\nimport {\n archiveNotifications,\n decideTask,\n listNotifications,\n markAllNotificationsRead,\n markNotificationRead,\n unarchiveNotifications,\n type NotificationRecord,\n type NotificationResolution,\n type NotificationType,\n} from '@rytass/bpm-core-client/workflow';\nimport { useAuth } from '../lib/auth-provider';\nimport { useNotificationDrawer } from '../lib/notification-drawer-provider';\nimport { useNotificationUnread } from '../lib/notification-unread-provider';\nimport { useRouterAdapter } from '../lib/router-adapter';\nimport { useBPMRoutes } from '../lib/routes-config';\nimport { BPMFormField } from './bpm-form-field';\nimport {\n buildNotificationOptions,\n type NotificationAction,\n} from './notification-drawer-options';\n\ntype FilterValue = 'all' | 'read' | 'unread';\n\ntype TimeGroup = 'today' | 'yesterday' | 'past7Days' | 'earlier';\n\nconst TIME_GROUP_ORDER: readonly TimeGroup[] = [\n 'today',\n 'yesterday',\n 'past7Days',\n 'earlier',\n];\n\nconst TIME_GROUP_LABEL: Readonly<Record<TimeGroup, string>> = {\n earlier: '更早',\n past7Days: '過去七天',\n today: '今天',\n yesterday: '昨天',\n};\n\nconst PAGE_SIZE = 50;\n\n/** Identifier for the filter-bar dropdown entry toggling the archived view. */\nconst TOGGLE_ARCHIVED_OPTION_ID = 'toggleArchived';\n\n/**\n * Title shown for a resolved task-assignment notification, replacing the\n * stored \"新的待簽任務\" wording so a decided card no longer reads as pending.\n * The stored `body` is kept as historical context (which case / node).\n */\nconst RESOLVED_TITLE: Readonly<Record<NotificationResolution, string>> = {\n APPROVED: '簽核任務已同意',\n REJECTED: '簽核任務已拒絕',\n RETURNED: '簽核任務已退回',\n SUPERSEDED: '簽核任務已結束',\n TRANSFERRED: '簽核任務已轉派',\n};\n\nfunction resolveDisplayTitle(record: NotificationRecord): string {\n return record.resolution ? RESOLVED_TITLE[record.resolution] : record.title;\n}\n\n/**\n * Severity (icon colour) for a notification. Once resolved, it reflects the\n * outcome — green for approved, red for rejected, neutral otherwise — instead\n * of the original by-type colour.\n */\nfunction resolveSeverity(record: NotificationRecord): NotificationSeverity {\n if (record.resolution === 'APPROVED') return 'success';\n if (record.resolution === 'REJECTED') return 'error';\n if (record.resolution) return 'info';\n return toSeverity(record.type);\n}\n\n/**\n * Right-side notification drawer mounted at the root by `<Providers>`.\n * Opens / closes via `useNotificationDrawer()`, polls\n * `listNotifications()` for the current member, supports filter\n * (`all` / `read` / `unread`), per-row mark-read, per-row archive / unarchive,\n * bulk mark-all-read, and load-more pagination. Archived notifications are\n * hidden until the filter-bar menu turns \"顯示已封存\" on. Clicking a row with an\n * `instanceId` navigates to `/instances/<id>` via the host's router adapter.\n */\nexport function NotificationDrawer(): ReactElement | null {\n const router = useRouterAdapter();\n const routes = useBPMRoutes();\n const { member } = useAuth();\n const { close, isOpen } = useNotificationDrawer();\n const { refreshUnreadCount } = useNotificationUnread();\n const currentMemberId = member?.memberId ?? null;\n const [rows, setRows] = useState<readonly NotificationRecord[]>([]);\n const [totalCount, setTotalCount] = useState(0);\n const [page, setPage] = useState(1);\n const [loading, setLoading] = useState(false);\n const [bulkLoading, setBulkLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [notice, setNotice] = useState<string | null>(null);\n const [filter, setFilter] = useState<FilterValue>('all');\n const [includeArchived, setIncludeArchived] = useState(false);\n const [approveTarget, setApproveTarget] = useState<NotificationRecord | null>(\n null,\n );\n const [approveComment, setApproveComment] = useState('');\n const [rejectTarget, setRejectTarget] = useState<NotificationRecord | null>(\n null,\n );\n const [rejectReason, setRejectReason] = useState('');\n const [deciding, setDeciding] = useState(false);\n\n const trimmedApproveComment = approveComment.trim();\n const trimmedRejectReason = rejectReason.trim();\n\n const loadPage = useCallback(\n async (nextPage: number, append: boolean): Promise<boolean> => {\n if (!currentMemberId) return false;\n setLoading(true);\n setError(null);\n try {\n const result = await listNotifications({\n includeArchived,\n includeRead: true,\n page: nextPage,\n pageSize: PAGE_SIZE,\n recipientMemberId: currentMemberId,\n });\n setRows((current): readonly NotificationRecord[] =>\n append ? [...current, ...result.notifications] : result.notifications,\n );\n setTotalCount(result.totalCount);\n setPage(nextPage);\n await refreshUnreadCount();\n return true;\n } catch (e: unknown) {\n setError(readErrorMessage(e));\n return false;\n } finally {\n setLoading(false);\n }\n },\n [currentMemberId, includeArchived, refreshUnreadCount],\n );\n\n useEffect((): void => {\n if (!isOpen || !currentMemberId) return;\n setError(null);\n setNotice(null);\n void loadPage(1, false);\n }, [isOpen, currentMemberId, loadPage]);\n\n const handleFilterChange = useCallback(\n (event: ChangeEvent<HTMLInputElement>): void => {\n const next = event.target.value;\n if (next === 'all' || next === 'read' || next === 'unread') setFilter(next);\n },\n [],\n );\n\n const handleMarkAllRead = useCallback(async (): Promise<void> => {\n if (!currentMemberId || bulkLoading) return;\n setBulkLoading(true);\n setError(null);\n try {\n await markAllNotificationsRead({ recipientMemberId: currentMemberId });\n await loadPage(1, false);\n } catch (e: unknown) {\n setError(readErrorMessage(e));\n } finally {\n setBulkLoading(false);\n }\n }, [bulkLoading, currentMemberId, loadPage]);\n\n const handleLoadMore = useCallback((): void => {\n if (loading) return;\n void loadPage(page + 1, true);\n }, [loading, loadPage, page]);\n\n const handleMarkRead = useCallback(\n async (id: string): Promise<void> => {\n if (!currentMemberId) return;\n try {\n await markNotificationRead({ id, readerMemberId: currentMemberId });\n await loadPage(1, false);\n } catch (e: unknown) {\n setError(readErrorMessage(e));\n }\n },\n [currentMemberId, loadPage],\n );\n\n const handleArchive = useCallback(\n async (record: NotificationRecord): Promise<void> => {\n if (!currentMemberId) return;\n setError(null);\n setNotice(null);\n try {\n // Name the notification the way the row does — `title` is the raw\n // stored title, which can differ from the rendered one.\n const label = resolveDisplayTitle(record);\n\n if (record.archivedAt) {\n await unarchiveNotifications({ ids: [record.id] });\n setNotice(`已將「${label}」移出封存。`);\n } else {\n await archiveNotifications({ ids: [record.id] });\n setNotice(`已封存「${label}」。`);\n }\n await loadPage(1, false);\n } catch (e: unknown) {\n setError(readErrorMessage(e));\n }\n },\n [currentMemberId, loadPage],\n );\n\n const handleFilterAreaSelect = useCallback((option: DropdownOption): void => {\n if (option.id !== TOGGLE_ARCHIVED_OPTION_ID) return;\n setNotice(null);\n setIncludeArchived((current): boolean => !current);\n }, []);\n\n const handleOpenInstance = useCallback(\n async (record: NotificationRecord): Promise<void> => {\n if (!record.instanceId || !currentMemberId) return;\n try {\n if (record.status !== 'READ') {\n await markNotificationRead({\n id: record.id,\n readerMemberId: currentMemberId,\n });\n await refreshUnreadCount();\n }\n close();\n router.push(routes.caseDetail(record.instanceId));\n } catch (e: unknown) {\n setError(readErrorMessage(e));\n }\n },\n [close, currentMemberId, refreshUnreadCount, router, routes],\n );\n\n const openApproveModal = useCallback((record: NotificationRecord): void => {\n setError(null);\n setApproveTarget(record);\n setApproveComment('');\n }, []);\n\n const closeApproveModal = useCallback((): void => {\n if (deciding) return;\n setApproveTarget(null);\n setApproveComment('');\n }, [deciding]);\n\n const handleApproveConfirm = useCallback(async (): Promise<void> => {\n const target = approveTarget;\n if (!target?.taskId || !currentMemberId || deciding) return;\n setDeciding(true);\n setError(null);\n setNotice(null);\n try {\n await decideTask({\n action: 'APPROVED',\n comment: trimmedApproveComment || null,\n decidedByMemberId: currentMemberId,\n taskId: target.taskId,\n });\n const refreshed = await loadPage(1, false);\n if (!refreshed) return;\n setApproveTarget(null);\n setApproveComment('');\n setNotice(`已同意「${target.title}」。`);\n } catch (e: unknown) {\n setError(readErrorMessage(e));\n } finally {\n setDeciding(false);\n }\n }, [\n approveTarget,\n currentMemberId,\n deciding,\n loadPage,\n trimmedApproveComment,\n ]);\n\n const openRejectModal = useCallback((record: NotificationRecord): void => {\n setRejectTarget(record);\n setRejectReason('');\n }, []);\n\n const closeRejectModal = useCallback((): void => {\n setRejectTarget(null);\n setRejectReason('');\n }, []);\n\n const handleRejectConfirm = useCallback(async (): Promise<void> => {\n const target = rejectTarget;\n if (!target?.taskId || !currentMemberId || !trimmedRejectReason || deciding)\n return;\n setDeciding(true);\n setError(null);\n setNotice(null);\n try {\n await decideTask({\n action: 'REJECTED',\n comment: trimmedRejectReason,\n decidedByMemberId: currentMemberId,\n taskId: target.taskId,\n });\n setRejectTarget(null);\n setRejectReason('');\n setNotice(`已拒絕「${target.title}」。`);\n await loadPage(1, false);\n } catch (e: unknown) {\n setError(readErrorMessage(e));\n } finally {\n setDeciding(false);\n }\n }, [currentMemberId, deciding, loadPage, rejectTarget, trimmedRejectReason]);\n\n const handleBadgeSelect = useCallback(\n (record: NotificationRecord, option: DropdownOption): void => {\n const action = option.id as NotificationAction;\n if (action === 'approve') openApproveModal(record);\n else if (action === 'reject') openRejectModal(record);\n else if (action === 'view') void handleOpenInstance(record);\n else if (action === 'read') void handleMarkRead(record.id);\n else if (action === 'archive' || action === 'unarchive')\n void handleArchive(record);\n },\n [\n handleArchive,\n handleMarkRead,\n handleOpenInstance,\n openApproveModal,\n openRejectModal,\n ],\n );\n\n /**\n * Whether an event that reached the card wrapper actually happened inside the\n * card, and not on one of its action controls.\n *\n * Two escape hatches are needed. The `...` menu button (and its `<svg>` icon —\n * hence the `Element` check, SVG nodes are not HTMLElements) sits inside the\n * card and must open the dropdown rather than navigate. The dropdown itself\n * renders into a portal, and React replays events along the component tree\n * rather than the DOM tree, so picking \"封存\" also reaches this handler even\n * though the `<li role=\"option\">` lives outside the card's DOM — and it is not\n * a `<button>`, so the first guard alone misses it.\n */\n const isCardActivation = useCallback(\n (target: EventTarget | null, card: HTMLDivElement): boolean => {\n if (!(target instanceof Node) || !card.contains(target)) return false;\n\n return !(target instanceof Element && target.closest('button'));\n },\n [],\n );\n\n const handleCardActivate = useCallback(\n (record: NotificationRecord, event: ReactMouseEvent<HTMLDivElement>): void => {\n if (!isCardActivation(event.target, event.currentTarget)) return;\n void handleOpenInstance(record);\n },\n [handleOpenInstance, isCardActivation],\n );\n\n const handleCardKeyDown = useCallback(\n (\n record: NotificationRecord,\n event: ReactKeyboardEvent<HTMLDivElement>,\n ): void => {\n if (event.key !== 'Enter' && event.key !== ' ') return;\n if (!isCardActivation(event.target, event.currentTarget)) return;\n event.preventDefault();\n void handleOpenInstance(record);\n },\n [handleOpenInstance, isCardActivation],\n );\n\n const filteredRows = useMemo(\n (): readonly NotificationRecord[] =>\n rows.filter((row): boolean => {\n if (filter === 'all') return true;\n if (filter === 'read') return row.status === 'READ';\n return row.status !== 'READ';\n }),\n [filter, rows],\n );\n\n const groupedRows = useMemo(\n (): ReadonlyArray<readonly [TimeGroup, readonly NotificationRecord[]]> => {\n const now = new Date();\n const buckets = TIME_GROUP_ORDER.reduce<\n Record<TimeGroup, NotificationRecord[]>\n >(\n (accumulator, group) => {\n accumulator[group] = [];\n return accumulator;\n },\n { earlier: [], past7Days: [], today: [], yesterday: [] },\n );\n filteredRows.forEach((row): void => {\n buckets[resolveTimeGroup(row.createdAt, now)].push(row);\n });\n return TIME_GROUP_ORDER.map(\n (group) => [group, buckets[group]] as const,\n ).filter(([, items]) => items.length > 0);\n },\n [filteredRows],\n );\n\n const hasMore = rows.length < totalCount;\n\n if (!currentMemberId) return null;\n\n return (\n <>\n <Drawer\n bottomGhostActionDisabled={bulkLoading || loading}\n bottomGhostActionLoading={bulkLoading}\n bottomGhostActionText=\"全部標為已讀\"\n bottomOnGhostActionClick={(): void => {\n void handleMarkAllRead();\n }}\n bottomOnPrimaryActionClick={(): void => {\n handleLoadMore();\n }}\n bottomPrimaryActionDisabled={!hasMore || loading}\n bottomPrimaryActionLoading={loading && hasMore}\n bottomPrimaryActionText={hasMore ? '載入更多' : '已顯示全部'}\n contentKey={`${filter}:${includeArchived}:${rows.length}`}\n filterAreaAllRadioLabel=\"全部\"\n filterAreaOnRadioChange={handleFilterChange}\n filterAreaOnSelect={handleFilterAreaSelect}\n filterAreaOptions={[\n {\n id: TOGGLE_ARCHIVED_OPTION_ID,\n name: includeArchived ? '隱藏已封存' : '顯示已封存',\n },\n ]}\n filterAreaReadRadioLabel=\"已讀\"\n filterAreaShow\n filterAreaUnreadRadioLabel=\"未讀\"\n filterAreaValue={filter}\n headerTitle=\"通知中心\"\n isBottomDisplay\n isHeaderDisplay\n onClose={close}\n open={isOpen}\n size=\"medium\"\n >\n <div role=\"list\">\n {error ? (\n <p\n role=\"alert\"\n style={{\n color: 'var(--mzn-color-text-error, #d92d20)',\n padding: '12px 16px',\n }}\n >\n {error}\n </p>\n ) : null}\n {notice ? (\n <p\n role=\"status\"\n style={{\n color: 'var(--mzn-color-text-success, #079455)',\n padding: '12px 16px',\n }}\n >\n {notice}\n </p>\n ) : null}\n {groupedRows.length === 0 ? (\n <p\n style={{\n color: 'var(--mzn-color-text-secondary, #6b7280)',\n padding: '24px 16px',\n textAlign: 'center',\n }}\n >\n {loading ? '載入中…' : '目前沒有通知'}\n </p>\n ) : null}\n {groupedRows.map(([group, items]) => (\n <Fragment key={group}>\n {items.map((record, itemIndex) => {\n const openable = record.instanceId !== null;\n\n return (\n <div\n key={record.id}\n onClick={\n openable\n ? (event: ReactMouseEvent<HTMLDivElement>): void => {\n handleCardActivate(record, event);\n }\n : undefined\n }\n onKeyDown={\n openable\n ? (event: ReactKeyboardEvent<HTMLDivElement>): void => {\n handleCardKeyDown(record, event);\n }\n : undefined\n }\n role={openable ? 'button' : undefined}\n style={openable ? { cursor: 'pointer' } : undefined}\n tabIndex={openable ? 0 : undefined}\n >\n <NotificationCenter\n appendTips={record.archivedAt ? '已封存' : undefined}\n description={record.body}\n onBadgeSelect={(option: DropdownOption): void => {\n handleBadgeSelect(record, option);\n }}\n options={[...buildNotificationOptions(record)]}\n prependTips={\n itemIndex === 0 ? TIME_GROUP_LABEL[group] : undefined\n }\n reference={record.id}\n severity={resolveSeverity(record)}\n showBadge={record.status !== 'READ'}\n timeStamp={record.createdAt}\n title={resolveDisplayTitle(record)}\n type=\"drawer\"\n />\n </div>\n );\n })}\n </Fragment>\n ))}\n </div>\n </Drawer>\n <Modal\n cancelText=\"取消\"\n confirmText=\"送出同意\"\n loading={deciding}\n modalType=\"standard\"\n onCancel={closeApproveModal}\n onClose={closeApproveModal}\n onConfirm={(): void => {\n void handleApproveConfirm();\n }}\n open={approveTarget !== null}\n showModalFooter\n showModalHeader\n size=\"regular\"\n supportingText=\"可以留下同意說明,內容會記錄在簽核歷程;不填也可以直接送出。\"\n title=\"簽核意見\"\n >\n {error ? (\n <Typography color=\"text-error\" role=\"alert\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n <BPMFormField label=\"簽核意見\" name=\"notificationApproveComment\">\n <Textarea\n autoFocus\n onChange={(event: ChangeEvent<HTMLTextAreaElement>): void => {\n setApproveComment(event.target.value);\n }}\n placeholder=\"選填,例如補充核准條件或提醒事項\"\n rows={4}\n value={approveComment}\n />\n </BPMFormField>\n </Modal>\n <Modal\n cancelText=\"取消\"\n confirmButtonProps={{\n disabled: !trimmedRejectReason,\n variant: 'destructive-primary',\n }}\n confirmText=\"送出拒絕\"\n loading={deciding}\n modalStatusType=\"error\"\n modalType=\"standard\"\n onCancel={closeRejectModal}\n onClose={closeRejectModal}\n onConfirm={(): void => {\n void handleRejectConfirm();\n }}\n open={rejectTarget !== null}\n showModalFooter\n showModalHeader\n size=\"regular\"\n supportingText=\"拒絕案件時必須留下原因,供發起人與後續追蹤查看。\"\n title=\"拒絕原因\"\n >\n <Textarea\n autoFocus\n onChange={(event: ChangeEvent<HTMLTextAreaElement>): void => {\n setRejectReason(event.target.value);\n }}\n placeholder=\"請輸入拒絕原因\"\n rows={4}\n value={rejectReason}\n />\n </Modal>\n </>\n );\n}\n\nfunction toSeverity(type: NotificationType): NotificationSeverity {\n if (type === 'SLA_OVERDUE') return 'error';\n if (type === 'SLA_WARNING') return 'warning';\n if (type === 'INSTANCE_COMPLETED') return 'success';\n return 'info';\n}\n\nfunction resolveTimeGroup(value: string, now: Date): TimeGroup {\n const notificationDate = new Date(value);\n if (Number.isNaN(notificationDate.getTime())) return 'earlier';\n const nowStartOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const notificationStartOfDay = new Date(\n notificationDate.getFullYear(),\n notificationDate.getMonth(),\n notificationDate.getDate(),\n );\n if (notificationStartOfDay.getTime() === nowStartOfDay.getTime()) return 'today';\n const yesterdayStartOfDay = new Date(nowStartOfDay);\n yesterdayStartOfDay.setDate(yesterdayStartOfDay.getDate() - 1);\n if (notificationStartOfDay.getTime() === yesterdayStartOfDay.getTime())\n return 'yesterday';\n const diffInDays =\n (now.getTime() - notificationDate.getTime()) / (1000 * 60 * 60 * 24);\n if (diffInDays <= 7) return 'past7Days';\n return 'earlier';\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n","'use client';\n\nimport type { ReactElement, ReactNode } from 'react';\nimport {\n CalendarConfigProviderMoment,\n CalendarLocale,\n} from '@mezzanine-ui/react/moment';\nimport { AuthProvider } from './auth-provider';\nimport {\n BPMLanguageProvider,\n DEFAULT_BPM_LANGUAGE,\n type BPMLanguage,\n} from './language-provider';\nimport { BPMOrganizationTimeZoneProvider } from './organization-time-zone-provider';\nimport { NotificationDrawer } from '../components/notification-drawer';\nimport { NotificationDrawerProvider } from './notification-drawer-provider';\nimport { NotificationUnreadProvider } from './notification-unread-provider';\n\ninterface ProvidersProps {\n readonly children: ReactNode;\n /** Override Mezzanine calendar locale. Defaults to `CalendarLocale.ZH_TW`. */\n readonly locale?: CalendarLocale;\n /**\n * Language BPM views write their messages in, such as publish-lint errors.\n * Defaults to `'zh-TW'`. Pass the user's choice as state to let them switch.\n * Independent of `locale`, which only formats calendar dates.\n */\n readonly language?: BPMLanguage;\n /**\n * IANA zone in which BPM views read \"today\" against organization effective\n * dates. Pass the same value given to `BPMRootModule` as\n * `organizationTimeZone`; leave it unset when the API does not set one.\n * Defaults to `DEFAULT_BPM_ORGANIZATION_TIME_ZONE` (`'Asia/Taipei'`); an\n * unknown zone falls back to it with a console warning.\n */\n readonly organizationTimeZone?: string;\n /**\n * Public paths that should not trigger redirect to `/login` when there\n * is no session. Forwarded to `<AuthProvider>`. Defaults to `['/login']`.\n */\n readonly publicPaths?: readonly string[];\n /** Where to send unauthenticated users. Defaults to `'/login'`. */\n readonly loginPath?: string;\n}\n\n/**\n * One-stop BPM admin provider stack. Wires:\n *\n * - Mezzanine UI calendar locale (moment-based, `ZH_TW` by default)\n * - `<BPMLanguageProvider>` (message language, `'zh-TW'` by default)\n * - `<BPMOrganizationTimeZoneProvider>` (organization \"today\" zone)\n * - `<AuthProvider>` (BPM session via REST `/auth/*`)\n * - `<NotificationUnreadProvider>` (polls unread count)\n * - `<NotificationDrawerProvider>` (controls drawer open/close state)\n * - `<NotificationDrawer />` mounted at the root so the host navigation\n * bell (`<BPMNotificationBellButton />` or any custom trigger calling\n * `useNotificationDrawer().open`) can open it.\n *\n * Consumer hosts wrap this **inside** a `<RouterAdapterProvider>` (provided\n * by the `pages/*` subpath shims when consuming via Next.js, or wired by\n * hand for other frameworks).\n */\nexport function Providers({\n children,\n locale = CalendarLocale.ZH_TW,\n language = DEFAULT_BPM_LANGUAGE,\n organizationTimeZone,\n publicPaths,\n loginPath,\n}: ProvidersProps): ReactElement {\n return (\n <CalendarConfigProviderMoment locale={locale}>\n <BPMLanguageProvider language={language}>\n <BPMOrganizationTimeZoneProvider timeZone={organizationTimeZone}>\n <AuthProvider publicPaths={publicPaths} loginPath={loginPath}>\n <NotificationUnreadProvider>\n <NotificationDrawerProvider>\n {children}\n <NotificationDrawer />\n </NotificationDrawerProvider>\n </NotificationUnreadProvider>\n </AuthProvider>\n </BPMOrganizationTimeZoneProvider>\n </BPMLanguageProvider>\n </CalendarConfigProviderMoment>\n );\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use client";let e=require("react"),t=require("react/jsx-runtime");function n(){return{dashboard:()=>`/dashboard`,inbox:()=>`/inbox`,sent:()=>`/sent`,cc:()=>`/cc`,search:()=>`/search`,delegations:()=>`/delegations`,notifications:()=>`/notifications`,caseDetail:e=>`/instances/${e}`,caseNew:e=>e?`/instances/new?templateId=${encodeURIComponent(e)}`:`/instances/new`,templates:()=>`/templates`,templateCompose:()=>`/templates/compose`,templateDesigner:e=>`/templates/${e}/designer`,templateVersions:e=>`/templates/${e}/versions`,templateCategories:()=>`/templates/categories`,notificationSettings:()=>`/settings/notifications`,adminOrgs:()=>`/admin/orgs`,adminUsers:()=>`/admin/users`,adminDelegations:()=>`/admin/delegations`,adminWebhookEndpoints:()=>`/admin/webhook-endpoints`}}var r=(0,e.createContext)(null);function i({value:i,children:a}){let o=(0,e.useMemo)(()=>i??n(),[i]);return(0,t.jsx)(r.Provider,{value:o,children:a})}function a(){return(0,e.useContext)(r)??o}var o=n();Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return n}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return i}});
2
- //# sourceMappingURL=routes-config-C1j_vFKo.cjs.map
1
+ "use client";let e=require("react"),t=require("react/jsx-runtime");function n(){return{dashboard:()=>`/dashboard`,inbox:()=>`/inbox`,sent:()=>`/sent`,cc:()=>`/cc`,search:()=>`/search`,delegations:()=>`/delegations`,notifications:()=>`/notifications`,caseDetail:e=>`/instances/${e}`,caseNew:e=>e?`/instances/new?templateId=${encodeURIComponent(e)}`:`/instances/new`,templates:()=>`/templates`,templateCompose:()=>`/templates/compose`,templateDesigner:e=>`/templates/${e}/designer`,templateVersions:e=>`/templates/${e}/versions`,templateCategories:()=>`/templates/categories`,notificationSettings:()=>`/settings/notifications`,adminOrgs:()=>`/admin/orgs`,adminUsers:()=>`/admin/users`,adminDelegations:()=>`/admin/delegations`,adminWebhookEndpoints:()=>`/admin/webhook-endpoints`,adminStuckInstances:()=>`/admin/stuck-instances`}}var r=(0,e.createContext)(null);function i({value:i,children:a}){let o=(0,e.useMemo)(()=>i??n(),[i]);return(0,t.jsx)(r.Provider,{value:o,children:a})}function a(){return(0,e.useContext)(r)??o}var o=n();Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return n}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return i}});
2
+ //# sourceMappingURL=routes-config-BWjZDAU3.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"routes-config-C1j_vFKo.cjs","names":["createContext","useMemo","useContext","react","react_jsx_runtime","createDefaultBPMRoutes","instanceId","templateId","BPMRoutesContext","BPMRoutesProvider","resolved","value","useBPMRoutes","DEFAULT_ROUTES"],"sources":["../../src/lib/routes-config.tsx"],"sourcesContent":["'use client';\n\nimport {\n createContext,\n useContext,\n useMemo,\n type ReactElement,\n type ReactNode,\n} from 'react';\n\n/**\n * Framework-agnostic path mapping every BPM view uses for internal\n * cross-navigation. When a host embeds BPM under a non-root prefix\n * (e.g. `/workspace/bpm/*`) it provides its own implementation through\n * `<BPMRoutesProvider value={...}>`; otherwise the default factory\n * preserves the historical `/instances/:id`, `/templates`, etc. paths.\n *\n * Function-shape (instead of string templates) means:\n * - Optional and multi-param routes can branch on argument presence\n * (`caseNew(templateId?)`).\n * - Query-string composition stays inside the host's resolver, not the\n * view.\n * - TypeScript flags missing arguments at compile time.\n *\n * Mirror sibling: {@link RouterAdapter} owns *navigation primitives*\n * (`push`, `replace`, `pathname`); `BPMRoutes` owns *path strings*. The\n * two compose: views call `router.push(routes.caseDetail(id))`.\n */\nexport interface BPMRoutes {\n /** Workflow dashboard landing. Used by sidebar + dashboard tiles. */\n dashboard(): string;\n /** Inbox (待簽) — pending tasks assigned to the current member. */\n inbox(): string;\n /** Sent (我發起的) — instances the current member initiated or submitted on someone's behalf. */\n sent(): string;\n /** CC (抄送給我) — instances the current member is copied on. */\n cc(): string;\n /** Cross-view search. */\n search(): string;\n /** Personal delegation rules. */\n delegations(): string;\n /**\n * Reserved for hosts that want a dedicated `/notifications` page —\n * BPM's built-in views do **not** navigate here by default (the\n * notification drawer mounted by `<BPMNextProviders>` is the primary\n * unread-notification UX). The `createDefaultBPMRoutes()` factory\n * returns `'/notifications'` so consumers can mount their own page\n * at that path if desired; no BPM-shipped `pages/notifications`\n * shim exists.\n */\n notifications(): string;\n\n /**\n * Detail page for one approval instance.\n *\n * @example default → `/instances/abc123`\n */\n caseDetail(instanceId: string): string;\n /**\n * Launch a new approval instance. When `templateId` is passed, the\n * launch form is pre-populated for that template — by default this is\n * appended as a `?templateId=` query string so the path itself stays\n * stable for routing.\n *\n * @example default `caseNew()` → `/instances/new`\n * @example default `caseNew('tpl-1')` → `/instances/new?templateId=tpl-1`\n */\n caseNew(templateId?: string): string;\n\n /** Template index. */\n templates(): string;\n /**\n * Unified \"form + flow\" creation wizard. Designs a form and an approval\n * flow together, then publishes both atomically. This is the only place\n * forms are designed — there is no separate standalone form builder page.\n */\n templateCompose(): string;\n /** Template designer (xyflow canvas). */\n templateDesigner(templateId: string): string;\n /** Template version history. */\n templateVersions(templateId: string): string;\n /** Template categories admin. */\n templateCategories(): string;\n\n /** Per-member notification preferences. */\n notificationSettings(): string;\n\n /** Admin: organization tree management. */\n adminOrgs(): string;\n /** Admin: member directory mapping. */\n adminUsers(): string;\n /** Admin: delegation rule management. */\n adminDelegations(): string;\n /** Admin: database-managed notify webhook endpoints (ADR 18). */\n adminWebhookEndpoints(): string;\n}\n\n/**\n * Factory for the default `BPMRoutes` value. Reproduces the exact path\n * literals BPM views used before `BPMRoutesContext` existed, so existing\n * hosts (no provider mounted) keep working unchanged.\n */\nexport function createDefaultBPMRoutes(): BPMRoutes {\n return {\n dashboard: () => '/dashboard',\n inbox: () => '/inbox',\n sent: () => '/sent',\n cc: () => '/cc',\n search: () => '/search',\n delegations: () => '/delegations',\n notifications: () => '/notifications',\n\n caseDetail: (instanceId) => `/instances/${instanceId}`,\n caseNew: (templateId) =>\n templateId\n ? `/instances/new?templateId=${encodeURIComponent(templateId)}`\n : '/instances/new',\n\n templates: () => '/templates',\n templateCompose: () => '/templates/compose',\n templateDesigner: (templateId) => `/templates/${templateId}/designer`,\n templateVersions: (templateId) => `/templates/${templateId}/versions`,\n templateCategories: () => '/templates/categories',\n\n notificationSettings: () => '/settings/notifications',\n\n adminOrgs: () => '/admin/orgs',\n adminUsers: () => '/admin/users',\n adminDelegations: () => '/admin/delegations',\n adminWebhookEndpoints: () => '/admin/webhook-endpoints',\n };\n}\n\nconst BPMRoutesContext = createContext<BPMRoutes | null>(null);\n\nexport interface BPMRoutesProviderProps {\n /**\n * Override the path mapping. Provide a full implementation, or spread\n * the default and override individual entries:\n *\n * ```tsx\n * <BPMRoutesProvider value={{\n * ...createDefaultBPMRoutes(),\n * caseDetail: (id) => `/workspace/cases/${id}`,\n * }}>\n * ```\n */\n readonly value?: BPMRoutes;\n readonly children: ReactNode;\n}\n\n/**\n * Wraps the BPM React tree with a {@link BPMRoutes} value. Mounting the\n * provider is **optional** — `useBPMRoutes()` falls back to\n * {@link createDefaultBPMRoutes} when no provider is present. Use it\n * only when the host needs to remap BPM's internal paths.\n */\nexport function BPMRoutesProvider({\n value,\n children,\n}: BPMRoutesProviderProps): ReactElement {\n const resolved = useMemo(() => value ?? createDefaultBPMRoutes(), [value]);\n return (\n <BPMRoutesContext.Provider value={resolved}>\n {children}\n </BPMRoutesContext.Provider>\n );\n}\n\n/**\n * Reads the host-configured {@link BPMRoutes}. Falls back to\n * {@link createDefaultBPMRoutes} when no `<BPMRoutesProvider>` ancestor\n * is mounted, so views remain self-contained.\n */\nexport function useBPMRoutes(): BPMRoutes {\n const value = useContext(BPMRoutesContext);\n return value ?? DEFAULT_ROUTES;\n}\n\nconst DEFAULT_ROUTES: BPMRoutes = createDefaultBPMRoutes();\n"],"mappings":"A,mEAsGA,SAAgBK,GAAoC,CAClD,MAAO,CACL,cAAiB,aACjB,UAAa,SACb,SAAY,QACZ,OAAU,MACV,WAAc,UACd,gBAAmB,eACnB,kBAAqB,iBAErB,WAAa,GAAe,cAAcC,IAC1C,QAAU,GACRC,EACI,6BAA6B,mBAAmBA,CAAU,IAC1D,iBAEN,cAAiB,aACjB,oBAAuB,qBACvB,iBAAmB,GAAe,cAAcA,EAAW,WAC3D,iBAAmB,GAAe,cAAcA,EAAW,WAC3D,uBAA0B,wBAE1B,yBAA4B,0BAE5B,cAAiB,cACjB,eAAkB,eAClB,qBAAwB,qBACxB,0BAA6B,0BAC/B,CACF,CAEA,IAAMC,GAAA,EAAmBR,EAAAA,cAAAA,CAAgC,IAAI,EAwB7D,SAAgBS,EAAkB,CAChC,QACA,YACuC,CACvC,IAAMC,GAAA,EAAWT,EAAAA,QAAAA,KAAcU,GAASN,EAAuB,EAAG,CAACM,CAAK,CAAC,EACzE,OACE,EAAAP,EAAA,IAAA,CAACI,EAAiB,SAAlB,CAA2B,MAAOE,EAC/B,UACwB,CAAA,CAE/B,CAOA,SAAgBE,GAA0B,CAExC,OAAA,EADcV,EAAAA,WAAAA,CAAWM,CAClB,GAASK,CAClB,CAEA,IAAMA,EAA4BR,EAAuB,E"}
1
+ {"version":3,"file":"routes-config-BWjZDAU3.cjs","names":["createContext","useMemo","useContext","react","react_jsx_runtime","createDefaultBPMRoutes","instanceId","templateId","BPMRoutesContext","BPMRoutesProvider","resolved","value","useBPMRoutes","DEFAULT_ROUTES"],"sources":["../../src/lib/routes-config.tsx"],"sourcesContent":["'use client';\n\nimport {\n createContext,\n useContext,\n useMemo,\n type ReactElement,\n type ReactNode,\n} from 'react';\n\n/**\n * Framework-agnostic path mapping every BPM view uses for internal\n * cross-navigation. When a host embeds BPM under a non-root prefix\n * (e.g. `/workspace/bpm/*`) it provides its own implementation through\n * `<BPMRoutesProvider value={...}>`; otherwise the default factory\n * preserves the historical `/instances/:id`, `/templates`, etc. paths.\n *\n * Function-shape (instead of string templates) means:\n * - Optional and multi-param routes can branch on argument presence\n * (`caseNew(templateId?)`).\n * - Query-string composition stays inside the host's resolver, not the\n * view.\n * - TypeScript flags missing arguments at compile time.\n *\n * Mirror sibling: {@link RouterAdapter} owns *navigation primitives*\n * (`push`, `replace`, `pathname`); `BPMRoutes` owns *path strings*. The\n * two compose: views call `router.push(routes.caseDetail(id))`.\n */\nexport interface BPMRoutes {\n /** Workflow dashboard landing. Used by sidebar + dashboard tiles. */\n dashboard(): string;\n /** Inbox (待簽) — pending tasks assigned to the current member. */\n inbox(): string;\n /** Sent (我發起的) — instances the current member initiated or submitted on someone's behalf. */\n sent(): string;\n /** CC (抄送給我) — instances the current member is copied on. */\n cc(): string;\n /** Cross-view search. */\n search(): string;\n /** Personal delegation rules. */\n delegations(): string;\n /**\n * Reserved for hosts that want a dedicated `/notifications` page —\n * BPM's built-in views do **not** navigate here by default (the\n * notification drawer mounted by `<BPMNextProviders>` is the primary\n * unread-notification UX). The `createDefaultBPMRoutes()` factory\n * returns `'/notifications'` so consumers can mount their own page\n * at that path if desired; no BPM-shipped `pages/notifications`\n * shim exists.\n */\n notifications(): string;\n\n /**\n * Detail page for one approval instance.\n *\n * @example default → `/instances/abc123`\n */\n caseDetail(instanceId: string): string;\n /**\n * Launch a new approval instance. When `templateId` is passed, the\n * launch form is pre-populated for that template — by default this is\n * appended as a `?templateId=` query string so the path itself stays\n * stable for routing.\n *\n * @example default `caseNew()` → `/instances/new`\n * @example default `caseNew('tpl-1')` → `/instances/new?templateId=tpl-1`\n */\n caseNew(templateId?: string): string;\n\n /** Template index. */\n templates(): string;\n /**\n * Unified \"form + flow\" creation wizard. Designs a form and an approval\n * flow together, then publishes both atomically. This is the only place\n * forms are designed — there is no separate standalone form builder page.\n */\n templateCompose(): string;\n /** Template designer (xyflow canvas). */\n templateDesigner(templateId: string): string;\n /** Template version history. */\n templateVersions(templateId: string): string;\n /** Template categories admin. */\n templateCategories(): string;\n\n /** Per-member notification preferences. */\n notificationSettings(): string;\n\n /** Admin: organization tree management. */\n adminOrgs(): string;\n /** Admin: member directory mapping. */\n adminUsers(): string;\n /** Admin: delegation rule management. */\n adminDelegations(): string;\n /** Admin: database-managed notify webhook endpoints (ADR 18). */\n adminWebhookEndpoints(): string;\n /** Admin: approval instances stuck after a failed advance, with cancel. */\n adminStuckInstances(): string;\n}\n\n/**\n * Factory for the default `BPMRoutes` value. Reproduces the exact path\n * literals BPM views used before `BPMRoutesContext` existed, so existing\n * hosts (no provider mounted) keep working unchanged.\n */\nexport function createDefaultBPMRoutes(): BPMRoutes {\n return {\n dashboard: () => '/dashboard',\n inbox: () => '/inbox',\n sent: () => '/sent',\n cc: () => '/cc',\n search: () => '/search',\n delegations: () => '/delegations',\n notifications: () => '/notifications',\n\n caseDetail: (instanceId) => `/instances/${instanceId}`,\n caseNew: (templateId) =>\n templateId\n ? `/instances/new?templateId=${encodeURIComponent(templateId)}`\n : '/instances/new',\n\n templates: () => '/templates',\n templateCompose: () => '/templates/compose',\n templateDesigner: (templateId) => `/templates/${templateId}/designer`,\n templateVersions: (templateId) => `/templates/${templateId}/versions`,\n templateCategories: () => '/templates/categories',\n\n notificationSettings: () => '/settings/notifications',\n\n adminOrgs: () => '/admin/orgs',\n adminUsers: () => '/admin/users',\n adminDelegations: () => '/admin/delegations',\n adminWebhookEndpoints: () => '/admin/webhook-endpoints',\n adminStuckInstances: () => '/admin/stuck-instances',\n };\n}\n\nconst BPMRoutesContext = createContext<BPMRoutes | null>(null);\n\nexport interface BPMRoutesProviderProps {\n /**\n * Override the path mapping. Provide a full implementation, or spread\n * the default and override individual entries:\n *\n * ```tsx\n * <BPMRoutesProvider value={{\n * ...createDefaultBPMRoutes(),\n * caseDetail: (id) => `/workspace/cases/${id}`,\n * }}>\n * ```\n */\n readonly value?: BPMRoutes;\n readonly children: ReactNode;\n}\n\n/**\n * Wraps the BPM React tree with a {@link BPMRoutes} value. Mounting the\n * provider is **optional** — `useBPMRoutes()` falls back to\n * {@link createDefaultBPMRoutes} when no provider is present. Use it\n * only when the host needs to remap BPM's internal paths.\n */\nexport function BPMRoutesProvider({\n value,\n children,\n}: BPMRoutesProviderProps): ReactElement {\n const resolved = useMemo(() => value ?? createDefaultBPMRoutes(), [value]);\n return (\n <BPMRoutesContext.Provider value={resolved}>\n {children}\n </BPMRoutesContext.Provider>\n );\n}\n\n/**\n * Reads the host-configured {@link BPMRoutes}. Falls back to\n * {@link createDefaultBPMRoutes} when no `<BPMRoutesProvider>` ancestor\n * is mounted, so views remain self-contained.\n */\nexport function useBPMRoutes(): BPMRoutes {\n const value = useContext(BPMRoutesContext);\n return value ?? DEFAULT_ROUTES;\n}\n\nconst DEFAULT_ROUTES: BPMRoutes = createDefaultBPMRoutes();\n"],"mappings":"A,mEAwGA,SAAgBK,GAAoC,CAClD,MAAO,CACL,cAAiB,aACjB,UAAa,SACb,SAAY,QACZ,OAAU,MACV,WAAc,UACd,gBAAmB,eACnB,kBAAqB,iBAErB,WAAa,GAAe,cAAcC,IAC1C,QAAU,GACRC,EACI,6BAA6B,mBAAmBA,CAAU,IAC1D,iBAEN,cAAiB,aACjB,oBAAuB,qBACvB,iBAAmB,GAAe,cAAcA,EAAW,WAC3D,iBAAmB,GAAe,cAAcA,EAAW,WAC3D,uBAA0B,wBAE1B,yBAA4B,0BAE5B,cAAiB,cACjB,eAAkB,eAClB,qBAAwB,qBACxB,0BAA6B,2BAC7B,wBAA2B,wBAC7B,CACF,CAEA,IAAMC,GAAA,EAAmBR,EAAAA,cAAAA,CAAgC,IAAI,EAwB7D,SAAgBS,EAAkB,CAChC,QACA,YACuC,CACvC,IAAMC,GAAA,EAAWT,EAAAA,QAAAA,KAAcU,GAASN,EAAuB,EAAG,CAACM,CAAK,CAAC,EACzE,OACE,EAAAP,EAAA,IAAA,CAACI,EAAiB,SAAlB,CAA2B,MAAOE,EAC/B,UACwB,CAAA,CAE/B,CAOA,SAAgBE,GAA0B,CAExC,OAAA,EADcV,EAAAA,WAAAA,CAAWM,CAClB,GAASK,CAClB,CAEA,IAAMA,EAA4BR,EAAuB,E"}
@@ -22,7 +22,8 @@ function i() {
22
22
  adminOrgs: () => "/admin/orgs",
23
23
  adminUsers: () => "/admin/users",
24
24
  adminDelegations: () => "/admin/delegations",
25
- adminWebhookEndpoints: () => "/admin/webhook-endpoints"
25
+ adminWebhookEndpoints: () => "/admin/webhook-endpoints",
26
+ adminStuckInstances: () => "/admin/stuck-instances"
26
27
  };
27
28
  }
28
29
  var a = e(null);
@@ -39,4 +40,4 @@ function s() {
39
40
  var c = i();
40
41
  export { i as n, s as r, o as t };
41
42
 
42
- //# sourceMappingURL=routes-config-BcNaWJWJ.js.map
43
+ //# sourceMappingURL=routes-config-DjEOE9eP.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"routes-config-BcNaWJWJ.js","names":["createDefaultBPMRoutes","instanceId","templateId","BPMRoutesContext","createContext","BPMRoutesProvider","resolved","useMemo","value","useBPMRoutes","useContext","DEFAULT_ROUTES"],"sources":["../../src/lib/routes-config.tsx"],"sourcesContent":["'use client';\n\nimport {\n createContext,\n useContext,\n useMemo,\n type ReactElement,\n type ReactNode,\n} from 'react';\n\n/**\n * Framework-agnostic path mapping every BPM view uses for internal\n * cross-navigation. When a host embeds BPM under a non-root prefix\n * (e.g. `/workspace/bpm/*`) it provides its own implementation through\n * `<BPMRoutesProvider value={...}>`; otherwise the default factory\n * preserves the historical `/instances/:id`, `/templates`, etc. paths.\n *\n * Function-shape (instead of string templates) means:\n * - Optional and multi-param routes can branch on argument presence\n * (`caseNew(templateId?)`).\n * - Query-string composition stays inside the host's resolver, not the\n * view.\n * - TypeScript flags missing arguments at compile time.\n *\n * Mirror sibling: {@link RouterAdapter} owns *navigation primitives*\n * (`push`, `replace`, `pathname`); `BPMRoutes` owns *path strings*. The\n * two compose: views call `router.push(routes.caseDetail(id))`.\n */\nexport interface BPMRoutes {\n /** Workflow dashboard landing. Used by sidebar + dashboard tiles. */\n dashboard(): string;\n /** Inbox (待簽) — pending tasks assigned to the current member. */\n inbox(): string;\n /** Sent (我發起的) — instances the current member initiated or submitted on someone's behalf. */\n sent(): string;\n /** CC (抄送給我) — instances the current member is copied on. */\n cc(): string;\n /** Cross-view search. */\n search(): string;\n /** Personal delegation rules. */\n delegations(): string;\n /**\n * Reserved for hosts that want a dedicated `/notifications` page —\n * BPM's built-in views do **not** navigate here by default (the\n * notification drawer mounted by `<BPMNextProviders>` is the primary\n * unread-notification UX). The `createDefaultBPMRoutes()` factory\n * returns `'/notifications'` so consumers can mount their own page\n * at that path if desired; no BPM-shipped `pages/notifications`\n * shim exists.\n */\n notifications(): string;\n\n /**\n * Detail page for one approval instance.\n *\n * @example default → `/instances/abc123`\n */\n caseDetail(instanceId: string): string;\n /**\n * Launch a new approval instance. When `templateId` is passed, the\n * launch form is pre-populated for that template — by default this is\n * appended as a `?templateId=` query string so the path itself stays\n * stable for routing.\n *\n * @example default `caseNew()` → `/instances/new`\n * @example default `caseNew('tpl-1')` → `/instances/new?templateId=tpl-1`\n */\n caseNew(templateId?: string): string;\n\n /** Template index. */\n templates(): string;\n /**\n * Unified \"form + flow\" creation wizard. Designs a form and an approval\n * flow together, then publishes both atomically. This is the only place\n * forms are designed — there is no separate standalone form builder page.\n */\n templateCompose(): string;\n /** Template designer (xyflow canvas). */\n templateDesigner(templateId: string): string;\n /** Template version history. */\n templateVersions(templateId: string): string;\n /** Template categories admin. */\n templateCategories(): string;\n\n /** Per-member notification preferences. */\n notificationSettings(): string;\n\n /** Admin: organization tree management. */\n adminOrgs(): string;\n /** Admin: member directory mapping. */\n adminUsers(): string;\n /** Admin: delegation rule management. */\n adminDelegations(): string;\n /** Admin: database-managed notify webhook endpoints (ADR 18). */\n adminWebhookEndpoints(): string;\n}\n\n/**\n * Factory for the default `BPMRoutes` value. Reproduces the exact path\n * literals BPM views used before `BPMRoutesContext` existed, so existing\n * hosts (no provider mounted) keep working unchanged.\n */\nexport function createDefaultBPMRoutes(): BPMRoutes {\n return {\n dashboard: () => '/dashboard',\n inbox: () => '/inbox',\n sent: () => '/sent',\n cc: () => '/cc',\n search: () => '/search',\n delegations: () => '/delegations',\n notifications: () => '/notifications',\n\n caseDetail: (instanceId) => `/instances/${instanceId}`,\n caseNew: (templateId) =>\n templateId\n ? `/instances/new?templateId=${encodeURIComponent(templateId)}`\n : '/instances/new',\n\n templates: () => '/templates',\n templateCompose: () => '/templates/compose',\n templateDesigner: (templateId) => `/templates/${templateId}/designer`,\n templateVersions: (templateId) => `/templates/${templateId}/versions`,\n templateCategories: () => '/templates/categories',\n\n notificationSettings: () => '/settings/notifications',\n\n adminOrgs: () => '/admin/orgs',\n adminUsers: () => '/admin/users',\n adminDelegations: () => '/admin/delegations',\n adminWebhookEndpoints: () => '/admin/webhook-endpoints',\n };\n}\n\nconst BPMRoutesContext = createContext<BPMRoutes | null>(null);\n\nexport interface BPMRoutesProviderProps {\n /**\n * Override the path mapping. Provide a full implementation, or spread\n * the default and override individual entries:\n *\n * ```tsx\n * <BPMRoutesProvider value={{\n * ...createDefaultBPMRoutes(),\n * caseDetail: (id) => `/workspace/cases/${id}`,\n * }}>\n * ```\n */\n readonly value?: BPMRoutes;\n readonly children: ReactNode;\n}\n\n/**\n * Wraps the BPM React tree with a {@link BPMRoutes} value. Mounting the\n * provider is **optional** — `useBPMRoutes()` falls back to\n * {@link createDefaultBPMRoutes} when no provider is present. Use it\n * only when the host needs to remap BPM's internal paths.\n */\nexport function BPMRoutesProvider({\n value,\n children,\n}: BPMRoutesProviderProps): ReactElement {\n const resolved = useMemo(() => value ?? createDefaultBPMRoutes(), [value]);\n return (\n <BPMRoutesContext.Provider value={resolved}>\n {children}\n </BPMRoutesContext.Provider>\n );\n}\n\n/**\n * Reads the host-configured {@link BPMRoutes}. Falls back to\n * {@link createDefaultBPMRoutes} when no `<BPMRoutesProvider>` ancestor\n * is mounted, so views remain self-contained.\n */\nexport function useBPMRoutes(): BPMRoutes {\n const value = useContext(BPMRoutesContext);\n return value ?? DEFAULT_ROUTES;\n}\n\nconst DEFAULT_ROUTES: BPMRoutes = createDefaultBPMRoutes();\n"],"mappings":";;;;AAsGA,SAAgBA,IAAoC;CAClD,OAAO;EACL,iBAAiB;EACjB,aAAa;EACb,YAAY;EACZ,UAAU;EACV,cAAc;EACd,mBAAmB;EACnB,qBAAqB;EAErB,aAAa,MAAe,cAAcC;EAC1C,UAAU,MACRC,IACI,6BAA6B,mBAAmBA,CAAU,MAC1D;EAEN,iBAAiB;EACjB,uBAAuB;EACvB,mBAAmB,MAAe,cAAcA,EAAW;EAC3D,mBAAmB,MAAe,cAAcA,EAAW;EAC3D,0BAA0B;EAE1B,4BAA4B;EAE5B,iBAAiB;EACjB,kBAAkB;EAClB,wBAAwB;EACxB,6BAA6B;CAC/B;AACF;AAEA,IAAMC,IAAmBC,EAAgC,IAAI;AAwB7D,SAAgBC,EAAkB,EAChC,UACA,eACuC;CACvC,IAAMC,IAAWC,QAAcC,KAASR,EAAuB,GAAG,CAACQ,CAAK,CAAC;CACzE,OACE,kBAACL,EAAiB,UAAlB;EAA2B,OAAOG;EAC/B;CACwB,CAAA;AAE/B;AAOA,SAAgBG,IAA0B;CAExC,OADcC,EAAWP,CAClB,KAASQ;AAClB;AAEA,IAAMA,IAA4BX,EAAuB"}
1
+ {"version":3,"file":"routes-config-DjEOE9eP.js","names":["createDefaultBPMRoutes","instanceId","templateId","BPMRoutesContext","createContext","BPMRoutesProvider","resolved","useMemo","value","useBPMRoutes","useContext","DEFAULT_ROUTES"],"sources":["../../src/lib/routes-config.tsx"],"sourcesContent":["'use client';\n\nimport {\n createContext,\n useContext,\n useMemo,\n type ReactElement,\n type ReactNode,\n} from 'react';\n\n/**\n * Framework-agnostic path mapping every BPM view uses for internal\n * cross-navigation. When a host embeds BPM under a non-root prefix\n * (e.g. `/workspace/bpm/*`) it provides its own implementation through\n * `<BPMRoutesProvider value={...}>`; otherwise the default factory\n * preserves the historical `/instances/:id`, `/templates`, etc. paths.\n *\n * Function-shape (instead of string templates) means:\n * - Optional and multi-param routes can branch on argument presence\n * (`caseNew(templateId?)`).\n * - Query-string composition stays inside the host's resolver, not the\n * view.\n * - TypeScript flags missing arguments at compile time.\n *\n * Mirror sibling: {@link RouterAdapter} owns *navigation primitives*\n * (`push`, `replace`, `pathname`); `BPMRoutes` owns *path strings*. The\n * two compose: views call `router.push(routes.caseDetail(id))`.\n */\nexport interface BPMRoutes {\n /** Workflow dashboard landing. Used by sidebar + dashboard tiles. */\n dashboard(): string;\n /** Inbox (待簽) — pending tasks assigned to the current member. */\n inbox(): string;\n /** Sent (我發起的) — instances the current member initiated or submitted on someone's behalf. */\n sent(): string;\n /** CC (抄送給我) — instances the current member is copied on. */\n cc(): string;\n /** Cross-view search. */\n search(): string;\n /** Personal delegation rules. */\n delegations(): string;\n /**\n * Reserved for hosts that want a dedicated `/notifications` page —\n * BPM's built-in views do **not** navigate here by default (the\n * notification drawer mounted by `<BPMNextProviders>` is the primary\n * unread-notification UX). The `createDefaultBPMRoutes()` factory\n * returns `'/notifications'` so consumers can mount their own page\n * at that path if desired; no BPM-shipped `pages/notifications`\n * shim exists.\n */\n notifications(): string;\n\n /**\n * Detail page for one approval instance.\n *\n * @example default → `/instances/abc123`\n */\n caseDetail(instanceId: string): string;\n /**\n * Launch a new approval instance. When `templateId` is passed, the\n * launch form is pre-populated for that template — by default this is\n * appended as a `?templateId=` query string so the path itself stays\n * stable for routing.\n *\n * @example default `caseNew()` → `/instances/new`\n * @example default `caseNew('tpl-1')` → `/instances/new?templateId=tpl-1`\n */\n caseNew(templateId?: string): string;\n\n /** Template index. */\n templates(): string;\n /**\n * Unified \"form + flow\" creation wizard. Designs a form and an approval\n * flow together, then publishes both atomically. This is the only place\n * forms are designed — there is no separate standalone form builder page.\n */\n templateCompose(): string;\n /** Template designer (xyflow canvas). */\n templateDesigner(templateId: string): string;\n /** Template version history. */\n templateVersions(templateId: string): string;\n /** Template categories admin. */\n templateCategories(): string;\n\n /** Per-member notification preferences. */\n notificationSettings(): string;\n\n /** Admin: organization tree management. */\n adminOrgs(): string;\n /** Admin: member directory mapping. */\n adminUsers(): string;\n /** Admin: delegation rule management. */\n adminDelegations(): string;\n /** Admin: database-managed notify webhook endpoints (ADR 18). */\n adminWebhookEndpoints(): string;\n /** Admin: approval instances stuck after a failed advance, with cancel. */\n adminStuckInstances(): string;\n}\n\n/**\n * Factory for the default `BPMRoutes` value. Reproduces the exact path\n * literals BPM views used before `BPMRoutesContext` existed, so existing\n * hosts (no provider mounted) keep working unchanged.\n */\nexport function createDefaultBPMRoutes(): BPMRoutes {\n return {\n dashboard: () => '/dashboard',\n inbox: () => '/inbox',\n sent: () => '/sent',\n cc: () => '/cc',\n search: () => '/search',\n delegations: () => '/delegations',\n notifications: () => '/notifications',\n\n caseDetail: (instanceId) => `/instances/${instanceId}`,\n caseNew: (templateId) =>\n templateId\n ? `/instances/new?templateId=${encodeURIComponent(templateId)}`\n : '/instances/new',\n\n templates: () => '/templates',\n templateCompose: () => '/templates/compose',\n templateDesigner: (templateId) => `/templates/${templateId}/designer`,\n templateVersions: (templateId) => `/templates/${templateId}/versions`,\n templateCategories: () => '/templates/categories',\n\n notificationSettings: () => '/settings/notifications',\n\n adminOrgs: () => '/admin/orgs',\n adminUsers: () => '/admin/users',\n adminDelegations: () => '/admin/delegations',\n adminWebhookEndpoints: () => '/admin/webhook-endpoints',\n adminStuckInstances: () => '/admin/stuck-instances',\n };\n}\n\nconst BPMRoutesContext = createContext<BPMRoutes | null>(null);\n\nexport interface BPMRoutesProviderProps {\n /**\n * Override the path mapping. Provide a full implementation, or spread\n * the default and override individual entries:\n *\n * ```tsx\n * <BPMRoutesProvider value={{\n * ...createDefaultBPMRoutes(),\n * caseDetail: (id) => `/workspace/cases/${id}`,\n * }}>\n * ```\n */\n readonly value?: BPMRoutes;\n readonly children: ReactNode;\n}\n\n/**\n * Wraps the BPM React tree with a {@link BPMRoutes} value. Mounting the\n * provider is **optional** — `useBPMRoutes()` falls back to\n * {@link createDefaultBPMRoutes} when no provider is present. Use it\n * only when the host needs to remap BPM's internal paths.\n */\nexport function BPMRoutesProvider({\n value,\n children,\n}: BPMRoutesProviderProps): ReactElement {\n const resolved = useMemo(() => value ?? createDefaultBPMRoutes(), [value]);\n return (\n <BPMRoutesContext.Provider value={resolved}>\n {children}\n </BPMRoutesContext.Provider>\n );\n}\n\n/**\n * Reads the host-configured {@link BPMRoutes}. Falls back to\n * {@link createDefaultBPMRoutes} when no `<BPMRoutesProvider>` ancestor\n * is mounted, so views remain self-contained.\n */\nexport function useBPMRoutes(): BPMRoutes {\n const value = useContext(BPMRoutesContext);\n return value ?? DEFAULT_ROUTES;\n}\n\nconst DEFAULT_ROUTES: BPMRoutes = createDefaultBPMRoutes();\n"],"mappings":";;;;AAwGA,SAAgBA,IAAoC;CAClD,OAAO;EACL,iBAAiB;EACjB,aAAa;EACb,YAAY;EACZ,UAAU;EACV,cAAc;EACd,mBAAmB;EACnB,qBAAqB;EAErB,aAAa,MAAe,cAAcC;EAC1C,UAAU,MACRC,IACI,6BAA6B,mBAAmBA,CAAU,MAC1D;EAEN,iBAAiB;EACjB,uBAAuB;EACvB,mBAAmB,MAAe,cAAcA,EAAW;EAC3D,mBAAmB,MAAe,cAAcA,EAAW;EAC3D,0BAA0B;EAE1B,4BAA4B;EAE5B,iBAAiB;EACjB,kBAAkB;EAClB,wBAAwB;EACxB,6BAA6B;EAC7B,2BAA2B;CAC7B;AACF;AAEA,IAAMC,IAAmBC,EAAgC,IAAI;AAwB7D,SAAgBC,EAAkB,EAChC,UACA,eACuC;CACvC,IAAMC,IAAWC,QAAcC,KAASR,EAAuB,GAAG,CAACQ,CAAK,CAAC;CACzE,OACE,kBAACL,EAAiB,UAAlB;EAA2B,OAAOG;EAC/B;CACwB,CAAA;AAE/B;AAOA,SAAgBG,IAA0B;CAExC,OADcC,EAAWP,CAClB,KAASQ;AAClB;AAEA,IAAMA,IAA4BX,EAAuB"}
@@ -0,0 +1,2 @@
1
+ "use client";require('../users.css');const e=require("./rolldown-runtime-BocRIvOZ.cjs"),t=require("./format-member-label-t7ANTF62.cjs"),n=require("./bpm-form-field-Bc6k4ZEO.cjs"),r=require("./admin-pickers-BjbkBpSJ.cjs");let i=require("react"),a=require("@mezzanine-ui/react"),o=require("@rytass/bpm-core-client"),s=require("react/jsx-runtime"),c=require("@rytass/bpm-core-client/workflow"),l=require("@mezzanine-ui/core/form"),u=require("@mezzanine-ui/react/ContentHeader");u=e.t(u,1);let d=require("@rytass/bpm-core-client/organization");var f={memberFilterArea:`bpm_memberFilterArea_9RB2k`,header:`bpm_header_sIEtg`,detailFields:`bpm_detailFields_TyKNL`,detailSection:`bpm_detailSection_-iLjy`,membershipList:`bpm_membershipList_5n9iq`},p=`已不在此人的待辦中`;function m({member:e,onClose:t}){let[o,l]=(0,i.useState)([]),[u,d]=(0,i.useState)(!1),[m,_]=(0,i.useState)([]),[v,y]=(0,i.useState)(null),[b,x]=(0,i.useState)(``),[S,C]=(0,i.useState)(null),[w,T]=(0,i.useState)(null),[E,D]=(0,i.useState)(!1),[O,k]=(0,i.useState)(null),A=(0,i.useMemo)(()=>{let e=new Set(m);return o.filter(t=>e.has(t.taskId)).map(e=>e.taskId)},[o,m]),j=[...A].sort().join(`,`),M=b.trim(),N=`${v?.id??``}|${M}|${j}`,P=S!==null&&S.inputKey===N,F=S!==null&&P&&A.length>0&&S.results.some(e=>e.outcome===`WOULD_REASSIGN`),I=(0,i.useRef)(0),L=(0,i.useRef)(null),R=(0,i.useCallback)(async(e,t)=>{let n=I.current+1;I.current=n,d(!0);try{let r=await(0,c.listMemberOpenTasks)(e);if(I.current===n){let e=t?new Set(t):null;l(r),_(r.map(e=>e.taskId).filter(t=>!e||e.has(t)))}}catch(e){I.current===n&&k(g(e))}finally{I.current===n&&d(!1)}},[]);(0,i.useEffect)(()=>{L.current=e?.memberId??null,y(null),x(``),C(null),T(null),k(null),e?(l([]),_([]),R(e.memberId)):(I.current+=1,l([]),d(!1))},[e,R]);let z=(0,i.useMemo)(()=>new Map(o.map(e=>[e.taskId,e.instanceTitle])),[o]);async function B(t){if(!e||!v||!M||A.length===0)return;let n=A,r=z,i=e.memberId;D(!0),k(null);try{let e=await(0,c.reassignMemberTasks)({dryRun:t,fromMemberId:i,reason:M,taskIds:n,toMemberId:v.id});if(L.current!==i)return;t?(C({inputKey:N,results:e,sentTaskIds:n,titleById:r}),T(null)):(T({results:e,sentTaskIds:n,titleById:r}),C(null),await R(i,n))}catch(e){L.current===i&&k(g(e))}finally{D(!1)}}let V=(0,i.useMemo)(()=>{let e=w??S;if(!e)return[];let t=new Set(e.results.map(e=>e.taskId)),n=e.results.map(t=>({instanceTitle:e.titleById.get(t.taskId)??t.taskId,key:t.taskId,message:t.message,outcomeLabel:h(t.outcome)})),r=e.sentTaskIds.filter(e=>!t.has(e)).map(t=>({instanceTitle:e.titleById.get(t)??t,key:`gone:${t}`,message:null,outcomeLabel:p}));return[...n,...r]},[w,S]),H=(0,i.useMemo)(()=>[{dataIndex:`instanceTitle`,key:`instanceTitle`,title:`案件`,width:220},{dataIndex:`nodeLabel`,key:`nodeLabel`,title:`節點`,width:160},{key:`memberRole`,render:e=>e.memberRole===`ASSIGNEE`?`指派人`:`會簽候選人`,title:`身分`,width:120}],[]),U=(0,i.useMemo)(()=>[{dataIndex:`instanceTitle`,key:`instanceTitle`,title:`案件`,width:220},{dataIndex:`outcomeLabel`,key:`outcomeLabel`,title:`結果`,width:100},{dataIndex:`message`,key:`message`,title:`說明`,width:160}],[]),W=()=>{E||t()};return(0,s.jsx)(a.Modal,{cancelText:`關閉`,confirmButtonProps:{disabled:!F||E},confirmText:`確認改派`,loading:E,modalType:`standard`,onCancel:W,onClose:W,onConfirm:()=>{B(!1)},open:!!e,showModalFooter:!0,showModalHeader:!0,size:`regular`,title:e?`改派待辦:${e.name}`:`改派待辦`,children:e?(0,s.jsxs)(`div`,{className:f.detailFields,children:[(0,s.jsx)(a.Typography,{variant:`body`,children:`改派會保留任務編號,但不產生簽核紀錄;原簽核人的待辦會結案為已轉交, 接手人會收到新的待辦通知。`}),O?(0,s.jsx)(a.Typography,{color:`text-error`,variant:`body`,children:O}):null,o.length?(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(a.Typography,{color:`text-neutral`,variant:`caption`,children:`已選 ${A.length}/${o.length} 筆`}),(0,s.jsx)(a.Table,{columns:H,dataSource:o.map(e=>({...e,key:e.taskId})),fullWidth:!0,loading:u,rowSelection:{hideSelectAll:E,mode:`checkbox`,onChange:e=>{E||(_(e),C(null),T(null))},selectedRowKeys:[...A]}})]}):(0,s.jsx)(a.Typography,{color:`text-neutral`,variant:`body`,children:u?`載入待辦中…`:`此成員目前沒有待簽任務。`}),(0,s.jsx)(n.t,{label:`接手人`,name:`reassignTarget`,children:(0,s.jsx)(r.t,{name:`reassignTarget`,onChange:e=>{y(e),C(null),T(null)},placeholder:`搜尋接手人姓名或信箱`,value:v})}),(0,s.jsx)(n.t,{label:`改派原因`,name:`reassignReason`,children:(0,s.jsx)(a.Input,{fullWidth:!0,name:`reassignReason`,onChange:e=>{x(e.target.value),C(null),T(null)},placeholder:`例如:原簽核人已離職`,value:b})}),(0,s.jsxs)(`div`,{className:f.membershipList,children:[(0,s.jsx)(a.Typography,{color:`text-neutral`,variant:`caption`,children:`先按「預覽」確認每筆任務的結果,確認無誤後再按「確認改派」。`}),(0,s.jsx)(`div`,{children:(0,s.jsx)(a.Button,{disabled:E||!v||!M||A.length===0,onClick:()=>{B(!0)},variant:`base-secondary`,children:`預覽`})})]}),V.length?(0,s.jsx)(a.Table,{columns:U,dataSource:V,fullWidth:!0}):null]}):null})}function h(e){return e===`WOULD_REASSIGN`?`會改派`:e===`REASSIGNED`?`已改派`:`會被拒`}function g(e){return e instanceof Error?e.message:`改派待辦失敗。`}var _=[10,20,50];function v(){let[e,t]=(0,i.useState)(null),[n,r]=(0,i.useState)([]),[p,h]=(0,i.useState)(null),[g,v]=(0,i.useState)(null),[b,x]=(0,i.useState)(null),[S,w]=(0,i.useState)([]),[T,E]=(0,i.useState)(null),[D,O]=(0,i.useState)(!0),[k,A]=(0,i.useState)(1),[j,M]=(0,i.useState)(10),[N,P]=(0,i.useState)(0),[F,I]=(0,i.useState)([]),[L,R]=(0,i.useState)([]),[z,B]=(0,i.useState)([]),[V,H]=(0,i.useState)(null),[U,W]=(0,i.useState)(``),G=(0,i.useMemo)(()=>new Map(L.map(e=>[e.id,e])),[L]),K=(0,i.useMemo)(()=>new Map(z.map(e=>[e.id,e])),[z]),q=(0,i.useCallback)(async()=>{O(!0),x(null);try{let[e,t]=await Promise.all([(0,o.listMemberDirectoryPage)({page:k,pageSize:j,searchText:U}),(0,d.readOrganizationDashboard)()]);I(e.members),P(e.totalCount),R(t.orgUnits),B(t.positions)}catch(e){x(C(e))}finally{O(!1)}},[k,j,U]);(0,i.useEffect)(()=>{q()},[q]);let J=(0,i.useRef)(0),Y=(0,i.useCallback)(async()=>{let e=J.current+1;J.current=e;try{let t=await(0,c.listInactiveMembersWithOpenTasks)();J.current===e&&(w(t),E(null))}catch(t){J.current===e&&E(C(t))}},[]);(0,i.useEffect)(()=>{Y()},[Y]);let X=(0,i.useMemo)(()=>S.map(e=>({...e,key:e.memberId})),[S]),Z=(0,i.useMemo)(()=>[{dataIndex:`name`,key:`name`,title:`姓名`,width:160},{dataIndex:`email`,key:`email`,title:`信箱`,width:260},{dataIndex:`openTaskCount`,key:`openTaskCount`,title:`待簽數`,width:96}],[]),Q=(0,i.useMemo)(()=>({render:()=>[{name:`改派待辦`,onClick:e=>{H({customFieldsJson:`{}`,email:e.email,memberId:e.memberId,name:e.name})}}],variant:`base-secondary`,width:112}),[]),ee=(0,i.useMemo)(()=>F.map(e=>({...e,key:e.memberId})),[F]),$=(0,i.useCallback)(async e=>{t(e),h(null),x(null);try{let[t,n]=await Promise.all([(0,d.listMemberships)({memberId:e.memberId}),(0,d.readResolvedManager)(e.memberId)]);r(t),v(n),h((await(0,o.resolveMembers)(n.managerMemberId?[n.managerMemberId]:[]))[0]??null)}catch(e){x(C(e))}},[]),te=(0,i.useMemo)(()=>[{dataIndex:`name`,key:`name`,title:`姓名`,width:160},{dataIndex:`email`,key:`email`,title:`信箱`,width:260}],[]),ne=(0,i.useMemo)(()=>({render:()=>[{name:`檢視`,onClick:e=>{$(e)}},{name:`改派待辦`,onClick:e=>{H(e)}}],variant:`base-secondary`,width:176}),[$]);function re(){t(null),h(null),r([]),v(null)}return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(a.PageHeader,{children:(0,s.jsx)(u.default,{description:`會員資料由 host member resolver 提供,BPM 僅維護組織歸屬與主管解析。`,title:`會員對照`})}),(0,s.jsxs)(a.SectionGroup,{children:[X.length||T?(0,s.jsx)(a.Section,{contentHeader:(0,s.jsx)(u.default,{description:`這些會員已停用,身上仍有待簽,請改派給在職的人。`,title:`已停用、仍有待簽的會員`}),children:(0,s.jsx)(`div`,{"data-inactive-members":``,children:T?(0,s.jsx)(a.Typography,{color:`text-error`,variant:`body`,children:T}):(0,s.jsx)(a.Table,{actions:Q,columns:Z,dataSource:X,fullWidth:!0})})}):null,(0,s.jsxs)(a.Section,{filterArea:(0,s.jsx)(a.FilterArea,{className:f.memberFilterArea,children:(0,s.jsx)(a.FilterLine,{children:(0,s.jsx)(a.Filter,{span:3,children:(0,s.jsx)(a.FormField,{fullWidth:!0,layout:l.FormFieldLayout.VERTICAL,name:`memberSearchText`,children:(0,s.jsx)(a.Input,{fullWidth:!0,onChange:e=>{W(e.target.value),A(1)},placeholder:`搜尋姓名或信箱`,size:`sub`,value:U,variant:`base`})})})})}),children:[b?(0,s.jsx)(a.Typography,{color:`text-error`,variant:`body`,children:b}):null,(0,s.jsx)(a.Table,{actions:ne,columns:te,dataSource:ee,fullWidth:!0,loading:D,pagination:{current:k,onChange:e=>{A(e)},onChangePageSize:e=>{A(1),M(e)},pageSize:j,pageSizeLabel:`每頁筆數`,pageSizeOptions:_,renderResultSummary:(e,t,n)=>`顯示 ${e}-${t} 筆,共 ${n} 筆`,showPageSizeOptions:!0,total:N}})]})]}),(0,s.jsx)(m,{member:V,onClose:()=>{H(null),Y()}}),(0,s.jsx)(y,{managerProfile:p,member:e,memberships:n,onClose:re,orgUnitsById:G,positionsById:K,resolvedManager:g})]})}function y({managerProfile:e,member:t,memberships:n,onClose:r,orgUnitsById:i,positionsById:o,resolvedManager:c}){return(0,s.jsx)(a.Modal,{cancelText:`關閉`,confirmText:`關閉`,modalType:`standard`,onCancel:r,onClose:r,onConfirm:r,open:!!t,showModalFooter:!0,showModalHeader:!0,size:`regular`,title:t?.name??`會員明細`,children:t?(0,s.jsxs)(`div`,{className:f.detailFields,children:[(0,s.jsx)(a.BaseCard,{title:`基本資料`,children:(0,s.jsx)(`div`,{className:f.detailSection,children:(0,s.jsxs)(a.Typography,{variant:`body`,children:[`信箱:`,t.email?.trim()?t.email:`未設定`]})})}),(0,s.jsx)(a.BaseCard,{title:`BPM 組織歸屬`,children:(0,s.jsx)(`div`,{className:f.membershipList,children:n.length?n.map(e=>(0,s.jsxs)(a.Typography,{variant:`body`,children:[b(i.get(e.orgUnitId)),` / `,e.positionId?x(o.get(e.positionId)):`未指定職位`,` / `,e.isPrimary?`主要`:`一般`]},e.id)):(0,s.jsx)(a.Typography,{color:`text-neutral`,variant:`body`,children:`尚未建立 BPM 組織歸屬`})})}),(0,s.jsx)(a.BaseCard,{title:`主管解析`,children:(0,s.jsx)(a.Typography,{variant:`body`,children:c?.managerMemberId?S(e):`尚未解析到主管`})})]}):null})}function b(e){return e?`${e.name} · ${e.code}`:`未知組織`}function x(e){return e?`${e.name} · ${e.code}`:`未知職位`}function S(e){return e?t.t(e.name,e.email,`dot`):`主管資料尚未載入`}function C(e){return e instanceof Error?e.message:`讀取會員資料失敗。`}Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return v}});
2
+ //# sourceMappingURL=users-C_Dtw_sR.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"users-C_Dtw_sR.cjs","names":["useState","useMemo","useRef","useCallback","listMemberOpenTasks","readErrorMessage","reassignMemberTasks","Modal","styles","Typography","_Fragment","Table","BPMFormField","MemberPicker","Input","Button","useState","useMemo","useCallback","listMemberDirectoryPage","readOrganizationDashboard","useRef","listInactiveMembersWithOpenTasks","listMemberships","readResolvedManager","resolveMembers","_Fragment","PageHeader","ContentHeader","SectionGroup","Section","Typography","Table","FilterArea","styles","FilterLine","Filter","FormField","FormFieldLayout","Input","Modal","BaseCard","formatMemberLabel","require_rolldown_runtime","require_format_member_label","require_bpm_form_field","require_admin_pickers","react","_mezzanine_ui_react","_rytass_bpm_core_client","react_jsx_runtime","_rytass_bpm_core_client_workflow","_mezzanine_ui_core_form","_mezzanine_ui_react_ContentHeader","_rytass_bpm_core_client_organization","users_module_default","TASK_GONE_LABEL","MemberTaskReassignModal","tasks","setTasks","tasksLoading","setTasksLoading","checkedIds","setCheckedIds","target","setTarget","reason","setReason","preview","setPreview","committed","setCommitted","busy","setBusy","error","setError","selectedIds","checked","task","selectionKey","trimmedReason","inputKey","previewIsCurrent","canConfirm","result","latestRequestRef","shownMemberIdRef","loadTasks","request","loaded","memberId","kept","keepCheckedIds","taskId","requestError","readErrorMessage$1","member","titleById","runReassignment","sentTaskIds","sentTitleById","sentMemberId","outcomes","dryRun","shownResultRows","shown","returnedIds","returnedRows","readOutcomeLabel","goneRows","taskColumns","record","resultColumns","handleClose","onClose","selectedRowKeys","option","event","outcome","MEMBER_PAGE_SIZE_OPTIONS","AdminUsersView","detailMember","setDetailMember","detailMemberships","setDetailMemberships","detailManagerProfile","setDetailManagerProfile","detailResolvedManager","setDetailResolvedManager","inactiveMembers","setInactiveMembers","inactiveMembersError","setInactiveMembersError","loading","setLoading","memberPage","setMemberPage","memberPageSize","setMemberPageSize","memberTotalCount","setMemberTotalCount","members","setMembers","orgUnits","setOrgUnits","positions","setPositions","reassignMember","setReassignMember","searchText","setSearchText","orgUnitsById","orgUnit","positionsById","position","refreshMembers","memberPageResult","organization","readErrorMessage","latestInactiveRequestRef","refreshInactiveMembers","inactiveMemberRows","inactiveMemberColumns","inactiveMemberActions","rows","openDetail","memberships","resolvedManager","columns","tableActions","closeDetail","page","pageSize","from","to","total","MemberDetailModal","readOrgUnitLabel","membership","readPositionLabel","readMemberLabel","managerProfile"],"sources":["../../src/views/admin/users/MemberTaskReassignModal.tsx","../../src/views/admin/users/AdminUsersView.tsx"],"sourcesContent":["'use client';\n\nimport {\n ChangeEvent,\n ReactElement,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport { Button, Input, Modal, Table, Typography } from '@mezzanine-ui/react';\nimport type { TableColumn } from '@mezzanine-ui/core/table';\nimport type { MemberProfileRecord } from '@rytass/bpm-core-client';\nimport {\n listMemberOpenTasks,\n type MemberOpenTaskRecord,\n reassignMemberTasks,\n type TaskReassignmentResultRecord,\n} from '@rytass/bpm-core-client/workflow';\nimport { BPMFormField } from '../../../components/bpm-form-field';\nimport { MemberOption, MemberPicker } from '../../../components/admin-pickers';\nimport styles from './users.module.scss';\n\ntype TaskRow = Readonly<\n Record<string, unknown> &\n MemberOpenTaskRecord & {\n key: string;\n }\n>;\n\ntype ResultRow = Readonly<\n Record<string, unknown> & {\n instanceTitle: string;\n key: string;\n message: string | null;\n outcomeLabel: string;\n }\n>;\n\n/**\n * Both states keep what was sent and the titles it was sent with: the server\n * skips an id the member no longer holds (no result row for it), and a commit\n * reloads the task list, so neither can be recovered from the current list.\n */\ninterface PreviewState {\n readonly inputKey: string;\n readonly results: readonly TaskReassignmentResultRecord[];\n readonly sentTaskIds: readonly string[];\n readonly titleById: ReadonlyMap<string, string>;\n}\n\ninterface CommittedState {\n readonly results: readonly TaskReassignmentResultRecord[];\n readonly sentTaskIds: readonly string[];\n readonly titleById: ReadonlyMap<string, string>;\n}\n\nconst TASK_GONE_LABEL = '已不在此人的待辦中';\n\n/**\n * Administrator reassignment of a member's open tasks. Lists what the member\n * holds, takes a target and a reason, previews every task's outcome (dry run),\n * and only then commits. Confirm stays disabled until the preview matches the\n * current target and reason. Replacing a seat is not a decision: no signature\n * is written, and the task keeps its id.\n */\nexport function MemberTaskReassignModal({\n member,\n onClose,\n}: {\n readonly member: MemberProfileRecord | null;\n readonly onClose: () => void;\n}): ReactElement {\n const [tasks, setTasks] = useState<readonly MemberOpenTaskRecord[]>([]);\n const [tasksLoading, setTasksLoading] = useState(false);\n const [checkedIds, setCheckedIds] = useState<readonly string[]>([]);\n const [target, setTarget] = useState<MemberOption | null>(null);\n const [reason, setReason] = useState('');\n const [preview, setPreview] = useState<PreviewState | null>(null);\n const [committed, setCommitted] = useState<CommittedState | null>(null);\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n // The ids to send are the checked ones that the current list still holds, so\n // a stale check (other member, reloaded list) never reaches the server.\n const selectedIds = useMemo((): readonly string[] => {\n const checked = new Set(checkedIds);\n\n return tasks\n .filter((task) => checked.has(task.taskId))\n .map((task) => task.taskId);\n }, [tasks, checkedIds]);\n const selectionKey = [...selectedIds].sort().join(',');\n const trimmedReason = reason.trim();\n const inputKey = `${target?.id ?? ''}|${trimmedReason}|${selectionKey}`;\n const previewIsCurrent = preview !== null && preview.inputKey === inputKey;\n const canConfirm =\n preview !== null &&\n previewIsCurrent &&\n selectedIds.length > 0 &&\n preview.results.some((result) => result.outcome === 'WOULD_REASSIGN');\n\n // Only the latest request may write: switching members while an earlier\n // listing is in flight must not let its late answer replace the current one.\n const latestRequestRef = useRef(0);\n // The member on screen now. A reassignment that answers after the member\n // changed belongs to the earlier one and must not write: the counter above\n // only orders requests, and the commit's reload would be the latest one.\n const shownMemberIdRef = useRef<string | null>(null);\n\n // `keepCheckedIds` is the selection to carry over after a reassignment;\n // without it (a fresh member) every task starts selected.\n const loadTasks = useCallback(\n async (\n memberId: string,\n keepCheckedIds?: readonly string[],\n ): Promise<void> => {\n const request = latestRequestRef.current + 1;\n\n latestRequestRef.current = request;\n setTasksLoading(true);\n\n try {\n const loaded = await listMemberOpenTasks(memberId);\n\n if (latestRequestRef.current === request) {\n const kept = keepCheckedIds ? new Set(keepCheckedIds) : null;\n\n setTasks(loaded);\n // Never select a task the administrator had left out: after a partial\n // reassignment only what they chose and still holds stays selected.\n setCheckedIds(\n loaded\n .map((task) => task.taskId)\n .filter((taskId) => !kept || kept.has(taskId)),\n );\n }\n } catch (requestError: unknown) {\n if (latestRequestRef.current === request) {\n setError(readErrorMessage(requestError));\n }\n } finally {\n if (latestRequestRef.current === request) {\n setTasksLoading(false);\n }\n }\n },\n [],\n );\n\n useEffect((): void => {\n shownMemberIdRef.current = member?.memberId ?? null;\n setTarget(null);\n setReason('');\n setPreview(null);\n setCommitted(null);\n setError(null);\n\n if (!member) {\n latestRequestRef.current += 1;\n setTasks([]);\n setTasksLoading(false);\n\n return;\n }\n\n setTasks([]);\n // Only clears; selecting everything again happens inside loadTasks (its\n // latest-request guard), once the new member's list has arrived.\n setCheckedIds([]);\n void loadTasks(member.memberId);\n }, [member, loadTasks]);\n\n const titleById = useMemo(\n (): ReadonlyMap<string, string> =>\n new Map(tasks.map((task) => [task.taskId, task.instanceTitle])),\n [tasks],\n );\n\n async function runReassignment(dryRun: boolean): Promise<void> {\n if (!member || !target || !trimmedReason || selectedIds.length === 0) {\n return;\n }\n\n // Snapshot at click time: the request, the preview key and the titles all\n // describe the same selection even if the list reloads while we wait.\n const sentTaskIds = selectedIds;\n const sentTitleById = titleById;\n const sentMemberId = member.memberId;\n\n setBusy(true);\n setError(null);\n\n try {\n const outcomes = await reassignMemberTasks({\n dryRun,\n fromMemberId: sentMemberId,\n reason: trimmedReason,\n taskIds: sentTaskIds,\n toMemberId: target.id,\n });\n\n if (shownMemberIdRef.current !== sentMemberId) {\n return;\n }\n\n if (dryRun) {\n setPreview({\n inputKey,\n results: outcomes,\n sentTaskIds,\n titleById: sentTitleById,\n });\n setCommitted(null);\n } else {\n setCommitted({\n results: outcomes,\n sentTaskIds,\n titleById: sentTitleById,\n });\n setPreview(null);\n await loadTasks(sentMemberId, sentTaskIds);\n }\n } catch (requestError: unknown) {\n if (shownMemberIdRef.current === sentMemberId) {\n setError(readErrorMessage(requestError));\n }\n } finally {\n setBusy(false);\n }\n }\n\n const shownResultRows = useMemo((): ResultRow[] => {\n const shown = committed ?? preview;\n\n if (!shown) {\n return [];\n }\n\n const returnedIds = new Set(shown.results.map((result) => result.taskId));\n const returnedRows = shown.results.map(\n (result): ResultRow => ({\n instanceTitle: shown.titleById.get(result.taskId) ?? result.taskId,\n key: result.taskId,\n message: result.message,\n outcomeLabel: readOutcomeLabel(result.outcome),\n }),\n );\n // Sent but not answered: the member no longer holds it, so the server\n // returns no row. Show it instead of letting the selection silently shrink.\n const goneRows = shown.sentTaskIds\n .filter((taskId) => !returnedIds.has(taskId))\n .map(\n (taskId): ResultRow => ({\n instanceTitle: shown.titleById.get(taskId) ?? taskId,\n key: `gone:${taskId}`,\n message: null,\n outcomeLabel: TASK_GONE_LABEL,\n }),\n );\n\n return [...returnedRows, ...goneRows];\n }, [committed, preview]);\n\n const taskColumns = useMemo(\n (): TableColumn<TaskRow>[] => [\n {\n dataIndex: 'instanceTitle',\n key: 'instanceTitle',\n title: '案件',\n width: 220,\n },\n {\n dataIndex: 'nodeLabel',\n key: 'nodeLabel',\n title: '節點',\n width: 160,\n },\n {\n key: 'memberRole',\n render: (record: TaskRow): string =>\n record.memberRole === 'ASSIGNEE' ? '指派人' : '會簽候選人',\n title: '身分',\n width: 120,\n },\n ],\n [],\n );\n const resultColumns = useMemo(\n (): TableColumn<ResultRow>[] => [\n {\n dataIndex: 'instanceTitle',\n key: 'instanceTitle',\n title: '案件',\n width: 220,\n },\n {\n dataIndex: 'outcomeLabel',\n key: 'outcomeLabel',\n title: '結果',\n width: 100,\n },\n {\n dataIndex: 'message',\n key: 'message',\n title: '說明',\n width: 160,\n },\n ],\n [],\n );\n\n // The backdrop hides the member table, so closing is the only way `member`\n // changes. While a request is in flight every close path is a no-op, which\n // closes the window where a late answer writes into another member's view.\n const handleClose = (): void => {\n if (busy) {\n return;\n }\n\n onClose();\n };\n\n return (\n <Modal\n cancelText=\"關閉\"\n confirmButtonProps={{ disabled: !canConfirm || busy }}\n confirmText=\"確認改派\"\n loading={busy}\n modalType=\"standard\"\n onCancel={handleClose}\n onClose={handleClose}\n onConfirm={(): void => {\n void runReassignment(false);\n }}\n open={Boolean(member)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n title={member ? `改派待辦:${member.name}` : '改派待辦'}\n >\n {member ? (\n <div className={styles.detailFields}>\n <Typography variant=\"body\">\n 改派會保留任務編號,但不產生簽核紀錄;原簽核人的待辦會結案為已轉交,\n 接手人會收到新的待辦通知。\n </Typography>\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n {tasks.length ? (\n <>\n <Typography color=\"text-neutral\" variant=\"caption\">\n {`已選 ${selectedIds.length}/${tasks.length} 筆`}\n </Typography>\n <Table\n columns={taskColumns}\n dataSource={tasks.map((task): TaskRow => ({\n ...task,\n key: task.taskId,\n }))}\n fullWidth\n loading={tasksLoading}\n rowSelection={{\n hideSelectAll: busy,\n mode: 'checkbox',\n onChange: (selectedRowKeys: string[]): void => {\n if (busy) {\n return;\n }\n\n setCheckedIds(selectedRowKeys);\n setPreview(null);\n setCommitted(null);\n },\n selectedRowKeys: [...selectedIds],\n }}\n />\n </>\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n {tasksLoading ? '載入待辦中…' : '此成員目前沒有待簽任務。'}\n </Typography>\n )}\n <BPMFormField label=\"接手人\" name=\"reassignTarget\">\n <MemberPicker\n name=\"reassignTarget\"\n onChange={(option): void => {\n setTarget(option);\n setPreview(null);\n setCommitted(null);\n }}\n placeholder=\"搜尋接手人姓名或信箱\"\n value={target}\n />\n </BPMFormField>\n <BPMFormField label=\"改派原因\" name=\"reassignReason\">\n <Input\n fullWidth\n name=\"reassignReason\"\n onChange={(event: ChangeEvent<HTMLInputElement>): void => {\n setReason(event.target.value);\n setPreview(null);\n setCommitted(null);\n }}\n placeholder=\"例如:原簽核人已離職\"\n value={reason}\n />\n </BPMFormField>\n <div className={styles.membershipList}>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 先按「預覽」確認每筆任務的結果,確認無誤後再按「確認改派」。\n </Typography>\n <div>\n <Button\n disabled={\n busy ||\n !target ||\n !trimmedReason ||\n selectedIds.length === 0\n }\n onClick={(): void => {\n void runReassignment(true);\n }}\n variant=\"base-secondary\"\n >\n 預覽\n </Button>\n </div>\n </div>\n {shownResultRows.length ? (\n <Table\n columns={resultColumns}\n dataSource={shownResultRows}\n fullWidth\n />\n ) : null}\n </div>\n ) : null}\n </Modal>\n );\n}\n\nfunction readOutcomeLabel(\n outcome: TaskReassignmentResultRecord['outcome'],\n): string {\n if (outcome === 'WOULD_REASSIGN') {\n return '會改派';\n }\n\n if (outcome === 'REASSIGNED') {\n return '已改派';\n }\n\n return '會被拒';\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '改派待辦失敗。';\n}\n","'use client';\n\nimport {\n ChangeEvent,\n ReactElement,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n BaseCard,\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n Input,\n Modal,\n PageHeader,\n Section,\n SectionGroup,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport { formatMemberLabel } from '../../../lib/format-member-label';\nimport styles from './users.module.scss';\nimport { MemberTaskReassignModal } from './MemberTaskReassignModal';\nimport {\n listMemberDirectoryPage,\n MemberProfileRecord,\n resolveMembers,\n} from '@rytass/bpm-core-client';\nimport {\n listMemberships,\n MembershipRecord,\n OrgUnitRecord,\n PositionRecord,\n readOrganizationDashboard,\n readResolvedManager,\n ResolvedManagerRecord,\n} from '@rytass/bpm-core-client/organization';\nimport {\n type InactiveMemberWithOpenTasksRecord,\n listInactiveMembersWithOpenTasks,\n} from '@rytass/bpm-core-client/workflow';\n\ntype MemberRow = Readonly<\n Record<string, unknown> &\n MemberProfileRecord & {\n key: string;\n }\n>;\n\ntype InactiveMemberRow = Readonly<\n Record<string, unknown> &\n InactiveMemberWithOpenTasksRecord & {\n key: string;\n }\n>;\n\nconst MEMBER_PAGE_SIZE_OPTIONS = [10, 20, 50];\n\nexport function AdminUsersView(): ReactElement {\n const [detailMember, setDetailMember] = useState<MemberProfileRecord | null>(\n null,\n );\n const [detailMemberships, setDetailMemberships] = useState<\n readonly MembershipRecord[]\n >([]);\n const [detailManagerProfile, setDetailManagerProfile] =\n useState<MemberProfileRecord | null>(null);\n const [detailResolvedManager, setDetailResolvedManager] =\n useState<ResolvedManagerRecord | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [inactiveMembers, setInactiveMembers] = useState<\n readonly InactiveMemberWithOpenTasksRecord[]\n >([]);\n const [inactiveMembersError, setInactiveMembersError] = useState<\n string | null\n >(null);\n const [loading, setLoading] = useState(true);\n const [memberPage, setMemberPage] = useState(1);\n const [memberPageSize, setMemberPageSize] = useState(10);\n const [memberTotalCount, setMemberTotalCount] = useState(0);\n const [members, setMembers] = useState<readonly MemberProfileRecord[]>([]);\n const [orgUnits, setOrgUnits] = useState<readonly OrgUnitRecord[]>([]);\n const [positions, setPositions] = useState<readonly PositionRecord[]>([]);\n const [reassignMember, setReassignMember] =\n useState<MemberProfileRecord | null>(null);\n const [searchText, setSearchText] = useState('');\n\n const orgUnitsById = useMemo(\n (): ReadonlyMap<string, OrgUnitRecord> =>\n new Map(orgUnits.map((orgUnit) => [orgUnit.id, orgUnit])),\n [orgUnits],\n );\n const positionsById = useMemo(\n (): ReadonlyMap<string, PositionRecord> =>\n new Map(positions.map((position) => [position.id, position])),\n [positions],\n );\n\n const refreshMembers = useCallback(async (): Promise<void> => {\n setLoading(true);\n setError(null);\n\n try {\n const [memberPageResult, organization] = await Promise.all([\n listMemberDirectoryPage({\n page: memberPage,\n pageSize: memberPageSize,\n searchText,\n }),\n readOrganizationDashboard(),\n ]);\n\n setMembers(memberPageResult.members);\n setMemberTotalCount(memberPageResult.totalCount);\n setOrgUnits(organization.orgUnits);\n setPositions(organization.positions);\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }, [memberPage, memberPageSize, searchText]);\n\n useEffect((): void => {\n void refreshMembers();\n }, [refreshMembers]);\n\n const latestInactiveRequestRef = useRef(0);\n\n // Loaded on its own so a failure here leaves the member directory usable.\n // Only the latest request may write: a reload started when the reassignment\n // closes must not be overwritten by an earlier one answering late.\n const refreshInactiveMembers = useCallback(async (): Promise<void> => {\n const request = latestInactiveRequestRef.current + 1;\n\n latestInactiveRequestRef.current = request;\n\n try {\n const loaded = await listInactiveMembersWithOpenTasks();\n\n if (latestInactiveRequestRef.current === request) {\n setInactiveMembers(loaded);\n setInactiveMembersError(null);\n }\n } catch (requestError: unknown) {\n if (latestInactiveRequestRef.current === request) {\n setInactiveMembersError(readErrorMessage(requestError));\n }\n }\n }, []);\n\n useEffect((): void => {\n void refreshInactiveMembers();\n }, [refreshInactiveMembers]);\n\n const inactiveMemberRows = useMemo(\n (): InactiveMemberRow[] =>\n inactiveMembers.map(\n (member): InactiveMemberRow => ({ ...member, key: member.memberId }),\n ),\n [inactiveMembers],\n );\n const inactiveMemberColumns = useMemo(\n (): TableColumn<InactiveMemberRow>[] => [\n { dataIndex: 'name', key: 'name', title: '姓名', width: 160 },\n { dataIndex: 'email', key: 'email', title: '信箱', width: 260 },\n {\n dataIndex: 'openTaskCount',\n key: 'openTaskCount',\n title: '待簽數',\n width: 96,\n },\n ],\n [],\n );\n const inactiveMemberActions = useMemo(\n (): TableActions<InactiveMemberRow> => ({\n render: (): ReturnType<TableActions<InactiveMemberRow>['render']> => [\n {\n name: '改派待辦',\n onClick: (record): void => {\n setReassignMember({\n customFieldsJson: '{}',\n email: record.email,\n memberId: record.memberId,\n name: record.name,\n });\n },\n },\n ],\n variant: 'base-secondary',\n width: 112,\n }),\n [],\n );\n\n const rows = useMemo(\n (): MemberRow[] =>\n members.map((member) => ({\n ...member,\n key: member.memberId,\n })),\n [members],\n );\n\n const openDetail = useCallback(\n async (member: MemberProfileRecord): Promise<void> => {\n setDetailMember(member);\n setDetailManagerProfile(null);\n setError(null);\n\n try {\n const [memberships, resolvedManager] = await Promise.all([\n listMemberships({ memberId: member.memberId }),\n readResolvedManager(member.memberId),\n ]);\n\n setDetailMemberships(memberships);\n setDetailResolvedManager(resolvedManager);\n setDetailManagerProfile(\n (\n await resolveMembers(\n resolvedManager.managerMemberId\n ? [resolvedManager.managerMemberId]\n : [],\n )\n )[0] ?? null,\n );\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n }\n },\n [],\n );\n\n const columns = useMemo(\n (): TableColumn<MemberRow>[] => [\n { dataIndex: 'name', key: 'name', title: '姓名', width: 160 },\n { dataIndex: 'email', key: 'email', title: '信箱', width: 260 },\n ],\n [],\n );\n const tableActions = useMemo(\n (): TableActions<MemberRow> => ({\n render: (): ReturnType<TableActions<MemberRow>['render']> => [\n {\n name: '檢視',\n onClick: (record): void => {\n void openDetail(record);\n },\n },\n {\n name: '改派待辦',\n onClick: (record): void => {\n setReassignMember(record);\n },\n },\n ],\n variant: 'base-secondary',\n width: 176,\n }),\n [openDetail],\n );\n\n function closeDetail(): void {\n setDetailMember(null);\n setDetailManagerProfile(null);\n setDetailMemberships([]);\n setDetailResolvedManager(null);\n }\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"會員資料由 host member resolver 提供,BPM 僅維護組織歸屬與主管解析。\"\n title=\"會員對照\"\n />\n </PageHeader>\n\n <SectionGroup>\n {inactiveMemberRows.length || inactiveMembersError ? (\n <Section\n contentHeader={\n <ContentHeader\n description=\"這些會員已停用,身上仍有待簽,請改派給在職的人。\"\n title=\"已停用、仍有待簽的會員\"\n />\n }\n >\n <div data-inactive-members=\"\">\n {inactiveMembersError ? (\n <Typography color=\"text-error\" variant=\"body\">\n {inactiveMembersError}\n </Typography>\n ) : (\n <Table\n actions={inactiveMemberActions}\n columns={inactiveMemberColumns}\n dataSource={inactiveMemberRows}\n fullWidth\n />\n )}\n </div>\n </Section>\n ) : null}\n <Section\n filterArea={\n <FilterArea className={styles.memberFilterArea}>\n <FilterLine>\n <Filter span={3}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"memberSearchText\"\n >\n <Input\n fullWidth\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n setSearchText(event.target.value);\n setMemberPage(1);\n }}\n placeholder=\"搜尋姓名或信箱\"\n size=\"sub\"\n value={searchText}\n variant=\"base\"\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n }\n >\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n <Table\n actions={tableActions}\n columns={columns}\n dataSource={rows}\n fullWidth\n loading={loading}\n pagination={{\n current: memberPage,\n onChange: (page): void => {\n setMemberPage(page);\n },\n onChangePageSize: (pageSize): void => {\n setMemberPage(1);\n setMemberPageSize(pageSize);\n },\n pageSize: memberPageSize,\n pageSizeLabel: '每頁筆數',\n pageSizeOptions: MEMBER_PAGE_SIZE_OPTIONS,\n renderResultSummary: (from, to, total): string =>\n `顯示 ${from}-${to} 筆,共 ${total} 筆`,\n showPageSizeOptions: true,\n total: memberTotalCount,\n }}\n />\n </Section>\n </SectionGroup>\n\n <MemberTaskReassignModal\n member={reassignMember}\n onClose={(): void => {\n setReassignMember(null);\n // A reassignment may have cleared someone off the list.\n void refreshInactiveMembers();\n }}\n />\n\n <MemberDetailModal\n managerProfile={detailManagerProfile}\n member={detailMember}\n memberships={detailMemberships}\n onClose={closeDetail}\n orgUnitsById={orgUnitsById}\n positionsById={positionsById}\n resolvedManager={detailResolvedManager}\n />\n </>\n );\n}\n\nfunction MemberDetailModal({\n managerProfile,\n member,\n memberships,\n onClose,\n orgUnitsById,\n positionsById,\n resolvedManager,\n}: {\n readonly managerProfile: MemberProfileRecord | null;\n readonly member: MemberProfileRecord | null;\n readonly memberships: readonly MembershipRecord[];\n readonly onClose: () => void;\n readonly orgUnitsById: ReadonlyMap<string, OrgUnitRecord>;\n readonly positionsById: ReadonlyMap<string, PositionRecord>;\n readonly resolvedManager: ResolvedManagerRecord | null;\n}): ReactElement {\n return (\n <Modal\n cancelText=\"關閉\"\n confirmText=\"關閉\"\n modalType=\"standard\"\n onCancel={onClose}\n onClose={onClose}\n onConfirm={onClose}\n open={Boolean(member)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n title={member?.name ?? '會員明細'}\n >\n {member ? (\n <div className={styles.detailFields}>\n <BaseCard title=\"基本資料\">\n <div className={styles.detailSection}>\n <Typography variant=\"body\">\n 信箱:{member.email?.trim() ? member.email : '未設定'}\n </Typography>\n </div>\n </BaseCard>\n <BaseCard title=\"BPM 組織歸屬\">\n <div className={styles.membershipList}>\n {memberships.length ? (\n memberships.map((membership) => (\n <Typography key={membership.id} variant=\"body\">\n {readOrgUnitLabel(orgUnitsById.get(membership.orgUnitId))}\n {' / '}\n {membership.positionId\n ? readPositionLabel(\n positionsById.get(membership.positionId),\n )\n : '未指定職位'}\n {' / '}\n {membership.isPrimary ? '主要' : '一般'}\n </Typography>\n ))\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n 尚未建立 BPM 組織歸屬\n </Typography>\n )}\n </div>\n </BaseCard>\n <BaseCard title=\"主管解析\">\n <Typography variant=\"body\">\n {resolvedManager?.managerMemberId\n ? readMemberLabel(managerProfile)\n : '尚未解析到主管'}\n </Typography>\n </BaseCard>\n </div>\n ) : null}\n </Modal>\n );\n}\n\nfunction readOrgUnitLabel(orgUnit: OrgUnitRecord | undefined): string {\n return orgUnit ? `${orgUnit.name} · ${orgUnit.code}` : '未知組織';\n}\n\nfunction readPositionLabel(position: PositionRecord | undefined): string {\n return position ? `${position.name} · ${position.code}` : '未知職位';\n}\n\nfunction readMemberLabel(member: MemberProfileRecord | null): string {\n return member\n ? formatMemberLabel(member.name, member.email, 'dot')\n : '主管資料尚未載入';\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '讀取會員資料失敗。';\n}\n"],"mappings":"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"}