mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-27 21:33:41 +02:00
* fix(notifications): make preference updates atomic Co-authored-by: multica-agent <github@multica.ai> * fix(notifications): serialize preference mutations Co-authored-by: multica-agent <github@multica.ai> --------- Co-authored-by: Lambda <lambda@multica.ai> Co-authored-by: multica-agent <github@multica.ai>
93 lines
2.2 KiB
TypeScript
93 lines
2.2 KiB
TypeScript
import type {
|
|
NotificationGroupKey,
|
|
NotificationGroupValue,
|
|
NotificationPreferences,
|
|
} from "../types";
|
|
|
|
const NOTIFICATION_GROUP_KEYS: readonly NotificationGroupKey[] = [
|
|
"assignments",
|
|
"status_changes",
|
|
"comments",
|
|
"updates",
|
|
"agent_activity",
|
|
"system_notifications",
|
|
];
|
|
|
|
function preferenceValue(
|
|
preferences: NotificationPreferences,
|
|
key: NotificationGroupKey,
|
|
): NotificationGroupValue {
|
|
return preferences[key] ?? "all";
|
|
}
|
|
|
|
/**
|
|
* Convert the full preference object produced by the settings UI into the
|
|
* smallest atomic patch. Missing keys mean the default value ("all").
|
|
*/
|
|
export function deriveNotificationPreferencePatch(
|
|
previous: NotificationPreferences,
|
|
next: NotificationPreferences,
|
|
): NotificationPreferences {
|
|
const patch: NotificationPreferences = {};
|
|
|
|
for (const key of NOTIFICATION_GROUP_KEYS) {
|
|
const previousValue = preferenceValue(previous, key);
|
|
const nextValue = preferenceValue(next, key);
|
|
if (previousValue !== nextValue) {
|
|
patch[key] = nextValue;
|
|
}
|
|
}
|
|
|
|
return patch;
|
|
}
|
|
|
|
/** Apply a preference patch while keeping default "all" values sparse. */
|
|
export function applyNotificationPreferencePatch(
|
|
current: NotificationPreferences,
|
|
patch: NotificationPreferences,
|
|
): NotificationPreferences {
|
|
const next = { ...current };
|
|
|
|
for (const key of NOTIFICATION_GROUP_KEYS) {
|
|
const value = patch[key];
|
|
if (value === "muted") {
|
|
next[key] = value;
|
|
} else if (value === "all") {
|
|
delete next[key];
|
|
}
|
|
}
|
|
|
|
return next;
|
|
}
|
|
|
|
/**
|
|
* Roll back only values that still match this mutation's optimistic patch.
|
|
* A later toggle that touched the same key wins.
|
|
*/
|
|
export function rollbackNotificationPreferencePatch(
|
|
current: NotificationPreferences,
|
|
patch: NotificationPreferences,
|
|
previous: NotificationPreferences,
|
|
): NotificationPreferences {
|
|
const next = { ...current };
|
|
|
|
for (const key of NOTIFICATION_GROUP_KEYS) {
|
|
const patchedValue = patch[key];
|
|
if (
|
|
patchedValue === undefined ||
|
|
preferenceValue(current, key) !== patchedValue
|
|
) {
|
|
continue;
|
|
}
|
|
|
|
const previousValue = preferenceValue(previous, key);
|
|
if (previousValue === "all") {
|
|
delete next[key];
|
|
} else {
|
|
next[key] = previousValue;
|
|
}
|
|
}
|
|
|
|
return next;
|
|
}
|