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:
parent
db181b338c
commit
3beb23a765
10 changed files with 231 additions and 143 deletions
54
frontend/app/hooks/useDebouncedValidation.ts
Normal file
54
frontend/app/hooks/useDebouncedValidation.ts
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
/**
|
||||
* Hook for debounced form validation.
|
||||
* Validates form data after the user stops typing for a specified delay.
|
||||
*
|
||||
* @param formData - The form data to validate
|
||||
* @param validator - Function that validates the form data and returns field errors
|
||||
* @param delay - Debounce delay in milliseconds (default: 500)
|
||||
* @returns Object containing current errors and a function to manually trigger validation
|
||||
*/
|
||||
export function useDebouncedValidation<T>(
|
||||
formData: T,
|
||||
validator: (data: T) => Record<string, string>,
|
||||
delay: number = 500
|
||||
): {
|
||||
errors: Record<string, string>;
|
||||
setErrors: React.Dispatch<React.SetStateAction<Record<string, string>>>;
|
||||
validate: (data?: T) => void;
|
||||
} {
|
||||
const [errors, setErrors] = useState<Record<string, string>>({});
|
||||
const validationTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
const formDataRef = useRef<T>(formData);
|
||||
|
||||
// Keep formDataRef in sync with formData
|
||||
useEffect(() => {
|
||||
formDataRef.current = formData;
|
||||
}, [formData]);
|
||||
|
||||
// Cleanup timeout on unmount
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (validationTimeoutRef.current) {
|
||||
clearTimeout(validationTimeoutRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
const validate = (data?: T) => {
|
||||
// Clear any pending validation timeout
|
||||
if (validationTimeoutRef.current) {
|
||||
clearTimeout(validationTimeoutRef.current);
|
||||
}
|
||||
|
||||
// Debounce validation - wait for user to stop typing
|
||||
validationTimeoutRef.current = setTimeout(() => {
|
||||
const dataToValidate = data ?? formDataRef.current;
|
||||
const newErrors = validator(dataToValidate);
|
||||
setErrors(newErrors);
|
||||
}, delay);
|
||||
};
|
||||
|
||||
return { errors, setErrors, validate };
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue