refactor(frontend): improve code quality and maintainability

- Extract API error handling utility (utils/error-handling.ts)
  - Centralize error message extraction logic
  - Add type guards for API errors
  - Replace duplicated error handling across components

- Create reusable Toast component (components/Toast.tsx)
  - Extract toast notification logic from profile page
  - Support auto-dismiss functionality
  - Consistent styling with shared styles

- Extract form validation debouncing hook (hooks/useDebouncedValidation.ts)
  - Reusable debounced validation logic
  - Clean timeout management
  - Used in profile page for form validation

- Consolidate duplicate styles (styles/auth-form.ts)
  - Use shared style tokens instead of duplicating values
  - Reduce code duplication between auth-form and shared styles

- Extract loading state component (components/LoadingState.tsx)
  - Standardize loading UI across pages
  - Replace duplicated loading JSX patterns
  - Used in profile, exchange, and trades pages

- Fix useRequireAuth dependency array
  - Remove unnecessary hasPermission from dependencies
  - Add eslint-disable comment with explanation
  - Improve hook stability and performance

All frontend tests pass. Linting passes.
This commit is contained in:
counterweight 2025-12-25 19:04:45 +01:00
parent db181b338c
commit 3beb23a765
Signed by: counterweight
GPG key ID: 883EDBAA726BD96C
10 changed files with 231 additions and 143 deletions

View file

@ -2,8 +2,9 @@
import { createContext, useContext, useState, useEffect, useCallback, ReactNode } from "react";
import { api, ApiError } from "./api";
import { api } from "./api";
import { components } from "./generated/api";
import { extractApiErrorMessage } from "./utils/error-handling";
// Permission type from generated OpenAPI schema
export type PermissionType = components["schemas"]["Permission"];
@ -67,11 +68,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
const userData = await api.post<User>("/api/auth/login", { email, password });
setUser(userData);
} catch (err) {
if (err instanceof ApiError) {
const data = err.data as { detail?: string };
throw new Error(data?.detail || "Login failed");
}
throw err;
throw new Error(extractApiErrorMessage(err, "Login failed"));
}
};
@ -84,11 +81,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
});
setUser(userData);
} catch (err) {
if (err instanceof ApiError) {
const data = err.data as { detail?: string };
throw new Error(data?.detail || "Registration failed");
}
throw err;
throw new Error(extractApiErrorMessage(err, "Registration failed"));
}
};