-
Notifications
You must be signed in to change notification settings - Fork 5
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 #260 from hotosm/feat/user-profile
Feat: Complete profile, update user details, change password and other minor fixes
- Loading branch information
Showing
25 changed files
with
728 additions
and
34 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
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
File renamed without changes.
File renamed without changes.
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
File renamed without changes.
File renamed without changes.
File renamed without changes.
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
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
150 changes: 150 additions & 0 deletions
150
src/frontend/src/components/UpdateUserDetails/BasicDetails.tsx/index.tsx
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 @@ | ||
import { toast } from 'react-toastify'; | ||
import { Controller, useForm } from 'react-hook-form'; | ||
import { FormControl, Input, Label, Select } from '@Components/common/FormUI'; | ||
import { Flex, FlexColumn } from '@Components/common/Layouts'; | ||
import { countriesWithPhoneCodes } from '@Constants/countryCode'; | ||
import { getLocalStorageValue } from '@Utils/getLocalStorageValue'; | ||
import ErrorMessage from '@Components/common/ErrorMessage'; | ||
import { Button } from '@Components/RadixComponents/Button'; | ||
import { useMutation, useQueryClient } from '@tanstack/react-query'; | ||
import { patchUserProfile } from '@Services/common'; | ||
|
||
const BasicDetails = () => { | ||
const userProfile = getLocalStorageValue('userprofile'); | ||
const initialState = { | ||
name: userProfile?.name, | ||
country: userProfile?.country || null, | ||
city: userProfile?.city || null, | ||
phone_number: userProfile?.phone_number || null, | ||
}; | ||
const queryClient = useQueryClient(); | ||
|
||
const { register, handleSubmit, formState, control } = useForm({ | ||
defaultValues: initialState, | ||
}); | ||
|
||
const { mutate: updateBasicInfo, isLoading } = useMutation< | ||
any, | ||
any, | ||
any, | ||
unknown | ||
>({ | ||
mutationFn: payloadDataObject => patchUserProfile(payloadDataObject), | ||
onSuccess: () => { | ||
queryClient.invalidateQueries(['user-profile']); | ||
toast.success('Details Updated Successfully'); | ||
}, | ||
onError: err => { | ||
// eslint-disable-next-line no-console | ||
console.log(err); | ||
toast.error(err?.response?.data?.detail || 'Something went wrong'); | ||
}, | ||
}); | ||
|
||
const onSubmit = (formData: Record<string, any>) => { | ||
updateBasicInfo({ userId: userProfile?.id, data: formData }); | ||
}; | ||
|
||
return ( | ||
<section className="naxatw-w-full naxatw-px-14"> | ||
<Flex> | ||
<p className="naxatw-text-lg naxatw-font-bold">Basic Details</p> | ||
</Flex> | ||
<FlexColumn gap={5} className="naxatw-mt-5"> | ||
<Flex className="naxatw-h-14 naxatw-w-14 naxatw-items-center naxatw-justify-center naxatw-overflow-hidden naxatw-rounded-full naxatw-bg-grey-600"> | ||
<img src={userProfile.profile_img} alt="profilepic" /> | ||
</Flex> | ||
<FormControl> | ||
<Label>Name</Label> | ||
<Input | ||
placeholder="Enter Name" | ||
className="naxatw-mt-1" | ||
{...register('name', { | ||
required: 'Name is Required', | ||
})} | ||
readOnly | ||
/> | ||
<ErrorMessage message={formState?.errors?.name?.message as string} /> | ||
</FormControl> | ||
<FormControl> | ||
<Label required>Country</Label> | ||
<Controller | ||
control={control} | ||
name="country" | ||
defaultValue="" | ||
rules={{ | ||
required: 'Country is Required', | ||
}} | ||
render={({ field: { value, onChange } }) => ( | ||
<Select | ||
placeholder="Choose a Country" | ||
options={countriesWithPhoneCodes} | ||
labelKey="label" | ||
valueKey="label" | ||
selectedOption={value} | ||
onChange={onChange} | ||
/> | ||
)} | ||
/> | ||
<ErrorMessage | ||
message={formState?.errors?.country?.message as string} | ||
/> | ||
</FormControl> | ||
<FormControl> | ||
<Label required>City</Label> | ||
<Input | ||
placeholder="Enter City" | ||
className="naxatw-mt-1" | ||
{...register('city', { | ||
setValueAs: (value: string) => value?.trim(), | ||
required: 'City is Required', | ||
})} | ||
/> | ||
<ErrorMessage message={formState.errors?.city?.message as string} /> | ||
</FormControl> | ||
<FormControl> | ||
<Label required>Phone number</Label> | ||
<div className="naxatw-flex naxatw-space-x-1"> | ||
{/* <Input | ||
placeholder="+977" | ||
className="naxatw-mt-1 naxatw-w-14" | ||
{...register('country_code', { | ||
required: 'Phone Number is Required', | ||
})} | ||
/> */} | ||
<Input | ||
placeholder="Enter Phone number" | ||
className="naxatw-mt-1 naxatw-w-full" | ||
type="number" | ||
{...register('phone_number', { | ||
required: 'Phone Number is Required', | ||
minLength: { | ||
value: 5, | ||
message: 'Invalid Phone Number', | ||
}, | ||
})} | ||
/> | ||
</div> | ||
<ErrorMessage | ||
message={formState.errors?.phone_number?.message as string} | ||
/> | ||
</FormControl> | ||
</FlexColumn> | ||
<div className="naxatw-flex naxatw-justify-center naxatw-py-4"> | ||
<Button | ||
className="naxatw-bg-red" | ||
onClick={e => { | ||
e.preventDefault(); | ||
handleSubmit(onSubmit)(); | ||
}} | ||
withLoader | ||
isLoading={isLoading} | ||
> | ||
Save | ||
</Button> | ||
</div> | ||
</section> | ||
); | ||
}; | ||
|
||
export default BasicDetails; |
16 changes: 16 additions & 0 deletions
16
src/frontend/src/components/UpdateUserDetails/Header/index.tsx
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,16 @@ | ||
import BreadCrumb from '@Components/common/Breadcrumb'; | ||
|
||
const Header = () => { | ||
return ( | ||
<div className="naxatw-py-1"> | ||
<BreadCrumb | ||
data={[ | ||
{ name: 'Dashboard', navLink: '/' }, | ||
{ name: 'Edit Profile', navLink: '' }, | ||
]} | ||
/> | ||
</div> | ||
); | ||
}; | ||
|
||
export default Header; |
113 changes: 113 additions & 0 deletions
113
src/frontend/src/components/UpdateUserDetails/OrganizationDetails/index.tsx
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,113 @@ | ||
import { useForm } from 'react-hook-form'; | ||
import { toast } from 'react-toastify'; | ||
import { useMutation, useQueryClient } from '@tanstack/react-query'; | ||
import ErrorMessage from '@Components/common/ErrorMessage'; | ||
import { FormControl, Input, Label } from '@Components/common/FormUI'; | ||
import { Flex, FlexColumn } from '@Components/common/Layouts'; | ||
import { Button } from '@Components/RadixComponents/Button'; | ||
import { patchUserProfile } from '@Services/common'; | ||
import { getLocalStorageValue } from '@Utils/getLocalStorageValue'; | ||
|
||
const OrganizationDetails = () => { | ||
const userProfile = getLocalStorageValue('userprofile'); | ||
|
||
const initialState = { | ||
organization_name: userProfile?.organization_name || null, | ||
organization_address: userProfile?.organization_address || null, | ||
job_title: userProfile?.job_title || null, | ||
}; | ||
const queryClient = useQueryClient(); | ||
|
||
const { register, handleSubmit, formState } = useForm({ | ||
defaultValues: initialState, | ||
}); | ||
|
||
const { mutate: updateOrganizationDetails, isLoading } = useMutation< | ||
any, | ||
any, | ||
any, | ||
unknown | ||
>({ | ||
mutationFn: payloadDataObject => patchUserProfile(payloadDataObject), | ||
onSuccess: () => { | ||
queryClient.invalidateQueries(['user-profile']); | ||
|
||
toast.success('Details Updated successfully'); | ||
}, | ||
onError: err => { | ||
// eslint-disable-next-line no-console | ||
console.log(err); | ||
toast.error(err?.response?.data?.detail || 'Something went wrong'); | ||
}, | ||
}); | ||
|
||
const onSubmit = (formData: Record<string, any>) => { | ||
updateOrganizationDetails({ userId: userProfile?.id, data: formData }); | ||
}; | ||
|
||
return ( | ||
<section className="naxatw-w-full naxatw-px-14"> | ||
<Flex> | ||
<p className="naxatw-mb-2 naxatw-text-lg naxatw-font-bold"> | ||
Organization Details | ||
</p> | ||
</Flex> | ||
<FlexColumn gap={5}> | ||
<FormControl> | ||
<Label>Organization Name</Label> | ||
<Input | ||
placeholder="Enter Organization Name" | ||
className="naxatw-mt-1" | ||
{...register('organization_name', { | ||
// required: 'Organization name is Required', | ||
})} | ||
/> | ||
<ErrorMessage | ||
message={formState.errors?.organization_name?.message as string} | ||
/> | ||
</FormControl> | ||
<FormControl> | ||
<Label>Organization Address</Label> | ||
<Input | ||
placeholder="Enter Organization Address" | ||
className="naxatw-mt-1" | ||
{...register('organization_address', { | ||
// required: 'Organization Address is Required', | ||
})} | ||
/> | ||
<ErrorMessage | ||
message={formState.errors?.organization_address?.message as string} | ||
/> | ||
</FormControl> | ||
<FormControl> | ||
<Label>Job Title</Label> | ||
<Input | ||
placeholder="Enter Job Title" | ||
className="naxatw-mt-1" | ||
{...register('job_title', { | ||
// required: 'Job Title is Required', | ||
})} | ||
/> | ||
<ErrorMessage | ||
message={formState.errors?.job_title?.message as string} | ||
/> | ||
</FormControl> | ||
</FlexColumn> | ||
<div className="naxatw-flex naxatw-justify-center naxatw-py-4"> | ||
<Button | ||
className="naxatw-bg-red" | ||
onClick={e => { | ||
e.preventDefault(); | ||
handleSubmit(onSubmit)(); | ||
}} | ||
withLoader | ||
isLoading={isLoading} | ||
> | ||
Save | ||
</Button> | ||
</div> | ||
</section> | ||
); | ||
}; | ||
|
||
export default OrganizationDetails; |
Oops, something went wrong.