@@ -5,14 +5,14 @@ import {
5
5
caseStatusVariants ,
6
6
useCaseStatuses ,
7
7
} from '@app-builder/components/Cases' ;
8
+ import { setToastMessage } from '@app-builder/components/MarbleToaster' ;
8
9
import { caseStatuses } from '@app-builder/models/cases' ;
9
10
import { serverServices } from '@app-builder/services/init.server' ;
10
11
import { getRoute } from '@app-builder/utils/routes' ;
11
- import { getFormProps , getInputProps , useForm } from '@conform-to/react' ;
12
- import { getZodConstraint , parseWithZod } from '@conform-to/zod' ;
13
12
import * as DropdownMenu from '@radix-ui/react-dropdown-menu' ;
14
13
import { type ActionFunctionArgs , json } from '@remix-run/node' ;
15
14
import { useFetcher } from '@remix-run/react' ;
15
+ import { useForm } from '@tanstack/react-form' ;
16
16
import { type Namespace } from 'i18next' ;
17
17
import * as React from 'react' ;
18
18
import { Trans , useTranslation } from 'react-i18next' ;
@@ -29,27 +29,66 @@ const schema = z.object({
29
29
status : z . enum ( caseStatuses ) ,
30
30
nextStatus : z . enum ( caseStatuses ) ,
31
31
} ) ;
32
+
32
33
type Schema = z . infer < typeof schema > ;
33
34
34
35
export async function action ( { request } : ActionFunctionArgs ) {
35
- const { authService } = serverServices ;
36
- const { cases } = await authService . isAuthenticated ( request , {
37
- failureRedirect : getRoute ( '/sign-in' ) ,
38
- } ) ;
36
+ const {
37
+ authService,
38
+ i18nextService : { getFixedT } ,
39
+ toastSessionService : { getSession, commitSession } ,
40
+ } = serverServices ;
39
41
40
- const formData = await request . formData ( ) ;
41
- const submission = parseWithZod ( formData , { schema } ) ;
42
+ const [ t , session , data , { cases } ] = await Promise . all ( [
43
+ getFixedT ( request , [ 'common' ] ) ,
44
+ getSession ( request ) ,
45
+ request . json ( ) ,
46
+ authService . isAuthenticated ( request , {
47
+ failureRedirect : getRoute ( '/sign-in' ) ,
48
+ } ) ,
49
+ ] ) ;
42
50
43
- if ( submission . status !== 'success' ) {
44
- return json ( submission . reply ( ) ) ;
51
+ const result = schema . safeParse ( data ) ;
52
+
53
+ if ( ! result . success ) {
54
+ return json (
55
+ { status : 'error' , errors : result . error . flatten ( ) } ,
56
+ {
57
+ headers : { 'Set-Cookie' : await commitSession ( session ) } ,
58
+ } ,
59
+ ) ;
45
60
}
46
61
47
- await cases . updateCase ( {
48
- caseId : submission . value . caseId ,
49
- body : { status : submission . value . nextStatus } ,
50
- } ) ;
62
+ try {
63
+ await cases . updateCase ( {
64
+ caseId : data . caseId ,
65
+ body : { status : data . nextStatus } ,
66
+ } ) ;
51
67
52
- return json ( submission . reply ( ) ) ;
68
+ setToastMessage ( session , {
69
+ type : 'success' ,
70
+ message : t ( 'common:success.save' ) ,
71
+ } ) ;
72
+
73
+ return json (
74
+ { status : 'success' , errors : [ ] } ,
75
+ {
76
+ headers : { 'Set-Cookie' : await commitSession ( session ) } ,
77
+ } ,
78
+ ) ;
79
+ } catch ( error ) {
80
+ setToastMessage ( session , {
81
+ type : 'error' ,
82
+ message : t ( 'common:errors.unknown' ) ,
83
+ } ) ;
84
+
85
+ return json (
86
+ { status : 'error' , errors : [ ] } ,
87
+ {
88
+ headers : { 'Set-Cookie' : await commitSession ( session ) } ,
89
+ } ,
90
+ ) ;
91
+ }
53
92
}
54
93
55
94
export function EditCaseStatus ( { status, caseId } : Pick < Schema , 'caseId' | 'status' > ) {
@@ -149,37 +188,40 @@ function ModalContent({
149
188
const { t } = useTranslation ( handle . i18n ) ;
150
189
const fetcher = useFetcher < typeof action > ( ) ;
151
190
152
- const [ form , fields ] = useForm ( {
153
- defaultValue : { caseId, status, nextStatus } ,
154
- lastResult : fetcher . data ,
155
- constraint : getZodConstraint ( schema ) ,
156
- onValidate ( { formData } ) {
157
- return parseWithZod ( formData , {
158
- schema,
159
- } ) ;
191
+ const form = useForm ( {
192
+ defaultValues : { caseId, status, nextStatus } ,
193
+ onSubmit : ( { value, formApi } ) => {
194
+ if ( formApi . state . isValid ) {
195
+ fetcher . submit ( value , {
196
+ method : 'PATCH' ,
197
+ action : getRoute ( '/ressources/cases/edit-status' ) ,
198
+ encType : 'application/json' ,
199
+ } ) ;
200
+ }
201
+ } ,
202
+ validators : {
203
+ onChangeAsync : schema ,
204
+ onBlurAsync : schema ,
205
+ onSubmitAsync : schema ,
160
206
} ,
161
207
} ) ;
162
208
163
209
React . useEffect ( ( ) => {
164
210
if ( fetcher . data ?. status === 'success' ) {
165
211
onSubmitSuccess ( ) ;
166
212
}
167
- } , [ fetcher . data ?. intent , fetcher . data ?. status , onSubmitSuccess ] ) ;
213
+ } , [ fetcher . data ?. status , onSubmitSuccess ] ) ;
168
214
169
215
return (
170
- < fetcher . Form
171
- method = "post"
172
- action = { getRoute ( '/ressources/cases/edit-status' ) }
173
- { ...getFormProps ( form ) }
216
+ < form
217
+ onSubmit = { ( e ) => {
218
+ e . preventDefault ( ) ;
219
+ e . stopPropagation ( ) ;
220
+ form . handleSubmit ( ) ;
221
+ } }
174
222
>
175
223
< Modal . Title > { t ( 'cases:change_status_modal.title' ) } </ Modal . Title >
176
224
< div className = "flex flex-col gap-6 p-6" >
177
- < input { ...getInputProps ( fields . caseId , { type : 'hidden' } ) } key = { fields . caseId . key } />
178
- < input { ...getInputProps ( fields . status , { type : 'hidden' } ) } key = { fields . status . key } />
179
- < input
180
- { ...getInputProps ( fields . nextStatus , { type : 'hidden' } ) }
181
- key = { fields . nextStatus . key }
182
- />
183
225
< div className = "text-grey-00 text-s flex flex-row items-center justify-center gap-6 font-medium capitalize" >
184
226
< div className = "flex w-full flex-1 flex-row items-center justify-end gap-2" >
185
227
< Trans
@@ -202,7 +244,7 @@ function ModalContent({
202
244
</ div >
203
245
< div className = "flex w-full flex-row gap-2" >
204
246
< Modal . Close asChild >
205
- < Button variant = "secondary" className = "flex-1 first-letter:capitalize" >
247
+ < Button variant = "secondary" type = "button" className = "flex-1 first-letter:capitalize" >
206
248
{ t ( 'common:close' ) }
207
249
</ Button >
208
250
</ Modal . Close >
@@ -212,6 +254,6 @@ function ModalContent({
212
254
</ Button >
213
255
</ div >
214
256
</ div >
215
- </ fetcher . Form >
257
+ </ form >
216
258
) ;
217
259
}
0 commit comments