From 72c48253339801fa2f7d38b5cd00316866608b17 Mon Sep 17 00:00:00 2001 From: Thomas Hallock Date: Wed, 14 Jan 2026 17:35:22 -0600 Subject: [PATCH] feat(players): add optimistic update for listWithSkillData When creating a new player, optimistically update both the player list and the listWithSkillData query (used by /practice page). This makes new players appear immediately without requiring a page reload. Co-Authored-By: Claude Opus 4.5 --- apps/web/src/hooks/useUserPlayers.ts | 58 ++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/apps/web/src/hooks/useUserPlayers.ts b/apps/web/src/hooks/useUserPlayers.ts index 9c3c5510..421a21b5 100644 --- a/apps/web/src/hooks/useUserPlayers.ts +++ b/apps/web/src/hooks/useUserPlayers.ts @@ -141,38 +141,64 @@ export function useCreatePlayer() { return useMutation({ mutationFn: createPlayer, onMutate: async (newPlayer) => { - // Cancel outgoing refetches - await queryClient.cancelQueries({ queryKey: playerKeys.lists() }) + // Cancel outgoing refetches for all player queries + await queryClient.cancelQueries({ queryKey: playerKeys.all }) - // Snapshot previous value + // Snapshot previous values const previousPlayers = queryClient.getQueryData(playerKeys.list()) + const previousPlayersWithSkillData = queryClient.getQueryData( + playerKeys.listWithSkillData() + ) - // Optimistically update to new value + // Create optimistic player + const optimisticPlayer: Player = { + id: `temp-${Date.now()}`, // Temporary ID + ...newPlayer, + createdAt: new Date(), + isActive: newPlayer.isActive ?? false, + isArchived: false, + userId: 'temp-user', // Temporary userId, will be replaced by server response + helpSettings: null, // Will be set by server with default values + notes: null, + familyCode: null, // Will be generated by server + } + + // Optimistically update player list if (previousPlayers) { - const optimisticPlayer: Player = { - id: `temp-${Date.now()}`, // Temporary ID - ...newPlayer, - createdAt: new Date(), - isActive: newPlayer.isActive ?? false, - isArchived: false, - userId: 'temp-user', // Temporary userId, will be replaced by server response - helpSettings: null, // Will be set by server with default values - notes: null, - familyCode: null, // Will be generated by server - } queryClient.setQueryData(playerKeys.list(), [ ...previousPlayers, optimisticPlayer, ]) } - return { previousPlayers } + // Optimistically update players with skill data (used by practice page) + if (previousPlayersWithSkillData) { + const optimisticPlayerWithSkillData: StudentWithSkillData = { + ...optimisticPlayer, + practicingSkills: [], + lastPracticedAt: null, + skillCategory: null, + intervention: null, + } + queryClient.setQueryData(playerKeys.listWithSkillData(), [ + ...previousPlayersWithSkillData, + optimisticPlayerWithSkillData, + ]) + } + + return { previousPlayers, previousPlayersWithSkillData } }, onError: (_err, _newPlayer, context) => { // Rollback on error if (context?.previousPlayers) { queryClient.setQueryData(playerKeys.list(), context.previousPlayers) } + if (context?.previousPlayersWithSkillData) { + queryClient.setQueryData( + playerKeys.listWithSkillData(), + context.previousPlayersWithSkillData + ) + } }, onSettled: () => { // Always refetch after error or success