11'use client' ;
22
3- import { useEffect , useState , useRef } from 'react' ;
3+ import { useEffect } from 'react' ;
44import { useGlobalStore } from './store.provider' ;
5- import { useShallow } from 'zustand/react/shallow' ;
6- import { fetchAuth } from '@/services/apiClient' ;
7- import { toast } from 'sonner' ;
8- import { requireAuth } from '@/components/RequiresAuth' ;
9- import { AppState , Order } from './store ' ;
10- import QRCode from 'qrcode ' ;
5+ import {
6+ useUserData as useUserDataSWR ,
7+ useTickets as useTicketsSWR ,
8+ useFavorites as useFavoritesSWR
9+ } from '@/hooks/useServerData ' ;
10+ import { AppState } from './store ' ;
1111// import { useWalletManager } from '@/hooks/useWalletManager';
1212
13+ /**
14+ * Manage favorite events (now using SWR)
15+ * Returns: [favorites, updateFavorite]
16+ */
1317export const useFavorites = ( ) => {
14- const userData = useGlobalStore ( useShallow ( ( state ) => state . userData ) ) ;
15- const favorites =
16- useGlobalStore ( ( state ) => {
17- return state . userData ?. favorite_events ;
18- } ) || [ ] ;
19- const setFavoriteEvents = useGlobalStore ( ( state ) => state . setFavoriteEvents ) ;
20-
21- const updateFavorite = ( eventId : string ) => {
22- if ( ! userData ) {
23- requireAuth (
24- 'You need to be authenticated to add events to your favorites.'
25- ) ;
26- return ;
27- }
28-
29- const nextFavoriteEvents = favorites ?. includes ( eventId )
30- ? favorites ?. filter ( ( existingEvent : string ) => existingEvent !== eventId )
31- : [ ...( favorites || [ ] ) , eventId ] ;
32-
33- setFavoriteEvents ( nextFavoriteEvents ) ;
34-
35- fetchAuth ( '/api/auth/favorites' , {
36- method : 'POST' ,
37- body : JSON . stringify ( { favoriteEvents : nextFavoriteEvents } ) ,
38- } ) . then ( ( response ) => {
39- if ( ! response . success ) {
40- toast . error (
41- 'There was an error updating your favorites. Check your connection and try again.'
42- ) ;
43- }
44- } ) ;
45- } ;
46-
18+ const { favorites, updateFavorite } = useFavoritesSWR ( ) ;
4719 return [ favorites , updateFavorite ] as [ string [ ] , ( eventId : string ) => void ] ;
4820} ;
4921
22+ /**
23+ * Get additional ticket emails (now using SWR)
24+ */
5025export const useAdditionalTicketEmails = ( ) => {
51- const additionalTicketEmails = useGlobalStore (
52- useShallow ( ( state ) => state . userData ?. additional_ticket_emails )
53- ) ;
54-
55- return additionalTicketEmails || [ ] ;
26+ const { additionalTicketEmails } = useUserDataSWR ( ) ;
27+ return additionalTicketEmails ;
5628} ;
5729
5830export const useEvents = ( ) => {
5931 const events = useGlobalStore ( ( state ) => state . events ) ;
6032 return events || [ ] ;
6133} ;
6234
35+ /**
36+ * Manually fetch and update user data (for backward compatibility)
37+ * Note: Most code should use useUserData() hook instead
38+ */
6339export const ensureUserData = async (
6440 setUserData : ( userData : AppState [ 'userData' ] ) => void
6541) => {
42+ // Direct fetch for backward compatibility
43+ const { fetchAuth } = await import ( '@/services/apiClient' ) ;
6644 const userData = await fetchAuth ( '/api/auth/user-data' ) ;
6745
6846 if ( userData . success ) {
@@ -72,123 +50,48 @@ export const ensureUserData = async (
7250 }
7351} ;
7452
75- // Hook to ensure user data is loaded from supabase whenever connection status changes
76- export const useEnsureUserData = ( isConnected : boolean ) => {
53+ /**
54+ * Hook to ensure user data is loaded (now uses SWR, no manual refetching needed)
55+ * SWR automatically handles revalidation on focus and reconnect
56+ */
57+ export const useEnsureUserData = ( email : string | undefined ) => {
58+ // SWR handles all the caching and revalidation automatically
59+ // We just need to use the hook - it will fetch when email is available
60+ const { userData, refresh } = useUserDataSWR ( ) ;
61+
62+ // Optionally sync to Zustand for backward compatibility
7763 const setUserData = useGlobalStore ( ( state ) => state . setUserData ) ;
7864
7965 useEffect ( ( ) => {
80- if ( isConnected ) {
81- console . log ( 'ensuring user data' ) ;
82- ensureUserData ( setUserData ) ;
83- } else {
66+ if ( userData ) {
67+ setUserData ( userData ) ;
68+ } else if ( ! email ) {
8469 setUserData ( null ) ;
8570 }
86- } , [ isConnected ] ) ;
87-
88- // Ensure user data is loaded whenever the window is focused (for when user returns from background, in case user updated its data on different device)
89- useEffect ( ( ) => {
90- const handleFocus = ( ) => {
91- if ( isConnected ) {
92- ensureUserData ( setUserData ) ;
93- }
94- } ;
95-
96- window . addEventListener ( 'focus' , handleFocus ) ;
97- return ( ) => window . removeEventListener ( 'focus' , handleFocus ) ;
98- } , [ isConnected , setUserData ] ) ;
71+ } , [ userData , email , setUserData ] ) ;
9972} ;
10073
101- // Fetch tickets and generate QR codes
102- export const fetchTickets = async (
103- setTickets : ( tickets : Order [ ] | null ) => void ,
104- setTicketsLoading : ( loading : boolean ) => void ,
105- setQrCodes : ( qrCodes : { [ key : string ] : string } ) => void
106- ) => {
107- setTicketsLoading ( true ) ;
108-
109- try {
110- const response = await fetchAuth < { tickets : Order [ ] } > ( '/api/auth/tickets' ) ;
111-
112- if ( ! response . success ) {
113- throw new Error ( response . error || 'Failed to fetch tickets' ) ;
114- }
115-
116- const orderData = response . data . tickets || [ ] ;
117- setTickets ( orderData ) ;
118-
119- // Generate QR codes for each ticket
120- const newQrCodes : { [ key : string ] : string } = { } ;
121- for ( const order of orderData ) {
122- for ( const ticket of order . tickets ) {
123- if ( ticket . secret ) {
124- try {
125- const qrDataUrl = await QRCode . toDataURL ( ticket . secret , {
126- width : 200 ,
127- margin : 1 ,
128- color : {
129- dark : '#000000' ,
130- light : '#FFFFFF' ,
131- } ,
132- } ) ;
133- newQrCodes [ ticket . secret ] = qrDataUrl ;
134-
135- if ( ticket . addons ) {
136- for ( const addon of ticket . addons ) {
137- const qrDataUrl = await QRCode . toDataURL ( addon . secret , {
138- width : 200 ,
139- margin : 1 ,
140- } ) ;
141- newQrCodes [ addon . secret ] = qrDataUrl ;
142- }
143- }
144- } catch ( qrErr ) {
145- console . error ( 'Error generating QR code:' , qrErr ) ;
146- }
147- }
148- }
149- }
150- setQrCodes ( newQrCodes ) ;
151- } catch ( err ) {
152- console . error ( 'Error fetching tickets:' , err ) ;
153- toast . error ( err instanceof Error ? err . message : 'Failed to load tickets' ) ;
154- } finally {
155- setTicketsLoading ( false ) ;
156- }
157- } ;
158-
159- // Hook to fetch and manage tickets
74+ /**
75+ * Hook to fetch and manage tickets (now using SWR)
76+ * SWR automatically handles caching, deduplication, and revalidation
77+ */
16078export const useTickets = ( ) => {
161- const additionalTicketEmails = useAdditionalTicketEmails ( ) ;
162- const email = useGlobalStore ( ( state ) => state . userData ?. email ) ;
163- const tickets = useGlobalStore ( ( state ) => state . tickets ) ;
164- const ticketsLoading = useGlobalStore ( ( state ) => state . ticketsLoading ) ;
165- const qrCodes = useGlobalStore ( ( state ) => state . qrCodes ) ;
79+ const { tickets, qrCodes, loading, refresh } = useTicketsSWR ( ) ;
80+
81+ // Optionally sync to Zustand for backward compatibility
16682 const setTickets = useGlobalStore ( ( state ) => state . setTickets ) ;
167- const setTicketsLoading = useGlobalStore ( ( state ) => state . setTicketsLoading ) ;
16883 const setQrCodes = useGlobalStore ( ( state ) => state . setQrCodes ) ;
169- const isLoadingRef = useRef ( false ) ;
170-
171- const refresh = async ( ) => {
172- if ( isLoadingRef . current ) {
173- console . log ( 'Already fetching tickets, skipping...' ) ;
174- return ;
175- }
176-
177- isLoadingRef . current = true ;
178- await fetchTickets ( setTickets , setTicketsLoading , setQrCodes ) ;
179- isLoadingRef . current = false ;
180- } ;
84+ const setTicketsLoading = useGlobalStore ( ( state ) => state . setTicketsLoading ) ;
18185
182- // Auto-fetch tickets when email is available
18386 useEffect ( ( ) => {
184- if ( email ) {
185- refresh ( ) ;
186- }
187- } , [ email , additionalTicketEmails ] ) ;
87+ setTickets ( tickets ) ;
88+ setQrCodes ( qrCodes ) ;
89+ setTicketsLoading ( loading ) ;
90+ } , [ tickets , qrCodes , loading , setTickets , setQrCodes , setTicketsLoading ] ) ;
18891
18992 return {
190- tickets : tickets || [ ] ,
191- loading : ticketsLoading ,
93+ tickets,
94+ loading,
19295 qrCodes,
19396 refresh,
19497 } ;
0 commit comments