-
Notifications
You must be signed in to change notification settings - Fork 93
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #32 from daritelska-platforma/generic-form-updates
Generic form updates
- Loading branch information
Showing
26 changed files
with
663 additions
and
457 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"invalid": "Невалидно поле", | ||
"required": "Задължително поле", | ||
"email": "Невалиден email", | ||
"password-min": "Паролата трябва да бъде поне {{min}} символа", | ||
"password-match": "Паролата не съвпада", | ||
"field-too-short": "Полето трябва да бъде поне {{min}} символа", | ||
"field-too-long": "Полето трябва да бъде най-много {{max}} символа", | ||
"one-of": "Невалидна стойност" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"invalid": "Field is invalid", | ||
"required": "Required field", | ||
"email": "Invalid email", | ||
"password-min": "Password should be at least {{min}} characters", | ||
"password-match": "Password doesn't match", | ||
"field-too-short": "Field should be at least {{min}} symbols", | ||
"field-too-long": "Field should be maximum {{max}} symbols", | ||
"one-of": "Invalid value" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
# Forms and validation | ||
|
||
## Form definition | ||
|
||
```tsx | ||
import React from 'react' | ||
import * as yup from 'yup' | ||
import { useTranslation } from 'react-i18next' | ||
import { Grid, TextField, Button } from '@material-ui/core' | ||
|
||
import { AlertStore } from 'stores/AlertStore' | ||
import useForm, { translateError, customValidators } from 'common/form/useForm' | ||
|
||
export type FormData = { | ||
email: string | ||
} | ||
|
||
const validationSchema: yup.SchemaOf<FormData> = yup.object().defined().shape({ | ||
email: yup.string().email().required(), | ||
}) | ||
|
||
const defaults: FormData = { | ||
email: '', | ||
} | ||
|
||
export type MyFormProps = { initialValues?: FormData } | ||
|
||
export default function MyForm({ initialValues = defaults }: MyFormProps) { | ||
const { t } = useTranslation() | ||
|
||
const { formik } = useForm({ | ||
initialValues, | ||
validationSchema, | ||
onSubmit: (values) => { | ||
console.log(values) | ||
}, | ||
}) | ||
|
||
return ( | ||
<form onSubmit={formik.handleSubmit}> | ||
<Grid container spacing={3}> | ||
<Grid item xs={12}> | ||
<TextField | ||
type="text" | ||
fullWidth | ||
label={t('auth:fields.email')} | ||
name="email" | ||
size="small" | ||
variant="outlined" | ||
autoFocus | ||
error={Boolean(formik.errors.email)} | ||
helperText={translateError(formik.errors.email)} | ||
value={formik.values.email} | ||
onBlur={formik.handleBlur} | ||
onChange={formik.handleChange} | ||
/> | ||
</Grid> | ||
<Grid item xs={12}> | ||
<Button fullWidth type="submit" color="primary" variant="contained"> | ||
{t('auth:cta.login')} | ||
</Button> | ||
</Grid> | ||
</Grid> | ||
</form> | ||
) | ||
} | ||
``` | ||
|
||
## Form usage | ||
|
||
```tsx | ||
<MyForm /> | ||
|
||
<MyForm initailValues={{email: '[email protected]'}} /> | ||
``` | ||
|
||
## Validation | ||
|
||
### Default translations | ||
|
||
Simple strings are mapped directly to their respective translation | ||
|
||
```json | ||
{ | ||
"invalid": "Field is invalid", | ||
"required": "Required field" | ||
} | ||
``` | ||
|
||
```tsx | ||
setLocale({ | ||
mixed: { | ||
default: 'validation:invalid', | ||
required: 'validation:required', | ||
}, | ||
string: { | ||
email: 'validation:email', | ||
}, | ||
}) | ||
``` | ||
|
||
### Default translations with interpolation | ||
|
||
Complex translation keys are being evaluated upon translation | ||
|
||
```json | ||
{ | ||
"field-too-short": "Field should be at least {{min}} symbols", | ||
"field-too-long": "Field should be maximum {{max}} symbols" | ||
} | ||
``` | ||
|
||
```tsx | ||
setLocale({ | ||
string: { | ||
min: ({ min }: { min: number }) => ({ | ||
key: 'validation:field-too-short', | ||
values: { min }, | ||
}), | ||
max: ({ max }: { max: number }) => ({ | ||
key: 'validation:field-too-long', | ||
values: { max }, | ||
}), | ||
}, | ||
}) | ||
``` | ||
|
||
#### Custom translations in validation schema | ||
|
||
Commonly used translations with the same translation key | ||
|
||
```tsx | ||
yup.string().min(6 customValidators.passwordMin) | ||
``` | ||
|
||
#### Inline translations in validation schema | ||
|
||
Custom translations with keys defined right next to the form | ||
|
||
```tsx | ||
const validationSchema: yup.SchemaOf<FormData> = yup | ||
.object() | ||
.defined() | ||
.shape({ | ||
password: yup.string().min(6, ({ min }) => ({ | ||
key: 'validation:password-min', | ||
values: { min }, | ||
})), | ||
}) | ||
``` |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { FormikConfig, useFormik } from 'formik' | ||
|
||
export { translateError, customValidators } from 'common/form/validation' | ||
|
||
export default function useForm<T>({ | ||
validateOnChange = false, | ||
validateOnBlur = false, | ||
...formikProps | ||
}: FormikConfig<T>) { | ||
const formik = useFormik({ validateOnChange, validateOnBlur, ...formikProps }) | ||
|
||
return { formik } | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { setLocale } from 'yup' | ||
import { useTranslation } from 'react-i18next' | ||
|
||
export const translateError = ( | ||
field: (string | undefined) | { key: string; values?: any }, | ||
): string | undefined => { | ||
const { t } = useTranslation() | ||
console.log(field) | ||
if (!field) { | ||
return undefined | ||
} | ||
if (typeof field === 'string') { | ||
return t(field) | ||
} | ||
return t(field.key, field.values) | ||
} | ||
|
||
// Default translations: | ||
// return 'validation:<key>' | ||
|
||
// Default translations with interpolation: | ||
// return { key: 'validation:<key>', values: { min, max } } | ||
|
||
// Custom translations in validation schema: | ||
// yup.string().min(6 customValidators.passwordMin) | ||
|
||
// Inline translations in validation schema: | ||
// yup.string().min(6, ({ min }) => ({ key: 'validation:password-min', values: { min } })) | ||
|
||
export const customValidators = { | ||
passwordMin: ({ min }: { min: number }) => ({ | ||
key: 'validation:password-min', | ||
values: { min }, | ||
}), | ||
} | ||
|
||
setLocale({ | ||
mixed: { | ||
default: 'validation:invalid', | ||
required: 'validation:required', | ||
}, | ||
string: { | ||
min: ({ min }: { min: number }) => ({ | ||
key: 'validation:field-too-short', | ||
values: { min }, | ||
}), | ||
max: ({ max }: { max: number }) => ({ | ||
key: 'validation:field-too-long', | ||
values: { max }, | ||
}), | ||
email: 'validation:email', | ||
}, | ||
}) |
Oops, something went wrong.