refactor-upto-phase 6
This commit is contained in:
@@ -6,6 +6,14 @@ import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
import { fetchAPI } from '../services/api';
|
||||
|
||||
type AuthErrorCode = 'ACCOUNT_REQUIRED' | 'PLAN_REQUIRED' | 'AUTH_FAILED';
|
||||
|
||||
function createAuthError(message: string, code: AuthErrorCode): Error & { code: AuthErrorCode } {
|
||||
const error = new Error(message) as Error & { code: AuthErrorCode };
|
||||
error.code = code;
|
||||
return error;
|
||||
}
|
||||
|
||||
interface User {
|
||||
id: number;
|
||||
email: string;
|
||||
@@ -60,15 +68,31 @@ export const useAuthStore = create<AuthState>()(
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok || !data.success) {
|
||||
throw new Error(data.error || data.message || 'Login failed');
|
||||
const message = data.error || data.message || 'Login failed';
|
||||
if (response.status === 402) {
|
||||
throw createAuthError(message, 'PLAN_REQUIRED');
|
||||
}
|
||||
if (response.status === 403) {
|
||||
throw createAuthError(message, 'ACCOUNT_REQUIRED');
|
||||
}
|
||||
throw createAuthError(message, 'AUTH_FAILED');
|
||||
}
|
||||
|
||||
// Store user and JWT tokens (handle both old and new API formats)
|
||||
const responseData = data.data || data;
|
||||
// Support both formats: new (access/refresh at top level) and old (tokens.access/refresh)
|
||||
const tokens = responseData.tokens || {};
|
||||
const userData = responseData.user || data.user;
|
||||
|
||||
if (!userData?.account) {
|
||||
throw createAuthError('Account not configured for this user. Please contact support.', 'ACCOUNT_REQUIRED');
|
||||
}
|
||||
if (!userData.account.plan) {
|
||||
throw createAuthError('Active subscription required. Visit igny8.com/pricing to subscribe.', 'PLAN_REQUIRED');
|
||||
}
|
||||
|
||||
set({
|
||||
user: responseData.user || data.user,
|
||||
user: userData,
|
||||
token: responseData.access || tokens.access || data.access || null,
|
||||
refreshToken: responseData.refresh || tokens.refresh || data.refresh || null,
|
||||
isAuthenticated: true,
|
||||
@@ -196,23 +220,24 @@ export const useAuthStore = create<AuthState>()(
|
||||
}
|
||||
|
||||
try {
|
||||
// Use fetchAPI which handles token automatically and extracts data from unified format
|
||||
// fetchAPI is already imported at the top of the file
|
||||
const response = await fetchAPI('/v1/auth/me/');
|
||||
|
||||
// fetchAPI extracts data field, so response is {user: {...}}
|
||||
if (!response || !response.user) {
|
||||
throw new Error('Failed to refresh user data');
|
||||
}
|
||||
|
||||
// Update user data with latest from server
|
||||
// This ensures account/plan changes are reflected immediately
|
||||
set({ user: response.user });
|
||||
const refreshedUser = response.user;
|
||||
if (!refreshedUser.account) {
|
||||
throw createAuthError('Account not configured for this user. Please contact support.', 'ACCOUNT_REQUIRED');
|
||||
}
|
||||
if (!refreshedUser.account.plan) {
|
||||
throw createAuthError('Active subscription required. Visit igny8.com/pricing to subscribe.', 'PLAN_REQUIRED');
|
||||
}
|
||||
|
||||
set({ user: refreshedUser, isAuthenticated: true });
|
||||
} catch (error: any) {
|
||||
// If refresh fails, don't logout - just log the error
|
||||
// User might still be authenticated, just couldn't refresh data
|
||||
console.warn('Failed to refresh user data:', error);
|
||||
// Don't throw - just log the warning to prevent error accumulation
|
||||
set({ user: null, token: null, refreshToken: null, isAuthenticated: false });
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user