This repository has no description
4.7 kB
139 lines
1import { createSembleClient } from '@/services/client.apiClient';
2import { useMutation, useQueryClient } from '@tanstack/react-query';
3import { cardKeys } from '../cardKeys';
4import { collectionKeys } from '@/features/collections/lib/collectionKeys';
5import { noteKeys } from '@/features/notes/lib/noteKeys';
6import { sembleKeys } from '@/features/semble/lib/sembleKeys';
7import { feedKeys } from '@/features/feeds/lib/feedKeys';
8import posthog from 'posthog-js';
9import {
10 CardSaveAnalyticsContext,
11 CardSaveEventProperties,
12} from '@/features/analytics/types';
13import { shouldCaptureAnalytics } from '@/features/analytics/utils';
14import { notifications } from '@mantine/notifications';
15import { BsCheck, BsExclamation } from 'react-icons/bs';
16
17export default function useUpdateCardAssociations(
18 analyticsContext?: CardSaveAnalyticsContext,
19) {
20 const client = createSembleClient();
21
22 const queryClient = useQueryClient();
23
24 const mutation = useMutation({
25 mutationFn: (updatedCard: {
26 cardId: string;
27 note?: string;
28 addToCollectionIds?: string[];
29 removeFromCollectionIds?: string[];
30 viaCardId?: string;
31 addToLibrary?: boolean;
32 notificationId?: string;
33 }) => {
34 return client.updateUrlCardAssociations({
35 cardId: updatedCard.cardId,
36 note: updatedCard.note,
37 addToCollections: updatedCard.addToCollectionIds,
38 removeFromCollections: updatedCard.removeFromCollectionIds,
39 viaCardId: updatedCard.viaCardId,
40 });
41 },
42
43 onSuccess: (_data, variables) => {
44 if (variables.notificationId) {
45 notifications.update({
46 id: variables.notificationId,
47 color: 'green',
48 title: 'Success!',
49 message: 'Card updated',
50 position: 'top-center',
51 loading: false,
52 autoClose: 2000,
53 icon: <BsCheck />,
54 });
55 }
56
57 queryClient.invalidateQueries({ queryKey: cardKeys.all() });
58 queryClient.invalidateQueries({ queryKey: noteKeys.all() });
59 queryClient.invalidateQueries({ queryKey: feedKeys.all() });
60 queryClient.invalidateQueries({ queryKey: sembleKeys.all() });
61 queryClient.invalidateQueries({ queryKey: collectionKeys.all() });
62 // Invalidate all URL metadata queries with stats to update tab counts
63 queryClient.invalidateQueries({
64 predicate: (query): boolean => {
65 const key = query.queryKey as unknown[];
66 return !!(
67 key[0] === 'cards' &&
68 key[1] === 'metadata' &&
69 key[3] &&
70 typeof key[3] === 'object' &&
71 'includeStats' in key[3] &&
72 key[3].includeStats === true
73 );
74 },
75 });
76
77 // invalidate each collection query individually
78 variables.addToCollectionIds?.forEach((id) => {
79 queryClient.invalidateQueries({
80 queryKey: collectionKeys.collection(id),
81 });
82 });
83
84 variables.removeFromCollectionIds?.forEach((id) => {
85 queryClient.invalidateQueries({
86 queryKey: collectionKeys.collection(id),
87 });
88 });
89
90 // Track card save event in PostHog (only when adding to library)
91 if (
92 shouldCaptureAnalytics() &&
93 analyticsContext &&
94 variables.addToLibrary
95 ) {
96 const eventProperties: CardSaveEventProperties = {
97 save_source: analyticsContext.saveSource,
98 is_new_card: false,
99 has_note: !!variables.note,
100 collection_count: variables.addToCollectionIds?.length || 0,
101 active_filters: analyticsContext.activeFilters
102 ? {
103 url_type: analyticsContext.activeFilters.urlType,
104 sort: analyticsContext.activeFilters.sort,
105 search_query: analyticsContext.activeFilters.searchQuery,
106 profile_filter: analyticsContext.activeFilters.profileFilter,
107 }
108 : undefined,
109 via_card_id: variables.viaCardId,
110 page_path: analyticsContext.pagePath,
111 };
112
113 posthog.capture('card_saved', eventProperties);
114
115 // Clear super properties after capture
116 posthog.unregister('original_save_source');
117 posthog.unregister('original_active_filters');
118 }
119 },
120
121 onError: (_error, variables) => {
122 if (variables.notificationId) {
123 notifications.update({
124 id: variables.notificationId,
125 color: 'red',
126 title: 'Error',
127 message: 'Could not update card',
128 position: 'top-center',
129 loading: false,
130 autoClose: false,
131 withCloseButton: true,
132 icon: <BsExclamation />,
133 });
134 }
135 },
136 });
137
138 return mutation;
139}