mirror of https://github.com/buster-so/buster.git
85 lines
2.5 KiB
TypeScript
85 lines
2.5 KiB
TypeScript
import type { User } from '@supabase/supabase-js';
|
|
import React, { useRef, useState } from 'react';
|
|
import { createContext, useContextSelector } from 'use-context-selector';
|
|
import { useMount } from '@/hooks/useMount';
|
|
import { getBrowserClient } from '@/integrations/supabase/client';
|
|
|
|
export type SupabaseContextType = {
|
|
user: {
|
|
id: string;
|
|
is_anonymous: boolean;
|
|
email: string;
|
|
identities: User['identities'];
|
|
app_metadata: User['app_metadata'];
|
|
};
|
|
accessToken: string;
|
|
};
|
|
|
|
const supabase = getBrowserClient();
|
|
const fiveMinutes = 5 * 60 * 1000;
|
|
|
|
const useSupabaseContextInternal = ({
|
|
user,
|
|
accessToken: accessTokenProp,
|
|
}: SupabaseContextType) => {
|
|
const refreshTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
|
|
const [supabaseUser, setSupabaseUser] = useState<Pick<
|
|
User,
|
|
'id' | 'is_anonymous' | 'email' | 'identities' | 'app_metadata'
|
|
> | null>(user);
|
|
const [accessToken, setAccessToken] = useState(accessTokenProp);
|
|
|
|
const isAnonymousUser: boolean = !user?.id || user?.is_anonymous === true;
|
|
|
|
useMount(() => {
|
|
const {
|
|
data: { subscription },
|
|
} = supabase.auth.onAuthStateChange((_event, session) => {
|
|
const user = session?.user ?? null;
|
|
const expiresAt = session?.expires_at ?? 0;
|
|
const timerMs = expiresAt - fiveMinutes;
|
|
const accessToken = session?.access_token ?? '';
|
|
|
|
setSupabaseUser(user);
|
|
|
|
if (accessToken) setAccessToken(accessToken);
|
|
|
|
if (refreshTimerRef.current) {
|
|
clearTimeout(refreshTimerRef.current);
|
|
}
|
|
|
|
refreshTimerRef.current = setTimeout(() => {
|
|
supabase.auth.refreshSession();
|
|
}, timerMs);
|
|
});
|
|
|
|
return () => {
|
|
subscription.unsubscribe();
|
|
if (refreshTimerRef.current) {
|
|
clearTimeout(refreshTimerRef.current);
|
|
}
|
|
};
|
|
});
|
|
|
|
return {
|
|
supabaseUser,
|
|
isAnonymousUser,
|
|
accessToken,
|
|
};
|
|
};
|
|
|
|
export const SupabaseContext = createContext<ReturnType<typeof useSupabaseContextInternal>>({
|
|
isAnonymousUser: true,
|
|
} as ReturnType<typeof useSupabaseContextInternal>);
|
|
|
|
export const SupabaseContextProvider: React.FC<
|
|
SupabaseContextType & { children: React.ReactNode }
|
|
> = React.memo(({ user, accessToken, children }) => {
|
|
const value = useSupabaseContextInternal({ user, accessToken });
|
|
|
|
return <SupabaseContext.Provider value={value}>{children}</SupabaseContext.Provider>;
|
|
});
|
|
SupabaseContextProvider.displayName = 'SupabaseContextProvider';
|
|
|
|
export type SupabaseContextReturnType = ReturnType<typeof useSupabaseContextInternal>;
|