This repository has no description
1'use client';
2
3import { createContext, useContext, ReactNode, useEffect } from 'react';
4import { useQuery, useQueryClient } from '@tanstack/react-query';
5import { useRouter } from 'next/navigation';
6import type { GetProfileResponse } from '@/api-client/ApiClient';
7import { ClientCookieAuthService } from '@/services/auth/CookieAuthService.client';
8import { verifySessionOnClient } from '@/lib/auth/dal';
9import { usePathname } from 'next/navigation';
10import posthog from 'posthog-js';
11import { isInternalUser, isEarlyTester } from '@/lib/userLists';
12import { shouldCaptureAnalytics } from '@/features/analytics/utils';
13
14const ENABLE_AUTH_LOGGING = true;
15
16interface AuthContextType {
17 user: GetProfileResponse | null;
18 isAuthenticated: boolean;
19 isLoading: boolean;
20 refreshAuth: () => Promise<void>;
21 logout: () => Promise<void>;
22}
23
24const AuthContext = createContext<AuthContextType | undefined>(undefined);
25
26export const AuthProvider = ({ children }: { children: ReactNode }) => {
27 const router = useRouter();
28 const queryClient = useQueryClient();
29 const pathname = usePathname(); // to prevent redirecting to login on landing page
30
31 const refreshAuth = async () => {
32 await query.refetch();
33 };
34
35 const logout = async () => {
36 if (ENABLE_AUTH_LOGGING) {
37 console.log('[useAuth] Initiating logout process');
38 }
39
40 // Reset PostHog user identity
41 if (shouldCaptureAnalytics()) {
42 posthog.reset();
43 if (ENABLE_AUTH_LOGGING) {
44 console.log('[useAuth] PostHog user identity reset');
45 }
46 }
47
48 await ClientCookieAuthService.clearTokens();
49 queryClient.clear();
50 router.push('/login');
51 };
52
53 const query = useQuery<GetProfileResponse | null>({
54 queryKey: ['authenticated user'],
55 queryFn: async () => {
56 const session = await verifySessionOnClient();
57 return session;
58 },
59 staleTime: 5 * 60 * 1000, // cache for 5 minutes
60 refetchOnWindowFocus: false,
61 retry: false,
62 });
63
64 useEffect(() => {
65 // Handle other auth errors
66 if (query.isError && !query.isLoading && pathname !== '/') logout();
67 }, [query.data, query.isError, query.isLoading, pathname, router, logout]);
68
69 // Set super properties for anonymous tracking (no PII)
70 useEffect(() => {
71 const user = query.data;
72
73 // Set super properties when analytics is enabled and user is available
74 // These properties are included in all events automatically
75 if (shouldCaptureAnalytics() && user) {
76 posthog.register({
77 is_internal: isInternalUser(user.handle),
78 is_early_tester: isEarlyTester(user.handle),
79 });
80 }
81 }, [query.data]);
82
83 const contextValue: AuthContextType = {
84 user: query.data ?? null,
85 isAuthenticated: !!query.data,
86 isLoading: query.isLoading,
87 refreshAuth,
88 logout,
89 };
90
91 return (
92 <AuthContext.Provider value={contextValue}>{children}</AuthContext.Provider>
93 );
94};
95
96export const useAuth = (): AuthContextType => {
97 const context = useContext(AuthContext);
98 if (!context) {
99 throw new Error('useAuth must be used within an AuthProvider');
100 }
101 return context;
102};