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 { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { SessionProvider } from '@/app/providers';
|
||||
import { TestSessionProvider } from './TestSessionProvider';
|
||||
|
||||
interface CustomRenderOptions extends Omit<RenderOptions, 'wrapper'> {
|
||||
queryClient?: QueryClient;
|
||||
@ -33,7 +33,7 @@ export function renderWithProviders(
|
||||
initialEntries={[route]}
|
||||
future={{ v7_startTransition: true, v7_relativeSplatPath: true }}
|
||||
>
|
||||
<SessionProvider>{children}</SessionProvider>
|
||||
<TestSessionProvider>{children}</TestSessionProvider>
|
||||
</MemoryRouter>
|
||||
</QueryClientProvider>
|
||||
);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user