fix(web): only announce a state change after the server confirms it
The 'Marked watched' / 'Hidden' notices (and resolving a stale notice on unwatch/unhide) fired synchronously, before the api.setState call resolved. When the write failed — e.g. the API was unreachable — the optimistic card override was rolled back in .catch, but the notice had already been emitted and lingered, falsely claiming a change that never persisted. Move all three branches into the .then() so the notice is produced only once the server has actually applied the change; on failure the card reverts and nothing is announced (the connection-lost status already explains why).
This commit is contained in:
parent
0ab6742b44
commit
9f9d2544ef
1 changed files with 36 additions and 30 deletions
|
|
@ -144,18 +144,14 @@ export default function Feed({
|
|||
(id: string, status: string) => {
|
||||
setOverrides((o) => ({ ...o, [id]: status }));
|
||||
// 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
|
||||
.setState(id, status)
|
||||
.then(() => qc.invalidateQueries({ queryKey: ["feed"] }))
|
||||
.catch(() =>
|
||||
// Server rejected the change — drop the optimistic override so the card
|
||||
// reverts to the real (unchanged) state instead of staying phantom-hidden.
|
||||
setOverrides((o) => {
|
||||
const next = { ...o };
|
||||
delete next[id];
|
||||
return next;
|
||||
})
|
||||
);
|
||||
.then(() => {
|
||||
qc.invalidateQueries({ queryKey: ["feed"] });
|
||||
if (status === "hidden") {
|
||||
const v = loadedRef.current.find((x) => x.id === id);
|
||||
notify({
|
||||
|
|
@ -181,10 +177,20 @@ export default function Feed({
|
|||
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.
|
||||
// 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(() =>
|
||||
// Server rejected the change — drop the optimistic override so the card
|
||||
// reverts to the real (unchanged) state instead of staying phantom-hidden.
|
||||
setOverrides((o) => {
|
||||
const next = { ...o };
|
||||
delete next[id];
|
||||
return next;
|
||||
})
|
||||
);
|
||||
},
|
||||
[qc]
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue