Files
glchat/web/src/lib/presence.ts
T
grendervill d02ef7527a fix(files): аватары и баннеры доступны авторизованным пользователям
Аватар нельзя было показать в списке друзей: файл без комнаты был доступен
только загрузившему. Добавлено назначение файла (`files.purpose`: attachment |
avatar | banner, миграция 00006): аватары и баннеры отдаются любому
авторизованному пользователю, вложения по-прежнему проверяются по правам
комнаты, а непривязанные загрузки остаются приватными.
2026-09-20 01:39:04 +03:00

54 lines
2.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { UserStatus } from '@/api/types';
import { DEFAULT_TIMEZONE } from '@/lib/timezones';
/**
* Присутствие в разделе друзей.
*
* Цвета точки статуса отличаются от панели пользователя (там «не беспокоить»
* красный, как в Discord): в списке друзей `dnd` — серый, а `invisible` —
* тёмно-голубой. У других пользователей «невидимка» приходит как `offline`,
* поэтому тёмно-голубой виден только у себя.
*/
export const presenceDotClass: Record<UserStatus, string> = {
online: 'bg-success',
offline: 'bg-danger',
idle: 'bg-warning',
dnd: 'bg-fg-muted',
invisible: 'bg-info',
};
/**
* Время последнего входа в часовом поясе пользователя из настроек
* (`user.timezone`, по умолчанию Москва).
*
* Возвращает `null`, если дата не пришла или не разбирается: вызывающий код
* показывает «Не в сети давно».
*/
export function formatLastSeen(
lastSeenAt: string | undefined,
timezone: string | undefined,
locale: string,
): string | null {
if (lastSeenAt === undefined || lastSeenAt === '') {
return null;
}
const date = new Date(lastSeenAt);
if (Number.isNaN(date.getTime())) {
return null;
}
try {
return new Intl.DateTimeFormat(locale, {
dateStyle: 'short',
timeStyle: 'short',
timeZone: timezone === undefined || timezone === '' ? DEFAULT_TIMEZONE : timezone,
}).format(date);
} catch {
// Неизвестный пояс (например, устаревшее значение в настройках) — МСК.
return new Intl.DateTimeFormat(locale, {
dateStyle: 'short',
timeStyle: 'short',
timeZone: DEFAULT_TIMEZONE,
}).format(date);
}
}