refactor!: remove unused resizable components and enhance efficiency in critical areas

Remove outdated `ResizablePanelGroup`, `ResizablePanel`, and `ResizableHandle` components from the codebase. Optimize API error handling with anti-spam protection for repetitive errors. Update Dockerfile for streamlined builds, improve sitemap generation in `app`, and refactor lazy loading using `React.Suspense`. Refine services to support enhanced query parameters like `author`.
This commit is contained in:
Mathis HERRIOT
2026-01-14 16:37:55 +01:00
parent 37a23390d5
commit fbc231dc9a
8 changed files with 61 additions and 114 deletions

View File

@@ -24,9 +24,13 @@ export default function DashboardLayout({
{children}
{modal}
</main>
<MobileFilters />
<React.Suspense fallback={null}>
<MobileFilters />
</React.Suspense>
</div>
<SearchSidebar />
<React.Suspense fallback={null}>
<SearchSidebar />
</React.Suspense>
</SidebarInset>
</SidebarProvider>
);

View File

@@ -1,13 +1,9 @@
"use client";
import * as React from "react";
import type { Metadata } from "next";
import { ContentList } from "@/components/content-list";
import { ContentService } from "@/services/content.service";
export const metadata: Metadata = {
title: "Nouveautés | MemeGoat",
description: "Découvrez les derniers mèmes publiés sur MemeGoat.",
};
export default function RecentPage() {
const fetchFn = React.useCallback((params: { limit: number; offset: number }) =>
ContentService.getRecent(params.limit, params.offset),

View File

@@ -1,13 +1,9 @@
"use client";
import * as React from "react";
import type { Metadata } from "next";
import { ContentList } from "@/components/content-list";
import { ContentService } from "@/services/content.service";
export const metadata: Metadata = {
title: "Tendances | MemeGoat",
description: "Découvrez les mèmes les plus populaires du moment sur MemeGoat.",
};
export default function TrendsPage() {
const fetchFn = React.useCallback((params: { limit: number; offset: number }) =>
ContentService.getTrends(params.limit, params.offset),

View File

@@ -6,7 +6,7 @@ export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || "https://memegoat.local";
// Pages statiques
const routes = ["", "/trends", "/recent"].map((route) => ({
const routes: MetadataRoute.Sitemap = ["", "/trends", "/recent"].map((route) => ({
url: `${baseUrl}${route}`,
lastModified: new Date(),
changeFrequency: "daily" as const,

View File

@@ -1,56 +0,0 @@
"use client"
import * as React from "react"
import { GripVerticalIcon } from "lucide-react"
import * as ResizablePrimitive from "react-resizable-panels"
import { cn } from "@/lib/utils"
function ResizablePanelGroup({
className,
...props
}: React.ComponentProps<typeof ResizablePrimitive.PanelGroup>) {
return (
<ResizablePrimitive.PanelGroup
data-slot="resizable-panel-group"
className={cn(
"flex h-full w-full data-[panel-group-direction=vertical]:flex-col",
className
)}
{...props}
/>
)
}
function ResizablePanel({
...props
}: React.ComponentProps<typeof ResizablePrimitive.Panel>) {
return <ResizablePrimitive.Panel data-slot="resizable-panel" {...props} />
}
function ResizableHandle({
withHandle,
className,
...props
}: React.ComponentProps<typeof ResizablePrimitive.PanelResizeHandle> & {
withHandle?: boolean
}) {
return (
<ResizablePrimitive.PanelResizeHandle
data-slot="resizable-handle"
className={cn(
"bg-border focus-visible:ring-ring relative flex w-px items-center justify-center after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:ring-1 focus-visible:ring-offset-1 focus-visible:outline-hidden data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:translate-x-0 data-[panel-group-direction=vertical]:after:-translate-y-1/2 [&[data-panel-group-direction=vertical]>div]:rotate-90",
className
)}
{...props}
>
{withHandle && (
<div className="bg-border z-10 flex h-4 w-3 items-center justify-center rounded-xs border">
<GripVerticalIcon className="size-2.5" />
</div>
)}
</ResizablePrimitive.PanelResizeHandle>
)
}
export { ResizablePanelGroup, ResizablePanel, ResizableHandle }

View File

@@ -8,4 +8,31 @@ const api = axios.create({
},
});
// Système anti-spam rudimentaire pour les erreurs répétitives
const errorCache = new Map<string, number>();
const SPAM_THRESHOLD_MS = 2000; // 2 secondes de silence après une erreur sur le même endpoint
api.interceptors.response.use(
(response) => {
// Nettoyer le cache d'erreur en cas de succès sur cet endpoint
const url = response.config.url || "";
errorCache.delete(url);
return response;
},
(error) => {
const url = error.config?.url || "unknown";
const now = Date.now();
const lastErrorTime = errorCache.get(url);
if (lastErrorTime && now - lastErrorTime < SPAM_THRESHOLD_MS) {
// 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(() => {});
}
errorCache.set(url, now);
return Promise.reject(error);
}
);
export default api;

View File

@@ -9,6 +9,7 @@ export const ContentService = {
tag?: string;
category?: string;
query?: string;
author?: string;
}): Promise<PaginatedResponse<Content>> {
const { data } = await api.get<PaginatedResponse<Content>>("/contents/explore", {
params,