build ok,
This commit is contained in:
37
002_source/cms/src/contexts/auth/auth0/user-context.tsx
Normal file
37
002_source/cms/src/contexts/auth/auth0/user-context.tsx
Normal 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;
|
77
002_source/cms/src/contexts/auth/cognito/user-context.tsx
Normal file
77
002_source/cms/src/contexts/auth/cognito/user-context.tsx
Normal 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;
|
52
002_source/cms/src/contexts/auth/custom/user-context.tsx
Normal file
52
002_source/cms/src/contexts/auth/custom/user-context.tsx
Normal 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;
|
55
002_source/cms/src/contexts/auth/firebase/user-context.tsx
Normal file
55
002_source/cms/src/contexts/auth/firebase/user-context.tsx
Normal 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;
|
101
002_source/cms/src/contexts/auth/supabase/user-context.tsx
Normal file
101
002_source/cms/src/contexts/auth/supabase/user-context.tsx
Normal 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;
|
8
002_source/cms/src/contexts/auth/types.d.ts
vendored
Normal file
8
002_source/cms/src/contexts/auth/types.d.ts
vendored
Normal 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>;
|
||||
}
|
44
002_source/cms/src/contexts/auth/user-context.ts
Normal file
44
002_source/cms/src/contexts/auth/user-context.ts
Normal 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 };
|
46
002_source/cms/src/contexts/settings.tsx
Normal file
46
002_source/cms/src/contexts/settings.tsx
Normal 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;
|
Reference in New Issue
Block a user