136 lines
5.8 KiB
TypeScript
136 lines
5.8 KiB
TypeScript
import Cookies from 'js-cookie';
|
|
|
|
const API_BASE = '/api';
|
|
|
|
interface FetchOptions extends RequestInit {
|
|
skipAuth?: boolean;
|
|
}
|
|
|
|
async function fetchApi(url: string, options: FetchOptions = {}) {
|
|
const { skipAuth, ...fetchOpts } = options;
|
|
const headers: Record<string, string> = {
|
|
'Content-Type': 'application/json',
|
|
...(fetchOpts.headers as Record<string, string>),
|
|
};
|
|
|
|
if (!skipAuth) {
|
|
const token = Cookies.get('accessToken');
|
|
if (token) headers['Authorization'] = `Bearer ${token}`;
|
|
}
|
|
|
|
const res = await fetch(`${API_BASE}${url}`, { ...fetchOpts, headers });
|
|
|
|
if (res.status === 401) {
|
|
const data = await res.json().catch(() => ({}));
|
|
if (data.code === 'TOKEN_EXPIRED') {
|
|
const refreshed = await refreshToken();
|
|
if (refreshed) {
|
|
headers['Authorization'] = `Bearer ${Cookies.get('accessToken')}`;
|
|
const retry = await fetch(`${API_BASE}${url}`, { ...fetchOpts, headers });
|
|
return retry.json();
|
|
}
|
|
}
|
|
if (typeof window !== 'undefined') {
|
|
Cookies.remove('accessToken');
|
|
Cookies.remove('refreshToken');
|
|
window.location.href = '/login';
|
|
}
|
|
throw new Error('Não autenticado');
|
|
}
|
|
|
|
if (!res.ok) {
|
|
const data = await res.json().catch(() => ({ error: 'Erro desconhecido' }));
|
|
throw new Error(data.error || 'Erro na requisição');
|
|
}
|
|
|
|
return res.json();
|
|
}
|
|
|
|
async function refreshToken(): Promise<boolean> {
|
|
try {
|
|
const rt = Cookies.get('refreshToken');
|
|
if (!rt) return false;
|
|
const res = await fetch(`${API_BASE}/auth/refresh`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ refreshToken: rt }),
|
|
});
|
|
if (!res.ok) return false;
|
|
const data = await res.json();
|
|
Cookies.set('accessToken', data.accessToken, { expires: 1 });
|
|
Cookies.set('refreshToken', data.refreshToken, { expires: 7 });
|
|
return true;
|
|
} catch { return false; }
|
|
}
|
|
|
|
export const api = {
|
|
// Auth
|
|
login: (email: string, password: string) =>
|
|
fetchApi('/auth/login', { method: 'POST', body: JSON.stringify({ email, password }), skipAuth: true }),
|
|
register: (data: any) =>
|
|
fetchApi('/auth/register', { method: 'POST', body: JSON.stringify(data), skipAuth: true }),
|
|
googleAuth: (data: any) =>
|
|
fetchApi('/auth/google', { method: 'POST', body: JSON.stringify(data), skipAuth: true }),
|
|
me: () => fetchApi('/auth/me'),
|
|
logout: () => fetchApi('/auth/logout', { method: 'POST' }),
|
|
|
|
// Users
|
|
getUsers: (params?: string) => fetchApi(`/users${params ? `?${params}` : ''}`),
|
|
getUser: (id: number) => fetchApi(`/users/${id}`),
|
|
updateUser: (id: number, data: any) => fetchApi(`/users/${id}`, { method: 'PUT', body: JSON.stringify(data) }),
|
|
deleteUser: (id: number) => fetchApi(`/users/${id}`, { method: 'DELETE' }),
|
|
getUserStats: () => fetchApi('/users/me/stats'),
|
|
getFavorites: () => fetchApi('/users/me/favorites'),
|
|
addFavorite: (benefitId: number) => fetchApi('/users/me/favorites', { method: 'POST', body: JSON.stringify({ benefitId }) }),
|
|
removeFavorite: (benefitId: number) => fetchApi(`/users/me/favorites/${benefitId}`, { method: 'DELETE' }),
|
|
getHistory: () => fetchApi('/users/me/history'),
|
|
|
|
// Partners
|
|
getPartners: (params?: string) => fetchApi(`/partners${params ? `?${params}` : ''}`),
|
|
getPartner: (id: number) => fetchApi(`/partners/${id}`),
|
|
getPartnerBySlug: (slug: string) => fetchApi(`/partners/slug/${slug}`),
|
|
createPartner: (data: any) => fetchApi('/partners', { method: 'POST', body: JSON.stringify(data) }),
|
|
updatePartner: (id: number, data: any) => fetchApi(`/partners/${id}`, { method: 'PUT', body: JSON.stringify(data) }),
|
|
deletePartner: (id: number) => fetchApi(`/partners/${id}`, { method: 'DELETE' }),
|
|
getPartnerStats: (id: number) => fetchApi(`/partners/${id}/stats`),
|
|
|
|
// Benefits
|
|
getBenefits: (params?: string) => fetchApi(`/benefits${params ? `?${params}` : ''}`),
|
|
getBenefit: (id: number) => fetchApi(`/benefits/${id}`),
|
|
createBenefit: (data: any) => fetchApi('/benefits', { method: 'POST', body: JSON.stringify(data) }),
|
|
updateBenefit: (id: number, data: any) => fetchApi(`/benefits/${id}`, { method: 'PUT', body: JSON.stringify(data) }),
|
|
deleteBenefit: (id: number) => fetchApi(`/benefits/${id}`, { method: 'DELETE' }),
|
|
approveBenefit: (id: number) => fetchApi(`/benefits/${id}/approve`, { method: 'POST' }),
|
|
redeemBenefit: (id: number) => fetchApi(`/benefits/${id}/redeem`, { method: 'POST' }),
|
|
getCategories: () => fetchApi('/benefits/categories'),
|
|
|
|
// Admin
|
|
getDashboard: () => fetchApi('/admin/dashboard'),
|
|
getAuditLogs: (params?: string) => fetchApi(`/admin/logs${params ? `?${params}` : ''}`),
|
|
getMetrics: (period?: string) => fetchApi(`/admin/metrics${period ? `?period=${period}` : ''}`),
|
|
|
|
// Plugins
|
|
getPlugins: () => fetchApi('/plugins'),
|
|
activatePlugin: (slug: string) => fetchApi(`/plugins/${slug}/activate`, { method: 'POST' }),
|
|
deactivatePlugin: (slug: string) => fetchApi(`/plugins/${slug}/deactivate`, { method: 'POST' }),
|
|
removePlugin: (slug: string) => fetchApi(`/plugins/${slug}`, { method: 'DELETE' }),
|
|
|
|
// Webhooks
|
|
getWebhooks: () => fetchApi('/webhooks'),
|
|
createWebhook: (data: any) => fetchApi('/webhooks', { method: 'POST', body: JSON.stringify(data) }),
|
|
};
|
|
|
|
export function setTokens(accessToken: string, refreshToken: string) {
|
|
Cookies.set('accessToken', accessToken, { expires: 1 });
|
|
Cookies.set('refreshToken', refreshToken, { expires: 7 });
|
|
}
|
|
|
|
export function clearTokens() {
|
|
Cookies.remove('accessToken');
|
|
Cookies.remove('refreshToken');
|
|
}
|
|
|
|
export function getAccessToken() {
|
|
return Cookies.get('accessToken');
|
|
}
|