fix(dashboard): block duplicate quick-watch clicks until refetch and use logical end inset

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
jakeandClaude Sonnet 5.5 committed 2026-10-05 14:21:47 -04:00
1 parent 04bcb66436
commit e3f7ccca07
2 files changed
+15 -10

No files matched your search

@@ -116,7 +116,7 @@ export function ContinueWatchingCard({ item }: { item: ContinueWatchingItemProps
size="icon"
aria-label={quickWatchLabel}
disabled={pendingId === nextEpisode.id}
className="absolute top-2 right-2 rounded-full bg-black/50 text-white backdrop-blur-sm hover:bg-black/70"
className="absolute end-2 top-2 rounded-full bg-black/50 text-white backdrop-blur-sm hover:bg-black/70"
onClick={() =>
watchEpisode(
nextEpisode.id,
@@ -1,5 +1,6 @@
import { useLingui } from "@lingui/react/macro";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useState } from "react";
import { toast } from "sonner";
import { getErrorMessage } from "@/lib/error-messages";
@@ -10,21 +11,25 @@ import { invalidateTrackingQueries } from "@/lib/orpc/invalidate";
export function useQuickWatchEpisode() {
const { t } = useLingui();
const queryClient = useQueryClient();
const { mutate, variables, isPending } = useMutation(orpc.tracking.watch.mutationOptions());
function watchEpisode(episodeId: string, label: string) {
mutate(
{ scope: "episode", ids: [episodeId] },
{
onSuccess: () => {
const [label, setLabel] = useState("");
// Handlers live on the hook-level options so the mutation stays pending until
// the tracking queries have refetched, which blocks duplicate clicks.
const { mutate, variables, isPending } = useMutation(
orpc.tracking.watch.mutationOptions({
onSuccess: async () => {
toast.success(t`Marked ${label} as watched`);
void invalidateTrackingQueries(queryClient);
await invalidateTrackingQueries(queryClient);
},
onError: (err) => {
toast.error(getErrorMessage(err, t`Failed to mark episode`));
},
},
}),
);
function watchEpisode(episodeId: string, episodeLabel: string) {
if (isPending) return;
setLabel(episodeLabel);
mutate({ scope: "episode", ids: [episodeId] });
}
const pendingId = isPending ? (variables?.ids?.[0] ?? null) : null;