refacto: tentative de refacto
This commit is contained in:
@@ -1,11 +1,38 @@
|
||||
{
|
||||
"extends": ["next/core-web-vitals", "prettier"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": ["@typescript-eslint"],
|
||||
"plugins": ["@typescript-eslint", "unused-imports"],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-unused-vars": "off",
|
||||
"no-console": "off",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"warn",
|
||||
{
|
||||
"argsIgnorePattern": "^_",
|
||||
"varsIgnorePattern": "^_",
|
||||
"caughtErrorsIgnorePattern": "^_"
|
||||
}
|
||||
],
|
||||
"no-console": [
|
||||
"warn",
|
||||
{
|
||||
"allow": ["warn", "error"]
|
||||
}
|
||||
],
|
||||
"@next/next/no-html-link-for-pages": "off",
|
||||
"react/no-unescaped-entities": "off"
|
||||
"react/no-unescaped-entities": "off",
|
||||
"no-unreachable": "error",
|
||||
"no-unused-expressions": "warn",
|
||||
"no-unused-private-class-members": "warn",
|
||||
"unused-imports/no-unused-imports": "warn",
|
||||
"unused-imports/no-unused-vars": [
|
||||
"warn",
|
||||
{
|
||||
"vars": "all",
|
||||
"varsIgnorePattern": "^_",
|
||||
"args": "after-used",
|
||||
"argsIgnorePattern": "^_"
|
||||
}
|
||||
],
|
||||
"no-empty-function": "warn",
|
||||
"no-empty": ["warn", { "allowEmptyCatch": true }]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,12 +35,13 @@
|
||||
"@types/node": "20.11.16",
|
||||
"@types/react": "18.2.52",
|
||||
"@types/react-dom": "18.2.18",
|
||||
"@typescript-eslint/eslint-plugin": "6.21.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.24.0",
|
||||
"@typescript-eslint/parser": "6.21.0",
|
||||
"autoprefixer": "10.4.17",
|
||||
"eslint": "8.56.0",
|
||||
"eslint-config-next": "14.1.0",
|
||||
"eslint-config-prettier": "10.0.1",
|
||||
"eslint-plugin-unused-imports": "^4.1.4",
|
||||
"postcss": "8.4.33",
|
||||
"tailwindcss": "3.4.1",
|
||||
"typescript": "5.3.3"
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { ConfigDBService } from "@/lib/services/config-db.service";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const data = await request.json();
|
||||
|
||||
@@ -10,7 +10,7 @@ export async function GET(
|
||||
try {
|
||||
// Convertir le numéro de page en nombre
|
||||
const pageNumber = parseInt(params.pageNumber);
|
||||
if (isNaN(pageNumber) || pageNumber < 1) {
|
||||
if (isNaN(pageNumber) || pageNumber < 0) {
|
||||
return NextResponse.json({ error: "Numéro de page invalide" }, { status: 400 });
|
||||
}
|
||||
|
||||
@@ -18,8 +18,11 @@ export async function GET(
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error("API Book Page Thumbnail - Erreur:", error);
|
||||
if (error instanceof Error) {
|
||||
return NextResponse.json({ error: error.message }, { status: 500 });
|
||||
}
|
||||
return NextResponse.json(
|
||||
{ error: "Erreur lors de la récupération de la miniature" },
|
||||
{ error: "Une erreur est survenue lors de la récupération de la miniature" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
import { ConfigDBService } from "@/lib/services/config-db.service";
|
||||
import { ClientSettings } from "@/components/settings/ClientSettings";
|
||||
import { Metadata } from "next";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Préférences",
|
||||
description: "Configurez vos préférences StripStream",
|
||||
};
|
||||
|
||||
export const viewport = {
|
||||
colorScheme: "dark light",
|
||||
};
|
||||
|
||||
export default async function SettingsPage() {
|
||||
let config = null;
|
||||
|
||||
@@ -23,10 +23,6 @@ export function HomeContent({ data }: HomeContentProps) {
|
||||
await router.push(path);
|
||||
};
|
||||
|
||||
const handleSeriesClick = (seriesId: string) => {
|
||||
router.push(`/series/${seriesId}`);
|
||||
};
|
||||
|
||||
// Vérification des données pour le debug
|
||||
// console.log("HomeContent - Données reçues:", {
|
||||
// ongoingCount: data.ongoing?.length || 0,
|
||||
|
||||
@@ -86,18 +86,9 @@ function MediaCard({ item, onClick }: MediaCardProps) {
|
||||
? item.metadata.title
|
||||
: item.metadata.title || `Tome ${item.metadata.number}`;
|
||||
|
||||
const handleClick = () => {
|
||||
console.log("MediaCard - handleClick:", {
|
||||
itemType: isSeries ? "series" : "book",
|
||||
itemId: item.id,
|
||||
itemTitle: title,
|
||||
});
|
||||
onClick?.();
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
onClick={handleClick}
|
||||
onClick={onClick}
|
||||
className="flex-shrink-0 w-[200px] relative flex flex-col rounded-lg border bg-card text-card-foreground shadow-sm hover:bg-accent hover:text-accent-foreground transition-colors overflow-hidden cursor-pointer"
|
||||
>
|
||||
{/* Image de couverture */}
|
||||
|
||||
@@ -6,8 +6,7 @@ import { Header } from "@/components/layout/Header";
|
||||
import { Sidebar } from "@/components/layout/Sidebar";
|
||||
import { InstallPWA } from "../ui/InstallPWA";
|
||||
import { Toaster } from "@/components/ui/toaster";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
import { authService } from "@/lib/services/auth.service";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { PreferencesProvider } from "@/contexts/PreferencesContext";
|
||||
|
||||
// Routes qui ne nécessitent pas d'authentification
|
||||
@@ -15,7 +14,6 @@ const publicRoutes = ["/login", "/register"];
|
||||
|
||||
export default function ClientLayout({ children }: { children: React.ReactNode }) {
|
||||
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
|
||||
const handleCloseSidebar = () => {
|
||||
@@ -56,8 +54,8 @@ export default function ClientLayout({ children }: { children: React.ReactNode }
|
||||
if ("serviceWorker" in navigator) {
|
||||
navigator.serviceWorker
|
||||
.register("/sw.js")
|
||||
.then((registration) => {
|
||||
console.log("Service Worker enregistré avec succès:", registration);
|
||||
.then(() => {
|
||||
// Succès silencieux
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Erreur lors de l'enregistrement du Service Worker:", error);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { BookOpen, Home, Library, Settings, LogOut, RefreshCw, Star } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { Home, Library, Settings, LogOut, RefreshCw, Star } from "lucide-react";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { authService } from "@/lib/services/auth.service";
|
||||
@@ -32,7 +31,9 @@ export function Sidebar({ isOpen, onClose }: SidebarProps) {
|
||||
const data = await response.json();
|
||||
setLibraries(data);
|
||||
} catch (error) {
|
||||
console.error("Erreur:", error);
|
||||
if (error instanceof Error) {
|
||||
console.error("Erreur de chargement des bibliothèques:", error.message);
|
||||
}
|
||||
setLibraries([]);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
@@ -43,7 +44,6 @@ export function Sidebar({ isOpen, onClose }: SidebarProps) {
|
||||
const fetchFavorites = useCallback(async () => {
|
||||
setIsLoadingFavorites(true);
|
||||
try {
|
||||
// Récupérer les IDs des favoris depuis l'API
|
||||
const favoritesResponse = await fetch("/api/komga/favorites");
|
||||
if (!favoritesResponse.ok) {
|
||||
throw new Error("Erreur lors de la récupération des favoris");
|
||||
@@ -55,7 +55,6 @@ export function Sidebar({ isOpen, onClose }: SidebarProps) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Récupérer les détails des séries pour chaque ID
|
||||
const promises = favoriteIds.map(async (id: string) => {
|
||||
const response = await fetch(`/api/komga/series/${id}`);
|
||||
if (!response.ok) return null;
|
||||
@@ -65,7 +64,9 @@ export function Sidebar({ isOpen, onClose }: SidebarProps) {
|
||||
const results = await Promise.all(promises);
|
||||
setFavorites(results.filter((series): series is KomgaSeries => series !== null));
|
||||
} catch (error) {
|
||||
console.error("Erreur lors de la récupération des favoris:", error);
|
||||
if (error instanceof Error) {
|
||||
console.error("Erreur de chargement des favoris:", error.message);
|
||||
}
|
||||
setFavorites([]);
|
||||
} finally {
|
||||
setIsLoadingFavorites(false);
|
||||
|
||||
@@ -6,9 +6,10 @@ import { useRouter, usePathname, useSearchParams } from "next/navigation";
|
||||
import { useState, useEffect } from "react";
|
||||
import { Loader2, Filter } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { KomgaSeries } from "@/types/komga";
|
||||
|
||||
interface PaginatedSeriesGridProps {
|
||||
series: any[];
|
||||
series: KomgaSeries[];
|
||||
currentPage: number;
|
||||
totalPages: number;
|
||||
totalElements: number;
|
||||
@@ -61,10 +62,6 @@ export function PaginatedSeriesGrid({
|
||||
await router.push(`${pathname}?${params.toString()}`);
|
||||
};
|
||||
|
||||
const handleSeriesClick = (seriesId: string) => {
|
||||
router.push(`/series/${seriesId}`);
|
||||
};
|
||||
|
||||
// Calcul des indices de début et de fin pour l'affichage
|
||||
const startIndex = (currentPage - 1) * pageSize + 1;
|
||||
const endIndex = Math.min(currentPage * pageSize, totalElements);
|
||||
|
||||
@@ -24,12 +24,9 @@ export function BookReader({ book, pages, onClose }: BookReaderProps) {
|
||||
setIsLoading,
|
||||
secondPageLoading,
|
||||
setSecondPageLoading,
|
||||
imageError,
|
||||
setImageError,
|
||||
handlePreviousPage,
|
||||
handleNextPage,
|
||||
shouldShowDoublePage,
|
||||
syncReadProgress,
|
||||
} = usePageNavigation({
|
||||
book,
|
||||
pages,
|
||||
@@ -66,9 +63,12 @@ export function BookReader({ book, pages, onClose }: BookReaderProps) {
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Erreur lors du chargement des URLs:", error);
|
||||
setImageError(true);
|
||||
} finally {
|
||||
if (error instanceof Error) {
|
||||
console.error(
|
||||
`Erreur de chargement des URLs pour la page ${currentPage}:`,
|
||||
error.message
|
||||
);
|
||||
}
|
||||
// On s'assure que le chargement est terminé même en cas d'erreur
|
||||
if (isMounted) {
|
||||
setIsLoading(false);
|
||||
@@ -91,7 +91,6 @@ export function BookReader({ book, pages, onClose }: BookReaderProps) {
|
||||
getPageUrl,
|
||||
setIsLoading,
|
||||
setSecondPageLoading,
|
||||
setImageError,
|
||||
]);
|
||||
|
||||
// Effet pour précharger la page courante et les pages adjacentes
|
||||
@@ -205,6 +204,13 @@ export function BookReader({ book, pages, onClose }: BookReaderProps) {
|
||||
{/* Pages */}
|
||||
<div className="relative flex-1 flex items-center justify-center overflow-hidden p-1">
|
||||
<div className="relative w-full h-[calc(100vh-2rem)] flex items-center justify-center gap-0">
|
||||
{/*
|
||||
Note: Nous utilisons intentionnellement des balises <img> natives au lieu de next/image pour :
|
||||
1. Avoir un contrôle précis sur le chargement et le préchargement des pages
|
||||
2. Gérer efficacement le mode double page et les transitions
|
||||
3. Les images sont déjà optimisées côté serveur
|
||||
4. La performance est critique pour une lecture fluide
|
||||
*/}
|
||||
{/* Page courante */}
|
||||
<div
|
||||
className={cn(
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
import { KomgaBook } from "@/types/komga";
|
||||
import { BookReader } from "./BookReader";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useEffect } from "react";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
|
||||
interface ClientBookWrapperProps {
|
||||
book: KomgaBook;
|
||||
|
||||
@@ -31,6 +31,10 @@ export const ControlButtons = ({
|
||||
"absolute top-4 left-1/2 -translate-x-1/2 z-30 flex items-center gap-2 transition-all duration-300",
|
||||
showControls ? "opacity-100" : "opacity-0 pointer-events-none"
|
||||
)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onToggleControls();
|
||||
}}
|
||||
>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { NavigationBarProps } from "../types";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Thumbnail } from "./Thumbnail";
|
||||
import { useThumbnails } from "../hooks/useThumbnails";
|
||||
import { useEffect } from "react";
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
export const NavigationBar = ({
|
||||
currentPage,
|
||||
@@ -11,17 +11,14 @@ export const NavigationBar = ({
|
||||
showControls,
|
||||
book,
|
||||
}: NavigationBarProps) => {
|
||||
const {
|
||||
loadedThumbnails,
|
||||
handleThumbnailLoad,
|
||||
getThumbnailUrl,
|
||||
visibleThumbnails,
|
||||
scrollToActiveThumbnail,
|
||||
} = useThumbnails({
|
||||
const { loadedThumbnails, handleThumbnailLoad, getThumbnailUrl, visibleThumbnails } =
|
||||
useThumbnails({
|
||||
book,
|
||||
currentPage,
|
||||
});
|
||||
|
||||
const thumbnailsContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Scroll à l'ouverture des contrôles et au changement de page
|
||||
useEffect(() => {
|
||||
if (showControls) {
|
||||
@@ -53,6 +50,7 @@ export const NavigationBar = ({
|
||||
onTouchStart={(e) => e.stopPropagation()}
|
||||
onTouchMove={(e) => e.stopPropagation()}
|
||||
onTouchEnd={(e) => e.stopPropagation()}
|
||||
ref={thumbnailsContainerRef}
|
||||
>
|
||||
<div className="w-[calc(50vw-18rem)] flex-shrink-0" />
|
||||
{pages.map((_, index) => {
|
||||
|
||||
@@ -6,15 +6,7 @@ import { forwardRef, useEffect, useState, useCallback, useRef } from "react";
|
||||
|
||||
export const Thumbnail = forwardRef<HTMLButtonElement, ThumbnailProps>(
|
||||
(
|
||||
{
|
||||
pageNumber,
|
||||
currentPage,
|
||||
onPageChange,
|
||||
getThumbnailUrl,
|
||||
loadedThumbnails,
|
||||
onThumbnailLoad,
|
||||
isVisible,
|
||||
},
|
||||
{ pageNumber, currentPage, onPageChange, getThumbnailUrl, loadedThumbnails, onThumbnailLoad },
|
||||
ref
|
||||
) => {
|
||||
const [imageUrl, setImageUrl] = useState<string | null>(null);
|
||||
@@ -59,9 +51,6 @@ export const Thumbnail = forwardRef<HTMLButtonElement, ThumbnailProps>(
|
||||
if (loadAttempts.current < maxAttempts) {
|
||||
// Réessayer avec un délai croissant
|
||||
const delay = Math.min(1000 * Math.pow(2, loadAttempts.current - 1), 5000);
|
||||
console.log(
|
||||
`Réessai ${loadAttempts.current}/${maxAttempts} dans ${delay}ms pour la page ${pageNumber}`
|
||||
);
|
||||
setTimeout(() => {
|
||||
setImageUrl((prev) => (prev ? `${prev}?retry=${loadAttempts.current}` : null));
|
||||
}, delay);
|
||||
@@ -94,7 +83,7 @@ export const Thumbnail = forwardRef<HTMLButtonElement, ThumbnailProps>(
|
||||
src={imageUrl}
|
||||
alt={`Miniature page ${pageNumber}`}
|
||||
className={cn(
|
||||
"object-cover transition-opacity duration-300",
|
||||
"object-contain transition-opacity duration-300",
|
||||
isLoading ? "opacity-0" : "opacity-100"
|
||||
)}
|
||||
fill
|
||||
|
||||
@@ -12,12 +12,11 @@ export const usePageNavigation = ({
|
||||
book,
|
||||
pages,
|
||||
isDoublePage,
|
||||
onClose = () => {},
|
||||
onClose,
|
||||
}: UsePageNavigationProps) => {
|
||||
const [currentPage, setCurrentPage] = useState(book.readProgress?.page || 1);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [secondPageLoading, setSecondPageLoading] = useState(true);
|
||||
const [imageError, setImageError] = useState(false);
|
||||
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
const touchStartXRef = useRef<number | null>(null);
|
||||
const touchStartYRef = useRef<number | null>(null);
|
||||
@@ -39,7 +38,12 @@ export const usePageNavigation = ({
|
||||
body: JSON.stringify({ page, completed }),
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Erreur lors de la synchronisation de la progression:", error);
|
||||
if (error instanceof Error) {
|
||||
console.error(
|
||||
`Erreur de synchronisation de la progression pour le livre ${book.id} à la page ${page}:`,
|
||||
error.message
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
[book.id, pages.length]
|
||||
@@ -73,7 +77,6 @@ export const usePageNavigation = ({
|
||||
setCurrentPage(page);
|
||||
setIsLoading(true);
|
||||
setSecondPageLoading(true);
|
||||
setImageError(false);
|
||||
debouncedSyncReadProgress(page);
|
||||
},
|
||||
[debouncedSyncReadProgress]
|
||||
@@ -167,11 +170,8 @@ export const usePageNavigation = ({
|
||||
setIsLoading,
|
||||
secondPageLoading,
|
||||
setSecondPageLoading,
|
||||
imageError,
|
||||
setImageError,
|
||||
handlePreviousPage,
|
||||
handleNextPage,
|
||||
shouldShowDoublePage,
|
||||
syncReadProgress: debouncedSyncReadProgress,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -16,7 +16,8 @@ export const useThumbnails = ({ book, currentPage }: UseThumbnailsProps) => {
|
||||
|
||||
const getThumbnailUrl = useCallback(
|
||||
(pageNumber: number) => {
|
||||
return `/api/komga/images/books/${book.id}/pages/${pageNumber}/thumbnail`;
|
||||
const zeroBasedPage = pageNumber - 1;
|
||||
return `/api/komga/images/books/${book.id}/pages/${zeroBasedPage}/thumbnail?zero_based=true`;
|
||||
},
|
||||
[book.id]
|
||||
);
|
||||
|
||||
@@ -70,10 +70,6 @@ export function PaginatedBookGrid({
|
||||
const startIndex = (currentPage - 1) * pageSize + 1;
|
||||
const endIndex = Math.min(currentPage * pageSize, totalElements);
|
||||
|
||||
const getBookThumbnailUrl = (bookId: string) => {
|
||||
return `/api/komga/images/books/${bookId}/thumbnail`;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
<div className="flex items-center justify-between flex-wrap gap-4">
|
||||
@@ -115,11 +111,7 @@ export function PaginatedBookGrid({
|
||||
isChangingPage ? "opacity-25" : "opacity-100"
|
||||
)}
|
||||
>
|
||||
<BookGrid
|
||||
books={books}
|
||||
onBookClick={handleBookClick}
|
||||
getBookThumbnailUrl={getBookThumbnailUrl}
|
||||
/>
|
||||
<BookGrid books={books} onBookClick={handleBookClick} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -5,15 +5,13 @@ import { KomgaSeries } from "@/types/komga";
|
||||
import { useState, useEffect } from "react";
|
||||
import { Button } from "../ui/button";
|
||||
import { useToast } from "@/components/ui/use-toast";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Cover } from "@/components/ui/cover";
|
||||
|
||||
interface SeriesHeaderProps {
|
||||
series: KomgaSeries;
|
||||
onSeriesUpdate?: (series: KomgaSeries) => void;
|
||||
}
|
||||
|
||||
export const SeriesHeader = ({ series, onSeriesUpdate }: SeriesHeaderProps) => {
|
||||
export const SeriesHeader = ({ series }: SeriesHeaderProps) => {
|
||||
const { toast } = useToast();
|
||||
const [isFavorite, setIsFavorite] = useState(false);
|
||||
|
||||
|
||||
@@ -9,10 +9,6 @@ import { usePreferences } from "@/contexts/PreferencesContext";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { Label } from "@/components/ui/label";
|
||||
|
||||
interface ErrorMessage {
|
||||
message: string;
|
||||
}
|
||||
|
||||
interface KomgaConfig {
|
||||
url: string;
|
||||
username: string;
|
||||
@@ -256,7 +252,10 @@ export function ClientSettings({ initialConfig, initialTTLConfig }: ClientSettin
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Erreur",
|
||||
description: "Une erreur est survenue lors de la mise à jour des préférences",
|
||||
description:
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Une erreur est survenue lors de la mise à jour des préférences",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface ImageLoaderProps {
|
||||
|
||||
@@ -12,7 +12,7 @@ type ToasterToast = ToastProps & {
|
||||
action?: ToastActionElement;
|
||||
};
|
||||
|
||||
const actionTypes = {
|
||||
const _actionTypes = {
|
||||
ADD_TOAST: "ADD_TOAST",
|
||||
UPDATE_TOAST: "UPDATE_TOAST",
|
||||
DISMISS_TOAST: "DISMISS_TOAST",
|
||||
@@ -26,7 +26,7 @@ function genId() {
|
||||
return count.toString();
|
||||
}
|
||||
|
||||
type ActionType = typeof actionTypes;
|
||||
type ActionType = typeof _actionTypes;
|
||||
|
||||
type Action =
|
||||
| {
|
||||
|
||||
@@ -2,16 +2,13 @@
|
||||
|
||||
import { AuthError } from "@/types/auth";
|
||||
|
||||
interface AuthUser {
|
||||
id: string;
|
||||
email: string;
|
||||
roles: string[];
|
||||
authenticated: boolean;
|
||||
}
|
||||
class AuthService {
|
||||
private static instance: AuthService;
|
||||
|
||||
private constructor() {}
|
||||
// Constructeur privé pour le pattern Singleton
|
||||
private constructor() {
|
||||
// Pas d'initialisation nécessaire
|
||||
}
|
||||
|
||||
public static getInstance(): AuthService {
|
||||
if (!AuthService.instance) {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { cookies } from "next/headers";
|
||||
import { AuthConfig } from "@/types/auth";
|
||||
import { serverCacheService } from "./server-cache.service";
|
||||
import { ConfigDBService } from "./config-db.service";
|
||||
@@ -71,18 +70,12 @@ export abstract class BaseApiService {
|
||||
});
|
||||
}
|
||||
|
||||
// Log de l'URL finale
|
||||
console.log(`🔄 [Komga API] ${url.toString()}`);
|
||||
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
protected static async fetchFromApi<T>(url: string, headers: Headers): Promise<T> {
|
||||
const response = await fetch(url, { headers });
|
||||
|
||||
// Log du résultat de la requête
|
||||
console.log(`📡 [Komga API] ${response.status} ${response.statusText} - ${url}`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Erreur HTTP: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
@@ -18,9 +18,6 @@ export class ImageService extends BaseApiService {
|
||||
async () => {
|
||||
const response = await fetch(url, { headers });
|
||||
|
||||
// Log du résultat de la requête
|
||||
console.log(`📡 [Komga API] ${response.status} ${response.statusText} - ${url}`);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Erreur HTTP: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
type CacheEntry = {
|
||||
data: any;
|
||||
timestamp: number;
|
||||
ttl: number;
|
||||
};
|
||||
|
||||
class ServerCacheService {
|
||||
private static instance: ServerCacheService;
|
||||
private cache: Map<string, { data: unknown; expiry: number }> = new Map();
|
||||
@@ -94,14 +88,11 @@ class ServerCacheService {
|
||||
type: keyof typeof ServerCacheService.DEFAULT_TTL = "DEFAULT"
|
||||
): Promise<T> {
|
||||
const now = Date.now();
|
||||
console.log("👀 Getting or setting cache for key:", key);
|
||||
const cached = this.cache.get(key);
|
||||
|
||||
if (cached && cached.expiry > now) {
|
||||
console.log("✅ Cache hit for key:", key);
|
||||
return cached.data as T;
|
||||
}
|
||||
console.log("❌ Cache not hit for key:", key);
|
||||
|
||||
try {
|
||||
const data = await fetcher();
|
||||
|
||||
@@ -11,13 +11,13 @@ export interface Series {
|
||||
booksUnreadCount: number;
|
||||
booksInProgressCount: number;
|
||||
metadata: {
|
||||
status: string;
|
||||
status: "ENDED" | "ONGOING" | "ABANDONED" | "HIATUS";
|
||||
created: string;
|
||||
lastModified: string;
|
||||
title: string;
|
||||
titleSort: string;
|
||||
summary: string;
|
||||
readingDirection: string;
|
||||
readingDirection: "LEFT_TO_RIGHT" | "RIGHT_TO_LEFT" | "VERTICAL" | "WEBTOON";
|
||||
publisher: string;
|
||||
ageRating: number;
|
||||
language: string;
|
||||
@@ -47,4 +47,6 @@ export interface Series {
|
||||
}>;
|
||||
};
|
||||
deleted: boolean;
|
||||
oneshot: boolean;
|
||||
favorite: boolean;
|
||||
}
|
||||
|
||||
123
yarn.lock
123
yarn.lock
@@ -28,7 +28,7 @@
|
||||
dependencies:
|
||||
eslint-visitor-keys "^3.4.3"
|
||||
|
||||
"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1":
|
||||
"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.6.1":
|
||||
version "4.12.1"
|
||||
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0"
|
||||
integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==
|
||||
@@ -741,11 +741,6 @@
|
||||
dependencies:
|
||||
tslib "^2.4.0"
|
||||
|
||||
"@types/json-schema@^7.0.12":
|
||||
version "7.0.15"
|
||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
|
||||
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
|
||||
|
||||
"@types/json5@^0.0.29":
|
||||
version "0.0.29"
|
||||
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
||||
@@ -798,11 +793,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.23.0.tgz#0a6655b3e2708eaabca00b7372fafd7a792a7b09"
|
||||
integrity sha512-YIoDCTH3Af6XM5VuwGG/QL/CJqga1Zm3NkU3HZ4ZHK2fRMPYP1VczsTUqtsf43PH/iJNVlPHAo2oWX7BSdB2Hw==
|
||||
|
||||
"@types/semver@^7.5.0":
|
||||
version "7.5.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e"
|
||||
integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==
|
||||
|
||||
"@types/webidl-conversions@*":
|
||||
version "7.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz#1306dbfa53768bcbcfc95a1c8cde367975581859"
|
||||
@@ -815,22 +805,20 @@
|
||||
dependencies:
|
||||
"@types/webidl-conversions" "*"
|
||||
|
||||
"@typescript-eslint/eslint-plugin@6.21.0":
|
||||
version "6.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz#30830c1ca81fd5f3c2714e524c4303e0194f9cd3"
|
||||
integrity sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==
|
||||
"@typescript-eslint/eslint-plugin@^8.24.0":
|
||||
version "8.24.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.24.0.tgz#574a95d67660a1e4544ae131d672867a5b40abb3"
|
||||
integrity sha512-aFcXEJJCI4gUdXgoo/j9udUYIHgF23MFkg09LFz2dzEmU0+1Plk4rQWv/IYKvPHAtlkkGoB3m5e6oUp+JPsNaQ==
|
||||
dependencies:
|
||||
"@eslint-community/regexpp" "^4.5.1"
|
||||
"@typescript-eslint/scope-manager" "6.21.0"
|
||||
"@typescript-eslint/type-utils" "6.21.0"
|
||||
"@typescript-eslint/utils" "6.21.0"
|
||||
"@typescript-eslint/visitor-keys" "6.21.0"
|
||||
debug "^4.3.4"
|
||||
"@eslint-community/regexpp" "^4.10.0"
|
||||
"@typescript-eslint/scope-manager" "8.24.0"
|
||||
"@typescript-eslint/type-utils" "8.24.0"
|
||||
"@typescript-eslint/utils" "8.24.0"
|
||||
"@typescript-eslint/visitor-keys" "8.24.0"
|
||||
graphemer "^1.4.0"
|
||||
ignore "^5.2.4"
|
||||
ignore "^5.3.1"
|
||||
natural-compare "^1.4.0"
|
||||
semver "^7.5.4"
|
||||
ts-api-utils "^1.0.1"
|
||||
ts-api-utils "^2.0.1"
|
||||
|
||||
"@typescript-eslint/parser@6.21.0", "@typescript-eslint/parser@^5.4.2 || ^6.0.0":
|
||||
version "6.21.0"
|
||||
@@ -851,21 +839,34 @@
|
||||
"@typescript-eslint/types" "6.21.0"
|
||||
"@typescript-eslint/visitor-keys" "6.21.0"
|
||||
|
||||
"@typescript-eslint/type-utils@6.21.0":
|
||||
version "6.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz#6473281cfed4dacabe8004e8521cee0bd9d4c01e"
|
||||
integrity sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==
|
||||
"@typescript-eslint/scope-manager@8.24.0":
|
||||
version "8.24.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.24.0.tgz#2e34b3eb2ce768f2ffb109474174ced5417002b1"
|
||||
integrity sha512-HZIX0UByphEtdVBKaQBgTDdn9z16l4aTUz8e8zPQnyxwHBtf5vtl1L+OhH+m1FGV9DrRmoDuYKqzVrvWDcDozw==
|
||||
dependencies:
|
||||
"@typescript-eslint/typescript-estree" "6.21.0"
|
||||
"@typescript-eslint/utils" "6.21.0"
|
||||
"@typescript-eslint/types" "8.24.0"
|
||||
"@typescript-eslint/visitor-keys" "8.24.0"
|
||||
|
||||
"@typescript-eslint/type-utils@8.24.0":
|
||||
version "8.24.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.24.0.tgz#6ee3ec4db06f9e5e7b01ca6c2b5dd5843a9fd1e8"
|
||||
integrity sha512-8fitJudrnY8aq0F1wMiPM1UUgiXQRJ5i8tFjq9kGfRajU+dbPyOuHbl0qRopLEidy0MwqgTHDt6CnSeXanNIwA==
|
||||
dependencies:
|
||||
"@typescript-eslint/typescript-estree" "8.24.0"
|
||||
"@typescript-eslint/utils" "8.24.0"
|
||||
debug "^4.3.4"
|
||||
ts-api-utils "^1.0.1"
|
||||
ts-api-utils "^2.0.1"
|
||||
|
||||
"@typescript-eslint/types@6.21.0":
|
||||
version "6.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.21.0.tgz#205724c5123a8fef7ecd195075fa6e85bac3436d"
|
||||
integrity sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==
|
||||
|
||||
"@typescript-eslint/types@8.24.0":
|
||||
version "8.24.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.24.0.tgz#694e7fb18d70506c317b816de9521300b0f72c8e"
|
||||
integrity sha512-VacJCBTyje7HGAw7xp11q439A+zeGG0p0/p2zsZwpnMzjPB5WteaWqt4g2iysgGFafrqvyLWqq6ZPZAOCoefCw==
|
||||
|
||||
"@typescript-eslint/typescript-estree@6.21.0":
|
||||
version "6.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz#c47ae7901db3b8bddc3ecd73daff2d0895688c46"
|
||||
@@ -880,18 +881,29 @@
|
||||
semver "^7.5.4"
|
||||
ts-api-utils "^1.0.1"
|
||||
|
||||
"@typescript-eslint/utils@6.21.0":
|
||||
version "6.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.21.0.tgz#4714e7a6b39e773c1c8e97ec587f520840cd8134"
|
||||
integrity sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==
|
||||
"@typescript-eslint/typescript-estree@8.24.0":
|
||||
version "8.24.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.24.0.tgz#0487349be174097bb329a58273100a9629e03c6c"
|
||||
integrity sha512-ITjYcP0+8kbsvT9bysygfIfb+hBj6koDsu37JZG7xrCiy3fPJyNmfVtaGsgTUSEuTzcvME5YI5uyL5LD1EV5ZQ==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.24.0"
|
||||
"@typescript-eslint/visitor-keys" "8.24.0"
|
||||
debug "^4.3.4"
|
||||
fast-glob "^3.3.2"
|
||||
is-glob "^4.0.3"
|
||||
minimatch "^9.0.4"
|
||||
semver "^7.6.0"
|
||||
ts-api-utils "^2.0.1"
|
||||
|
||||
"@typescript-eslint/utils@8.24.0":
|
||||
version "8.24.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.24.0.tgz#21cb1195ae79230af825bfeed59574f5cb70a749"
|
||||
integrity sha512-07rLuUBElvvEb1ICnafYWr4hk8/U7X9RDCOqd9JcAMtjh/9oRmcfN4yGzbPVirgMR0+HLVHehmu19CWeh7fsmQ==
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils" "^4.4.0"
|
||||
"@types/json-schema" "^7.0.12"
|
||||
"@types/semver" "^7.5.0"
|
||||
"@typescript-eslint/scope-manager" "6.21.0"
|
||||
"@typescript-eslint/types" "6.21.0"
|
||||
"@typescript-eslint/typescript-estree" "6.21.0"
|
||||
semver "^7.5.4"
|
||||
"@typescript-eslint/scope-manager" "8.24.0"
|
||||
"@typescript-eslint/types" "8.24.0"
|
||||
"@typescript-eslint/typescript-estree" "8.24.0"
|
||||
|
||||
"@typescript-eslint/visitor-keys@6.21.0":
|
||||
version "6.21.0"
|
||||
@@ -901,6 +913,14 @@
|
||||
"@typescript-eslint/types" "6.21.0"
|
||||
eslint-visitor-keys "^3.4.1"
|
||||
|
||||
"@typescript-eslint/visitor-keys@8.24.0":
|
||||
version "8.24.0"
|
||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.24.0.tgz#36ecf0b9b1d819ad88a3bd4157ab7d594cb797c9"
|
||||
integrity sha512-kArLq83QxGLbuHrTMoOEWO+l2MwsNS2TGISEdx8xgqpkbytB07XmlQyQdNDrCc1ecSqx0cnmhGvpX+VBwqqSkg==
|
||||
dependencies:
|
||||
"@typescript-eslint/types" "8.24.0"
|
||||
eslint-visitor-keys "^4.2.0"
|
||||
|
||||
"@ungap/structured-clone@^1.2.0":
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8"
|
||||
@@ -1720,6 +1740,11 @@ eslint-plugin-react@^7.33.2:
|
||||
string.prototype.matchall "^4.0.12"
|
||||
string.prototype.repeat "^1.0.0"
|
||||
|
||||
eslint-plugin-unused-imports@^4.1.4:
|
||||
version "4.1.4"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.4.tgz#62ddc7446ccbf9aa7b6f1f0b00a980423cda2738"
|
||||
integrity sha512-YptD6IzQjDardkl0POxnnRBhU1OEePMV0nd6siHaRBbd+lyh6NAhFEobiznKU7kTsSsDeSD62Pe7kAM1b7dAZQ==
|
||||
|
||||
eslint-scope@^7.2.2:
|
||||
version "7.2.2"
|
||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f"
|
||||
@@ -1733,6 +1758,11 @@ eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3:
|
||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
|
||||
integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
|
||||
|
||||
eslint-visitor-keys@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45"
|
||||
integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==
|
||||
|
||||
eslint@8.56.0:
|
||||
version "8.56.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.56.0.tgz#4957ce8da409dc0809f99ab07a1b94832ab74b15"
|
||||
@@ -1815,7 +1845,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
||||
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
|
||||
|
||||
fast-glob@^3.2.9, fast-glob@^3.3.0:
|
||||
fast-glob@^3.2.9, fast-glob@^3.3.0, fast-glob@^3.3.2:
|
||||
version "3.3.3"
|
||||
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818"
|
||||
integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==
|
||||
@@ -2115,7 +2145,7 @@ hasown@^2.0.2:
|
||||
dependencies:
|
||||
function-bind "^1.1.2"
|
||||
|
||||
ignore@^5.2.0, ignore@^5.2.4:
|
||||
ignore@^5.2.0, ignore@^5.3.1:
|
||||
version "5.3.2"
|
||||
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5"
|
||||
integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==
|
||||
@@ -3246,7 +3276,7 @@ semver@^6.3.1:
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
|
||||
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
|
||||
|
||||
semver@^7.5.4, semver@^7.6.3:
|
||||
semver@^7.5.4, semver@^7.6.0, semver@^7.6.3:
|
||||
version "7.7.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f"
|
||||
integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==
|
||||
@@ -3661,6 +3691,11 @@ ts-api-utils@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.4.3.tgz#bfc2215fe6528fecab2b0fba570a2e8a4263b064"
|
||||
integrity sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==
|
||||
|
||||
ts-api-utils@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.0.1.tgz#660729385b625b939aaa58054f45c058f33f10cd"
|
||||
integrity sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w==
|
||||
|
||||
ts-interface-checker@^0.1.9:
|
||||
version "0.1.13"
|
||||
resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699"
|
||||
|
||||
Reference in New Issue
Block a user