Skip to content

Commit

Permalink
feat(app-signup): add error translations
Browse files Browse the repository at this point in the history
  • Loading branch information
rams23 committed Dec 31, 2020
1 parent 7a31384 commit 93953f5
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 34 deletions.
1 change: 1 addition & 0 deletions packages/game-app/.env.template
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ REACT_APP_FIREBASE_CONFIG_PROJECT_ID=
REACT_APP_FIREBASE_CONFIG_STORAGE_BUCKET=
REACT_APP_FIREBASE_CONFIG_MESSAGING_SENDER_ID=
REACT_APP_FIREBASE_CONFIG_APP_ID=
REACT_APP_FIREBASE_USE_EMULATORS=
FIREBASE_AUTH_EMULATOR_HOST=
FIRESTORE_EMULATOR_HOST=
17 changes: 14 additions & 3 deletions packages/game-app/src/_shared/form/FormSelect/FormSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useCallback } from 'react';
import React, { useCallback, useMemo } from 'react';
import { Controller, ControllerRenderProps, useFormContext } from 'react-hook-form';
import { SelectInput } from '@pipeline/components';
import { useTranslate } from '@pipeline/i18n';

type Props = {} & Omit<React.ComponentProps<typeof SelectInput>, 'errorMessage' | 'onChange' | 'value'>;

Expand All @@ -9,6 +10,16 @@ const FormSelect: React.FC<Props> = ({ name, label, options, disabled }) => {

const error = data.errors[name];

const t = useTranslate();

const translatedError = useMemo(() => {
if (!error) {
return undefined;
} else {
return t(error.message);
}
}, [error, t]);

const renderInput = useCallback(
(props: ControllerRenderProps) => {
return (
Expand All @@ -19,11 +30,11 @@ const FormSelect: React.FC<Props> = ({ name, label, options, disabled }) => {
options={options}
onChange={props.onChange}
disabled={disabled}
errorMessage={error ? error.message : null}
errorMessage={translatedError}
/>
);
},
[error, label, options, disabled],
[translatedError, label, options, disabled],
);

return (
Expand Down
17 changes: 14 additions & 3 deletions packages/game-app/src/_shared/form/FormTextField/FormTextField.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useCallback } from 'react';
import React, { useCallback, useMemo } from 'react';
import { Controller, ControllerRenderProps, useFormContext } from 'react-hook-form';
import { TextInput } from '@pipeline/components';
import { useTranslate } from '@pipeline/i18n';

type Props = {
name: string;
Expand All @@ -12,6 +13,16 @@ const FormTextField: React.FC<Props> = ({ name, label }) => {

const error = data.errors[name];

const t = useTranslate();

const translatedError = useMemo(() => {
if (!error) {
return undefined;
} else {
return t(error.message);
}
}, [error, t]);

const renderInput = useCallback(
(props: ControllerRenderProps) => {
return (
Expand All @@ -20,11 +31,11 @@ const FormTextField: React.FC<Props> = ({ name, label }) => {
label={label}
value={props.value}
onChange={props.onChange}
errorMessage={error?.message}
errorMessage={translatedError}
/>
);
},
[error, label],
[translatedError, label],
);

return (
Expand Down
14 changes: 14 additions & 0 deletions packages/game-app/src/assets/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,20 @@ const translations = {
test1: 'Pipeline - The Game that Delivers!',
test2: 'Random stuff',
},
signup: {
errors: {
invalidEmail: 'Invalid email',
passwordRequirements:
'The password must be 8 chars long and should contain at least a lowercase letter, an uppercase letter and a spectial character',
passwordMatch: 'The two password must match',
'auth/email-already-in-use': 'Ops, it seams that this email is not allowed',
},
},
general: {
errors: {
required: 'This field is required',
},
},
};

export default translations;
20 changes: 9 additions & 11 deletions packages/game-app/src/signup/apis/executeSignup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import 'firebase/firestore';
import { User } from '../../_shared/auth/slice';

export async function executeSignup(signupInfo: SignupInfo): Promise<User> {
try {
const credentials = await firebase.auth().createUserWithEmailAndPassword(signupInfo.email, signupInfo.password);
if (credentials.user) {
const user = credentials.user;
const credentials = await firebase.auth().createUserWithEmailAndPassword(signupInfo.email, signupInfo.password);
if (credentials.user) {
const user = credentials.user;
try {
await firebase.firestore().doc(`${FirebaseCollections.Users}/${user?.uid}`).set({
email: signupInfo.email,
role: signupInfo.role,
Expand All @@ -19,16 +19,14 @@ export async function executeSignup(signupInfo: SignupInfo): Promise<User> {
id: user.uid,
email: user.email!,
};
} else {
throw new Error('user-not-created');
}
} catch (e) {
try {
} catch (e) {
const currentUser = firebase.auth().currentUser;
if (currentUser !== null) {
await currentUser.delete();
}
} catch (e) {}
throw e;
throw e;
}
} else {
throw { code: 'user-not-created' };
}
}
18 changes: 2 additions & 16 deletions packages/game-app/src/signup/components/Signup/Signup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,18 @@ import React, { useMemo } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { FormSelect, FormTextField } from '@pipeline/form';
import { yupResolver } from '@hookform/resolvers/yup';
import * as yup from 'yup';
import { SignupInfo } from '../../types/signupInfo';
import useSignup from '../../hooks/useSignup';
import { useDevOpsMaturities, useGameRoles } from '@pipeline/dynamicData';
import { signupValidationSchema } from '../../utils/validation';

type Props = {};

const schema = yup.object().shape({
email: yup.string().required('signup.required').email('signup.invalidEmail'),
password: yup
.string()
.required('signup.required')
.matches(new RegExp('^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*])(?=.{8,})'), 'signup.passwordRequirements'),
repeatPassword: yup
.string()
.required('signup.required')
.oneOf([yup.ref('password')], 'signup.passwordMatch'),
role: yup.string().required('signup.required'),
devOpsMaturity: yup.string().required('signup.required'),
});

const Signup: React.FC<Props> = () => {
const methods = useForm<SignupInfo>({
defaultValues: {},
mode: 'onBlur',
resolver: yupResolver(schema),
resolver: yupResolver(signupValidationSchema),
});

const { handleSubmit } = methods;
Expand Down
2 changes: 1 addition & 1 deletion packages/game-app/src/signup/hooks/useSignup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as actions from '../actions';
import { createRequestHook } from '@pipeline/requests-status';

const useSignup = createRequestHook('signup', actions.signup, {
errorMessagesScope: 'signup',
errorMessagesScope: 'signup.errors',
});

export default useSignup;
20 changes: 20 additions & 0 deletions packages/game-app/src/signup/utils/validation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import * as yup from 'yup';

const requiredError = 'general.errors.required';

export const signupValidationSchema = yup.object().shape({
email: yup.string().required(requiredError).email('signup.errors.invalidEmail'),
password: yup
.string()
.required(requiredError)
.matches(
new RegExp('^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*])(?=.{8,})'),
'signup.errors.passwordRequirements',
),
repeatPassword: yup
.string()
.required(requiredError)
.oneOf([yup.ref('password')], 'signup.errors.passwordMatch'),
role: yup.string().required(requiredError),
devOpsMaturity: yup.string().required(requiredError),
});

0 comments on commit 93953f5

Please sign in to comment.