build ok,

This commit is contained in:
louiscklaw
2025-04-14 09:26:24 +08:00
commit 6c931c1fe8
770 changed files with 63959 additions and 0 deletions

View File

@@ -0,0 +1,37 @@
'use client';
import * as React from 'react';
import { UserProvider as Auth0UserProvider, useUser } from '@auth0/nextjs-auth0/client';
import type { User } from '@/types/user';
import { paths } from '@/paths';
import type { UserContextValue } from '../types';
export const UserContext = React.createContext<UserContextValue | undefined>(undefined);
export interface UserProviderProps {
children: React.ReactNode;
}
function UserProviderImpl({ children }: UserProviderProps): React.JSX.Element {
const { user, error, isLoading, checkSession } = useUser();
return (
<UserContext.Provider
value={{ user: user ? (user as User) : null, error: error ? error.message : null, isLoading, checkSession }}
>
{children}
</UserContext.Provider>
);
}
export function UserProvider({ children }: UserProviderProps): React.JSX.Element {
return (
<Auth0UserProvider loginUrl={paths.auth.auth0.signIn} profileUrl={paths.auth.auth0.profile}>
<UserProviderImpl>{children}</UserProviderImpl>
</Auth0UserProvider>
);
}
export const UserConsumer = UserContext.Consumer;

View File

@@ -0,0 +1,77 @@
'use client';
import * as React from 'react';
import { Hub } from 'aws-amplify/utils';
import type { User } from '@/types/user';
import type { UserContextValue } from '../types';
import '@/lib/auth/cognito/client';
import { useRouter } from 'next/navigation';
import { getCurrentUser } from '@aws-amplify/auth';
import type { AuthUser } from '@aws-amplify/auth';
import { logger } from '@/lib/default-logger';
export const UserContext = React.createContext<UserContextValue | undefined>(undefined);
export interface UserProviderProps {
children: React.ReactNode;
}
export function UserProvider({ children }: UserProviderProps): React.JSX.Element {
const router = useRouter();
const [state, setState] = React.useState<{ user: User | null; error: string | null; isLoading: boolean }>({
user: null,
error: null,
isLoading: true,
});
React.useEffect(() => {
// Only run on initial mount.
getCurrentUser()
.then((user) => {
setState({ user: { id: user.userId, email: user.username }, error: null, isLoading: false });
})
.catch(() => {
setState({ user: null, error: null, isLoading: false });
});
}, []);
React.useEffect(() => {
function handleSignedIn(data: AuthUser): void {
setState({ user: { id: data.userId, email: data.username }, error: null, isLoading: false });
router.refresh();
}
function handleSignedOut(): void {
setState({ user: null, error: null, isLoading: false });
router.refresh();
}
const unsubscribe = Hub.listen('auth', ({ payload }): void => {
logger.debug('[Auth] Hub event:', payload);
if (payload.event === 'signedIn') {
handleSignedIn(payload.data);
}
if (payload.event === 'signedOut') {
handleSignedOut();
}
});
return (): void => {
unsubscribe();
};
}, [router]);
return <UserContext.Provider value={{ ...state }}>{children}</UserContext.Provider>;
}
export const UserConsumer = UserContext.Consumer;

View File

