Files
glchat/web/src/api/users.ts
T

90 lines
3.0 KiB
TypeScript
Raw Normal View History

import { request } from './client';
import type { GuildSummary, User, UserSummary } from './types';
export interface UpdateProfileInput {
display_name?: string;
bio?: string;
status?: string;
custom_status?: string;
custom_status_emoji?: string;
locale?: string;
/** Часовой пояс в формате IANA (например `Europe/Moscow`). */
timezone?: string;
}
export interface OnboardingInput {
display_name?: string;
bio?: string;
locale?: string;
}
export const currentUserQueryKey = ['users', '@me'] as const;
export const myGuildsQueryKey = ['users', '@me', 'guilds'] as const;
export function userQueryKey(userId: string) {
return ['users', userId] as const;
}
export async function fetchCurrentUser(signal?: AbortSignal): Promise<User> {
const payload = await request<{ user: User }>(
'/users/@me',
signal === undefined ? {} : { signal },
);
return payload.user;
}
export async function updateProfile(input: UpdateProfileInput): Promise<User> {
const payload = await request<{ user: User }>('/users/@me', { method: 'PATCH', body: input });
return payload.user;
}
export async function completeOnboarding(input: OnboardingInput): Promise<User> {
const payload = await request<{ user: User }>('/users/@me/onboarding/complete', {
method: 'POST',
body: input,
});
return payload.user;
}
/** Максимальный размер аватара: сервер отвечает `file.too_large` выше лимита. */
export const AVATAR_MAX_BYTES = 8 * 1024 * 1024;
/**
* Загрузка аватара: `POST /users/@me/avatar` multipart с полем `file`.
*
* Сервер может ответить как полным профилем, так и только идентификатором
* файла, поэтому возвращаем профиль, если он есть, иначе `null` — вызывающий
* код в этом случае перечитывает `GET /users/@me`.
*/
export async function uploadAvatar(file: File): Promise<User | null> {
const form = new FormData();
form.append('file', file);
const payload = await request<{ user?: User }>('/users/@me/avatar', {
method: 'POST',
form,
});
return payload.user ?? null;
}
/** Удаление аватара: `DELETE /users/@me/avatar`. */
export async function deleteAvatar(): Promise<User | null> {
const payload = await request<{ user?: User }>('/users/@me/avatar', { method: 'DELETE' });
return payload.user ?? null;
}
export async function fetchMyGuilds(signal?: AbortSignal): Promise<GuildSummary[]> {
const payload = await request<{ guilds: GuildSummary[] }>(
'/users/@me/guilds',
signal === undefined ? {} : { signal },
);
return payload.guilds;
}
export async function fetchUser(userId: string, signal?: AbortSignal): Promise<UserSummary> {
const payload = await request<{ user: UserSummary }>(
`/users/${encodeURIComponent(userId)}`,
signal === undefined ? {} : { signal },
);
return payload.user;
}