1- import { IStep } from '@plumber/types'
1+ import { IStep , IStepApprovalBranch , IStepApprovalConfig } from '@plumber/types'
22
3+ import { useCallback } from 'react'
34import { useMutation } from '@apollo/client'
45import { useToast } from '@opengovsg/design-system-react'
56
6- import { StepEnumType } from '@/graphql/__generated__/graphql'
7+ import {
8+ StepConfigInput ,
9+ StepEnumType ,
10+ StepPositionInput ,
11+ } from '@/graphql/__generated__/graphql'
712import { UPDATE_STEP_POSITIONS } from '@/graphql/mutations/update-step-positions'
813import { GET_FLOW } from '@/graphql/queries/get-flow'
914
10- interface StepPositionInput {
11- id : string
12- position : number
13- type : StepEnumType
14- }
15-
1615const useReorderSteps = ( flowId : string ) => {
1716 const toast = useToast ( )
1817 const [ updateStepPositions ] = useMutation ( UPDATE_STEP_POSITIONS )
1918
19+ // TODO: write unit test for this function
20+ const calculateReorderedSteps = useCallback (
21+ ( {
22+ reorderedSteps,
23+ allSteps,
24+ mrfSteps,
25+ mrfApprovalSteps,
26+ approvalBranches,
27+ } : {
28+ reorderedSteps : IStep [ ]
29+ allSteps : IStep [ ]
30+ mrfSteps : IStep [ ]
31+ mrfApprovalSteps : IStep [ ]
32+ approvalBranches : { [ stepId : string ] : IStepApprovalBranch }
33+ } ) : StepPositionInput [ ] => {
34+ // we start from 2 because the first step is the trigger step and not part of the sortable list
35+ let nextPosition = 2
36+ let currentApprovalconfig : IStepApprovalConfig | null = null
37+ const allReorderedSteps : StepPositionInput [ ] = [ ]
38+ reorderedSteps . forEach ( ( step ) => {
39+ const isMrfStep = mrfSteps . some ( ( mrfStep ) => mrfStep . id === step . id )
40+
41+ if ( isMrfStep ) {
42+ // if the previous approval config is in the approve branch
43+ // we need to add the steps in the reject branch that was hidden
44+ if ( currentApprovalconfig ?. branch === 'approve' ) {
45+ const stepsInRejectBranch = allSteps . filter (
46+ ( step ) =>
47+ step . config ?. approval ?. branch === 'reject' &&
48+ step . config ?. approval ?. stepId === currentApprovalconfig ?. stepId ,
49+ ) as IStep [ ]
50+ stepsInRejectBranch . forEach ( ( step ) => {
51+ allReorderedSteps . push ( {
52+ id : step . id ,
53+ position : nextPosition ++ ,
54+ type : step . type as StepEnumType ,
55+ config : {
56+ approval : step . config . approval ,
57+ } as StepConfigInput ,
58+ } )
59+ } )
60+ }
61+ currentApprovalconfig = null
62+ }
63+
64+ // add the current step to the list
65+ allReorderedSteps . push ( {
66+ id : step . id ,
67+ position : nextPosition ++ ,
68+ type : step . type as StepEnumType ,
69+ config : {
70+ approval : currentApprovalconfig ,
71+ } as StepConfigInput ,
72+ } )
73+
74+ const isMrfApprovalStep = mrfApprovalSteps . some (
75+ ( mrfApprovalStep ) => mrfApprovalStep . id === step . id ,
76+ )
77+ if ( isMrfApprovalStep ) {
78+ currentApprovalconfig = {
79+ branch : approvalBranches [ step . id ] ,
80+ stepId : step . id ,
81+ }
82+ // if the current approval config is in the reject branch
83+ // we need to add the steps in the approve branch that was hidden
84+ if ( currentApprovalconfig ?. branch === 'reject' ) {
85+ const stepsInApproveBranch = allSteps . filter (
86+ ( step ) =>
87+ step . config ?. approval ?. branch === 'approve' &&
88+ step . config ?. approval ?. stepId === currentApprovalconfig ?. stepId ,
89+ ) as IStep [ ]
90+ stepsInApproveBranch . forEach ( ( step ) => {
91+ allReorderedSteps . push ( {
92+ id : step . id ,
93+ position : nextPosition ++ ,
94+ type : step . type as StepEnumType ,
95+ config : {
96+ approval : step . config . approval ,
97+ } as StepConfigInput ,
98+ } )
99+ } )
100+ }
101+ }
102+ } )
103+
104+ // all later steps not in the sortable list need not be updated since
105+ // reordering of visible steps will not affect them
106+
107+ return allReorderedSteps
108+ } ,
109+ [ ] ,
110+ )
111+
20112 const handleReorderUpdate = async ( stepPositions : StepPositionInput [ ] ) => {
21113 try {
22114 await updateStepPositions ( {
@@ -25,6 +117,7 @@ const useReorderSteps = (flowId: string) => {
25117 updateStepPositions : stepPositions . map ( ( sp ) => ( {
26118 id : sp . id ,
27119 position : sp . position ,
120+ config : sp . config ? { approval : sp . config . approval } : undefined ,
28121 __typename : 'Step' as const ,
29122 } ) ) ,
30123 } ,
@@ -37,15 +130,22 @@ const useReorderSteps = (flowId: string) => {
37130
38131 if ( flow ) {
39132 // Create a map of step positions for quick lookup
40- const positionMap = new Map (
41- stepPositions . map ( ( sp ) => [ sp . id , sp . position ] ) ,
133+ const updatedStepMap = new Map (
134+ stepPositions . map ( ( sp ) => [
135+ sp . id ,
136+ { position : sp . position , config : sp . config } ,
137+ ] ) ,
42138 )
43139
44140 // Update steps with new positions
45141 const updatedSteps = flow . steps . map ( ( step : IStep ) => {
46- const newPosition = positionMap . get ( step . id )
47- return newPosition !== undefined
48- ? { ...step , position : newPosition }
142+ const updatedStep = updatedStepMap . get ( step . id )
143+ return updatedStep !== undefined
144+ ? {
145+ ...step ,
146+ position : updatedStep . position ,
147+ config : { ...step . config , ...updatedStep . config } ,
148+ }
49149 : step
50150 } )
51151
@@ -91,7 +191,7 @@ const useReorderSteps = (flowId: string) => {
91191 }
92192 }
93193
94- return { handleReorderUpdate }
194+ return { handleReorderUpdate, calculateReorderedSteps }
95195}
96196
97197export default useReorderSteps
0 commit comments