@@ -0,0 +1,52 @@
'use client';
import * as React from 'react';
import type { User } from '@/types/user';
import { authClient } from '@/lib/auth/custom/client';
import { logger } from '@/lib/default-logger';
import type { UserContextValue } from '../types';
export const UserContext = React.createContext<UserContextValue | undefined>(undefined);
export interface UserProviderProps {
children: React.ReactNode;
}
export function UserProvider({ children }: UserProviderProps): React.JSX.Element {
const [state, setState] = React.useState<{ user: User | null; error: string | null; isLoading: boolean }>({
user: null,
error: null,
isLoading: true,
});
const checkSession = React.useCallback(async (): Promise<void> => {
try {
const { data, error } = await authClient.getUser();
if (error) {
logger.error(error);
setState((prev) => ({ ...prev, user: null, error: 'Something went wrong', isLoading: false }));
return;
}
setState((prev) => ({ ...prev, user: data ?? null, error: null, isLoading: false }));
} catch (err) {
logger.error(err);
setState((prev) => ({ ...prev, user: null, error: 'Something went wrong', isLoading: false }));
}
}, []);
React.useEffect(() => {
checkSession().catch((err) => {
logger.error(err);
// noop
});
// eslint-disable-next-line react-hooks/exhaustive-deps -- Expected
}, []);
return <UserContext.Provider value={{ ...state, checkSession }}>{children}</UserContext.Provider>;
}
export const UserConsumer = UserContext.Consumer;

View File

@@ -0,0 +1,55 @@
'use client';
import * as React from 'react';
import { onAuthStateChanged } from 'firebase/auth';
import type { Auth } from 'firebase/auth';
import type { User } from '@/types/user';
import { getFirebaseAuth } from '@/lib/auth/firebase/client';
import { logger } from '@/lib/default-logger';
import type { UserContextValue } from '../types';
export const UserContext = React.createContext<UserContextValue | undefined>(undefined);
export interface UserProviderProps {
children: React.ReactNode;
}
export function UserProvider({ children }: UserProviderProps): React.JSX.Element {
const [firebaseAuth] = React.useState<Auth>(getFirebaseAuth());
const [state, setState] = React.useState<{ user: User | null; error: string | null; isLoading: boolean }>({
user: null,
error: null,
isLoading: true,
});
React.useEffect(() => {
const unsubscribe = onAuthStateChanged(firebaseAuth, (user) => {
logger.debug('[Auth] onAuthStateChanged:', user);
setState((prev) => ({
...prev,
user: user
? ({
id: user.uid,
email: user.email ?? undefined,
name: user.displayName ?? undefined,
avatar: user.photoURL ?? undefined,
} satisfies User)
: null,
error: null,
isLoading: false,
}));
});
return () => {
unsubscribe();
};
}, [firebaseAuth]);
return <UserContext.Provider value={{ ...state }}>{children}</UserContext.Provider>;
}
export const UserConsumer = UserContext.Consumer;

View File

@@ -0,0 +1,101 @@
'use client';
import * as React from 'react';
import { useRouter } from 'next/navigation';
import type { Session } from '@supabase/supabase-js';
import type { User } from '@/types/user';
import { logger } from '@/lib/default-logger';
import { createClient as createSupabaseClient } from '@/lib/supabase/client';
import type { UserContextValue } from '../types';
export const UserContext = React.createContext<UserContextValue | undefined>(undefined);
export interface UserProviderProps {
children: React.ReactNode;
}
export function UserProvider({ children }: UserProviderProps): React.JSX.Element {
const router = useRouter();
const [supabaseClient] = React.useState(createSupabaseClient());
const [state, setState] = React.useState<{ user: User | null; error: string | null; isLoading: boolean }>({
user: null,
error: null,
isLoading: true,
});
React.useEffect(() => {
function handleInitialSession(session: Session | null): void {
const user = session?.user;
setState((prev) => ({
...prev,
user: user
? ({
id: user.id ?? undefined,
email: user.email ?? undefined,
name: (user.user_metadata?.full_name as string) ?? undefined,
avatar: (user.user_metadata?.avatar_url as string) ?? undefined,
} satisfies User)
: null,
error: null,
isLoading: false,
}));
}
function handleSignedIn(session: Session | null): void {
const user = session?.user;
setState((prev) => ({
...prev,
user: user
? ({
id: user.id ?? undefined,
email: user.email ?? undefined,
name: (user.user_metadata?.full_name as string) ?? undefined,
avatar: (user.user_metadata?.avatar_url as string) ?? undefined,
} satisfies User)
: null,
error: null,
isLoading: false,
}));
router.refresh();
}
function handleSignedOut(): void {
setState((prev) => ({ ...prev, user: null, error: null, isLoading: false }));
router.refresh();
}
const {
data: { subscription },
} = supabaseClient.auth.onAuthStateChange((event, session) => {
logger.debug('[Auth] onAuthStateChange:', event, session);
if (event === 'INITIAL_SESSION') {
handleInitialSession(session);
}
if (event === 'SIGNED_IN') {
handleSignedIn(session);
}
if (event === 'SIGNED_OUT') {
handleSignedOut();
}
});
return () => {
subscription?.unsubscribe();
};
}, [router, supabaseClient]);
return <UserContext.Provider value={{ ...state }}>{children}</UserContext.Provider>;
}
export const UserConsumer = UserContext.Consumer;

