1
- import { FC , ReactNode , createContext , useState , useCallback } from "react" ;
2
- import { useMultistepForm } from "../hooks/useMultistepForm" ;
3
- import PageOne from "../components/form/PageOne" ;
4
- import PageTwo from "../components/form/PageTwo" ;
5
- import PageThree from "../components/form/PageThree" ;
6
- import { Badge , BadgeDataTransfer , Card } from "../types" ;
7
- import PageFour from "../components/form/PageFour" ;
1
+ import { FC , ReactNode , createContext , useCallback , useState } from "react" ;
8
2
import PageFive from "../components/form/PageFive" ;
3
+ import PageFour from "../components/form/PageFour" ;
4
+ import PageOne from "../components/form/PageOne" ;
9
5
import PageSix from "../components/form/PageSix" ;
6
+ import PageThree from "../components/form/PageThree" ;
7
+ import PageTwo from "../components/form/PageTwo" ;
10
8
import { INITIAL_CARD } from "../const" ;
9
+ import { useMultistepForm } from "../hooks/useMultistepForm" ;
10
+ import { Badge , BadgeDataTransfer , Card , Line } from "../types" ;
11
11
12
12
export interface MultistepContextType {
13
13
isFirstPage : boolean ;
@@ -22,9 +22,7 @@ export interface MultistepContextType {
22
22
addBadge : ( lineNumber : number , badge : Omit < Badge , "position" > ) => void ;
23
23
removeBadge : ( lineNumber : number , position : number ) => void ;
24
24
grabbedBadge : BadgeDataTransfer | undefined ;
25
- setGrabbedBadge : React . Dispatch <
26
- React . SetStateAction < BadgeDataTransfer | undefined >
27
- > ;
25
+ setGrabbedBadge : ( grabbedBadge : BadgeDataTransfer | undefined ) => void ;
28
26
insertBadge : (
29
27
lineNumber : number ,
30
28
position : number ,
@@ -63,82 +61,111 @@ export const MultistepProvider: FC<MultistepProviderProps> = ({ children }) => {
63
61
< PageSix /> ,
64
62
] ) ;
65
63
64
+ /**
65
+ * Updates the card in a way that none of the card's parameters is required.
66
+ *
67
+ * @param {Partial<Card> } updated
68
+ */
66
69
const updateCard = useCallback (
67
70
( updated : Partial < Card > ) => setCard ( ( prev ) => ( { ...prev , ...updated } ) ) ,
68
71
[ ]
69
72
) ;
70
73
71
- const addBadge = useCallback (
72
- ( lineNumber : number , badge : Omit < Badge , "position" > ) => {
74
+ /**
75
+ * Updates a line with the specified lineNumber.
76
+ * If the line with the lineNumber is not presented, it does nothing.
77
+ *
78
+ * @param {number } lineNumber
79
+ * @param {(line: Line) => void } callback
80
+ */
81
+ const updateLine = useCallback (
82
+ ( lineNumber : number , callback : ( line : Line ) => void ) => {
73
83
setCard ( ( prev ) => {
74
84
// check whether the line exists
75
- const line = prev . lines . findIndex ( ( x ) => x . lineNumber === lineNumber ) ;
76
- if ( line === - 1 ) return prev ;
85
+ const idx = prev . lines . findIndex ( ( x ) => x . lineNumber === lineNumber ) ;
86
+ if ( idx === - 1 ) return prev ;
77
87
78
88
const newCard = structuredClone ( prev ) ;
79
-
80
- // update the badges
81
- newCard . lines [ line ] . badges = [
82
- ...newCard . lines [ line ] . badges ,
83
- { ...badge , position : newCard . lines [ line ] . badges . length } ,
84
- ] ;
89
+ callback ( newCard . lines [ idx ] ) ;
85
90
86
91
return newCard ;
87
92
} ) ;
88
93
} ,
89
94
[ ]
90
95
) ;
91
96
92
- const removeBadge = useCallback ( ( lineNumber : number , position : number ) => {
93
- setCard ( ( prev ) => {
94
- // check whether the line exists
95
- const line = prev . lines . findIndex ( ( x ) => x . lineNumber === lineNumber ) ;
96
- if ( line === - 1 ) return prev ;
97
+ /**
98
+ * Pushes a badge to the end of a line.
99
+ * You should pass the badge without the position property.
100
+ *
101
+ * @param {number } lineNumber
102
+ * @param {Omit<Badge, "position"> } badge
103
+ */
104
+ const addBadge = useCallback (
105
+ ( lineNumber : number , badge : Omit < Badge , "position" > ) => {
106
+ updateLine ( lineNumber , ( line ) => {
107
+ const { badges } = line ;
108
+ badges . push ( { position : badges . length , ...badge } ) ;
109
+ } ) ;
110
+ } ,
111
+ [ updateLine ]
112
+ ) ;
97
113
98
- const newCard = structuredClone ( prev ) ;
114
+ /**
115
+ * Removes a badge in the specified line at the specified position.
116
+ *
117
+ * @param {number } lineNumber
118
+ * @param {number } position
119
+ */
120
+ const removeBadge = useCallback (
121
+ ( lineNumber : number , position : number ) => {
122
+ updateLine ( lineNumber , ( line ) => {
123
+ const { badges } = line ;
99
124
100
- // remove the badge and rearrange the positions
101
- newCard . lines [ line ] . badges = newCard . lines [ line ] . badges
102
- . sort ( ( a , z ) => a . position - z . position )
103
- . filter ( ( x ) => x . position !== position )
104
- . map ( ( prev , i ) => ( { ...prev , position : i } ) ) ;
125
+ // remove the old badge
126
+ const idx = badges . map ( ( x ) => x . position ) . indexOf ( position ) ;
127
+ if ( idx !== - 1 ) badges . splice ( idx , 1 ) ;
105
128
106
- return newCard ;
107
- } ) ;
108
- } , [ ] ) ;
129
+ // rearrange the positions
130
+ badges . forEach ( ( badge , i ) => ( badge . position = i ) ) ;
131
+ } ) ;
132
+ } ,
133
+ [ updateLine ]
134
+ ) ;
109
135
136
+ /**
137
+ * Inserts a new badge in the specified line at a specified position.
138
+ * This function also removes the old badge from the array.
139
+ *
140
+ * @param {number } lineNumber
141
+ * @param {number } position
142
+ * @param {BadgeDataTransfer } bdt
143
+ */
110
144
const insertBadge = useCallback (
111
145
( lineNumber : number , position : number , bdt : BadgeDataTransfer ) => {
112
146
// If the grabbed badge is in the left side of the new position,
113
147
// we need to decrement the position by one,
114
148
// because we grabbed (technically removed) one from the new position's left side.
115
149
if ( position > bdt . badge . position ) position -- ;
116
150
117
- setCard ( ( prev ) => {
118
- // check whether the line exists
119
- const line = prev . lines . findIndex ( ( x ) => x . lineNumber === lineNumber ) ;
120
- if ( line === - 1 ) return prev ;
121
-
122
- const newCard = structuredClone ( prev ) ;
123
- const badges = newCard . lines [ line ] . badges ;
124
- const badgePositions = badges . map ( ( badge ) => badge . position ) ;
151
+ updateLine ( lineNumber , ( line ) => {
152
+ const { badges } = line ;
125
153
126
154
// remove the old badge
127
- const idx = badgePositions . indexOf ( bdt . badge . position ) ;
155
+ const idx = badges . map ( ( x ) => x . position ) . indexOf ( bdt . badge . position ) ;
128
156
if ( idx !== - 1 ) badges . splice ( idx , 1 ) ;
129
157
130
158
// insert the new badge
131
159
badges . splice ( position , 0 , bdt . badge ) ;
132
-
133
- // rearrange the positions
134
160
badges . forEach ( ( badge , i ) => ( badge . position = i ) ) ;
135
-
136
- return newCard ;
137
161
} ) ;
138
162
} ,
139
- [ ]
163
+ [ updateLine ]
140
164
) ;
141
165
166
+ /**
167
+ * Resets the card by setting it to it's initial state.
168
+ */
142
169
const resetCard = useCallback ( ( ) => {
143
170
goToPageFirst ( ) ;
144
171
setCard ( structuredClone ( INITIAL_CARD ) ) ;
0 commit comments