fix(frontend): Fix user field name mapping from backend to frontend
Resolved authentication issue where user.id was undefined, causing Epic creation to fail. Root Cause: - Backend /api/auth/login returns UserDto with PascalCase fields (Id, Email, etc.) - Backend /api/auth/me returns JWT claims with camelCase (userId, email, etc.) - Frontend User type expects camelCase fields (id, email, etc.) - Previous code directly assigned backend fields without mapping Changes: - useLogin: Added field mapping to handle both PascalCase and camelCase - useCurrentUser: Map userId -> id and tenantSlug -> tenantName - Both functions now correctly populate user.id for localStorage persistence Impact: - Epic creation now works (user.id is correctly set) - Auth state persists correctly across page reloads - Consistent user object structure throughout frontend 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -30,16 +30,20 @@ export function useLogin() {
|
|||||||
tokenManager.setAccessToken(data.accessToken);
|
tokenManager.setAccessToken(data.accessToken);
|
||||||
tokenManager.setRefreshToken(data.refreshToken);
|
tokenManager.setRefreshToken(data.refreshToken);
|
||||||
|
|
||||||
|
// Map backend field names to frontend User type
|
||||||
|
// Backend returns: { Id, TenantId, Email, FullName, ... }
|
||||||
|
// Frontend expects: { id, tenantId, email, fullName, ... }
|
||||||
|
const backendUser = data.user;
|
||||||
setUser({
|
setUser({
|
||||||
id: data.user.id,
|
id: backendUser.id || backendUser.Id, // Handle both casing
|
||||||
email: data.user.email,
|
email: backendUser.email || backendUser.Email,
|
||||||
fullName: data.user.fullName,
|
fullName: backendUser.fullName || backendUser.FullName,
|
||||||
tenantId: data.user.tenantId,
|
tenantId: backendUser.tenantId || backendUser.TenantId,
|
||||||
tenantName: data.user.tenantName,
|
tenantName: data.tenant?.name || data.tenant?.Name || 'Unknown',
|
||||||
role: data.user.role,
|
role: data.tenant?.role || backendUser.role || 'TenantMember',
|
||||||
isEmailVerified: data.user.isEmailVerified,
|
isEmailVerified: backendUser.isEmailVerified ?? backendUser.IsEmailVerified ?? false,
|
||||||
createdAt: data.user.createdAt || new Date().toISOString(),
|
createdAt: backendUser.createdAt || backendUser.CreatedAt || new Date().toISOString(),
|
||||||
updatedAt: data.user.updatedAt,
|
updatedAt: backendUser.updatedAt || backendUser.UpdatedAt,
|
||||||
});
|
});
|
||||||
|
|
||||||
router.push('/dashboard');
|
router.push('/dashboard');
|
||||||
@@ -95,9 +99,24 @@ export function useCurrentUser() {
|
|||||||
queryKey: ['currentUser'],
|
queryKey: ['currentUser'],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const { data } = await apiClient.get(API_ENDPOINTS.ME);
|
const { data } = await apiClient.get(API_ENDPOINTS.ME);
|
||||||
setUser(data);
|
|
||||||
|
// Map backend /me response to frontend User type
|
||||||
|
// Backend returns: { userId, tenantId, email, fullName, tenantSlug, tenantRole, role }
|
||||||
|
// Frontend expects: { id, tenantId, email, fullName, tenantName, role, isEmailVerified, createdAt }
|
||||||
|
const mappedUser = {
|
||||||
|
id: data.userId || data.id, // Backend uses 'userId'
|
||||||
|
email: data.email,
|
||||||
|
fullName: data.fullName,
|
||||||
|
tenantId: data.tenantId,
|
||||||
|
tenantName: data.tenantSlug || 'Unknown', // Use tenantSlug as tenantName fallback
|
||||||
|
role: data.tenantRole || data.role || 'TenantMember',
|
||||||
|
isEmailVerified: true, // Assume verified if token is valid
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
};
|
||||||
|
|
||||||
|
setUser(mappedUser);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
return data;
|
return mappedUser;
|
||||||
},
|
},
|
||||||
enabled: !!tokenManager.getAccessToken(),
|
enabled: !!tokenManager.getAccessToken(),
|
||||||
retry: false,
|
retry: false,
|
||||||
|
|||||||
Reference in New Issue
Block a user