diff --git a/src/games/clairobscur/data/collected-items.ts b/src/games/clairobscur/data/collected-items.ts
index 5bc776f..a0a19f3 100644
--- a/src/games/clairobscur/data/collected-items.ts
+++ b/src/games/clairobscur/data/collected-items.ts
@@ -85,7 +85,10 @@ const useCollect = () => {
payload: { itemId: input.itemId, itemName: input.itemName },
idempotencyKey: `${ENTITY}:upsert:${anonUserId}:${input.itemId}`,
serverUpdatedAt: toIso(existing?.updatedAt),
- summary: { title: `Collected: ${input.itemName}` },
+ summary: {
+ title: `Collected: ${input.itemName}`,
+ gameId: "clairobscur",
+ },
}),
]);
return record;
@@ -123,7 +126,10 @@ const useUncollect = () => {
payload: { itemId: input.itemId, itemName: input.itemName },
idempotencyKey: `${ENTITY}:delete:${anonUserId}:${input.itemId}`,
serverUpdatedAt: toIso(existing?.updatedAt),
- summary: { title: `Uncollected: ${input.itemName}` },
+ summary: {
+ title: `Uncollected: ${input.itemName}`,
+ gameId: "clairobscur",
+ },
}),
]);
return { ok: true as const };
diff --git a/src/games/remnant2/data/collected-items/use-collected-items.ts b/src/games/remnant2/data/collected-items/use-collected-items.ts
index b83cb41..9bdc5ab 100644
--- a/src/games/remnant2/data/collected-items/use-collected-items.ts
+++ b/src/games/remnant2/data/collected-items/use-collected-items.ts
@@ -85,7 +85,10 @@ const useCollect = () => {
payload: { itemId: input.itemId, itemName: input.itemName },
idempotencyKey: `${ENTITY}:upsert:${anonUserId}:${input.itemId}`,
serverUpdatedAt: toIso(existing?.updatedAt),
- summary: { title: `Collected: ${input.itemName}` },
+ summary: {
+ title: `Collected: ${input.itemName}`,
+ gameId: "remnant2",
+ },
}),
]);
return record;
@@ -123,7 +126,10 @@ const useUncollect = () => {
payload: { itemId: input.itemId, itemName: input.itemName },
idempotencyKey: `${ENTITY}:delete:${anonUserId}:${input.itemId}`,
serverUpdatedAt: toIso(existing?.updatedAt),
- summary: { title: `Uncollected: ${input.itemName}` },
+ summary: {
+ title: `Uncollected: ${input.itemName}`,
+ gameId: "remnant2",
+ },
}),
]);
return { ok: true as const };
diff --git a/src/games/remnant2/data/created-builds/use-created-builds.ts b/src/games/remnant2/data/created-builds/use-created-builds.ts
index 85ff563..a3ff711 100644
--- a/src/games/remnant2/data/created-builds/use-created-builds.ts
+++ b/src/games/remnant2/data/created-builds/use-created-builds.ts
@@ -106,6 +106,7 @@ const useUpdate = () => {
title: input.name
? `Updated build: ${input.name}`
: "Updated build",
+ gameId: "remnant2",
},
}),
]);
@@ -140,7 +141,7 @@ const useRemove = () => {
payload: input,
idempotencyKey: `${ENTITY}:delete:${anonUserId}:${input.buildId}`,
serverUpdatedAt: toIso(existing?.updatedAt),
- summary: { title: "Deleted build" },
+ summary: { title: "Deleted build", gameId: "remnant2" },
}),
]);
return { ok: true as const };
diff --git a/src/games/slaythespire2/data/collected-items.ts b/src/games/slaythespire2/data/collected-items.ts
index 04e10bb..13ebec5 100644
--- a/src/games/slaythespire2/data/collected-items.ts
+++ b/src/games/slaythespire2/data/collected-items.ts
@@ -85,7 +85,10 @@ const useCollect = () => {
payload: { itemId: input.itemId, itemName: input.itemName },
idempotencyKey: `${ENTITY}:upsert:${anonUserId}:${input.itemId}`,
serverUpdatedAt: toIso(existing?.updatedAt),
- summary: { title: `Collected: ${input.itemName}` },
+ summary: {
+ title: `Collected: ${input.itemName}`,
+ gameId: "slaythespire2",
+ },
}),
]);
return record;
@@ -123,7 +126,10 @@ const useUncollect = () => {
payload: { itemId: input.itemId, itemName: input.itemName },
idempotencyKey: `${ENTITY}:delete:${anonUserId}:${input.itemId}`,
serverUpdatedAt: toIso(existing?.updatedAt),
- summary: { title: `Uncollected: ${input.itemName}` },
+ summary: {
+ title: `Uncollected: ${input.itemName}`,
+ gameId: "slaythespire2",
+ },
}),
]);
return { ok: true as const };
diff --git a/src/routes/account/profile/$userId/data-sync.tsx b/src/routes/account/profile/$userId/data-sync.tsx
index 3cc24e8..af17b7d 100644
--- a/src/routes/account/profile/$userId/data-sync.tsx
+++ b/src/routes/account/profile/$userId/data-sync.tsx
@@ -13,10 +13,8 @@ import { notifications } from "@mantine/notifications";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { createFileRoute } from "@tanstack/react-router";
import { type PropsWithChildren, useEffect, useState } from "react";
-import {
- clearSynced,
- deleteOp,
-} from "#/features/sync/local-data/queue/pending-ops";
+import { useGameId } from "#/features/game/use-game-id.ts";
+import { deleteOp } from "#/features/sync/local-data/queue/pending-ops";
import type { PendingOp } from "#/features/sync/local-data/queue/types";
import { usePendingOps } from "#/features/sync/local-data/queue/use-pending-ops";
import {
@@ -27,8 +25,8 @@ import {
buildTabHead,
loadProfileTabData,
} from "#/features/user/profile-tab-head.ts";
-import { getGameMetadata } from "#/registry/game-public-registry.tsx";
import { useSession } from "#/integrations/better-auth/auth-client";
+import { getGameMetadata } from "#/registry/game-public-registry.tsx";
const PendingList = ({
ops,
@@ -243,10 +241,19 @@ function DataSync() {
const pending = usePendingOps();
const canSync = !!session?.user?.id && online;
+ // Scope the tab to the active game. Ops with no `summary.gameId` are
+ // account-wide (profile, primary avatar) and stay visible under every game.
+ const gameId = useGameId();
+ const visibleOps = (pending.data ?? []).filter(
+ (op) => op.summary?.gameId == null || op.summary.gameId === gameId,
+ );
+ const pendingOps = visibleOps.filter((op) => op.status !== "synced");
+ const syncedOps = visibleOps.filter((op) => op.status === "synced");
+
const syncAll = useMutation({
mutationFn: async () => {
- if (!pending.data) return null;
- return syncOps(pending.data);
+ if (!visibleOps.length) return null;
+ return syncOps(visibleOps);
},
onSuccess: (report) => {
if (!report) return;
@@ -269,7 +276,9 @@ function DataSync() {
});
const clear = useMutation({
- mutationFn: () => clearSynced(),
+ mutationFn: async () => {
+ await Promise.all(syncedOps.map((op) => deleteOp(op.id)));
+ },
onSuccess: () =>
queryClient.invalidateQueries({ queryKey: ["sync-queue"] }),
});
@@ -321,14 +330,14 @@ function DataSync() {
size="xs"
variant="default"
onClick={() => clear.mutate()}
- disabled={clear.isPending}
+ disabled={clear.isPending || !syncedOps.length}
>
Clear synced
@@ -340,7 +349,7 @@ function DataSync() {
) : null}
op.status !== "synced")}
+ ops={pendingOps}
onDelete={(id) => {
deleteOp(id).then(() =>
queryClient.invalidateQueries({ queryKey: ["sync-queue"] }),
@@ -357,9 +366,7 @@ function DataSync() {
: null
}
/>
- op.status === "synced")}
- />
+
);
}