View File

@@ -0,0 +1,8 @@
import type { User } from '@/types/user';
export interface UserContextValue {
user: User | null;
error: string | null;
isLoading: boolean;
checkSession?: () => Promise<void>;
}

View File

@@ -0,0 +1,44 @@
import type * as React from 'react';
import { config } from '@/config';
import { AuthStrategy } from '@/lib/auth/strategy';
import { UserContext as Auth0UserContext, UserProvider as Auth0UserProvider } from './auth0/user-context';
import { UserContext as CognitoUserContext, UserProvider as CognitoUserProvider } from './cognito/user-context';
import { UserContext as CustomUserContext, UserProvider as CustomUserProvider } from './custom/user-context';
import { UserContext as FirebaseUserContext, UserProvider as FirebaseUserProvider } from './firebase/user-context';
import { UserContext as SupabaseUserContext, UserProvider as SupabaseUserProvider } from './supabase/user-context';
import type { UserContextValue } from './types';
// eslint-disable-next-line import/no-mutable-exports -- Export based on config
let UserProvider: React.FC<{ children: React.ReactNode }>;
// eslint-disable-next-line import/no-mutable-exports -- Export based on config
let UserContext: React.Context<UserContextValue | undefined>;
switch (config.auth.strategy) {
case AuthStrategy.CUSTOM:
UserContext = CustomUserContext;
UserProvider = CustomUserProvider;
break;
case AuthStrategy.AUTH0:
UserContext = Auth0UserContext;
UserProvider = Auth0UserProvider;
break;
case AuthStrategy.COGNITO:
UserContext = CognitoUserContext;
UserProvider = CognitoUserProvider;
break;
case AuthStrategy.FIREBASE:
UserContext = FirebaseUserContext;
UserProvider = FirebaseUserProvider;
break;
case AuthStrategy.SUPABASE:
UserContext = SupabaseUserContext;
UserProvider = SupabaseUserProvider;
break;
default:
throw new Error('Invalid auth strategy');
}
export { UserProvider, UserContext };

View File

@@ -0,0 +1,46 @@
'use client';
import * as React from 'react';
import type { Settings } from '@/types/settings';
import { applyDefaultSettings } from '@/lib/settings/apply-default-settings';
export interface SettingsContextValue {
settings: Settings;
setSettings: (settings: Settings) => void;
}
export const SettingsContext = React.createContext<SettingsContextValue>({
settings: applyDefaultSettings({}),
setSettings: () => {
// noop
},
});
export interface SettingsProviderProps {
children: React.ReactNode;
settings: Settings;
}
export function SettingsProvider({ children, settings: initialSettings }: SettingsProviderProps): React.JSX.Element {
const [state, setState] = React.useState<Settings>(initialSettings);
React.useEffect(() => {
setState(initialSettings);
}, [initialSettings]);
return (
<SettingsContext.Provider
value={{
settings: state,
setSettings: (newSettings: Settings) => {
setState(newSettings);
},
}}
>
{children}
</SettingsContext.Provider>
);
}
export const SettingsConsumer = SettingsContext.Consumer;