From fd9be09582d39f55327e572b50d6bfe0474201ed Mon Sep 17 00:00:00 2001 From: Leander Furumo Date: Tue, 9 Jul 2024 22:53:19 +0200 Subject: [PATCH 1/8] display error on login when API is unreachable --- src/modules/login/Login.tsx | 4 ++-- src/modules/login/useLogin.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/login/Login.tsx b/src/modules/login/Login.tsx index ca3fcfe..edd1357 100644 --- a/src/modules/login/Login.tsx +++ b/src/modules/login/Login.tsx @@ -10,12 +10,11 @@ import theme from 'src/theme'; import useLogin from './useLogin'; const Login = () => { - const { isLoggingIn, errors, control, setFocus, onSubmit } = useLogin(); + const { isLoggingIn, isSubmitted, errors, loginError, control, setFocus, onSubmit } = useLogin(); return ( - { > Glemt passord? + {loginError && isSubmitted && } {isLoggingIn && } diff --git a/src/modules/login/useLogin.tsx b/src/modules/login/useLogin.tsx index c084014..7064011 100644 --- a/src/modules/login/useLogin.tsx +++ b/src/modules/login/useLogin.tsx @@ -22,7 +22,7 @@ const useLogin = () => { const { control, handleSubmit, - formState: { errors }, + formState: { errors, isSubmitted }, setFocus, } = useForm(); @@ -37,7 +37,7 @@ const useLogin = () => { } }, [isAuthenticated, navigation]); - return { onSubmit, isLoggingIn, setFocus, control, errors: { ...errors, ...loginError } }; + return { onSubmit, isLoggingIn, isSubmitted, setFocus, control, errors: { ...errors }, loginError }; }; export default useLogin; From ab932e31a5d0c947a10a8e6746a38d716c344543 Mon Sep 17 00:00:00 2001 From: Leander Furumo Date: Tue, 9 Jul 2024 22:55:20 +0200 Subject: [PATCH 2/8] don't ignore errors with no fields --- src/components/FormErrors.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/components/FormErrors.tsx b/src/components/FormErrors.tsx index f12681d..41a636d 100644 --- a/src/components/FormErrors.tsx +++ b/src/components/FormErrors.tsx @@ -4,10 +4,6 @@ import { Text, StyleSheet, View } from 'react-native'; // eslint-disable-next-line @typescript-eslint/no-explicit-any const FormErrors = ({ errors }: { errors: Record }) => { - if (!Object.keys(errors).length || !['non_field_errors', 'detail'].some((errorField) => errorField in errors)) { - return null; - } - let errorFormatted; if ('non_field_errors' in errors) { errorFormatted = errors.non_field_errors?.[0]; From fb62f6f9675daa9e59c5c86b3159d7a8ee20374d Mon Sep 17 00:00:00 2001 From: Leander Furumo Date: Tue, 9 Jul 2024 22:55:27 +0200 Subject: [PATCH 3/8] rephrase generic error messge --- src/components/FormErrors.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/FormErrors.tsx b/src/components/FormErrors.tsx index 41a636d..9564043 100644 --- a/src/components/FormErrors.tsx +++ b/src/components/FormErrors.tsx @@ -10,7 +10,7 @@ const FormErrors = ({ errors }: { errors: Record }) => { } else if ('detail' in errors) { errorFormatted = errors.detail; } - if (!errorFormatted) errorFormatted = 'Kunne ikke sende inn skjemaet, prøv igjen...'; + if (!errorFormatted) errorFormatted = 'Kunne ikke sende inn skjemaet! Prøv igjen senere...'; return ( From 1caeebdca3340421916862369234ec79992d7c54 Mon Sep 17 00:00:00 2001 From: Leander Furumo Date: Fri, 26 Jul 2024 03:01:43 +0200 Subject: [PATCH 4/8] use snake_case field names for registration form Although not conventional, our API uses snake_case and returns form field exceptions in the same format. Thus to avoid handling variable name conversions it is probably for the better --- src/api.ts | 9 +++++---- src/modules/register/UserRegister.tsx | 10 +++++----- src/modules/register/useUserRegister.tsx | 6 +++--- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/api.ts b/src/api.ts index adc6891..3f80ee9 100644 --- a/src/api.ts +++ b/src/api.ts @@ -79,7 +79,8 @@ export function requestUserData(authToken: string) { }; } -export function requestRegisterUser({ firstName, lastName, email, phoneNumber, password }: UserRegisterFormValues) { +// We use snake_case in order to fetch and display field errors from the API without any additional formatting +export function requestRegisterUser({ first_name, last_name, email, phone_number, password }: UserRegisterFormValues) { return (dispatch: AppDispatch) => { dispatch(registerUserRequest()); @@ -90,10 +91,10 @@ export function requestRegisterUser({ firstName, lastName, email, phoneNumber, p 'Content-Type': 'application/json', }, body: JSON.stringify({ - first_name: firstName, - last_name: lastName, + first_name: first_name, + last_name: last_name, email, - phone_number: phoneNumber, + phone_number: phone_number, password, }), }) diff --git a/src/modules/register/UserRegister.tsx b/src/modules/register/UserRegister.tsx index c7bbf5a..ac11718 100644 --- a/src/modules/register/UserRegister.tsx +++ b/src/modules/register/UserRegister.tsx @@ -24,15 +24,15 @@ const UserRegister = () => { setFocus('lastName')} + onSubmitEditing={() => setFocus('last_name')} /> { required: 'Kan ikke være tomt!', validate: (v) => EmailValidator.validate(v) || 'er ikke en gyldig e-post', }} - onSubmitEditing={() => setFocus('phoneNumber')} + onSubmitEditing={() => setFocus('phone_number')} /> Date: Fri, 26 Jul 2024 03:02:23 +0200 Subject: [PATCH 5/8] remove unused error formatter --- src/reducers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/reducers.ts b/src/reducers.ts index 2471717..e095e9d 100644 --- a/src/reducers.ts +++ b/src/reducers.ts @@ -77,7 +77,7 @@ export default function duskenApp(state = initialState, action: any) { return { ...state, isRegisteringUser: true, registerError: null }; case REGISTER_USER_FAILURE: - return { ...state, isRegisteringUser: false, registerError: formatErrors(action.registerError) }; + return { ...state, isRegisteringUser: false, registerError: action.registerError }; case REGISTER_USER_SUCCESS: // eslint-disable-next-line no-case-declarations From e8bb66b7403f610a2dfa2bdcf13cc96d15f7128d Mon Sep 17 00:00:00 2001 From: Leander Furumo Date: Fri, 26 Jul 2024 03:04:08 +0200 Subject: [PATCH 6/8] display message on javascript error Specifically this allows us to display an error message when the API is unavailable --- src/components/FormErrors.tsx | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/components/FormErrors.tsx b/src/components/FormErrors.tsx index 9564043..0b0dca7 100644 --- a/src/components/FormErrors.tsx +++ b/src/components/FormErrors.tsx @@ -4,13 +4,24 @@ import { Text, StyleSheet, View } from 'react-native'; // eslint-disable-next-line @typescript-eslint/no-explicit-any const FormErrors = ({ errors }: { errors: Record }) => { + if (!errors) { + return; + } + let errorFormatted; - if ('non_field_errors' in errors) { + if (errors instanceof Error) { + // This check might backfire on us as it's too general. We do not wish to display the error message to the user + // Hence we display this generic one + errorFormatted = 'Kunne ikke sende inn skjemaet! Prøv igjen senere...'; + } else if ('non_field_errors' in errors) { errorFormatted = errors.non_field_errors?.[0]; } else if ('detail' in errors) { errorFormatted = errors.detail; } - if (!errorFormatted) errorFormatted = 'Kunne ikke sende inn skjemaet! Prøv igjen senere...'; + + if (!errorFormatted) { + return; + } return ( From 702adabf84113f79aa77dc95bb30c1e2ba3546cb Mon Sep 17 00:00:00 2001 From: Leander Furumo Date: Fri, 26 Jul 2024 03:08:03 +0200 Subject: [PATCH 7/8] fix ugly formatting for fields with multiple errors --- src/modules/register/useUserRegister.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/register/useUserRegister.tsx b/src/modules/register/useUserRegister.tsx index 44b04ae..834ebc6 100644 --- a/src/modules/register/useUserRegister.tsx +++ b/src/modules/register/useUserRegister.tsx @@ -46,7 +46,7 @@ const useUserRegister = () => { // Display error messages from API on form fields Object.keys(registerError).forEach((key) => { - setError(key as keyof UserRegisterFormValues, { type: 'manual', message: registerError[key] }); + setError(key as keyof UserRegisterFormValues, { type: 'server', message: registerError[key].join('\n') }); }); }); From 666846759400cd9aad52cd7a5dc534c3f6dcc252 Mon Sep 17 00:00:00 2001 From: Leander Furumo Date: Fri, 26 Jul 2024 03:09:41 +0200 Subject: [PATCH 8/8] fix display of field errors from api --- src/modules/register/UserRegister.tsx | 19 ++++++++++++----- src/modules/register/useUserRegister.tsx | 27 +++++++++++++++++++++--- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/src/modules/register/UserRegister.tsx b/src/modules/register/UserRegister.tsx index ac11718..cfbb90f 100644 --- a/src/modules/register/UserRegister.tsx +++ b/src/modules/register/UserRegister.tsx @@ -13,8 +13,18 @@ import useUserRegister from './useUserRegister'; const { Toast } = Incubator; const UserRegister = () => { - const { isRegisteringUser, onSubmit, isValid, control, errors, registerError, setFocus, toast, setToast } = - useUserRegister(); + const { + isRegisteringUser, + onSubmit, + isValid, + isSubmitted, + control, + errors, + registerError, + setFocus, + toast, + setToast, + } = useUserRegister(); const isDisabled = isRegisteringUser || !isValid; // TODO: validate on type // TODO: highlight errorfields @@ -72,10 +82,9 @@ const UserRegister = () => { onSubmitEditing={onSubmit} /> - - + {registerError && isSubmitted && } - {isRegisteringUser && } diff --git a/src/modules/register/useUserRegister.tsx b/src/modules/register/useUserRegister.tsx index 834ebc6..9cbade9 100644 --- a/src/modules/register/useUserRegister.tsx +++ b/src/modules/register/useUserRegister.tsx @@ -19,7 +19,7 @@ const useUserRegister = () => { const navigation = useNavigation(); const isAuthenticated = useAppSelector((store) => store.isAuthenticated); const isRegisteringUser = useAppSelector((store) => store.isRegisteringUser); - const registerError = useAppSelector((store) => store.registerError) || {}; + const registerError = useAppSelector((store) => store.registerError); const [toast, setToast] = useState(null); const isAuthenticatedPrev = usePrevious(isAuthenticated); @@ -27,11 +27,13 @@ const useUserRegister = () => { const { control, handleSubmit, - formState: { errors, isValid }, + formState: { errors, isValid, isSubmitted }, setFocus, setError, + clearErrors, } = useForm(); const onSubmit = handleSubmit((values) => { + clearErrors(); if (!isValid) { setToast({ message: 'Noen av feltene er ikke fylt ut riktig', @@ -56,6 +58,25 @@ const useUserRegister = () => { } }, [isAuthenticatedPrev, isAuthenticated, navigation]); - return { isRegisteringUser, onSubmit, isValid, registerError, control, errors, setFocus, toast, setToast }; + useEffect(() => { + clearErrors(); + if (!isSubmitted || !registerError) return; + Object.keys(registerError).forEach((key) => { + setError(key as keyof UserRegisterFormValues, { type: 'server', message: registerError[key].join('\n') }); + }); + }, [registerError]); + + return { + isRegisteringUser, + onSubmit, + isValid, + isSubmitted, + registerError, + control, + errors, + setFocus, + toast, + setToast, + }; }; export default useUserRegister;