Преглед изворни кода

fix: align query keys and realtime cache shape with useInfiniteQuery

useToggleWatched, useDeleteMovie, and useRealtimeMovies were using
["movies", groupId] while useGroupMovies uses ["group-movies", groupId],
causing cache invalidation and realtime updates to silently fail.
Also rewrites realtime setQueryData to operate on InfiniteData<MovieRow[]>.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
User пре 2 месеци
родитељ
комит
6ed09fd3bb
3 измењених фајлова са 30 додато и 15 уклоњено
  1. 1 1
      src/hooks/use-delete-movie.ts
  2. 28 13
      src/hooks/use-realtime-movies.ts
  3. 1 1
      src/hooks/use-toggle-watched.ts

+ 1 - 1
src/hooks/use-delete-movie.ts

@@ -21,7 +21,7 @@ export function useDeleteMovie(groupId: string) {
   return useMutation({
     mutationFn: deleteMovie,
     onSuccess: () => {
-      void queryClient.invalidateQueries({ queryKey: ["movies", groupId] });
+      void queryClient.invalidateQueries({ queryKey: ["group-movies", groupId] });
     },
   });
 }

+ 28 - 13
src/hooks/use-realtime-movies.ts

@@ -2,7 +2,7 @@
 
 import { useCallback } from "react";
 import type { RealtimePostgresChangesPayload } from "@supabase/supabase-js";
-import { useQueryClient } from "@tanstack/react-query";
+import { useQueryClient, type InfiniteData } from "@tanstack/react-query";
 import type { Database } from "@/types/database";
 import { useRealtimeChannel } from "./use-realtime-channel";
 import { buildEqFilter } from "@/lib/realtime/subscription-manager";
@@ -10,7 +10,7 @@ import { buildEqFilter } from "@/lib/realtime/subscription-manager";
 type MovieRow = Database["public"]["Tables"]["movies"]["Row"];
 
 function moviesQueryKey(groupId: string): readonly [string, string] {
-  return ["movies", groupId] as const;
+  return ["group-movies", groupId] as const;
 }
 
 /**
@@ -29,24 +29,39 @@ export function useRealtimeMovies(groupId: string | null) {
 
       if (payload.eventType === "INSERT") {
         const newMovie = payload.new;
-        queryClient.setQueryData<MovieRow[]>(key, (old) => {
-          if (!old) return [newMovie];
-          // Avoid duplicates (e.g., if the local optimistic update already added it)
-          if (old.some((m) => m.id === newMovie.id)) return old;
-          return [...old, newMovie];
+        queryClient.setQueryData<InfiniteData<MovieRow[]>>(key, (old) => {
+          if (!old) return undefined;
+          // Avoid duplicates across all pages
+          if (old.pages.some((page) => page.some((m) => m.id === newMovie.id)))
+            return old;
+          // Prepend to first page (ordered by added_at DESC)
+          return {
+            pages: [[newMovie, ...old.pages[0]], ...old.pages.slice(1)],
+            pageParams: old.pageParams,
+          };
         });
       } else if (payload.eventType === "UPDATE") {
         const updated = payload.new;
-        queryClient.setQueryData<MovieRow[]>(key, (old) => {
-          if (!old) return old;
-          return old.map((m) => (m.id === updated.id ? updated : m));
+        queryClient.setQueryData<InfiniteData<MovieRow[]>>(key, (old) => {
+          if (!old) return undefined;
+          return {
+            pages: old.pages.map((page) =>
+              page.map((m) => (m.id === updated.id ? updated : m)),
+            ),
+            pageParams: old.pageParams,
+          };
         });
       } else if (payload.eventType === "DELETE") {
         const deleted = payload.old;
         if (deleted && "id" in deleted) {
-          queryClient.setQueryData<MovieRow[]>(key, (old) => {
-            if (!old) return old;
-            return old.filter((m) => m.id !== deleted.id);
+          queryClient.setQueryData<InfiniteData<MovieRow[]>>(key, (old) => {
+            if (!old) return undefined;
+            return {
+              pages: old.pages.map((page) =>
+                page.filter((m) => m.id !== deleted.id),
+              ),
+              pageParams: old.pageParams,
+            };
           });
         }
       }

+ 1 - 1
src/hooks/use-toggle-watched.ts

@@ -28,7 +28,7 @@ export function useToggleWatched(groupId: string) {
   return useMutation({
     mutationFn: toggleWatched,
     onSuccess: () => {
-      void queryClient.invalidateQueries({ queryKey: ["movies", groupId] });
+      void queryClient.invalidateQueries({ queryKey: ["group-movies", groupId] });
     },
   });
 }