Merge bug/optimistic-state-notify-on-success: gate state-change notices on server confirmation
This commit is contained in:
commit
c0192b8bb7
1 changed files with 36 additions and 30 deletions
|
|
@ -144,9 +144,44 @@ export default function Feed({
|
||||||
(id: string, status: string) => {
|
(id: string, status: string) => {
|
||||||
setOverrides((o) => ({ ...o, [id]: status }));
|
setOverrides((o) => ({ ...o, [id]: status }));
|
||||||
// Refetch once the server has the change so other views (e.g. Hidden) are in sync.
|
// Refetch once the server has the change so other views (e.g. Hidden) are in sync.
|
||||||
|
// Announce the change only AFTER the server confirms it: a "Marked watched"/"Hidden"
|
||||||
|
// notice (or resolving a stale one) is a claim of success, so firing it optimistically
|
||||||
|
// would falsely report a change that the .catch below is about to roll back (e.g. when
|
||||||
|
// the API is unreachable).
|
||||||
api
|
api
|
||||||
.setState(id, status)
|
.setState(id, status)
|
||||||
.then(() => qc.invalidateQueries({ queryKey: ["feed"] }))
|
.then(() => {
|
||||||
|
qc.invalidateQueries({ queryKey: ["feed"] });
|
||||||
|
if (status === "hidden") {
|
||||||
|
const v = loadedRef.current.find((x) => x.id === id);
|
||||||
|
notify({
|
||||||
|
message: v?.title
|
||||||
|
? i18n.t("feed.hiddenNamed", { title: v.title })
|
||||||
|
: i18n.t("feed.hidden"),
|
||||||
|
action: { label: i18n.t("feed.undo"), onClick: () => onState(id, "new") },
|
||||||
|
meta: {
|
||||||
|
kind: "video-hidden",
|
||||||
|
videoId: id,
|
||||||
|
title: v?.title ?? "this video",
|
||||||
|
channelId: v?.channel_id ?? "",
|
||||||
|
channelName: v?.channel_title ?? "",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else if (status === "watched") {
|
||||||
|
const v = loadedRef.current.find((x) => x.id === id);
|
||||||
|
notify({
|
||||||
|
message: v?.title
|
||||||
|
? i18n.t("feed.markedWatchedNamed", { title: v.title })
|
||||||
|
: i18n.t("feed.markedWatched"),
|
||||||
|
action: { label: i18n.t("feed.unwatch"), onClick: () => onState(id, "new") },
|
||||||
|
meta: { kind: "video-watched", videoId: id, title: v?.title ?? "this video" },
|
||||||
|
});
|
||||||
|
} else if (status === "new") {
|
||||||
|
// Unhide / unwatch (from a card, the toast's Undo, or the center): quietly resolve
|
||||||
|
// any stale hide/watch notice for this video so it doesn't linger with a dead action.
|
||||||
|
resolveVideo(id);
|
||||||
|
}
|
||||||
|
})
|
||||||
.catch(() =>
|
.catch(() =>
|
||||||
// Server rejected the change — drop the optimistic override so the card
|
// Server rejected the change — drop the optimistic override so the card
|
||||||
// reverts to the real (unchanged) state instead of staying phantom-hidden.
|
// reverts to the real (unchanged) state instead of staying phantom-hidden.
|
||||||
|
|
@ -156,35 +191,6 @@ export default function Feed({
|
||||||
return next;
|
return next;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
if (status === "hidden") {
|
|
||||||
const v = loadedRef.current.find((x) => x.id === id);
|
|
||||||
notify({
|
|
||||||
message: v?.title
|
|
||||||
? i18n.t("feed.hiddenNamed", { title: v.title })
|
|
||||||
: i18n.t("feed.hidden"),
|
|
||||||
action: { label: i18n.t("feed.undo"), onClick: () => onState(id, "new") },
|
|
||||||
meta: {
|
|
||||||
kind: "video-hidden",
|
|
||||||
videoId: id,
|
|
||||||
title: v?.title ?? "this video",
|
|
||||||
channelId: v?.channel_id ?? "",
|
|
||||||
channelName: v?.channel_title ?? "",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else if (status === "watched") {
|
|
||||||
const v = loadedRef.current.find((x) => x.id === id);
|
|
||||||
notify({
|
|
||||||
message: v?.title
|
|
||||||
? i18n.t("feed.markedWatchedNamed", { title: v.title })
|
|
||||||
: i18n.t("feed.markedWatched"),
|
|
||||||
action: { label: i18n.t("feed.unwatch"), onClick: () => onState(id, "new") },
|
|
||||||
meta: { kind: "video-watched", videoId: id, title: v?.title ?? "this video" },
|
|
||||||
});
|
|
||||||
} else if (status === "new") {
|
|
||||||
// Unhide / unwatch (from a card, the toast's Undo, or the center): quietly resolve any
|
|
||||||
// stale hide/watch notice for this video so it doesn't linger with a dead action.
|
|
||||||
resolveVideo(id);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[qc]
|
[qc]
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue