diff --git a/package.json b/package.json index 0e56e1a0..bac25904 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "@sentry/react": "^7.81.1", "@togglecorp/fujs": "^2.1.1", "@togglecorp/re-map": "^0.2.0-beta-6", + "@togglecorp/toggle-form": "^2.0.4", "@turf/bbox": "^6.5.0", "@turf/circle": "^6.5.0", "graphql": "^16.8.1", diff --git a/src/views/Register/i18n.json b/src/views/Register/i18n.json index 755d2795..0fe2941f 100644 --- a/src/views/Register/i18n.json +++ b/src/views/Register/i18n.json @@ -11,18 +11,10 @@ "registerCity": "City", "registerOrganizationType": "Organization Type", "registerOrganizationName": "Organization Name", - "registerDepartment": "Department", - "registerPosition": "Position", - "registerPhoneNumber": "Phone Number", "registerPassword": "Password", "registerConfirmPassword": "Confirm Password", - "registerJustification": "Justification", "registerSubmit": "Register", "registerAccountPresent": "Already have an account? {loginLink}", - "registerLogin": "Login", - "registrationFailure": "Sorry could not register new user right now!", - "registrationSuccess": "Successfully created a user!", - "requestAccess": "Request Access", - "registerJustify": "It appears you do not have an official Red Cross Red Crescent email, we will need to verify your status. Please note, this may take some time." + "registerLogin": "Login" } } diff --git a/src/views/Register/index.tsx b/src/views/Register/index.tsx index 2b73584a..64e05e9a 100644 --- a/src/views/Register/index.tsx +++ b/src/views/Register/index.tsx @@ -2,21 +2,14 @@ import { useState } from 'react'; import { Button, SelectInput, - TextArea, TextInput, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; -import { - isWhitelistedEmail, - resolveToComponent, -} from '@ifrc-go/ui/utils'; -import { - isDefined, - isTruthyString, - isValidEmail, -} from '@togglecorp/fujs'; +import { resolveToComponent } from '@ifrc-go/ui/utils'; +import { isTruthyString } from '@togglecorp/fujs'; import { addCondition, + createSubmitHandler, emailCondition, getErrorObject, type ObjectSchema, @@ -31,6 +24,18 @@ import Page from '#components/Page'; import i18n from './i18n.json'; import styles from './styles.module.css'; +interface DefaultFormValue { + first_name: string; + last_name: string; + email: string; + password: string; + confirm_password: string; + country: string; + city: string; + organization: string; + organization_type: string; +} + function getPasswordMatchCondition(referenceVal: string | undefined) { return (val: string | undefined) => ( isTruthyString(val) && isTruthyString(referenceVal) && val !== referenceVal @@ -39,72 +44,44 @@ function getPasswordMatchCondition(referenceVal: string | undefined) { ); } -const registerationData = { - whitelistedDomains: [ - { id: '1', domain: 'example.org' }, - { id: '2', domain: 'example.com' }, - { id: '3', domain: 'nonprofit.net' }, - ], - organizationTypes: [ - { id: '101', key: 'NTLS', value: 'National Society' }, - { id: '102', key: 'NGO', value: 'Non-Governmental Organization' }, - { id: '103', key: 'UN', value: 'United Nations Agency' }, - ], - nationalSocietyOptions: [ - { id: '201', society_name: 'Red Cross Society' }, - { id: '202', society_name: 'Red Crescent Society' }, - ], - strings: { - registerTitle: 'Register Account', - registerHeader: 'Create Your Account', - registerSubHeader: 'Join us to access exclusive content.', - registerFirstName: 'First Name', - registerLastName: 'Last Name', - registerEmail: 'Email Address', - registerPassword: 'Password', - registerConfirmPassword: 'Confirm Password', - registerCountry: 'Country', - registerCity: 'City', - registerOrganizationType: 'Organization Type', - registerOrganizationName: 'Organization Name', - registerDepartment: 'Department', - registerPosition: 'Position', - registerPhoneNumber: 'Phone Number', - registerJustify: 'Please provide a justification for access.', - registerJustification: 'Justification', - registerSubmit: 'Register', - registerAccountPresent: 'Already have an account? Login', - registerLogin: 'Login', - requestAccess: 'Request Access', - }, - defaultFormValue: { - first_name: '', - last_name: '', - email: '', - password: '', - confirm_password: '', - country: '', - city: '', - organization: '', - organization_type: '', - department: '', - position: '', - phone_number: '', - justification: '', - }, -}; +const organizationTypes = [ + { id: '101', key: 'NTLS', value: 'National Society' }, + { id: '102', key: 'NGO', value: 'Non-Governmental Organization' }, + { id: '103', key: 'UN', value: 'United Nations Agency' }, +]; +const nationalSocietyOptions = [ + { id: '201', society_name: 'Red Cross Society' }, + { id: '202', society_name: 'Red Crescent Society' }, +]; +const whitelistedDomains = [ + 'example.com', + 'anotherdomain.org', + 'somedomain.net', +]; -type FormFields = typeof registerationData['defaultFormValue']; +type FormFields = DefaultFormValue; -const keySelector = (option: { key: string; label: string }) => option.key; -const labelSelector = (option: { key: string; label: string }) => option.label; +const keySelector = (option: { id: string; society_name: string }): string => option.id; +const labelSelector = (option: { id: string; society_name: string }) => option.society_name; -type FormSchema = ObjectSchema; -type FormSchemaFields = ReturnType +type PartialFormFields = Partial; +type FormSchema = ObjectSchema; +type FormSchemaFields = ReturnType; + +const isWhitelistedEmail = (email: string): boolean => { + const domain = email.split('@')[1]; + return whitelistedDomains.includes(domain); +}; + +const emailWhitelistValidation = (value: string | undefined) => { + if (!isWhitelistedEmail(value || '')) { + return 'Email not allowed'; + } + return undefined; +}; const formSchema: FormSchema = { - fields: (value, _, context): FormSchemaFields => { + fields: (value): FormSchemaFields => { let fields: FormSchemaFields = { first_name: { required: true, @@ -117,7 +94,7 @@ const formSchema: FormSchema = { email: { required: true, requiredValidation: requiredStringCondition, - validations: [emailCondition], + validations: [emailCondition, emailWhitelistValidation], }, password: { required: true, @@ -143,18 +120,6 @@ const formSchema: FormSchema = { required: true, requiredValidation: requiredStringCondition, }, - department: { - defaultValue: undefinedValue, - }, - position: { - defaultValue: undefinedValue, - }, - phone_number: { - defaultValue: undefinedValue, - }, - justification: { - forceValue: undefinedValue, - }, }; fields = addCondition( fields, @@ -171,34 +136,6 @@ const formSchema: FormSchema = { }), ); - fields = addCondition( - fields, - value, - ['email'], - ['justification'], - (safeValue) => { - const justificationNeeded = ( - isDefined(safeValue) - && isTruthyString(safeValue.email) - && isValidEmail(safeValue.email) - && context.whitelistedDomains - && !isWhitelistedEmail(safeValue.email, context.whitelistedDomains) - ); - - return !justificationNeeded - ? { - justification: { - forceValue: undefinedValue, - }, - } - : { - justification: { - required: true, - requiredValidation: requiredStringCondition, - }, - }; - }, - ); return fields; }, }; @@ -206,22 +143,24 @@ const formSchema: FormSchema = { // eslint-disable-next-line import/prefer-default-export export function Component() { const strings = useTranslation(i18n); - const [formValue] = useState(registerationData.defaultFormValue); + const [formValue] = useState({}); - const { value, error, setFieldValue } = useForm(formSchema, { - value: registerationData.defaultFormValue, + const { + value, + setFieldValue, + setError, + validate, + } = useForm(formSchema, { + value: formValue, }); - const fieldError = getErrorObject(error); - const isNationalSociety = formValue.organization_type === 'NTLS'; - const justificationNeeded = ( - isTruthyString(formValue.email) - && isValidEmail(formValue.email) - ); + const fieldError: PartialFormFields = {}; + const handleFormSubmit = createSubmitHandler(validate, setError, () => {}); + const isNationalSociety = formValue?.organization_type === 'NTLS'; const loginInfo = resolveToComponent(strings.registerAccountPresent, { loginLink: ( {strings.registerLogin} @@ -255,6 +194,7 @@ export function Component() { withAsterisk /> +
setFieldValue} + value={value.organization_type} + onChange={setFieldValue} error={fieldError?.organization_type} - withAsterisk /> -
- setFieldValue} - keySelector={keySelector} - labelSelector={labelSelector} - options={registerationData.organizationTypes} - error={fieldError?.organization_type} - disabled={false} - withAsterisk /> {isNationalSociety ? ( setFieldValue} + value={value.organization} + onChange={setFieldValue} error={fieldError?.organization} - withAsterisk /> ) : ( )} - - - - {justificationNeeded && ( - <> -
- {strings.registerJustify} -
-