@rytass/bpm-core-react 0.7.2 → 0.7.3

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 CHANGED
@@ -8,6 +8,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8
8
  Releases are managed by [`nx release`](https://nx.dev/recipes/nx-release) with
9
9
  Conventional Commits — see `nx.json` for the release config.
10
10
 
11
+ ## 0.7.3 — 2026-07-02
12
+
13
+ ### Fixed
14
+
15
+ - The organization tree editor's readable opening viewport now actually shows
16
+ the tree: dagre can place the synthetic root at the far edge of an asymmetric
17
+ layout, so anchoring on the root's own coordinates opened onto empty margin
18
+ with every other node off-screen. The root is now re-centered over the layout
19
+ width and the opening viewport anchors on the layout's horizontal center and
20
+ top ranks.
21
+ - The 收合 / 展開 (and 編輯 / 新增) buttons on tree node cards now respond to
22
+ real mouse clicks. The node action row was only marked `nodrag`, so a click
23
+ with ≥1px of pointer jitter was captured by the canvas pan gesture and the
24
+ click was suppressed before reaching the button; the row is now also `nopan`.
25
+ - The initial expansion of a large organization tree now also stops before any
26
+ level that would render more than 12 sibling nodes side by side — depth alone
27
+ still let a wide level open thousands of pixels across.
28
+ - Collapsing or expanding a subtree re-centers the viewport on the toggled node
29
+ (at the user's current zoom), so the layout shift from the re-run dagre
30
+ layout no longer leaves the change off-screen.
31
+
11
32
  ## 0.7.2 — 2026-07-02
12
33
 
13
34
  ### Fixed
@@ -0,0 +1,2 @@
1
+ "use client";require('../orgs.css');const e=require("./chunk-CMqjfN_6.cjs"),t=require("./admin-pickers-Btvij1at.cjs"),n=require("./bpm-form-field-Bc6k4ZEO.cjs");let r=require("react"),i=require("@mezzanine-ui/react"),a=require("@rytass/bpm-core-client"),o=require("react/jsx-runtime"),s=require("@mezzanine-ui/react/ContentHeader");s=e.t(s,1);let c=require("@mezzanine-ui/core/form"),l=require("@mezzanine-ui/icons"),u=require("@rytass/bpm-core-client/organization"),d=require("@xyflow/react"),f=require("dagre");f=e.t(f,1);function p(e){return new Map(e.map(e=>[e.id,e.parentId]))}function m({orgUnitId:e,parentDraft:t,parentId:n}){let r=n===e?e:n,i=g({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 h({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 g({orgUnitId:e,parentDraft:t,parentId:n}){return t.has(e)?n?t.has(n)?n===e?`組織不可成為自己的上層。`:_({orgUnitId:e,parentDraft:t,parentId:n})?`不可搬移到自己的下層組織。`:null:`找不到新的上層組織。`:null:`找不到要搬移的組織節點。`}function _({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 v={orgTreeEditor:`bpm_orgTreeEditor_TMOtD`,orgTreeSummary:`bpm_orgTreeSummary_vpcV8`,orgTreeChangeList:`bpm_orgTreeChangeList_EzmOv`,orgTreeCanvas:`bpm_orgTreeCanvas_MeD7y`,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`},y=`__org-tree-root__`,b=232,x=118,S=232,C=86,w=320,T=1.4,E=.25,D=.005,ee=250,te=80,O=.85,ne=.7,re=1200,k=600,A=60,ie=3,ae=12,j={COMPANY:`公司`,DEPARTMENT:`部門`,DIVISION:`事業群`,TEAM:`小組`},oe={orgUnit:M},se=(0,r.forwardRef)(function({onCreateChild:e,onCreateRoot:t,onEditOrgUnit:n,onSaveDraft:a,onStateChange:s,orgUnits:c},l){let[u,f]=(0,r.useState)(!1),[g,_]=(0,r.useState)(null),[S,C]=(0,r.useState)(null),[w,A]=(0,r.useState)(()=>p(c)),[ie,ae]=(0,r.useState)(()=>le(c,p(c))),[j,se]=(0,r.useState)([]),M=(0,r.useRef)(null),N=(0,r.useRef)(null),ce=(0,r.useCallback)(e=>{N.current=e,ae(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},[]),P=(0,r.useMemo)(()=>new Map(c.map(e=>[e.id,e])),[c]),F=(0,r.useMemo)(()=>h({orgUnits:c,parentDraft:w}),[c,w]),I=(0,r.useMemo)(()=>ue({collapsedIds:ie,isEditing:u,onCreateChild:n=>{n?e(n):t()},onEditOrgUnit:e=>{let t=P.get(e);t&&n(t)},onToggleCollapse:ce,orgUnits:c,orgUnitsById:P,parentDraft:w,selectedOrgUnitId:S}),[ie,ce,u,e,t,n,c,P,w,S]),L=(0,r.useRef)(I);L.current=I;let R=F.length>0,z=(0,r.useMemo)(()=>{let e=Math.max(I.bounds.width,I.bounds.height);return e<=0?E:Math.min(E,Math.max(D,ee/e))},[I.bounds.height,I.bounds.width]),B=c.length<=te,V=(0,r.useCallback)(()=>{let e=M.current;if(!e)return;let{bounds:t,rootCenter:n}=L.current,r=t.width>0?re/t.width:1/0,i=t.height>0?k/t.height:1/0,a=Math.min(r,i);if(!Number.isFinite(a)||a>=ne){e.fitView({padding:.18});return}let o=k/(2*O);e.setCenter(n.x,Math.min(t.height/2,o),{duration:0,zoom:O})},[]),H=(0,r.useCallback)(e=>{M.current=e,V()},[V]);(0,r.useImperativeHandle)(l,()=>({cancelEditing:_e,saveDraft:K,startEditing:ge})),(0,r.useEffect)(()=>{s({hasDraftChanges:R,isEditing:u})},[R,u,s]),(0,r.useEffect)(()=>{let e=p(c);A(e),ae(le(c,e)),C(null),_(null),f(!1)},[c]),(0,r.useEffect)(()=>{se(I.nodes)},[I.nodes]),(0,r.useEffect)(()=>{if(typeof window>`u`)return()=>void 0;let e=window.requestAnimationFrame(()=>{V()});return()=>window.cancelAnimationFrame(e)},[V,c]),(0,r.useEffect)(()=>{let e=N.current;if(!e)return;N.current=null;let t=M.current,n=I.nodes.find(t=>t.id===e);!t||!n||t.setCenter(n.position.x+(n.width??b)/2,n.position.y+(n.height??x)/2,{duration:200,zoom:t.getZoom()})},[I.nodes]);let U=(0,r.useCallback)((e,t)=>{A(n=>{let r=m({orgUnitId:e,parentDraft:n,parentId:t});return _(r.message),r.parentDraft})},[]),W=(0,r.useCallback)(e=>{if(!u||!e.target||!e.source)return;let t=e.source===y?null:e.source;if(e.target===y){_(`根節點不能搬移到其他節點下。`);return}U(e.target,t)},[U,u]),G=(0,r.useCallback)(e=>{u&&se(t=>(0,d.applyNodeChanges)(e,[...t]))},[u]),he=(0,r.useCallback)((e,t,n)=>{if(!u||t.id===y)return;let r=fe(e,t.id)??de(t,n);if(r===void 0){_(`拖曳到目標父節點附近,或從父節點拉線到子節點。`);return}U(t.id,r===y?null:r)},[U,u]);function ge(){f(!0),A(p(c)),_(`已進入編輯模式,拖曳節點或拉線只會更新前端草稿。`)}function _e(){f(!1),A(p(c)),_(`已取消草稿變更。`)}async function K(){if(!a){_(`批次儲存 API 尚未接上,草稿仍保留在前端。`);return}await a(F),f(!1),_(`組織樹草稿已儲存。`)}return(0,o.jsxs)(`div`,{className:v.orgTreeEditor,children:[(0,o.jsxs)(`div`,{className:v.orgTreeSummary,children:[(0,o.jsx)(i.Typography,{color:`text-neutral`,variant:`caption`,children:g??(R?`目前有 ${F.length} 筆父子關係草稿變更。`:`目前沒有草稿變更。`)}),R?(0,o.jsx)(`ul`,{className:v.orgTreeChangeList,children:F.map(e=>(0,o.jsxs)(`li`,{children:[me(e.orgUnitId,P),`:`,me(e.previousParentId,P),` -> `,me(e.parentId,P)]},e.orgUnitId))}):null]}),(0,o.jsx)(`div`,{className:v.orgTreeCanvas,children:(0,o.jsxs)(d.ReactFlow,{connectionMode:d.ConnectionMode.Strict,edges:[...I.edges],fitViewOptions:{minZoom:z,padding:.18},isValidConnection:e=>pe({source:e.source,target:e.target},w),maxZoom:T,minZoom:z,nodeTypes:oe,nodes:[...j],nodesConnectable:u,nodesDraggable:u,onConnect:W,onInit:H,onNodeClick:(e,t)=>{C(t.id===y?null:t.id)},onNodeDoubleClick:(e,t)=>{if(t.id!==y){let e=P.get(t.id);e&&n(e)}},onNodeDragStop:he,onNodesChange:G,onPaneClick:()=>C(null),panOnDrag:!0,proOptions:{hideAttribution:!0},children:[(0,o.jsx)(d.Background,{}),(0,o.jsx)(d.Controls,{}),B?(0,o.jsx)(d.MiniMap,{pannable:!0,zoomable:!0}):null]})})]})});function M({data:e,selected:t}){return(0,o.jsxs)(`div`,{className:[v.orgTreeNode,e.isSyntheticRoot?v.orgTreeNodeRoot:``,e.changed?v.orgTreeNodeChanged:``,e.deleted?v.orgTreeNodeDeleted:``,t?v.orgTreeNodeSelected:``].filter(Boolean).join(` `),children:[e.isSyntheticRoot?null:(0,o.jsx)(d.Handle,{id:`target`,isConnectable:e.isEditing,position:d.Position.Top,type:`target`}),(0,o.jsx)(d.Handle,{id:`source`,isConnectable:e.isEditing,position:d.Position.Bottom,type:`source`}),(0,o.jsxs)(`div`,{className:v.orgTreeNodeHeader,children:[(0,o.jsx)(i.Typography,{component:`span`,ellipsis:!0,title:e.name,variant:`label-primary`,children:e.name}),e.changed?(0,o.jsx)(`span`,{className:v.orgTreeNodeBadge,children:`草稿`}):null]}),(0,o.jsx)(i.Typography,{color:`text-neutral`,component:`span`,ellipsis:!0,title:e.code,variant:`caption`,children:e.isSyntheticRoot?`根節點容器`:`${e.typeLabel} · ${e.code}`}),e.isSyntheticRoot?null:(0,o.jsxs)(i.Typography,{color:`text-neutral`,component:`span`,ellipsis:!0,title:e.parentLabel,variant:`caption`,children:[`上層:`,e.parentLabel]}),(0,o.jsxs)(`div`,{className:`${v.orgTreeNodeActions} nodrag nopan`,children:[e.childCount>0?(0,o.jsx)(i.Button,{onClick:t=>{t.stopPropagation(),e.onToggleCollapse(e.orgUnitId??y)},size:`sub`,variant:`base-secondary`,children:e.collapsed?`展開 (${e.childCount})`:`收合 (${e.childCount})`}):null,e.isSyntheticRoot?(0,o.jsx)(i.Button,{icon:l.PlusIcon,iconType:`leading`,onClick:()=>e.onCreateChild(null),size:`sub`,variant:`base-secondary`,children:`新增根節點`}):(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(i.Button,{icon:l.EditIcon,iconType:`leading`,onClick:()=>{e.orgUnitId&&e.onEdit(e.orgUnitId)},size:`sub`,variant:`base-secondary`,children:`編輯`}),(0,o.jsx)(i.Button,{icon:l.PlusIcon,iconType:`leading`,onClick:()=>e.onCreateChild(e.orgUnitId),size:`sub`,variant:`base-secondary`,children:`新增子節點`})]})]})]})}function N(e,t){let n=new Map;return e.forEach(e=>{let r=t.get(e.id)??y;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(y),n}function le(e,t){if(e.length<=A)return new Set;let n=N(e,t),r=new Set,i=[y],a=0;for(;i.length>0&&a<ie;){let e=i.flatMap(e=>n.get(e)??[]);if(e.length>ae)break;i.forEach(e=>{r.add(e)}),i=e,a+=1}let o=new Set,s=e=>{let t=n.get(e)??[];t.length!==0&&(r.has(e)||o.add(e),t.forEach(s))};return s(y),o}function ue({collapsedIds:e,isEditing:t,onCreateChild:n,onEditOrgUnit:r,onToggleCollapse:i,orgUnits:a,orgUnitsById:o,parentDraft:s,selectedOrgUnitId:c}){let l=N(a,s),u=ce({childrenMap:l,collapsedIds:e}),d=a.filter(e=>u.has(e.id)),p=e=>l.get(e)?.length??0,m=new f.graphlib.Graph;m.setDefaultEdgeLabel(()=>({})),m.setGraph({marginx:36,marginy:36,nodesep:44,rankdir:`TB`}),m.setNode(y,{height:C,width:S}),d.forEach(e=>{m.setNode(e.id,{height:x,width:b})}),d.forEach(e=>{let t=s.get(e.id)??null;m.setEdge(t??y,e.id)}),f.layout(m);let h=m.graph(),g={height:h.height??0,width:h.width??0},_=m.node(y),v={x:g.width>0?g.width/2:_?.x??0,y:_?.y??0},w={...P({data:{changed:!1,childCount:p(y),code:y,collapsed:e.has(y),deleted:!1,isEditing:t,isSyntheticRoot:!0,name:`組織根節點`,onCreateChild:n,onEdit:r,onToggleCollapse:i,orgUnitId:null,parentLabel:``,path:``,typeLabel:``},graph:m,height:C,id:y,selected:c===null,width:S}),position:{x:v.x-S/2,y:v.y-C/2}},T=d.map(a=>{let l=s.get(a.id)??null,u=me(l,o);return P({data:{changed:l!==a.parentId,childCount:p(a.id),code:a.code,collapsed:e.has(a.id),deleted:!!a.deletedAt,isEditing:t,isSyntheticRoot:!1,name:a.name,onCreateChild:n,onEdit:r,onToggleCollapse:i,orgUnitId:a.id,parentLabel:u,path:a.path,typeLabel:z(a.type)},graph:m,height:x,id:a.id,selected:c===a.id,width:b})});return{bounds:g,edges:d.map(e=>{let n=s.get(e.id)??null,r=n!==e.parentId;return{animated:t&&r,data:{},id:`org-tree-edge-${n??`root`}-${e.id}`,source:n??y,sourceHandle:`source`,style:r?{stroke:`var(--mzn-color-primary, #0057ff)`,strokeWidth:2}:void 0,target:e.id,targetHandle:`target`,type:`smoothstep`}}),nodes:[w,...T],rootCenter:v}}function P({data:e,graph:t,height:n,id:r,selected:i,width:a}){let o=t.node(r);return{data:e,height:n,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:d.Position.Bottom,targetPosition:d.Position.Top,type:`orgUnit`,width:a}}function de(e,t){let n=L(e);return t.filter(t=>t.id!==e.id).map(e=>({distance:R(n,L(e)),id:e.id})).filter(e=>e.distance<=w).sort((e,t)=>e.distance-t.distance)[0]?.id}function fe(e,t){let n=F(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();return{distance:R(n,{x:i.left+i.width/2,y:i.top+i.height/2}),id:r}}).filter(e=>!!e).filter(e=>e.distance<=w).sort((e,t)=>e.distance-t.distance)[0]?.id}function F(e){return I(e)?{x:e.clientX,y:e.clientY}:null}function I(e){return typeof e==`object`&&!!e&&`clientX`in e&&`clientY`in e&&typeof e.clientX==`number`&&typeof e.clientY==`number`}function L(e){return{x:e.position.x+(e.width??b)/2,y:e.position.y+(e.height??x)/2}}function R(e,t){return Math.hypot(e.x-t.x,e.y-t.y)}function pe(e,t){return!e.source||!e.target||e.target===y?!1:g({orgUnitId:e.target,parentDraft:t,parentId:e.source===y?null:e.source})===null}function me(e,t){if(!e)return`根節點`;let n=t.get(e);return n?`${n.name} · ${n.code}`:`未知組織`}function z(e){return j[e.toUpperCase()]??`未知類型`}var B={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`},V={hasDraftChanges:!1,isEditing:!1},H=[{id:`COMPANY`,name:`公司`},{id:`DIVISION`,name:`事業群`},{id:`DEPARTMENT`,name:`部門`},{id:`TEAM`,name:`小組`}],U={id:`ALL`,name:`全部類型`},W=[U,...H],G=[{id:`MEMBER`,name:`指定會員`},{id:`ORG_UNIT`,name:`指定組織`},{id:`POSITION`,name:`指定職位`}],he={id:`ALL`,name:`全部範圍`},ge=[he,...G],_e={activeOnly:!1,id:`ALL`,name:`全部狀態`},K=[_e,{activeOnly:!0,id:`ACTIVE`,name:`目前有效`}],q=[{id:`true`,name:`主要歸屬`,value:!0},{id:`false`,name:`一般歸屬`,value:!1}],ve=[10,20,50],ye=1368,be=908,xe=1292,Se=1124;function Ce(){let[e,t]=(0,r.useState)(`ORG_UNITS`),[n,c]=(0,r.useState)(null),[l,d]=(0,r.useState)(null),[f,p]=(0,r.useState)(null),[m,h]=(0,r.useState)(!0),[g,_]=(0,r.useState)(null),[v,y]=(0,r.useState)(_e),[b,x]=(0,r.useState)(1),[S,C]=(0,r.useState)(10),[w,T]=(0,r.useState)(he),[E,D]=(0,r.useState)(0),[ee,te]=(0,r.useState)([]),[O,ne]=(0,r.useState)(null),[re,k]=(0,r.useState)(null),[A,ie]=(0,r.useState)(null),[ae,j]=(0,r.useState)(1),[oe,se]=(0,r.useState)(10),[M,N]=(0,r.useState)(null),[ce,le]=(0,r.useState)(0),[ue,P]=(0,r.useState)(null),[de,fe]=(0,r.useState)(1),[F,I]=(0,r.useState)(10),[L,R]=(0,r.useState)(``),[pe,me]=(0,r.useState)(0),[z,B]=(0,r.useState)(U),[V,H]=(0,r.useState)(`TABLE`),[W,G]=(0,r.useState)([]),[ge,K]=(0,r.useState)([]),[q,ve]=(0,r.useState)([]),[ye,be]=(0,r.useState)(null),[xe,Se]=(0,r.useState)(1),[Ce,Oe]=(0,r.useState)(10),[ke,Ae]=(0,r.useState)(``),[je,Me]=(0,r.useState)(0),[J,Le]=(0,r.useState)([]),[Ge,Ke]=(0,r.useState)([]),[qe,Je]=(0,r.useState)([]),[Y,Ye]=(0,r.useState)(!1);(0,r.useEffect)(()=>{n&&d(n)},[n]);let Xe=n??l,Ze=(0,r.useCallback)(async()=>{h(!0),p(null);try{let e=await(0,u.readOrganizationDashboard)({managerActiveOnly:v.activeOnly,managerPage:b,managerPageSize:S,managerScopeType:w.id===`ALL`?null:w.id,membershipActiveOnly:O?.activeOnly??!1,membershipOrgUnitId:A?.id??null,membershipPage:ae,membershipPageSize:oe,membershipPositionId:M?.id??null,orgUnitPage:de,orgUnitPageSize:F,orgUnitSearchText:L,orgUnitType:z.id===`ALL`?null:z.id,positionPage:xe,positionPageSize:Ce,positionSearchText:ke});te(await(0,a.resolveMembers)(Re(e.memberships,e.managerResolutions))),G(e.orgUnits),me(e.orgUnitCount),K(e.filteredOrgUnits),Le(e.positions),Me(e.positionCount),ve(e.filteredPositions),le(e.membershipCount),Je(e.filteredMemberships),D(e.managerResolutionCount),Ke(e.filteredManagerResolutions)}catch(e){p(nt(e))}finally{h(!1)}},[v,b,S,w,O,A,ae,oe,M,de,F,L,z,xe,Ce,ke]);(0,r.useEffect)(()=>{Ze()},[Ze]);let X=(0,r.useMemo)(()=>new Map(W.map(e=>[e.id,e])),[W]),Z=(0,r.useMemo)(()=>new Map(J.map(e=>[e.id,e])),[J]),Q=(0,r.useMemo)(()=>new Map(ee.map(e=>[e.memberId,e])),[ee]),$=(0,r.useMemo)(()=>ge.map(e=>({...e,key:e.id,parentName:e.parentId?Ve(X.get(e.parentId)):`根節點`,typeLabel:He(e.type)})),[ge,X]),$e=(0,r.useMemo)(()=>q.map(e=>({...e,key:e.id})),[q]),et=(0,r.useMemo)(()=>qe.map(e=>({...e,key:e.id,memberName:Be(Q.get(e.memberId)),orgUnitName:Ve(X.get(e.orgUnitId)),positionName:e.positionId?Ue(Z.get(e.positionId)):`未指定`})),[Q,qe,X,Z]),tt=(0,r.useMemo)(()=>Ge.map(e=>({...e,key:e.id,managerName:Be(Q.get(e.managerMemberId)),scopeLabel:ze(e,{membersById:Q,orgUnitsById:X,positionsById:Z})})),[Ge,Q,X,Z]),rt=(0,r.useMemo)(()=>({render:e=>[{name:`編輯`,onClick:()=>P({record:e,type:`EDIT`})},{name:`停用`,onClick:()=>c({confirmText:`停用組織`,description:`停用「${e.name}」後,這個組織節點將不再出現在可用組織清單中。`,id:e.id,title:`停用組織節點`,type:`ORG_UNIT`}),variant:`destructive-secondary`}],variant:`base-secondary`,width:128}),[]),it=(0,r.useMemo)(()=>({render:e=>[{name:`編輯`,onClick:()=>be({record:e,type:`EDIT`})}],variant:`base-secondary`,width:88}),[]),at=(0,r.useMemo)(()=>({render:e=>[{name:`編輯`,onClick:()=>k({record:e,type:`EDIT`})},{name:`刪除`,onClick:()=>c({confirmText:`刪除歸屬`,description:`刪除「${e.memberName}」在「${e.orgUnitName}」的會員歸屬。`,id:e.id,title:`刪除會員歸屬`,type:`MEMBERSHIP`}),variant:`destructive-secondary`}],variant:`base-secondary`,width:128}),[]),ot=(0,r.useMemo)(()=>({render:e=>[{name:`編輯`,onClick:()=>_({record:e,type:`EDIT`})},{name:`刪除`,onClick:()=>c({confirmText:`刪除主管規則`,description:`刪除「${e.scopeLabel}」指派給「${e.managerName}」的主管解析規則。`,id:e.id,title:`刪除主管解析規則`,type:`MANAGER_RESOLUTION`}),variant:`destructive-secondary`}],variant:`base-secondary`,width:128}),[]);function st(e){fe(1),R(e)}function ct(e){fe(1),B(e)}function lt(e){Se(1),Ae(e)}function ut(e){j(1),ne(e)}function dt(e){j(1),ie(e)}function ft(e){j(1),N(e)}function pt(e){x(1),y(e)}function mt(e){x(1),T(e)}function ht(){Y||c(null)}async function gt(){n&&await vt(async()=>{n.type===`ORG_UNIT`&&await(0,u.deleteOrgUnit)(n.id),n.type===`MEMBERSHIP`&&await(0,u.deleteMembership)(n.id),n.type===`MANAGER_RESOLUTION`&&await(0,u.deleteManagerResolution)(n.id),c(null)})}async function _t(e){Ye(!0),p(null);try{await(0,u.commitOrgUnitTreeDraft)({moves:e.map(e=>({baseUpdatedAt:X.get(e.orgUnitId)?.updatedAt??``,id:e.orgUnitId,parentId:e.parentId}))}),await Ze()}catch(e){throw p(nt(e)),e}finally{Ye(!1)}}async function vt(e){Ye(!0),p(null);try{await e(),await Ze()}catch(e){p(nt(e))}finally{Ye(!1)}}return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(i.PageHeader,{children:(0,o.jsx)(s.default,{description:`維護組織樹、職位、會員歸屬與簽核主管解析規則。`,title:`組織管理`})}),(0,o.jsx)(i.SectionGroup,{children:(0,o.jsxs)(i.Section,{tab:(0,o.jsxs)(i.Tab,{activeKey:e,onChange:e=>t(We(e)),children:[(0,o.jsx)(i.TabItem,{children:`組織樹`},`ORG_UNITS`),(0,o.jsx)(i.TabItem,{children:`職位`},`POSITIONS`),(0,o.jsx)(i.TabItem,{children:`會員歸屬`},`MEMBERSHIPS`),(0,o.jsx)(i.TabItem,{children:`簽核主管`},`MANAGERS`)]}),children:[f?(0,o.jsx)(i.Typography,{color:`text-error`,variant:`body`,children:f}):null,e===`ORG_UNITS`?(0,o.jsx)(we,{actions:rt,loading:m,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:fe,onSaveDraft:_t,onPageSizeChange:e=>{fe(1),I(e)},onSearchTextChange:st,onTypeFilterChange:ct,orgUnits:W,page:de,pageSize:F,rows:$,searchText:L,saving:Y,total:pe,typeFilter:z,viewMode:V,onViewModeChange:H}):null,e===`POSITIONS`?(0,o.jsx)(Te,{actions:it,loading:m,onCreate:()=>be({record:null,type:`CREATE`}),onPageChange:Se,onPageSizeChange:e=>{Se(1),Oe(e)},onSearchTextChange:lt,page:xe,pageSize:Ce,rows:$e,searchText:ke,total:je}):null,e===`MEMBERSHIPS`?(0,o.jsx)(Ee,{actions:at,loading:m,onCreate:()=>k({record:null,type:`CREATE`}),onActiveFilterChange:ut,onOrgUnitFilterChange:dt,onPageChange:j,onPageSizeChange:e=>{j(1),se(e)},onPositionFilterChange:ft,orgUnitFilter:A,orgUnits:W,page:ae,pageSize:oe,positionFilter:M,positions:J,rows:et,statusFilter:O,total:ce}):null,e===`MANAGERS`?(0,o.jsx)(De,{actions:ot,loading:m,onCreate:()=>_({record:null,type:`CREATE`}),onActiveFilterChange:pt,onPageChange:x,onPageSizeChange:e=>{x(1),C(e)},onScopeTypeFilterChange:mt,page:b,pageSize:S,rows:tt,scopeTypeFilter:w,statusFilter:v,total:E}):null]})}),(0,o.jsx)(Ne,{modal:ue,onClose:()=>P(null),onSubmit:e=>vt(async()=>{ue?.type===`EDIT`&&ue.record?await(0,u.updateOrgUnit)({...e,id:ue.record.id,metadataJson:null}):await(0,u.createOrgUnit)({code:e.code??``,metadataJson:`{}`,name:e.name??``,parentId:e.parentId,type:e.type??`DEPARTMENT`}),P(null)}),orgUnits:W,saving:Y}),(0,o.jsx)(Pe,{modal:ye,onClose:()=>be(null),onSubmit:e=>vt(async()=>{ye?.type===`EDIT`&&ye.record?await(0,u.updatePosition)({...e,id:ye.record.id,metadataJson:null}):await(0,u.createPosition)({code:e.code??``,level:e.level??0,metadataJson:`{}`,name:e.name??``}),be(null)}),saving:Y}),(0,o.jsx)(Fe,{membersById:Q,modal:re,onClose:()=>k(null),onSubmit:e=>vt(async()=>{re?.type===`EDIT`&&re.record?await(0,u.updateMembership)({...e,id:re.record.id}):await(0,u.createMembership)({effectiveFrom:e.effectiveFrom??Qe(),effectiveTo:e.effectiveTo,isPrimary:e.isPrimary??!1,memberId:e.memberId??``,orgUnitId:e.orgUnitId??``,positionId:e.positionId}),k(null)}),orgUnits:W,positions:J,saving:Y}),(0,o.jsx)(Ie,{membersById:Q,modal:g,onClose:()=>_(null),onSubmit:e=>vt(async()=>{g?.type===`EDIT`&&g.record?await(0,u.updateManagerResolution)({...e,id:g.record.id}):await(0,u.createManagerResolution)({effectiveFrom:e.effectiveFrom??Qe(),effectiveTo:e.effectiveTo,managerMemberId:e.managerMemberId??``,priority:e.priority??0,scopeId:e.scopeId??``,scopeType:e.scopeType??`MEMBER`}),_(null)}),orgUnits:W,positions:J,saving:Y}),(0,o.jsx)(i.Modal,{cancelText:`取消`,confirmButtonProps:{variant:`destructive-primary`},confirmText:Xe?.confirmText??``,loading:Y,modalStatusType:`error`,modalType:`standard`,onCancel:ht,onClose:ht,onConfirm:()=>void gt(),open:!!n,showModalFooter:!0,showModalHeader:!0,size:`regular`,supportingText:`此操作會立即套用,請確認後再繼續。`,title:Xe?.title??``,children:(0,o.jsx)(i.Typography,{color:`text-neutral`,variant:`body`,children:Xe?.description??``})})]})}function we({actions:e,loading:t,onCreate:n,onCreateChild:a,onEditOrgUnit:s,onPageChange:u,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,r.useRef)(null),[E,D]=(0,r.useState)(V),ee=w===`TABLE`?`FLOW`:`TABLE`,te=w===`TABLE`?`切換樹狀圖`:`切換表格`,O=w===`FLOW`,ne=ke({isTreeMode:O,isTreeEditing:E.isEditing}),re=Ae({isTreeMode:O,isTreeEditing:E.isEditing}),k=je({hasDraftChanges:E.hasDraftChanges,isTreeEditing:E.isEditing,isTreeMode:O,loading:t,saving:x}),A=(0,r.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,r.useEffect)(()=>{w===`TABLE`&&D(V)},[w]),(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(Me,{actionDisabled:k,actionIcon:re,actionLabel:ne,actions:(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(i.Button,{onClick:()=>h(ee),variant:`base-secondary`,children:te}),O&&E.isEditing?(0,o.jsx)(i.Button,{disabled:x,icon:l.CloseIcon,iconType:`leading`,onClick:()=>T.current?.cancelEditing(),variant:`base-secondary`,children:`取消`}):null]}),description:`組織節點使用 ltree path 維護階層,搬移節點會同步更新子節點 path。`,onCreate:()=>{if(!O){n();return}if(E.isEditing){T.current?.saveDraft();return}T.current?.startEditing()},title:`組織樹`}),w===`TABLE`?(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(i.FilterArea,{className:B.orgFilterArea,size:`sub`,children:(0,o.jsxs)(i.FilterLine,{children:[(0,o.jsx)(i.Filter,{span:3,children:(0,o.jsx)(i.FormField,{fullWidth:!0,layout:c.FormFieldLayout.VERTICAL,name:`orgUnitSearchText`,children:(0,o.jsx)(i.Input,{fullWidth:!0,onChange:e=>p(e.target.value),placeholder:`搜尋組織名稱或代碼`,size:`sub`,value:b,variant:`base`})})}),(0,o.jsx)(i.Filter,{span:2,children:(0,o.jsx)(i.FormField,{fullWidth:!0,layout:c.FormFieldLayout.VERTICAL,name:`orgUnitTypeFilter`,children:(0,o.jsx)(i.Select,{clearable:!1,fullWidth:!0,onChange:e=>m(Ke(e)),options:[...W],placeholder:`類型`,size:`sub`,value:C})})})]})}),(0,o.jsx)(`div`,{className:B.tableFrame,children:(0,o.jsx)(i.Table,{actions:e,columns:A,dataSource:[...y],fullWidth:!0,loading:t,pagination:Oe({onPageChange:u,onPageSizeChange:f,page:_,pageSize:v,total:S}),style:{minWidth:ye}})})]}):(0,o.jsx)(se,{ref:T,onCreateChild:a,onCreateRoot:n,onEditOrgUnit:s,onSaveDraft:d,onStateChange:D,orgUnits:g,saving:x})]})}function Te({actions:e,loading:t,onCreate:n,onPageChange:a,onPageSizeChange:s,onSearchTextChange:l,page:u,pageSize:d,rows:f,searchText:p,total:m}){let h=(0,r.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,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(Me,{actionLabel:`新增職位`,description:`職位提供會員歸屬與主管解析規則使用。`,onCreate:n,title:`職位`}),(0,o.jsx)(i.FilterArea,{className:B.orgFilterArea,size:`sub`,children:(0,o.jsx)(i.FilterLine,{children:(0,o.jsx)(i.Filter,{span:3,children:(0,o.jsx)(i.FormField,{fullWidth:!0,layout:c.FormFieldLayout.VERTICAL,name:`positionSearchText`,children:(0,o.jsx)(i.Input,{fullWidth:!0,onChange:e=>l(e.target.value),placeholder:`搜尋職位名稱或代碼`,size:`sub`,value:p,variant:`base`})})})})}),(0,o.jsx)(`div`,{className:B.tableFrame,children:(0,o.jsx)(i.Table,{actions:e,columns:h,dataSource:[...f],fullWidth:!0,loading:t,pagination:Oe({onPageChange:a,onPageSizeChange:s,page:u,pageSize:d,total:m}),style:{minWidth:be}})})]})}function Ee({actions:e,loading:n,onCreate:a,onActiveFilterChange:s,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,r.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,r.useMemo)(()=>m.map(t.a),[m]),w=(0,r.useMemo)(()=>v.map(t.o),[v]);return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(Me,{actionLabel:`新增歸屬`,description:`會員歸屬是 BPM 內部組織權限、主管解析與條件判斷的來源。`,onCreate:a,title:`會員歸屬`}),(0,o.jsx)(i.FilterArea,{className:[B.orgFilterArea,B.membershipFilterArea].join(` `),size:`sub`,children:(0,o.jsxs)(i.FilterLine,{children:[(0,o.jsx)(i.Filter,{span:2,children:(0,o.jsx)(i.FormField,{fullWidth:!0,layout:c.FormFieldLayout.VERTICAL,name:`membershipOrgUnitFilter`,children:(0,o.jsx)(i.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,o.jsx)(i.Filter,{span:2,children:(0,o.jsx)(i.FormField,{fullWidth:!0,layout:c.FormFieldLayout.VERTICAL,name:`membershipPositionFilter`,children:(0,o.jsx)(i.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,o.jsx)(i.Filter,{span:2,children:(0,o.jsx)(i.FormField,{fullWidth:!0,layout:c.FormFieldLayout.VERTICAL,name:`membershipStatusFilter`,children:(0,o.jsx)(i.AutoComplete,{disabledOptionsFilter:!0,emptyText:`沒有符合的狀態`,inputProps:{autoCapitalize:`none`,autoCorrect:`off`,name:`membershipStatusFilter`,spellCheck:!1},mode:`single`,name:`membershipStatusFilter`,onChange:e=>s(Ye(e)),options:[...K],placeholder:`全部狀態`,size:`sub`,value:b})})})]})}),(0,o.jsx)(`div`,{className:B.tableFrame,children:(0,o.jsx)(i.Table,{actions:e,columns:S,dataSource:[...y],fullWidth:!0,loading:n,pagination:Oe({onPageChange:u,onPageSizeChange:d,page:h,pageSize:g,total:x}),style:{minWidth:xe}})})]})}function De({actions:e,loading:t,onCreate:n,onActiveFilterChange:a,onPageChange:s,onPageSizeChange:l,onScopeTypeFilterChange:u,page:d,pageSize:f,rows:p,scopeTypeFilter:m,statusFilter:h,total:g}){let _=(0,r.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,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(Me,{actionLabel:`新增主管規則`,description:`簽核主管規則獨立於組織樹 parent,解析優先序為會員、組織、職位。`,onCreate:n,title:`簽核主管`}),(0,o.jsx)(i.FilterArea,{className:B.orgFilterArea,size:`sub`,children:(0,o.jsxs)(i.FilterLine,{children:[(0,o.jsx)(i.Filter,{span:3,children:(0,o.jsx)(i.FormField,{fullWidth:!0,layout:c.FormFieldLayout.VERTICAL,name:`managerScopeTypeFilter`,children:(0,o.jsx)(i.Select,{clearable:!1,fullWidth:!0,onChange:e=>u(Je(e)),options:[...ge],placeholder:`套用範圍`,size:`sub`,value:m})})}),(0,o.jsx)(i.Filter,{span:2,children:(0,o.jsx)(i.FormField,{fullWidth:!0,layout:c.FormFieldLayout.VERTICAL,name:`managerStatusFilter`,children:(0,o.jsx)(i.Select,{clearable:!1,fullWidth:!0,onChange:e=>a(Y(e)),options:[...K],placeholder:`狀態`,size:`sub`,value:h})})})]})}),(0,o.jsx)(`div`,{className:B.tableFrame,children:(0,o.jsx)(i.Table,{actions:e,columns:_,dataSource:[...p],fullWidth:!0,loading:t,pagination:Oe({onPageChange:s,onPageSizeChange:l,page:d,pageSize:f,total:g}),style:{minWidth:Se}})})]})}function Oe({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 ke({isTreeEditing:e,isTreeMode:t}){return t?e?`儲存`:`開始編輯`:`新增組織`}function Ae({isTreeEditing:e,isTreeMode:t}){return t?e?l.SaveIcon:l.EditIcon:l.PlusIcon}function je({hasDraftChanges:e,isTreeEditing:t,isTreeMode:n,loading:r,saving:i}){return n?t?!e||i:r:!1}function Me({actionDisabled:e=!1,actionIcon:t=l.PlusIcon,actionLabel:n,actions:r,description:a,onCreate:s,title:c}){return(0,o.jsxs)(`div`,{className:B.tableIntro,children:[(0,o.jsxs)(`div`,{children:[(0,o.jsx)(i.Typography,{component:`h2`,variant:`h3`,children:c}),(0,o.jsx)(i.Typography,{color:`text-neutral`,variant:`body`,children:a})]}),(0,o.jsxs)(`div`,{className:B.tableIntroActions,children:[r,(0,o.jsx)(i.Button,{disabled:e,icon:t,iconType:`leading`,onClick:s,children:n})]})]})}function Ne({modal:e,onClose:a,onSubmit:s,orgUnits:c,saving:l}){let[u,d]=(0,r.useState)(``),[f,p]=(0,r.useState)(``),[m,h]=(0,r.useState)(null),[g,_]=(0,r.useState)(H[2]);return(0,r.useEffect)(()=>{if(!e)return;let n=e.record,r=n?.parentId??e.parentId??null,i=r?c.find(e=>e.id===r)??null:null;d(n?.code??``),p(n?.name??``),h(i?t.a(i):null),_(H.find(e=>e.id===n?.type)??H[2])},[e,c]),(0,o.jsx)(i.Modal,{cancelText:`取消`,confirmButtonProps:{disabled:!u||!f},confirmText:e?.type===`EDIT`?`儲存`:`建立`,loading:l,modalType:`standard`,onCancel:a,onClose:a,onConfirm:()=>void s({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,o.jsxs)(`div`,{className:B.modalFields,children:[(0,o.jsx)(J,{label:`代碼`,name:`orgCode`,onChange:d,placeholder:`例如 FIN-TW`,value:u}),(0,o.jsx)(J,{label:`名稱`,name:`orgName`,onChange:p,placeholder:`例如 財務部`,value:f}),(0,o.jsx)(n.t,{label:`類型`,name:`orgType`,children:(0,o.jsx)(i.Select,{clearable:!1,fullWidth:!0,onChange:e=>_(Ge(e)),options:[...H],placeholder:`選擇組織類型`,value:g})}),(0,o.jsx)(n.t,{label:`上層組織`,name:`parentId`,children:(0,o.jsx)(t.n,{name:`parentId`,onChange:h,orgUnits:c.filter(t=>t.id!==e?.record?.id),placeholder:`選擇上層組織`,value:m})})]})})}function Pe({modal:e,onClose:t,onSubmit:n,saving:a}){let[s,c]=(0,r.useState)(``),[l,u]=(0,r.useState)(`0`),[d,f]=(0,r.useState)(``);return(0,r.useEffect)(()=>{e&&(c(e.record?.code??``),u(String(e.record?.level??0)),f(e.record?.name??``))},[e]),(0,o.jsx)(i.Modal,{cancelText:`取消`,confirmButtonProps:{disabled:!s||!d},confirmText:e?.type===`EDIT`?`儲存`:`建立`,loading:a,modalType:`standard`,onCancel:t,onClose:t,onConfirm:()=>void n({code:s,level:Number(l),name:d}),open:!!e,showModalFooter:!0,showModalHeader:!0,size:`regular`,title:e?.type===`EDIT`?`編輯職位`:`新增職位`,children:(0,o.jsxs)(`div`,{className:B.modalFields,children:[(0,o.jsx)(J,{label:`代碼`,name:`positionCode`,onChange:c,placeholder:`例如 FIN-MGR`,value:s}),(0,o.jsx)(J,{label:`名稱`,name:`positionName`,onChange:f,placeholder:`例如 財務主管`,value:d}),(0,o.jsx)(J,{label:`職等`,name:`positionLevel`,onChange:u,placeholder:`例如 5`,value:l})]})})}function Fe({membersById:e,modal:a,onClose:s,onSubmit:c,orgUnits:l,positions:u,saving:d}){let[f,p]=(0,r.useState)(Qe()),[m,h]=(0,r.useState)(``),[g,_]=(0,r.useState)(q[1]),[v,y]=(0,r.useState)(null),[b,x]=(0,r.useState)(null),[S,C]=(0,r.useState)(null);return(0,r.useEffect)(()=>{if(!a)return;let n=a.record,r=n?e.get(n.memberId):null;p(n?.effectiveFrom??Qe()),h(n?.effectiveTo??``),_(q.find(e=>e.value===n?.isPrimary)??q[1]),y(r?t.i(r):null),x($(l.find(e=>e.id===n?.orgUnitId),t.a)),C($(u.find(e=>e.id===n?.positionId),t.o))},[e,a,l,u]),(0,o.jsx)(i.Modal,{cancelText:`取消`,confirmButtonProps:{disabled:!v||!b},confirmText:a?.type===`EDIT`?`儲存`:`建立`,loading:d,modalType:`standard`,onCancel:s,onClose:s,onConfirm:()=>void c({effectiveFrom:f,effectiveTo:m||null,isPrimary:g.value,memberId:v?.id??null,orgUnitId:b?.id??null,positionId:S?.id??null}),open:!!a,showModalFooter:!0,showModalHeader:!0,size:`regular`,title:a?.type===`EDIT`?`編輯會員歸屬`:`新增會員歸屬`,children:(0,o.jsxs)(`div`,{className:B.modalFields,children:[(0,o.jsx)(n.t,{label:`會員`,name:`memberId`,children:(0,o.jsx)(t.t,{name:`memberId`,onChange:y,placeholder:`搜尋會員姓名或信箱`,value:v})}),(0,o.jsx)(n.t,{label:`組織`,name:`orgUnitId`,children:(0,o.jsx)(t.n,{name:`orgUnitId`,onChange:x,orgUnits:l,placeholder:`選擇歸屬組織`,value:b})}),(0,o.jsx)(n.t,{label:`職位`,name:`positionId`,children:(0,o.jsx)(t.r,{name:`positionId`,onChange:C,placeholder:`選擇職位`,positions:u,value:S})}),(0,o.jsx)(n.t,{label:`歸屬類型`,name:`isPrimary`,children:(0,o.jsx)(i.Select,{clearable:!1,fullWidth:!0,onChange:e=>_(X(e)),options:[...q],placeholder:`選擇歸屬類型`,value:g})}),(0,o.jsx)(Le,{label:`生效日`,name:`membershipEffectiveFrom`,onChange:p,placeholder:`YYYY-MM-DD`,value:f}),(0,o.jsx)(Le,{label:`結束日`,name:`membershipEffectiveTo`,onChange:h,placeholder:`YYYY-MM-DD,未設定代表無期限`,value:m})]})})}function Ie({membersById:e,modal:a,onClose:s,onSubmit:c,orgUnits:l,positions:u,saving:d}){let[f,p]=(0,r.useState)(Qe()),[m,h]=(0,r.useState)(``),[g,_]=(0,r.useState)(null),[v,y]=(0,r.useState)(`0`),[b,x]=(0,r.useState)(null),[S,C]=(0,r.useState)(null),[w,T]=(0,r.useState)(null),[E,D]=(0,r.useState)(G[0]);(0,r.useEffect)(()=>{if(!a)return;let n=a.record,r=G.find(e=>e.id===n?.scopeType)??G[0];p(n?.effectiveFrom??Qe()),h(n?.effectiveTo??``),_($(n?e.get(n.managerMemberId):null,t.i)),y(String(n?.priority??0)),x(r.id===`MEMBER`?$(n?e.get(n.scopeId):null,t.i):null),C(r.id===`ORG_UNIT`?$(l.find(e=>e.id===n?.scopeId),t.a):null),T(r.id===`POSITION`?$(u.find(e=>e.id===n?.scopeId),t.o):null),D(r)},[e,a,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,o.jsx)(i.Modal,{cancelText:`取消`,confirmButtonProps:{disabled:!g||!ee||te},confirmText:a?.type===`EDIT`?`儲存`:`建立`,loading:d,modalType:`standard`,onCancel:s,onClose:s,onConfirm:()=>void c({effectiveFrom:f,effectiveTo:m||null,managerMemberId:g?.id??null,priority:Number(v),scopeId:ee??null,scopeType:E.id}),open:!!a,showModalFooter:!0,showModalHeader:!0,size:`regular`,title:a?.type===`EDIT`?`編輯主管規則`:`新增主管規則`,children:(0,o.jsxs)(`div`,{className:B.modalFields,children:[(0,o.jsx)(n.t,{label:`套用範圍`,name:`scopeType`,children:(0,o.jsx)(i.Select,{clearable:!1,fullWidth:!0,onChange:e=>D(qe(e)),options:[...G],placeholder:`選擇套用範圍`,value:E})}),E.id===`MEMBER`?(0,o.jsx)(n.t,{label:`會員`,name:`scopeMemberId`,children:(0,o.jsx)(t.t,{name:`scopeMemberId`,onChange:x,placeholder:`搜尋套用會員`,value:b})}):null,E.id===`ORG_UNIT`?(0,o.jsx)(n.t,{label:`組織`,name:`scopeOrgUnitId`,children:(0,o.jsx)(t.n,{name:`scopeOrgUnitId`,onChange:C,orgUnits:l,placeholder:`選擇套用組織`,value:S})}):null,E.id===`POSITION`?(0,o.jsx)(n.t,{label:`職位`,name:`scopePositionId`,children:(0,o.jsx)(t.r,{name:`scopePositionId`,onChange:T,placeholder:`選擇套用職位`,positions:u,value:w})}):null,(0,o.jsx)(n.t,{label:`簽核主管`,name:`managerMemberId`,children:(0,o.jsx)(t.t,{name:`managerMemberId`,onChange:_,placeholder:`搜尋簽核主管`,value:g})}),te?(0,o.jsx)(i.Typography,{color:`text-error`,variant:`caption`,children:`簽核主管不可設定為套用會員本人。`}):null,(0,o.jsx)(J,{label:`優先序`,name:`managerPriority`,onChange:y,placeholder:`例如 10`,value:v}),(0,o.jsx)(Le,{label:`生效日`,name:`managerEffectiveFrom`,onChange:p,placeholder:`YYYY-MM-DD`,value:f}),(0,o.jsx)(Le,{label:`結束日`,name:`managerEffectiveTo`,onChange:h,placeholder:`YYYY-MM-DD,未設定代表無期限`,value:m})]})})}function J({label:e,name:t,onChange:r,placeholder:a,value:s}){return(0,o.jsx)(n.t,{label:e,name:t,children:(0,o.jsx)(i.Input,{fullWidth:!0,name:t,onChange:e=>r(e.target.value),placeholder:a,value:s})})}function Le({label:e,name:t,onChange:r,placeholder:a,value:s}){return(0,o.jsx)(n.t,{label:e,name:t,children:(0,o.jsx)(i.DatePicker,{format:`YYYY-MM-DD`,fullWidth:!0,inputProps:{name:t},onChange:e=>r($e(e)),placeholder:a,value:s.trim()?s:void 0})})}function Re(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 ze(e,t){return e.scopeType===`MEMBER`?`會員:${Be(t.membersById.get(e.scopeId))}`:e.scopeType===`ORG_UNIT`?`組織:${Ve(t.orgUnitsById.get(e.scopeId))}`:`職位:${Ue(t.positionsById.get(e.scopeId))}`}function Be(e){return e?`${e.name} · ${e.email}`:`未知會員`}function Ve(e){return e?`${e.name} · ${e.code}`:`未知組織`}function He(e){return H.find(t=>t.id.toLowerCase()===e.toLowerCase())?.name??`未知類型`}function Ue(e){return e?`${e.name} · ${e.code}`:`未指定`}function We(e){return e===`MANAGERS`||e===`MEMBERSHIPS`||e===`POSITIONS`?e:`ORG_UNITS`}function Ge(e){let t=Q(e)?e:null;if(typeof t?.id==`string`){let e=t.id;return H.find(t=>t.id.toLowerCase()===e.toLowerCase())??H[2]}return H[2]}function Ke(e){let t=Q(e)?e:null;if(typeof t?.id==`string`){let e=t.id;return W.find(t=>t.id.toLowerCase()===e.toLowerCase())??U}return U}function qe(e){return Z(e,G,G[0])}function Je(e){return Z(e,ge,he)}function Y(e){return Z(e,K,_e)}function Ye(e){let t=Q(e)?e:null,n=typeof t?.id==`string`?t.id:null;return K.find(e=>e.id===n)??null}function Xe(e){let t=Q(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=Q(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 X(e){return Z(e,q,q[1])}function Z(e,t,n){let r=Q(e)?e:null,i=typeof r?.id==`string`?r.id:null;return t.find(e=>e.id===i)??n}function Q(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function $(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-BcaGmB_x.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orgs-BcaGmB_x.cjs","names":[],"sources":["../../src/lib/org-tree-draft.ts","../../src/components/org-unit-tree-draft-editor.module.scss","../../src/components/org-unit-tree-draft-editor.tsx","../../src/views/admin/orgs/orgs.module.scss","../../src/views/admin/orgs/AdminOrgsView.tsx"],"sourcesContent":["import type { OrgUnitRecord } from '@rytass/bpm-core-client/organization';\n\nexport type OrgUnitParentDraftMap = ReadonlyMap<string, string | null>;\n\nexport type OrgUnitHierarchyDraftChange = Readonly<{\n orgUnitId: string;\n parentId: string | null;\n previousParentId: string | null;\n}>;\n\nexport type OrgUnitParentAssignmentResult = Readonly<{\n message: string;\n parentDraft: OrgUnitParentDraftMap;\n status: 'INVALID' | 'UNCHANGED' | 'UPDATED';\n}>;\n\nexport function createOrgUnitParentDraftMap(\n orgUnits: readonly OrgUnitRecord[],\n): OrgUnitParentDraftMap {\n return new Map(\n orgUnits.map((orgUnit): readonly [string, string | null] => [\n orgUnit.id,\n orgUnit.parentId,\n ]),\n );\n}\n\nexport function assignOrgUnitDraftParent({\n orgUnitId,\n parentDraft,\n parentId,\n}: {\n readonly orgUnitId: string;\n readonly parentDraft: OrgUnitParentDraftMap;\n readonly parentId: string | null;\n}): OrgUnitParentAssignmentResult {\n const normalizedParentId = parentId === orgUnitId ? orgUnitId : parentId;\n const validationMessage = readOrgUnitParentValidationMessage({\n orgUnitId,\n parentDraft,\n parentId: normalizedParentId,\n });\n\n if (validationMessage) {\n return {\n message: validationMessage,\n parentDraft,\n status: 'INVALID',\n };\n }\n\n if ((parentDraft.get(orgUnitId) ?? null) === normalizedParentId) {\n return {\n message: '父子關係沒有變更。',\n parentDraft,\n status: 'UNCHANGED',\n };\n }\n\n const nextDraft = new Map(parentDraft);\n nextDraft.set(orgUnitId, normalizedParentId);\n\n return {\n message: normalizedParentId ? '已暫存新的上層組織。' : '已暫存為根節點。',\n parentDraft: nextDraft,\n status: 'UPDATED',\n };\n}\n\nexport function readOrgUnitHierarchyDraftChanges({\n orgUnits,\n parentDraft,\n}: {\n readonly orgUnits: readonly OrgUnitRecord[];\n readonly parentDraft: OrgUnitParentDraftMap;\n}): readonly OrgUnitHierarchyDraftChange[] {\n return orgUnits\n .map((orgUnit): OrgUnitHierarchyDraftChange | null => {\n const parentId = parentDraft.get(orgUnit.id) ?? null;\n\n return parentId === orgUnit.parentId\n ? null\n : {\n orgUnitId: orgUnit.id,\n parentId,\n previousParentId: orgUnit.parentId,\n };\n })\n .filter((change): change is OrgUnitHierarchyDraftChange => Boolean(change));\n}\n\nexport function readOrgUnitParentValidationMessage({\n orgUnitId,\n parentDraft,\n parentId,\n}: {\n readonly orgUnitId: string;\n readonly parentDraft: OrgUnitParentDraftMap;\n readonly parentId: string | null;\n}): string | null {\n if (!parentDraft.has(orgUnitId)) {\n return '找不到要搬移的組織節點。';\n }\n\n if (!parentId) {\n return null;\n }\n\n if (!parentDraft.has(parentId)) {\n return '找不到新的上層組織。';\n }\n\n if (parentId === orgUnitId) {\n return '組織不可成為自己的上層。';\n }\n\n return createsOrgUnitParentCycle({ orgUnitId, parentDraft, parentId })\n ? '不可搬移到自己的下層組織。'\n : null;\n}\n\nfunction createsOrgUnitParentCycle({\n orgUnitId,\n parentDraft,\n parentId,\n}: {\n readonly orgUnitId: string;\n readonly parentDraft: OrgUnitParentDraftMap;\n readonly parentId: string;\n}): boolean {\n const visitedIds = new Set<string>();\n let currentParentId: string | null = parentId;\n\n while (currentParentId) {\n if (currentParentId === orgUnitId || visitedIds.has(currentParentId)) {\n return true;\n }\n\n visitedIds.add(currentParentId);\n currentParentId = parentDraft.get(currentParentId) ?? null;\n }\n\n return false;\n}\n",".orgTreeEditor {\n display: grid;\n gap: 12px;\n min-width: 0;\n}\n\n.orgTreeSummary {\n display: grid;\n gap: 6px;\n min-width: 0;\n padding: 10px 12px;\n border: 1px solid var(--mzn-color-border, #d9dce1);\n border-radius: 8px;\n background: var(--mzn-color-bg, #fff);\n}\n\n.orgTreeChangeList {\n display: grid;\n gap: 4px;\n max-height: 128px;\n margin: 0;\n padding-left: 18px;\n overflow: auto;\n color: var(--mzn-color-text-neutral, #5f6673);\n font-size: 13px;\n}\n\n.orgTreeCanvas {\n width: 100%;\n height: min(720px, calc(100vh - 300px));\n min-height: 520px;\n overflow: hidden;\n border: 1px solid var(--mzn-color-border, #d9dce1);\n border-radius: 8px;\n background: #f7f9fc;\n}\n\n.orgTreeNode {\n display: grid;\n gap: 6px;\n width: 232px;\n min-height: 118px;\n padding: 12px;\n border: 1px solid var(--mzn-color-border, #d9dce1);\n border-radius: 8px;\n background: #fff;\n box-shadow: 0 4px 12px rgb(20 28 44 / 8%);\n}\n\n.orgTreeNodeRoot {\n min-height: 86px;\n border-style: dashed;\n background: #eef4ff;\n}\n\n.orgTreeNodeSelected {\n border-color: var(--mzn-color-primary, #0057ff);\n box-shadow: 0 0 0 3px rgb(0 87 255 / 14%);\n}\n\n.orgTreeNodeChanged {\n border-color: var(--mzn-color-primary, #0057ff);\n}\n\n.orgTreeNodeDeleted {\n opacity: 0.58;\n}\n\n.orgTreeNodeHeader {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 8px;\n min-width: 0;\n}\n\n.orgTreeNodeHeader > :global(.mzn-typography) {\n min-width: 0;\n}\n\n.orgTreeNodeBadge {\n flex: 0 0 auto;\n padding: 2px 6px;\n border-radius: 999px;\n background: #e4f0ff;\n color: var(--mzn-color-primary, #0057ff);\n font-size: 12px;\n line-height: 18px;\n}\n\n.orgTreeNodeActions {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n padding-top: 2px;\n}\n","'use client';\n\nimport {\n ReactElement,\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n Background,\n Connection,\n ConnectionMode,\n Controls,\n Edge,\n Handle,\n MiniMap,\n Node,\n NodeProps,\n NodeTypes,\n OnNodeDrag,\n OnNodesChange,\n Position,\n ReactFlow,\n ReactFlowInstance,\n applyNodeChanges,\n} from '@xyflow/react';\nimport * as dagre from 'dagre';\nimport { Button, Typography } from '@mezzanine-ui/react';\nimport { EditIcon, PlusIcon } from '@mezzanine-ui/icons';\nimport type { OrgUnitRecord, OrgUnitType } from '@rytass/bpm-core-client/organization';\nimport {\n OrgUnitHierarchyDraftChange,\n OrgUnitParentDraftMap,\n assignOrgUnitDraftParent,\n createOrgUnitParentDraftMap,\n readOrgUnitHierarchyDraftChanges,\n readOrgUnitParentValidationMessage,\n} from '../lib/org-tree-draft';\nimport styles from './org-unit-tree-draft-editor.module.scss';\n\ntype OrgUnitTreeFlowData = Readonly<{\n changed: boolean;\n childCount: number;\n code: string;\n collapsed: boolean;\n deleted: boolean;\n isEditing: boolean;\n isSyntheticRoot: boolean;\n name: string;\n onCreateChild: (parentId: string | null) => void;\n onEdit: (orgUnitId: string) => void;\n onToggleCollapse: (nodeId: string) => void;\n orgUnitId: string | null;\n parentLabel: string;\n path: string;\n typeLabel: string;\n}>;\n\ntype OrgUnitTreeNode = Node<OrgUnitTreeFlowData, 'orgUnit'>;\ntype OrgUnitTreeEdge = Edge<Record<string, never>>;\ntype OrgUnitTreeFlowInstance = ReactFlowInstance<\n OrgUnitTreeNode,\n OrgUnitTreeEdge\n>;\n\ntype OrgUnitTreeFlowElements = Readonly<{\n bounds: Readonly<{ height: number; width: number }>;\n edges: readonly OrgUnitTreeEdge[];\n nodes: readonly OrgUnitTreeNode[];\n rootCenter: Readonly<{ x: number; y: number }>;\n}>;\n\nexport type OrgUnitTreeDraftEditorHandle = Readonly<{\n cancelEditing: () => void;\n saveDraft: () => Promise<void>;\n startEditing: () => void;\n}>;\n\nexport type OrgUnitTreeDraftEditorState = Readonly<{\n hasDraftChanges: boolean;\n isEditing: boolean;\n}>;\n\ntype OrgUnitTreeDraftEditorProps = Readonly<{\n onCreateChild: (parentId: string) => void;\n onCreateRoot: () => void;\n onEditOrgUnit: (orgUnit: OrgUnitRecord) => void;\n onSaveDraft?: (\n changes: readonly OrgUnitHierarchyDraftChange[],\n ) => Promise<void>;\n onStateChange: (state: OrgUnitTreeDraftEditorState) => void;\n orgUnits: readonly OrgUnitRecord[];\n saving: boolean;\n}>;\n\nconst ORG_TREE_ROOT_ID = '__org-tree-root__';\nconst ORG_TREE_NODE_WIDTH = 232;\nconst ORG_TREE_NODE_HEIGHT = 118;\nconst ORG_TREE_ROOT_WIDTH = 232;\nconst ORG_TREE_ROOT_HEIGHT = 86;\nconst ORG_TREE_DROP_DISTANCE = 320;\n\n// Zoom bounds for the ReactFlow canvas. `minZoom` is computed per layout so\n// that fitView can shrink a very wide/tall tree enough to reveal the whole\n// graph; a fixed minZoom (e.g. 0.25) leaves huge trees clipped off-screen.\nconst ORG_TREE_MAX_ZOOM = 1.4;\nconst ORG_TREE_BASE_MIN_ZOOM = 0.25;\n// Absolute lowest zoom; keeps even an extremely wide tree (tens of thousands of\n// px across) fully fittable while never reaching 0.\nconst ORG_TREE_MIN_ZOOM_FLOOR = 0.005;\n// Reference viewport side (px) the fit-all zoom should still work in; minZoom is\n// derived as reference / longest-graph-side, clamped between the floor and base.\n// A small reference keeps fitView from being clamped on narrow viewports.\nconst ORG_TREE_MIN_ZOOM_REFERENCE = 250;\n// Above this node count the MiniMap turns into an unreadable black block and\n// adds render cost, so it is hidden for large trees.\nconst ORG_TREE_MINIMAP_MAX_NODES = 80;\n\n// Initial viewport strategy. A very wide/deep tree fitted to the whole graph\n// collapses into an unreadable thin line at ~0.05 zoom, so instead of fitView\n// we open large trees at a readable zoom anchored on the root node and let the\n// user pan/zoom. Small trees still open with fitView.\nconst ORG_TREE_READABLE_ZOOM = 0.85;\n// If fitView would land at or above this zoom the tree is small enough to open\n// fully; below it we switch to the readable-anchored-on-root strategy.\nconst ORG_TREE_FIT_READABLE_MIN_ZOOM = 0.7;\n// Reference viewport used to estimate the fitView zoom before the canvas is\n// measured (the real canvas is ~1000-1400 x 520-720).\nconst ORG_TREE_VIEWPORT_REF_WIDTH = 1200;\nconst ORG_TREE_VIEWPORT_REF_HEIGHT = 600;\n// Above this visible-node count a freshly loaded large tree starts collapsed to\n// `ORG_TREE_INITIAL_EXPAND_DEPTH` levels so it opens readable instead of\n// exploding into hundreds of side-by-side nodes.\nconst ORG_TREE_LARGE_NODE_COUNT = 60;\n// Depth (synthetic root = 0, top-level org units = 1) kept expanded on the\n// initial load of a large tree; nodes at or below this depth start collapsed so\n// only the root plus this many org levels show, and the user drills down.\nconst ORG_TREE_INITIAL_EXPAND_DEPTH = 3;\n// A single expanded level wider than this puts too many nodes side by side for\n// the readable opening zoom (each level row costs ~276px per node), so the\n// initial expansion also stops before any level that would exceed this count.\nconst ORG_TREE_INITIAL_EXPAND_LAYER_LIMIT = 12;\n\nconst ORG_UNIT_TYPE_LABELS: Readonly<Record<Uppercase<OrgUnitType>, string>> = {\n COMPANY: '公司',\n DEPARTMENT: '部門',\n DIVISION: '事業群',\n TEAM: '小組',\n};\n\nconst orgUnitTreeNodeTypes: NodeTypes = {\n orgUnit: OrgUnitTreeNodeCard,\n};\n\nexport const OrgUnitTreeDraftEditor = forwardRef<\n OrgUnitTreeDraftEditorHandle,\n OrgUnitTreeDraftEditorProps\n>(function OrgUnitTreeDraftEditor(\n {\n onCreateChild,\n onCreateRoot,\n onEditOrgUnit,\n onSaveDraft,\n onStateChange,\n orgUnits,\n },\n ref,\n): ReactElement {\n const [isEditing, setIsEditing] = useState(false);\n const [draftMessage, setDraftMessage] = useState<string | null>(null);\n const [selectedOrgUnitId, setSelectedOrgUnitId] = useState<string | null>(\n null,\n );\n const [parentDraft, setParentDraft] = useState<OrgUnitParentDraftMap>(() =>\n createOrgUnitParentDraftMap(orgUnits),\n );\n const [collapsedIds, setCollapsedIds] = useState<ReadonlySet<string>>(() =>\n createDefaultCollapsedOrgUnitIds(orgUnits, createOrgUnitParentDraftMap(orgUnits)),\n );\n const [flowNodes, setFlowNodes] = useState<readonly OrgUnitTreeNode[]>([]);\n const flowInstanceRef = useRef<OrgUnitTreeFlowInstance | null>(null);\n const pendingFocusNodeIdRef = useRef<string | null>(null);\n\n const handleToggleCollapse = useCallback((nodeId: string): void => {\n pendingFocusNodeIdRef.current = nodeId;\n setCollapsedIds((current) => {\n const next = new Set(current);\n\n if (next.has(nodeId)) {\n next.delete(nodeId);\n } else {\n next.add(nodeId);\n }\n\n return next;\n });\n }, []);\n\n const orgUnitsById = useMemo(\n (): ReadonlyMap<string, OrgUnitRecord> =>\n new Map(orgUnits.map((orgUnit) => [orgUnit.id, orgUnit])),\n [orgUnits],\n );\n const draftChanges = useMemo(\n (): readonly OrgUnitHierarchyDraftChange[] =>\n readOrgUnitHierarchyDraftChanges({ orgUnits, parentDraft }),\n [orgUnits, parentDraft],\n );\n const flowElements = useMemo(\n (): OrgUnitTreeFlowElements =>\n createOrgUnitTreeFlowElements({\n collapsedIds,\n isEditing,\n onCreateChild: (parentId): void => {\n if (parentId) {\n onCreateChild(parentId);\n } else {\n onCreateRoot();\n }\n },\n onEditOrgUnit: (orgUnitId): void => {\n const orgUnit = orgUnitsById.get(orgUnitId);\n\n if (orgUnit) {\n onEditOrgUnit(orgUnit);\n }\n },\n onToggleCollapse: handleToggleCollapse,\n orgUnits,\n orgUnitsById,\n parentDraft,\n selectedOrgUnitId,\n }),\n [\n collapsedIds,\n handleToggleCollapse,\n isEditing,\n onCreateChild,\n onCreateRoot,\n onEditOrgUnit,\n orgUnits,\n orgUnitsById,\n parentDraft,\n selectedOrgUnitId,\n ],\n );\n const flowElementsRef = useRef(flowElements);\n flowElementsRef.current = flowElements;\n const hasDraftChanges = draftChanges.length > 0;\n const minZoom = useMemo((): number => {\n const largestSide = Math.max(\n flowElements.bounds.width,\n flowElements.bounds.height,\n );\n\n if (largestSide <= 0) {\n return ORG_TREE_BASE_MIN_ZOOM;\n }\n\n return Math.min(\n ORG_TREE_BASE_MIN_ZOOM,\n Math.max(\n ORG_TREE_MIN_ZOOM_FLOOR,\n ORG_TREE_MIN_ZOOM_REFERENCE / largestSide,\n ),\n );\n }, [flowElements.bounds.height, flowElements.bounds.width]);\n const showMiniMap = orgUnits.length <= ORG_TREE_MINIMAP_MAX_NODES;\n\n const applyInitialViewport = useCallback((): void => {\n const instance = flowInstanceRef.current;\n\n if (!instance) {\n return;\n }\n\n const { bounds, rootCenter } = flowElementsRef.current;\n const widthZoom =\n bounds.width > 0\n ? ORG_TREE_VIEWPORT_REF_WIDTH / bounds.width\n : Number.POSITIVE_INFINITY;\n const heightZoom =\n bounds.height > 0\n ? ORG_TREE_VIEWPORT_REF_HEIGHT / bounds.height\n : Number.POSITIVE_INFINITY;\n const estimatedFitZoom = Math.min(widthZoom, heightZoom);\n\n if (\n !Number.isFinite(estimatedFitZoom) ||\n estimatedFitZoom >= ORG_TREE_FIT_READABLE_MIN_ZOOM\n ) {\n instance.fitView({ padding: 0.18 });\n return;\n }\n\n // Anchor on the root at a readable zoom. The synthetic root is horizontally\n // centered over the layout, and the vertical anchor keeps the top ranks in\n // view (or vertically centers the graph when it is shorter than the\n // viewport) instead of centering on the root's own row only.\n const halfViewportHeight =\n ORG_TREE_VIEWPORT_REF_HEIGHT / (2 * ORG_TREE_READABLE_ZOOM);\n\n instance.setCenter(\n rootCenter.x,\n Math.min(bounds.height / 2, halfViewportHeight),\n {\n duration: 0,\n zoom: ORG_TREE_READABLE_ZOOM,\n },\n );\n }, []);\n\n const handleFlowInit = useCallback(\n (instance: OrgUnitTreeFlowInstance): void => {\n flowInstanceRef.current = instance;\n applyInitialViewport();\n },\n [applyInitialViewport],\n );\n\n useImperativeHandle(\n ref,\n (): OrgUnitTreeDraftEditorHandle => ({\n cancelEditing,\n saveDraft,\n startEditing,\n }),\n );\n\n useEffect((): void => {\n onStateChange({ hasDraftChanges, isEditing });\n }, [hasDraftChanges, isEditing, onStateChange]);\n\n useEffect((): void => {\n const nextParentDraft = createOrgUnitParentDraftMap(orgUnits);\n\n setParentDraft(nextParentDraft);\n setCollapsedIds(\n createDefaultCollapsedOrgUnitIds(orgUnits, nextParentDraft),\n );\n setSelectedOrgUnitId(null);\n setDraftMessage(null);\n setIsEditing(false);\n }, [orgUnits]);\n\n useEffect((): void => {\n setFlowNodes(flowElements.nodes);\n }, [flowElements.nodes]);\n\n // Apply the opening viewport once per dataset load: fitView for small trees,\n // but a readable zoom anchored on the root node for large/very-wide trees so\n // they do not collapse into an unreadable line. Runs on dataset changes only\n // (not on collapse/selection) so the user's own pan/zoom is preserved.\n useEffect((): (() => void) => {\n if (typeof window === 'undefined') {\n return (): void => undefined;\n }\n\n const frame = window.requestAnimationFrame((): void => {\n applyInitialViewport();\n });\n\n return (): void => window.cancelAnimationFrame(frame);\n }, [applyInitialViewport, orgUnits]);\n\n // A collapse/expand re-runs the dagre layout and every node shifts, so\n // re-center on the node the user toggled (keeping their zoom) — otherwise the\n // toggled subtree can land entirely off-screen and the click looks dead.\n useEffect((): void => {\n const focusNodeId = pendingFocusNodeIdRef.current;\n\n if (!focusNodeId) {\n return;\n }\n\n pendingFocusNodeIdRef.current = null;\n\n const instance = flowInstanceRef.current;\n const focusNode = flowElements.nodes.find(\n (node) => node.id === focusNodeId,\n );\n\n if (!instance || !focusNode) {\n return;\n }\n\n instance.setCenter(\n focusNode.position.x + (focusNode.width ?? ORG_TREE_NODE_WIDTH) / 2,\n focusNode.position.y + (focusNode.height ?? ORG_TREE_NODE_HEIGHT) / 2,\n { duration: 200, zoom: instance.getZoom() },\n );\n }, [flowElements.nodes]);\n\n const assignDraftParent = useCallback(\n (orgUnitId: string, parentId: string | null): void => {\n setParentDraft((currentDraft) => {\n const result = assignOrgUnitDraftParent({\n orgUnitId,\n parentDraft: currentDraft,\n parentId,\n });\n\n setDraftMessage(result.message);\n\n return result.parentDraft;\n });\n },\n [],\n );\n\n const handleConnect = useCallback(\n (connection: Connection): void => {\n if (!isEditing || !connection.target || !connection.source) {\n return;\n }\n\n const nextParentId =\n connection.source === ORG_TREE_ROOT_ID ? null : connection.source;\n\n if (connection.target === ORG_TREE_ROOT_ID) {\n setDraftMessage('根節點不能搬移到其他節點下。');\n return;\n }\n\n assignDraftParent(connection.target, nextParentId);\n },\n [assignDraftParent, isEditing],\n );\n\n const handleNodeChanges = useCallback<OnNodesChange<OrgUnitTreeNode>>(\n (changes): void => {\n if (!isEditing) {\n return;\n }\n\n setFlowNodes((currentNodes) =>\n applyNodeChanges(changes, [...currentNodes]),\n );\n },\n [isEditing],\n );\n\n const handleNodeDragStop = useCallback<OnNodeDrag<OrgUnitTreeNode>>(\n (event, node, nodes): void => {\n if (!isEditing || node.id === ORG_TREE_ROOT_ID) {\n return;\n }\n\n const nearestParent =\n readNearestParentNodeIdFromPointer(event, node.id) ??\n readNearestParentNodeId(node, nodes);\n\n if (nearestParent === undefined) {\n setDraftMessage('拖曳到目標父節點附近,或從父節點拉線到子節點。');\n return;\n }\n\n assignDraftParent(\n node.id,\n nearestParent === ORG_TREE_ROOT_ID ? null : nearestParent,\n );\n },\n [assignDraftParent, isEditing],\n );\n\n function startEditing(): void {\n setIsEditing(true);\n setParentDraft(createOrgUnitParentDraftMap(orgUnits));\n setDraftMessage('已進入編輯模式,拖曳節點或拉線只會更新前端草稿。');\n }\n\n function cancelEditing(): void {\n setIsEditing(false);\n setParentDraft(createOrgUnitParentDraftMap(orgUnits));\n setDraftMessage('已取消草稿變更。');\n }\n\n async function saveDraft(): Promise<void> {\n if (!onSaveDraft) {\n setDraftMessage('批次儲存 API 尚未接上,草稿仍保留在前端。');\n return;\n }\n\n await onSaveDraft(draftChanges);\n setIsEditing(false);\n setDraftMessage('組織樹草稿已儲存。');\n }\n\n return (\n <div className={styles.orgTreeEditor}>\n <div className={styles.orgTreeSummary}>\n <Typography color=\"text-neutral\" variant=\"caption\">\n {draftMessage ??\n (hasDraftChanges\n ? `目前有 ${draftChanges.length} 筆父子關係草稿變更。`\n : '目前沒有草稿變更。')}\n </Typography>\n {hasDraftChanges ? (\n <ul className={styles.orgTreeChangeList}>\n {draftChanges.map((change) => (\n <li key={change.orgUnitId}>\n {readOrgUnitName(change.orgUnitId, orgUnitsById)}\n {':'}\n {readOrgUnitName(change.previousParentId, orgUnitsById)}\n {' -> '}\n {readOrgUnitName(change.parentId, orgUnitsById)}\n </li>\n ))}\n </ul>\n ) : null}\n </div>\n <div className={styles.orgTreeCanvas}>\n <ReactFlow\n connectionMode={ConnectionMode.Strict}\n edges={[...flowElements.edges]}\n fitViewOptions={{ minZoom, padding: 0.18 }}\n isValidConnection={(connection): boolean =>\n isOrgTreeConnectionValid(\n { source: connection.source, target: connection.target },\n parentDraft,\n )\n }\n maxZoom={ORG_TREE_MAX_ZOOM}\n minZoom={minZoom}\n nodeTypes={orgUnitTreeNodeTypes}\n nodes={[...flowNodes]}\n nodesConnectable={isEditing}\n nodesDraggable={isEditing}\n onConnect={handleConnect}\n onInit={handleFlowInit}\n onNodeClick={(_, node): void => {\n setSelectedOrgUnitId(node.id === ORG_TREE_ROOT_ID ? null : node.id);\n }}\n onNodeDoubleClick={(_, node): void => {\n if (node.id !== ORG_TREE_ROOT_ID) {\n const orgUnit = orgUnitsById.get(node.id);\n\n if (orgUnit) {\n onEditOrgUnit(orgUnit);\n }\n }\n }}\n onNodeDragStop={handleNodeDragStop}\n onNodesChange={handleNodeChanges}\n onPaneClick={(): void => setSelectedOrgUnitId(null)}\n panOnDrag\n proOptions={{ hideAttribution: true }}\n >\n <Background />\n <Controls />\n {showMiniMap ? <MiniMap pannable zoomable /> : null}\n </ReactFlow>\n </div>\n </div>\n );\n});\n\nfunction OrgUnitTreeNodeCard({\n data,\n selected,\n}: NodeProps<OrgUnitTreeNode>): ReactElement {\n return (\n <div\n className={[\n styles.orgTreeNode,\n data.isSyntheticRoot ? styles.orgTreeNodeRoot : '',\n data.changed ? styles.orgTreeNodeChanged : '',\n data.deleted ? styles.orgTreeNodeDeleted : '',\n selected ? styles.orgTreeNodeSelected : '',\n ]\n .filter(Boolean)\n .join(' ')}\n >\n {data.isSyntheticRoot ? null : (\n <Handle\n id=\"target\"\n isConnectable={data.isEditing}\n position={Position.Top}\n type=\"target\"\n />\n )}\n <Handle\n id=\"source\"\n isConnectable={data.isEditing}\n position={Position.Bottom}\n type=\"source\"\n />\n <div className={styles.orgTreeNodeHeader}>\n <Typography\n component=\"span\"\n ellipsis\n title={data.name}\n variant=\"label-primary\"\n >\n {data.name}\n </Typography>\n {data.changed ? (\n <span className={styles.orgTreeNodeBadge}>草稿</span>\n ) : null}\n </div>\n <Typography\n color=\"text-neutral\"\n component=\"span\"\n ellipsis\n title={data.code}\n variant=\"caption\"\n >\n {data.isSyntheticRoot\n ? '根節點容器'\n : `${data.typeLabel} · ${data.code}`}\n </Typography>\n {data.isSyntheticRoot ? null : (\n <Typography\n color=\"text-neutral\"\n component=\"span\"\n ellipsis\n title={data.parentLabel}\n variant=\"caption\"\n >\n 上層:{data.parentLabel}\n </Typography>\n )}\n {/* `nopan` keeps the pane's d3-zoom from capturing pointerdown on the\n buttons: without it a real mouse click with ≥1px of jitter becomes a\n pan gesture and d3 suppresses the click before it reaches onClick. */}\n <div className={`${styles.orgTreeNodeActions} nodrag nopan`}>\n {data.childCount > 0 ? (\n <Button\n onClick={(event): void => {\n event.stopPropagation();\n data.onToggleCollapse(data.orgUnitId ?? ORG_TREE_ROOT_ID);\n }}\n size=\"sub\"\n variant=\"base-secondary\"\n >\n {data.collapsed\n ? `展開 (${data.childCount})`\n : `收合 (${data.childCount})`}\n </Button>\n ) : null}\n {data.isSyntheticRoot ? (\n <Button\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={(): void => data.onCreateChild(null)}\n size=\"sub\"\n variant=\"base-secondary\"\n >\n 新增根節點\n </Button>\n ) : (\n <>\n <Button\n icon={EditIcon}\n iconType=\"leading\"\n onClick={(): void => {\n if (data.orgUnitId) {\n data.onEdit(data.orgUnitId);\n }\n }}\n size=\"sub\"\n variant=\"base-secondary\"\n >\n 編輯\n </Button>\n <Button\n icon={PlusIcon}\n iconType=\"leading\"\n onClick={(): void => data.onCreateChild(data.orgUnitId)}\n size=\"sub\"\n variant=\"base-secondary\"\n >\n 新增子節點\n </Button>\n </>\n )}\n </div>\n </div>\n );\n}\n\nfunction buildOrgUnitChildrenMap(\n orgUnits: readonly OrgUnitRecord[],\n parentDraft: OrgUnitParentDraftMap,\n): ReadonlyMap<string, readonly string[]> {\n const childrenMap = new Map<string, readonly string[]>();\n\n orgUnits.forEach((orgUnit): void => {\n const parentKey = parentDraft.get(orgUnit.id) ?? ORG_TREE_ROOT_ID;\n\n childrenMap.set(parentKey, [\n ...(childrenMap.get(parentKey) ?? []),\n orgUnit.id,\n ]);\n });\n\n return childrenMap;\n}\n\nfunction collectVisibleOrgUnitIds({\n childrenMap,\n collapsedIds,\n}: {\n readonly childrenMap: ReadonlyMap<string, readonly string[]>;\n readonly collapsedIds: ReadonlySet<string>;\n}): ReadonlySet<string> {\n const visible = new Set<string>();\n\n const visit = (nodeId: string): void => {\n if (collapsedIds.has(nodeId)) {\n return;\n }\n\n (childrenMap.get(nodeId) ?? []).forEach((childId): void => {\n visible.add(childId);\n visit(childId);\n });\n };\n\n visit(ORG_TREE_ROOT_ID);\n\n return visible;\n}\n\nfunction createDefaultCollapsedOrgUnitIds(\n orgUnits: readonly OrgUnitRecord[],\n parentDraft: OrgUnitParentDraftMap,\n): ReadonlySet<string> {\n if (orgUnits.length <= ORG_TREE_LARGE_NODE_COUNT) {\n return new Set<string>();\n }\n\n const childrenMap = buildOrgUnitChildrenMap(orgUnits, parentDraft);\n\n // Expand level by level from the root, stopping at the depth limit or before\n // any level that would put more than the layer limit nodes side by side —\n // depth alone still lets a wide-but-shallow tree open thousands of px across.\n const expanded = new Set<string>();\n let frontier: readonly string[] = [ORG_TREE_ROOT_ID];\n let depth = 0;\n\n while (frontier.length > 0 && depth < ORG_TREE_INITIAL_EXPAND_DEPTH) {\n const nextLayer = frontier.flatMap(\n (nodeId) => childrenMap.get(nodeId) ?? [],\n );\n\n if (nextLayer.length > ORG_TREE_INITIAL_EXPAND_LAYER_LIMIT) {\n break;\n }\n\n frontier.forEach((nodeId): void => {\n expanded.add(nodeId);\n });\n frontier = nextLayer;\n depth += 1;\n }\n\n const collapsed = new Set<string>();\n\n const visit = (nodeId: string): void => {\n const children = childrenMap.get(nodeId) ?? [];\n\n if (children.length === 0) {\n return;\n }\n\n if (!expanded.has(nodeId)) {\n collapsed.add(nodeId);\n }\n\n children.forEach(visit);\n };\n\n visit(ORG_TREE_ROOT_ID);\n\n return collapsed;\n}\n\nfunction createOrgUnitTreeFlowElements({\n collapsedIds,\n isEditing,\n onCreateChild,\n onEditOrgUnit,\n onToggleCollapse,\n orgUnits,\n orgUnitsById,\n parentDraft,\n selectedOrgUnitId,\n}: {\n readonly collapsedIds: ReadonlySet<string>;\n readonly isEditing: boolean;\n readonly onCreateChild: (parentId: string | null) => void;\n readonly onEditOrgUnit: (orgUnitId: string) => void;\n readonly onToggleCollapse: (nodeId: string) => void;\n readonly orgUnits: readonly OrgUnitRecord[];\n readonly orgUnitsById: ReadonlyMap<string, OrgUnitRecord>;\n readonly parentDraft: OrgUnitParentDraftMap;\n readonly selectedOrgUnitId: string | null;\n}): OrgUnitTreeFlowElements {\n const childrenMap = buildOrgUnitChildrenMap(orgUnits, parentDraft);\n const visibleIds = collectVisibleOrgUnitIds({ childrenMap, collapsedIds });\n const visibleOrgUnits = orgUnits.filter((orgUnit) =>\n visibleIds.has(orgUnit.id),\n );\n const readChildCount = (nodeId: string): number =>\n childrenMap.get(nodeId)?.length ?? 0;\n\n const graph = new dagre.graphlib.Graph();\n graph.setDefaultEdgeLabel(() => ({}));\n graph.setGraph({ marginx: 36, marginy: 36, nodesep: 44, rankdir: 'TB' });\n graph.setNode(ORG_TREE_ROOT_ID, {\n height: ORG_TREE_ROOT_HEIGHT,\n width: ORG_TREE_ROOT_WIDTH,\n });\n visibleOrgUnits.forEach((orgUnit): void => {\n graph.setNode(orgUnit.id, {\n height: ORG_TREE_NODE_HEIGHT,\n width: ORG_TREE_NODE_WIDTH,\n });\n });\n visibleOrgUnits.forEach((orgUnit): void => {\n const parentId = parentDraft.get(orgUnit.id) ?? null;\n graph.setEdge(parentId ?? ORG_TREE_ROOT_ID, orgUnit.id);\n });\n dagre.layout(graph);\n\n const graphLabel = graph.graph();\n const bounds = {\n height: graphLabel.height ?? 0,\n width: graphLabel.width ?? 0,\n };\n const rootGraphNode = graph.node(ORG_TREE_ROOT_ID) as\n | Readonly<{ x: number; y: number }>\n | undefined;\n // Dagre's alignment pass can shove the synthetic root to the far edge of an\n // asymmetric layout (measured x=3326 on a 4030px-wide real tree), which both\n // looks broken and puts a root-anchored viewport over empty margin, so the\n // root is re-centered over the whole layout width.\n const rootCenter = {\n x: bounds.width > 0 ? bounds.width / 2 : (rootGraphNode?.x ?? 0),\n y: rootGraphNode?.y ?? 0,\n };\n\n const positionedRootNode = createOrgUnitTreeNode({\n data: {\n changed: false,\n childCount: readChildCount(ORG_TREE_ROOT_ID),\n code: ORG_TREE_ROOT_ID,\n collapsed: collapsedIds.has(ORG_TREE_ROOT_ID),\n deleted: false,\n isEditing,\n isSyntheticRoot: true,\n name: '組織根節點',\n onCreateChild,\n onEdit: onEditOrgUnit,\n onToggleCollapse,\n orgUnitId: null,\n parentLabel: '',\n path: '',\n typeLabel: '',\n },\n graph,\n height: ORG_TREE_ROOT_HEIGHT,\n id: ORG_TREE_ROOT_ID,\n selected: selectedOrgUnitId === null,\n width: ORG_TREE_ROOT_WIDTH,\n });\n const rootNode: OrgUnitTreeNode = {\n ...positionedRootNode,\n position: {\n x: rootCenter.x - ORG_TREE_ROOT_WIDTH / 2,\n y: rootCenter.y - ORG_TREE_ROOT_HEIGHT / 2,\n },\n };\n const orgNodes = visibleOrgUnits.map((orgUnit): OrgUnitTreeNode => {\n const parentId = parentDraft.get(orgUnit.id) ?? null;\n const parentLabel = readOrgUnitName(parentId, orgUnitsById);\n\n return createOrgUnitTreeNode({\n data: {\n changed: parentId !== orgUnit.parentId,\n childCount: readChildCount(orgUnit.id),\n code: orgUnit.code,\n collapsed: collapsedIds.has(orgUnit.id),\n deleted: Boolean(orgUnit.deletedAt),\n isEditing,\n isSyntheticRoot: false,\n name: orgUnit.name,\n onCreateChild,\n onEdit: onEditOrgUnit,\n onToggleCollapse,\n orgUnitId: orgUnit.id,\n parentLabel,\n path: orgUnit.path,\n typeLabel: readOrgUnitTypeLabel(orgUnit.type),\n },\n graph,\n height: ORG_TREE_NODE_HEIGHT,\n id: orgUnit.id,\n selected: selectedOrgUnitId === orgUnit.id,\n width: ORG_TREE_NODE_WIDTH,\n });\n });\n const edges = visibleOrgUnits.map((orgUnit): OrgUnitTreeEdge => {\n const parentId = parentDraft.get(orgUnit.id) ?? null;\n const changed = parentId !== orgUnit.parentId;\n\n return {\n animated: isEditing && changed,\n data: {},\n id: `org-tree-edge-${parentId ?? 'root'}-${orgUnit.id}`,\n source: parentId ?? ORG_TREE_ROOT_ID,\n sourceHandle: 'source',\n style: changed\n ? { stroke: 'var(--mzn-color-primary, #0057ff)', strokeWidth: 2 }\n : undefined,\n target: orgUnit.id,\n targetHandle: 'target',\n type: 'smoothstep',\n };\n });\n\n return {\n bounds,\n edges,\n nodes: [rootNode, ...orgNodes],\n rootCenter,\n };\n}\n\nfunction createOrgUnitTreeNode({\n data,\n graph,\n height,\n id,\n selected,\n width,\n}: {\n readonly data: OrgUnitTreeFlowData;\n readonly graph: dagre.graphlib.Graph;\n readonly height: number;\n readonly id: string;\n readonly selected: boolean;\n readonly width: number;\n}): OrgUnitTreeNode {\n const positionedNode = graph.node(id) as\n | Readonly<{ x: number; y: number }>\n | undefined;\n\n return {\n data,\n height,\n id,\n initialHeight: height,\n initialWidth: width,\n position: positionedNode\n ? {\n x: positionedNode.x - width / 2,\n y: positionedNode.y - height / 2,\n }\n : { x: 0, y: 0 },\n selected,\n sourcePosition: Position.Bottom,\n targetPosition: Position.Top,\n type: 'orgUnit',\n width,\n };\n}\n\nfunction readNearestParentNodeId(\n draggedNode: OrgUnitTreeNode,\n nodes: readonly OrgUnitTreeNode[],\n): string | undefined {\n const draggedCenter = readNodeCenter(draggedNode);\n const candidates = nodes\n .filter((node) => node.id !== draggedNode.id)\n .map(\n (node): Readonly<{ distance: number; id: string }> => ({\n distance: readDistance(draggedCenter, readNodeCenter(node)),\n id: node.id,\n }),\n )\n .filter((candidate) => candidate.distance <= ORG_TREE_DROP_DISTANCE)\n .sort((left, right) => left.distance - right.distance);\n\n return candidates[0]?.id;\n}\n\nfunction readNearestParentNodeIdFromPointer(\n event: unknown,\n draggedNodeId: string,\n): string | undefined {\n const point = readPointerPoint(event);\n\n if (!point) {\n return undefined;\n }\n\n const candidates = Array.from(\n document.querySelectorAll<HTMLElement>('.react-flow__node[data-id]'),\n )\n .map((element): Readonly<{ distance: number; id: string }> | null => {\n const id = element.dataset['id'];\n\n if (!id || id === draggedNodeId) {\n return null;\n }\n\n const rect = element.getBoundingClientRect();\n const center = {\n x: rect.left + rect.width / 2,\n y: rect.top + rect.height / 2,\n };\n\n return {\n distance: readDistance(point, center),\n id,\n };\n })\n .filter(\n (\n candidate,\n ): candidate is Readonly<{ distance: number; id: string }> =>\n Boolean(candidate),\n )\n .filter((candidate) => candidate.distance <= ORG_TREE_DROP_DISTANCE)\n .sort((left, right) => left.distance - right.distance);\n\n return candidates[0]?.id;\n}\n\nfunction readPointerPoint(\n event: unknown,\n): Readonly<{ x: number; y: number }> | null {\n if (!isPointerEventLike(event)) {\n return null;\n }\n\n return { x: event.clientX, y: event.clientY };\n}\n\nfunction isPointerEventLike(\n event: unknown,\n): event is Readonly<{ clientX: number; clientY: number }> {\n return (\n typeof event === 'object' &&\n event !== null &&\n 'clientX' in event &&\n 'clientY' in event &&\n typeof event.clientX === 'number' &&\n typeof event.clientY === 'number'\n );\n}\n\nfunction readNodeCenter(\n node: OrgUnitTreeNode,\n): Readonly<{ x: number; y: number }> {\n return {\n x: node.position.x + (node.width ?? ORG_TREE_NODE_WIDTH) / 2,\n y: node.position.y + (node.height ?? ORG_TREE_NODE_HEIGHT) / 2,\n };\n}\n\nfunction readDistance(\n source: Readonly<{ x: number; y: number }>,\n target: Readonly<{ x: number; y: number }>,\n): number {\n return Math.hypot(source.x - target.x, source.y - target.y);\n}\n\nfunction isOrgTreeConnectionValid(\n connection: Readonly<{ source: string | null; target: string | null }>,\n parentDraft: OrgUnitParentDraftMap,\n): boolean {\n if (!connection.source || !connection.target) {\n return false;\n }\n\n if (connection.target === ORG_TREE_ROOT_ID) {\n return false;\n }\n\n return (\n readOrgUnitParentValidationMessage({\n orgUnitId: connection.target,\n parentDraft,\n parentId:\n connection.source === ORG_TREE_ROOT_ID ? null : connection.source,\n }) === null\n );\n}\n\nfunction readOrgUnitName(\n orgUnitId: string | null,\n orgUnitsById: ReadonlyMap<string, OrgUnitRecord>,\n): string {\n if (!orgUnitId) {\n return '根節點';\n }\n\n const orgUnit = orgUnitsById.get(orgUnitId);\n\n return orgUnit ? `${orgUnit.name} · ${orgUnit.code}` : '未知組織';\n}\n\nfunction readOrgUnitTypeLabel(type: OrgUnitType): string {\n const normalizedType = type.toUpperCase() as Uppercase<OrgUnitType>;\n\n return ORG_UNIT_TYPE_LABELS[normalizedType] ?? '未知類型';\n}\n",".tableIntroActions {\n display: inline-flex;\n align-items: center;\n justify-content: flex-end;\n gap: 8px;\n flex: 0 0 auto;\n max-width: 100%;\n}\n\n.tableIntroActions > :global(.mzn-button) {\n flex: 0 0 auto;\n}\n\n.modalFields {\n display: grid;\n gap: 12px;\n width: 100%;\n\n :global(.mzn-form-field--horizontal) {\n align-items: flex-start;\n }\n\n :global(.mzn-form-field--horizontal .mzn-form-field__label-area) {\n flex: 0 0 120px;\n width: 120px;\n min-width: 120px;\n white-space: nowrap;\n }\n\n :global(.mzn-form-field--horizontal .mzn-form-field__label) {\n flex-wrap: nowrap;\n white-space: nowrap;\n }\n\n :global(.mzn-form-field--horizontal .mzn-form-field__data-entry) {\n flex: 1 1 auto;\n align-items: stretch;\n min-width: 0;\n max-width: none;\n }\n\n :global(.mzn-form-field__control-field-slot--main) {\n width: 100%;\n min-width: 0;\n }\n\n :global(.mzn-auto-complete) {\n width: 100%;\n min-width: 0;\n }\n\n :global(.mzn-input),\n :global(.mzn-input-container),\n :global(.mzn-picker),\n :global(.mzn-select),\n :global(.mzn-select-trigger),\n :global(.mzn-text-field) {\n width: 100%;\n min-width: 0 !important;\n }\n\n :global(.mzn-select-trigger__input) {\n width: 100%;\n min-width: 0 !important;\n text-overflow: ellipsis;\n }\n}\n\n.tableIntro {\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 16px;\n min-width: 0;\n max-width: 100%;\n margin-bottom: 12px;\n}\n\n.tableIntro > div {\n min-width: 0;\n}\n\n.tableIntro > div > * {\n overflow-wrap: anywhere;\n}\n\n.tableFrame {\n width: 100%;\n min-width: 0;\n max-width: 100%;\n overflow-x: auto;\n}\n\n.orgFilterArea {\n margin-bottom: 12px;\n\n :global(.mzn-filter-line),\n :global(.mzn-filter-area__line) {\n flex-wrap: nowrap;\n }\n\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.membershipFilterArea {\n overflow-x: auto;\n\n :global(.mzn-filter-line),\n :global(.mzn-filter-area__line) {\n align-items: center;\n flex-wrap: nowrap !important;\n min-width: 760px;\n }\n\n :global(.mzn-filter),\n :global(.mzn-filter-area__filter) {\n flex: 1 1 0;\n min-width: 0;\n }\n\n :global(.mzn-filter:nth-child(3)),\n :global(.mzn-filter-area__filter:nth-child(3)) {\n flex: 0 0 180px;\n }\n\n :global(.mzn-autocomplete) {\n width: 100%;\n min-width: 0;\n }\n}\n\n.scopeLabel {\n display: inline-flex;\n align-items: center;\n min-height: 24px;\n}\n\n@media (max-width: 960px) {\n .tableIntro {\n flex-direction: column;\n align-items: flex-start;\n }\n\n .tableIntroActions {\n justify-content: flex-start;\n }\n\n .tableIntroActions {\n flex-wrap: wrap;\n }\n\n .orgFilterArea {\n :global(.mzn-filter-line),\n :global(.mzn-filter-area__line) {\n flex-wrap: wrap;\n }\n }\n\n .membershipFilterArea {\n :global(.mzn-filter-line),\n :global(.mzn-filter-area__line) {\n align-items: stretch;\n flex-wrap: nowrap !important;\n }\n\n :global(.mzn-form-field--horizontal) {\n align-items: center;\n }\n }\n}\n","'use client';\n\nimport {\n ChangeEvent,\n ReactElement,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n AutoComplete,\n Button,\n DatePicker,\n Filter,\n FilterArea,\n FilterLine,\n FormField,\n Input,\n Modal,\n PageHeader,\n Section,\n SectionGroup,\n Select,\n Tab,\n TabItem,\n Table,\n Typography,\n} from '@mezzanine-ui/react';\nimport ContentHeader from '@mezzanine-ui/react/ContentHeader';\nimport { FormFieldLayout } from '@mezzanine-ui/core/form';\nimport type { TableActions, TableColumn } from '@mezzanine-ui/core/table';\nimport {\n CloseIcon,\n EditIcon,\n PlusIcon,\n SaveIcon,\n} from '@mezzanine-ui/icons';\nimport type { IconDefinition } from '@mezzanine-ui/icons';\nimport { BPMFormField } from '../../../components/bpm-form-field';\nimport {\n MemberOption,\n OrgUnitPicker,\n OrgUnitOption,\n PositionOption,\n PositionPicker,\n MemberPicker,\n readMemberOption,\n readOrgUnitOption,\n readPositionOption,\n} from '../../../components/admin-pickers';\nimport {\n commitOrgUnitTreeDraft,\n createManagerResolution,\n createMembership,\n createOrgUnit,\n createPosition,\n deleteManagerResolution,\n deleteMembership,\n deleteOrgUnit,\n ManagerResolutionRecord,\n ManagerResolutionScopeType,\n MembershipRecord,\n OrgUnitRecord,\n OrgUnitType,\n PositionRecord,\n readOrganizationDashboard,\n updateManagerResolution,\n updateMembership,\n updateOrgUnit,\n updatePosition,\n} from '@rytass/bpm-core-client/organization';\nimport { MemberProfileRecord, resolveMembers } from '@rytass/bpm-core-client';\nimport {\n OrgUnitTreeDraftEditor,\n OrgUnitTreeDraftEditorHandle,\n OrgUnitTreeDraftEditorState,\n} from '../../../components/org-unit-tree-draft-editor';\nimport type { OrgUnitHierarchyDraftChange } from '../../../lib/org-tree-draft';\nimport styles from './orgs.module.scss';\n\ntype AdminOrgTab = 'MANAGERS' | 'MEMBERSHIPS' | 'ORG_UNITS' | 'POSITIONS';\ntype OrgUnitViewMode = 'FLOW' | 'TABLE';\n\nconst INITIAL_ORG_TREE_EDITOR_STATE: OrgUnitTreeDraftEditorState = {\n hasDraftChanges: false,\n isEditing: false,\n};\n\ntype OrgUnitRow = Readonly<\n Record<string, unknown> &\n OrgUnitRecord & {\n key: string;\n parentName: string;\n typeLabel: string;\n }\n>;\n\ntype PositionRow = Readonly<\n Record<string, unknown> &\n PositionRecord & {\n key: string;\n }\n>;\n\ntype MembershipRow = Readonly<\n Record<string, unknown> &\n MembershipRecord & {\n key: string;\n memberName: string;\n orgUnitName: string;\n positionName: string;\n }\n>;\n\ntype ManagerResolutionRow = Readonly<\n Record<string, unknown> &\n ManagerResolutionRecord & {\n key: string;\n managerName: string;\n scopeLabel: string;\n }\n>;\n\ntype OrgModalState = Readonly<{\n parentId?: string | null;\n record: OrgUnitRecord | null;\n type: 'CREATE' | 'EDIT';\n}>;\n\ntype PositionModalState = Readonly<{\n record: PositionRecord | null;\n type: 'CREATE' | 'EDIT';\n}>;\n\ntype MembershipModalState = Readonly<{\n record: MembershipRecord | null;\n type: 'CREATE' | 'EDIT';\n}>;\n\ntype ManagerModalState = Readonly<{\n record: ManagerResolutionRecord | null;\n type: 'CREATE' | 'EDIT';\n}>;\n\ntype DeleteConfirmationState = Readonly<{\n confirmText: string;\n description: string;\n id: string;\n title: string;\n type: 'MANAGER_RESOLUTION' | 'MEMBERSHIP' | 'ORG_UNIT';\n}>;\n\ntype OrgUnitTypeOption = Readonly<{\n id: OrgUnitType;\n name: string;\n}>;\n\ntype OrgUnitTypeFilterOption = Readonly<{\n id: 'ALL' | OrgUnitType;\n name: string;\n}>;\n\ntype ScopeTypeOption = Readonly<{\n id: ManagerResolutionScopeType;\n name: string;\n}>;\n\ntype ScopeTypeFilterOption = Readonly<{\n id: 'ALL' | ManagerResolutionScopeType;\n name: string;\n}>;\n\ntype ActiveFilterOption = Readonly<{\n activeOnly: boolean;\n id: 'ACTIVE' | 'ALL';\n name: string;\n}>;\n\ntype PrimaryOption = Readonly<{\n id: 'false' | 'true';\n name: string;\n value: boolean;\n}>;\n\ntype TablePaginationState = Readonly<{\n onPageChange: (page: number) => void;\n onPageSizeChange: (pageSize: number) => void;\n page: number;\n pageSize: number;\n total: number;\n}>;\n\nconst ORG_UNIT_TYPES: readonly OrgUnitTypeOption[] = [\n { id: 'COMPANY', name: '公司' },\n { id: 'DIVISION', name: '事業群' },\n { id: 'DEPARTMENT', name: '部門' },\n { id: 'TEAM', name: '小組' },\n];\nconst ALL_ORG_UNIT_TYPE_FILTER: OrgUnitTypeFilterOption = {\n id: 'ALL',\n name: '全部類型',\n};\nconst ORG_UNIT_TYPE_FILTER_OPTIONS: readonly OrgUnitTypeFilterOption[] = [\n ALL_ORG_UNIT_TYPE_FILTER,\n ...ORG_UNIT_TYPES,\n];\n\nconst SCOPE_TYPES: readonly ScopeTypeOption[] = [\n { id: 'MEMBER', name: '指定會員' },\n { id: 'ORG_UNIT', name: '指定組織' },\n { id: 'POSITION', name: '指定職位' },\n];\nconst ALL_SCOPE_TYPE_FILTER: ScopeTypeFilterOption = {\n id: 'ALL',\n name: '全部範圍',\n};\nconst SCOPE_TYPE_FILTER_OPTIONS: readonly ScopeTypeFilterOption[] = [\n ALL_SCOPE_TYPE_FILTER,\n ...SCOPE_TYPES,\n];\nconst ALL_ACTIVE_FILTER: ActiveFilterOption = {\n activeOnly: false,\n id: 'ALL',\n name: '全部狀態',\n};\nconst ACTIVE_FILTER_OPTIONS: readonly ActiveFilterOption[] = [\n ALL_ACTIVE_FILTER,\n { activeOnly: true, id: 'ACTIVE', name: '目前有效' },\n];\n\nconst PRIMARY_OPTIONS: readonly PrimaryOption[] = [\n { id: 'true', name: '主要歸屬', value: true },\n { id: 'false', name: '一般歸屬', value: false },\n];\nconst ORGANIZATION_TABLE_PAGE_SIZE_OPTIONS = [10, 20, 50];\nconst ORG_UNIT_TABLE_MIN_WIDTH = 1368;\nconst POSITION_TABLE_MIN_WIDTH = 908;\nconst MEMBERSHIP_TABLE_MIN_WIDTH = 1292;\nconst MANAGER_TABLE_MIN_WIDTH = 1124;\n\n\nexport function AdminOrgsView(): ReactElement {\n const [activeTab, setActiveTab] = useState<AdminOrgTab>('ORG_UNITS');\n const [deleteConfirmation, setDeleteConfirmation] =\n useState<DeleteConfirmationState | null>(null);\n const [lastDeleteConfirmation, setLastDeleteConfirmation] =\n useState<DeleteConfirmationState | null>(null);\n const [error, setError] = useState<string | null>(null);\n const [loading, setLoading] = useState(true);\n const [managerModal, setManagerModal] = useState<ManagerModalState | null>(\n null,\n );\n const [managerActiveFilter, setManagerActiveFilter] =\n useState<ActiveFilterOption>(ALL_ACTIVE_FILTER);\n const [managerPage, setManagerPage] = useState(1);\n const [managerPageSize, setManagerPageSize] = useState(10);\n const [managerScopeTypeFilter, setManagerScopeTypeFilter] =\n useState<ScopeTypeFilterOption>(ALL_SCOPE_TYPE_FILTER);\n const [managerTotalCount, setManagerTotalCount] = useState(0);\n const [memberProfiles, setMemberProfiles] = useState<\n readonly MemberProfileRecord[]\n >([]);\n const [membershipActiveFilter, setMembershipActiveFilter] =\n useState<ActiveFilterOption | null>(null);\n const [membershipModal, setMembershipModal] =\n useState<MembershipModalState | null>(null);\n const [membershipOrgUnitFilter, setMembershipOrgUnitFilter] =\n useState<OrgUnitOption | null>(null);\n const [membershipPage, setMembershipPage] = useState(1);\n const [membershipPageSize, setMembershipPageSize] = useState(10);\n const [membershipPositionFilter, setMembershipPositionFilter] =\n useState<PositionOption | null>(null);\n const [membershipTotalCount, setMembershipTotalCount] = useState(0);\n const [orgModal, setOrgModal] = useState<OrgModalState | null>(null);\n const [orgUnitPage, setOrgUnitPage] = useState(1);\n const [orgUnitPageSize, setOrgUnitPageSize] = useState(10);\n const [orgUnitSearchText, setOrgUnitSearchText] = useState('');\n const [orgUnitTotalCount, setOrgUnitTotalCount] = useState(0);\n const [orgUnitTypeFilter, setOrgUnitTypeFilter] =\n useState<OrgUnitTypeFilterOption>(ALL_ORG_UNIT_TYPE_FILTER);\n const [orgUnitViewMode, setOrgUnitViewMode] =\n useState<OrgUnitViewMode>('TABLE');\n const [orgUnits, setOrgUnits] = useState<readonly OrgUnitRecord[]>([]);\n const [visibleOrgUnits, setVisibleOrgUnits] = useState<\n readonly OrgUnitRecord[]\n >([]);\n const [visiblePositions, setVisiblePositions] = useState<\n readonly PositionRecord[]\n >([]);\n const [positionModal, setPositionModal] = useState<PositionModalState | null>(\n null,\n );\n const [positionPage, setPositionPage] = useState(1);\n const [positionPageSize, setPositionPageSize] = useState(10);\n const [positionSearchText, setPositionSearchText] = useState('');\n const [positionTotalCount, setPositionTotalCount] = useState(0);\n const [positions, setPositions] = useState<readonly PositionRecord[]>([]);\n const [visibleManagerResolutions, setVisibleManagerResolutions] = useState<\n readonly ManagerResolutionRecord[]\n >([]);\n const [visibleMemberships, setVisibleMemberships] = useState<\n readonly MembershipRecord[]\n >([]);\n const [saving, setSaving] = useState(false);\n\n useEffect((): void => {\n if (deleteConfirmation) {\n setLastDeleteConfirmation(deleteConfirmation);\n }\n }, [deleteConfirmation]);\n\n const visibleDeleteConfirmation =\n deleteConfirmation ?? lastDeleteConfirmation;\n\n const refreshOrganization = useCallback(async (): Promise<void> => {\n setLoading(true);\n setError(null);\n\n try {\n const dashboard = await readOrganizationDashboard({\n managerActiveOnly: managerActiveFilter.activeOnly,\n managerPage,\n managerPageSize,\n managerScopeType:\n managerScopeTypeFilter.id === 'ALL'\n ? null\n : managerScopeTypeFilter.id,\n membershipActiveOnly: membershipActiveFilter?.activeOnly ?? false,\n membershipOrgUnitId: membershipOrgUnitFilter?.id ?? null,\n membershipPage,\n membershipPageSize,\n membershipPositionId: membershipPositionFilter?.id ?? null,\n orgUnitPage,\n orgUnitPageSize,\n orgUnitSearchText,\n orgUnitType:\n orgUnitTypeFilter.id === 'ALL' ? null : orgUnitTypeFilter.id,\n positionPage,\n positionPageSize,\n positionSearchText,\n });\n const memberIds = readReferencedMemberIds(\n dashboard.memberships,\n dashboard.managerResolutions,\n );\n const profiles = await resolveMembers(memberIds);\n\n setMemberProfiles(profiles);\n setOrgUnits(dashboard.orgUnits);\n setOrgUnitTotalCount(dashboard.orgUnitCount);\n setVisibleOrgUnits(dashboard.filteredOrgUnits);\n setPositions(dashboard.positions);\n setPositionTotalCount(dashboard.positionCount);\n setVisiblePositions(dashboard.filteredPositions);\n setMembershipTotalCount(dashboard.membershipCount);\n setVisibleMemberships(dashboard.filteredMemberships);\n setManagerTotalCount(dashboard.managerResolutionCount);\n setVisibleManagerResolutions(dashboard.filteredManagerResolutions);\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setLoading(false);\n }\n }, [\n managerActiveFilter,\n managerPage,\n managerPageSize,\n managerScopeTypeFilter,\n membershipActiveFilter,\n membershipOrgUnitFilter,\n membershipPage,\n membershipPageSize,\n membershipPositionFilter,\n orgUnitPage,\n orgUnitPageSize,\n orgUnitSearchText,\n orgUnitTypeFilter,\n positionPage,\n positionPageSize,\n positionSearchText,\n ]);\n\n useEffect((): void => {\n void refreshOrganization();\n }, [refreshOrganization]);\n\n const orgUnitsById = useMemo(\n (): ReadonlyMap<string, OrgUnitRecord> =>\n new Map(orgUnits.map((orgUnit) => [orgUnit.id, orgUnit])),\n [orgUnits],\n );\n const positionsById = useMemo(\n (): ReadonlyMap<string, PositionRecord> =>\n new Map(positions.map((position) => [position.id, position])),\n [positions],\n );\n const membersById = useMemo(\n (): ReadonlyMap<string, MemberProfileRecord> =>\n new Map(memberProfiles.map((member) => [member.memberId, member])),\n [memberProfiles],\n );\n\n const orgRows = useMemo(\n (): OrgUnitRow[] =>\n visibleOrgUnits.map((orgUnit) => ({\n ...orgUnit,\n key: orgUnit.id,\n parentName: orgUnit.parentId\n ? readOrgUnitLabel(orgUnitsById.get(orgUnit.parentId))\n : '根節點',\n typeLabel: readOrgUnitTypeLabel(orgUnit.type),\n })),\n [visibleOrgUnits, orgUnitsById],\n );\n const positionRows = useMemo(\n (): PositionRow[] =>\n visiblePositions.map((position) => ({\n ...position,\n key: position.id,\n })),\n [visiblePositions],\n );\n const membershipRows = useMemo(\n (): MembershipRow[] =>\n visibleMemberships.map((membership) => ({\n ...membership,\n key: membership.id,\n memberName: readMemberLabel(membersById.get(membership.memberId)),\n orgUnitName: readOrgUnitLabel(orgUnitsById.get(membership.orgUnitId)),\n positionName: membership.positionId\n ? readPositionLabel(positionsById.get(membership.positionId))\n : '未指定',\n })),\n [membersById, visibleMemberships, orgUnitsById, positionsById],\n );\n const managerRows = useMemo(\n (): ManagerResolutionRow[] =>\n visibleManagerResolutions.map((resolution) => ({\n ...resolution,\n key: resolution.id,\n managerName: readMemberLabel(\n membersById.get(resolution.managerMemberId),\n ),\n scopeLabel: readScopeLabel(resolution, {\n membersById,\n orgUnitsById,\n positionsById,\n }),\n })),\n [visibleManagerResolutions, membersById, orgUnitsById, positionsById],\n );\n\n const orgActions = useMemo(\n (): TableActions<OrgUnitRow> => ({\n render: (record): ReturnType<TableActions<OrgUnitRow>['render']> => [\n {\n name: '編輯',\n onClick: (): void => setOrgModal({ record, type: 'EDIT' }),\n },\n {\n name: '停用',\n onClick: (): void =>\n setDeleteConfirmation({\n confirmText: '停用組織',\n description: `停用「${record.name}」後,這個組織節點將不再出現在可用組織清單中。`,\n id: record.id,\n title: '停用組織節點',\n type: 'ORG_UNIT',\n }),\n variant: 'destructive-secondary',\n },\n ],\n variant: 'base-secondary',\n width: 128,\n }),\n [],\n );\n const positionActions = useMemo(\n (): TableActions<PositionRow> => ({\n render: (record): ReturnType<TableActions<PositionRow>['render']> => [\n {\n name: '編輯',\n onClick: (): void => setPositionModal({ record, type: 'EDIT' }),\n },\n ],\n variant: 'base-secondary',\n width: 88,\n }),\n [],\n );\n const membershipActions = useMemo(\n (): TableActions<MembershipRow> => ({\n render: (record): ReturnType<TableActions<MembershipRow>['render']> => [\n {\n name: '編輯',\n onClick: (): void => setMembershipModal({ record, type: 'EDIT' }),\n },\n {\n name: '刪除',\n onClick: (): void =>\n setDeleteConfirmation({\n confirmText: '刪除歸屬',\n description: `刪除「${record.memberName}」在「${record.orgUnitName}」的會員歸屬。`,\n id: record.id,\n title: '刪除會員歸屬',\n type: 'MEMBERSHIP',\n }),\n variant: 'destructive-secondary',\n },\n ],\n variant: 'base-secondary',\n width: 128,\n }),\n [],\n );\n const managerActions = useMemo(\n (): TableActions<ManagerResolutionRow> => ({\n render: (\n record,\n ): ReturnType<TableActions<ManagerResolutionRow>['render']> => [\n {\n name: '編輯',\n onClick: (): void => setManagerModal({ record, type: 'EDIT' }),\n },\n {\n name: '刪除',\n onClick: (): void =>\n setDeleteConfirmation({\n confirmText: '刪除主管規則',\n description: `刪除「${record.scopeLabel}」指派給「${record.managerName}」的主管解析規則。`,\n id: record.id,\n title: '刪除主管解析規則',\n type: 'MANAGER_RESOLUTION',\n }),\n variant: 'destructive-secondary',\n },\n ],\n variant: 'base-secondary',\n width: 128,\n }),\n [],\n );\n\n function updateOrgUnitSearchText(value: string): void {\n setOrgUnitPage(1);\n setOrgUnitSearchText(value);\n }\n\n function updateOrgUnitTypeFilter(value: OrgUnitTypeFilterOption): void {\n setOrgUnitPage(1);\n setOrgUnitTypeFilter(value);\n }\n\n function updatePositionSearchText(value: string): void {\n setPositionPage(1);\n setPositionSearchText(value);\n }\n\n function updateMembershipActiveFilter(value: ActiveFilterOption | null): void {\n setMembershipPage(1);\n setMembershipActiveFilter(value);\n }\n\n function updateMembershipOrgUnitFilter(value: OrgUnitOption | null): void {\n setMembershipPage(1);\n setMembershipOrgUnitFilter(value);\n }\n\n function updateMembershipPositionFilter(value: PositionOption | null): void {\n setMembershipPage(1);\n setMembershipPositionFilter(value);\n }\n\n function updateManagerActiveFilter(value: ActiveFilterOption): void {\n setManagerPage(1);\n setManagerActiveFilter(value);\n }\n\n function updateManagerScopeTypeFilter(value: ScopeTypeFilterOption): void {\n setManagerPage(1);\n setManagerScopeTypeFilter(value);\n }\n\n function closeDeleteConfirmation(): void {\n if (saving) {\n return;\n }\n\n setDeleteConfirmation(null);\n }\n\n async function handleConfirmDelete(): Promise<void> {\n if (!deleteConfirmation) {\n return;\n }\n\n await runMutation(async (): Promise<void> => {\n if (deleteConfirmation.type === 'ORG_UNIT') {\n await deleteOrgUnit(deleteConfirmation.id);\n }\n\n if (deleteConfirmation.type === 'MEMBERSHIP') {\n await deleteMembership(deleteConfirmation.id);\n }\n\n if (deleteConfirmation.type === 'MANAGER_RESOLUTION') {\n await deleteManagerResolution(deleteConfirmation.id);\n }\n\n setDeleteConfirmation(null);\n });\n }\n\n async function saveOrgUnitTreeDraft(\n changes: readonly OrgUnitHierarchyDraftChange[],\n ): Promise<void> {\n setSaving(true);\n setError(null);\n\n try {\n await commitOrgUnitTreeDraft({\n moves: changes.map((change) => {\n const orgUnit = orgUnitsById.get(change.orgUnitId);\n\n return {\n baseUpdatedAt: orgUnit?.updatedAt ?? '',\n id: change.orgUnitId,\n parentId: change.parentId,\n };\n }),\n });\n await refreshOrganization();\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n throw requestError;\n } finally {\n setSaving(false);\n }\n }\n\n async function runMutation(mutation: () => Promise<void>): Promise<void> {\n setSaving(true);\n setError(null);\n\n try {\n await mutation();\n await refreshOrganization();\n } catch (requestError: unknown) {\n setError(readErrorMessage(requestError));\n } finally {\n setSaving(false);\n }\n }\n\n return (\n <>\n <PageHeader>\n <ContentHeader\n description=\"維護組織樹、職位、會員歸屬與簽核主管解析規則。\"\n title=\"組織管理\"\n />\n </PageHeader>\n\n <SectionGroup>\n <Section\n tab={\n <Tab\n activeKey={activeTab}\n onChange={(key): void => setActiveTab(readAdminOrgTab(key))}\n >\n <TabItem key=\"ORG_UNITS\">組織樹</TabItem>\n <TabItem key=\"POSITIONS\">職位</TabItem>\n <TabItem key=\"MEMBERSHIPS\">會員歸屬</TabItem>\n <TabItem key=\"MANAGERS\">簽核主管</TabItem>\n </Tab>\n }\n >\n {error ? (\n <Typography color=\"text-error\" variant=\"body\">\n {error}\n </Typography>\n ) : null}\n {activeTab === 'ORG_UNITS' ? (\n <OrgUnitPanel\n actions={orgActions}\n loading={loading}\n onCreate={(): void =>\n setOrgModal({ parentId: null, record: null, type: 'CREATE' })\n }\n onCreateChild={(parentId): void =>\n setOrgModal({ parentId, record: null, type: 'CREATE' })\n }\n onEditOrgUnit={(record): void =>\n setOrgModal({ record, type: 'EDIT' })\n }\n onPageChange={setOrgUnitPage}\n onSaveDraft={saveOrgUnitTreeDraft}\n onPageSizeChange={(pageSize): void => {\n setOrgUnitPage(1);\n setOrgUnitPageSize(pageSize);\n }}\n onSearchTextChange={updateOrgUnitSearchText}\n onTypeFilterChange={updateOrgUnitTypeFilter}\n orgUnits={orgUnits}\n page={orgUnitPage}\n pageSize={orgUnitPageSize}\n rows={orgRows}\n searchText={orgUnitSearchText}\n saving={saving}\n total={orgUnitTotalCount}\n typeFilter={orgUnitTypeFilter}\n viewMode={orgUnitViewMode}\n onViewModeChange={setOrgUnitViewMode}\n />\n ) : null}\n {activeTab === 'POSITIONS' ? (\n <PositionPanel\n actions={positionActions}\n loading={loading}\n onCreate={(): void =>\n setPositionModal({ record: null, type: 'CREATE' })\n }\n onPageChange={setPositionPage}\n onPageSizeChange={(pageSize): void => {\n setPositionPage(1);\n setPositionPageSize(pageSize);\n }}\n onSearchTextChange={updatePositionSearchText}\n page={positionPage}\n pageSize={positionPageSize}\n rows={positionRows}\n searchText={positionSearchText}\n total={positionTotalCount}\n />\n ) : null}\n {activeTab === 'MEMBERSHIPS' ? (\n <MembershipPanel\n actions={membershipActions}\n loading={loading}\n onCreate={(): void =>\n setMembershipModal({ record: null, type: 'CREATE' })\n }\n onActiveFilterChange={updateMembershipActiveFilter}\n onOrgUnitFilterChange={updateMembershipOrgUnitFilter}\n onPageChange={setMembershipPage}\n onPageSizeChange={(pageSize): void => {\n setMembershipPage(1);\n setMembershipPageSize(pageSize);\n }}\n onPositionFilterChange={updateMembershipPositionFilter}\n orgUnitFilter={membershipOrgUnitFilter}\n orgUnits={orgUnits}\n page={membershipPage}\n pageSize={membershipPageSize}\n positionFilter={membershipPositionFilter}\n positions={positions}\n rows={membershipRows}\n statusFilter={membershipActiveFilter}\n total={membershipTotalCount}\n />\n ) : null}\n {activeTab === 'MANAGERS' ? (\n <ManagerPanel\n actions={managerActions}\n loading={loading}\n onCreate={(): void =>\n setManagerModal({ record: null, type: 'CREATE' })\n }\n onActiveFilterChange={updateManagerActiveFilter}\n onPageChange={setManagerPage}\n onPageSizeChange={(pageSize): void => {\n setManagerPage(1);\n setManagerPageSize(pageSize);\n }}\n onScopeTypeFilterChange={updateManagerScopeTypeFilter}\n page={managerPage}\n pageSize={managerPageSize}\n rows={managerRows}\n scopeTypeFilter={managerScopeTypeFilter}\n statusFilter={managerActiveFilter}\n total={managerTotalCount}\n />\n ) : null}\n </Section>\n </SectionGroup>\n\n <OrgUnitModal\n modal={orgModal}\n onClose={(): void => setOrgModal(null)}\n onSubmit={(input): Promise<void> =>\n runMutation(async (): Promise<void> => {\n if (orgModal?.type === 'EDIT' && orgModal.record) {\n await updateOrgUnit({\n ...input,\n id: orgModal.record.id,\n metadataJson: null,\n });\n } else {\n await createOrgUnit({\n code: input.code ?? '',\n metadataJson: '{}',\n name: input.name ?? '',\n parentId: input.parentId,\n type: input.type ?? 'DEPARTMENT',\n });\n }\n setOrgModal(null);\n })\n }\n orgUnits={orgUnits}\n saving={saving}\n />\n <PositionModal\n modal={positionModal}\n onClose={(): void => setPositionModal(null)}\n onSubmit={(input): Promise<void> =>\n runMutation(async (): Promise<void> => {\n if (positionModal?.type === 'EDIT' && positionModal.record) {\n await updatePosition({\n ...input,\n id: positionModal.record.id,\n metadataJson: null,\n });\n } else {\n await createPosition({\n code: input.code ?? '',\n level: input.level ?? 0,\n metadataJson: '{}',\n name: input.name ?? '',\n });\n }\n setPositionModal(null);\n })\n }\n saving={saving}\n />\n <MembershipModal\n membersById={membersById}\n modal={membershipModal}\n onClose={(): void => setMembershipModal(null)}\n onSubmit={(input): Promise<void> =>\n runMutation(async (): Promise<void> => {\n if (membershipModal?.type === 'EDIT' && membershipModal.record) {\n await updateMembership({\n ...input,\n id: membershipModal.record.id,\n });\n } else {\n await createMembership({\n effectiveFrom: input.effectiveFrom ?? today(),\n effectiveTo: input.effectiveTo,\n isPrimary: input.isPrimary ?? false,\n memberId: input.memberId ?? '',\n orgUnitId: input.orgUnitId ?? '',\n positionId: input.positionId,\n });\n }\n setMembershipModal(null);\n })\n }\n orgUnits={orgUnits}\n positions={positions}\n saving={saving}\n />\n <ManagerResolutionModal\n membersById={membersById}\n modal={managerModal}\n onClose={(): void => setManagerModal(null)}\n onSubmit={(input): Promise<void> =>\n runMutation(async (): Promise<void> => {\n if (managerModal?.type === 'EDIT' && managerModal.record) {\n await updateManagerResolution({\n ...input,\n id: managerModal.record.id,\n });\n } else {\n await createManagerResolution({\n effectiveFrom: input.effectiveFrom ?? today(),\n effectiveTo: input.effectiveTo,\n managerMemberId: input.managerMemberId ?? '',\n priority: input.priority ?? 0,\n scopeId: input.scopeId ?? '',\n scopeType: input.scopeType ?? 'MEMBER',\n });\n }\n setManagerModal(null);\n })\n }\n orgUnits={orgUnits}\n positions={positions}\n saving={saving}\n />\n <Modal\n cancelText=\"取消\"\n confirmButtonProps={{ variant: 'destructive-primary' }}\n confirmText={visibleDeleteConfirmation?.confirmText ?? ''}\n loading={saving}\n modalStatusType=\"error\"\n modalType=\"standard\"\n onCancel={closeDeleteConfirmation}\n onClose={closeDeleteConfirmation}\n onConfirm={(): void => void handleConfirmDelete()}\n open={Boolean(deleteConfirmation)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n supportingText=\"此操作會立即套用,請確認後再繼續。\"\n title={visibleDeleteConfirmation?.title ?? ''}\n >\n <Typography color=\"text-neutral\" variant=\"body\">\n {visibleDeleteConfirmation?.description ?? ''}\n </Typography>\n </Modal>\n </>\n );\n}\n\nfunction OrgUnitPanel({\n actions,\n loading,\n onCreate,\n onCreateChild,\n onEditOrgUnit,\n onPageChange,\n onSaveDraft,\n onPageSizeChange,\n onSearchTextChange,\n onTypeFilterChange,\n onViewModeChange,\n orgUnits,\n page,\n pageSize,\n rows,\n searchText,\n saving,\n total,\n typeFilter,\n viewMode,\n}: {\n readonly actions: TableActions<OrgUnitRow>;\n readonly loading: boolean;\n readonly onCreate: () => void;\n readonly onCreateChild: (parentId: string) => void;\n readonly onEditOrgUnit: (record: OrgUnitRecord) => void;\n readonly onPageChange: (page: number) => void;\n readonly onSaveDraft: (\n changes: readonly OrgUnitHierarchyDraftChange[],\n ) => Promise<void>;\n readonly onPageSizeChange: (pageSize: number) => void;\n readonly onSearchTextChange: (value: string) => void;\n readonly onTypeFilterChange: (value: OrgUnitTypeFilterOption) => void;\n readonly onViewModeChange: (mode: OrgUnitViewMode) => void;\n readonly orgUnits: readonly OrgUnitRecord[];\n readonly page: number;\n readonly pageSize: number;\n readonly rows: readonly OrgUnitRow[];\n readonly searchText: string;\n readonly saving: boolean;\n readonly total: number;\n readonly typeFilter: OrgUnitTypeFilterOption;\n readonly viewMode: OrgUnitViewMode;\n}): ReactElement {\n const treeEditorRef = useRef<OrgUnitTreeDraftEditorHandle | null>(null);\n const [treeEditorState, setTreeEditorState] =\n useState<OrgUnitTreeDraftEditorState>(INITIAL_ORG_TREE_EDITOR_STATE);\n const nextViewMode: OrgUnitViewMode = viewMode === 'TABLE' ? 'FLOW' : 'TABLE';\n const viewModeToggleLabel = viewMode === 'TABLE' ? '切換樹狀圖' : '切換表格';\n const isTreeMode = viewMode === 'FLOW';\n const primaryActionLabel = readOrgUnitPrimaryActionLabel({\n isTreeMode,\n isTreeEditing: treeEditorState.isEditing,\n });\n const primaryActionIcon = readOrgUnitPrimaryActionIcon({\n isTreeMode,\n isTreeEditing: treeEditorState.isEditing,\n });\n const primaryActionDisabled = readOrgUnitPrimaryActionDisabled({\n hasDraftChanges: treeEditorState.hasDraftChanges,\n isTreeEditing: treeEditorState.isEditing,\n isTreeMode,\n loading,\n saving,\n });\n const columns = useMemo(\n (): TableColumn<OrgUnitRow>[] => [\n { dataIndex: 'code', key: 'code', title: '代碼', width: 180 },\n { dataIndex: 'name', key: 'name', title: '名稱', width: 240 },\n { dataIndex: 'typeLabel', key: 'typeLabel', title: '類型', width: 120 },\n { dataIndex: 'parentName', key: 'parentName', title: '上層', width: 280 },\n { dataIndex: 'path', key: 'path', title: 'Path', width: 420 },\n ],\n [],\n );\n\n useEffect((): void => {\n if (viewMode === 'TABLE') {\n setTreeEditorState(INITIAL_ORG_TREE_EDITOR_STATE);\n }\n }, [viewMode]);\n\n return (\n <>\n <PanelIntro\n actionDisabled={primaryActionDisabled}\n actionIcon={primaryActionIcon}\n actionLabel={primaryActionLabel}\n actions={\n <>\n <Button\n onClick={(): void => onViewModeChange(nextViewMode)}\n variant=\"base-secondary\"\n >\n {viewModeToggleLabel}\n </Button>\n {isTreeMode && treeEditorState.isEditing ? (\n <Button\n disabled={saving}\n icon={CloseIcon}\n iconType=\"leading\"\n onClick={(): void => treeEditorRef.current?.cancelEditing()}\n variant=\"base-secondary\"\n >\n 取消\n </Button>\n ) : null}\n </>\n }\n description=\"組織節點使用 ltree path 維護階層,搬移節點會同步更新子節點 path。\"\n onCreate={(): void => {\n if (!isTreeMode) {\n onCreate();\n return;\n }\n\n if (treeEditorState.isEditing) {\n void treeEditorRef.current?.saveDraft();\n return;\n }\n\n treeEditorRef.current?.startEditing();\n }}\n title=\"組織樹\"\n />\n {viewMode === 'TABLE' ? (\n <>\n <FilterArea className={styles.orgFilterArea} size=\"sub\">\n <FilterLine>\n <Filter span={3}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"orgUnitSearchText\"\n >\n <Input\n fullWidth\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n onSearchTextChange(event.target.value)\n }\n placeholder=\"搜尋組織名稱或代碼\"\n size=\"sub\"\n value={searchText}\n variant=\"base\"\n />\n </FormField>\n </Filter>\n <Filter span={2}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"orgUnitTypeFilter\"\n >\n <Select\n clearable={false}\n fullWidth\n onChange={(option): void =>\n onTypeFilterChange(readOrgUnitTypeFilterOption(option))\n }\n options={[...ORG_UNIT_TYPE_FILTER_OPTIONS]}\n placeholder=\"類型\"\n size=\"sub\"\n value={typeFilter}\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n <div className={styles.tableFrame}>\n <Table\n actions={actions}\n columns={columns}\n dataSource={[...rows]}\n fullWidth\n loading={loading}\n pagination={createTablePagination({\n onPageChange,\n onPageSizeChange,\n page,\n pageSize,\n total,\n })}\n style={{ minWidth: ORG_UNIT_TABLE_MIN_WIDTH }}\n />\n </div>\n </>\n ) : (\n <OrgUnitTreeDraftEditor\n ref={treeEditorRef}\n onCreateChild={onCreateChild}\n onCreateRoot={onCreate}\n onEditOrgUnit={onEditOrgUnit}\n onSaveDraft={onSaveDraft}\n onStateChange={setTreeEditorState}\n orgUnits={orgUnits}\n saving={saving}\n />\n )}\n </>\n );\n}\n\nfunction PositionPanel({\n actions,\n loading,\n onCreate,\n onPageChange,\n onPageSizeChange,\n onSearchTextChange,\n page,\n pageSize,\n rows,\n searchText,\n total,\n}: {\n readonly actions: TableActions<PositionRow>;\n readonly loading: boolean;\n readonly onCreate: () => void;\n readonly onPageChange: (page: number) => void;\n readonly onPageSizeChange: (pageSize: number) => void;\n readonly onSearchTextChange: (value: string) => void;\n readonly page: number;\n readonly pageSize: number;\n readonly rows: readonly PositionRow[];\n readonly searchText: string;\n readonly total: number;\n}): ReactElement {\n const columns = useMemo(\n (): TableColumn<PositionRow>[] => [\n { dataIndex: 'code', key: 'code', title: '代碼', width: 180 },\n { dataIndex: 'name', key: 'name', title: '名稱', width: 280 },\n { dataIndex: 'level', key: 'level', title: '職等', width: 96 },\n {\n dataIndex: 'updatedAt',\n key: 'updatedAt',\n title: '更新時間',\n width: 220,\n },\n ],\n [],\n );\n\n return (\n <>\n <PanelIntro\n actionLabel=\"新增職位\"\n description=\"職位提供會員歸屬與主管解析規則使用。\"\n onCreate={onCreate}\n title=\"職位\"\n />\n <FilterArea className={styles.orgFilterArea} size=\"sub\">\n <FilterLine>\n <Filter span={3}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"positionSearchText\"\n >\n <Input\n fullWidth\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n onSearchTextChange(event.target.value)\n }\n placeholder=\"搜尋職位名稱或代碼\"\n size=\"sub\"\n value={searchText}\n variant=\"base\"\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n <div className={styles.tableFrame}>\n <Table\n actions={actions}\n columns={columns}\n dataSource={[...rows]}\n fullWidth\n loading={loading}\n pagination={createTablePagination({\n onPageChange,\n onPageSizeChange,\n page,\n pageSize,\n total,\n })}\n style={{ minWidth: POSITION_TABLE_MIN_WIDTH }}\n />\n </div>\n </>\n );\n}\n\nfunction MembershipPanel({\n actions,\n loading,\n onCreate,\n onActiveFilterChange,\n onOrgUnitFilterChange,\n onPageChange,\n onPageSizeChange,\n onPositionFilterChange,\n orgUnitFilter,\n orgUnits,\n page,\n pageSize,\n positionFilter,\n positions,\n rows,\n statusFilter,\n total,\n}: {\n readonly actions: TableActions<MembershipRow>;\n readonly loading: boolean;\n readonly onCreate: () => void;\n readonly onActiveFilterChange: (value: ActiveFilterOption | null) => void;\n readonly onOrgUnitFilterChange: (value: OrgUnitOption | null) => void;\n readonly onPageChange: (page: number) => void;\n readonly onPageSizeChange: (pageSize: number) => void;\n readonly onPositionFilterChange: (value: PositionOption | null) => void;\n readonly orgUnitFilter: OrgUnitOption | null;\n readonly orgUnits: readonly OrgUnitRecord[];\n readonly page: number;\n readonly pageSize: number;\n readonly positionFilter: PositionOption | null;\n readonly positions: readonly PositionRecord[];\n readonly rows: readonly MembershipRow[];\n readonly statusFilter: ActiveFilterOption | null;\n readonly total: number;\n}): ReactElement {\n const columns = useMemo(\n (): TableColumn<MembershipRow>[] => [\n { dataIndex: 'memberName', key: 'memberName', title: '會員', width: 280 },\n {\n dataIndex: 'orgUnitName',\n key: 'orgUnitName',\n title: '組織',\n width: 280,\n },\n {\n dataIndex: 'positionName',\n key: 'positionName',\n title: '職位',\n width: 220,\n },\n {\n key: 'isPrimary',\n render: (record: MembershipRow): string =>\n record.isPrimary ? '主要' : '一般',\n title: '類型',\n width: 104,\n },\n {\n dataIndex: 'effectiveFrom',\n key: 'effectiveFrom',\n title: '生效日',\n width: 140,\n },\n {\n dataIndex: 'effectiveTo',\n key: 'effectiveTo',\n title: '結束日',\n width: 140,\n },\n ],\n [],\n );\n const orgUnitOptions = useMemo(\n (): readonly OrgUnitOption[] => orgUnits.map(readOrgUnitOption),\n [orgUnits],\n );\n const positionOptions = useMemo(\n (): readonly PositionOption[] => positions.map(readPositionOption),\n [positions],\n );\n\n return (\n <>\n <PanelIntro\n actionLabel=\"新增歸屬\"\n description=\"會員歸屬是 BPM 內部組織權限、主管解析與條件判斷的來源。\"\n onCreate={onCreate}\n title=\"會員歸屬\"\n />\n <FilterArea\n className={[styles.orgFilterArea, styles.membershipFilterArea].join(\n ' ',\n )}\n size=\"sub\"\n >\n <FilterLine>\n <Filter span={2}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"membershipOrgUnitFilter\"\n >\n <AutoComplete\n disabledOptionsFilter\n emptyText=\"沒有符合的組織\"\n inputProps={{\n autoCapitalize: 'none',\n autoCorrect: 'off',\n name: 'membershipOrgUnitFilter',\n spellCheck: false,\n }}\n mode=\"single\"\n name=\"membershipOrgUnitFilter\"\n onChange={(option): void =>\n onOrgUnitFilterChange(readOrgUnitOptionFromValue(option))\n }\n options={[...orgUnitOptions]}\n placeholder=\"全部組織\"\n size=\"sub\"\n value={orgUnitFilter}\n />\n </FormField>\n </Filter>\n <Filter span={2}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"membershipPositionFilter\"\n >\n <AutoComplete\n disabledOptionsFilter\n emptyText=\"沒有符合的職位\"\n inputProps={{\n autoCapitalize: 'none',\n autoCorrect: 'off',\n name: 'membershipPositionFilter',\n spellCheck: false,\n }}\n mode=\"single\"\n name=\"membershipPositionFilter\"\n onChange={(option): void =>\n onPositionFilterChange(readPositionOptionFromValue(option))\n }\n options={[...positionOptions]}\n placeholder=\"全部職位\"\n size=\"sub\"\n value={positionFilter}\n />\n </FormField>\n </Filter>\n <Filter span={2}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"membershipStatusFilter\"\n >\n <AutoComplete\n disabledOptionsFilter\n emptyText=\"沒有符合的狀態\"\n inputProps={{\n autoCapitalize: 'none',\n autoCorrect: 'off',\n name: 'membershipStatusFilter',\n spellCheck: false,\n }}\n mode=\"single\"\n name=\"membershipStatusFilter\"\n onChange={(option): void =>\n onActiveFilterChange(readNullableActiveFilterOption(option))\n }\n options={[...ACTIVE_FILTER_OPTIONS]}\n placeholder=\"全部狀態\"\n size=\"sub\"\n value={statusFilter}\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n <div className={styles.tableFrame}>\n <Table\n actions={actions}\n columns={columns}\n dataSource={[...rows]}\n fullWidth\n loading={loading}\n pagination={createTablePagination({\n onPageChange,\n onPageSizeChange,\n page,\n pageSize,\n total,\n })}\n style={{ minWidth: MEMBERSHIP_TABLE_MIN_WIDTH }}\n />\n </div>\n </>\n );\n}\n\nfunction ManagerPanel({\n actions,\n loading,\n onCreate,\n onActiveFilterChange,\n onPageChange,\n onPageSizeChange,\n onScopeTypeFilterChange,\n page,\n pageSize,\n rows,\n scopeTypeFilter,\n statusFilter,\n total,\n}: {\n readonly actions: TableActions<ManagerResolutionRow>;\n readonly loading: boolean;\n readonly onCreate: () => void;\n readonly onActiveFilterChange: (value: ActiveFilterOption) => void;\n readonly onPageChange: (page: number) => void;\n readonly onPageSizeChange: (pageSize: number) => void;\n readonly onScopeTypeFilterChange: (value: ScopeTypeFilterOption) => void;\n readonly page: number;\n readonly pageSize: number;\n readonly rows: readonly ManagerResolutionRow[];\n readonly scopeTypeFilter: ScopeTypeFilterOption;\n readonly statusFilter: ActiveFilterOption;\n readonly total: number;\n}): ReactElement {\n const columns = useMemo(\n (): TableColumn<ManagerResolutionRow>[] => [\n {\n dataIndex: 'scopeLabel',\n key: 'scopeLabel',\n title: '套用範圍',\n width: 320,\n },\n {\n dataIndex: 'managerName',\n key: 'managerName',\n title: '簽核主管',\n width: 300,\n },\n { dataIndex: 'priority', key: 'priority', title: '優先序', width: 96 },\n {\n dataIndex: 'effectiveFrom',\n key: 'effectiveFrom',\n title: '生效日',\n width: 140,\n },\n {\n dataIndex: 'effectiveTo',\n key: 'effectiveTo',\n title: '結束日',\n width: 140,\n },\n ],\n [],\n );\n\n return (\n <>\n <PanelIntro\n actionLabel=\"新增主管規則\"\n description=\"簽核主管規則獨立於組織樹 parent,解析優先序為會員、組織、職位。\"\n onCreate={onCreate}\n title=\"簽核主管\"\n />\n <FilterArea className={styles.orgFilterArea} size=\"sub\">\n <FilterLine>\n <Filter span={3}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"managerScopeTypeFilter\"\n >\n <Select\n clearable={false}\n fullWidth\n onChange={(option): void =>\n onScopeTypeFilterChange(readScopeTypeFilterOption(option))\n }\n options={[...SCOPE_TYPE_FILTER_OPTIONS]}\n placeholder=\"套用範圍\"\n size=\"sub\"\n value={scopeTypeFilter}\n />\n </FormField>\n </Filter>\n <Filter span={2}>\n <FormField\n fullWidth\n layout={FormFieldLayout.VERTICAL}\n name=\"managerStatusFilter\"\n >\n <Select\n clearable={false}\n fullWidth\n onChange={(option): void =>\n onActiveFilterChange(readActiveFilterOption(option))\n }\n options={[...ACTIVE_FILTER_OPTIONS]}\n placeholder=\"狀態\"\n size=\"sub\"\n value={statusFilter}\n />\n </FormField>\n </Filter>\n </FilterLine>\n </FilterArea>\n <div className={styles.tableFrame}>\n <Table\n actions={actions}\n columns={columns}\n dataSource={[...rows]}\n fullWidth\n loading={loading}\n pagination={createTablePagination({\n onPageChange,\n onPageSizeChange,\n page,\n pageSize,\n total,\n })}\n style={{ minWidth: MANAGER_TABLE_MIN_WIDTH }}\n />\n </div>\n </>\n );\n}\n\nfunction createTablePagination({\n onPageChange,\n onPageSizeChange,\n page,\n pageSize,\n total,\n}: TablePaginationState): {\n current: number;\n onChange: (page: number) => void;\n onChangePageSize: (pageSize: number) => void;\n pageSize: number;\n pageSizeLabel: string;\n pageSizeOptions: number[];\n renderResultSummary: (from: number, to: number, total: number) => string;\n showPageSizeOptions: true;\n total: number;\n} {\n return {\n current: page,\n onChange: onPageChange,\n onChangePageSize: onPageSizeChange,\n pageSize,\n pageSizeLabel: '每頁筆數',\n pageSizeOptions: [...ORGANIZATION_TABLE_PAGE_SIZE_OPTIONS],\n renderResultSummary: (from, to, resultTotal): string =>\n `顯示 ${from}-${to} 筆,共 ${resultTotal} 筆`,\n showPageSizeOptions: true,\n total,\n };\n}\n\nfunction readOrgUnitPrimaryActionLabel({\n isTreeEditing,\n isTreeMode,\n}: {\n readonly isTreeEditing: boolean;\n readonly isTreeMode: boolean;\n}): string {\n if (!isTreeMode) {\n return '新增組織';\n }\n\n return isTreeEditing ? '儲存' : '開始編輯';\n}\n\nfunction readOrgUnitPrimaryActionIcon({\n isTreeEditing,\n isTreeMode,\n}: {\n readonly isTreeEditing: boolean;\n readonly isTreeMode: boolean;\n}): IconDefinition {\n if (!isTreeMode) {\n return PlusIcon;\n }\n\n return isTreeEditing ? SaveIcon : EditIcon;\n}\n\nfunction readOrgUnitPrimaryActionDisabled({\n hasDraftChanges,\n isTreeEditing,\n isTreeMode,\n loading,\n saving,\n}: {\n readonly hasDraftChanges: boolean;\n readonly isTreeEditing: boolean;\n readonly isTreeMode: boolean;\n readonly loading: boolean;\n readonly saving: boolean;\n}): boolean {\n if (!isTreeMode) {\n return false;\n }\n\n if (!isTreeEditing) {\n return loading;\n }\n\n return !hasDraftChanges || saving;\n}\n\nfunction PanelIntro({\n actionDisabled = false,\n actionIcon = PlusIcon,\n actionLabel,\n actions,\n description,\n onCreate,\n title,\n}: {\n readonly actionDisabled?: boolean;\n readonly actionIcon?: IconDefinition;\n readonly actionLabel: string;\n readonly actions?: ReactElement;\n readonly description: string;\n readonly onCreate: () => void;\n readonly title: string;\n}): ReactElement {\n return (\n <div className={styles.tableIntro}>\n <div>\n <Typography component=\"h2\" variant=\"h3\">\n {title}\n </Typography>\n <Typography color=\"text-neutral\" variant=\"body\">\n {description}\n </Typography>\n </div>\n <div className={styles.tableIntroActions}>\n {actions}\n <Button\n disabled={actionDisabled}\n icon={actionIcon}\n iconType=\"leading\"\n onClick={onCreate}\n >\n {actionLabel}\n </Button>\n </div>\n </div>\n );\n}\n\nfunction OrgUnitModal({\n modal,\n onClose,\n onSubmit,\n orgUnits,\n saving,\n}: {\n readonly modal: OrgModalState | null;\n readonly onClose: () => void;\n readonly onSubmit: (input: {\n readonly code: string | null;\n readonly name: string | null;\n readonly parentId: string | null;\n readonly type: OrgUnitType | null;\n }) => Promise<void>;\n readonly orgUnits: readonly OrgUnitRecord[];\n readonly saving: boolean;\n}): ReactElement {\n const [code, setCode] = useState('');\n const [name, setName] = useState('');\n const [parent, setParent] = useState<OrgUnitOption | null>(null);\n const [type, setType] = useState<OrgUnitTypeOption>(ORG_UNIT_TYPES[2]);\n\n useEffect((): void => {\n if (!modal) {\n return;\n }\n\n const record = modal.record;\n const parentId = record?.parentId ?? modal.parentId ?? null;\n const parentOrgUnit = parentId\n ? (orgUnits.find((orgUnit) => orgUnit.id === parentId) ?? null)\n : null;\n\n setCode(record?.code ?? '');\n setName(record?.name ?? '');\n setParent(parentOrgUnit ? readOrgUnitOption(parentOrgUnit) : null);\n setType(\n ORG_UNIT_TYPES.find((option) => option.id === record?.type) ??\n ORG_UNIT_TYPES[2],\n );\n }, [modal, orgUnits]);\n\n return (\n <Modal\n cancelText=\"取消\"\n confirmButtonProps={{ disabled: !code || !name }}\n confirmText={modal?.type === 'EDIT' ? '儲存' : '建立'}\n loading={saving}\n modalType=\"standard\"\n onCancel={onClose}\n onClose={onClose}\n onConfirm={(): void =>\n void onSubmit({\n code,\n name,\n parentId: parent?.id ?? null,\n type: type.id,\n })\n }\n open={Boolean(modal)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n title={modal?.type === 'EDIT' ? '編輯組織' : '新增組織'}\n >\n <div className={styles.modalFields}>\n <OrgModalTextField\n label=\"代碼\"\n name=\"orgCode\"\n onChange={setCode}\n placeholder=\"例如 FIN-TW\"\n value={code}\n />\n <OrgModalTextField\n label=\"名稱\"\n name=\"orgName\"\n onChange={setName}\n placeholder=\"例如 財務部\"\n value={name}\n />\n <BPMFormField label=\"類型\" name=\"orgType\">\n <Select\n clearable={false}\n fullWidth\n onChange={(option): void => setType(readOrgUnitTypeOption(option))}\n options={[...ORG_UNIT_TYPES]}\n placeholder=\"選擇組織類型\"\n value={type}\n />\n </BPMFormField>\n <BPMFormField label=\"上層組織\" name=\"parentId\">\n <OrgUnitPicker\n name=\"parentId\"\n onChange={setParent}\n orgUnits={orgUnits.filter(\n (orgUnit) => orgUnit.id !== modal?.record?.id,\n )}\n placeholder=\"選擇上層組織\"\n value={parent}\n />\n </BPMFormField>\n </div>\n </Modal>\n );\n}\n\nfunction PositionModal({\n modal,\n onClose,\n onSubmit,\n saving,\n}: {\n readonly modal: PositionModalState | null;\n readonly onClose: () => void;\n readonly onSubmit: (input: {\n readonly code: string | null;\n readonly level: number | null;\n readonly name: string | null;\n }) => Promise<void>;\n readonly saving: boolean;\n}): ReactElement {\n const [code, setCode] = useState('');\n const [level, setLevel] = useState('0');\n const [name, setName] = useState('');\n\n useEffect((): void => {\n if (!modal) {\n return;\n }\n\n setCode(modal.record?.code ?? '');\n setLevel(String(modal.record?.level ?? 0));\n setName(modal.record?.name ?? '');\n }, [modal]);\n\n return (\n <Modal\n cancelText=\"取消\"\n confirmButtonProps={{ disabled: !code || !name }}\n confirmText={modal?.type === 'EDIT' ? '儲存' : '建立'}\n loading={saving}\n modalType=\"standard\"\n onCancel={onClose}\n onClose={onClose}\n onConfirm={(): void =>\n void onSubmit({\n code,\n level: Number(level),\n name,\n })\n }\n open={Boolean(modal)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n title={modal?.type === 'EDIT' ? '編輯職位' : '新增職位'}\n >\n <div className={styles.modalFields}>\n <OrgModalTextField\n label=\"代碼\"\n name=\"positionCode\"\n onChange={setCode}\n placeholder=\"例如 FIN-MGR\"\n value={code}\n />\n <OrgModalTextField\n label=\"名稱\"\n name=\"positionName\"\n onChange={setName}\n placeholder=\"例如 財務主管\"\n value={name}\n />\n <OrgModalTextField\n label=\"職等\"\n name=\"positionLevel\"\n onChange={setLevel}\n placeholder=\"例如 5\"\n value={level}\n />\n </div>\n </Modal>\n );\n}\n\nfunction MembershipModal({\n membersById,\n modal,\n onClose,\n onSubmit,\n orgUnits,\n positions,\n saving,\n}: {\n readonly membersById: ReadonlyMap<string, MemberProfileRecord>;\n readonly modal: MembershipModalState | null;\n readonly onClose: () => void;\n readonly onSubmit: (input: {\n readonly effectiveFrom: string | null;\n readonly effectiveTo: string | null;\n readonly isPrimary: boolean | null;\n readonly memberId: string | null;\n readonly orgUnitId: string | null;\n readonly positionId: string | null;\n }) => Promise<void>;\n readonly orgUnits: readonly OrgUnitRecord[];\n readonly positions: readonly PositionRecord[];\n readonly saving: boolean;\n}): ReactElement {\n const [effectiveFrom, setEffectiveFrom] = useState(today());\n const [effectiveTo, setEffectiveTo] = useState('');\n const [isPrimary, setIsPrimary] = useState<PrimaryOption>(PRIMARY_OPTIONS[1]);\n const [member, setMember] = useState<MemberOption | null>(null);\n const [orgUnit, setOrgUnit] = useState<OrgUnitOption | null>(null);\n const [position, setPosition] = useState<PositionOption | null>(null);\n\n useEffect((): void => {\n if (!modal) {\n return;\n }\n\n const record = modal.record;\n const profile = record ? membersById.get(record.memberId) : null;\n\n setEffectiveFrom(record?.effectiveFrom ?? today());\n setEffectiveTo(record?.effectiveTo ?? '');\n setIsPrimary(\n PRIMARY_OPTIONS.find((option) => option.value === record?.isPrimary) ??\n PRIMARY_OPTIONS[1],\n );\n setMember(profile ? readMemberOption(profile) : null);\n setOrgUnit(\n readNullableOption(\n orgUnits.find((candidate) => candidate.id === record?.orgUnitId),\n readOrgUnitOption,\n ),\n );\n setPosition(\n readNullableOption(\n positions.find((candidate) => candidate.id === record?.positionId),\n readPositionOption,\n ),\n );\n }, [membersById, modal, orgUnits, positions]);\n\n return (\n <Modal\n cancelText=\"取消\"\n confirmButtonProps={{ disabled: !member || !orgUnit }}\n confirmText={modal?.type === 'EDIT' ? '儲存' : '建立'}\n loading={saving}\n modalType=\"standard\"\n onCancel={onClose}\n onClose={onClose}\n onConfirm={(): void =>\n void onSubmit({\n effectiveFrom,\n effectiveTo: effectiveTo || null,\n isPrimary: isPrimary.value,\n memberId: member?.id ?? null,\n orgUnitId: orgUnit?.id ?? null,\n positionId: position?.id ?? null,\n })\n }\n open={Boolean(modal)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n title={modal?.type === 'EDIT' ? '編輯會員歸屬' : '新增會員歸屬'}\n >\n <div className={styles.modalFields}>\n <BPMFormField label=\"會員\" name=\"memberId\">\n <MemberPicker\n name=\"memberId\"\n onChange={setMember}\n placeholder=\"搜尋會員姓名或信箱\"\n value={member}\n />\n </BPMFormField>\n <BPMFormField label=\"組織\" name=\"orgUnitId\">\n <OrgUnitPicker\n name=\"orgUnitId\"\n onChange={setOrgUnit}\n orgUnits={orgUnits}\n placeholder=\"選擇歸屬組織\"\n value={orgUnit}\n />\n </BPMFormField>\n <BPMFormField label=\"職位\" name=\"positionId\">\n <PositionPicker\n name=\"positionId\"\n onChange={setPosition}\n placeholder=\"選擇職位\"\n positions={positions}\n value={position}\n />\n </BPMFormField>\n <BPMFormField label=\"歸屬類型\" name=\"isPrimary\">\n <Select\n clearable={false}\n fullWidth\n onChange={(option): void => setIsPrimary(readPrimaryOption(option))}\n options={[...PRIMARY_OPTIONS]}\n placeholder=\"選擇歸屬類型\"\n value={isPrimary}\n />\n </BPMFormField>\n <DateField\n label=\"生效日\"\n name=\"membershipEffectiveFrom\"\n onChange={setEffectiveFrom}\n placeholder=\"YYYY-MM-DD\"\n value={effectiveFrom}\n />\n <DateField\n label=\"結束日\"\n name=\"membershipEffectiveTo\"\n onChange={setEffectiveTo}\n placeholder=\"YYYY-MM-DD,未設定代表無期限\"\n value={effectiveTo}\n />\n </div>\n </Modal>\n );\n}\n\nfunction ManagerResolutionModal({\n membersById,\n modal,\n onClose,\n onSubmit,\n orgUnits,\n positions,\n saving,\n}: {\n readonly membersById: ReadonlyMap<string, MemberProfileRecord>;\n readonly modal: ManagerModalState | null;\n readonly onClose: () => void;\n readonly onSubmit: (input: {\n readonly effectiveFrom: string | null;\n readonly effectiveTo: string | null;\n readonly managerMemberId: string | null;\n readonly priority: number | null;\n readonly scopeId: string | null;\n readonly scopeType: ManagerResolutionScopeType | null;\n }) => Promise<void>;\n readonly orgUnits: readonly OrgUnitRecord[];\n readonly positions: readonly PositionRecord[];\n readonly saving: boolean;\n}): ReactElement {\n const [effectiveFrom, setEffectiveFrom] = useState(today());\n const [effectiveTo, setEffectiveTo] = useState('');\n const [manager, setManager] = useState<MemberOption | null>(null);\n const [priority, setPriority] = useState('0');\n const [scopeMember, setScopeMember] = useState<MemberOption | null>(null);\n const [scopeOrgUnit, setScopeOrgUnit] = useState<OrgUnitOption | null>(null);\n const [scopePosition, setScopePosition] = useState<PositionOption | null>(\n null,\n );\n const [scopeType, setScopeType] = useState<ScopeTypeOption>(SCOPE_TYPES[0]);\n\n useEffect((): void => {\n if (!modal) {\n return;\n }\n\n const record = modal.record;\n const nextScopeType =\n SCOPE_TYPES.find((option) => option.id === record?.scopeType) ??\n SCOPE_TYPES[0];\n\n setEffectiveFrom(record?.effectiveFrom ?? today());\n setEffectiveTo(record?.effectiveTo ?? '');\n setManager(\n readNullableOption(\n record ? membersById.get(record.managerMemberId) : null,\n readMemberOption,\n ),\n );\n setPriority(String(record?.priority ?? 0));\n setScopeMember(\n nextScopeType.id === 'MEMBER'\n ? readNullableOption(\n record ? membersById.get(record.scopeId) : null,\n readMemberOption,\n )\n : null,\n );\n setScopeOrgUnit(\n nextScopeType.id === 'ORG_UNIT'\n ? readNullableOption(\n orgUnits.find((candidate) => candidate.id === record?.scopeId),\n readOrgUnitOption,\n )\n : null,\n );\n setScopePosition(\n nextScopeType.id === 'POSITION'\n ? readNullableOption(\n positions.find((candidate) => candidate.id === record?.scopeId),\n readPositionOption,\n )\n : null,\n );\n setScopeType(nextScopeType);\n }, [membersById, modal, orgUnits, positions]);\n\n const scopeId =\n scopeType.id === 'MEMBER'\n ? scopeMember?.id\n : scopeType.id === 'ORG_UNIT'\n ? scopeOrgUnit?.id\n : scopePosition?.id;\n const isSelfManagerResolution = Boolean(\n scopeType.id === 'MEMBER' &&\n scopeMember?.id &&\n manager?.id &&\n scopeMember.id === manager.id,\n );\n\n return (\n <Modal\n cancelText=\"取消\"\n confirmButtonProps={{\n disabled: !manager || !scopeId || isSelfManagerResolution,\n }}\n confirmText={modal?.type === 'EDIT' ? '儲存' : '建立'}\n loading={saving}\n modalType=\"standard\"\n onCancel={onClose}\n onClose={onClose}\n onConfirm={(): void =>\n void onSubmit({\n effectiveFrom,\n effectiveTo: effectiveTo || null,\n managerMemberId: manager?.id ?? null,\n priority: Number(priority),\n scopeId: scopeId ?? null,\n scopeType: scopeType.id,\n })\n }\n open={Boolean(modal)}\n showModalFooter\n showModalHeader\n size=\"regular\"\n title={modal?.type === 'EDIT' ? '編輯主管規則' : '新增主管規則'}\n >\n <div className={styles.modalFields}>\n <BPMFormField label=\"套用範圍\" name=\"scopeType\">\n <Select\n clearable={false}\n fullWidth\n onChange={(option): void =>\n setScopeType(readScopeTypeOption(option))\n }\n options={[...SCOPE_TYPES]}\n placeholder=\"選擇套用範圍\"\n value={scopeType}\n />\n </BPMFormField>\n {scopeType.id === 'MEMBER' ? (\n <BPMFormField label=\"會員\" name=\"scopeMemberId\">\n <MemberPicker\n name=\"scopeMemberId\"\n onChange={setScopeMember}\n placeholder=\"搜尋套用會員\"\n value={scopeMember}\n />\n </BPMFormField>\n ) : null}\n {scopeType.id === 'ORG_UNIT' ? (\n <BPMFormField label=\"組織\" name=\"scopeOrgUnitId\">\n <OrgUnitPicker\n name=\"scopeOrgUnitId\"\n onChange={setScopeOrgUnit}\n orgUnits={orgUnits}\n placeholder=\"選擇套用組織\"\n value={scopeOrgUnit}\n />\n </BPMFormField>\n ) : null}\n {scopeType.id === 'POSITION' ? (\n <BPMFormField label=\"職位\" name=\"scopePositionId\">\n <PositionPicker\n name=\"scopePositionId\"\n onChange={setScopePosition}\n placeholder=\"選擇套用職位\"\n positions={positions}\n value={scopePosition}\n />\n </BPMFormField>\n ) : null}\n <BPMFormField label=\"簽核主管\" name=\"managerMemberId\">\n <MemberPicker\n name=\"managerMemberId\"\n onChange={setManager}\n placeholder=\"搜尋簽核主管\"\n value={manager}\n />\n </BPMFormField>\n {isSelfManagerResolution ? (\n <Typography color=\"text-error\" variant=\"caption\">\n 簽核主管不可設定為套用會員本人。\n </Typography>\n ) : null}\n <OrgModalTextField\n label=\"優先序\"\n name=\"managerPriority\"\n onChange={setPriority}\n placeholder=\"例如 10\"\n value={priority}\n />\n <DateField\n label=\"生效日\"\n name=\"managerEffectiveFrom\"\n onChange={setEffectiveFrom}\n placeholder=\"YYYY-MM-DD\"\n value={effectiveFrom}\n />\n <DateField\n label=\"結束日\"\n name=\"managerEffectiveTo\"\n onChange={setEffectiveTo}\n placeholder=\"YYYY-MM-DD,未設定代表無期限\"\n value={effectiveTo}\n />\n </div>\n </Modal>\n );\n}\n\nfunction OrgModalTextField({\n label,\n name,\n onChange,\n placeholder,\n value,\n}: {\n readonly label: string;\n readonly name: string;\n readonly onChange: (value: string) => void;\n readonly placeholder: string;\n readonly value: string;\n}): ReactElement {\n return (\n <BPMFormField label={label} name={name}>\n <Input\n fullWidth\n name={name}\n onChange={(event: ChangeEvent<HTMLInputElement>): void =>\n onChange(event.target.value)\n }\n placeholder={placeholder}\n value={value}\n />\n </BPMFormField>\n );\n}\n\nfunction DateField({\n label,\n name,\n onChange,\n placeholder,\n value,\n}: {\n readonly label: string;\n readonly name: string;\n readonly onChange: (value: string) => void;\n readonly placeholder: string;\n readonly value: string;\n}): ReactElement {\n return (\n <BPMFormField label={label} name={name}>\n <DatePicker\n format=\"YYYY-MM-DD\"\n fullWidth\n inputProps={{ name }}\n onChange={(nextValue): void => onChange(formatDateOnly(nextValue))}\n placeholder={placeholder}\n value={value.trim() ? value : undefined}\n />\n </BPMFormField>\n );\n}\n\nfunction readReferencedMemberIds(\n memberships: readonly MembershipRecord[],\n managerResolutions: readonly ManagerResolutionRecord[],\n): readonly string[] {\n return [\n ...new Set([\n ...memberships.map((membership) => membership.memberId),\n ...managerResolutions.map((resolution) => resolution.managerMemberId),\n ...managerResolutions\n .filter((resolution) => resolution.scopeType === 'MEMBER')\n .map((resolution) => resolution.scopeId),\n ]),\n ];\n}\n\nfunction readScopeLabel(\n resolution: ManagerResolutionRecord,\n lookup: {\n readonly membersById: ReadonlyMap<string, MemberProfileRecord>;\n readonly orgUnitsById: ReadonlyMap<string, OrgUnitRecord>;\n readonly positionsById: ReadonlyMap<string, PositionRecord>;\n },\n): string {\n if (resolution.scopeType === 'MEMBER') {\n return `會員:${readMemberLabel(lookup.membersById.get(resolution.scopeId))}`;\n }\n\n if (resolution.scopeType === 'ORG_UNIT') {\n return `組織:${readOrgUnitLabel(lookup.orgUnitsById.get(resolution.scopeId))}`;\n }\n\n return `職位:${readPositionLabel(lookup.positionsById.get(resolution.scopeId))}`;\n}\n\nfunction readMemberLabel(member: MemberProfileRecord | undefined): string {\n return member ? `${member.name} · ${member.email}` : '未知會員';\n}\n\nfunction readOrgUnitLabel(orgUnit: OrgUnitRecord | undefined): string {\n return orgUnit ? `${orgUnit.name} · ${orgUnit.code}` : '未知組織';\n}\n\nfunction readOrgUnitTypeLabel(type: OrgUnitType): string {\n return (\n ORG_UNIT_TYPES.find(\n (option) => option.id.toLowerCase() === type.toLowerCase(),\n )?.name ?? '未知類型'\n );\n}\n\nfunction readPositionLabel(position: PositionRecord | undefined): string {\n return position ? `${position.name} · ${position.code}` : '未指定';\n}\n\nfunction readAdminOrgTab(value: unknown): AdminOrgTab {\n return value === 'MANAGERS' ||\n value === 'MEMBERSHIPS' ||\n value === 'POSITIONS'\n ? value\n : 'ORG_UNITS';\n}\n\nfunction readOrgUnitTypeOption(value: unknown): OrgUnitTypeOption {\n const record = isRecord(value) ? value : null;\n\n if (typeof record?.id === 'string') {\n const id = record.id;\n\n return (\n ORG_UNIT_TYPES.find(\n (option) => option.id.toLowerCase() === id.toLowerCase(),\n ) ?? ORG_UNIT_TYPES[2]\n );\n }\n\n return ORG_UNIT_TYPES[2];\n}\n\nfunction readOrgUnitTypeFilterOption(value: unknown): OrgUnitTypeFilterOption {\n const record = isRecord(value) ? value : null;\n\n if (typeof record?.id === 'string') {\n const id = record.id;\n\n return (\n ORG_UNIT_TYPE_FILTER_OPTIONS.find(\n (option) => option.id.toLowerCase() === id.toLowerCase(),\n ) ?? ALL_ORG_UNIT_TYPE_FILTER\n );\n }\n\n return ALL_ORG_UNIT_TYPE_FILTER;\n}\n\nfunction readScopeTypeOption(value: unknown): ScopeTypeOption {\n return readOption(value, SCOPE_TYPES, SCOPE_TYPES[0]);\n}\n\nfunction readScopeTypeFilterOption(value: unknown): ScopeTypeFilterOption {\n return readOption(value, SCOPE_TYPE_FILTER_OPTIONS, ALL_SCOPE_TYPE_FILTER);\n}\n\nfunction readActiveFilterOption(value: unknown): ActiveFilterOption {\n return readOption(value, ACTIVE_FILTER_OPTIONS, ALL_ACTIVE_FILTER);\n}\n\nfunction readNullableActiveFilterOption(\n value: unknown,\n): ActiveFilterOption | null {\n const record = isRecord(value) ? value : null;\n const id = typeof record?.id === 'string' ? record.id : null;\n\n return ACTIVE_FILTER_OPTIONS.find((option) => option.id === id) ?? null;\n}\n\nfunction readOrgUnitOptionFromValue(value: unknown): OrgUnitOption | null {\n const record = isRecord(value) ? value : null;\n const id = typeof record?.id === 'string' ? record.id : null;\n const name = typeof record?.name === 'string' ? record.name : null;\n\n return id && name ? { id, name } : null;\n}\n\nfunction readPositionOptionFromValue(value: unknown): PositionOption | null {\n const record = isRecord(value) ? value : null;\n const id = typeof record?.id === 'string' ? record.id : null;\n const name = typeof record?.name === 'string' ? record.name : null;\n\n return id && name ? { id, name } : null;\n}\n\nfunction readPrimaryOption(value: unknown): PrimaryOption {\n return readOption(value, PRIMARY_OPTIONS, PRIMARY_OPTIONS[1]);\n}\n\nfunction readOption<TOption extends { readonly id: string }>(\n value: unknown,\n options: readonly TOption[],\n fallback: TOption,\n): TOption {\n const record = isRecord(value) ? value : null;\n const id = typeof record?.id === 'string' ? record.id : null;\n\n return options.find((option) => option.id === id) ?? fallback;\n}\n\nfunction isRecord(value: unknown): value is Readonly<Record<string, unknown>> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction readNullableOption<TValue, TOption>(\n value: TValue | null | undefined,\n mapper: (value: TValue) => TOption,\n): TOption | null {\n return value ? mapper(value) : null;\n}\n\nfunction today(): string {\n return formatDateParts(new Date());\n}\n\nfunction formatDateOnly(value: string | undefined): string {\n const date = value ? new Date(value) : null;\n\n return date && !Number.isNaN(date.getTime()) ? formatDateParts(date) : '';\n}\n\nfunction formatDateParts(date: Date): string {\n return `${date.getFullYear()}-${padDatePart(date.getMonth() + 1)}-${padDatePart(\n date.getDate(),\n )}`;\n}\n\nfunction padDatePart(value: number): string {\n return String(value).padStart(2, '0');\n}\n\nfunction readErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : '讀取組織資料失敗。';\n}\n"],"mappings":"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"}