@rytass/bpm-core-react 0.18.0 → 0.19.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.
- package/CHANGELOG.md +45 -0
- package/dist/chunks/{FormBuilderView-BVKY1j_0.js → FormBuilderView-Djlm3y4S.js} +485 -481
- package/dist/chunks/FormBuilderView-Djlm3y4S.js.map +1 -0
- package/dist/chunks/FormBuilderView-G6uRSywl.cjs +3 -0
- package/dist/chunks/FormBuilderView-G6uRSywl.cjs.map +1 -0
- package/dist/chunks/{FormRendererView-BsTwZkqU.js → FormRendererView-DHfVgbo6.js} +511 -274
- package/dist/chunks/FormRendererView-DHfVgbo6.js.map +1 -0
- package/dist/chunks/FormRendererView-DwfFbaip.cjs +6 -0
- package/dist/chunks/FormRendererView-DwfFbaip.cjs.map +1 -0
- package/dist/chunks/admin-pickers-BjbkBpSJ.cjs +2 -0
- package/dist/chunks/admin-pickers-BjbkBpSJ.cjs.map +1 -0
- package/dist/chunks/{admin-pickers-Djq3h-UR.js → admin-pickers-DfGxsjpp.js} +42 -42
- package/dist/chunks/admin-pickers-DfGxsjpp.js.map +1 -0
- package/dist/chunks/{approval-instance-list-page-CPXMP3PL.js → approval-instance-list-page-BnI4t5mD.js} +7 -8
- package/dist/chunks/{approval-instance-list-page-CPXMP3PL.js.map → approval-instance-list-page-BnI4t5mD.js.map} +1 -1
- package/dist/chunks/{approval-instance-list-page-ax0pm8bt.cjs → approval-instance-list-page-fqvmkBlg.cjs} +2 -2
- package/dist/chunks/{approval-instance-list-page-ax0pm8bt.cjs.map → approval-instance-list-page-fqvmkBlg.cjs.map} +1 -1
- package/dist/chunks/auth-provider-4BeCw7cI.cjs.map +1 -1
- package/dist/chunks/{auth-provider-B5oPmvk2.js → auth-provider-C2b-5mGt.js} +2 -3
- package/dist/chunks/{auth-provider-B5oPmvk2.js.map → auth-provider-C2b-5mGt.js.map} +1 -1
- package/dist/chunks/{bpm-form-field-Cao0rMol.js → bpm-form-field-9B-Det0u.js} +2 -3
- package/dist/chunks/{bpm-form-field-Cao0rMol.js.map → bpm-form-field-9B-Det0u.js.map} +1 -1
- package/dist/chunks/bpm-form-field-Bc6k4ZEO.cjs.map +1 -1
- package/dist/chunks/{categories-riC33J_j.js → categories-BAdxjNSA.js} +14 -15
- package/dist/chunks/{categories-riC33J_j.js.map → categories-BAdxjNSA.js.map} +1 -1
- package/dist/chunks/{categories-AxxhqjLZ.cjs → categories-DQUtVEiV.cjs} +2 -2
- package/dist/chunks/{categories-AxxhqjLZ.cjs.map → categories-DQUtVEiV.cjs.map} +1 -1
- package/dist/chunks/{compose-B1GlrZW9.js → compose-D6zBIc2Z.js} +131 -148
- package/dist/chunks/compose-D6zBIc2Z.js.map +1 -0
- package/dist/chunks/compose-NH6dsFXD.cjs +2 -0
- package/dist/chunks/compose-NH6dsFXD.cjs.map +1 -0
- package/dist/chunks/{dashboard-page-DdBvV6YI.js → dashboard-page-BoqNhjT_.js} +5 -6
- package/dist/chunks/{dashboard-page-DdBvV6YI.js.map → dashboard-page-BoqNhjT_.js.map} +1 -1
- package/dist/chunks/{dashboard-page-BWQBSGDq.cjs → dashboard-page-D7YJ3udk.cjs} +2 -2
- package/dist/chunks/{dashboard-page-BWQBSGDq.cjs.map → dashboard-page-D7YJ3udk.cjs.map} +1 -1
- package/dist/chunks/{delegations-MxF3uJGW.js → delegations-BfhCDz5e.js} +15 -16
- package/dist/chunks/{delegations-MxF3uJGW.js.map → delegations-BfhCDz5e.js.map} +1 -1
- package/dist/chunks/{delegations-Ckf03icM.cjs → delegations-BmFGcuhA.cjs} +2 -2
- package/dist/chunks/{delegations-Ckf03icM.cjs.map → delegations-BmFGcuhA.cjs.map} +1 -1
- package/dist/chunks/{delegations-V9HIe3_P.cjs → delegations-CcS0SHbf.cjs} +2 -2
- package/dist/chunks/{delegations-V9HIe3_P.cjs.map → delegations-CcS0SHbf.cjs.map} +1 -1
- package/dist/chunks/{delegations-xUt1tj8d.js → delegations-DBh5TT6G.js} +16 -17
- package/dist/chunks/{delegations-xUt1tj8d.js.map → delegations-DBh5TT6G.js.map} +1 -1
- package/dist/chunks/designer-Be9UI9Tg.cjs +65 -0
- package/dist/chunks/designer-Be9UI9Tg.cjs.map +1 -0
- package/dist/chunks/{designer-BCLrjb4H.js → designer-uhC_7m2i.js} +1791 -1407
- package/dist/chunks/designer-uhC_7m2i.js.map +1 -0
- package/dist/chunks/detail-6uw5dmTi.cjs +5 -0
- package/dist/chunks/detail-6uw5dmTi.cjs.map +1 -0
- package/dist/chunks/{detail-4F39ggBn.js → detail-_GeKqNC-.js} +1012 -972
- package/dist/chunks/detail-_GeKqNC-.js.map +1 -0
- package/dist/chunks/{format-date-time-CB-LxzqT.js → format-date-time-B0LdmWg4.js} +2 -3
- package/dist/chunks/{format-date-time-CB-LxzqT.js.map → format-date-time-B0LdmWg4.js.map} +1 -1
- package/dist/chunks/format-date-time-D-cx5M8z.cjs.map +1 -1
- package/dist/chunks/{format-member-label-DudVI55w.js → format-member-label-C73FuP-d.js} +2 -3
- package/dist/chunks/{format-member-label-DudVI55w.js.map → format-member-label-C73FuP-d.js.map} +1 -1
- package/dist/chunks/format-member-label-t7ANTF62.cjs.map +1 -1
- package/dist/chunks/{approver-filled-form-Dm3Iw7iw.cjs → instance-error-message-DTARGbGo.cjs} +2 -2
- package/dist/chunks/instance-error-message-DTARGbGo.cjs.map +1 -0
- package/dist/chunks/{approver-filled-form-ZEwpmsHJ.js → instance-error-message-q6gy5evy.js} +50 -38
- package/dist/chunks/instance-error-message-q6gy5evy.js.map +1 -0
- package/dist/chunks/language-provider-Bdnx3Gxl.cjs.map +1 -1
- package/dist/chunks/{language-provider-B3cEbLe4.js → language-provider-phkWOapf.js} +2 -3
- package/dist/chunks/{language-provider-B3cEbLe4.js.map → language-provider-phkWOapf.js.map} +1 -1
- package/dist/chunks/{login-C6qlTC6F.js → login-D6cc3bo7.js} +4 -5
- package/dist/chunks/{login-C6qlTC6F.js.map → login-D6cc3bo7.js.map} +1 -1
- package/dist/chunks/{login-AtVxZBsC.cjs → login-uvVcltrS.cjs} +2 -2
- package/dist/chunks/{login-AtVxZBsC.cjs.map → login-uvVcltrS.cjs.map} +1 -1
- package/dist/chunks/notifications-Bc4mgSds.cjs.map +1 -1
- package/dist/chunks/{notifications-DJ5wzCye.js → notifications-Cvme5Qbl.js} +2 -3
- package/dist/chunks/{notifications-DJ5wzCye.js.map → notifications-Cvme5Qbl.js.map} +1 -1
- package/dist/chunks/orgs-B_2J2tLX.cjs +2 -0
- package/dist/chunks/{orgs-BeeDDWL1.cjs.map → orgs-B_2J2tLX.cjs.map} +1 -1
- package/dist/chunks/{orgs-8hje_l2n.js → orgs-DqxMds26.js} +48 -49
- package/dist/chunks/{orgs-8hje_l2n.js.map → orgs-DqxMds26.js.map} +1 -1
- package/dist/chunks/{providers-B_d5tbCL.js → providers-BbCs23sk.js} +21 -25
- package/dist/chunks/{providers-B_d5tbCL.js.map → providers-BbCs23sk.js.map} +1 -1
- package/dist/chunks/{providers-chuJvMgv.cjs → providers-D_KAgOOu.cjs} +2 -2
- package/dist/chunks/{providers-chuJvMgv.cjs.map → providers-D_KAgOOu.cjs.map} +1 -1
- package/dist/chunks/router-adapter--gYs13E8.cjs.map +1 -1
- package/dist/chunks/{router-adapter-DftlFTOd.js → router-adapter-CkxCyzf5.js} +2 -3
- package/dist/chunks/{router-adapter-DftlFTOd.js.map → router-adapter-CkxCyzf5.js.map} +1 -1
- package/dist/chunks/{routes-config-yZbESPlw.js → routes-config-BcNaWJWJ.js} +2 -3
- package/dist/chunks/{routes-config-yZbESPlw.js.map → routes-config-BcNaWJWJ.js.map} +1 -1
- package/dist/chunks/routes-config-C1j_vFKo.cjs.map +1 -1
- package/dist/chunks/task-decision-3d17ZvZE.js +29 -0
- package/dist/chunks/task-decision-3d17ZvZE.js.map +1 -0
- package/dist/chunks/task-decision-CqZ4WQOC.cjs +2 -0
- package/dist/chunks/task-decision-CqZ4WQOC.cjs.map +1 -0
- package/dist/chunks/{use-bpm-member-D57LKe_u.js → use-bpm-member-BPzcNU1g.js} +3 -4
- package/dist/chunks/{use-bpm-member-D57LKe_u.js.map → use-bpm-member-BPzcNU1g.js.map} +1 -1
- package/dist/chunks/use-bpm-member-DpNAQtNC.cjs.map +1 -1
- package/dist/chunks/{users-Pl6hY5Y5.js → users-BBtiZ9QQ.js} +22 -25
- package/dist/chunks/{users-Pl6hY5Y5.js.map → users-BBtiZ9QQ.js.map} +1 -1
- package/dist/chunks/{users-O2L_M3BK.cjs → users-EqSzDhuj.cjs} +2 -2
- package/dist/chunks/{users-O2L_M3BK.cjs.map → users-EqSzDhuj.cjs.map} +1 -1
- package/dist/components/admin-picker-options.d.cts +11 -0
- package/dist/components/admin-picker-options.d.ts +11 -0
- package/dist/components/admin-pickers.d.cts +2 -11
- package/dist/components/admin-pickers.d.ts +2 -11
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +17 -19
- package/dist/index.js.map +1 -1
- package/dist/lib/task-decision.d.cts +16 -0
- package/dist/lib/task-decision.d.ts +16 -0
- package/dist/lib/use-org-unit-names.d.cts +10 -0
- package/dist/lib/use-org-unit-names.d.ts +10 -0
- package/dist/next/index.cjs +1 -1
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.js +7 -8
- package/dist/next/index.js.map +1 -1
- package/dist/next/workflow-chat-route.cjs +19 -1
- package/dist/next/workflow-chat-route.cjs.map +1 -1
- package/dist/next/workflow-chat-route.js +2 -3
- package/dist/next/workflow-chat-route.js.map +1 -1
- package/dist/pages/admin/delegations/index.cjs +1 -1
- package/dist/pages/admin/delegations/index.cjs.map +1 -1
- package/dist/pages/admin/delegations/index.js +2 -3
- package/dist/pages/admin/orgs/index.cjs +1 -1
- package/dist/pages/admin/orgs/index.cjs.map +1 -1
- package/dist/pages/admin/orgs/index.js +2 -3
- package/dist/pages/admin/users/index.cjs +1 -1
- package/dist/pages/admin/users/index.cjs.map +1 -1
- package/dist/pages/admin/users/index.js +2 -3
- package/dist/pages/admin/webhook-endpoints/index.cjs.map +1 -1
- package/dist/pages/admin/webhook-endpoints/index.js +1 -2
- package/dist/pages/cc/index.cjs.map +1 -1
- package/dist/pages/cc/index.js +1 -2
- package/dist/pages/dashboard/index.cjs.map +1 -1
- package/dist/pages/dashboard/index.js +1 -2
- package/dist/pages/delegations/index.cjs +1 -1
- package/dist/pages/delegations/index.cjs.map +1 -1
- package/dist/pages/delegations/index.js +2 -3
- package/dist/pages/inbox/index.cjs.map +1 -1
- package/dist/pages/inbox/index.js +1 -2
- package/dist/pages/instances/detail/index.cjs +1 -1
- package/dist/pages/instances/detail/index.cjs.map +1 -1
- package/dist/pages/instances/detail/index.js +2 -3
- package/dist/pages/instances/new/index.cjs.map +1 -1
- package/dist/pages/instances/new/index.js +1 -2
- package/dist/pages/login/index.cjs +1 -1
- package/dist/pages/login/index.cjs.map +1 -1
- package/dist/pages/login/index.js +2 -3
- package/dist/pages/root/index.cjs.map +1 -1
- package/dist/pages/root/index.js +1 -2
- package/dist/pages/search/index.cjs.map +1 -1
- package/dist/pages/search/index.js +1 -2
- package/dist/pages/sent/index.cjs.map +1 -1
- package/dist/pages/sent/index.js +1 -2
- package/dist/pages/settings/notifications/index.cjs.map +1 -1
- package/dist/pages/settings/notifications/index.js +2 -3
- package/dist/pages/templates/categories/index.cjs +1 -1
- package/dist/pages/templates/categories/index.cjs.map +1 -1
- package/dist/pages/templates/categories/index.js +2 -3
- package/dist/pages/templates/compose/index.cjs +1 -1
- package/dist/pages/templates/compose/index.cjs.map +1 -1
- package/dist/pages/templates/compose/index.js +2 -3
- package/dist/pages/templates/designer/index.cjs +1 -1
- package/dist/pages/templates/designer/index.cjs.map +1 -1
- package/dist/pages/templates/designer/index.js +2 -3
- package/dist/pages/templates/index.cjs.map +1 -1
- package/dist/pages/templates/index.js +1 -2
- package/dist/pages/templates/versions/index.cjs.map +1 -1
- package/dist/pages/templates/versions/index.js +1 -2
- package/dist/views/admin/delegations/index.cjs +1 -1
- package/dist/views/admin/delegations/index.js +1 -1
- package/dist/views/admin/index.cjs +1 -1
- package/dist/views/admin/index.js +3 -3
- package/dist/views/admin/orgs/index.cjs +1 -1
- package/dist/views/admin/orgs/index.js +1 -1
- package/dist/views/admin/users/index.cjs +1 -1
- package/dist/views/admin/users/index.js +1 -1
- package/dist/views/admin/webhook-endpoints/index.cjs +1 -1
- package/dist/views/admin/webhook-endpoints/index.cjs.map +1 -1
- package/dist/views/admin/webhook-endpoints/index.js +52 -53
- package/dist/views/admin/webhook-endpoints/index.js.map +1 -1
- package/dist/views/cc/index.cjs +1 -1
- package/dist/views/cc/index.cjs.map +1 -1
- package/dist/views/cc/index.js +2 -3
- package/dist/views/dashboard/index.cjs +1 -1
- package/dist/views/dashboard/index.cjs.map +1 -1
- package/dist/views/dashboard/index.js +2 -3
- package/dist/views/delegations/index.cjs +1 -1
- package/dist/views/delegations/index.js +1 -1
- package/dist/views/forms/builder/index.cjs +1 -1
- package/dist/views/forms/builder/index.js +1 -1
- package/dist/views/forms/renderer/FormRendererView.d.cts +24 -1
- package/dist/views/forms/renderer/FormRendererView.d.ts +24 -1
- package/dist/views/forms/renderer/file-upload-field.d.cts +84 -0
- package/dist/views/forms/renderer/file-upload-field.d.ts +84 -0
- package/dist/views/forms/renderer/form-value-readers.d.cts +7 -0
- package/dist/views/forms/renderer/form-value-readers.d.ts +7 -0
- package/dist/views/forms/renderer/index.cjs +1 -1
- package/dist/views/forms/renderer/index.d.cts +1 -0
- package/dist/views/forms/renderer/index.d.ts +1 -0
- package/dist/views/forms/renderer/index.js +1 -1
- package/dist/views/forms/renderer/org-unit-field-options.d.cts +44 -0
- package/dist/views/forms/renderer/org-unit-field-options.d.ts +44 -0
- package/dist/views/forms/renderer/org-unit-field.d.cts +23 -0
- package/dist/views/forms/renderer/org-unit-field.d.ts +23 -0
- package/dist/views/inbox/index.cjs +1 -1
- package/dist/views/inbox/index.cjs.map +1 -1
- package/dist/views/inbox/index.js +133 -137
- package/dist/views/inbox/index.js.map +1 -1
- package/dist/views/instances/approver-filled-form.d.cts +9 -2
- package/dist/views/instances/approver-filled-form.d.ts +9 -2
- package/dist/views/instances/detail/index.cjs +1 -1
- package/dist/views/instances/detail/index.js +1 -1
- package/dist/views/instances/detail/sections/InstanceFormSection.d.cts +19 -2
- package/dist/views/instances/detail/sections/InstanceFormSection.d.ts +19 -2
- package/dist/views/instances/detail/sections/InstanceHistorySection.d.cts +8 -1
- package/dist/views/instances/detail/sections/InstanceHistorySection.d.ts +8 -1
- package/dist/views/instances/detail/sections/container-helpers.d.cts +0 -1
- package/dist/views/instances/detail/sections/container-helpers.d.ts +0 -1
- package/dist/views/instances/detail/sections/shared.d.cts +3 -4
- package/dist/views/instances/detail/sections/shared.d.ts +3 -4
- package/dist/views/instances/instance-error-message.d.cts +5 -0
- package/dist/views/instances/instance-error-message.d.ts +5 -0
- package/dist/views/instances/new/index.cjs +1 -1
- package/dist/views/instances/new/index.cjs.map +1 -1
- package/dist/views/instances/new/index.js +78 -77
- package/dist/views/instances/new/index.js.map +1 -1
- package/dist/views/login/index.cjs +1 -1
- package/dist/views/login/index.js +1 -1
- package/dist/views/search/index.cjs +1 -1
- package/dist/views/search/index.cjs.map +1 -1
- package/dist/views/search/index.js +2 -3
- package/dist/views/sent/index.cjs +1 -1
- package/dist/views/sent/index.cjs.map +1 -1
- package/dist/views/sent/index.js +2 -3
- package/dist/views/settings/index.js +1 -1
- package/dist/views/settings/notifications/index.js +1 -1
- package/dist/views/templates/categories/index.cjs +1 -1
- package/dist/views/templates/categories/index.js +1 -1
- package/dist/views/templates/compose/index.cjs +1 -1
- package/dist/views/templates/compose/index.js +1 -1
- package/dist/views/templates/designer/approver-resolver-model.d.cts +211 -0
- package/dist/views/templates/designer/approver-resolver-model.d.ts +211 -0
- package/dist/views/templates/designer/dry-run-assignee-label.d.cts +2 -0
- package/dist/views/templates/designer/dry-run-assignee-label.d.ts +2 -0
- package/dist/views/templates/designer/dry-run-sample-data.d.cts +6 -0
- package/dist/views/templates/designer/dry-run-sample-data.d.ts +6 -0
- package/dist/views/templates/designer/dynamic-form-resolver-options.d.cts +25 -0
- package/dist/views/templates/designer/dynamic-form-resolver-options.d.ts +25 -0
- package/dist/views/templates/designer/index.cjs +1 -1
- package/dist/views/templates/designer/index.js +1 -1
- package/dist/views/templates/designer/node-actor-resolver-options.d.cts +38 -0
- package/dist/views/templates/designer/node-actor-resolver-options.d.ts +38 -0
- package/dist/views/templates/index.cjs +1 -1
- package/dist/views/templates/index.cjs.map +1 -1
- package/dist/views/templates/index.js +50 -51
- package/dist/views/templates/index.js.map +1 -1
- package/dist/views/templates/versions/index.cjs +1 -1
- package/dist/views/templates/versions/index.cjs.map +1 -1
- package/dist/views/templates/versions/index.js +7 -8
- package/dist/views/templates/versions/index.js.map +1 -1
- package/package.json +3 -3
- package/dist/chunks/FormBuilderView-BVKY1j_0.js.map +0 -1
- package/dist/chunks/FormBuilderView-SrGltzFT.cjs +0 -3
- package/dist/chunks/FormBuilderView-SrGltzFT.cjs.map +0 -1
- package/dist/chunks/FormRendererView-BsTwZkqU.js.map +0 -1
- package/dist/chunks/FormRendererView-GpsE03np.cjs +0 -4
- package/dist/chunks/FormRendererView-GpsE03np.cjs.map +0 -1
- package/dist/chunks/admin-pickers-BRHk3qKq.cjs +0 -2
- package/dist/chunks/admin-pickers-BRHk3qKq.cjs.map +0 -1
- package/dist/chunks/admin-pickers-Djq3h-UR.js.map +0 -1
- package/dist/chunks/approver-filled-form-Dm3Iw7iw.cjs.map +0 -1
- package/dist/chunks/approver-filled-form-ZEwpmsHJ.js.map +0 -1
- package/dist/chunks/compose-B1GlrZW9.js.map +0 -1
- package/dist/chunks/compose-DZk-SfHT.cjs +0 -2
- package/dist/chunks/compose-DZk-SfHT.cjs.map +0 -1
- package/dist/chunks/designer-BCLrjb4H.js.map +0 -1
- package/dist/chunks/designer-BYYxEN9L.cjs +0 -65
- package/dist/chunks/designer-BYYxEN9L.cjs.map +0 -1
- package/dist/chunks/detail-4F39ggBn.js.map +0 -1
- package/dist/chunks/detail-BkMtA_0K.cjs +0 -2
- package/dist/chunks/detail-BkMtA_0K.cjs.map +0 -1
- package/dist/chunks/orgs-BeeDDWL1.cjs +0 -2
- package/dist/chunks/task-node-label-BF6UllxP.cjs +0 -2
- package/dist/chunks/task-node-label-BF6UllxP.cjs.map +0 -1
- package/dist/chunks/task-node-label-CWZgOBj0.js +0 -9
- package/dist/chunks/task-node-label-CWZgOBj0.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login-AtVxZBsC.cjs","names":["useRouterAdapter","useAuth","useState","listApiTestMembers","useCallback","styles","Typography","Input","Button","LoginIcon","require_router_adapter","require_auth_provider","react","_mezzanine_ui_react","_rytass_bpm_core_client","react_jsx_runtime","_mezzanine_ui_icons","login_module_default","DEFAULT_LOGO","DEFAULT_IDENTIFIER","DEFAULT_PASSWORD","LoginView","router","testMembers","setTestMembers","error","setError","identifier","setIdentifier","defaultIdentifier","password","setPassword","defaultPassword","submitting","setSubmitting","member","resolveNextPath","defaultNextPath","loading","handleSubmit","event","login","loginError","readErrorMessage","handleIdentifierChange","handlePasswordChange","logoSrc","brandTitle","brandSubtitle","testMember","fallback","next","readBrowserSearchParams"],"sources":["../../src/views/login/login.module.scss","../../src/views/login/LoginView.tsx"],"sourcesContent":[".loginPage {\n align-items: center;\n background: var(--mzn-color-bg-body);\n display: flex;\n min-height: 100vh;\n justify-content: center;\n padding: 32px;\n}\n\n.loginPanel {\n border: 1px solid var(--mzn-color-border);\n border-radius: 8px;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 28px;\n max-width: 440px;\n padding: 32px;\n width: 100%;\n}\n\n.brand {\n align-items: center;\n display: flex;\n gap: 14px;\n}\n\n.brandLogo {\n border-radius: 8px;\n height: 40px;\n width: 40px;\n object-fit: contain;\n}\n\n.form {\n display: flex;\n flex-direction: column;\n gap: 18px;\n}\n\n.demoUsers {\n border-top: 1px solid var(--mzn-color-border);\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding-top: 20px;\n}\n\n.demoUserList {\n display: grid;\n gap: 8px;\n}\n\n.demoUserButton {\n background: transparent;\n border: 1px solid var(--mzn-color-border);\n border-radius: 6px;\n color: inherit;\n cursor: pointer;\n display: flex;\n flex-direction: column;\n font: inherit;\n gap: 2px;\n padding: 10px 12px;\n text-align: left;\n}\n\n.demoUserButton:hover {\n border-color: var(--mzn-color-primary);\n}\n\n.demoUserButton span:last-child {\n color: var(--mzn-color-text-secondary);\n font-size: 12px;\n}\n","'use client';\n\nimport {\n useCallback,\n useEffect,\n useState,\n type ChangeEvent,\n type FormEvent,\n type ReactElement,\n} from 'react';\nimport { Button, Input, Typography } from '@mezzanine-ui/react';\nimport { LoginIcon } from '@mezzanine-ui/icons';\nimport {\n listApiTestMembers,\n type ApiPublicMember,\n} from '@rytass/bpm-core-client';\nimport { useAuth } from '../../lib/auth-provider';\nimport { useRouterAdapter } from '../../lib/router-adapter';\nimport styles from './login.module.scss';\n\nexport interface LoginViewProps {\n /**\n * Logo image URL. Renders an inline `<img>` so the view stays framework\n * agnostic (no `next/image` dependency). Defaults to\n * `/rytass-logo.png` — host should serve a static asset at that path or\n * override via this prop.\n */\n readonly logoSrc?: string;\n /**\n * Pre-fill the identifier input. Defaults to the seeded demo account\n * email so the form is usable out of the box.\n */\n readonly defaultIdentifier?: string;\n /**\n * Pre-fill the password input. Defaults to the seeded demo password\n * (`'demo'`). Production hosts should pass an empty string.\n */\n readonly defaultPassword?: string;\n /**\n * Custom redirect target after a successful login. Defaults to reading\n * `?next=` from the host router's search params, falling back to `'/'`.\n */\n readonly defaultNextPath?: string;\n /**\n * Override the BPM admin brand title shown above the form. Defaults to\n * `'BPM Admin'`.\n */\n readonly brandTitle?: string;\n /**\n * Override the brand subtitle shown above the form. Defaults to\n * `'BPM API 登入'`.\n */\n readonly brandSubtitle?: string;\n}\n\nconst DEFAULT_LOGO = '/rytass-logo.png';\nconst DEFAULT_IDENTIFIER = 'lin.ceo@example.internal';\nconst DEFAULT_PASSWORD = 'demo';\n\n/**\n * Login UI for the BPM admin host. Renders the brand mark, identifier /\n * password fields, and a \"test members\" picker fed by\n * `listApiTestMembers()`. Self-contained: composes Mezzanine UI primitives,\n * reads the auth context, and uses the host router adapter to redirect on\n * success.\n *\n * Wrap with `<AuthProvider>` (and indirectly `<RouterAdapterProvider>`)\n * higher in the tree. The `pages/login` subpath ships a thin Next.js\n * wrapper that exports `default` (Server Component) and `metadata`.\n */\nexport function LoginView({\n logoSrc = DEFAULT_LOGO,\n defaultIdentifier = DEFAULT_IDENTIFIER,\n defaultPassword = DEFAULT_PASSWORD,\n defaultNextPath,\n brandTitle = 'BPM Admin',\n brandSubtitle = 'BPM API 登入',\n}: LoginViewProps = {}): ReactElement {\n const router = useRouterAdapter();\n const { loading, login, member } = useAuth();\n const [testMembers, setTestMembers] = useState<readonly ApiPublicMember[]>(\n [],\n );\n const [error, setError] = useState<string | null>(null);\n const [identifier, setIdentifier] = useState(defaultIdentifier);\n const [password, setPassword] = useState(defaultPassword);\n const [submitting, setSubmitting] = useState(false);\n\n useEffect((): void => {\n if (loading || !member) return;\n router.replace(resolveNextPath(defaultNextPath));\n }, [defaultNextPath, loading, member, router]);\n\n useEffect((): void => {\n void (async () => {\n try {\n setTestMembers(await listApiTestMembers());\n } catch {\n setTestMembers([]);\n }\n })();\n }, []);\n\n const handleSubmit = useCallback(\n async (event: FormEvent<HTMLFormElement>): Promise<void> => {\n event.preventDefault();\n setError(null);\n setSubmitting(true);\n try {\n await login({ identifier, password });\n router.replace(resolveNextPath(defaultNextPath));\n } catch (loginError: unknown) {\n setError(readErrorMessage(loginError));\n } finally {\n setSubmitting(false);\n }\n },\n [defaultNextPath, identifier, login, password, router],\n );\n\n function handleIdentifierChange(event: ChangeEvent<HTMLInputElement>): void {\n setIdentifier(event.target.value);\n }\n function handlePasswordChange(event: ChangeEvent<HTMLInputElement>): void {\n setPassword(event.target.value);\n }\n\n return (\n <main className={styles.loginPage}>\n <section className={styles.loginPanel}>\n <div className={styles.brand}>\n <img alt=\"\" className={styles.brandLogo} src={logoSrc} />\n <div>\n <Typography variant=\"h3\">{brandTitle}</Typography>\n <Typography color=\"text-neutral\" variant=\"body\">\n {brandSubtitle}\n </Typography>\n </div>\n </div>\n\n <form className={styles.form} onSubmit={handleSubmit}>\n <label>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 帳號\n </Typography>\n <Input\n fullWidth\n name=\"identifier\"\n onChange={handleIdentifierChange}\n placeholder=\"member id 或 email\"\n value={identifier}\n />\n </label>\n\n <label>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 密碼\n </Typography>\n <Input\n fullWidth\n inputType=\"password\"\n name=\"password\"\n onChange={handlePasswordChange}\n value={password}\n variant=\"password\"\n />\n </label>\n\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n\n <Button\n disabled={submitting}\n icon={LoginIcon}\n iconType=\"leading\"\n type=\"submit\"\n variant=\"base-primary\"\n >\n 登入\n </Button>\n </form>\n\n {testMembers.length ? (\n <div className={styles.demoUsers}>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 測試帳號\n </Typography>\n <div className={styles.demoUserList}>\n {testMembers.map((testMember) => (\n <button\n className={styles.demoUserButton}\n key={testMember.memberId}\n onClick={(): void => setIdentifier(testMember.email)}\n type=\"button\"\n >\n <span>{testMember.name}</span>\n <span>{testMember.email}</span>\n </button>\n ))}\n </div>\n </div>\n ) : null}\n </section>\n </main>\n );\n}\n\nfunction resolveNextPath(fallback: string | undefined): string {\n if (fallback && fallback.startsWith('/') && !fallback.startsWith('//')) {\n return fallback;\n }\n const params = readBrowserSearchParams();\n const next = params.get('next');\n if (!next || !next.startsWith('/') || next.startsWith('//')) {\n return '/';\n }\n return next;\n}\n\nfunction readBrowserSearchParams(): URLSearchParams {\n if (typeof window === 'undefined') return new URLSearchParams();\n return new URLSearchParams(window.location.search);\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '登入失敗';\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"login-uvVcltrS.cjs","names":["useRouterAdapter","useAuth","useState","listApiTestMembers","useCallback","styles","Typography","Input","Button","LoginIcon","require_auth_provider","require_router_adapter","react","_mezzanine_ui_react","_rytass_bpm_core_client","react_jsx_runtime","_mezzanine_ui_icons","login_module_default","DEFAULT_LOGO","DEFAULT_IDENTIFIER","DEFAULT_PASSWORD","LoginView","router","testMembers","setTestMembers","error","setError","identifier","setIdentifier","defaultIdentifier","password","setPassword","defaultPassword","submitting","setSubmitting","member","resolveNextPath","defaultNextPath","loading","handleSubmit","event","login","loginError","readErrorMessage","handleIdentifierChange","handlePasswordChange","logoSrc","brandTitle","brandSubtitle","testMember","fallback","next","readBrowserSearchParams"],"sources":["../../src/views/login/login.module.scss","../../src/views/login/LoginView.tsx"],"sourcesContent":[".loginPage {\n align-items: center;\n background: var(--mzn-color-bg-body);\n display: flex;\n min-height: 100vh;\n justify-content: center;\n padding: 32px;\n}\n\n.loginPanel {\n border: 1px solid var(--mzn-color-border);\n border-radius: 8px;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n gap: 28px;\n max-width: 440px;\n padding: 32px;\n width: 100%;\n}\n\n.brand {\n align-items: center;\n display: flex;\n gap: 14px;\n}\n\n.brandLogo {\n border-radius: 8px;\n height: 40px;\n width: 40px;\n object-fit: contain;\n}\n\n.form {\n display: flex;\n flex-direction: column;\n gap: 18px;\n}\n\n.demoUsers {\n border-top: 1px solid var(--mzn-color-border);\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding-top: 20px;\n}\n\n.demoUserList {\n display: grid;\n gap: 8px;\n}\n\n.demoUserButton {\n background: transparent;\n border: 1px solid var(--mzn-color-border);\n border-radius: 6px;\n color: inherit;\n cursor: pointer;\n display: flex;\n flex-direction: column;\n font: inherit;\n gap: 2px;\n padding: 10px 12px;\n text-align: left;\n}\n\n.demoUserButton:hover {\n border-color: var(--mzn-color-primary);\n}\n\n.demoUserButton span:last-child {\n color: var(--mzn-color-text-secondary);\n font-size: 12px;\n}\n","'use client';\n\nimport {\n useCallback,\n useEffect,\n useState,\n type ChangeEvent,\n type FormEvent,\n type ReactElement,\n} from 'react';\nimport { Button, Input, Typography } from '@mezzanine-ui/react';\nimport { LoginIcon } from '@mezzanine-ui/icons';\nimport {\n listApiTestMembers,\n type ApiPublicMember,\n} from '@rytass/bpm-core-client';\nimport { useAuth } from '../../lib/auth-provider';\nimport { useRouterAdapter } from '../../lib/router-adapter';\nimport styles from './login.module.scss';\n\nexport interface LoginViewProps {\n /**\n * Logo image URL. Renders an inline `<img>` so the view stays framework\n * agnostic (no `next/image` dependency). Defaults to\n * `/rytass-logo.png` — host should serve a static asset at that path or\n * override via this prop.\n */\n readonly logoSrc?: string;\n /**\n * Pre-fill the identifier input. Defaults to the seeded demo account\n * email so the form is usable out of the box.\n */\n readonly defaultIdentifier?: string;\n /**\n * Pre-fill the password input. Defaults to the seeded demo password\n * (`'demo'`). Production hosts should pass an empty string.\n */\n readonly defaultPassword?: string;\n /**\n * Custom redirect target after a successful login. Defaults to reading\n * `?next=` from the host router's search params, falling back to `'/'`.\n */\n readonly defaultNextPath?: string;\n /**\n * Override the BPM admin brand title shown above the form. Defaults to\n * `'BPM Admin'`.\n */\n readonly brandTitle?: string;\n /**\n * Override the brand subtitle shown above the form. Defaults to\n * `'BPM API 登入'`.\n */\n readonly brandSubtitle?: string;\n}\n\nconst DEFAULT_LOGO = '/rytass-logo.png';\nconst DEFAULT_IDENTIFIER = 'lin.ceo@example.internal';\nconst DEFAULT_PASSWORD = 'demo';\n\n/**\n * Login UI for the BPM admin host. Renders the brand mark, identifier /\n * password fields, and a \"test members\" picker fed by\n * `listApiTestMembers()`. Self-contained: composes Mezzanine UI primitives,\n * reads the auth context, and uses the host router adapter to redirect on\n * success.\n *\n * Wrap with `<AuthProvider>` (and indirectly `<RouterAdapterProvider>`)\n * higher in the tree. The `pages/login` subpath ships a thin Next.js\n * wrapper that exports `default` (Server Component) and `metadata`.\n */\nexport function LoginView({\n logoSrc = DEFAULT_LOGO,\n defaultIdentifier = DEFAULT_IDENTIFIER,\n defaultPassword = DEFAULT_PASSWORD,\n defaultNextPath,\n brandTitle = 'BPM Admin',\n brandSubtitle = 'BPM API 登入',\n}: LoginViewProps = {}): ReactElement {\n const router = useRouterAdapter();\n const { loading, login, member } = useAuth();\n const [testMembers, setTestMembers] = useState<readonly ApiPublicMember[]>(\n [],\n );\n const [error, setError] = useState<string | null>(null);\n const [identifier, setIdentifier] = useState(defaultIdentifier);\n const [password, setPassword] = useState(defaultPassword);\n const [submitting, setSubmitting] = useState(false);\n\n useEffect((): void => {\n if (loading || !member) return;\n router.replace(resolveNextPath(defaultNextPath));\n }, [defaultNextPath, loading, member, router]);\n\n useEffect((): void => {\n void (async () => {\n try {\n setTestMembers(await listApiTestMembers());\n } catch {\n setTestMembers([]);\n }\n })();\n }, []);\n\n const handleSubmit = useCallback(\n async (event: FormEvent<HTMLFormElement>): Promise<void> => {\n event.preventDefault();\n setError(null);\n setSubmitting(true);\n try {\n await login({ identifier, password });\n router.replace(resolveNextPath(defaultNextPath));\n } catch (loginError: unknown) {\n setError(readErrorMessage(loginError));\n } finally {\n setSubmitting(false);\n }\n },\n [defaultNextPath, identifier, login, password, router],\n );\n\n function handleIdentifierChange(event: ChangeEvent<HTMLInputElement>): void {\n setIdentifier(event.target.value);\n }\n function handlePasswordChange(event: ChangeEvent<HTMLInputElement>): void {\n setPassword(event.target.value);\n }\n\n return (\n <main className={styles.loginPage}>\n <section className={styles.loginPanel}>\n <div className={styles.brand}>\n <img alt=\"\" className={styles.brandLogo} src={logoSrc} />\n <div>\n <Typography variant=\"h3\">{brandTitle}</Typography>\n <Typography color=\"text-neutral\" variant=\"body\">\n {brandSubtitle}\n </Typography>\n </div>\n </div>\n\n <form className={styles.form} onSubmit={handleSubmit}>\n <label>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 帳號\n </Typography>\n <Input\n fullWidth\n name=\"identifier\"\n onChange={handleIdentifierChange}\n placeholder=\"member id 或 email\"\n value={identifier}\n />\n </label>\n\n <label>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 密碼\n </Typography>\n <Input\n fullWidth\n inputType=\"password\"\n name=\"password\"\n onChange={handlePasswordChange}\n value={password}\n variant=\"password\"\n />\n </label>\n\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n\n <Button\n disabled={submitting}\n icon={LoginIcon}\n iconType=\"leading\"\n type=\"submit\"\n variant=\"base-primary\"\n >\n 登入\n </Button>\n </form>\n\n {testMembers.length ? (\n <div className={styles.demoUsers}>\n <Typography color=\"text-neutral\" variant=\"caption\">\n 測試帳號\n </Typography>\n <div className={styles.demoUserList}>\n {testMembers.map((testMember) => (\n <button\n className={styles.demoUserButton}\n key={testMember.memberId}\n onClick={(): void => setIdentifier(testMember.email)}\n type=\"button\"\n >\n <span>{testMember.name}</span>\n <span>{testMember.email}</span>\n </button>\n ))}\n </div>\n </div>\n ) : null}\n </section>\n </main>\n );\n}\n\nfunction resolveNextPath(fallback: string | undefined): string {\n if (fallback && fallback.startsWith('/') && !fallback.startsWith('//')) {\n return fallback;\n }\n const params = readBrowserSearchParams();\n const next = params.get('next');\n if (!next || !next.startsWith('/') || next.startsWith('//')) {\n return '/';\n }\n return next;\n}\n\nfunction readBrowserSearchParams(): URLSearchParams {\n if (typeof window === 'undefined') return new URLSearchParams();\n return new URLSearchParams(window.location.search);\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '登入失敗';\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notifications-Bc4mgSds.cjs","names":["useAuth","useState","updateNotificationPreference","_Fragment","PageHeader","ContentHeader","SectionGroup","Section","FilterArea","styles","FilterLine","Filter","FormField","FormFieldLayout","RadioGroup","Typography","require_rolldown_runtime","require_auth_provider","react","_mezzanine_ui_react","react_jsx_runtime","_rytass_bpm_core_client_workflow","_mezzanine_ui_core_form","_mezzanine_ui_react_ContentHeader","notification_settings_module_default","DIGEST_OPTIONS","ENABLED_SEGMENT_OPTIONS","DEFAULT_PREFERENCE","SettingsNotificationsView","currentMemberId","member","preference","setPreference","loading","setLoading","saving","setSaving","error","setError","nextPreference","readErrorMessage","requestError","handlePreferenceChange","previousPreference","controlsDisabled","FILTER_FIELD_STYLE","readEnabledSegmentValue","event","readEnabledSegmentValueId","readDigestMode","value","enabled"],"sources":["../../src/views/settings/notifications/notification-settings.module.scss","../../src/views/settings/notifications/SettingsNotificationsView.tsx"],"sourcesContent":[".preferenceFilter {\n :global(.mzn-filter-area__actions) {\n display: none;\n }\n\n :global(.mzn-form-field__label-area) {\n display: none;\n }\n\n :global(.mzn-form-field__control-field-slot--main) {\n width: 100%;\n min-width: 0;\n }\n}\n\n.segmentFilterControl {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n min-width: 0;\n white-space: nowrap;\n\n :global(.mzn-input-check-group--segmented) {\n align-self: flex-start;\n transform: translateY(-7px);\n }\n}\n\n.segmentFilterLabel {\n flex: 0 0 auto;\n color: var(--mzn-color-text-primary, #1f2937);\n font-size: 13px;\n line-height: 16px;\n}\n","'use client';\n\nimport {\n ChangeEvent,\n CSSProperties,\n ReactElement,\n useEffect,\n useState,\n} from 'react';\nimport {\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n PageHeader,\n RadioGroup,\n Section,\n SectionGroup,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport { useAuth } from '../../../lib/auth-provider';\nimport {\n NotificationDigestMode,\n NotificationPreferenceRecord,\n readNotificationPreference,\n updateNotificationPreference,\n} from '@rytass/bpm-core-client/workflow';\nimport styles from './notification-settings.module.scss';\n\ninterface DigestOption {\n readonly id: NotificationDigestMode;\n readonly name: string;\n}\n\ntype EnabledSegmentValue = 'OFF' | 'ON';\n\ninterface EnabledSegmentOption {\n readonly id: EnabledSegmentValue;\n readonly name: string;\n}\n\nconst DIGEST_OPTIONS: readonly DigestOption[] = [\n { id: 'INSTANT', name: '即時通知' },\n { id: 'DAILY', name: '每日摘要' },\n];\n\nconst ENABLED_SEGMENT_OPTIONS: readonly EnabledSegmentOption[] = [\n { id: 'ON', name: '開' },\n { id: 'OFF', name: '關' },\n];\n\nconst DEFAULT_PREFERENCE: NotificationPreferenceRecord = {\n emailDigestMode: 'INSTANT',\n emailEnabled: true,\n inAppEnabled: true,\n memberId: '',\n quietHoursEnd: null,\n quietHoursStart: null,\n updatedAt: '',\n};\n\n\nexport function SettingsNotificationsView(): ReactElement {\n const { member } = useAuth();\n const currentMemberId = member?.memberId ?? null;\n const [preference, setPreference] =\n useState<NotificationPreferenceRecord>(DEFAULT_PREFERENCE);\n const [loading, setLoading] = useState(true);\n const [saving, setSaving] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect((): void => {\n if (!currentMemberId) {\n return;\n }\n\n setLoading(true);\n setError(null);\n\n readNotificationPreference(currentMemberId)\n .then((nextPreference): void => {\n setPreference(nextPreference);\n })\n .catch((requestError: unknown): void => {\n setError(readErrorMessage(requestError));\n })\n .finally((): void => {\n setLoading(false);\n });\n }, [currentMemberId]);\n\n async function handlePreferenceChange(\n nextPreference: NotificationPreferenceRecord,\n ): Promise<void> {\n if (!currentMemberId || saving) {\n return;\n }\n\n const previousPreference = preference;\n setPreference(nextPreference);\n setSaving(true);\n\n try {\n setPreference(\n await updateNotificationPreference({\n emailDigestMode: nextPreference.emailDigestMode,\n emailEnabled: nextPreference.emailEnabled,\n inAppEnabled: nextPreference.inAppEnabled,\n memberId: currentMemberId,\n quietHoursEnd: nextPreference.quietHoursEnd,\n quietHoursStart: nextPreference.quietHoursStart,\n }),\n );\n } catch (requestError: unknown) {\n setPreference(previousPreference);\n setError(readErrorMessage(requestError));\n } finally {\n setSaving(false);\n }\n }\n\n const controlsDisabled = loading || saving;\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"調整站內通知、Email 通知與摘要頻率。\"\n title=\"通知設定\"\n />\n </PageHeader>\n\n <SectionGroup>\n <Section\n filterArea={\n <FilterArea className={styles.preferenceFilter} isDirty={false}>\n <FilterLine>\n <Filter minWidth={160} span={1}>\n <FormField\n layout={FormFieldLayout.VERTICAL}\n name=\"inAppEnabled\"\n style={FILTER_FIELD_STYLE}\n >\n <div className={styles.segmentFilterControl}>\n <span className={styles.segmentFilterLabel}>\n 站內通知\n </span>\n <RadioGroup\n disabled={controlsDisabled}\n name=\"inAppEnabled\"\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n void handlePreferenceChange({\n ...preference,\n inAppEnabled: readEnabledSegmentValue(\n event.target.value,\n ),\n });\n }}\n options={[...ENABLED_SEGMENT_OPTIONS]}\n size=\"sub\"\n type=\"segment\"\n value={readEnabledSegmentValueId(\n preference.inAppEnabled,\n )}\n />\n </div>\n </FormField>\n </Filter>\n <Filter minWidth={180} span={1}>\n <FormField\n layout={FormFieldLayout.VERTICAL}\n name=\"emailEnabled\"\n style={FILTER_FIELD_STYLE}\n >\n <div className={styles.segmentFilterControl}>\n <span className={styles.segmentFilterLabel}>\n Email 通知\n </span>\n <RadioGroup\n disabled={controlsDisabled}\n name=\"emailEnabled\"\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n void handlePreferenceChange({\n ...preference,\n emailEnabled: readEnabledSegmentValue(\n event.target.value,\n ),\n });\n }}\n options={[...ENABLED_SEGMENT_OPTIONS]}\n size=\"sub\"\n type=\"segment\"\n value={readEnabledSegmentValueId(\n preference.emailEnabled,\n )}\n />\n </div>\n </FormField>\n </Filter>\n <Filter minWidth={280} span={2}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"emailDigestMode\"\n style={FILTER_FIELD_STYLE}\n >\n <div className={styles.segmentFilterControl}>\n <span className={styles.segmentFilterLabel}>\n Email 頻率\n </span>\n <RadioGroup\n disabled={controlsDisabled}\n name=\"emailDigestMode\"\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n void handlePreferenceChange({\n ...preference,\n emailDigestMode: readDigestMode(\n event.target.value,\n ),\n });\n }}\n options={[...DIGEST_OPTIONS]}\n size=\"sub\"\n type=\"segment\"\n value={preference.emailDigestMode}\n />\n </div>\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n }\n >\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n 偏好設定會立即生效。\n </Typography>\n )}\n </Section>\n </SectionGroup>\n </>\n );\n}\n\nconst FILTER_FIELD_STYLE = {\n minWidth: 0,\n whiteSpace: 'nowrap',\n} satisfies CSSProperties;\n\nfunction readDigestMode(value: unknown): NotificationDigestMode {\n return value === 'DAILY' ? 'DAILY' : 'INSTANT';\n}\n\nfunction readEnabledSegmentValue(value: unknown): boolean {\n return value !== 'OFF';\n}\n\nfunction readEnabledSegmentValueId(enabled: boolean): EnabledSegmentValue {\n return enabled ? 'ON' : 'OFF';\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"notifications-Bc4mgSds.cjs","names":["useAuth","useState","updateNotificationPreference","_Fragment","PageHeader","ContentHeader","SectionGroup","Section","FilterArea","styles","FilterLine","Filter","FormField","FormFieldLayout","RadioGroup","Typography","require_rolldown_runtime","require_auth_provider","react","_mezzanine_ui_react","react_jsx_runtime","_rytass_bpm_core_client_workflow","_mezzanine_ui_core_form","_mezzanine_ui_react_ContentHeader","notification_settings_module_default","DIGEST_OPTIONS","ENABLED_SEGMENT_OPTIONS","DEFAULT_PREFERENCE","SettingsNotificationsView","currentMemberId","member","preference","setPreference","loading","setLoading","saving","setSaving","error","setError","nextPreference","readErrorMessage","requestError","handlePreferenceChange","previousPreference","controlsDisabled","FILTER_FIELD_STYLE","readEnabledSegmentValue","event","readEnabledSegmentValueId","readDigestMode","value","enabled"],"sources":["../../src/views/settings/notifications/notification-settings.module.scss","../../src/views/settings/notifications/SettingsNotificationsView.tsx"],"sourcesContent":[".preferenceFilter {\n :global(.mzn-filter-area__actions) {\n display: none;\n }\n\n :global(.mzn-form-field__label-area) {\n display: none;\n }\n\n :global(.mzn-form-field__control-field-slot--main) {\n width: 100%;\n min-width: 0;\n }\n}\n\n.segmentFilterControl {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n min-width: 0;\n white-space: nowrap;\n\n :global(.mzn-input-check-group--segmented) {\n align-self: flex-start;\n transform: translateY(-7px);\n }\n}\n\n.segmentFilterLabel {\n flex: 0 0 auto;\n color: var(--mzn-color-text-primary, #1f2937);\n font-size: 13px;\n line-height: 16px;\n}\n","'use client';\n\nimport {\n ChangeEvent,\n CSSProperties,\n ReactElement,\n useEffect,\n useState,\n} from 'react';\nimport {\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n PageHeader,\n RadioGroup,\n Section,\n SectionGroup,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport { useAuth } from '../../../lib/auth-provider';\nimport {\n NotificationDigestMode,\n NotificationPreferenceRecord,\n readNotificationPreference,\n updateNotificationPreference,\n} from '@rytass/bpm-core-client/workflow';\nimport styles from './notification-settings.module.scss';\n\ninterface DigestOption {\n readonly id: NotificationDigestMode;\n readonly name: string;\n}\n\ntype EnabledSegmentValue = 'OFF' | 'ON';\n\ninterface EnabledSegmentOption {\n readonly id: EnabledSegmentValue;\n readonly name: string;\n}\n\nconst DIGEST_OPTIONS: readonly DigestOption[] = [\n { id: 'INSTANT', name: '即時通知' },\n { id: 'DAILY', name: '每日摘要' },\n];\n\nconst ENABLED_SEGMENT_OPTIONS: readonly EnabledSegmentOption[] = [\n { id: 'ON', name: '開' },\n { id: 'OFF', name: '關' },\n];\n\nconst DEFAULT_PREFERENCE: NotificationPreferenceRecord = {\n emailDigestMode: 'INSTANT',\n emailEnabled: true,\n inAppEnabled: true,\n memberId: '',\n quietHoursEnd: null,\n quietHoursStart: null,\n updatedAt: '',\n};\n\n\nexport function SettingsNotificationsView(): ReactElement {\n const { member } = useAuth();\n const currentMemberId = member?.memberId ?? null;\n const [preference, setPreference] =\n useState<NotificationPreferenceRecord>(DEFAULT_PREFERENCE);\n const [loading, setLoading] = useState(true);\n const [saving, setSaving] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect((): void => {\n if (!currentMemberId) {\n return;\n }\n\n setLoading(true);\n setError(null);\n\n readNotificationPreference(currentMemberId)\n .then((nextPreference): void => {\n setPreference(nextPreference);\n })\n .catch((requestError: unknown): void => {\n setError(readErrorMessage(requestError));\n })\n .finally((): void => {\n setLoading(false);\n });\n }, [currentMemberId]);\n\n async function handlePreferenceChange(\n nextPreference: NotificationPreferenceRecord,\n ): Promise<void> {\n if (!currentMemberId || saving) {\n return;\n }\n\n const previousPreference = preference;\n setPreference(nextPreference);\n setSaving(true);\n\n try {\n setPreference(\n await updateNotificationPreference({\n emailDigestMode: nextPreference.emailDigestMode,\n emailEnabled: nextPreference.emailEnabled,\n inAppEnabled: nextPreference.inAppEnabled,\n memberId: currentMemberId,\n quietHoursEnd: nextPreference.quietHoursEnd,\n quietHoursStart: nextPreference.quietHoursStart,\n }),\n );\n } catch (requestError: unknown) {\n setPreference(previousPreference);\n setError(readErrorMessage(requestError));\n } finally {\n setSaving(false);\n }\n }\n\n const controlsDisabled = loading || saving;\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"調整站內通知、Email 通知與摘要頻率。\"\n title=\"通知設定\"\n />\n </PageHeader>\n\n <SectionGroup>\n <Section\n filterArea={\n <FilterArea className={styles.preferenceFilter} isDirty={false}>\n <FilterLine>\n <Filter minWidth={160} span={1}>\n <FormField\n layout={FormFieldLayout.VERTICAL}\n name=\"inAppEnabled\"\n style={FILTER_FIELD_STYLE}\n >\n <div className={styles.segmentFilterControl}>\n <span className={styles.segmentFilterLabel}>\n 站內通知\n </span>\n <RadioGroup\n disabled={controlsDisabled}\n name=\"inAppEnabled\"\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n void handlePreferenceChange({\n ...preference,\n inAppEnabled: readEnabledSegmentValue(\n event.target.value,\n ),\n });\n }}\n options={[...ENABLED_SEGMENT_OPTIONS]}\n size=\"sub\"\n type=\"segment\"\n value={readEnabledSegmentValueId(\n preference.inAppEnabled,\n )}\n />\n </div>\n </FormField>\n </Filter>\n <Filter minWidth={180} span={1}>\n <FormField\n layout={FormFieldLayout.VERTICAL}\n name=\"emailEnabled\"\n style={FILTER_FIELD_STYLE}\n >\n <div className={styles.segmentFilterControl}>\n <span className={styles.segmentFilterLabel}>\n Email 通知\n </span>\n <RadioGroup\n disabled={controlsDisabled}\n name=\"emailEnabled\"\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n void handlePreferenceChange({\n ...preference,\n emailEnabled: readEnabledSegmentValue(\n event.target.value,\n ),\n });\n }}\n options={[...ENABLED_SEGMENT_OPTIONS]}\n size=\"sub\"\n type=\"segment\"\n value={readEnabledSegmentValueId(\n preference.emailEnabled,\n )}\n />\n </div>\n </FormField>\n </Filter>\n <Filter minWidth={280} span={2}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"emailDigestMode\"\n style={FILTER_FIELD_STYLE}\n >\n <div className={styles.segmentFilterControl}>\n <span className={styles.segmentFilterLabel}>\n Email 頻率\n </span>\n <RadioGroup\n disabled={controlsDisabled}\n name=\"emailDigestMode\"\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n void handlePreferenceChange({\n ...preference,\n emailDigestMode: readDigestMode(\n event.target.value,\n ),\n });\n }}\n options={[...DIGEST_OPTIONS]}\n size=\"sub\"\n type=\"segment\"\n value={preference.emailDigestMode}\n />\n </div>\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n }\n >\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n 偏好設定會立即生效。\n </Typography>\n )}\n </Section>\n </SectionGroup>\n </>\n );\n}\n\nconst FILTER_FIELD_STYLE = {\n minWidth: 0,\n whiteSpace: 'nowrap',\n} satisfies CSSProperties;\n\nfunction readDigestMode(value: unknown): NotificationDigestMode {\n return value === 'DAILY' ? 'DAILY' : 'INSTANT';\n}\n\nfunction readEnabledSegmentValue(value: unknown): boolean {\n return value !== 'OFF';\n}\n\nfunction readEnabledSegmentValueId(enabled: boolean): EnabledSegmentValue {\n return enabled ? 'ON' : 'OFF';\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { n as e } from "./auth-provider-
|
|
2
|
+
import { n as e } from "./auth-provider-C2b-5mGt.js";
|
|
3
3
|
import { useEffect as t, useState as n } from "react";
|
|
4
4
|
import { Filter as r, FilterArea as i, FilterLine as a, FormField as o, PageHeader as s, RadioGroup as c, Section as l, SectionGroup as u, Typography as d } from "@mezzanine-ui/react";
|
|
5
5
|
import { Fragment as f, jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
@@ -187,7 +187,6 @@ function D(e) {
|
|
|
187
187
|
function O(e) {
|
|
188
188
|
return e instanceof Error ? e.message : "發生未知錯誤";
|
|
189
189
|
}
|
|
190
|
-
//#endregion
|
|
191
190
|
export { C as t };
|
|
192
191
|
|
|
193
|
-
//# sourceMappingURL=notifications-
|
|
192
|
+
//# sourceMappingURL=notifications-Cvme5Qbl.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notifications-DJ5wzCye.js","names":["_Fragment","styles","useAuth","Fragment$1","ContentHeader","notification_settings_module_default","DIGEST_OPTIONS","ENABLED_SEGMENT_OPTIONS","DEFAULT_PREFERENCE","SettingsNotificationsView","currentMemberId","member","preference","setPreference","useState","loading","setLoading","saving","setSaving","error","setError","readNotificationPreference","nextPreference","readErrorMessage","requestError","handlePreferenceChange","previousPreference","updateNotificationPreference","controlsDisabled","PageHeader","SectionGroup","Section","FilterArea","FilterLine","Filter","FormField","FormFieldLayout","FILTER_FIELD_STYLE","RadioGroup","readEnabledSegmentValue","event","readEnabledSegmentValueId","readDigestMode","Typography","value","enabled"],"sources":["../../src/views/settings/notifications/notification-settings.module.scss","../../src/views/settings/notifications/SettingsNotificationsView.tsx"],"sourcesContent":[".preferenceFilter {\n :global(.mzn-filter-area__actions) {\n display: none;\n }\n\n :global(.mzn-form-field__label-area) {\n display: none;\n }\n\n :global(.mzn-form-field__control-field-slot--main) {\n width: 100%;\n min-width: 0;\n }\n}\n\n.segmentFilterControl {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n min-width: 0;\n white-space: nowrap;\n\n :global(.mzn-input-check-group--segmented) {\n align-self: flex-start;\n transform: translateY(-7px);\n }\n}\n\n.segmentFilterLabel {\n flex: 0 0 auto;\n color: var(--mzn-color-text-primary, #1f2937);\n font-size: 13px;\n line-height: 16px;\n}\n","'use client';\n\nimport {\n ChangeEvent,\n CSSProperties,\n ReactElement,\n useEffect,\n useState,\n} from 'react';\nimport {\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n PageHeader,\n RadioGroup,\n Section,\n SectionGroup,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport { useAuth } from '../../../lib/auth-provider';\nimport {\n NotificationDigestMode,\n NotificationPreferenceRecord,\n readNotificationPreference,\n updateNotificationPreference,\n} from '@rytass/bpm-core-client/workflow';\nimport styles from './notification-settings.module.scss';\n\ninterface DigestOption {\n readonly id: NotificationDigestMode;\n readonly name: string;\n}\n\ntype EnabledSegmentValue = 'OFF' | 'ON';\n\ninterface EnabledSegmentOption {\n readonly id: EnabledSegmentValue;\n readonly name: string;\n}\n\nconst DIGEST_OPTIONS: readonly DigestOption[] = [\n { id: 'INSTANT', name: '即時通知' },\n { id: 'DAILY', name: '每日摘要' },\n];\n\nconst ENABLED_SEGMENT_OPTIONS: readonly EnabledSegmentOption[] = [\n { id: 'ON', name: '開' },\n { id: 'OFF', name: '關' },\n];\n\nconst DEFAULT_PREFERENCE: NotificationPreferenceRecord = {\n emailDigestMode: 'INSTANT',\n emailEnabled: true,\n inAppEnabled: true,\n memberId: '',\n quietHoursEnd: null,\n quietHoursStart: null,\n updatedAt: '',\n};\n\n\nexport function SettingsNotificationsView(): ReactElement {\n const { member } = useAuth();\n const currentMemberId = member?.memberId ?? null;\n const [preference, setPreference] =\n useState<NotificationPreferenceRecord>(DEFAULT_PREFERENCE);\n const [loading, setLoading] = useState(true);\n const [saving, setSaving] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect((): void => {\n if (!currentMemberId) {\n return;\n }\n\n setLoading(true);\n setError(null);\n\n readNotificationPreference(currentMemberId)\n .then((nextPreference): void => {\n setPreference(nextPreference);\n })\n .catch((requestError: unknown): void => {\n setError(readErrorMessage(requestError));\n })\n .finally((): void => {\n setLoading(false);\n });\n }, [currentMemberId]);\n\n async function handlePreferenceChange(\n nextPreference: NotificationPreferenceRecord,\n ): Promise<void> {\n if (!currentMemberId || saving) {\n return;\n }\n\n const previousPreference = preference;\n setPreference(nextPreference);\n setSaving(true);\n\n try {\n setPreference(\n await updateNotificationPreference({\n emailDigestMode: nextPreference.emailDigestMode,\n emailEnabled: nextPreference.emailEnabled,\n inAppEnabled: nextPreference.inAppEnabled,\n memberId: currentMemberId,\n quietHoursEnd: nextPreference.quietHoursEnd,\n quietHoursStart: nextPreference.quietHoursStart,\n }),\n );\n } catch (requestError: unknown) {\n setPreference(previousPreference);\n setError(readErrorMessage(requestError));\n } finally {\n setSaving(false);\n }\n }\n\n const controlsDisabled = loading || saving;\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"調整站內通知、Email 通知與摘要頻率。\"\n title=\"通知設定\"\n />\n </PageHeader>\n\n <SectionGroup>\n <Section\n filterArea={\n <FilterArea className={styles.preferenceFilter} isDirty={false}>\n <FilterLine>\n <Filter minWidth={160} span={1}>\n <FormField\n layout={FormFieldLayout.VERTICAL}\n name=\"inAppEnabled\"\n style={FILTER_FIELD_STYLE}\n >\n <div className={styles.segmentFilterControl}>\n <span className={styles.segmentFilterLabel}>\n 站內通知\n </span>\n <RadioGroup\n disabled={controlsDisabled}\n name=\"inAppEnabled\"\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n void handlePreferenceChange({\n ...preference,\n inAppEnabled: readEnabledSegmentValue(\n event.target.value,\n ),\n });\n }}\n options={[...ENABLED_SEGMENT_OPTIONS]}\n size=\"sub\"\n type=\"segment\"\n value={readEnabledSegmentValueId(\n preference.inAppEnabled,\n )}\n />\n </div>\n </FormField>\n </Filter>\n <Filter minWidth={180} span={1}>\n <FormField\n layout={FormFieldLayout.VERTICAL}\n name=\"emailEnabled\"\n style={FILTER_FIELD_STYLE}\n >\n <div className={styles.segmentFilterControl}>\n <span className={styles.segmentFilterLabel}>\n Email 通知\n </span>\n <RadioGroup\n disabled={controlsDisabled}\n name=\"emailEnabled\"\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n void handlePreferenceChange({\n ...preference,\n emailEnabled: readEnabledSegmentValue(\n event.target.value,\n ),\n });\n }}\n options={[...ENABLED_SEGMENT_OPTIONS]}\n size=\"sub\"\n type=\"segment\"\n value={readEnabledSegmentValueId(\n preference.emailEnabled,\n )}\n />\n </div>\n </FormField>\n </Filter>\n <Filter minWidth={280} span={2}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"emailDigestMode\"\n style={FILTER_FIELD_STYLE}\n >\n <div className={styles.segmentFilterControl}>\n <span className={styles.segmentFilterLabel}>\n Email 頻率\n </span>\n <RadioGroup\n disabled={controlsDisabled}\n name=\"emailDigestMode\"\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n void handlePreferenceChange({\n ...preference,\n emailDigestMode: readDigestMode(\n event.target.value,\n ),\n });\n }}\n options={[...DIGEST_OPTIONS]}\n size=\"sub\"\n type=\"segment\"\n value={preference.emailDigestMode}\n />\n </div>\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n }\n >\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n 偏好設定會立即生效。\n </Typography>\n )}\n </Section>\n </SectionGroup>\n </>\n );\n}\n\nconst FILTER_FIELD_STYLE = {\n minWidth: 0,\n whiteSpace: 'nowrap',\n} satisfies CSSProperties;\n\nfunction readDigestMode(value: unknown): NotificationDigestMode {\n return value === 'DAILY' ? 'DAILY' : 'INSTANT';\n}\n\nfunction readEnabledSegmentValue(value: unknown): boolean {\n return value !== 'OFF';\n}\n\nfunction readEnabledSegmentValueId(enabled: boolean): EnabledSegmentValue {\n return enabled ? 'ON' : 'OFF';\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"notifications-Cvme5Qbl.js","names":["_Fragment","styles","useAuth","Fragment$1","ContentHeader","notification_settings_module_default","DIGEST_OPTIONS","ENABLED_SEGMENT_OPTIONS","DEFAULT_PREFERENCE","SettingsNotificationsView","currentMemberId","member","preference","setPreference","useState","loading","setLoading","saving","setSaving","error","setError","readNotificationPreference","nextPreference","readErrorMessage","requestError","handlePreferenceChange","previousPreference","updateNotificationPreference","controlsDisabled","PageHeader","SectionGroup","Section","FilterArea","FilterLine","Filter","FormField","FormFieldLayout","FILTER_FIELD_STYLE","RadioGroup","readEnabledSegmentValue","event","readEnabledSegmentValueId","readDigestMode","Typography","value","enabled"],"sources":["../../src/views/settings/notifications/notification-settings.module.scss","../../src/views/settings/notifications/SettingsNotificationsView.tsx"],"sourcesContent":[".preferenceFilter {\n :global(.mzn-filter-area__actions) {\n display: none;\n }\n\n :global(.mzn-form-field__label-area) {\n display: none;\n }\n\n :global(.mzn-form-field__control-field-slot--main) {\n width: 100%;\n min-width: 0;\n }\n}\n\n.segmentFilterControl {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n min-width: 0;\n white-space: nowrap;\n\n :global(.mzn-input-check-group--segmented) {\n align-self: flex-start;\n transform: translateY(-7px);\n }\n}\n\n.segmentFilterLabel {\n flex: 0 0 auto;\n color: var(--mzn-color-text-primary, #1f2937);\n font-size: 13px;\n line-height: 16px;\n}\n","'use client';\n\nimport {\n ChangeEvent,\n CSSProperties,\n ReactElement,\n useEffect,\n useState,\n} from 'react';\nimport {\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n PageHeader,\n RadioGroup,\n Section,\n SectionGroup,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport { useAuth } from '../../../lib/auth-provider';\nimport {\n NotificationDigestMode,\n NotificationPreferenceRecord,\n readNotificationPreference,\n updateNotificationPreference,\n} from '@rytass/bpm-core-client/workflow';\nimport styles from './notification-settings.module.scss';\n\ninterface DigestOption {\n readonly id: NotificationDigestMode;\n readonly name: string;\n}\n\ntype EnabledSegmentValue = 'OFF' | 'ON';\n\ninterface EnabledSegmentOption {\n readonly id: EnabledSegmentValue;\n readonly name: string;\n}\n\nconst DIGEST_OPTIONS: readonly DigestOption[] = [\n { id: 'INSTANT', name: '即時通知' },\n { id: 'DAILY', name: '每日摘要' },\n];\n\nconst ENABLED_SEGMENT_OPTIONS: readonly EnabledSegmentOption[] = [\n { id: 'ON', name: '開' },\n { id: 'OFF', name: '關' },\n];\n\nconst DEFAULT_PREFERENCE: NotificationPreferenceRecord = {\n emailDigestMode: 'INSTANT',\n emailEnabled: true,\n inAppEnabled: true,\n memberId: '',\n quietHoursEnd: null,\n quietHoursStart: null,\n updatedAt: '',\n};\n\n\nexport function SettingsNotificationsView(): ReactElement {\n const { member } = useAuth();\n const currentMemberId = member?.memberId ?? null;\n const [preference, setPreference] =\n useState<NotificationPreferenceRecord>(DEFAULT_PREFERENCE);\n const [loading, setLoading] = useState(true);\n const [saving, setSaving] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect((): void => {\n if (!currentMemberId) {\n return;\n }\n\n setLoading(true);\n setError(null);\n\n readNotificationPreference(currentMemberId)\n .then((nextPreference): void => {\n setPreference(nextPreference);\n })\n .catch((requestError: unknown): void => {\n setError(readErrorMessage(requestError));\n })\n .finally((): void => {\n setLoading(false);\n });\n }, [currentMemberId]);\n\n async function handlePreferenceChange(\n nextPreference: NotificationPreferenceRecord,\n ): Promise<void> {\n if (!currentMemberId || saving) {\n return;\n }\n\n const previousPreference = preference;\n setPreference(nextPreference);\n setSaving(true);\n\n try {\n setPreference(\n await updateNotificationPreference({\n emailDigestMode: nextPreference.emailDigestMode,\n emailEnabled: nextPreference.emailEnabled,\n inAppEnabled: nextPreference.inAppEnabled,\n memberId: currentMemberId,\n quietHoursEnd: nextPreference.quietHoursEnd,\n quietHoursStart: nextPreference.quietHoursStart,\n }),\n );\n } catch (requestError: unknown) {\n setPreference(previousPreference);\n setError(readErrorMessage(requestError));\n } finally {\n setSaving(false);\n }\n }\n\n const controlsDisabled = loading || saving;\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"調整站內通知、Email 通知與摘要頻率。\"\n title=\"通知設定\"\n />\n </PageHeader>\n\n <SectionGroup>\n <Section\n filterArea={\n <FilterArea className={styles.preferenceFilter} isDirty={false}>\n <FilterLine>\n <Filter minWidth={160} span={1}>\n <FormField\n layout={FormFieldLayout.VERTICAL}\n name=\"inAppEnabled\"\n style={FILTER_FIELD_STYLE}\n >\n <div className={styles.segmentFilterControl}>\n <span className={styles.segmentFilterLabel}>\n 站內通知\n </span>\n <RadioGroup\n disabled={controlsDisabled}\n name=\"inAppEnabled\"\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n void handlePreferenceChange({\n ...preference,\n inAppEnabled: readEnabledSegmentValue(\n event.target.value,\n ),\n });\n }}\n options={[...ENABLED_SEGMENT_OPTIONS]}\n size=\"sub\"\n type=\"segment\"\n value={readEnabledSegmentValueId(\n preference.inAppEnabled,\n )}\n />\n </div>\n </FormField>\n </Filter>\n <Filter minWidth={180} span={1}>\n <FormField\n layout={FormFieldLayout.VERTICAL}\n name=\"emailEnabled\"\n style={FILTER_FIELD_STYLE}\n >\n <div className={styles.segmentFilterControl}>\n <span className={styles.segmentFilterLabel}>\n Email 通知\n </span>\n <RadioGroup\n disabled={controlsDisabled}\n name=\"emailEnabled\"\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n void handlePreferenceChange({\n ...preference,\n emailEnabled: readEnabledSegmentValue(\n event.target.value,\n ),\n });\n }}\n options={[...ENABLED_SEGMENT_OPTIONS]}\n size=\"sub\"\n type=\"segment\"\n value={readEnabledSegmentValueId(\n preference.emailEnabled,\n )}\n />\n </div>\n </FormField>\n </Filter>\n <Filter minWidth={280} span={2}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"emailDigestMode\"\n style={FILTER_FIELD_STYLE}\n >\n <div className={styles.segmentFilterControl}>\n <span className={styles.segmentFilterLabel}>\n Email 頻率\n </span>\n <RadioGroup\n disabled={controlsDisabled}\n name=\"emailDigestMode\"\n onChange={(\n event: ChangeEvent<HTMLInputElement>,\n ): void => {\n void handlePreferenceChange({\n ...preference,\n emailDigestMode: readDigestMode(\n event.target.value,\n ),\n });\n }}\n options={[...DIGEST_OPTIONS]}\n size=\"sub\"\n type=\"segment\"\n value={preference.emailDigestMode}\n />\n </div>\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n }\n >\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : (\n <Typography color=\"text-neutral\" variant=\"body\">\n 偏好設定會立即生效。\n </Typography>\n )}\n </Section>\n </SectionGroup>\n </>\n );\n}\n\nconst FILTER_FIELD_STYLE = {\n minWidth: 0,\n whiteSpace: 'nowrap',\n} satisfies CSSProperties;\n\nfunction readDigestMode(value: unknown): NotificationDigestMode {\n return value === 'DAILY' ? 'DAILY' : 'INSTANT';\n}\n\nfunction readEnabledSegmentValue(value: unknown): boolean {\n return value !== 'OFF';\n}\n\nfunction readEnabledSegmentValueId(enabled: boolean): EnabledSegmentValue {\n return enabled ? 'ON' : 'OFF';\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '發生未知錯誤';\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";require('../style.css');require('../orgs.css');const e=require("./rolldown-runtime-BocRIvOZ.cjs"),t=require("./bpm-form-field-Bc6k4ZEO.cjs"),n=require("./admin-pickers-BjbkBpSJ.cjs");;/* empty css */const r=require("./format-member-label-t7ANTF62.cjs");let i=require("react"),a=require("@mezzanine-ui/react"),o=require("@rytass/bpm-core-client"),s=require("react/jsx-runtime"),c=require("@mezzanine-ui/core/form"),l=require("@mezzanine-ui/react/ContentHeader");l=e.t(l,1);let u=require("@mezzanine-ui/icons"),d=require("@rytass/bpm-core-client/organization"),f=require("@xyflow/react"),p=require("dagre");p=e.t(p,1);function m(e){return new Map(e.map(e=>[e.id,e.parentId]))}function h({orgUnitId:e,parentDraft:t,parentId:n}){let r=n===e?e:n,i=_({orgUnitId:e,parentDraft:t,parentId:r});if(i)return{message:i,parentDraft:t,status:`INVALID`};if((t.get(e)??null)===r)return{message:`父子關係沒有變更。`,parentDraft:t,status:`UNCHANGED`};let a=new Map(t);return a.set(e,r),{message:r?`已暫存新的上層組織。`:`已暫存為根節點。`,parentDraft:a,status:`UPDATED`}}function g({orgUnits:e,parentDraft:t}){return e.map(e=>{let n=t.get(e.id)??null;return n===e.parentId?null:{orgUnitId:e.id,parentId:n,previousParentId:e.parentId}}).filter(e=>!!e)}function _({orgUnitId:e,parentDraft:t,parentId:n}){return t.has(e)?n?t.has(n)?n===e?`組織不可成為自己的上層。`:v({orgUnitId:e,parentDraft:t,parentId:n})?`不可搬移到自己的下層組織。`:null:`找不到新的上層組織。`:null:`找不到要搬移的組織節點。`}function v({orgUnitId:e,parentDraft:t,parentId:n}){let r=new Set,i=n;for(;i;){if(i===e||r.has(i))return!0;r.add(i),i=t.get(i)??null}return!1}var y={orgTreeEditor:`bpm_orgTreeEditor_TMOtD`,orgTreeSummary:`bpm_orgTreeSummary_vpcV8`,orgTreeChangeList:`bpm_orgTreeChangeList_EzmOv`,orgTreeCanvas:`bpm_orgTreeCanvas_MeD7y`,orgTreePanel:`bpm_orgTreePanel_VFZph`,orgTreeNode:`bpm_orgTreeNode_bN4FS`,orgTreeNodeRoot:`bpm_orgTreeNodeRoot_Hr2KD`,orgTreeNodeSelected:`bpm_orgTreeNodeSelected_eRwtL`,orgTreeNodeChanged:`bpm_orgTreeNodeChanged_qPJg0`,orgTreeNodeDeleted:`bpm_orgTreeNodeDeleted_Ab0cI`,orgTreeNodeHeader:`bpm_orgTreeNodeHeader_LEXl-`,orgTreeNodeBadge:`bpm_orgTreeNodeBadge_zLc7t`,orgTreeNodeActions:`bpm_orgTreeNodeActions_cMldI`},b=`__org-tree-root__`,x=232,S=118,C=232,w=86,T=320,E=1.4,D=.25,ee=.005,te=250,O=80,ne=.85,re=.7,ie=1200,k=600,A=96,j={COMPANY:`公司`,DEPARTMENT:`部門`,DIVISION:`事業群`,TEAM:`小組`},ae={orgUnit:M},oe=(0,i.forwardRef)(function({onCreateChild:e,onCreateRoot:t,onEditOrgUnit:n,onSaveDraft:r,onStateChange:o,orgUnits:c},l){let[u,d]=(0,i.useState)(!1),[p,_]=(0,i.useState)(null),[v,C]=(0,i.useState)(null),[w,T]=(0,i.useState)(()=>m(c)),[A,j]=(0,i.useState)(()=>new Set),[oe,M]=(0,i.useState)(()=>new Map),[ce,ue]=(0,i.useState)([]),N=(0,i.useRef)(null),P=(0,i.useRef)(null),F=(0,i.useCallback)(e=>{P.current=e,j(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},[]),I=(0,i.useCallback)(()=>{P.current=b,j(new Set)},[]),he=(0,i.useCallback)(()=>{P.current=b,j(()=>{let e=se(c,w);return new Set([...e.keys()].filter(e=>e!==b))})},[c,w]),L=(0,i.useMemo)(()=>new Map(c.map(e=>[e.id,e])),[c]),R=(0,i.useMemo)(()=>g({orgUnits:c,parentDraft:w}),[c,w]),z=(0,i.useMemo)(()=>le({collapsedIds:A,isEditing:u,measuredHeights:oe,onCreateChild:n=>{n?e(n):t()},onEditOrgUnit:e=>{let t=L.get(e);t&&n(t)},onToggleCollapse:F,orgUnits:c,orgUnitsById:L,parentDraft:w,selectedOrgUnitId:v}),[A,F,u,oe,e,t,n,c,L,w,v]),B=(0,i.useRef)(z);B.current=z;let V=R.length>0,H=(0,i.useMemo)(()=>{let e=Math.max(z.bounds.width,z.bounds.height);return e<=0?D:Math.min(D,Math.max(ee,te/e))},[z.bounds.height,z.bounds.width]),U=c.length<=O,W=(0,i.useCallback)(()=>{let e=N.current;if(!e)return;let{bounds:t,rootCenter:n}=B.current,r=t.width>0?ie/t.width:1/0,i=t.height>0?k/t.height:1/0,a=Math.min(r,i);if(!Number.isFinite(a)||a>=re){e.fitView({padding:.18});return}let o=k/(2*ne);e.setCenter(n.x,Math.min(t.height/2,o),{duration:0,zoom:ne})},[]),ge=(0,i.useCallback)(e=>{N.current=e,W()},[W]);(0,i.useImperativeHandle)(l,()=>({cancelEditing:be,saveDraft:xe,startEditing:ye})),(0,i.useEffect)(()=>{o({hasDraftChanges:V,isEditing:u})},[V,u,o]),(0,i.useEffect)(()=>{let e=m(c);T(e),j(new Set),M(new Map),C(null),_(null),d(!1)},[c]),(0,i.useEffect)(()=>{ue(z.nodes)},[z.nodes]),(0,i.useEffect)(()=>{if(typeof window>`u`)return()=>void 0;let e=window.requestAnimationFrame(()=>{W()});return()=>window.cancelAnimationFrame(e)},[W,c]),(0,i.useEffect)(()=>{let e=P.current;if(!e)return;P.current=null;let t=N.current,n=z.nodes.find(t=>t.id===e);t&&n&&t.setCenter(n.position.x+(n.width??x)/2,n.position.y+(n.initialHeight??S)/2,{duration:200,zoom:t.getZoom()})},[z.nodes]);let G=(0,i.useCallback)((e,t)=>{T(n=>{let r=h({orgUnitId:e,parentDraft:n,parentId:t});return _(r.message),r.parentDraft})},[]),_e=(0,i.useCallback)(e=>{if(!u||!e.target||!e.source)return;let t=e.source===b?null:e.source;e.target===b?_(`根節點不能搬移到其他節點下。`):G(e.target,t)},[G,u]),K=(0,i.useCallback)(e=>{let t=e.filter(e=>e.type===`dimensions`&&e.dimensions);t.length>0&&M(e=>{let n=new Map(e);return t.reduce((e,t)=>{if(t.type!==`dimensions`||!t.dimensions)return e;let r=Math.ceil(t.dimensions.height);return Math.abs((n.get(t.id)??0)-r)<=1?e:(n.set(t.id,r),!0)},!1)?n:e}),u&&ue(t=>(0,f.applyNodeChanges)(e,[...t]))},[u]),ve=(0,i.useCallback)((e,t,n)=>{if(!u||t.id===b)return;let r=fe(e,t.id)??de(t,n);r===void 0?_(`拖曳到目標父節點附近,或從父節點拉線到子節點。`):G(t.id,r===b?null:r)},[G,u]);function ye(){d(!0),T(m(c)),_(`已進入編輯模式,拖曳節點或拉線只會更新前端草稿。`)}function be(){d(!1),T(m(c)),_(`已取消草稿變更。`)}async function xe(){r?(await r(R),d(!1),_(`組織樹草稿已儲存。`)):_(`批次儲存 API 尚未接上,草稿仍保留在前端。`)}return(0,s.jsxs)(`div`,{className:y.orgTreeEditor,children:[(0,s.jsxs)(`div`,{className:y.orgTreeSummary,children:[(0,s.jsx)(a.Typography,{color:`text-neutral`,variant:`caption`,children:p??(V?`目前有 ${R.length} 筆父子關係草稿變更。`:`目前沒有草稿變更。`)}),V?(0,s.jsx)(`ul`,{className:y.orgTreeChangeList,children:R.map(e=>(0,s.jsxs)(`li`,{children:[me(e.orgUnitId,L),`:`,me(e.previousParentId,L),` -> `,me(e.parentId,L)]},e.orgUnitId))}):null]}),(0,s.jsx)(`div`,{className:y.orgTreeCanvas,children:(0,s.jsxs)(f.ReactFlow,{connectionMode:f.ConnectionMode.Strict,edges:[...z.edges],fitViewOptions:{minZoom:H,padding:.18},isValidConnection:e=>pe({source:e.source,target:e.target},w),maxZoom:E,minZoom:H,nodeTypes:ae,nodes:[...ce],nodesConnectable:u,nodesDraggable:u,onConnect:_e,onInit:ge,onNodeClick:(e,t)=>{C(t.id===b?null:t.id)},onNodeDoubleClick:(e,t)=>{if(t.id!==b){let e=L.get(t.id);e&&n(e)}},onNodeDragStop:ve,onNodesChange:K,onPaneClick:()=>C(null),panOnDrag:!0,proOptions:{hideAttribution:!0},children:[(0,s.jsx)(f.Background,{}),(0,s.jsx)(f.Controls,{}),(0,s.jsxs)(f.Panel,{className:`${y.orgTreePanel} nopan nodrag`,position:`top-right`,children:[(0,s.jsx)(a.Button,{onClick:I,size:`sub`,variant:`base-secondary`,children:`全部展開`}),(0,s.jsx)(a.Button,{onClick:he,size:`sub`,variant:`base-secondary`,children:`全部收合`})]}),U?(0,s.jsx)(f.MiniMap,{pannable:!0,zoomable:!0}):null]})})]})});function M({data:e,selected:t}){return(0,s.jsxs)(`div`,{className:[y.orgTreeNode,e.isSyntheticRoot?y.orgTreeNodeRoot:``,e.changed?y.orgTreeNodeChanged:``,e.deleted?y.orgTreeNodeDeleted:``,t?y.orgTreeNodeSelected:``].filter(Boolean).join(` `),children:[e.isSyntheticRoot?null:(0,s.jsx)(f.Handle,{id:`target`,isConnectable:e.isEditing,position:f.Position.Top,type:`target`}),(0,s.jsx)(f.Handle,{id:`source`,isConnectable:e.isEditing,position:f.Position.Bottom,type:`source`}),(0,s.jsxs)(`div`,{className:y.orgTreeNodeHeader,children:[(0,s.jsx)(a.Typography,{component:`span`,ellipsis:!0,title:e.name,variant:`label-primary`,children:e.name}),e.changed?(0,s.jsx)(`span`,{className:y.orgTreeNodeBadge,children:`草稿`}):null]}),(0,s.jsx)(a.Typography,{color:`text-neutral`,component:`span`,ellipsis:!0,title:e.code,variant:`caption`,children:e.isSyntheticRoot?`根節點容器`:`${e.typeLabel} · ${e.code}`}),e.isSyntheticRoot?null:(0,s.jsxs)(a.Typography,{color:`text-neutral`,component:`span`,ellipsis:!0,title:e.parentLabel,variant:`caption`,children:[`上層:`,e.parentLabel]}),(0,s.jsxs)(`div`,{className:`${y.orgTreeNodeActions} nodrag nopan`,children:[e.childCount>0?(0,s.jsx)(a.Button,{onClick:t=>{t.stopPropagation(),e.onToggleCollapse(e.orgUnitId??b)},size:`sub`,variant:`base-secondary`,children:e.collapsed?`展開 (${e.childCount})`:`收合 (${e.childCount})`}):null,e.isSyntheticRoot?(0,s.jsx)(a.Button,{icon:u.PlusIcon,iconType:`leading`,onClick:()=>e.onCreateChild(null),size:`sub`,variant:`base-secondary`,children:`新增根節點`}):(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(a.Button,{icon:u.EditIcon,iconType:`leading`,onClick:()=>{e.orgUnitId&&e.onEdit(e.orgUnitId)},size:`sub`,variant:`base-secondary`,children:`編輯`}),(0,s.jsx)(a.Button,{icon:u.PlusIcon,iconType:`leading`,onClick:()=>e.onCreateChild(e.orgUnitId),size:`sub`,variant:`base-secondary`,children:`新增子節點`})]})]})]})}function se(e,t){let n=new Map;return e.forEach(e=>{let r=t.get(e.id)??b;n.set(r,[...n.get(r)??[],e.id])}),n}function ce({childrenMap:e,collapsedIds:t}){let n=new Set,r=i=>{t.has(i)||(e.get(i)??[]).forEach(e=>{n.add(e),r(e)})};return r(b),n}function le({collapsedIds:e,isEditing:t,measuredHeights:n,onCreateChild:r,onEditOrgUnit:i,onToggleCollapse:a,orgUnits:o,orgUnitsById:s,parentDraft:c,selectedOrgUnitId:l}){let u=se(o,c),d=ce({childrenMap:u,collapsedIds:e}),f=o.filter(e=>d.has(e.id)),m=e=>u.get(e)?.length??0,h=(e,t)=>Math.max(t,n.get(e)??0),g=new p.graphlib.Graph;g.setDefaultEdgeLabel(()=>({})),g.setGraph({marginx:36,marginy:36,nodesep:44,rankdir:`TB`,ranksep:A}),g.setNode(b,{height:h(b,w),width:C}),f.forEach(e=>{g.setNode(e.id,{height:h(e.id,S),width:x})}),f.forEach(e=>{let t=c.get(e.id)??null;g.setEdge(t??b,e.id)}),p.layout(g);let _=g.graph(),v={height:_.height??0,width:_.width??0},y=g.node(b),T={x:v.width>0?v.width/2:y?.x??0,y:y?.y??0},E={...ue({data:{changed:!1,childCount:m(b),code:b,collapsed:e.has(b),deleted:!1,isEditing:t,isSyntheticRoot:!0,name:`組織根節點`,onCreateChild:r,onEdit:i,onToggleCollapse:a,orgUnitId:null,parentLabel:``,path:``,typeLabel:``},graph:g,height:h(b,w),id:b,selected:l===null,width:C}),position:{x:T.x-C/2,y:T.y-h(b,w)/2}},D=f.map(n=>{let o=c.get(n.id)??null,u=me(o,s);return ue({data:{changed:o!==n.parentId,childCount:m(n.id),code:n.code,collapsed:e.has(n.id),deleted:!!n.deletedAt,isEditing:t,isSyntheticRoot:!1,name:n.name,onCreateChild:r,onEdit:i,onToggleCollapse:a,orgUnitId:n.id,parentLabel:u,path:n.path,typeLabel:he(n.type)},graph:g,height:h(n.id,S),id:n.id,selected:l===n.id,width:x})});return{bounds:v,edges:f.map(e=>{let n=c.get(e.id)??null,r=n!==e.parentId;return{animated:t&&r,data:{},id:`org-tree-edge-${n??`root`}-${e.id}`,source:n??b,sourceHandle:`source`,style:r?{stroke:`var(--mzn-color-primary, #0057ff)`,strokeWidth:2}:void 0,target:e.id,targetHandle:`target`,type:`smoothstep`}}),nodes:[E,...D],rootCenter:T}}function ue({data:e,graph:t,height:n,id:r,selected:i,width:a}){let o=t.node(r);return{data:e,id:r,initialHeight:n,initialWidth:a,position:o?{x:o.x-a/2,y:o.y-n/2}:{x:0,y:0},selected:i,sourcePosition:f.Position.Bottom,targetPosition:f.Position.Top,type:`orgUnit`,width:a}}function de(e,t){let n=F(e);return t.filter(t=>t.id!==e.id).map(e=>({distance:I(n,F(e)),id:e.id})).filter(e=>e.distance<=T).sort((e,t)=>e.distance-t.distance)[0]?.id}function fe(e,t){let n=N(e);if(n)return Array.from(document.querySelectorAll(`.react-flow__node[data-id]`)).map(e=>{let r=e.dataset.id;if(!r||r===t)return null;let i=e.getBoundingClientRect(),a={x:i.left+i.width/2,y:i.top+i.height/2};return{distance:I(n,a),id:r}}).filter(e=>!!e).filter(e=>e.distance<=T).sort((e,t)=>e.distance-t.distance)[0]?.id}function N(e){return P(e)?{x:e.clientX,y:e.clientY}:null}function P(e){return typeof e==`object`&&!!e&&`clientX`in e&&`clientY`in e&&typeof e.clientX==`number`&&typeof e.clientY==`number`}function F(e){return{x:e.position.x+(e.width??x)/2,y:e.position.y+(e.measured?.height??e.initialHeight??S)/2}}function I(e,t){return Math.hypot(e.x-t.x,e.y-t.y)}function pe(e,t){return!e.source||!e.target||e.target===b?!1:_({orgUnitId:e.target,parentDraft:t,parentId:e.source===b?null:e.source})===null}function me(e,t){if(!e)return`根節點`;let n=t.get(e);return n?`${n.name} · ${n.code}`:`未知組織`}function he(e){return j[e.toUpperCase()]??`未知類型`}var L={tableIntroActions:`bpm_tableIntroActions_WO4XU`,modalFields:`bpm_modalFields_juyv6`,tableIntro:`bpm_tableIntro_u3hcm`,tableFrame:`bpm_tableFrame_IdbmB`,orgFilterArea:`bpm_orgFilterArea_Xjbbp`,membershipFilterArea:`bpm_membershipFilterArea_zob-Y`,scopeLabel:`bpm_scopeLabel_TLHMC`},R={hasDraftChanges:!1,isEditing:!1},z=100,B=[{id:`COMPANY`,name:`公司`},{id:`DIVISION`,name:`事業群`},{id:`DEPARTMENT`,name:`部門`},{id:`TEAM`,name:`小組`}],V={id:`ALL`,name:`全部類型`},H=[V,...B],U=[{id:`MEMBER`,name:`指定會員`},{id:`ORG_UNIT`,name:`指定組織`},{id:`POSITION`,name:`指定職位`}],W={id:`ALL`,name:`全部範圍`},ge=[W,...U],G={activeOnly:!1,id:`ALL`,name:`全部狀態`},_e=[G,{activeOnly:!0,id:`ACTIVE`,name:`目前有效`}],K=[{id:`true`,name:`主要歸屬`,value:!0},{id:`false`,name:`一般歸屬`,value:!1}],ve=[10,20,50],ye=1368,be=948,xe=1292,Se=1124;function Ce(){let[e,r]=(0,i.useState)(`ORG_UNITS`),[c,u]=(0,i.useState)(null),[f,p]=(0,i.useState)(null),[m,h]=(0,i.useState)(null),[g,_]=(0,i.useState)(!0),[v,y]=(0,i.useState)(null),[b,x]=(0,i.useState)(G),[S,C]=(0,i.useState)(1),[w,T]=(0,i.useState)(10),[E,D]=(0,i.useState)(W),[ee,te]=(0,i.useState)(0),[O,ne]=(0,i.useState)([]),[re,ie]=(0,i.useState)(null),[k,A]=(0,i.useState)(null),[j,ae]=(0,i.useState)(null),[oe,M]=(0,i.useState)(1),[se,ce]=(0,i.useState)(10),[le,ue]=(0,i.useState)(null),[de,fe]=(0,i.useState)(0),[N,P]=(0,i.useState)(null),[F,I]=(0,i.useState)(1),[pe,me]=(0,i.useState)(10),[he,L]=(0,i.useState)(``),[R,B]=(0,i.useState)(0),[H,U]=(0,i.useState)(V),[ge,_e]=(0,i.useState)(`TABLE`),[K,ve]=(0,i.useState)([]),[ye,be]=(0,i.useState)([]),[xe,Se]=(0,i.useState)([]),[Ce,q]=(0,i.useState)(null),[Oe,ke]=(0,i.useState)(1),[Ae,je]=(0,i.useState)(10),[J,Ie]=(0,i.useState)(``),[We,Ge]=(0,i.useState)(0),[Ke,qe]=(0,i.useState)([]),[Je,Ye]=(0,i.useState)([]),[Xe,Ze]=(0,i.useState)([]),[Y,X]=(0,i.useState)(!1),[Z,Q]=(0,i.useState)(null),[$e,et]=(0,i.useState)(null);(0,i.useEffect)(()=>{c&&p(c)},[c]),(0,i.useEffect)(()=>{let e=!1;return Q(null),et(null),c?.type===`ORG_UNIT`&&(0,d.readOrgUnitRetirementImpact)(c.id).then(t=>{e||Q(t)}).catch(t=>{e||h(nt(t))}),()=>{e=!0}},[c]);let tt=c?.type===`ORG_UNIT`,rt=tt&&Z!==null&&(Z.openMembershipCount>0||Z.openManagerResolutionCount>0),it=tt&&(Z===null||Z.childUnitCount>0||rt&&!$e),at=c??f,ot=(0,i.useCallback)(async()=>{_(!0),h(null);try{let e=await(0,d.readOrganizationDashboard)({managerActiveOnly:b.activeOnly,managerPage:S,managerPageSize:w,managerScopeType:E.id===`ALL`?null:E.id,membershipActiveOnly:re?.activeOnly??!1,membershipOrgUnitId:j?.id??null,membershipPage:oe,membershipPageSize:se,membershipPositionId:le?.id??null,orgUnitPage:F,orgUnitPageSize:pe,orgUnitSearchText:he,orgUnitType:H.id===`ALL`?null:H.id,positionPage:Oe,positionPageSize:Ae,positionSearchText:J}),t=Le(e.memberships,e.managerResolutions),n=await(0,o.resolveMembers)(t);ne(n),ve(e.orgUnits),B(e.orgUnitCount),be(e.filteredOrgUnits),qe(e.positions),Ge(e.positionCount),Se(e.filteredPositions),fe(e.membershipCount),Ze(e.filteredMemberships),te(e.managerResolutionCount),Ye(e.filteredManagerResolutions)}catch(e){h(nt(e))}finally{_(!1)}},[b,S,w,E,re,j,oe,se,le,F,pe,he,H,Oe,Ae,J]);(0,i.useEffect)(()=>{ot()},[ot]);let $=(0,i.useMemo)(()=>new Map(K.map(e=>[e.id,e])),[K]),st=(0,i.useMemo)(()=>new Map(Ke.map(e=>[e.id,e])),[Ke]),ct=(0,i.useMemo)(()=>new Map(O.map(e=>[e.memberId,e])),[O]),lt=(0,i.useMemo)(()=>ye.map(e=>({...e,key:e.id,parentName:e.parentId?Be($.get(e.parentId)):`根節點`,typeLabel:Ve(e.type)})),[ye,$]),ut=(0,i.useMemo)(()=>xe.map(e=>({...e,key:e.id})),[xe]),dt=(0,i.useMemo)(()=>Xe.map(e=>({...e,key:e.id,memberName:ze(ct.get(e.memberId)),orgUnitName:Be($.get(e.orgUnitId)),positionName:e.positionId?He(st.get(e.positionId)):`未指定`})),[ct,Xe,$,st]),ft=(0,i.useMemo)(()=>Je.map(e=>({...e,key:e.id,managerName:ze(ct.get(e.managerMemberId)),scopeLabel:Re(e,{membersById:ct,orgUnitsById:$,positionsById:st})})),[Je,ct,$,st]),pt=(0,i.useMemo)(()=>({render:e=>[{name:`編輯`,onClick:()=>P({record:e,type:`EDIT`})},{name:`停用`,onClick:()=>u({confirmText:`停用組織`,description:`停用「${e.name}」後,這個組織節點將不再出現在可用組織清單中。`,id:e.id,title:`停用組織節點`,type:`ORG_UNIT`}),variant:`destructive-secondary`}],variant:`base-secondary`,width:128}),[]),mt=(0,i.useMemo)(()=>({render:e=>[{name:`編輯`,onClick:()=>q({record:e,type:`EDIT`})},{name:`刪除`,onClick:()=>u({confirmText:`刪除職位`,description:`刪除職位「${e.name}」。若仍有會員歸屬、主管解析規則、簽核範本或進行中單據的加簽對象引用它,系統會拒絕刪除並說明原因。`,id:e.id,title:`刪除職位`,type:`POSITION`}),variant:`destructive-secondary`}],variant:`base-secondary`,width:128}),[]),ht=(0,i.useMemo)(()=>({render:e=>[{name:`編輯`,onClick:()=>A({record:e,type:`EDIT`})},{name:`刪除`,onClick:()=>u({confirmText:`刪除歸屬`,description:`刪除「${e.memberName}」在「${e.orgUnitName}」的會員歸屬。`,id:e.id,title:`刪除會員歸屬`,type:`MEMBERSHIP`}),variant:`destructive-secondary`}],variant:`base-secondary`,width:128}),[]),gt=(0,i.useMemo)(()=>({render:e=>[{name:`編輯`,onClick:()=>y({record:e,type:`EDIT`})},{name:`刪除`,onClick:()=>u({confirmText:`刪除主管規則`,description:`刪除「${e.scopeLabel}」指派給「${e.managerName}」的主管解析規則。`,id:e.id,title:`刪除主管解析規則`,type:`MANAGER_RESOLUTION`}),variant:`destructive-secondary`}],variant:`base-secondary`,width:128}),[]);function _t(e){I(1),L(e)}function vt(e){I(1),U(e)}function yt(e){ke(1),Ie(e)}function bt(e){M(1),ie(e)}function xt(e){M(1),ae(e)}function St(e){M(1),ue(e)}function Ct(e){C(1),x(e)}function wt(e){C(1),D(e)}function Tt(){Y||u(null)}async function Et(){c&&await Ot(async()=>{c.type===`ORG_UNIT`&&await(0,d.deleteOrgUnit)(c.id,{transferToOrgUnitId:rt?$e?.id??null:null}),c.type===`POSITION`&&await(0,d.deletePosition)(c.id),c.type===`MEMBERSHIP`&&await(0,d.deleteMembership)(c.id),c.type===`MANAGER_RESOLUTION`&&await(0,d.deleteManagerResolution)(c.id),u(null)})}async function Dt(e){X(!0),h(null);try{await(0,d.commitOrgUnitTreeDraft)({moves:e.map(e=>({baseUpdatedAt:$.get(e.orgUnitId)?.updatedAt??``,id:e.orgUnitId,parentId:e.parentId}))}),await ot()}catch(e){throw h(nt(e)),e}finally{X(!1)}}async function Ot(e){X(!0),h(null);try{await e(),await ot()}catch(e){h(nt(e))}finally{X(!1)}}return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(a.PageHeader,{children:(0,s.jsx)(l.default,{description:`維護組織樹、職位、會員歸屬與簽核主管解析規則。`,title:`組織管理`})}),(0,s.jsx)(a.SectionGroup,{children:(0,s.jsxs)(a.Section,{tab:(0,s.jsxs)(a.Tab,{activeKey:e,onChange:e=>r(Ue(e)),children:[(0,s.jsx)(a.TabItem,{children:`組織樹`},`ORG_UNITS`),(0,s.jsx)(a.TabItem,{children:`職位`},`POSITIONS`),(0,s.jsx)(a.TabItem,{children:`會員歸屬`},`MEMBERSHIPS`),(0,s.jsx)(a.TabItem,{children:`簽核主管`},`MANAGERS`)]}),children:[m?(0,s.jsx)(a.Typography,{color:`text-error`,variant:`body`,children:m}):null,e===`ORG_UNITS`?(0,s.jsx)(we,{actions:pt,loading:g,onCreate:()=>P({parentId:null,record:null,type:`CREATE`}),onCreateChild:e=>P({parentId:e,record:null,type:`CREATE`}),onEditOrgUnit:e=>P({record:e,type:`EDIT`}),onPageChange:I,onSaveDraft:Dt,onPageSizeChange:e=>{I(1),me(e)},onSearchTextChange:_t,onTypeFilterChange:vt,orgUnits:K,page:F,pageSize:pe,rows:lt,searchText:he,saving:Y,total:R,typeFilter:H,viewMode:ge,onViewModeChange:_e}):null,e===`POSITIONS`?(0,s.jsx)(Te,{actions:mt,loading:g,onCreate:()=>q({record:null,type:`CREATE`}),onPageChange:ke,onPageSizeChange:e=>{ke(1),je(e)},onSearchTextChange:yt,page:Oe,pageSize:Ae,rows:ut,searchText:J,total:We}):null,e===`MEMBERSHIPS`?(0,s.jsx)(Ee,{actions:ht,loading:g,onCreate:()=>A({record:null,type:`CREATE`}),onActiveFilterChange:bt,onOrgUnitFilterChange:xt,onPageChange:M,onPageSizeChange:e=>{M(1),ce(e)},onPositionFilterChange:St,orgUnitFilter:j,orgUnits:K,page:oe,pageSize:se,positionFilter:le,positions:Ke,rows:dt,statusFilter:re,total:de}):null,e===`MANAGERS`?(0,s.jsx)(De,{actions:gt,loading:g,onCreate:()=>y({record:null,type:`CREATE`}),onActiveFilterChange:Ct,onPageChange:C,onPageSizeChange:e=>{C(1),T(e)},onScopeTypeFilterChange:wt,page:S,pageSize:w,rows:ft,scopeTypeFilter:E,statusFilter:b,total:ee}):null]})}),(0,s.jsx)(Me,{modal:N,onClose:()=>P(null),onSubmit:e=>Ot(async()=>{N?.type===`EDIT`&&N.record?await(0,d.updateOrgUnit)({...e,id:N.record.id,metadataJson:null}):await(0,d.createOrgUnit)({code:e.code??``,metadataJson:`{}`,name:e.name??``,parentId:e.parentId,type:e.type??`DEPARTMENT`}),P(null)}),orgUnits:K,saving:Y}),(0,s.jsx)(Ne,{modal:Ce,onClose:()=>q(null),onSubmit:e=>Ot(async()=>{Ce?.type===`EDIT`&&Ce.record?await(0,d.updatePosition)({...e,id:Ce.record.id,metadataJson:null}):await(0,d.createPosition)({code:e.code??``,level:e.level??0,metadataJson:`{}`,name:e.name??``}),q(null)}),saving:Y}),(0,s.jsx)(Pe,{membersById:ct,modal:k,onClose:()=>A(null),onSubmit:e=>Ot(async()=>{k?.type===`EDIT`&&k.record?await(0,d.updateMembership)({effectiveFrom:e.effectiveFrom,effectiveTo:e.effectiveTo,id:k.record.id,isPrimary:e.isPrimary,orgUnitId:e.orgUnitId,positionId:e.positionId}):await(0,d.createMembership)({effectiveFrom:e.effectiveFrom??Qe(),effectiveTo:e.effectiveTo,isPrimary:e.isPrimary??!1,memberId:e.memberId??``,orgUnitId:e.orgUnitId??``,positionId:e.positionId}),A(null)}),orgUnits:K,positions:Ke,saving:Y}),(0,s.jsx)(Fe,{membersById:ct,modal:v,onClose:()=>y(null),onSubmit:e=>Ot(async()=>{v?.type===`EDIT`&&v.record?await(0,d.updateManagerResolution)({...e,id:v.record.id}):await(0,d.createManagerResolution)({effectiveFrom:e.effectiveFrom??Qe(),effectiveTo:e.effectiveTo,managerMemberId:e.managerMemberId??``,priority:e.priority??z,scopeId:e.scopeId??``,scopeType:e.scopeType??`MEMBER`}),y(null)}),orgUnits:K,positions:Ke,saving:Y}),(0,s.jsxs)(a.Modal,{cancelText:`取消`,confirmButtonProps:{disabled:it,variant:`destructive-primary`},confirmText:rt?`轉移並停用`:at?.confirmText??``,loading:Y,modalStatusType:`error`,modalType:`standard`,onCancel:Tt,onClose:Tt,onConfirm:()=>void Et(),open:!!c,showModalFooter:!0,showModalHeader:!0,size:`regular`,supportingText:`此操作會立即套用,請確認後再繼續。`,title:at?.title??``,children:[(0,s.jsx)(a.Typography,{color:`text-neutral`,variant:`body`,children:at?.description??``}),tt&&Z===null&&!m?(0,s.jsx)(a.Typography,{color:`text-neutral`,variant:`body`,children:`正在確認這個組織目前的歸屬與主管規則…`}):null,tt&&Z&&Z.childUnitCount>0?(0,s.jsx)(a.Typography,{color:`text-error`,variant:`body`,children:`這個組織底下還有 ${Z.childUnitCount} 個子組織,請先移動或停用子組織。`}):null,rt&&Z?(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(a.Typography,{color:`text-neutral`,variant:`body`,children:`這個組織還有 ${Z.openMembershipCount} 筆尚未結束的會員歸屬(含未來才生效的)、${Z.openManagerResolutionCount} 筆簽核主管規則。請選擇承接組織:已生效的歸屬會在昨天結束,並自今天起改掛到承接組織,保留歷史;尚未生效的歸屬直接改掛;這個組織的簽核主管規則會一併結束。`}),(0,s.jsx)(t.t,{label:`承接組織`,name:`successorOrgUnitId`,children:(0,s.jsx)(n.n,{name:`successorOrgUnitId`,onChange:et,orgUnits:K.filter(e=>e.id!==c?.id),placeholder:`選擇承接組織`,value:$e})})]}):null,m?(0,s.jsx)(a.Typography,{color:`text-error`,variant:`body`,children:m}):null]})]})}function we({actions:e,loading:t,onCreate:n,onCreateChild:r,onEditOrgUnit:o,onPageChange:l,onSaveDraft:d,onPageSizeChange:f,onSearchTextChange:p,onTypeFilterChange:m,onViewModeChange:h,orgUnits:g,page:_,pageSize:v,rows:y,searchText:b,saving:x,total:S,typeFilter:C,viewMode:w}){let T=(0,i.useRef)(null),[E,D]=(0,i.useState)(R),ee=w===`TABLE`?`FLOW`:`TABLE`,te=w===`TABLE`?`切換樹狀圖`:`切換表格`,O=w===`FLOW`,ne=Oe({isTreeMode:O,isTreeEditing:E.isEditing}),re=ke({isTreeMode:O,isTreeEditing:E.isEditing}),ie=Ae({hasDraftChanges:E.hasDraftChanges,isTreeEditing:E.isEditing,isTreeMode:O,loading:t,saving:x}),k=(0,i.useMemo)(()=>[{dataIndex:`code`,key:`code`,title:`代碼`,width:180},{dataIndex:`name`,key:`name`,title:`名稱`,width:240},{dataIndex:`typeLabel`,key:`typeLabel`,title:`類型`,width:120},{dataIndex:`parentName`,key:`parentName`,title:`上層`,width:280},{dataIndex:`path`,key:`path`,title:`Path`,width:420}],[]);return(0,i.useEffect)(()=>{w===`TABLE`&&D(R)},[w]),(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(je,{actionDisabled:ie,actionIcon:re,actionLabel:ne,actions:(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(a.Button,{onClick:()=>h(ee),variant:`base-secondary`,children:te}),O&&E.isEditing?(0,s.jsx)(a.Button,{disabled:x,icon:u.CloseIcon,iconType:`leading`,onClick:()=>T.current?.cancelEditing(),variant:`base-secondary`,children:`取消`}):null]}),description:`組織節點使用 ltree path 維護階層,搬移節點會同步更新子節點 path。`,onCreate:()=>{O?E.isEditing?T.current?.saveDraft():T.current?.startEditing():n()},title:`組織樹`}),w===`TABLE`?(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(a.FilterArea,{className:L.orgFilterArea,size:`sub`,children:(0,s.jsxs)(a.FilterLine,{children:[(0,s.jsx)(a.Filter,{span:3,children:(0,s.jsx)(a.FormField,{fullWidth:!0,layout:c.FormFieldLayout.VERTICAL,name:`orgUnitSearchText`,children:(0,s.jsx)(a.Input,{fullWidth:!0,onChange:e=>p(e.target.value),placeholder:`搜尋組織名稱或代碼`,size:`sub`,value:b,variant:`base`})})}),(0,s.jsx)(a.Filter,{span:2,children:(0,s.jsx)(a.FormField,{fullWidth:!0,layout:c.FormFieldLayout.VERTICAL,name:`orgUnitTypeFilter`,children:(0,s.jsx)(a.Select,{clearable:!1,fullWidth:!0,onChange:e=>m(Ge(e)),options:[...H],placeholder:`類型`,size:`sub`,value:C})})})]})}),(0,s.jsx)(`div`,{className:L.tableFrame,children:(0,s.jsx)(a.Table,{actions:e,columns:k,dataSource:[...y],fullWidth:!0,loading:t,pagination:q({onPageChange:l,onPageSizeChange:f,page:_,pageSize:v,total:S}),style:{minWidth:ye}})})]}):(0,s.jsx)(oe,{ref:T,onCreateChild:r,onCreateRoot:n,onEditOrgUnit:o,onSaveDraft:d,onStateChange:D,orgUnits:g,saving:x})]})}function Te({actions:e,loading:t,onCreate:n,onPageChange:r,onPageSizeChange:o,onSearchTextChange:l,page:u,pageSize:d,rows:f,searchText:p,total:m}){let h=(0,i.useMemo)(()=>[{dataIndex:`code`,key:`code`,title:`代碼`,width:180},{dataIndex:`name`,key:`name`,title:`名稱`,width:280},{dataIndex:`level`,key:`level`,title:`職等`,width:96},{dataIndex:`updatedAt`,key:`updatedAt`,title:`更新時間`,width:220}],[]);return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(je,{actionLabel:`新增職位`,description:`職位提供會員歸屬與主管解析規則使用。`,onCreate:n,title:`職位`}),(0,s.jsx)(a.FilterArea,{className:L.orgFilterArea,size:`sub`,children:(0,s.jsx)(a.FilterLine,{children:(0,s.jsx)(a.Filter,{span:3,children:(0,s.jsx)(a.FormField,{fullWidth:!0,layout:c.FormFieldLayout.VERTICAL,name:`positionSearchText`,children:(0,s.jsx)(a.Input,{fullWidth:!0,onChange:e=>l(e.target.value),placeholder:`搜尋職位名稱或代碼`,size:`sub`,value:p,variant:`base`})})})})}),(0,s.jsx)(`div`,{className:L.tableFrame,children:(0,s.jsx)(a.Table,{actions:e,columns:h,dataSource:[...f],fullWidth:!0,loading:t,pagination:q({onPageChange:r,onPageSizeChange:o,page:u,pageSize:d,total:m}),style:{minWidth:be}})})]})}function Ee({actions:e,loading:t,onCreate:r,onActiveFilterChange:o,onOrgUnitFilterChange:l,onPageChange:u,onPageSizeChange:d,onPositionFilterChange:f,orgUnitFilter:p,orgUnits:m,page:h,pageSize:g,positionFilter:_,positions:v,rows:y,statusFilter:b,total:x}){let S=(0,i.useMemo)(()=>[{dataIndex:`memberName`,key:`memberName`,title:`會員`,width:280},{dataIndex:`orgUnitName`,key:`orgUnitName`,title:`組織`,width:280},{dataIndex:`positionName`,key:`positionName`,title:`職位`,width:220},{key:`isPrimary`,render:e=>e.isPrimary?`主要`:`一般`,title:`類型`,width:104},{dataIndex:`effectiveFrom`,key:`effectiveFrom`,title:`生效日`,width:140},{dataIndex:`effectiveTo`,key:`effectiveTo`,title:`結束日`,width:140}],[]),C=(0,i.useMemo)(()=>m.map(n.a),[m]),w=(0,i.useMemo)(()=>v.map(n.o),[v]);return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(je,{actionLabel:`新增歸屬`,description:`會員歸屬是 BPM 內部組織權限、主管解析與條件判斷的來源。`,onCreate:r,title:`會員歸屬`}),(0,s.jsx)(a.FilterArea,{className:[L.orgFilterArea,L.membershipFilterArea].join(` `),size:`sub`,children:(0,s.jsxs)(a.FilterLine,{children:[(0,s.jsx)(a.Filter,{span:2,children:(0,s.jsx)(a.FormField,{fullWidth:!0,layout:c.FormFieldLayout.VERTICAL,name:`membershipOrgUnitFilter`,children:(0,s.jsx)(a.AutoComplete,{disabledOptionsFilter:!0,emptyText:`沒有符合的組織`,inputProps:{autoCapitalize:`none`,autoCorrect:`off`,name:`membershipOrgUnitFilter`,spellCheck:!1},mode:`single`,name:`membershipOrgUnitFilter`,onChange:e=>l(Xe(e)),options:[...C],placeholder:`全部組織`,size:`sub`,value:p})})}),(0,s.jsx)(a.Filter,{span:2,children:(0,s.jsx)(a.FormField,{fullWidth:!0,layout:c.FormFieldLayout.VERTICAL,name:`membershipPositionFilter`,children:(0,s.jsx)(a.AutoComplete,{disabledOptionsFilter:!0,emptyText:`沒有符合的職位`,inputProps:{autoCapitalize:`none`,autoCorrect:`off`,name:`membershipPositionFilter`,spellCheck:!1},mode:`single`,name:`membershipPositionFilter`,onChange:e=>f(Ze(e)),options:[...w],placeholder:`全部職位`,size:`sub`,value:_})})}),(0,s.jsx)(a.Filter,{span:2,children:(0,s.jsx)(a.FormField,{fullWidth:!0,layout:c.FormFieldLayout.VERTICAL,name:`membershipStatusFilter`,children:(0,s.jsx)(a.AutoComplete,{disabledOptionsFilter:!0,emptyText:`沒有符合的狀態`,inputProps:{autoCapitalize:`none`,autoCorrect:`off`,name:`membershipStatusFilter`,spellCheck:!1},mode:`single`,name:`membershipStatusFilter`,onChange:e=>o(Ye(e)),options:[..._e],placeholder:`全部狀態`,size:`sub`,value:b})})})]})}),(0,s.jsx)(`div`,{className:L.tableFrame,children:(0,s.jsx)(a.Table,{actions:e,columns:S,dataSource:[...y],fullWidth:!0,loading:t,pagination:q({onPageChange:u,onPageSizeChange:d,page:h,pageSize:g,total:x}),style:{minWidth:xe}})})]})}function De({actions:e,loading:t,onCreate:n,onActiveFilterChange:r,onPageChange:o,onPageSizeChange:l,onScopeTypeFilterChange:u,page:d,pageSize:f,rows:p,scopeTypeFilter:m,statusFilter:h,total:g}){let _=(0,i.useMemo)(()=>[{dataIndex:`scopeLabel`,key:`scopeLabel`,title:`套用範圍`,width:320},{dataIndex:`managerName`,key:`managerName`,title:`簽核主管`,width:300},{dataIndex:`priority`,key:`priority`,title:`優先序`,width:96},{dataIndex:`effectiveFrom`,key:`effectiveFrom`,title:`生效日`,width:140},{dataIndex:`effectiveTo`,key:`effectiveTo`,title:`結束日`,width:140}],[]);return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(je,{actionLabel:`新增主管規則`,description:`簽核主管規則獨立於組織樹 parent,解析優先序為會員、組織、職位。`,onCreate:n,title:`簽核主管`}),(0,s.jsx)(a.FilterArea,{className:L.orgFilterArea,size:`sub`,children:(0,s.jsxs)(a.FilterLine,{children:[(0,s.jsx)(a.Filter,{span:3,children:(0,s.jsx)(a.FormField,{fullWidth:!0,layout:c.FormFieldLayout.VERTICAL,name:`managerScopeTypeFilter`,children:(0,s.jsx)(a.Select,{clearable:!1,fullWidth:!0,onChange:e=>u(qe(e)),options:[...ge],placeholder:`套用範圍`,size:`sub`,value:m})})}),(0,s.jsx)(a.Filter,{span:2,children:(0,s.jsx)(a.FormField,{fullWidth:!0,layout:c.FormFieldLayout.VERTICAL,name:`managerStatusFilter`,children:(0,s.jsx)(a.Select,{clearable:!1,fullWidth:!0,onChange:e=>r(Je(e)),options:[..._e],placeholder:`狀態`,size:`sub`,value:h})})})]})}),(0,s.jsx)(`div`,{className:L.tableFrame,children:(0,s.jsx)(a.Table,{actions:e,columns:_,dataSource:[...p],fullWidth:!0,loading:t,pagination:q({onPageChange:o,onPageSizeChange:l,page:d,pageSize:f,total:g}),style:{minWidth:Se}})})]})}function q({onPageChange:e,onPageSizeChange:t,page:n,pageSize:r,total:i}){return{current:n,onChange:e,onChangePageSize:t,pageSize:r,pageSizeLabel:`每頁筆數`,pageSizeOptions:[...ve],renderResultSummary:(e,t,n)=>`顯示 ${e}-${t} 筆,共 ${n} 筆`,showPageSizeOptions:!0,total:i}}function Oe({isTreeEditing:e,isTreeMode:t}){return t?e?`儲存`:`開始編輯`:`新增組織`}function ke({isTreeEditing:e,isTreeMode:t}){return t?e?u.SaveIcon:u.EditIcon:u.PlusIcon}function Ae({hasDraftChanges:e,isTreeEditing:t,isTreeMode:n,loading:r,saving:i}){return n?t?!e||i:r:!1}function je({actionDisabled:e=!1,actionIcon:t=u.PlusIcon,actionLabel:n,actions:r,description:i,onCreate:o,title:c}){return(0,s.jsxs)(`div`,{className:L.tableIntro,children:[(0,s.jsxs)(`div`,{children:[(0,s.jsx)(a.Typography,{component:`h2`,variant:`h3`,children:c}),(0,s.jsx)(a.Typography,{color:`text-neutral`,variant:`body`,children:i})]}),(0,s.jsxs)(`div`,{className:L.tableIntroActions,children:[r,(0,s.jsx)(a.Button,{disabled:e,icon:t,iconType:`leading`,onClick:o,children:n})]})]})}function Me({modal:e,onClose:r,onSubmit:o,orgUnits:c,saving:l}){let[u,d]=(0,i.useState)(``),[f,p]=(0,i.useState)(``),[m,h]=(0,i.useState)(null),[g,_]=(0,i.useState)(B[2]);return(0,i.useEffect)(()=>{if(!e)return;let t=e.record,r=t?.parentId??e.parentId??null,i=r?c.find(e=>e.id===r)??null:null;d(t?.code??``),p(t?.name??``),h(i?n.a(i):null),_(B.find(e=>e.id===t?.type)??B[2])},[e,c]),(0,s.jsx)(a.Modal,{cancelText:`取消`,confirmButtonProps:{disabled:!u||!f},confirmText:e?.type===`EDIT`?`儲存`:`建立`,loading:l,modalType:`standard`,onCancel:r,onClose:r,onConfirm:()=>void o({code:u,name:f,parentId:m?.id??null,type:g.id}),open:!!e,showModalFooter:!0,showModalHeader:!0,size:`regular`,title:e?.type===`EDIT`?`編輯組織`:`新增組織`,children:(0,s.jsxs)(`div`,{className:L.modalFields,children:[(0,s.jsx)(J,{label:`代碼`,name:`orgCode`,onChange:d,placeholder:`例如 FIN-TW`,value:u}),(0,s.jsx)(J,{label:`名稱`,name:`orgName`,onChange:p,placeholder:`例如 財務部`,value:f}),(0,s.jsx)(t.t,{label:`類型`,name:`orgType`,children:(0,s.jsx)(a.Select,{clearable:!1,fullWidth:!0,onChange:e=>_(We(e)),options:[...B],placeholder:`選擇組織類型`,value:g})}),(0,s.jsx)(t.t,{label:`上層組織`,name:`parentId`,children:(0,s.jsx)(n.n,{name:`parentId`,onChange:h,orgUnits:c.filter(t=>t.id!==e?.record?.id),placeholder:`選擇上層組織`,value:m})})]})})}function Ne({modal:e,onClose:t,onSubmit:n,saving:r}){let[o,c]=(0,i.useState)(``),[l,u]=(0,i.useState)(`0`),[d,f]=(0,i.useState)(``);return(0,i.useEffect)(()=>{e&&(c(e.record?.code??``),u(String(e.record?.level??0)),f(e.record?.name??``))},[e]),(0,s.jsx)(a.Modal,{cancelText:`取消`,confirmButtonProps:{disabled:!o||!d},confirmText:e?.type===`EDIT`?`儲存`:`建立`,loading:r,modalType:`standard`,onCancel:t,onClose:t,onConfirm:()=>void n({code:o,level:Number(l),name:d}),open:!!e,showModalFooter:!0,showModalHeader:!0,size:`regular`,title:e?.type===`EDIT`?`編輯職位`:`新增職位`,children:(0,s.jsxs)(`div`,{className:L.modalFields,children:[(0,s.jsx)(J,{label:`代碼`,name:`positionCode`,onChange:c,placeholder:`例如 FIN-MGR`,value:o}),(0,s.jsx)(J,{label:`名稱`,name:`positionName`,onChange:f,placeholder:`例如 財務主管`,value:d}),(0,s.jsx)(J,{label:`職等`,name:`positionLevel`,onChange:u,placeholder:`例如 5`,value:l})]})})}function Pe({membersById:e,modal:r,onClose:o,onSubmit:c,orgUnits:l,positions:u,saving:d}){let[f,p]=(0,i.useState)(Qe()),[m,h]=(0,i.useState)(``),[g,_]=(0,i.useState)(K[1]),[v,y]=(0,i.useState)(null),[b,x]=(0,i.useState)(null),[S,C]=(0,i.useState)(null);return(0,i.useEffect)(()=>{if(!r)return;let t=r.record,i=t?e.get(t.memberId):null;p(t?.effectiveFrom??Qe()),h(t?.effectiveTo??``),_(K.find(e=>e.value===t?.isPrimary)??K[1]),y(i?n.i(i):null),x(Q(l.find(e=>e.id===t?.orgUnitId),n.a)),C(Q(u.find(e=>e.id===t?.positionId),n.o))},[e,r,l,u]),(0,s.jsx)(a.Modal,{cancelText:`取消`,confirmButtonProps:{disabled:!b||r?.type!==`EDIT`&&!v},confirmText:r?.type===`EDIT`?`儲存`:`建立`,loading:d,modalType:`standard`,onCancel:o,onClose:o,onConfirm:()=>void c({effectiveFrom:f,effectiveTo:m||null,isPrimary:g.value,memberId:v?.id??null,orgUnitId:b?.id??null,positionId:S?.id??null}),open:!!r,showModalFooter:!0,showModalHeader:!0,size:`regular`,title:r?.type===`EDIT`?`編輯會員歸屬`:`新增會員歸屬`,children:(0,s.jsxs)(`div`,{className:L.modalFields,children:[(0,s.jsx)(t.t,{label:`會員`,name:`memberId`,children:(0,s.jsx)(n.t,{disabled:r?.type===`EDIT`,name:`memberId`,onChange:y,placeholder:`搜尋會員姓名或信箱`,value:v})}),(0,s.jsx)(t.t,{label:`組織`,name:`orgUnitId`,children:(0,s.jsx)(n.n,{name:`orgUnitId`,onChange:x,orgUnits:l,placeholder:`選擇歸屬組織`,value:b})}),(0,s.jsx)(t.t,{label:`職位`,name:`positionId`,children:(0,s.jsx)(n.r,{name:`positionId`,onChange:C,placeholder:`選擇職位`,positions:u,value:S})}),(0,s.jsx)(t.t,{label:`歸屬類型`,name:`isPrimary`,children:(0,s.jsx)(a.Select,{clearable:!1,fullWidth:!0,onChange:e=>_(Y(e)),options:[...K],placeholder:`選擇歸屬類型`,value:g})}),(0,s.jsx)(Ie,{label:`生效日`,name:`membershipEffectiveFrom`,onChange:p,placeholder:`YYYY-MM-DD`,value:f}),(0,s.jsx)(Ie,{label:`結束日`,name:`membershipEffectiveTo`,onChange:h,placeholder:`YYYY-MM-DD,未設定代表無期限`,value:m})]})})}function Fe({membersById:e,modal:r,onClose:o,onSubmit:c,orgUnits:l,positions:u,saving:d}){let[f,p]=(0,i.useState)(Qe()),[m,h]=(0,i.useState)(``),[g,_]=(0,i.useState)(null),[v,y]=(0,i.useState)(String(z)),[b,x]=(0,i.useState)(null),[S,C]=(0,i.useState)(null),[w,T]=(0,i.useState)(null),[E,D]=(0,i.useState)(U[0]);(0,i.useEffect)(()=>{if(!r)return;let t=r.record,i=U.find(e=>e.id===t?.scopeType)??U[0];p(t?.effectiveFrom??Qe()),h(t?.effectiveTo??``),_(Q(t?e.get(t.managerMemberId):null,n.i)),y(String(t?.priority??z)),x(i.id===`MEMBER`?Q(t?e.get(t.scopeId):null,n.i):null),C(i.id===`ORG_UNIT`?Q(l.find(e=>e.id===t?.scopeId),n.a):null),T(i.id===`POSITION`?Q(u.find(e=>e.id===t?.scopeId),n.o):null),D(i)},[e,r,l,u]);let ee=E.id===`MEMBER`?b?.id:E.id===`ORG_UNIT`?S?.id:w?.id,te=!!(E.id===`MEMBER`&&b?.id&&g?.id&&b.id===g.id);return(0,s.jsx)(a.Modal,{cancelText:`取消`,confirmButtonProps:{disabled:!g||!ee||te},confirmText:r?.type===`EDIT`?`儲存`:`建立`,loading:d,modalType:`standard`,onCancel:o,onClose:o,onConfirm:()=>void c({effectiveFrom:f,effectiveTo:m||null,managerMemberId:g?.id??null,priority:Number(v),scopeId:ee??null,scopeType:E.id}),open:!!r,showModalFooter:!0,showModalHeader:!0,size:`regular`,title:r?.type===`EDIT`?`編輯主管規則`:`新增主管規則`,children:(0,s.jsxs)(`div`,{className:L.modalFields,children:[(0,s.jsx)(t.t,{label:`套用範圍`,name:`scopeType`,children:(0,s.jsx)(a.Select,{clearable:!1,fullWidth:!0,onChange:e=>D(Ke(e)),options:[...U],placeholder:`選擇套用範圍`,value:E})}),E.id===`MEMBER`?(0,s.jsx)(t.t,{label:`會員`,name:`scopeMemberId`,children:(0,s.jsx)(n.t,{name:`scopeMemberId`,onChange:x,placeholder:`搜尋套用會員`,value:b})}):null,E.id===`ORG_UNIT`?(0,s.jsx)(t.t,{label:`組織`,name:`scopeOrgUnitId`,children:(0,s.jsx)(n.n,{name:`scopeOrgUnitId`,onChange:C,orgUnits:l,placeholder:`選擇套用組織`,value:S})}):null,E.id===`POSITION`?(0,s.jsx)(t.t,{label:`職位`,name:`scopePositionId`,children:(0,s.jsx)(n.r,{name:`scopePositionId`,onChange:T,placeholder:`選擇套用職位`,positions:u,value:w})}):null,(0,s.jsx)(t.t,{label:`簽核主管`,name:`managerMemberId`,children:(0,s.jsx)(n.t,{name:`managerMemberId`,onChange:_,placeholder:`搜尋簽核主管`,value:g})}),te?(0,s.jsx)(a.Typography,{color:`text-error`,variant:`caption`,children:`簽核主管不可設定為套用會員本人。`}):null,(0,s.jsx)(J,{hintText:`數字越大越優先,同一位成員命中多條規則時只會採用最高的那一層。建議:指定到人 200、部門主管 100、全公司通用的墊底規則 10。`,label:`優先序`,name:`managerPriority`,onChange:y,placeholder:`例如 100`,value:v}),(0,s.jsx)(Ie,{label:`生效日`,name:`managerEffectiveFrom`,onChange:p,placeholder:`YYYY-MM-DD`,value:f}),(0,s.jsx)(Ie,{label:`結束日`,name:`managerEffectiveTo`,onChange:h,placeholder:`YYYY-MM-DD,未設定代表無期限`,value:m})]})})}function J({hintText:e,label:n,name:r,onChange:i,placeholder:o,value:c}){return(0,s.jsx)(t.t,{hintText:e,label:n,name:r,children:(0,s.jsx)(a.Input,{fullWidth:!0,name:r,onChange:e=>i(e.target.value),placeholder:o,value:c})})}function Ie({label:e,name:n,onChange:r,placeholder:i,value:o}){return(0,s.jsx)(t.t,{label:e,name:n,children:(0,s.jsx)(a.DatePicker,{format:`YYYY-MM-DD`,fullWidth:!0,inputProps:{name:n},onChange:e=>r($e(e)),placeholder:i,value:o.trim()?o:void 0})})}function Le(e,t){return[...new Set([...e.map(e=>e.memberId),...t.map(e=>e.managerMemberId),...t.filter(e=>e.scopeType===`MEMBER`).map(e=>e.scopeId)])]}function Re(e,t){return e.scopeType===`MEMBER`?`會員:${ze(t.membersById.get(e.scopeId))}`:e.scopeType===`ORG_UNIT`?`組織:${Be(t.orgUnitsById.get(e.scopeId))}`:`職位:${He(t.positionsById.get(e.scopeId))}`}function ze(e){return e?r.t(e.name,e.email,`dot`):`未知會員`}function Be(e){return e?`${e.name} · ${e.code}`:`未知組織`}function Ve(e){return B.find(t=>t.id.toLowerCase()===e.toLowerCase())?.name??`未知類型`}function He(e){return e?`${e.name} · ${e.code}`:`未指定`}function Ue(e){return e===`MANAGERS`||e===`MEMBERSHIPS`||e===`POSITIONS`?e:`ORG_UNITS`}function We(e){let t=Z(e)?e:null;if(typeof t?.id==`string`){let e=t.id;return B.find(t=>t.id.toLowerCase()===e.toLowerCase())??B[2]}return B[2]}function Ge(e){let t=Z(e)?e:null;if(typeof t?.id==`string`){let e=t.id;return H.find(t=>t.id.toLowerCase()===e.toLowerCase())??V}return V}function Ke(e){return X(e,U,U[0])}function qe(e){return X(e,ge,W)}function Je(e){return X(e,_e,G)}function Ye(e){let t=Z(e)?e:null,n=typeof t?.id==`string`?t.id:null;return _e.find(e=>e.id===n)??null}function Xe(e){let t=Z(e)?e:null,n=typeof t?.id==`string`?t.id:null,r=typeof t?.name==`string`?t.name:null;return n&&r?{id:n,name:r}:null}function Ze(e){let t=Z(e)?e:null,n=typeof t?.id==`string`?t.id:null,r=typeof t?.name==`string`?t.name:null;return n&&r?{id:n,name:r}:null}function Y(e){return X(e,K,K[1])}function X(e,t,n){let r=Z(e)?e:null,i=typeof r?.id==`string`?r.id:null;return t.find(e=>e.id===i)??n}function Z(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function Q(e,t){return e?t(e):null}function Qe(){return et(new Date)}function $e(e){let t=e?new Date(e):null;return t&&!Number.isNaN(t.getTime())?et(t):``}function et(e){return`${e.getFullYear()}-${tt(e.getMonth()+1)}-${tt(e.getDate())}`}function tt(e){return String(e).padStart(2,`0`)}function nt(e){return e instanceof Error?e.message:`讀取組織資料失敗。`}Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return Ce}});
|
|
2
|
+
//# sourceMappingURL=orgs-B_2J2tLX.cjs.map
|