prile form:
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import * as api from "../service/Service";
|
||||
import { useSharedStore } from "@/share/store/sharedStore";
|
||||
import { UpdateProfileRequest } from "../types/ProfileTypes";
|
||||
|
||||
export const useGetProfile = () => {
|
||||
const { isLogin } = useSharedStore();
|
||||
@@ -10,3 +11,18 @@ export const useGetProfile = () => {
|
||||
enabled: isLogin,
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateProfile = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: (profileData: UpdateProfileRequest) =>
|
||||
api.updateProfile(profileData),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["profile"] });
|
||||
},
|
||||
onError: (error: any) => {
|
||||
console.error("خطا در بهروزرسانی پروفایل:", error);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
+140
-112
@@ -1,40 +1,94 @@
|
||||
'use client'
|
||||
import React, { useState } from 'react'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { yupResolver } from '@hookform/resolvers/yup'
|
||||
import * as yup from 'yup'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import Input from '@/components/Input'
|
||||
import { Edit2 } from 'lucide-react'
|
||||
import Layout from '@/hoc/Layout'
|
||||
import { Heart, ShoppingCart } from 'iconsax-react'
|
||||
import Menu from './components/Menu'
|
||||
import { useGetProfile, useUpdateProfile } from './hooks/useProfileData'
|
||||
|
||||
// Schema validation
|
||||
const profileSchema = yup.object({
|
||||
fullName: yup.string().required('نام و نام خانوادگی الزامی است'),
|
||||
phoneNumber: yup
|
||||
.string()
|
||||
.required('شماره تماس الزامی است')
|
||||
.matches(/^09\d{9}$/, 'شماره تماس باید با 09 شروع شود و 11 رقم باشد'),
|
||||
dateOfBirth: yup.string().required('تاریخ تولد الزامی است'),
|
||||
nationalCode: yup
|
||||
.string()
|
||||
.required('کد ملی الزامی است')
|
||||
.matches(/^\d{10}$/, 'کد ملی باید 10 رقم باشد'),
|
||||
address: yup.string().required('آدرس الزامی است'),
|
||||
})
|
||||
|
||||
const ProfilePage = () => {
|
||||
const [userInfo, setUserInfo] = useState({
|
||||
name: 'حسین دهقانی',
|
||||
email: 'sondos@gmail.com',
|
||||
phone: '09010901789',
|
||||
nationalCode: '052093452',
|
||||
birthDate: '1365/5/8',
|
||||
postalCode: '1235478951',
|
||||
province: 'مرکزی',
|
||||
city: 'اراک',
|
||||
address: 'خیابان دانشگاه رودوی بیمارستان خوانساری ساختمان مهر طبقه سوم واحد2',
|
||||
district: '58'
|
||||
})
|
||||
|
||||
const { data: profile, isLoading } = useGetProfile()
|
||||
const updateProfileMutation = useUpdateProfile()
|
||||
const [isEditing, setIsEditing] = useState(false)
|
||||
|
||||
const handleInputChange = (field: string, value: string) => {
|
||||
setUserInfo(prev => ({
|
||||
...prev,
|
||||
[field]: value
|
||||
}))
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
formState: { errors, isSubmitting },
|
||||
reset,
|
||||
setValue,
|
||||
} = useForm({
|
||||
resolver: yupResolver(profileSchema),
|
||||
mode: 'onChange',
|
||||
defaultValues: {
|
||||
fullName: '',
|
||||
phoneNumber: '',
|
||||
dateOfBirth: '',
|
||||
nationalCode: '',
|
||||
address: '',
|
||||
},
|
||||
})
|
||||
|
||||
// Set form values when profile data is loaded
|
||||
useEffect(() => {
|
||||
if (profile?.results?.info) {
|
||||
const userInfo = profile.results.info
|
||||
setValue('fullName', userInfo.fullName || '')
|
||||
setValue('phoneNumber', userInfo.phoneNumber || '')
|
||||
setValue('dateOfBirth', userInfo.dateOfBirth || '')
|
||||
setValue('nationalCode', userInfo.nationalCode || '')
|
||||
setValue('address', userInfo.userAddress?.address || '')
|
||||
}
|
||||
}, [profile, setValue])
|
||||
|
||||
const onSubmit = async (data: Record<string, unknown>) => {
|
||||
await updateProfileMutation.mutateAsync(data)
|
||||
setIsEditing(false)
|
||||
}
|
||||
|
||||
const handleSubmit = () => {
|
||||
// Handle form submission
|
||||
const handleFormSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
handleSubmit(onSubmit)(e)
|
||||
}
|
||||
|
||||
const handleCancel = () => {
|
||||
reset()
|
||||
setIsEditing(false)
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="p-3 sm:p-4 md:p-6">
|
||||
<Menu pageActive='profile' />
|
||||
<div className='mt-4 sm:mt-6 md:mt-8 lg:mt-10'>
|
||||
<div className="flex justify-center items-center h-64">
|
||||
<div className="text-gray-500">در حال بارگذاری...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-3 sm:p-4 md:p-6">
|
||||
<Menu pageActive='profile' />
|
||||
@@ -54,98 +108,74 @@ const ProfilePage = () => {
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4">
|
||||
<Input
|
||||
label="نام و نام خانوادگی"
|
||||
value={userInfo.name}
|
||||
onChange={(e) => handleInputChange('name', e.target.value)}
|
||||
readOnly={!isEditing}
|
||||
/>
|
||||
<form onSubmit={handleFormSubmit}>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 sm:gap-4">
|
||||
<div>
|
||||
<Input
|
||||
label="نام و نام خانوادگی"
|
||||
{...register('fullName')}
|
||||
readOnly={!isEditing}
|
||||
error_text={errors.fullName?.message}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Input
|
||||
label="کد ملی"
|
||||
value={userInfo.nationalCode}
|
||||
onChange={(e) => handleInputChange('nationalCode', e.target.value)}
|
||||
readOnly={!isEditing}
|
||||
/>
|
||||
<div>
|
||||
<Input
|
||||
label="کد ملی"
|
||||
{...register('nationalCode')}
|
||||
readOnly={!isEditing}
|
||||
error_text={errors.nationalCode?.message}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Input
|
||||
label="ایمیل"
|
||||
value={userInfo.email}
|
||||
onChange={(e) => handleInputChange('email', e.target.value)}
|
||||
readOnly={!isEditing}
|
||||
type="email"
|
||||
/>
|
||||
<div>
|
||||
<Input
|
||||
label="شماره تماس"
|
||||
{...register('phoneNumber')}
|
||||
readOnly={!isEditing}
|
||||
error_text={errors.phoneNumber?.message}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Input
|
||||
label="شماره تماس"
|
||||
value={userInfo.phone}
|
||||
onChange={(e) => handleInputChange('phone', e.target.value)}
|
||||
readOnly={!isEditing}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label="تاریخ تولد"
|
||||
value={userInfo.birthDate}
|
||||
onChange={(e) => handleInputChange('birthDate', e.target.value)}
|
||||
readOnly={!isEditing}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label="استان"
|
||||
value={userInfo.province}
|
||||
onChange={(e) => handleInputChange('province', e.target.value)}
|
||||
readOnly={!isEditing}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label="شهر"
|
||||
value={userInfo.city}
|
||||
onChange={(e) => handleInputChange('city', e.target.value)}
|
||||
readOnly={!isEditing}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label="کد پستی"
|
||||
value={userInfo.postalCode}
|
||||
onChange={(e) => handleInputChange('postalCode', e.target.value)}
|
||||
readOnly={!isEditing}
|
||||
/>
|
||||
|
||||
<Input
|
||||
label="پلاک"
|
||||
value={userInfo.district}
|
||||
onChange={(e) => handleInputChange('district', e.target.value)}
|
||||
readOnly={!isEditing}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-3 sm:mt-4">
|
||||
<Input
|
||||
label="آدرس"
|
||||
value={userInfo.address}
|
||||
onChange={(e) => handleInputChange('address', e.target.value)}
|
||||
readOnly={!isEditing}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{isEditing && (
|
||||
<div className="mt-4 sm:mt-6 flex flex-col sm:flex-row gap-3">
|
||||
<Button
|
||||
onClick={handleSubmit}
|
||||
className="px-6 sm:px-8 bg-blue-600 hover:bg-blue-700 text-sm sm:text-base"
|
||||
>
|
||||
ذخیره تغییرات
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => setIsEditing(false)}
|
||||
variant="outline"
|
||||
className="text-sm sm:text-base"
|
||||
>
|
||||
انصراف
|
||||
</Button>
|
||||
<div>
|
||||
<Input
|
||||
label="تاریخ تولد"
|
||||
{...register('dateOfBirth')}
|
||||
readOnly={!isEditing}
|
||||
error_text={errors.dateOfBirth?.message}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-3 sm:mt-4">
|
||||
<Input
|
||||
label="آدرس"
|
||||
{...register('address')}
|
||||
readOnly={!isEditing}
|
||||
error_text={errors.address?.message}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{isEditing && (
|
||||
<div className="mt-4 sm:mt-6 flex flex-col sm:flex-row gap-3">
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={isSubmitting || updateProfileMutation.isPending}
|
||||
className="px-6 sm:px-8 bg-blue-600 hover:bg-blue-700 text-sm sm:text-base"
|
||||
>
|
||||
{isSubmitting || updateProfileMutation.isPending ? 'در حال ذخیره...' : 'ذخیره تغییرات'}
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
onClick={handleCancel}
|
||||
variant="outline"
|
||||
className="text-sm sm:text-base"
|
||||
>
|
||||
انصراف
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -170,11 +200,9 @@ const ProfilePage = () => {
|
||||
</div>
|
||||
|
||||
<div className='flex-1 bg-red-50 '>
|
||||
|
||||
{/* محتوای اضافی */}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,19 @@
|
||||
import axios from "@/config/axios";
|
||||
import { UserMeResponseType } from "@/share/types/SharedTypes";
|
||||
import {
|
||||
UpdateProfileRequest,
|
||||
UpdateProfileResponse,
|
||||
} from "../types/ProfileTypes";
|
||||
|
||||
export const getProfile = async () => {
|
||||
const { data } = await axios.get<UserMeResponseType>("/user/profile");
|
||||
return data;
|
||||
};
|
||||
|
||||
export const updateProfile = async (profileData: UpdateProfileRequest) => {
|
||||
const { data } = await axios.patch<UpdateProfileResponse>(
|
||||
"/user/profile",
|
||||
profileData
|
||||
);
|
||||
return data;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
export interface ProfileFormData {
|
||||
fullName: string;
|
||||
phoneNumber: string;
|
||||
dateOfBirth: string;
|
||||
nationalCode: string;
|
||||
address: string;
|
||||
}
|
||||
|
||||
export interface UpdateProfileRequest {
|
||||
fullName?: string;
|
||||
phoneNumber?: string;
|
||||
dateOfBirth?: string;
|
||||
nationalCode?: string;
|
||||
address?: string;
|
||||
}
|
||||
|
||||
export interface UpdateProfileResponse {
|
||||
status: number;
|
||||
success: boolean;
|
||||
results: {
|
||||
info: {
|
||||
_id: string;
|
||||
fullName: string;
|
||||
phoneNumber: string;
|
||||
dateOfBirth: string | null;
|
||||
address: string;
|
||||
nationalCode: string | null;
|
||||
homeNumber: string | null;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
userAddress: {
|
||||
_id: string;
|
||||
address: string;
|
||||
city: {
|
||||
_id: number;
|
||||
name: string;
|
||||
province: number;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
__v: number;
|
||||
};
|
||||
province: {
|
||||
_id: number;
|
||||
name: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
__v: number;
|
||||
};
|
||||
postalCode: string;
|
||||
plaque: string;
|
||||
lat: string;
|
||||
lon: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
__v: number;
|
||||
};
|
||||
isSeller: boolean;
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user