diff --git a/src/api/user.ts b/src/api/user.ts new file mode 100644 index 0000000..76f1242 --- /dev/null +++ b/src/api/user.ts @@ -0,0 +1,43 @@ +import { apiAuthenticated } from './index'; + +/** + * Updates the password for the authenticated user. + * + * @param {string} currentPassword - The user's current password. + * @param {string} password - The user's new password. + * @param {string} confirmPassword - The user's new password confirmation. + * @returns {Promise} - A promise that resolves when the password is updated. + * @throws {Promise} - A promise that rejects with an error message if the current password is incorrect. + * @route - /api/v1//user/me/password + * @method - PATCH + * @authentication - required + * Check if password and currentPassword are different + */ +export async function updatePassword( + currentPassword: string, + password: string, + confirmPassword: string, +): Promise { + if (password !== confirmPassword) { + throw new Error('Passwords do not match'); + } + + return apiAuthenticated('/api/v1/user/me/password', { + method: 'PATCH', + data: JSON.stringify({ currentPassword, password, confirmPassword }), + }); +} + +// Update user details for the authenticated user. + +/** + * Updates the details for the authenticated user. + * + * @param {string} email - The user's new email address. + * @param {string} username - The user's new username. + * @returns {Promise} - A promise that resolves when the user details are updated. + * @throws {Promise} - A promise that rejects with an error message if the email is invalid. + * @route - /api/v1/user/me + * @method - PATCH + * @authentication - required + */ diff --git a/src/components/navbar/navbar.tsx b/src/components/navbar/navbar.tsx index 4dd68da..07dba73 100644 --- a/src/components/navbar/navbar.tsx +++ b/src/components/navbar/navbar.tsx @@ -162,11 +162,9 @@ export const Navbar = () => { {t('navbar.analysis')} - {/**/} - {/* */} - {/* {t('account-dropdown.profile')}*/} - {/* */} - {/**/} + + {t('account-dropdown.profile')} + {t('account-dropdown.theme')} diff --git a/src/pages/profile/profile.tsx b/src/pages/profile/profile.tsx index 9cf97fd..6a84d80 100644 --- a/src/pages/profile/profile.tsx +++ b/src/pages/profile/profile.tsx @@ -1,17 +1,17 @@ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { useAuthStore } from '@/store/auth.ts'; -import { useNavigate } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { Avatar, AvatarImage } from '@radix-ui/react-avatar'; -import { Pencil, PencilOff, SquarePen, LogOut, Trash, Save } from 'lucide-react'; +import { Pencil, PencilOff, SquarePen, Trash, Save } from 'lucide-react'; import { useForm } from 'react-hook-form'; import { z } from 'zod'; import { zodResolver } from '@hookform/resolvers/zod'; import { ProfileSchema } from '@/schema/profile.ts'; import { Form, FormControl, FormField, FormItem, FormMessage } from '@/components/ui/form.tsx'; -import { Card } from '@/components/ui/card'; import { Button } from '@/components/ui/button.tsx'; import { Input } from '@/components/ui/input'; +import { updatePassword } from '@/api/user'; +import { useNavigate } from 'react-router-dom'; /** * Profile component renders the user's profile page. @@ -60,29 +60,46 @@ import { Input } from '@/components/ui/input'; */ export const Profile = () => { const { t } = useTranslation('profile'); - const { logout, user } = useAuthStore((state) => state); - const navigate = useNavigate(); + const { user } = useAuthStore((state) => state); const [isEditing, setIsEditing] = useState(false); + const navigate = useNavigate(); + + useEffect(() => { + console.log('User:', user); + }, [user]); const form = useForm>({ resolver: zodResolver(ProfileSchema), defaultValues: { email: user?.email, + username: user?.username, password: '', currentPassword: '', - newPassword: '', confirmPassword: '', }, }); const onSubmit = async (data: z.infer) => { - console.log(data); - setIsEditing(false); - }; + console.log('Modification', data); + try { + if (!data.currentPassword || !data.password || !data.confirmPassword) { + console.error('Please fill all the fields'); + return; + } - const handleLogout = () => { - logout(); - navigate('/login'); + if (data.email !== user?.email || data.username !== user?.username) { + // update email and username + console.log('Email and username updated successfully'); + } + + await updatePassword(data.currentPassword, data.password, data.confirmPassword); + console.log('Password updated successfully'); + form.reset(); + navigate('/profile'); + } catch (error) { + console.error('Error updating password:', error); + } + setIsEditing(false); }; const handleEditToggle = () => { @@ -98,31 +115,36 @@ export const Profile = () => { return (
-
- - + {/* + * This Block is for the Avatar Image and the edit button + */} + +
- -

{user?.username}

+
+

{user?.username}

+ {/* + * This block is for the form fields when user is not in edit mode + */}
( @@ -133,8 +155,26 @@ export const Profile = () => { )} /> + {/* + * This block is for password fields when user is in edit mode + */} {isEditing && ( <> + {/* ajouter une field pour le username */} + ( + + + + + + + )} + /> + { /> ( @@ -194,38 +234,34 @@ export const Profile = () => {
+ {/* + * This block is for Save button when user is in edit mode + */} {isEditing && ( )} - + {/* + * This block is for Delete account when user is not in edit mode + */} {!isEditing && ( <> - -
- +
); }; diff --git a/src/schema/profile.ts b/src/schema/profile.ts index 80ac756..7d42d19 100644 --- a/src/schema/profile.ts +++ b/src/schema/profile.ts @@ -2,13 +2,13 @@ import { z } from 'zod'; export const ProfileSchema = z .object({ - email: z.string().email(), + email: z.string().email().optional(), + username: z.string().min(3).max(20).optional(), password: z.string().optional(), currentPassword: z.string().optional(), - newPassword: z.string().optional(), confirmPassword: z.string().optional(), }) - .refine((data) => data.newPassword === data.confirmPassword, { + .refine((data) => data.password === data.confirmPassword, { message: "Passwords don't match", path: ['confirmPassword'], });