Skip to content

Commit

Permalink
feat: updates validation logic for edit profile
Browse files Browse the repository at this point in the history
- matches server logic for firstname, lastname, name, address, city
- adds translations to editProfile.json
- groups translation text for field labels & validation errors together
- removes unreqd translation files from serverSideTranslations for page
  • Loading branch information
mohitb35 committed Nov 10, 2023
1 parent 257e872 commit f0c6b0c
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 67 deletions.
21 changes: 1 addition & 20 deletions pages/profile/edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,26 +25,7 @@ export async function getStaticProps({ locale }: GetStaticPropsContext) {
props: {
...(await serverSideTranslations(
locale || 'en',
[
'bulkCodes',
'common',
'country',
'donate',
'donationLink',
'editProfile',
'giftfunds',
'leaderboard',
'managePayouts',
'manageProjects',
'maps',
'me',
'planet',
'planetcash',
'redeem',
'registerTrees',
'tenants',
'treemapper',
],
['editProfile', 'me', 'common', 'country'],
null,
['en', 'de', 'fr', 'es', 'it', 'pt-BR', 'cs']
)),
Expand Down
48 changes: 36 additions & 12 deletions public/static/locales/en/editProfile.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,17 @@
"loginTitle": "{{log}} - Login",
"signUpText": "Complete Signup",
"profileTypes": "{{item.title}}",
"profileName": "Name of {{type}}",
"createAccount": "Create Account",
"individual": "Person",
"iamA": "I am a",
"tpo": "Reforestation Organisation",
"education": "School",
"organization": "Company",
"profileCreated": "Profile Successfully created!",
"profileCreationFailed": "Error in creating profile. Please try again.",
"profileCreationError": "Error in creating profile.",
"edit": "Edit Profile",
"privateAccount": "Private Account",
"privateAccountTxt": "Your profile is hidden and only your first name appears in the leaderboard",
"subscribe": "Subscribe to news via email",
"profileDescription": "Profile Desciption",
"descriptionRequired": "You have exceeded the maximum length",
"website": "Website",
"websiteError": "Invalid website URL",
"websiteRequired": "Please enter valid Website URL",
"save": "Save",
"nameValidation": "Please enter a name",
"profilePicUpdated": "Profile picture is being updated...",
"profileSaved": "Saved successfully!",
"profileSaveFailed": "Error in updating profile.",
Expand All @@ -32,5 +22,39 @@
"continue": "Continue",
"cancel": "Cancel",
"termAndCondition": "I agree to the <0>Terms and Conditions</0> of the Plant-for-the-Planet platform.",
"termAndConditionError": "Please Accept the Terms and Conditions"
}
"termAndConditionError": "Please Accept the Terms and Conditions",
"fieldLabels": {
"profileType": "I am a",
"firstName": "First Name",
"lastName": "Last Name",
"name": "Name of {{type}}",
"email": "Email",
"address": "Address",
"city": "City",
"zipCode": "Postal/Zip Code",
"country": "Country",
"bio": "Profile Desciption",
"website": "Website",
"privateAccount": "Private Account",
"subscribe": "Subscribe to news via email"
},
"validationErrors": {
"maxChars": "Should be {{max}} characters or less",
"firstNameRequired": "First Name field is required",
"firstNameInvalid": "First name is invalid. Only these special characters are allowed: space ' . -",
"lastNameRequired": "Last Name field is required",
"lastNameInvalid": "Last name is invalid. Only these special characters are allowed: space ' -",
"emailRequired": "Email is required",
"nameRequired": "Please enter a name",
"nameInvalid": "Name is invalid. Only these special characters are allowed: space . , ' & ( ) ! -",
"addressRequired": "Address is required",
"addressInvalid": "Address is invalid. Only these special characters are allowed: space . , # - /",
"cityRequired": "City is required",
"cityInvalid": "City is invalid. Only letters and these special characters are allowed: space . , ( ) -",
"zipCodeRequired": "Zip Code is required",
"zipCodeInvalid": "Zip Code is invalid",
"websiteInvalid": "Please enter valid Website URL",
"countryRequired": "Country is required",
"companyRequired": "Company Name is required"
}
}
107 changes: 72 additions & 35 deletions src/features/user/Settings/EditProfile/EditProfileForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export default function EditProfileForm() {
const { user, setUser, token, contextLoaded, logoutUser } = useUserProps();

const [isUploadingData, setIsUploadingData] = React.useState(false);
const { t, ready } = useTranslation(['editProfile', 'donate']);
const { t, ready } = useTranslation('editProfile');

const defaultProfileDetails = useMemo(() => {
return {
Expand Down Expand Up @@ -179,24 +179,24 @@ export default function EditProfileForm() {
);
const [localProfileType, setLocalProfileType] = useState<ProfileTypeOption>({
id: 1,
title: ready ? t('editProfile:individual') : '',
title: ready ? t('individual') : '',
value: 'individual',
});

const profileTypes: ProfileTypeOption[] = [
{
id: 1,
title: ready ? t('editProfile:individual') : '',
title: ready ? t('individual') : '',
value: 'individual',
},
{
id: 2,
title: ready ? t('editProfile:organization') : '',
title: ready ? t('organization') : '',
value: 'organization',
},
{
id: 3,
title: ready ? t('editProfile:education') : '',
title: ready ? t('education') : '',
value: 'education',
},
];
Expand Down Expand Up @@ -229,7 +229,7 @@ export default function EditProfileForm() {
imageFile: event.target?.result,
};
setSeverity('info');
setSnackbarMessage(ready ? t('editProfile:profilePicUpdated') : '');
setSnackbarMessage(ready ? t('profilePicUpdated') : '');
handleSnackbarOpen();

try {
Expand Down Expand Up @@ -278,7 +278,7 @@ export default function EditProfileForm() {
logoutUser
);
setSeverity('success');
setSnackbarMessage(ready ? t('editProfile:profileSaved') : '');
setSnackbarMessage(ready ? t('profileSaved') : '');
handleSnackbarOpen();
setIsUploadingData(false);
setUser(res);
Expand Down Expand Up @@ -342,18 +342,28 @@ export default function EditProfileForm() {
}
}}
renderInput={(params) => (
<TextField {...params} label={t('editProfile:iamA')} />
<TextField {...params} label={t('fieldLabels.profileType')} />
)}
/>
) : null}
<InlineFormDisplayGroup>
<Controller
name="firstname"
control={control}
rules={{ required: t('donate:firstNameRequired') }}
rules={{
required: t('validationErrors.firstNameRequired'),
maxLength: {
value: 50,
message: t('validationErrors.maxChars', { max: 50 }),
},
pattern: {
value: /^[\p{L}\p{N}\sß.'-]+$/u,
message: t('validationErrors.firstNameInvalid'),
},
}}
render={({ field: { onChange, value, onBlur } }) => (
<TextField
label={t('donate:firstName')}
label={t('fieldLabels.firstName')}
onChange={onChange}
onBlur={onBlur}
value={value}
Expand All @@ -367,10 +377,20 @@ export default function EditProfileForm() {
<Controller
name="lastname"
control={control}
rules={{ required: t('donate:lastNameRequired') }}
rules={{
required: t('validationErrors.lastNameRequired'),
maxLength: {
value: 50,
message: t('validationErrors.maxChars', { max: 50 }),
},
pattern: {
value: /^[\p{L}\p{N}\sß'-]+$/u,
message: t('validationErrors.lastNameInvalid'),
},
}}
render={({ field: { onChange, value, onBlur } }) => (
<TextField
label={t('donate:lastName')}
label={t('fieldLabels.lastName')}
onChange={onChange}
onBlur={onBlur}
value={value}
Expand All @@ -383,7 +403,7 @@ export default function EditProfileForm() {
/>
</InlineFormDisplayGroup>
<TextField
label={t('donate:email')}
label={t('fieldLabels.email')}
name="email"
defaultValue={user?.email}
disabled
Expand All @@ -392,10 +412,16 @@ export default function EditProfileForm() {
<Controller
name="name"
control={control}
rules={{ required: t('editProfile:nameValidation') }}
rules={{
required: t('validationErrors.nameRequired'),
pattern: {
value: /^[\p{L}\p{N}\sß.,'&()!-]+$/u,
message: t('validationErrors.nameInvalid'),
},
}}
render={({ field: { onChange, value, onBlur } }) => (
<TextField
label={t('editProfile:profileName', {
label={t('fieldLabels.name', {
type: selectUserType(type, t),
})}
onChange={onChange}
Expand All @@ -411,12 +437,18 @@ export default function EditProfileForm() {
<Controller
name="address"
control={control}
rules={{ required: t('donate:addressRequired') }}
rules={{
required: t('validationErrors.addressRequired'),
pattern: {
value: /^[\p{L}\p{N}\sß.,#/-]+$/u,
message: t('validationErrors.addressInvalid'),
},
}}
render={({
field: { onChange: handleChange, value, onBlur: handleBlur },
}) => (
<TextField
label={t('donate:address')}
label={t('fieldLabels.address')}
onChange={(event) => {
suggestAddress(event.target.value);
handleChange(event);
Expand Down Expand Up @@ -457,10 +489,16 @@ export default function EditProfileForm() {
<Controller
name="city"
control={control}
rules={{ required: t('donate:cityRequired') }}
rules={{
required: t('validationErrors.cityRequired'),
pattern: {
value: /^[\p{L}\sß.,()-]+$/u,
message: t('validationErrors.cityInvalid'),
},
}}
render={({ field: { onChange, value, onBlur } }) => (
<TextField
label={t('donate:city')}
label={t('fieldLabels.city')}
onChange={onChange}
onBlur={onBlur}
value={value}
Expand All @@ -473,12 +511,15 @@ export default function EditProfileForm() {
name="zipCode"
control={control}
rules={{
required: t('donate:zipCodeAlphaNumValidation'),
pattern: postalRegex,
required: t('validationErrors.zipCodeRequired'),
pattern: {
value: postalRegex as RegExp,
message: t('validationErrors.zipCodeInvalid'),
},
}}
render={({ field: { onChange, value, onBlur } }) => (
<TextField
label={t('donate:zipCode')}
label={t('fieldLabels.zipCode')}
onChange={onChange}
onBlur={onBlur}
value={value}
Expand All @@ -493,7 +534,7 @@ export default function EditProfileForm() {
<AutoCompleteCountry
defaultValue={country}
onChange={setCountry}
label={t('donate:country')}
label={t('fieldLabels.country')}
name="editProfile"
countries={allCountries}
/>
Expand All @@ -504,12 +545,12 @@ export default function EditProfileForm() {
className={styles.mainText}
style={{ cursor: 'pointer' }}
>
{t('editProfile:privateAccount')}
{t('fieldLabels.privateAccount')}
</label>{' '}
<br />
{watchIsPrivate && (
<label className={styles.isPrivateAccountText}>
{t('editProfile:privateAccountTxt')}
{t('privateAccountTxt')}
</label>
)}
</div>
Expand All @@ -533,7 +574,7 @@ export default function EditProfileForm() {
className={styles.mainText}
style={{ cursor: 'pointer' }}
>
{t('editProfile:subscribe')}
{t('fieldLabels.subscribe')}
</label>

<Controller
Expand All @@ -558,12 +599,12 @@ export default function EditProfileForm() {
rules={{
maxLength: {
value: 300,
message: t('editProfile:descriptionRequired'),
message: t('validationErrors.maxChars', { max: 300 }),
},
}}
render={({ field: { onChange, value, onBlur } }) => (
<TextField
label={t('editProfile:profileDescription')}
label={t('fieldLabels.bio')}
onChange={onChange}
onBlur={onBlur}
value={value}
Expand All @@ -583,12 +624,12 @@ export default function EditProfileForm() {
//value: /^(?:http(s)?:\/\/)?[\w\.\-]+(?:\.[\w\.\-]+)+[\w\.\-_~:/?#[\]@!\$&'\(\)\*\+,;=#%]+$/,
value:
/^(https?:\/\/)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=*]*)$/,
message: t('editProfile:websiteRequired'),
message: t('validationErrors.websiteInvalid'),
},
}}
render={({ field: { onChange, value, onBlur } }) => (
<TextField
label={t('editProfile:website')}
label={t('fieldLabels.website')}
onChange={onChange}
onBlur={onBlur}
value={value}
Expand All @@ -605,11 +646,7 @@ export default function EditProfileForm() {
onClick={handleSubmit(saveProfile)}
disabled={isUploadingData}
>
{isUploadingData ? (
<div className={styles.spinner}></div>
) : (
t('editProfile:save')
)}
{isUploadingData ? <div className={styles.spinner}></div> : t('save')}
</Button>

{/* snackbar for showing various messages */}
Expand Down

0 comments on commit f0c6b0c

Please sign in to comment.