fix(reminders): make cancel optimistic, no contradictory error

The shared account-data store removes optimistically with no rollback, so the
reminder row vanished the instant Cancel was clicked. Showing a "could not
cancel" error beside the already-gone row (and it reappearing on next sync) was
self-contradictory. Match the removeBookmark convention: fire-and-forget
optimistic removal, no inline error. Drops the now-moot cancelling busy-guard
and uses a collision-safe React key for same-minute custom reminders.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-10 15:56:22 -04:00
co-authored by Claude Opus 4.8
parent 7d67cdeef0
commit 4a3a80df9f
@@ -62,7 +62,6 @@ export function RemindMeDialog({ roomId, eventId, previewText, onClose }: Remind
const [busy, setBusy] = useState(false);
const [error, setError] = useState<string | null>(null);
const [customOpen, setCustomOpen] = useState(false);
const [cancelling, setCancelling] = useState<Set<number>>(new Set());
const def = useMemo(() => defaultCustomDate(), []);
const [dateValue, setDateValue] = useState(() => toLocalDate(def));
const [timeValue, setTimeValue] = useState(() => toLocalTime(def));
@@ -83,21 +82,13 @@ export function RemindMeDialog({ roomId, eventId, previewText, onClose }: Remind
if (customOpen) dateInputRef.current?.focus();
}, [customOpen]);
const handleCancelExisting = async (timestamp: number) => {
if (cancelling.has(timestamp)) return;
setCancelling((prev) => new Set(prev).add(timestamp));
setError(null);
try {
await removeReminder(eventId, timestamp);
} catch {
setError('Could not cancel reminder. Try again.');
} finally {
setCancelling((prev) => {
const next = new Set(prev);
next.delete(timestamp);
return next;
});
}
const handleCancelExisting = (timestamp: number) => {
// Optimistic, matching removeBookmark: the shared account-data store drops
// the reminder locally at once (no rollback) and re-syncs from the server.
// We deliberately show no inline error — the store has no rollback path, so a
// failed write simply reappears on the next sync rather than leaving a stale
// "couldn't cancel" message beside an already-vanished row.
removeReminder(eventId, timestamp).catch(() => undefined);
};
const commit = async (timestamp: number) => {
@@ -191,8 +182,10 @@ export function RemindMeDialog({ roomId, eventId, previewText, onClose }: Remind
<Text size="L400" priority="300" style={{ paddingLeft: config.space.S200 }}>
{existing.length === 1 ? 'Reminder set' : 'Reminders set'}
</Text>
{existing.map((r) => (
<Box key={r.timestamp} alignItems="Center" gap="200">
{existing.map((r, idx) => (
// Composite key: two custom reminders on one message can share
// a minute-precision timestamp; index keeps React keys unique.
<Box key={`${r.timestamp}-${idx}`} alignItems="Center" gap="200">
<Icon src={Icons.Clock} size="100" style={{ flexShrink: 0 }} />
<Text size="T200" style={{ flexGrow: 1, minWidth: 0 }} truncate>
{formatFriendlyDateTime(r.timestamp)}
@@ -202,7 +195,6 @@ export function RemindMeDialog({ roomId, eventId, previewText, onClose }: Remind
radii="300"
variant="SurfaceVariant"
fill="None"
disabled={cancelling.has(r.timestamp)}
onClick={() => handleCancelExisting(r.timestamp)}
aria-label={`Cancel reminder for ${formatFriendlyDateTime(r.timestamp)}`}
>