UI & Feature update - Alpha #9
@@ -8,6 +8,23 @@ const api = axios.create({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Interceptor for Server-Side Rendering to pass cookies
|
||||||
|
api.interceptors.request.use(async (config) => {
|
||||||
|
if (typeof window === "undefined") {
|
||||||
|
try {
|
||||||
|
const { cookies } = await import("next/headers");
|
||||||
|
const cookieStore = await cookies();
|
||||||
|
const cookieHeader = cookieStore.toString();
|
||||||
|
if (cookieHeader) {
|
||||||
|
config.headers.Cookie = cookieHeader;
|
||||||
|
}
|
||||||
|
} catch (_error) {
|
||||||
|
// Fail silently if cookies() is not available (e.g. during build)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
});
|
||||||
|
|
||||||
// Système anti-spam rudimentaire pour les erreurs répétitives
|
// Système anti-spam rudimentaire pour les erreurs répétitives
|
||||||
const errorCache = new Map<string, number>();
|
const errorCache = new Map<string, number>();
|
||||||
const SPAM_THRESHOLD_MS = 2000; // 2 secondes de silence après une erreur sur le même endpoint
|
const SPAM_THRESHOLD_MS = 2000; // 2 secondes de silence après une erreur sur le même endpoint
|
||||||
@@ -19,14 +36,35 @@ api.interceptors.response.use(
|
|||||||
errorCache.delete(url);
|
errorCache.delete(url);
|
||||||
return response;
|
return response;
|
||||||
},
|
},
|
||||||
(error) => {
|
async (error) => {
|
||||||
|
const originalRequest = error.config;
|
||||||
|
|
||||||
|
// Handle Token Refresh (401 Unauthorized)
|
||||||
|
if (
|
||||||
|
error.response?.status === 401 &&
|
||||||
|
!originalRequest._retry &&
|
||||||
|
!originalRequest.url?.includes("/auth/refresh") &&
|
||||||
|
!originalRequest.url?.includes("/auth/login")
|
||||||
|
) {
|
||||||
|
originalRequest._retry = true;
|
||||||
|
try {
|
||||||
|
await api.post("/auth/refresh");
|
||||||
|
return api(originalRequest);
|
||||||
|
} catch (refreshError) {
|
||||||
|
// If refresh fails, we might want to redirect to login on the client
|
||||||
|
if (typeof window !== "undefined") {
|
||||||
|
window.location.href = "/login";
|
||||||
|
}
|
||||||
|
return Promise.reject(refreshError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const url = error.config?.url || "unknown";
|
const url = error.config?.url || "unknown";
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
const lastErrorTime = errorCache.get(url);
|
const lastErrorTime = errorCache.get(url);
|
||||||
|
|
||||||
if (lastErrorTime && now - lastErrorTime < SPAM_THRESHOLD_MS) {
|
if (lastErrorTime && now - lastErrorTime < SPAM_THRESHOLD_MS) {
|
||||||
// Ignorer l'erreur si elle se produit trop rapidement (déjà signalée)
|
// Ignorer l'erreur si elle se produit trop rapidement (déjà signalée)
|
||||||
// On retourne une promesse qui ne se résout jamais ou on rejette avec une marque spéciale
|
|
||||||
return new Promise(() => {});
|
return new Promise(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,9 +14,15 @@ export const FavoriteService = {
|
|||||||
limit: number;
|
limit: number;
|
||||||
offset: number;
|
offset: number;
|
||||||
}): Promise<PaginatedResponse<Content>> {
|
}): Promise<PaginatedResponse<Content>> {
|
||||||
const { data } = await api.get<PaginatedResponse<Content>>("/favorites", {
|
const { data } = await api.get<PaginatedResponse<Content>>(
|
||||||
params,
|
"/contents/explore",
|
||||||
});
|
{
|
||||||
|
params: {
|
||||||
|
...params,
|
||||||
|
favoritesOnly: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
return data;
|
return data;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
16
frontend/src/services/tag.service.ts
Normal file
16
frontend/src/services/tag.service.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import api from "@/lib/api";
|
||||||
|
import type { Tag } from "@/types/content";
|
||||||
|
|
||||||
|
export const TagService = {
|
||||||
|
async getAll(
|
||||||
|
params: {
|
||||||
|
limit?: number;
|
||||||
|
offset?: number;
|
||||||
|
query?: string;
|
||||||
|
sort?: "popular" | "recent";
|
||||||
|
} = {},
|
||||||
|
): Promise<Tag[]> {
|
||||||
|
const { data } = await api.get<Tag[]>("/tags", { params });
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user