145 lines
3.5 KiB
TypeScript
145 lines
3.5 KiB
TypeScript
import React, { createContext, useContext, useEffect, useState, ReactNode } from 'react';
|
|
import { createAuthClient } from 'better-auth/react';
|
|
import { AUTH_BASE_URL } from '@/config/api';
|
|
import type { User } from '@shared-types';
|
|
|
|
// Создаем клиент Better Auth
|
|
export const authClient = createAuthClient({
|
|
baseURL: AUTH_BASE_URL,
|
|
});
|
|
|
|
interface AuthContextType {
|
|
user: User | null;
|
|
session: any | null;
|
|
loading: boolean;
|
|
signIn: (email: string, password: string) => Promise<void>;
|
|
signUp: (email: string, password: string, name: string) => Promise<void>;
|
|
signOut: () => Promise<void>;
|
|
refresh: () => Promise<void>;
|
|
}
|
|
|
|
const AuthContext = createContext<AuthContextType | undefined>(undefined);
|
|
|
|
export function AuthProvider({ children }: { children: ReactNode }) {
|
|
const [user, setUser] = useState<User | null>(null);
|
|
const [session, setSession] = useState<any | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
const refresh = async () => {
|
|
try {
|
|
const sessionData = await authClient.getSession();
|
|
setSession(sessionData.data?.session || null);
|
|
const userData = sessionData.data?.user;
|
|
if (userData) {
|
|
setUser({
|
|
...userData,
|
|
image: userData.image ?? null,
|
|
} as User);
|
|
} else {
|
|
setUser(null);
|
|
}
|
|
} catch (error) {
|
|
console.error('Ошибка получения сессии:', error);
|
|
setSession(null);
|
|
setUser(null);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
refresh();
|
|
}, []);
|
|
|
|
const signIn = async (email: string, password: string) => {
|
|
setLoading(true);
|
|
try {
|
|
const result = await authClient.signIn.email({
|
|
email,
|
|
password,
|
|
});
|
|
|
|
if (result.data?.user) {
|
|
const userData = result.data.user;
|
|
setUser({
|
|
...userData,
|
|
image: userData.image ?? null,
|
|
} as User);
|
|
setSession(result.data as any);
|
|
} else {
|
|
throw new Error('Ошибка входа');
|
|
}
|
|
} catch (error) {
|
|
console.error('Ошибка входа:', error);
|
|
throw error;
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
const signUp = async (email: string, password: string, name: string) => {
|
|
setLoading(true);
|
|
try {
|
|
const result = await authClient.signUp.email({
|
|
email,
|
|
password,
|
|
name,
|
|
});
|
|
|
|
if (result.data?.user) {
|
|
const userData = result.data.user;
|
|
setUser({
|
|
...userData,
|
|
image: userData.image ?? null,
|
|
} as User);
|
|
setSession(result.data as any);
|
|
} else {
|
|
throw new Error('Ошибка регистрации');
|
|
}
|
|
} catch (error) {
|
|
console.error('Ошибка регистрации:', error);
|
|
throw error;
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
const signOut = async () => {
|
|
setLoading(true);
|
|
try {
|
|
await authClient.signOut();
|
|
setUser(null);
|
|
setSession(null);
|
|
} catch (error) {
|
|
console.error('Ошибка выхода:', error);
|
|
throw error;
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<AuthContext.Provider
|
|
value={{
|
|
user,
|
|
session,
|
|
loading,
|
|
signIn,
|
|
signUp,
|
|
signOut,
|
|
refresh,
|
|
}}
|
|
>
|
|
{children}
|
|
</AuthContext.Provider>
|
|
);
|
|
}
|
|
|
|
export function useAuth() {
|
|
const context = useContext(AuthContext);
|
|
if (context === undefined) {
|
|
throw new Error('useAuth must be used within an AuthProvider');
|
|
}
|
|
return context;
|
|
}
|