improvement: error handeling structure changed and unified all across the app. user no longer sees inappropriate messages.

This commit is contained in:
2026-07-12 18:27:38 +03:30
parent 901d838a2c
commit fab5111aa8
45 changed files with 977 additions and 241 deletions

View File

@@ -16,6 +16,21 @@ import {
rememberAccessTokenExpiresAt,
startProactiveSessionRefresh,
} from '@/lib/auth/proactiveRefresh';
import { asApiError, legacyStatusCode, type ApiError } from '@/types/api';
function toApiError(err: unknown): ApiError {
return (
asApiError(err) ?? {
statusCode: legacyStatusCode(err) ?? 500,
code:
legacyStatusCode(err) === 401
? 'AUTH_UNAUTHORIZED'
: legacyStatusCode(err) === 403
? 'PERMISSION_DENIED'
: 'INTERNAL_ERROR',
}
);
}
interface AuthContextType {
user: User | null;
@@ -23,7 +38,7 @@ interface AuthContextType {
currentOrganization: Organization | null;
isLoading: boolean;
isAuthReady: boolean;
error: string | null;
apiError: ApiError | null;
registerTrial: (
email: string,
password: string,
@@ -56,7 +71,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
const [currentOrganization, setCurrentOrganization] = useState<Organization | null>(null);
const [isLoading, setIsLoading] = useState(false);
const [isAuthReady, setIsAuthReady] = useState(false); // ✅ KEY FIX
const [error, setError] = useState<string | null>(null);
const [apiError, setApiError] = useState<ApiError | null>(null);
const router = useRouter();
@@ -135,9 +150,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
}
}
} catch (err: unknown) {
const status =
(err as { statusCode?: number })?.statusCode ??
(err as { response?: { status?: number } })?.response?.status;
const status = legacyStatusCode(err);
// Access token may have expired while refresh cookie is still valid (e.g. JWT_EXPIRES_IN=15m).
if (status === 401) {
@@ -251,7 +264,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
) => {
try {
setIsLoading(true);
setError(null);
setApiError(null);
const response = await authApi.registerTrial({
email,
@@ -282,7 +295,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
}
} catch (err: any) {
setError(err.message || t('errorRegistrationFailed'));
setApiError(toApiError(err));
throw err;
} finally {
setIsLoading(false);
@@ -297,7 +310,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
) => {
try {
setIsLoading(true);
setError(null);
setApiError(null);
const response = await authApi.login({ email, password, rememberMe });
@@ -325,7 +338,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
}
} catch (err: any) {
setError(err.message || t('errorLoginFailed'));
setApiError(toApiError(err));
throw err;
} finally {
setIsLoading(false);
@@ -348,7 +361,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
setUser(null);
setOrganizations([]);
setCurrentOrganization(null);
setError(null);
setApiError(null);
clearAccessTokenExpiresAt();
setIsAuthReady(true);
router.replace('/');
@@ -387,7 +400,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
}
} catch (err: any) {
setError(err.message);
setApiError(toApiError(err));
throw err;
} finally {
setIsLoading(false);
@@ -402,7 +415,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
) => {
try {
setIsLoading(true);
setError(null);
setApiError(null);
const createResponse = await authApi.createOrganization({
organizationName,
@@ -420,7 +433,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
return createResponse.data.organization.id as string;
} catch (err: any) {
setError(err.message || t('errorCreateOrganization'));
setApiError(toApiError(err));
throw err;
} finally {
setIsLoading(false);
@@ -431,7 +444,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
await checkAuth();
}, [checkAuth]);
const clearError = useCallback(() => setError(null), []);
const clearError = useCallback(() => setApiError(null), []);
const setUserLanguage = useCallback((language: string) => {
const normalized = isAppLocale(language) ? language : 'en';
@@ -445,7 +458,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
currentOrganization,
isLoading,
isAuthReady,
error,
apiError,
registerTrial,
login,
logout,
@@ -461,7 +474,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
currentOrganization,
isLoading,
isAuthReady,
error,
apiError,
registerTrial,
login,
logout,