Fixed critical issues with the profile page (/dashboard/profile):
1. **Form data not persisting on page refresh**:
- Added useEffect to update form values when user data loads
- Forms now properly populate after auth context loads user data
2. **Blank page on refresh**:
- Added loading and error states for better UX
- Handle case where user is not loaded yet (loading spinner)
- Handle case where user fails to load (retry button)
3. **Password change API endpoint correction**:
- Fixed: POST /api/v1/users/change-password (incorrect)
- Corrected to: PATCH /api/v1/users/me/password (matches backend)
- Updated return type to include { message: string }
The root cause was that useForm defaultValues were set once at
component mount when user was still null. The form never updated
when user data was subsequently loaded by the auth context.
Now the form properly resets with user data via useEffect, and
proper loading/error states prevent showing a blank page.
Refs: apps/frontend/app/dashboard/profile/page.tsx:68-78
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
110 lines
2.3 KiB
TypeScript
110 lines
2.3 KiB
TypeScript
/**
|
|
* Users API
|
|
*
|
|
* User management API calls
|
|
*/
|
|
|
|
import { apiClient } from './client';
|
|
|
|
export interface User {
|
|
id: string;
|
|
organizationId: string;
|
|
email: string;
|
|
firstName: string;
|
|
lastName: string;
|
|
role: 'admin' | 'manager' | 'user' | 'viewer';
|
|
phoneNumber?: string;
|
|
isEmailVerified: boolean;
|
|
isActive: boolean;
|
|
lastLoginAt?: string;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
}
|
|
|
|
export interface CreateUserRequest {
|
|
organizationId: string;
|
|
email: string;
|
|
firstName: string;
|
|
lastName: string;
|
|
role: 'admin' | 'manager' | 'user' | 'viewer';
|
|
phoneNumber?: string;
|
|
password?: string;
|
|
}
|
|
|
|
export interface UpdateUserRequest {
|
|
firstName?: string;
|
|
lastName?: string;
|
|
phoneNumber?: string;
|
|
isActive?: boolean;
|
|
}
|
|
|
|
export interface ChangePasswordRequest {
|
|
currentPassword: string;
|
|
newPassword: string;
|
|
}
|
|
|
|
export const usersApi = {
|
|
/**
|
|
* Get users in current organization
|
|
*/
|
|
async list(): Promise<User[]> {
|
|
return apiClient.get<User[]>('/api/v1/users');
|
|
},
|
|
|
|
/**
|
|
* Get user by ID
|
|
*/
|
|
async getById(id: string): Promise<User> {
|
|
return apiClient.get<User>(`/api/v1/users/${id}`);
|
|
},
|
|
|
|
/**
|
|
* Create/invite user
|
|
*/
|
|
async create(data: CreateUserRequest): Promise<User> {
|
|
return apiClient.post<User>('/api/v1/users', data);
|
|
},
|
|
|
|
/**
|
|
* Update user
|
|
*/
|
|
async update(id: string, data: UpdateUserRequest): Promise<User> {
|
|
return apiClient.patch<User>(`/api/v1/users/${id}`, data);
|
|
},
|
|
|
|
/**
|
|
* Change user role
|
|
*/
|
|
async changeRole(id: string, role: 'admin' | 'manager' | 'user' | 'viewer'): Promise<User> {
|
|
return apiClient.patch<User>(`/api/v1/users/${id}/role`, { role });
|
|
},
|
|
|
|
/**
|
|
* Deactivate user
|
|
*/
|
|
async deactivate(id: string): Promise<void> {
|
|
return apiClient.patch<void>(`/api/v1/users/${id}`, { isActive: false });
|
|
},
|
|
|
|
/**
|
|
* Activate user
|
|
*/
|
|
async activate(id: string): Promise<void> {
|
|
return apiClient.patch<void>(`/api/v1/users/${id}`, { isActive: true });
|
|
},
|
|
|
|
/**
|
|
* Delete user
|
|
*/
|
|
async delete(id: string): Promise<void> {
|
|
return apiClient.delete<void>(`/api/v1/users/${id}`);
|
|
},
|
|
|
|
/**
|
|
* Change password
|
|
*/
|
|
async changePassword(data: ChangePasswordRequest): Promise<{ message: string }> {
|
|
return apiClient.patch<{ message: string }>('/api/v1/users/me/password', data);
|
|
},
|
|
};
|