Skip to content

Commit b418d2c

Browse files
Refactor formBase functions to use handleCallAPI
1 parent 01324d4 commit b418d2c

File tree

8 files changed

+207
-200
lines changed

8 files changed

+207
-200
lines changed

lib/ts/recipe/emailpassword/components/library/formBase.tsx

Lines changed: 94 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,9 @@ import { useCallback } from "react";
2121
import { useRef } from "react";
2222
import { useEffect } from "react";
2323

24+
import { handleCallAPI } from "../../../../utils";
2425
import { MANDATORY_FORM_FIELDS_ID_ARRAY } from "../../constants";
2526

26-
import { handleFormSubmit } from "./functions/form";
27-
2827
import type { APIFormField } from "../../../../types";
2928
import type { FormBaseProps, FormFieldThemeProps } from "../../types";
3029
import type { FormEvent } from "react";
@@ -210,17 +209,101 @@ export const FormBase: React.FC<FormBaseProps<any>> = (props) => {
210209

211210
const onFormSubmit = useCallback(
212211
async (e: FormEvent): Promise<void> => {
213-
return await handleFormSubmit({
214-
...props,
215-
event: e,
216-
setIsLoading,
217-
setFieldStates,
218-
unmounting,
219-
fieldStates,
220-
updateFieldState,
212+
// Prevent default event propagation.
213+
e.preventDefault();
214+
215+
// Set loading state.
216+
if (setIsLoading) {
217+
setIsLoading(true);
218+
}
219+
220+
if (setFieldStates) {
221+
setFieldStates((os) => os.map((fs) => ({ ...fs, error: undefined })));
222+
}
223+
224+
// Get the fields values from form.
225+
const apiFields = formFields?.map((field) => {
226+
const fieldState = fieldStates?.find((fs) => fs.id === field.id);
227+
return {
228+
id: field.id,
229+
value: fieldState === undefined ? "" : fieldState.value,
230+
};
221231
});
232+
233+
const fieldUpdates: FieldState[] = [];
234+
// Call API.
235+
try {
236+
const { result, generalError, fetchError } = await handleCallAPI({
237+
apiFields,
238+
fieldUpdates,
239+
callAPI: props.callAPI,
240+
});
241+
if (unmounting?.current.signal.aborted) {
242+
return;
243+
}
244+
245+
if (generalError !== undefined || (result !== undefined && result.status !== "OK")) {
246+
for (const field of formFields || []) {
247+
const update = fieldUpdates.find((f) => f.id === field.id);
248+
if ((update || field.clearOnSubmit === true) && updateFieldState) {
249+
// We can do these one by one, it's almost never more than one field
250+
updateFieldState(field.id, (os) => ({ ...os, value: update ? update.value : "" }));
251+
}
252+
}
253+
}
254+
255+
if (generalError !== undefined) {
256+
props.onError(generalError.message);
257+
} else if (fetchError !== undefined) {
258+
if (props.onFetchError) {
259+
props.onFetchError(fetchError);
260+
} else {
261+
throw fetchError;
262+
}
263+
} else {
264+
// If successful
265+
if (result.status === "OK") {
266+
if (setIsLoading) {
267+
setIsLoading(false);
268+
}
269+
props.clearError();
270+
if (props.onSuccess !== undefined) {
271+
props.onSuccess(result);
272+
}
273+
}
274+
275+
if (unmounting?.current.signal.aborted) {
276+
return;
277+
}
278+
279+
// If field error.
280+
if (result.status === "FIELD_ERROR") {
281+
const errorFields = result.formFields;
282+
const getErrorMessage = (fs: FieldState) => {
283+
const errorMessage = errorFields.find((ef: any) => ef.id === fs.id)?.error;
284+
if (errorMessage === "Field is not optional") {
285+
const fieldConfigData = formFields?.find((f) => f.id === fs.id);
286+
// replace non-optional server error message from nonOptionalErrorMsg
287+
if (fieldConfigData?.nonOptionalErrorMsg !== undefined) {
288+
return fieldConfigData?.nonOptionalErrorMsg;
289+
}
290+
}
291+
return errorMessage;
292+
};
293+
if (setFieldStates) {
294+
setFieldStates((os) => os.map((fs) => ({ ...fs, error: getErrorMessage(fs) })));
295+
}
296+
}
297+
}
298+
} catch (e) {
299+
props.onError("SOMETHING_WENT_WRONG_ERROR");
300+
} finally {
301+
if (setIsLoading) {
302+
setIsLoading(false);
303+
}
304+
}
222305
},
223-
[setIsLoading, setFieldStates, props, formFields, fieldStates]
306+
[setIsLoading, setFieldStates, props, formFields, fieldStates, updateFieldState]
224307
);
225308

226309
return (

lib/ts/recipe/emailpassword/components/library/functions/form.ts

Lines changed: 0 additions & 122 deletions
This file was deleted.

lib/ts/recipe/emailpassword/components/library/functions/types.ts

Lines changed: 0 additions & 21 deletions
This file was deleted.

lib/ts/recipe/webauthn/components/themes/signIn/index.tsx

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@ import * as React from "react";
1818
import SuperTokens from "../../../../../superTokens";
1919
import { useUserContext } from "../../../../../usercontext";
2020
import UserContextWrapper from "../../../../../usercontext/userContextWrapper";
21-
import { handleFormSubmit } from "../../../../emailpassword/components/library/functions/form";
21+
import { handleCallAPI } from "../../../../../utils";
2222
import { ContinueWithPasskeyTheme } from "../continueWithPasskey";
2323
import { RecoverableError } from "../error/recoverableError";
2424
import { ThemeBase } from "../themeBase";
2525

2626
import type { APIFormField } from "../../../../../types";
27+
import type { FieldState } from "../../../../emailpassword/components/library/formBase";
2728
import type { SignInThemeProps } from "../../../types";
2829

2930
function PasskeySignInTheme(props: SignInThemeProps): JSX.Element {
@@ -56,14 +57,39 @@ function PasskeySignInTheme(props: SignInThemeProps): JSX.Element {
5657

5758
// Define the code to handle sign in properly through this component.
5859
const handleWebauthnSignInClick = async () => {
59-
await handleFormSubmit({
60-
callAPI: callAPI,
61-
clearError: () => setError(null),
62-
onError: (error) => setError(error),
63-
onFetchError: () => setError("Failed to fetch from upstream"),
64-
onSuccess: (payload) => console.warn("payload: ", payload),
65-
setIsLoading: setIsLoading,
66-
});
60+
const fieldUpdates: FieldState[] = [];
61+
setIsLoading(true);
62+
63+
try {
64+
const { result, generalError, fetchError } = await handleCallAPI<any>({
65+
apiFields: [],
66+
fieldUpdates,
67+
callAPI: callAPI,
68+
});
69+
70+
if (generalError !== undefined) {
71+
setError(generalError.message);
72+
} else if (fetchError !== undefined) {
73+
setError("Failed to fetch from upstream");
74+
} else {
75+
// If successful
76+
if (result.status === "OK") {
77+
if (setIsLoading) {
78+
setIsLoading(false);
79+
}
80+
setError(null);
81+
if (props.onSuccess !== undefined) {
82+
props.onSuccess(result);
83+
}
84+
}
85+
}
86+
} catch (e) {
87+
setError("SOMETHING_WENT_WRONG_ERROR");
88+
} finally {
89+
if (setIsLoading) {
90+
setIsLoading(false);
91+
}
92+
}
6793
};
6894

6995
const rootStyle = SuperTokens.getInstanceOrThrow().rootStyle;

0 commit comments

Comments
 (0)