eletrotupi / tcc/ frontend/hooks/useSleepRecord.queries.ts80d91bc2ac14c41ba7e7ed6b4640d9d958a3b41f
3.4 KB | 116 lines Raw
1
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
2

3
import { apiClient, SleepRecord, SleepRecordPayload } from "@/lib/api";
4
import { insightKeys } from "./useInsights.queries";
5

6
export const sleepRecordKeys = {
7
  all: () => ["sleep-records"] as const,
8
  lists: () => [...sleepRecordKeys.all(), "list"] as const,
9
  list: (filters?: SleepRecordFilters) =>
10
    [...sleepRecordKeys.lists(), filters] as const,
11
  detail: (id: string) => [...sleepRecordKeys.all(), "detail", id] as const,
12
};
13

14
interface SleepRecordFilters {
15
  from?: string; // ISO date
16
  to?: string; // ISO date
17
  limit?: number;
18
}
19

20
export const useSleepRecords = (filters?: SleepRecordFilters) => {
21
  return useQuery({
22
    queryKey: sleepRecordKeys.list(filters),
23
    queryFn: () => apiClient.getSleepRecords(filters),
24
  });
25
};
26

27
// Single entry detail
28
export const useSleepRecord = (id: string) => {
29
  return useQuery({
30
    queryKey: sleepRecordKeys.detail(id),
31
    queryFn: () => apiClient.getSleepRecord(id),
32
    enabled: !!id,
33
  });
34
};
35

36
export const useCreateSleepRecord = () => {
37
  const queryClient = useQueryClient();
38

39
  return useMutation({
40
    mutationFn: (payload: SleepRecordPayload) =>
41
      apiClient.createSleepRecord(payload),
42

43
    onMutate: async (payload) => {
44
      await queryClient.cancelQueries({ queryKey: sleepRecordKeys.lists() });
45

46
      const previous = queryClient.getQueryData(sleepRecordKeys.list());
47

48
      // TODO: might as well create a shared attrs that we're keeping it
49
      queryClient.setQueryData(
50
        sleepRecordKeys.list(),
51
        (old: SleepRecord[] = []) => [
52
          {
53
            ...payload,
54
            id: `temp-${Date.now()}`,
55
            createdAt: new Date().toISOString(),
56
            _optimistic: true,
57
          },
58
          ...old,
59
        ],
60
      );
61

62
      return { previous };
63
    },
64

65
    onError: (_err, _payload, context) => {
66
      if (context?.previous) {
67
        queryClient.setQueryData(sleepRecordKeys.list(), context.previous);
68
      }
69
    },
70

71
    onSuccess: () => {
72
      queryClient.invalidateQueries({ queryKey: sleepRecordKeys.lists() });
73

74
      // Invalidate insights, so we can force refresh
75
      setTimeout(() => {
76
        queryClient.invalidateQueries({ queryKey: insightKeys.byType("ENERGY_SLEEP_CORRELATION") });
77
        queryClient.invalidateQueries({ queryKey: insightKeys.byType("DAILY_SLEEP") });
78
      }, 2000);
79
    },
80
  });
81
};
82

83
// Delete a sleep record with optimistic removal
84
export const useDeleteSleepRecord = () => {
85
  const queryClient = useQueryClient();
86

87
  return useMutation({
88
    mutationFn: (id: string) => apiClient.deleteSleepRecord(id),
89

90
    onMutate: async (id) => {
91
      await queryClient.cancelQueries({ queryKey: sleepRecordKeys.lists() });
92
      const previous = queryClient.getQueryData(sleepRecordKeys.list());
93

94
      queryClient.setQueryData(
95
        sleepRecordKeys.list(),
96
        (old: SleepRecord[] = []) => old.filter((e) => e.id !== Number(id)),
97
      );
98

99
      return { previous };
100
    },
101

102
    onError: (_err, _id, context) => {
103
      if (context?.previous) {
104
        queryClient.setQueryData(sleepRecordKeys.list(), context.previous);
105
      }
106
    },
107

108
    onSuccess: () => {
109
      queryClient.invalidateQueries({ queryKey: sleepRecordKeys.lists() });
110
      setTimeout(() => {
111
        queryClient.invalidateQueries({ queryKey: insightKeys.byType("ENERGY_SLEEP_CORRELATION") });
112
        queryClient.invalidateQueries({ queryKey: insightKeys.byType("DAILY_SLEEP") });
113
      }, 2000);
114
    },
115
  });
116
};