mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-10-15 23:55:43 -04:00
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:
2 files changed
+15
-10
No files matched your search
@@ -116,7 +116,7 @@ export function ContinueWatchingCard({ item }: { item: ContinueWatchingItemProps
|
|||||||
size="icon"
|
size="icon"
|
||||||
aria-label={quickWatchLabel}
|
aria-label={quickWatchLabel}
|
||||||
disabled={pendingId === nextEpisode.id}
|
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={() =>
|
onClick={() =>
|
||||||
watchEpisode(
|
watchEpisode(
|
||||||
nextEpisode.id,
|
nextEpisode.id,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useLingui } from "@lingui/react/macro";
|
import { useLingui } from "@lingui/react/macro";
|
||||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||||
|
import { useState } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
|
|
||||||
import { getErrorMessage } from "@/lib/error-messages";
|
import { getErrorMessage } from "@/lib/error-messages";
|
||||||
@@ -10,21 +11,25 @@ import { invalidateTrackingQueries } from "@/lib/orpc/invalidate";
|
|||||||
export function useQuickWatchEpisode() {
|
export function useQuickWatchEpisode() {
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const { mutate, variables, isPending } = useMutation(orpc.tracking.watch.mutationOptions());
|
const [label, setLabel] = useState("");
|
||||||
|
// Handlers live on the hook-level options so the mutation stays pending until
|
||||||
function watchEpisode(episodeId: string, label: string) {
|
// the tracking queries have refetched, which blocks duplicate clicks.
|
||||||
mutate(
|
const { mutate, variables, isPending } = useMutation(
|
||||||
{ scope: "episode", ids: [episodeId] },
|
orpc.tracking.watch.mutationOptions({
|
||||||
{
|
onSuccess: async () => {
|
||||||
onSuccess: () => {
|
|
||||||
toast.success(t`Marked ${label} as watched`);
|
toast.success(t`Marked ${label} as watched`);
|
||||||
void invalidateTrackingQueries(queryClient);
|
await invalidateTrackingQueries(queryClient);
|
||||||
},
|
},
|
||||||
onError: (err) => {
|
onError: (err) => {
|
||||||
toast.error(getErrorMessage(err, t`Failed to mark episode`));
|
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;
|
const pendingId = isPending ? (variables?.ids?.[0] ?? null) : null;
|
||||||
|
|||||||
Reference in new issue
Block a user