- Consolidate API logic: hooks/useApi.ts now uses services/api.ts - Create BaseFormField component to reduce form duplication - Refactor FormField, FormSelect, FormTextarea to use BaseFormField - Add centralized theme utility (utils/theme.ts) for colors/styles - Add comprehensive tests for api, auth.service, useApi hooks, AuthContext - Add tests for theme utility This reduces duplication from 11.45% and improves test coverage. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
129 lines
3.4 KiB
TypeScript
129 lines
3.4 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useCallback } from 'react';
|
|
import { toast } from 'react-hot-toast';
|
|
import { api, ApiError } from '@/services/api';
|
|
|
|
// Re-export for backward compatibility
|
|
export { api, ApiError };
|
|
|
|
interface UseApiState<T> {
|
|
data: T | null;
|
|
loading: boolean;
|
|
error: string | null;
|
|
}
|
|
|
|
interface UseApiReturn<T> extends UseApiState<T> {
|
|
execute: <R = T>(
|
|
method: 'get' | 'post' | 'put' | 'patch' | 'delete',
|
|
endpoint: string,
|
|
data?: unknown
|
|
) => Promise<R | null>;
|
|
reset: () => void;
|
|
}
|
|
|
|
/**
|
|
* Hook for API calls with loading and error states
|
|
* Uses centralized api service from services/api.ts
|
|
*/
|
|
export function useApi<T = unknown>(): UseApiReturn<T> {
|
|
const [state, setState] = useState<UseApiState<T>>({
|
|
data: null,
|
|
loading: false,
|
|
error: null,
|
|
});
|
|
|
|
const execute = useCallback(async <R = T>(
|
|
method: 'get' | 'post' | 'put' | 'patch' | 'delete',
|
|
endpoint: string,
|
|
data?: unknown
|
|
): Promise<R | null> => {
|
|
setState(prev => ({ ...prev, loading: true, error: null }));
|
|
|
|
try {
|
|
let result: R;
|
|
switch (method) {
|
|
case 'get':
|
|
result = await api.get<R>(endpoint);
|
|
break;
|
|
case 'post':
|
|
result = await api.post<R>(endpoint, data);
|
|
break;
|
|
case 'put':
|
|
result = await api.put<R>(endpoint, data);
|
|
break;
|
|
case 'patch':
|
|
result = await api.patch<R>(endpoint, data);
|
|
break;
|
|
case 'delete':
|
|
result = await api.delete<R>(endpoint);
|
|
break;
|
|
}
|
|
setState({ data: result as unknown as T, loading: false, error: null });
|
|
return result;
|
|
} catch (err: unknown) {
|
|
const message = err instanceof Error ? err.message : 'Une erreur est survenue';
|
|
setState(prev => ({ ...prev, loading: false, error: message }));
|
|
toast.error(message);
|
|
return null;
|
|
}
|
|
}, []);
|
|
|
|
const reset = useCallback(() => {
|
|
setState({ data: null, loading: false, error: null });
|
|
}, []);
|
|
|
|
return { ...state, execute, reset };
|
|
}
|
|
|
|
interface UseFetchDataOptions {
|
|
onSuccess?: (data: unknown) => void;
|
|
onError?: (error: string) => void;
|
|
showErrorToast?: boolean;
|
|
}
|
|
|
|
interface UseFetchDataReturn<T> {
|
|
data: T | null;
|
|
loading: boolean;
|
|
error: string | null;
|
|
refetch: () => Promise<void>;
|
|
}
|
|
|
|
/**
|
|
* Hook for fetching data with auto-refresh support
|
|
* Uses centralized api service from services/api.ts
|
|
*/
|
|
export function useFetchData<T>(
|
|
endpoint: string,
|
|
options?: UseFetchDataOptions
|
|
): UseFetchDataReturn<T> {
|
|
const [data, setData] = useState<T | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
const fetchData = useCallback(async () => {
|
|
setLoading(true);
|
|
setError(null);
|
|
|
|
try {
|
|
const result = await api.get<{ data: T } | T>(endpoint);
|
|
const responseData = (result as { data: T }).data ?? result as T;
|
|
setData(responseData);
|
|
options?.onSuccess?.(responseData);
|
|
} catch (err: unknown) {
|
|
const message = err instanceof Error ? err.message : 'Une erreur est survenue';
|
|
setError(message);
|
|
options?.onError?.(message);
|
|
if (options?.showErrorToast !== false) {
|
|
toast.error(message);
|
|
}
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, [endpoint, options]);
|
|
|
|
return { data, loading, error, refetch: fetchData };
|
|
}
|
|
|
|
export default useApi;
|