Skip to content

Commit db6ca4b

Browse files
Add updated callAPI functions for signup
1 parent 41a83fe commit db6ca4b

File tree

4 files changed

+80
-24
lines changed

4 files changed

+80
-24
lines changed

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

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,20 @@ export const handleFormSubmit = async ({
1818
updateFieldState,
1919
}: FormOnSubmitParameters<any>): Promise<void> => {
2020
// Prevent default event propagation.
21-
e.preventDefault();
21+
e?.preventDefault();
2222

2323
// Set loading state.
24-
setIsLoading(true);
24+
if (setIsLoading) {
25+
setIsLoading(true);
26+
}
2527

26-
setFieldStates((os) => os.map((fs) => ({ ...fs, error: undefined })));
28+
if (setFieldStates) {
29+
setFieldStates((os) => os.map((fs) => ({ ...fs, error: undefined })));
30+
}
2731

2832
// Get the fields values from form.
29-
const apiFields = formFields.map((field) => {
30-
const fieldState = fieldStates.find((fs) => fs.id === field.id);
33+
const apiFields = formFields?.map((field) => {
34+
const fieldState = fieldStates?.find((fs) => fs.id === field.id);
3135
return {
3236
id: field.id,
3337
value: fieldState === undefined ? "" : fieldState.value,
@@ -41,7 +45,7 @@ export const handleFormSubmit = async ({
4145
let generalError: STGeneralError | undefined;
4246
let fetchError: Response | undefined;
4347
try {
44-
result = await callAPI(apiFields, (id, value) => fieldUpdates.push({ id, value }));
48+
result = await callAPI(apiFields || [], (id, value) => fieldUpdates.push({ id, value }));
4549
} catch (e) {
4650
if (STGeneralError.isThisError(e)) {
4751
generalError = e;
@@ -51,14 +55,14 @@ export const handleFormSubmit = async ({
5155
throw e;
5256
}
5357
}
54-
if (unmounting.current.signal.aborted) {
58+
if (unmounting?.current.signal.aborted) {
5559
return;
5660
}
5761

5862
if (generalError !== undefined || (result !== undefined && result.status !== "OK")) {
59-
for (const field of formFields) {
63+
for (const field of formFields || []) {
6064
const update = fieldUpdates.find((f) => f.id === field.id);
61-
if (update || field.clearOnSubmit === true) {
65+
if ((update || field.clearOnSubmit === true) && updateFieldState) {
6266
// We can do these one by one, it's almost never more than one field
6367
updateFieldState(field.id, (os) => ({ ...os, value: update ? update.value : "" }));
6468
}
@@ -76,14 +80,16 @@ export const handleFormSubmit = async ({
7680
} else {
7781
// If successful
7882
if (result.status === "OK") {
79-
setIsLoading(false);
83+
if (setIsLoading) {
84+
setIsLoading(false);
85+
}
8086
clearError();
8187
if (onSuccess !== undefined) {
8288
onSuccess(result);
8389
}
8490
}
8591

86-
if (unmounting.current.signal.aborted) {
92+
if (unmounting?.current.signal.aborted) {
8793
return;
8894
}
8995

@@ -93,20 +99,24 @@ export const handleFormSubmit = async ({
9399
const getErrorMessage = (fs: FieldState) => {
94100
const errorMessage = errorFields.find((ef: any) => ef.id === fs.id)?.error;
95101
if (errorMessage === "Field is not optional") {
96-
const fieldConfigData = formFields.find((f) => f.id === fs.id);
102+
const fieldConfigData = formFields?.find((f) => f.id === fs.id);
97103
// replace non-optional server error message from nonOptionalErrorMsg
98104
if (fieldConfigData?.nonOptionalErrorMsg !== undefined) {
99105
return fieldConfigData?.nonOptionalErrorMsg;
100106
}
101107
}
102108
return errorMessage;
103109
};
104-
setFieldStates((os) => os.map((fs) => ({ ...fs, error: getErrorMessage(fs) })));
110+
if (setFieldStates) {
111+
setFieldStates((os) => os.map((fs) => ({ ...fs, error: getErrorMessage(fs) })));
112+
}
105113
}
106114
}
107115
} catch (e) {
108116
onError("SOMETHING_WENT_WRONG_ERROR");
109117
} finally {
110-
setIsLoading(false);
118+
if (setIsLoading) {
119+
setIsLoading(false);
120+
}
111121
}
112122
};
Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
1-
import type { FormBaseProps } from "../../../types";
1+
import type { APIFormField } from "../../../../../types";
2+
import type { FormBaseAPIResponse, FormFieldThemeProps } from "../../../types";
23
import type { FieldState } from "../formBase";
34
import type { FormEvent } from "react";
45

5-
export type FormOnSubmitParameters<T> = FormBaseProps<T> & {
6-
event: FormEvent;
7-
setIsLoading: React.Dispatch<React.SetStateAction<boolean>>;
8-
setFieldStates: React.Dispatch<React.SetStateAction<FieldState[]>>;
9-
fieldStates: FieldState[];
10-
unmounting: React.MutableRefObject<AbortController>;
11-
updateFieldState: (id: string, update: (os: FieldState) => FieldState) => void;
6+
export type FormOnSubmitParameters<T> = {
7+
event?: FormEvent;
8+
setIsLoading?: React.Dispatch<React.SetStateAction<boolean>>;
9+
setFieldStates?: React.Dispatch<React.SetStateAction<FieldState[]>>;
10+
fieldStates?: FieldState[];
11+
unmounting?: React.MutableRefObject<AbortController>;
12+
updateFieldState?: (id: string, update: (os: FieldState) => FieldState) => void;
13+
14+
formFields?: FormFieldThemeProps[];
15+
clearError: () => void;
16+
onError: (error: string) => void;
17+
onFetchError?: (err: Response) => void;
18+
onSuccess?: (result: T & { status: "OK" }) => void;
19+
20+
callAPI: (fields: APIFormField[], setValue: (id: string, value: string) => void) => Promise<FormBaseAPIResponse<T>>;
1221
};

lib/ts/recipe/webauthn/components/themes/signUp/confirmation.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export const PasskeyConfirmation = withOverride(
2727
function PasskeyConfirmation(
2828
props: SignUpFormProps & {
2929
email: string;
30+
onContinueClick: () => void;
3031
}
3132
): JSX.Element {
3233
const t = useTranslation();
@@ -39,7 +40,13 @@ export const PasskeyConfirmation = withOverride(
3940
</div>
4041
<PasskeyFeatureBlocks />
4142
<div data-supertokens="passkeyConfirmationFooter">
42-
<Button disabled={false} isLoading={false} type="button" label="WEBAUTHN_EMAIL_CONTINUE_BUTTON" />
43+
<Button
44+
disabled={false}
45+
isLoading={false}
46+
type="button"
47+
onClick={props.onContinueClick}
48+
label="WEBAUTHN_EMAIL_CONTINUE_BUTTON"
49+
/>
4350
<ContinueWithoutPasskey onClick={props.resetFactorList} />
4451
</div>
4552
</div>

lib/ts/recipe/webauthn/components/themes/signUp/signUpForm.tsx

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@ import STGeneralError from "supertokens-web-js/utils/error";
1818

1919
import { withOverride } from "../../../../../components/componentOverride/withOverride";
2020
import { useTranslation } from "../../../../../translation/translationContext";
21+
import { useUserContext } from "../../../../../usercontext";
2122
import { Label } from "../../../../emailpassword/components/library";
2223
import FormBase from "../../../../emailpassword/components/library/formBase";
24+
import { handleFormSubmit } from "../../../../emailpassword/components/library/functions/form";
2325
import { defaultEmailValidator } from "../../../../emailpassword/validators";
2426

2527
import { PasskeyConfirmation } from "./confirmation";
2628
import { ContinueWithoutPasskey } from "./continueWithoutPasskey";
2729

30+
import type { APIFormField } from "../../../../../types";
2831
import type { ContinueOnSuccessParams, SignUpFormProps } from "../../../types";
2932

3033
export enum SignUpScreen {
@@ -109,6 +112,7 @@ export const SignUpForm = (
109112
}
110113
): JSX.Element | null => {
111114
const [continueClickResponse, setContinueClickResponse] = useState<ContinueOnSuccessParams | null>(null);
115+
const userContext = useUserContext();
112116

113117
const onContinueClickCallback = useCallback(
114118
(params: ContinueOnSuccessParams) => {
@@ -118,9 +122,35 @@ export const SignUpForm = (
118122
[setContinueClickResponse, props]
119123
);
120124

125+
const callAPI = useCallback(
126+
async (_: APIFormField[], __: (id: string, value: string) => any) => {
127+
if (continueClickResponse === null) {
128+
throw props.onError("EMAIL_INPUT_NOT_POPULATED_ERROR");
129+
}
130+
131+
return await props.recipeImplementation.registerCredentialWithSignUp({
132+
email: continueClickResponse.email,
133+
userContext,
134+
});
135+
},
136+
[continueClickResponse, props, userContext]
137+
);
138+
139+
const onConfirmationClick = useCallback(async () => {
140+
await handleFormSubmit({
141+
callAPI: callAPI,
142+
clearError: () => alert("Clearing error"),
143+
onError: (error) => console.error("Got error: ", error),
144+
});
145+
}, [callAPI]);
146+
121147
return props.activeScreen === SignUpScreen.SignUpForm ? (
122148
<SignUpFormInner {...props} onContinueClick={onContinueClickCallback} />
123149
) : props.activeScreen === SignUpScreen.PasskeyConfirmation ? (
124-
<PasskeyConfirmation {...props} email={continueClickResponse?.email || ""} />
150+
<PasskeyConfirmation
151+
{...props}
152+
email={continueClickResponse?.email || ""}
153+
onContinueClick={onConfirmationClick}
154+
/>
125155
) : null;
126156
};

0 commit comments

Comments
 (0)