Reorganize web folder structurally

This commit is contained in:
Халимов Рустам
2026-03-19 22:24:21 +03:00
parent 11ebbc853b
commit 4384233aa5
62 changed files with 0 additions and 0 deletions
@@ -0,0 +1,114 @@
import { create } from 'zustand';
import { AuthApi } from '../infrastructure/authApi';
import { connectSocket, disconnectSocket } from '../../../core/infrastructure/socket';
import type { User } from '../../../core/domain/types';
interface AuthState {
token: string | null;
user: User | null;
isLoading: boolean;
error: string | null;
login: (username: string, password: string) => Promise<void>;
register: (username: string, displayName: string, password: string, bio?: string) => Promise<void>;
logout: () => void;
checkAuth: () => Promise<void>;
updateUser: (data: Partial<User>) => void;
config: any;
fetchConfig: () => Promise<void>;
}
export const useAuthStore = create<AuthState>((set, get) => ({
token: localStorage.getItem('knot_token'),
user: null,
isLoading: true,
error: null,
config: null,
fetchConfig: async () => {
if (!get().token) return;
try {
const res = await AuthApi.getConfig();
set({ config: res });
} catch {}
},
login: async (username, password) => {
try {
set({ error: null, isLoading: true });
const { token, user } = await AuthApi.login(username, password);
localStorage.setItem('knot_token', token);
AuthApi.setToken(token);
connectSocket(token);
set({ token, user, isLoading: false });
await get().fetchConfig();
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
set({ error: msg, isLoading: false });
throw err;
}
},
register: async (username, displayName, password, bio) => {
try {
set({ error: null, isLoading: true });
const { token, user } = await AuthApi.register(username, displayName, password, bio);
localStorage.setItem('knot_token', token);
AuthApi.setToken(token);
connectSocket(token);
set({ token, user, isLoading: false });
await get().fetchConfig();
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);
set({ error: msg, isLoading: false });
throw err;
}
},
logout: () => {
localStorage.removeItem('knot_token');
AuthApi.setToken(null);
disconnectSocket();
set({ token: null, user: null });
},
checkAuth: async () => {
const token = get().token;
if (!token) {
set({ isLoading: false });
return;
}
// Retry up to 3 times in case server is still starting
let lastError: unknown;
for (let attempt = 0; attempt < 3; attempt++) {
try {
AuthApi.setToken(token);
const { user } = await AuthApi.getMe();
connectSocket(token);
set({ user, isLoading: false });
await get().fetchConfig();
return;
} catch (err) {
lastError = err;
// Only retry on network/server errors, not on auth errors (401/403)
const msg = err instanceof Error ? err.message : '';
if (msg.includes('Требуется авторизация') || msg.includes('Недействительный токен')) {
break;
}
if (attempt < 2) {
await new Promise(r => setTimeout(r, 1000 * (attempt + 1)));
}
}
}
console.warn('checkAuth failed:', lastError);
localStorage.removeItem('knot_token');
set({ token: null, user: null, isLoading: false });
},
updateUser: (data) => {
const { user } = get();
if (user) {
set({ user: { ...user, ...data } });
}
},
}));