Skip to content

Commit fb21d36

Browse files
Field requirements (canada-ca#2866)
* reformat fieldRequirements the object is now formatted using yup createValidationSchema can create a schema from the passed keys custom validation schemas can be created with getRequirment and schemaToValidation * updates code to use new fieldRequirments * add remained of Field changes * Fix type="string" * remove await
1 parent c22672c commit fb21d36

24 files changed

+232
-422
lines changed

frontend/src/admin/AdminDomainModal.js

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import {
66
Button,
77
FormControl,
88
FormErrorMessage,
9-
FormLabel,
109
Grid,
1110
IconButton,
1211
Input,
@@ -26,6 +25,7 @@ import { array, bool, func, object, string } from 'prop-types'
2625
import { Field, FieldArray, Formik } from 'formik'
2726
import { useMutation } from '@apollo/client'
2827

28+
import { DomainField } from '../domains/DomainField'
2929
import { CREATE_DOMAIN, UPDATE_DOMAIN } from '../graphql/mutations'
3030

3131
export function AdminDomainModal({
@@ -193,30 +193,11 @@ export function AdminDomainModal({
193193
<ModalCloseButton />
194194
<ModalBody>
195195
<Stack spacing={4} p={25}>
196-
<Field id="domainUrl" name="domainUrl">
197-
{({ field, form }) => (
198-
<FormControl
199-
isInvalid={
200-
form.errors.domainUrl && form.touched.domainUrl
201-
}
202-
>
203-
<FormLabel htmlFor="domainUrl" fontWeight="bold">
204-
<Trans>New Domain URL:</Trans>
205-
</FormLabel>
206-
207-
<Input
208-
mb="2"
209-
{...field}
210-
id="domainUrl"
211-
placeholder={i18n._(t`New Domain URL`)}
212-
ref={initialFocusRef}
213-
/>
214-
<FormErrorMessage>
215-
{form.errors.domainUrl}
216-
</FormErrorMessage>
217-
</FormControl>
218-
)}
219-
</Field>
196+
<DomainField
197+
name="domainUrl"
198+
label={t`New Domain URL:`}
199+
placeholder={i18n._(t`New Domain URL`)}
200+
/>
220201

221202
<FieldArray
222203
name="selectors"

frontend/src/admin/AdminDomains.js

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,6 @@ import { AddIcon, EditIcon, MinusIcon, PlusSquareIcon } from '@chakra-ui/icons'
2525
import { useMutation } from '@apollo/client'
2626
import { useLingui } from '@lingui/react'
2727
import { number, string } from 'prop-types'
28-
import {
29-
array as yupArray,
30-
object as yupObject,
31-
string as yupString,
32-
} from 'yup'
3328

3429
import { AdminDomainModal } from './AdminDomainModal'
3530
import { AdminDomianCard } from './AdminDomianCard'
@@ -39,7 +34,7 @@ import { LoadingMessage } from '../components/LoadingMessage'
3934
import { ErrorFallbackMessage } from '../components/ErrorFallbackMessage'
4035
import { RelayPaginationControls } from '../components/RelayPaginationControls'
4136
import { useDebouncedFunction } from '../utilities/useDebouncedFunction'
42-
import { fieldRequirements } from '../utilities/fieldRequirements'
37+
import { createValidationSchema } from '../utilities/fieldRequirements'
4338
import { usePaginatedCollection } from '../utilities/usePaginatedCollection'
4439
import { PAGINATED_ORG_DOMAINS_ADMIN_PAGE as FORWARD } from '../graphql/queries'
4540
import { REMOVE_DOMAIN } from '../graphql/mutations'
@@ -141,20 +136,6 @@ export function AdminDomains({ orgSlug, domainsPerPage, orgId }) {
141136
},
142137
)
143138

144-
const updatedDomainValidationSchema = yupObject().shape({
145-
domainUrl: yupString().required(
146-
i18n._(fieldRequirements.domainUrl.required.message),
147-
),
148-
selectors: yupArray().of(
149-
yupString()
150-
.required(i18n._(fieldRequirements.selector.required.message))
151-
.matches(
152-
fieldRequirements.selector.matches.regex,
153-
i18n._(fieldRequirements.selector.matches.message),
154-
),
155-
),
156-
})
157-
158139
if (error) return <ErrorFallbackMessage error={error} />
159140

160141
const adminDomainList = loading ? (
@@ -279,7 +260,7 @@ export function AdminDomains({ orgSlug, domainsPerPage, orgId }) {
279260
<AdminDomainModal
280261
isOpen={updateIsOpen}
281262
onClose={updateOnClose}
282-
validationSchema={updatedDomainValidationSchema}
263+
validationSchema={createValidationSchema(['domainUrl', 'selectors'])}
283264
orgId={orgId}
284265
orgSlug={orgSlug}
285266
selectorInputList={selectorInputList}

frontend/src/admin/OrganizationInformation.js

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,17 @@ import { CheckCircleIcon, MinusIcon, EditIcon } from '@chakra-ui/icons'
2323
import { func, string } from 'prop-types'
2424
import { useMutation, useQuery } from '@apollo/client'
2525
import { t, Trans } from '@lingui/macro'
26-
import { object, string as yupString } from 'yup'
27-
import { useLingui } from '@lingui/react'
2826
import { Formik } from 'formik'
2927

3028
import { ORGANIZATION_INFORMATION } from '../graphql/queries'
3129
import { REMOVE_ORGANIZATION, UPDATE_ORGANIZATION } from '../graphql/mutations'
3230
import { FormField } from '../components/FormField'
3331
import { LoadingMessage } from '../components/LoadingMessage'
3432
import { ErrorFallbackMessage } from '../components/ErrorFallbackMessage'
35-
import { fieldRequirements } from '../utilities/fieldRequirements'
33+
import {
34+
getRequirment,
35+
schemaToValidation,
36+
} from '../utilities/fieldRequirements'
3637

3738
export function OrganizationInformation({
3839
orgSlug,
@@ -46,7 +47,6 @@ export function OrganizationInformation({
4647
onClose: onRemovalClose,
4748
} = useDisclosure()
4849
const removeOrgBtnRef = useRef()
49-
const { i18n } = useLingui()
5050
const [isEditingOrg, setIsEditingOrg] = useState(false)
5151

5252
const { loading, error, data } = useQuery(ORGANIZATION_INFORMATION, {
@@ -193,21 +193,16 @@ export function OrganizationInformation({
193193

194194
const org = data.findOrganizationBySlug
195195

196-
const updateOrgValidationSchema = object().shape({
197-
acronymEN: yupString().matches(
198-
fieldRequirements.acronym.matches.regex,
199-
i18n._(fieldRequirements.acronym.matches.message),
200-
),
201-
acronymFR: yupString().matches(
202-
fieldRequirements.acronym.matches.regex,
203-
i18n._(fieldRequirements.acronym.matches.message),
204-
),
196+
const updateOrgValidationSchema = schemaToValidation({
197+
acronymEN: getRequirment('acronym'),
198+
acronymFR: getRequirment('acronym'),
205199
})
206200

207-
const removeOrgValidationSchema = object().shape({
208-
orgName: yupString()
209-
.required(i18n._(fieldRequirements.field.required.message))
210-
.matches(org.name, t`Organization name does not match.`),
201+
const removeOrgValidationSchema = schemaToValidation({
202+
orgName: getRequirment('field').matches(
203+
org.name,
204+
t`Organization name does not match.`,
205+
),
211206
})
212207

213208
return (

frontend/src/admin/UserListModal.js

Lines changed: 8 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import React, { useRef } from 'react'
22
import {
33
Button,
44
FormLabel,
5-
Input,
65
Modal,
76
ModalBody,
87
ModalCloseButton,
@@ -13,22 +12,16 @@ import {
1312
Stack,
1413
useToast,
1514
Select,
16-
FormControl,
17-
FormErrorMessage,
1815
Text,
19-
InputGroup,
20-
InputLeftElement,
2116
} from '@chakra-ui/react'
2217
import { t, Trans } from '@lingui/macro'
23-
import { Field, Formik } from 'formik'
18+
import { Formik } from 'formik'
2419
import { useMutation } from '@apollo/client'
25-
import { useLingui } from '@lingui/react'
26-
import { EmailIcon } from '@chakra-ui/icons'
2720
import { bool, func, string } from 'prop-types'
28-
import { object as yupObject, string as yupString } from 'yup'
2921

22+
import { EmailField } from '../components/EmailField'
3023
import { UPDATE_USER_ROLE, INVITE_USER_TO_ORG } from '../graphql/mutations'
31-
import { fieldRequirements } from '../utilities/fieldRequirements'
24+
import { createValidationSchema } from '../utilities/fieldRequirements'
3225

3326
export function UserListModal({
3427
isOpen,
@@ -42,7 +35,6 @@ export function UserListModal({
4235
}) {
4336
const toast = useToast()
4437
const initialFocusRef = useRef()
45-
const { i18n } = useLingui()
4638

4739
const [addUser, { loading: _addUserLoading }] = useMutation(
4840
INVITE_USER_TO_ORG,
@@ -156,29 +148,25 @@ export function UserListModal({
156148
validateOnBlur={false}
157149
initialValues={{
158150
role: editingUserRole,
159-
userName: editingUserName,
151+
email: editingUserName,
160152
}}
161-
validationSchema={yupObject().shape({
162-
userName: yupString()
163-
.required(i18n._(fieldRequirements.email.required.message))
164-
.email(i18n._(fieldRequirements.email.email.message)),
165-
})}
153+
validationSchema={createValidationSchema(['email'])}
166154
onSubmit={async (values) => {
167155
// Submit update role mutation
168156
if (mutation === 'update') {
169157
await updateUserRole({
170158
variables: {
171159
orgId: orgId,
172160
role: values.role,
173-
userName: values.userName,
161+
userName: values.email,
174162
},
175163
})
176164
} else if (mutation === 'create') {
177165
await addUser({
178166
variables: {
179167
orgId: orgId,
180168
requestedRole: values.role,
181-
userName: values.userName,
169+
userName: values.email,
182170
preferredLang: 'ENGLISH',
183171
},
184172
})
@@ -204,36 +192,7 @@ export function UserListModal({
204192
<Text>{editingUserName}</Text>
205193
</Stack>
206194
) : (
207-
<Field id="userName" name="userName">
208-
{({ field, form }) => (
209-
<FormControl
210-
isInvalid={
211-
form.errors.userName && form.touched.userName
212-
}
213-
>
214-
<Stack isInline align="center">
215-
<FormLabel htmlFor="userName" fontWeight="bold">
216-
<Trans>User:</Trans>
217-
</FormLabel>
218-
<InputGroup>
219-
<InputLeftElement aria-hidden="true">
220-
<EmailIcon color="gray.300" />
221-
</InputLeftElement>
222-
<Input
223-
mb="2"
224-
{...field}
225-
id="userName"
226-
placeholder={i18n._(t`user email`)}
227-
ref={initialFocusRef}
228-
/>
229-
</InputGroup>
230-
</Stack>
231-
<FormErrorMessage>
232-
{form.errors.userName}
233-
</FormErrorMessage>
234-
</FormControl>
235-
)}
236-
</Field>
195+
<EmailField />
237196
)}
238197
<Stack isInline align="center">
239198
<FormLabel htmlFor="role" fontWeight="bold" mt="2">

frontend/src/admin/__tests__/AdminDomains.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ describe('<AdminDomains />', () => {
229229
},
230230
]
231231

232-
const { getByText, getByRole, findByRole } = render(
232+
const { getByText, getByRole } = render(
233233
<MockedProvider mocks={mocks} cache={createCache()}>
234234
<UserVarProvider
235235
userVar={makeVar({
@@ -253,7 +253,7 @@ describe('<AdminDomains />', () => {
253253
</MockedProvider>,
254254
)
255255

256-
const domainUrlInput = await findByRole('textbox', {
256+
const domainUrlInput = getByRole('textbox', {
257257
name: 'Search by Domain URL',
258258
})
259259

frontend/src/auth/CreateUserPage.js

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,9 @@ import {
99
useToast,
1010
} from '@chakra-ui/react'
1111
import { useMutation } from '@apollo/client'
12-
import { object, string } from 'yup'
1312
import { Link as RouteLink, useParams } from 'react-router-dom'
1413
import { Formik } from 'formik'
1514
import { t, Trans } from '@lingui/macro'
16-
import { i18n } from '@lingui/core'
1715
import { ArrowForwardIcon, CheckCircleIcon } from '@chakra-ui/icons'
1816

1917
import { LanguageSelect } from './LanguageSelect'
@@ -22,7 +20,7 @@ import { EmailField } from '../components/EmailField'
2220
import { DisplayNameField } from '../components/DisplayNameField'
2321
import { PasswordConfirmation } from '../components/PasswordConfirmation'
2422
import { LoadingMessage } from '../components/LoadingMessage'
25-
import { fieldRequirements } from '../utilities/fieldRequirements'
23+
import { createValidationSchema } from '../utilities/fieldRequirements'
2624
import { useUserVar } from '../utilities/userState'
2725
import { activate } from '../utilities/i18n.config'
2826
import TermsConditionsPage from '../termsConditions/TermsConditionsPage'
@@ -34,30 +32,6 @@ export default function CreateUserPage() {
3432
const userOrgToken = useParams().userOrgToken || ''
3533
const [showVerifyMessage, setShowVerifyMessage] = useState(false)
3634

37-
const validationSchema = object().shape({
38-
email: string()
39-
.required(i18n._(fieldRequirements.email.required.message))
40-
.email(i18n._(fieldRequirements.email.email.message)),
41-
displayName: string().required(
42-
i18n._(fieldRequirements.displayName.required.message),
43-
),
44-
password: string()
45-
.required(i18n._(fieldRequirements.password.required.message))
46-
.min(
47-
fieldRequirements.password.min.minLength,
48-
i18n._(fieldRequirements.password.min.message),
49-
),
50-
confirmPassword: string()
51-
.required(i18n._(fieldRequirements.confirmPassword.required.message))
52-
.oneOf(
53-
fieldRequirements.confirmPassword.oneOf.types,
54-
i18n._(fieldRequirements.confirmPassword.oneOf.message),
55-
),
56-
lang: string()
57-
.required(i18n._(fieldRequirements.lang.required.message))
58-
.oneOf(fieldRequirements.lang.oneOf.types),
59-
})
60-
6135
const [signUp, { loading }] = useMutation(SIGN_UP, {
6236
onError(error) {
6337
toast({
@@ -159,7 +133,13 @@ export default function CreateUserPage() {
159133
return (
160134
<Box px="4" mx="auto" overflow="hidden">
161135
<Formik
162-
validationSchema={validationSchema}
136+
validationSchema={createValidationSchema([
137+
'email',
138+
'displayName',
139+
'password',
140+
'confirmPassword',
141+
'lang',
142+
])}
163143
initialValues={{
164144
email: '',
165145
displayName: '',

frontend/src/auth/SignInPage.js

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import React from 'react'
22
import { t, Trans } from '@lingui/macro'
3-
import { object, string } from 'yup'
43
import {
54
Box,
65
Button,
@@ -21,7 +20,10 @@ import { PasswordField } from '../components/PasswordField'
2120
import { LoadingMessage } from '../components/LoadingMessage'
2221
import { useUserVar } from '../utilities/userState'
2322
import { activate } from '../utilities/i18n.config'
24-
import { fieldRequirements } from '../utilities/fieldRequirements'
23+
import {
24+
getRequirment,
25+
schemaToValidation,
26+
} from '../utilities/fieldRequirements'
2527
import { SIGN_IN } from '../graphql/mutations'
2628

2729
export default function SignInPage() {
@@ -33,13 +35,9 @@ export default function SignInPage() {
3335

3436
const { from } = location.state || { from: { pathname: '/' } }
3537

36-
const validationSchema = object().shape({
37-
password: string().required(
38-
i18n._(fieldRequirements.password.required.message),
39-
),
40-
email: string()
41-
.required(i18n._(fieldRequirements.email.required.message))
42-
.email(i18n._(fieldRequirements.email.email.message)),
38+
const validationSchema = schemaToValidation({
39+
email: getRequirment('email'),
40+
password: getRequirment('passwordSignIn'),
4341
})
4442

4543
const [signIn, { loading }] = useMutation(SIGN_IN, {

0 commit comments

Comments
 (0)