2c5d751f72
- Add useProfile hook for managing user data - Add Profile page to view/edit user information - Add Settings layout with sidebar navigation - Add Settings pages: Profile, Password, Notifications, Account - Add user dropdown menu in Header with Profile/Settings links - Add protected routes for /settings/* pages - Implement profile update and password change functionality Completes Fase 2 of frontend missing features analysis from todo.md
110 lines
2.7 KiB
TypeScript
110 lines
2.7 KiB
TypeScript
import { useState, useEffect, useCallback } from 'react';
|
|
import api from '@/lib/api';
|
|
import { showToast } from '@/components/ui/toast-utils';
|
|
|
|
export interface User {
|
|
id: string;
|
|
email: string;
|
|
full_name: string;
|
|
is_active: boolean;
|
|
created_at: string;
|
|
}
|
|
|
|
export function useProfile() {
|
|
const [user, setUser] = useState<User | null>(null);
|
|
const [loading, setLoading] = useState<boolean>(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
// Fetch user profile
|
|
const getProfile = useCallback(async () => {
|
|
setLoading(true);
|
|
setError(null);
|
|
try {
|
|
const response = await api.get('/auth/me');
|
|
const userData = response.data;
|
|
setUser(userData);
|
|
return userData;
|
|
} catch (err: any) {
|
|
const message = err.response?.data?.detail || 'Failed to load profile';
|
|
setError(message);
|
|
showToast({
|
|
title: 'Error loading profile',
|
|
description: message,
|
|
variant: 'destructive'
|
|
});
|
|
return null;
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
// Update user profile
|
|
const updateProfile = useCallback(async (data: Partial<User>) => {
|
|
setLoading(true);
|
|
setError(null);
|
|
try {
|
|
const response = await api.put('/auth/me', data);
|
|
const updatedUser = response.data;
|
|
setUser(updatedUser);
|
|
showToast({
|
|
title: 'Profile updated',
|
|
description: 'Your profile has been successfully updated'
|
|
});
|
|
return updatedUser;
|
|
} catch (err: any) {
|
|
const message = err.response?.data?.detail || 'Failed to update profile';
|
|
setError(message);
|
|
showToast({
|
|
title: 'Update failed',
|
|
description: message,
|
|
variant: 'destructive'
|
|
});
|
|
throw err;
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
// Change password
|
|
const changePassword = useCallback(async (passwordData: {
|
|
current_password: string;
|
|
new_password: string;
|
|
}) => {
|
|
setLoading(true);
|
|
setError(null);
|
|
try {
|
|
await api.post('/auth/change-password', passwordData);
|
|
showToast({
|
|
title: 'Password changed',
|
|
description: 'Your password has been successfully updated'
|
|
});
|
|
return true;
|
|
} catch (err: any) {
|
|
const message = err.response?.data?.detail || 'Failed to change password';
|
|
setError(message);
|
|
showToast({
|
|
title: 'Password change failed',
|
|
description: message,
|
|
variant: 'destructive'
|
|
});
|
|
throw err;
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, []);
|
|
|
|
// Load profile on mount
|
|
useEffect(() => {
|
|
getProfile();
|
|
}, [getProfile]);
|
|
|
|
return {
|
|
user,
|
|
loading,
|
|
error,
|
|
getProfile,
|
|
updateProfile,
|
|
changePassword
|
|
};
|
|
}
|