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

@ -0,0 +1,20 @@
"use client";
import { layoutStyles } from "../styles/shared";
interface LoadingStateProps {
/** Custom loading message (default: "Loading...") */
message?: string;
}
/**
* Standard loading state component.
* Displays a centered loading message with consistent styling.
*/
export function LoadingState({ message = "Loading..." }: LoadingStateProps) {
return (
<main style={layoutStyles.main}>
<div style={layoutStyles.loader}>{message}</div>
</main>
);
}

View file

@ -0,0 +1,40 @@
"use client";
import { useEffect } from "react";
import { toastStyles } from "../styles/shared";
export type ToastType = "success" | "error";
export interface ToastProps {
message: string;
type: ToastType;
onDismiss?: () => void;
/** Auto-dismiss delay in milliseconds (default: 3000) */
autoDismissDelay?: number;
}
/**
* Toast notification component with auto-dismiss functionality.
* Displays success or error messages in a fixed position.
*/
export function Toast({ message, type, onDismiss, autoDismissDelay = 3000 }: ToastProps) {
useEffect(() => {
if (onDismiss) {
const timer = setTimeout(() => {
onDismiss();
}, autoDismissDelay);
return () => clearTimeout(timer);
}
}, [onDismiss, autoDismissDelay]);
return (
<div
style={{
...toastStyles.toast,
...(type === "success" ? toastStyles.toastSuccess : toastStyles.toastError),
}}
>
{message}
</div>
);
}