feat: enhance login error handling and add server unavailable message (#516)

This commit is contained in:
samanhappy
2025-12-17 13:24:07 +08:00
committed by GitHub
parent 292876a991
commit 350a022ea3
7 changed files with 58 additions and 12 deletions

View File

@@ -14,14 +14,17 @@ const initialState: AuthState = {
// Create auth context
const AuthContext = createContext<{
auth: AuthState;
login: (username: string, password: string) => Promise<{ success: boolean; isUsingDefaultPassword?: boolean }>;
login: (
username: string,
password: string,
) => Promise<{ success: boolean; isUsingDefaultPassword?: boolean; message?: string }>;
register: (username: string, password: string, isAdmin?: boolean) => Promise<boolean>;
logout: () => void;
}>({
auth: initialState,
login: async () => ({ success: false }),
register: async () => false,
logout: () => { },
logout: () => {},
});
// Auth provider component
@@ -90,7 +93,10 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
}, []);
// Login function
const login = async (username: string, password: string): Promise<{ success: boolean; isUsingDefaultPassword?: boolean }> => {
const login = async (
username: string,
password: string,
): Promise<{ success: boolean; isUsingDefaultPassword?: boolean; message?: string }> => {
try {
const response = await authService.login({ username, password });
@@ -111,7 +117,7 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
loading: false,
error: response.message || 'Authentication failed',
});
return { success: false };
return { success: false, message: response.message };
}
} catch (error) {
setAuth({
@@ -119,7 +125,7 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
loading: false,
error: 'Authentication failed',
});
return { success: false };
return { success: false, message: error instanceof Error ? error.message : undefined };
}
};
@@ -127,7 +133,7 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
const register = async (
username: string,
password: string,
isAdmin = false
isAdmin = false,
): Promise<boolean> => {
try {
const response = await authService.register({ username, password, isAdmin });
@@ -175,4 +181,4 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
};
// Custom hook to use auth context
export const useAuth = () => useContext(AuthContext);
export const useAuth = () => useContext(AuthContext);

View File

@@ -44,6 +44,24 @@ const LoginPage: React.FC = () => {
return sanitizeReturnUrl(params.get('returnUrl'));
}, [location.search]);
const isServerUnavailableError = useCallback((message?: string) => {
if (!message) return false;
const normalized = message.toLowerCase();
return (
normalized.includes('failed to fetch') ||
normalized.includes('networkerror') ||
normalized.includes('network error') ||
normalized.includes('connection refused') ||
normalized.includes('unable to connect') ||
normalized.includes('fetch error') ||
normalized.includes('econnrefused') ||
normalized.includes('http 500') ||
normalized.includes('internal server error') ||
normalized.includes('proxy error')
);
}, []);
const buildRedirectTarget = useCallback(() => {
if (!returnUrl) {
return '/';
@@ -100,10 +118,20 @@ const LoginPage: React.FC = () => {
redirectAfterLogin();
}
} else {
setError(t('auth.loginFailed'));
const message = result.message;
if (isServerUnavailableError(message)) {
setError(t('auth.serverUnavailable'));
} else {
setError(t('auth.loginFailed'));
}
}
} catch (err) {
setError(t('auth.loginError'));
const message = err instanceof Error ? err.message : undefined;
if (isServerUnavailableError(message)) {
setError(t('auth.serverUnavailable'));
} else {
setError(t('auth.loginError'));
}
} finally {
setLoading(false);
}
@@ -131,13 +159,21 @@ const LoginPage: React.FC = () => {
}}
/>
<div className="pointer-events-none absolute inset-0 -z-10">
<svg className="h-full w-full opacity-[0.08] dark:opacity-[0.12]" xmlns="http://www.w3.org/2000/svg">
<svg
className="h-full w-full opacity-[0.08] dark:opacity-[0.12]"
xmlns="http://www.w3.org/2000/svg"
>
<defs>
<pattern id="grid" width="32" height="32" patternUnits="userSpaceOnUse">
<path d="M 32 0 L 0 0 0 32" fill="none" stroke="currentColor" strokeWidth="0.5" />
</pattern>
</defs>
<rect width="100%" height="100%" fill="url(#grid)" className="text-gray-400 dark:text-gray-300" />
<rect
width="100%"
height="100%"
fill="url(#grid)"
className="text-gray-400 dark:text-gray-300"
/>
</svg>
</div>

View File

@@ -29,7 +29,7 @@ export const login = async (credentials: LoginCredentials): Promise<AuthResponse
console.error('Login error:', error);
return {
success: false,
message: 'An error occurred during login',
message: error instanceof Error ? error.message : 'An error occurred during login',
};
}
};