codex/fsd-frontend-refactor #31
94
apps/frontend/src/shared/lib/test/TestSessionProvider.tsx
Normal file
94
apps/frontend/src/shared/lib/test/TestSessionProvider.tsx
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import { useState, useEffect, useCallback, type ReactNode } from 'react';
|
||||||
|
import { SessionContext, type SessionContextValue } from '@/entities/session';
|
||||||
|
import * as sessionApi from '@/entities/session';
|
||||||
|
import type { UserResponse } from '@/shared/api/responses';
|
||||||
|
|
||||||
|
export function TestSessionProvider({ children }: { children: ReactNode }) {
|
||||||
|
const [user, setUser] = useState<UserResponse | null>(null);
|
||||||
|
const [accessToken, setAccessTokenState] = useState<string | null>(null);
|
||||||
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
const [initialized, setInitialized] = useState(false);
|
||||||
|
|
||||||
|
const updateSession = useCallback((authData: { user: UserResponse; accessToken: string }) => {
|
||||||
|
setUser(authData.user);
|
||||||
|
setAccessTokenState(authData.accessToken);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const clearSession = useCallback(() => {
|
||||||
|
setUser(null);
|
||||||
|
setAccessTokenState(null);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const login = useCallback(
|
||||||
|
async (email: string, password: string) => {
|
||||||
|
const result = await sessionApi.login(email, password);
|
||||||
|
updateSession(result);
|
||||||
|
},
|
||||||
|
[updateSession],
|
||||||
|
);
|
||||||
|
|
||||||
|
const register = useCallback(
|
||||||
|
async (email: string, password: string, name?: string) => {
|
||||||
|
const result = await sessionApi.register(email, password, name);
|
||||||
|
updateSession(result);
|
||||||
|
},
|
||||||
|
[updateSession],
|
||||||
|
);
|
||||||
|
|
||||||
|
const logout = useCallback(async () => {
|
||||||
|
try {
|
||||||
|
await sessionApi.logout();
|
||||||
|
} catch {
|
||||||
|
// ignore network errors on logout
|
||||||
|
}
|
||||||
|
clearSession();
|
||||||
|
}, [clearSession]);
|
||||||
|
|
||||||
|
const updateProfileFn = useCallback(async (data: { name?: string }) => {
|
||||||
|
const result = await sessionApi.updateProfile(data);
|
||||||
|
setUser(result);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let mounted = true;
|
||||||
|
|
||||||
|
async function init() {
|
||||||
|
try {
|
||||||
|
const result = await sessionApi.refresh();
|
||||||
|
if (mounted) {
|
||||||
|
updateSession(result);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// No valid session
|
||||||
|
} finally {
|
||||||
|
if (mounted) {
|
||||||
|
setIsLoading(false);
|
||||||
|
setInitialized(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init();
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
mounted = false;
|
||||||
|
};
|
||||||
|
}, [updateSession]);
|
||||||
|
|
||||||
|
if (!initialized && isLoading) {
|
||||||
|
return <div>Загрузка...</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const value: SessionContextValue = {
|
||||||
|
user,
|
||||||
|
accessToken,
|
||||||
|
isAuthenticated: !!user,
|
||||||
|
isLoading,
|
||||||
|
login,
|
||||||
|
register,
|
||||||
|
logout,
|
||||||
|
updateProfile: updateProfileFn,
|
||||||
|
};
|
||||||
|
|
||||||
|
return <SessionContext.Provider value={value}>{children}</SessionContext.Provider>;
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@ import { type ReactElement } from 'react';
|
|||||||
import { render, type RenderOptions } from '@testing-library/react';
|
import { render, type RenderOptions } from '@testing-library/react';
|
||||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
import { SessionProvider } from '@/app/providers';
|
import { TestSessionProvider } from './TestSessionProvider';
|
||||||
|
|
||||||
interface CustomRenderOptions extends Omit<RenderOptions, 'wrapper'> {
|
interface CustomRenderOptions extends Omit<RenderOptions, 'wrapper'> {
|
||||||
queryClient?: QueryClient;
|
queryClient?: QueryClient;
|
||||||
@ -33,7 +33,7 @@ export function renderWithProviders(
|
|||||||
initialEntries={[route]}
|
initialEntries={[route]}
|
||||||
future={{ v7_startTransition: true, v7_relativeSplatPath: true }}
|
future={{ v7_startTransition: true, v7_relativeSplatPath: true }}
|
||||||
>
|
>
|
||||||
<SessionProvider>{children}</SessionProvider>
|
<TestSessionProvider>{children}</TestSessionProvider>
|
||||||
</MemoryRouter>
|
</MemoryRouter>
|
||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user