"use client";
import { useTransition } from "react";
import { useRouter } from "next/navigation";
import {
markMovieAction,
undoAction,
unmarkMovieAction,
watchNextAction,
} from "@/app/actions/library";
import { useToasts } from "@/components/Toasts";
import { episodeCode, formatDate, isUpcoming } from "@/lib/labels";
/**
* „Als Nächstes dran" mit dem Schnellknopf.
*
* Das ist der meistbenutzte Knopf der ganzen Anwendung — deshalb steht er
* oben, ist groß, und sagt vorher, was er abhaken wird.
*/
export function NextEpisodeCard({
entryId,
next,
}: {
entryId: string;
next: {
id: string;
name: string;
seasonNumber: number;
episodeNumber: number;
airDate: string | null;
runtime: number | null;
};
}) {
const router = useRouter();
const { report } = useToasts();
const [pending, startTransition] = useTransition();
const upcoming = isUpcoming(next.airDate);
const code = episodeCode(next.seasonNumber, next.episodeNumber);
async function undo(watchIds: string[]) {
await undoAction(entryId, watchIds);
router.refresh();
}
return (
Als Nächstes dran
{code} {" "}
{next.name}
{upcoming
? `Erscheint erst am ${formatDate(next.airDate)}`
: [formatDate(next.airDate), next.runtime ? `${next.runtime} min` : null]
.filter(Boolean)
.join(" · ") || "Kein Ausstrahlungsdatum hinterlegt"}
startTransition(async () => {
const result = await watchNextAction(entryId);
report(result, (ids) => undo(ids));
router.refresh();
})
}
className="fl-btn fl-btn-primary"
title={`${code} als gesehen markieren`}
>
+1 Episode
);
}
/** Sichtungsknopf für Filme. */
export function WatchMovieButton({
entryId,
watched,
}: {
entryId: string;
watched: boolean;
}) {
const router = useRouter();
const { report } = useToasts();
const [pending, startTransition] = useTransition();
async function undo(watchIds: string[]) {
await undoAction(entryId, watchIds);
router.refresh();
}
// Im Zustand „gesehen" bleibt die grüne Plakette stehen, ist aber klickbar —
// so wie sich Episodenhäkchen auch wieder abwählen lassen. Vorher stand hier
// ein : ein Etikett ohne Klickziel, aus dem es kein Zurück gab.
if (watched) {
return (
startTransition(async () => {
report(await unmarkMovieAction(entryId));
router.refresh();
})
}
className="group inline-flex items-center gap-2 rounded-xl border border-[color-mix(in_oklab,var(--fl-success)_45%,transparent)] bg-[color-mix(in_oklab,var(--fl-success)_12%,transparent)] px-3 py-2 text-sm text-[var(--fl-success)] transition-colors hover:border-[color-mix(in_oklab,var(--fl-success)_70%,transparent)] hover:bg-[color-mix(in_oklab,var(--fl-success)_20%,transparent)] disabled:opacity-60"
>
Gesehen
— Markierung entfernen
);
}
return (
startTransition(async () => {
const result = await markMovieAction(entryId);
report(result, (ids) => undo(ids));
router.refresh();
})
}
className="fl-btn fl-btn-primary"
>
Als gesehen markieren
);
}