Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: updateprofile #126

Merged
merged 2 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified src/app/favicon.ico
Binary file not shown.
6 changes: 6 additions & 0 deletions src/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ body {
overflow-y: hidden;
}

.truncate-text {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

@layer components {
.btn {
@apply p-3 rounded-md flex text-[#ffffff] items-center justify-center text-base;
Expand Down
189 changes: 96 additions & 93 deletions src/components/Timeline/Modals/EditProfileModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ import { useEffect, useState } from 'react'
import { replaceImage } from '@/services/uploadImage'
import { currYear, degreeAndMajors, GenderOptions, occupationAndDepartment } from '@/types/RegisterForm'
import { FaCamera } from 'react-icons/fa'
import { useGetUserData } from '@/services/user'
import { profile } from 'console'

export interface editProfileInputs {
first_name: string
last_name: string
firstName: string
lastName: string
profilePicture: string | null
users_id: string
profile_dp?: string
email?: string
Expand All @@ -39,8 +42,11 @@ export interface editProfileInputs {
const EditProfileModal = () => {
const { mutate: mutateEditProfile, isPending } = useEditProfile()
const { userData, userProfileData } = useUniStore()
const { data: userProfile } = useGetUserData(userProfileData?.users_id as string)

const [user, setUser] = useState<any>(null)
const [userType, setUserType] = useState('student')
const [profileImage, setProfileImage] = useState<File | null | string>(userProfileData?.profile_dp?.imageUrl as string)
const [previewProfileImage, setPreviewProfileImage] = useState<File | null | string>(null)
const {
register,
handleSubmit,
Expand All @@ -49,26 +55,55 @@ const EditProfileModal = () => {
watch,
setError,
setValue,
formState: { errors },
} = useForm<editProfileInputs>({
defaultValues: {
first_name: userData?.firstName,
last_name: userData?.lastName,
bio: userProfileData?.bio,
phone_number: userProfileData?.phone_number,
gender: userData?.gender,
dob: userProfileData?.dob ? new Date(userProfileData?.dob).toISOString().split('T')[0] : '',
country: userProfileData?.country,
city: userProfileData?.city,
university_name: userProfileData?.university_name,
study_year: userProfileData?.study_year,
degree: userProfileData?.degree,
major: userProfileData?.major,
affiliation: userProfileData?.affiliation,
occupation: userProfileData?.occupation,
totalFilled: userProfileData?.totalFilled,
},
})
formState: { errors, isDirty },
} = useForm<editProfileInputs>()
// {
// defaultValues: {
// first_name: userData?.firstName,
// last_name: userData?.lastName,
// bio: userProfileData?.bio,
// phone_number: userProfileData?.phone_number,
// gender: userData?.gender,
// dob: userProfileData?.dob ? new Date(userProfileData?.dob).toISOString().split('T')[0] : '',
// country: userProfileData?.country,
// city: userProfileData?.city,
// university_name: userProfileData?.university_name,
// study_year: userProfileData?.study_year,
// degree: userProfileData?.degree,
// major: userProfileData?.major,
// affiliation: userProfileData?.affiliation,
// occupation: userProfileData?.occupation,
// totalFilled: userProfileData?.totalFilled,
// },
// }

const profilePicture = watch('profilePicture')

useEffect(() => {
if (userProfile) {
const { firstName, lastName, gender, profile, email } = userProfile || {}
const userDefault = {
firstName: firstName || '',
lastName: lastName || '',
email: email || '',
gender: gender || '',
affiliation: profile.affiliation || '',
bio: profile.bio || '',
city: profile.city || '',
country: profile.country || '',
degree: profile.degree || '',
dob: profile.dob || '',
major: profile.major || '',
occupation: profile.occupation || '',
phone_number: profile.phone_number || '',
study_year: profile.study_year || '',
profilePicture: null,
}
reset(userDefault)
setUser({ ...userDefault, profile_dp: profile.profile_dp })
setPreviewProfileImage(profile.profile_dp.imageUrl)
}
}, [userProfile, reset])

const [cityOptions, setCityOptions] = useState<string[]>([])
const [isCityAvailable, setIsCityAvailable] = useState(true)
Expand Down Expand Up @@ -103,19 +138,11 @@ const EditProfileModal = () => {

useEffect(() => {
setCurrMajor(degreeAndMajors[currDegree] || [])
if (!degreeAndMajors[currDegree]?.includes(currMa)) {
setValue('major', '')
}
}, [currDegree, setValue])

useEffect(() => {
const cities = country_list[currCountry] || []

setCityOptions(cities.length > 0 ? cities : ['Not available'])

if (!country_list[currCountry].includes(currCity)) {
setValue('city', '')
}
}, [currCountry, setValue])

const validateBio = (value: string | undefined): string | boolean => {
Expand All @@ -127,63 +154,33 @@ const EditProfileModal = () => {
}

const handleImageUpload = async () => {
const files = profileImage
const files = profilePicture
if (files) {
const data = await replaceImage(files, userProfileData?.profile_dp?.publicId)

const dataToPush = { profile_dp: { imageUrl: data?.imageUrl, publicId: data?.publicId } }

return dataToPush
return { imageUrl: data?.imageUrl, publicId: data?.publicId }
} else {
console.error('No file selected.')
}
}

const onSubmit: SubmitHandler<editProfileInputs> = async (data) => {
let profileImageData
let dataToPush
// Handle image preview
const handleImagePreview = (e: any) => {
const file = e.target.files[0]
if (file) {
setPreviewProfileImage(URL.createObjectURL(file))
setValue('profilePicture', file)
}
}

if (profileImage) {
const onSubmit: SubmitHandler<editProfileInputs> = async (data) => {
let profileImageData = user?.profile_dp
if (profilePicture) {
profileImageData = await handleImageUpload()
}

if (userType === 'applicant') {
const { major, degree, study_year, occupation, affiliation, university_name, ...rest } = data

dataToPush = {
...rest,
major: '',
degree: '',
study_year: '',
occupation: '',
affiliation: '',
university_name: '',
...(profileImageData && { profile_dp: profileImageData.profile_dp }),
}
} else if (userType === 'faculty') {
const { major, degree, study_year, ...rest } = data

dataToPush = {
...rest,
major: '',
degree: '',
study_year: '',
...(profileImageData && { profile_dp: profileImageData.profile_dp }),
}
} else {
const { occupation, affiliation, ...rest } = data

dataToPush = {
...rest,
occupation: '',
affiliation: '',
...(profileImageData && { profile_dp: profileImageData.profile_dp }),
}
}
// return console.log('submit', dataToPush)
console.log(dataToPush)
mutateEditProfile(dataToPush)
mutateEditProfile({ ...data, profile_dp: profileImageData })
}

return (
<div className=" flex flex-col justify-center rounded-xl font-poppins w-full">
<h1 className="text-md font-bold text-neutral-700">Edit Profile</h1>
Expand All @@ -193,15 +190,21 @@ const EditProfileModal = () => {
</p>
<form className="flex flex-col font-medium text-sm gap-4">
<div className="flex items-center gap-4 mt-4">
{profileImage ? (
{previewProfileImage ? (
<div className="relative w-20 h-20 rounded-full border border-neutral-200 group">
<img
className="rounded-full object-cover w-20 h-20"
src={typeof profileImage === 'string' ? profileImage : URL.createObjectURL(profileImage)}
src={typeof previewProfileImage === 'string' ? previewProfileImage : URL.createObjectURL(previewProfileImage)}
alt="aa"
/>
<div className="group-hover:block hidden absolute top-1/2 left-1/2 -translate-y-1/2 -translate-x-1/2 bg-primary-50 py-1 px-2 rounded-full text-primary font-medium cursor-pointer">
<input style={{ display: 'none' }} type="file" id="changeProfileImage" onChange={(e: any) => setProfileImage(e.target.files[0])} />
<input
{...register('profilePicture')}
style={{ display: 'none' }}
type="file"
id="changeProfileImage"
onChange={handleImagePreview}
/>
<label
htmlFor="changeProfileImage"
className="bg-primary w-10 h-10 flex justify-center items-center rounded-full p-2 text-neutral-800"
Expand All @@ -212,7 +215,7 @@ const EditProfileModal = () => {
</div>
) : (
<label htmlFor="changeProfileImage" className="w-20 h-20 rounded-full border border-neutral-200 flex items-center justify-center">
<input style={{ display: 'none' }} type="file" id="changeProfileImage" onChange={(e: any) => setProfileImage(e.target.files[0])} />
<input style={{ display: 'none' }} {...register('profilePicture')} type="file" id="changeProfileImage" onChange={handleImagePreview} />
<TiCameraOutline className="text-primary text-lg" />
</label>
)}
Expand All @@ -225,22 +228,22 @@ const EditProfileModal = () => {
First Name <span className="text-destructive-600">*</span>
</label>
<input
{...register('first_name', { required: true })}
{...register('firstName', { required: true })}
placeholder="Enter First Name"
className="text-base border pl-3 py-1 rounded-lg border-gray-light font-normal"
/>
{errors.first_name && <span className="text-red-500 font-normal">Please enter first name</span>}
{errors.firstName && <span className="text-red-500 font-normal">Please enter first name</span>}
</div>
<div className="flex flex-col">
<label htmlFor="lastname" className="py-1 text-sm text-neutral-700">
Last Name <span className="text-destructive-600">*</span>
</label>
<input
{...register('last_name', { required: true })}
{...register('lastName', { required: true })}
placeholder="Enter Last Name"
className="text-base border pl-3 py-1 rounded-lg border-gray-light font-normal"
/>
{errors.last_name && <span className="text-red-500 font-normal">Please enter your date of birth</span>}
{errors.lastName && <span className="text-red-500 font-normal">Please enter your date of birth</span>}
</div>
<div className="flex flex-col">
<label htmlFor="dob" className="py-1 text-sm text-neutral-700">
Expand Down Expand Up @@ -339,7 +342,7 @@ const EditProfileModal = () => {
{/* contact information start */}
<div>
<div className="flex flex-col gap-4">
<p className="text-sm font-bold py-2 ">Contact Information</p>
<p className="text-sm font-bold ">Contact Information</p>
<div className="flex flex-col gap-2">
<label htmlFor="phone_number" className="py-1 ">
Email
Expand All @@ -348,7 +351,7 @@ const EditProfileModal = () => {
{...register('email')}
placeholder="Enter an email you would like to show others"
type="email"
className=" text-base border pl-3 py-2 rounded-lg border-gray-light font-normal"
className="border pl-3 py-2 rounded-lg border-gray-light text-2xs"
/>
{errors.phone_number && <span className="text-red-500 font-normal">Please enter your phone number!</span>}
</div>
Expand All @@ -360,7 +363,7 @@ const EditProfileModal = () => {
{...register('phone_number')}
placeholder=""
type="number"
className=" text-base border pl-3 py-1 rounded-lg border-gray-light font-normal"
className=" text-xs border pl-3 py-1 rounded-lg border-gray-light font-normal"
/>
{errors.phone_number && <span className="text-red-500 font-normal">Please enter your phone number!</span>}
</div>
Expand Down Expand Up @@ -391,7 +394,7 @@ const EditProfileModal = () => {

{userType === 'student' && (
<>
<div className="flex flex-col">
<div className="flex flex-col py-2">
<label htmlFor="study_year" className="py-1">
Year <span className="text-destructive-600">*</span>
</label>
Expand All @@ -414,7 +417,7 @@ const EditProfileModal = () => {
{errors.study_year && <InputWarningText>{errors?.study_year?.message?.toString()}</InputWarningText>}
</div>
</div>
<div className="flex flex-col">
<div className="flex flex-col py-2">
<label htmlFor="degree" className="py-1">
Degree <span className="text-destructive-600">*</span>
</label>
Expand All @@ -438,7 +441,7 @@ const EditProfileModal = () => {
{errors.degree && <InputWarningText>{errors?.degree?.message?.toString()}</InputWarningText>}
</div>
</div>
<div className="flex flex-col">
<div className="flex flex-col py-2">
<label htmlFor="major" className="py-1">
Field of Study <span className="text-destructive-600">*</span>
</label>
Expand Down Expand Up @@ -498,7 +501,7 @@ const EditProfileModal = () => {
<label htmlFor="occupation" className="py-1">
Occupation <span className="text-destructive-600">*</span>
</label>
<div className="w-full flex flex-col relative">
<div className="w-full flex flex-col py-2 relative">
<Controller
name="occupation"
control={control}
Expand All @@ -518,7 +521,7 @@ const EditProfileModal = () => {
{errors.occupation && <InputWarningText>{errors?.occupation?.message?.toString()}</InputWarningText>}
</div>
</div>
<div className="flex flex-col">
<div className="flex flex-col py-2">
<label htmlFor="affiliation" className="py-1">
Affiliation <span className="text-destructive-600">*</span>
</label>
Expand Down Expand Up @@ -547,7 +550,7 @@ const EditProfileModal = () => {
)}
</div>

<Button variant="primary" type="submit" onClick={handleSubmit(onSubmit)} disabled={isPending}>
<Button variant="primary" type="submit" onClick={handleSubmit(onSubmit)} disabled={!isDirty}>
Update Profile
</Button>
<Button variant="shade" onClick={() => reset()}>
Expand Down
8 changes: 6 additions & 2 deletions src/components/atoms/Buttons/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
size?: 'small' | 'medium' | 'large' | 'extra_small' | 'extra_small_paddind_2'
}

const Buttons: React.FC<ButtonProps> = ({ className = '', variant = 'primary', size = 'small', children, ...props }) => {
const Buttons: React.FC<ButtonProps> = ({ className = '', variant = 'primary', size = 'small', children, disabled, ...props }) => {
const variantClasses = {
primary: 'bg-primary-500 text-white',
secondary: 'bg-gray-500 text-white',
Expand All @@ -26,7 +26,11 @@ const Buttons: React.FC<ButtonProps> = ({ className = '', variant = 'primary', s
const variantClass = variantClasses[variant]
const variantSize = variantSizes[size]
return (
<button className={`${variantClass} ${variantSize} rounded-md active:scale-95 transition-transform duration-150 ${className}`} {...props}>
<button
disabled={disabled}
className={`${variantClass} ${variantSize} rounded-md active:scale-95 transition-transform duration-150 ${className}`}
{...props}
>
{children}
</button>
)
Expand Down
9 changes: 1 addition & 8 deletions src/components/atoms/SelectDropdown/SelectDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,7 @@ const SelectDropdown = ({ options, onChange, value, placeholder, icon, search =
err ? 'border-red-400' : 'border-neutral-200'
} flex justify-between items-center py-2 px-3 border focus:ring-2 rounded-lg drop-shadow-sm text-neutral-400 outline-none`}
>
<p
className={`${value ? 'text-neutral-900' : 'text-neutral-400'} ${
!showIcon && value.length > 8 ? 'text-[8px]' : !showIcon ? '' : 'text-2xs'
}`}
>
{' '}
{value || placeholder}
</p>
<p className={`${value ? 'text-neutral-900' : 'text-neutral-400'} text-2xs`}> {value || placeholder}</p>
<div>
{icon == 'single' ? (
<IoIosArrowDown />
Expand Down
Loading
Loading