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)
This commit is contained in:
2026-02-28 10:46:03 +01:00
parent 7e3fb22d3a
commit 7308c0aa63
3 changed files with 44 additions and 77 deletions

View File

@@ -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" };
}
}

View File

@@ -4,9 +4,9 @@ import { SeriesService } from "@/lib/services/series.service";
import { ERROR_CODES } from "@/constants/errorCodes"; import { ERROR_CODES } from "@/constants/errorCodes";
import { AppError } from "@/utils/errors"; import { AppError } from "@/utils/errors";
import { getErrorMessage } from "@/utils/errors"; import { getErrorMessage } from "@/utils/errors";
import type { NextRequest } from "next/server";
import logger from "@/lib/logger"; import logger from "@/lib/logger";
// GET reste utilisé par Sidebar et SeriesHeader pour récupérer la liste des favoris
export async function GET() { export async function GET() {
try { try {
const favoriteIds: string[] = await FavoriteService.getAllFavoriteIds(); 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 }
);
}
}

View File

@@ -13,6 +13,7 @@ import { SeriesCover } from "@/components/ui/series-cover";
import { StatusBadge } from "@/components/ui/status-badge"; import { StatusBadge } from "@/components/ui/status-badge";
import { IconButton } from "@/components/ui/icon-button"; import { IconButton } from "@/components/ui/icon-button";
import logger from "@/lib/logger"; import logger from "@/lib/logger";
import { addToFavorites, removeFromFavorites } from "@/app/actions/favorites";
interface SeriesHeaderProps { interface SeriesHeaderProps {
series: KomgaSeries; series: KomgaSeries;
@@ -51,15 +52,10 @@ export const SeriesHeader = ({ series, refreshSeries }: SeriesHeaderProps) => {
const handleToggleFavorite = async () => { const handleToggleFavorite = async () => {
try { try {
const response = await fetch(`/api/komga/favorites`, { const action = isFavorite ? removeFromFavorites : addToFavorites;
method: isFavorite ? "DELETE" : "POST", const result = await action(series.id);
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ seriesId: series.id }),
});
if (response.ok) { if (result.success) {
setIsFavorite(!isFavorite); setIsFavorite(!isFavorite);
// Dispatcher l'événement avec le seriesId pour mise à jour optimiste de la sidebar // Dispatcher l'événement avec le seriesId pour mise à jour optimiste de la sidebar
const event = new CustomEvent("favoritesChanged", { 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"), title: t(isFavorite ? "series.header.favorite.remove" : "series.header.favorite.add"),
description: series.metadata.title, 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 { } else {
throw new AppError( throw new AppError(
isFavorite ? ERROR_CODES.FAVORITE.DELETE_ERROR : ERROR_CODES.FAVORITE.ADD_ERROR isFavorite ? ERROR_CODES.FAVORITE.DELETE_ERROR : ERROR_CODES.FAVORITE.ADD_ERROR