This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

semble / src / webapp / features / cards / lib / mutations / useUpdateCardAssociations.tsx
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}