From 7308c0aa636681cca8d7b8a2974fa5dcc3522e74 Mon Sep 17 00:00:00 2001 From: Julien Froidefond Date: Sat, 28 Feb 2026 10:46:03 +0100 Subject: [PATCH] refactor: convert favorites to Server Actions - Add src/app/actions/favorites.ts with addToFavorites and removeFromFavorites - Update SeriesHeader to use Server Actions instead of fetch - Keep API route GET only (POST/DELETE removed) --- src/app/actions/favorites.ts | 39 +++++++++++++++ src/app/api/komga/favorites/route.ts | 66 +------------------------- src/components/series/SeriesHeader.tsx | 16 ++----- 3 files changed, 44 insertions(+), 77 deletions(-) create mode 100644 src/app/actions/favorites.ts diff --git a/src/app/actions/favorites.ts b/src/app/actions/favorites.ts new file mode 100644 index 0000000..e985e63 --- /dev/null +++ b/src/app/actions/favorites.ts @@ -0,0 +1,39 @@ +"use server"; + +import { FavoriteService } from "@/lib/services/favorite.service"; +import { ERROR_CODES } from "@/constants/errorCodes"; +import { AppError } from "@/utils/errors"; + +/** + * Ajoute une série aux favoris + */ +export async function addToFavorites( + seriesId: string +): Promise<{ success: boolean; message: string }> { + try { + await FavoriteService.addToFavorites(seriesId); + return { success: true, message: "Série ajoutée aux favoris" }; + } catch (error) { + if (error instanceof AppError) { + return { success: false, message: error.message }; + } + return { success: false, message: "Erreur lors de l'ajout aux favoris" }; + } +} + +/** + * Retire une série des favoris + */ +export async function removeFromFavorites( + seriesId: string +): Promise<{ success: boolean; message: string }> { + try { + await FavoriteService.removeFromFavorites(seriesId); + return { success: true, message: "Série retirée des favoris" }; + } catch (error) { + if (error instanceof AppError) { + return { success: false, message: error.message }; + } + return { success: false, message: "Erreur lors de la suppression des favoris" }; + } +} diff --git a/src/app/api/komga/favorites/route.ts b/src/app/api/komga/favorites/route.ts index 61c1850..de4b4a1 100644 --- a/src/app/api/komga/favorites/route.ts +++ b/src/app/api/komga/favorites/route.ts @@ -4,9 +4,9 @@ import { SeriesService } from "@/lib/services/series.service"; import { ERROR_CODES } from "@/constants/errorCodes"; import { AppError } from "@/utils/errors"; import { getErrorMessage } from "@/utils/errors"; -import type { NextRequest } from "next/server"; import logger from "@/lib/logger"; +// GET reste utilisé par Sidebar et SeriesHeader pour récupérer la liste des favoris export async function GET() { try { const favoriteIds: string[] = await FavoriteService.getAllFavoriteIds(); @@ -61,67 +61,3 @@ export async function GET() { ); } } - -export async function POST(request: NextRequest) { - try { - const { seriesId }: { seriesId: string } = await request.json(); - await FavoriteService.addToFavorites(seriesId); - return NextResponse.json({ message: "⭐️ Série ajoutée aux favoris" }); - } catch (error) { - logger.error({ err: error }, "Erreur lors de l'ajout du favori:"); - if (error instanceof AppError) { - return NextResponse.json( - { - error: { - code: error.code, - name: "Favorite add error", - message: getErrorMessage(error.code), - }, - }, - { status: 500 } - ); - } - return NextResponse.json( - { - error: { - code: ERROR_CODES.FAVORITE.ADD_ERROR, - name: "Favorite add error", - message: getErrorMessage(ERROR_CODES.FAVORITE.ADD_ERROR), - }, - }, - { status: 500 } - ); - } -} - -export async function DELETE(request: NextRequest) { - try { - const { seriesId }: { seriesId: string } = await request.json(); - await FavoriteService.removeFromFavorites(seriesId); - return NextResponse.json({ message: "💔 Série retirée des favoris" }); - } catch (error) { - logger.error({ err: error }, "Erreur lors de la suppression du favori:"); - if (error instanceof AppError) { - return NextResponse.json( - { - error: { - code: error.code, - name: "Favorite delete error", - message: getErrorMessage(error.code), - }, - }, - { status: 500 } - ); - } - return NextResponse.json( - { - error: { - code: ERROR_CODES.FAVORITE.DELETE_ERROR, - name: "Favorite delete error", - message: getErrorMessage(ERROR_CODES.FAVORITE.DELETE_ERROR), - }, - }, - { status: 500 } - ); - } -} diff --git a/src/components/series/SeriesHeader.tsx b/src/components/series/SeriesHeader.tsx index d7f3e42..e7f2096 100644 --- a/src/components/series/SeriesHeader.tsx +++ b/src/components/series/SeriesHeader.tsx @@ -13,6 +13,7 @@ import { SeriesCover } from "@/components/ui/series-cover"; import { StatusBadge } from "@/components/ui/status-badge"; import { IconButton } from "@/components/ui/icon-button"; import logger from "@/lib/logger"; +import { addToFavorites, removeFromFavorites } from "@/app/actions/favorites"; interface SeriesHeaderProps { series: KomgaSeries; @@ -51,15 +52,10 @@ export const SeriesHeader = ({ series, refreshSeries }: SeriesHeaderProps) => { const handleToggleFavorite = async () => { try { - const response = await fetch(`/api/komga/favorites`, { - method: isFavorite ? "DELETE" : "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ seriesId: series.id }), - }); + const action = isFavorite ? removeFromFavorites : addToFavorites; + const result = await action(series.id); - if (response.ok) { + if (result.success) { setIsFavorite(!isFavorite); // Dispatcher l'événement avec le seriesId pour mise à jour optimiste de la sidebar const event = new CustomEvent("favoritesChanged", { @@ -70,10 +66,6 @@ export const SeriesHeader = ({ series, refreshSeries }: SeriesHeaderProps) => { title: t(isFavorite ? "series.header.favorite.remove" : "series.header.favorite.add"), description: series.metadata.title, }); - } else if (response.status === 500) { - throw new AppError(ERROR_CODES.FAVORITE.SERVER_ERROR); - } else if (response.status === 404) { - throw new AppError(ERROR_CODES.FAVORITE.UPDATE_ERROR); } else { throw new AppError( isFavorite ? ERROR_CODES.FAVORITE.DELETE_ERROR : ERROR_CODES.FAVORITE.ADD_ERROR