/** * API для профиля и настроек */ import apiClient from '@/lib/api-client'; import type { User } from './auth'; export interface CityOption { name: string; timezone?: string; region?: string; full_name?: string; } export interface MentorHomeworkAISettings { ai_trust_draft?: boolean; ai_trust_publish?: boolean; } export interface ProfileSettings { preferences: { timezone?: string; country?: string; city?: string; }; notifications: { email_notifications?: boolean; telegram_notifications?: boolean; in_app_notifications?: boolean; }; /** Только для ментора: доверие AI при проверке ДЗ */ mentor_homework_ai?: MentorHomeworkAISettings; } export async function getProfileSettings(): Promise { const response = await apiClient.get('/profile/settings/'); return response.data; } export async function updateProfileSettings(data: Partial): Promise { await apiClient.patch('/profile/update_settings/', data); } export async function searchCitiesFromCSV(query: string, limit = 50): Promise { try { const params = new URLSearchParams(); params.set('q', query); params.set('limit', limit.toString()); const response = await apiClient.get(`/profile/cities/search/?${params.toString()}`); return Array.isArray(response.data) ? response.data : []; } catch { return []; } } export interface UpdateProfileData { first_name?: string; last_name?: string; phone?: string; email?: string; bio?: string; avatar?: File | null; } /** Кэш аватаров — не делаем повторных запросов в течение сессии */ const avatarUrlCache = new Map(); const AVATAR_CACHE_TTL = 5 * 60 * 1000; // 5 минут /** URL аватара пользователя по ID (для плейсхолдера в видеоконференции). GET /api/users//avatar_url/ */ export async function getAvatarUrl(userId: number | string): Promise { const key = String(userId); const cached = avatarUrlCache.get(key); if (cached && Date.now() - cached.timestamp < AVATAR_CACHE_TTL) { return cached.url; } try { const response = await apiClient.get<{ avatar_url: string | null }>(`/users/${userId}/avatar_url/`); const url = response.data?.avatar_url ?? null; avatarUrlCache.set(key, { url, timestamp: Date.now() }); return url; } catch { avatarUrlCache.set(key, { url: null, timestamp: Date.now() }); return null; } } /** Загрузить аватар из Telegram (требуется привязанный Telegram). */ export async function loadTelegramAvatar(): Promise { const response = await apiClient.post<{ success?: boolean; user: User }>('/profile/load_telegram_avatar/'); const data = response.data as { success?: boolean; user?: User }; return data?.user ?? (data as unknown as User); } export async function updateProfile(data: UpdateProfileData): Promise { if (data.avatar !== undefined && data.avatar !== null && data.avatar instanceof File) { const formData = new FormData(); if (data.first_name) formData.append('first_name', data.first_name); if (data.last_name) formData.append('last_name', data.last_name); if (data.phone) formData.append('phone', data.phone); if (data.email) formData.append('email', data.email); if (data.bio) formData.append('bio', data.bio); formData.append('avatar', data.avatar); const res = await apiClient.getInstance().patch('/profile/update_profile/', formData); return res.data; } if (data.avatar === null) { const formData = new FormData(); if (data.first_name) formData.append('first_name', data.first_name); if (data.last_name) formData.append('last_name', data.last_name); if (data.phone) formData.append('phone', data.phone); if (data.email) formData.append('email', data.email); formData.append('avatar', ''); const res = await apiClient.getInstance().patch('/profile/update_profile/', formData); return res.data; } const response = await apiClient.patch('/profile/update_profile/', data); return response.data; }