// Общие помощники UI задач: подписи статусов, приоритеты, Markdown.
import DOMPurify from 'dompurify'
import { marked } from 'marked'
export const STATUS_LABELS: Record<string, string> = {
to_do: 'К выполнению',
in_progress: 'В работе',
done: 'Завершено',
cancelled: 'Отменено',
deferred: 'Отложено',
}
export const STATUS_VARIANTS: Record<string, string> = {
to_do: 'info',
in_progress: 'accent',
done: 'success',
cancelled: 'error',
deferred: 'warning',
}
export const RELEVANCE_LABELS: Record<string, string> = {
active: 'Активен',
paused: 'Приостановлен',
archived: 'Закрыт',
}
export function statusLabel(status: string): string {
return STATUS_LABELS[status] ?? status
}
export function statusVariant(status: string): string {
return STATUS_VARIANTS[status] ?? 'neutral'
}
export function relevanceLabel(status: string): string {
return RELEVANCE_LABELS[status] ?? status
}
export function renderMarkdown(text: string): string {
return DOMPurify.sanitize(marked.parse(text, { async: false }))
}
// «90» → «1 ч 30 м»; для чипов оценок времени
export function formatMinutes(minutes: number | null): string {
if (minutes === null) return ''
const h = Math.floor(minutes / 60)
const m = minutes % 60
if (h && m) return `${h} ч ${m} м`
if (h) return `${h} ч`
return `${m} м`
}
// Валюта бюджетов — глобальная настройка, выбирается один раз и применяется всюду
export const CURRENCIES: { value: string; label: string }[] = [
{ value: 'UAH', label: '₴ Гривна (UAH)' },
{ value: 'USD', label: '$ Доллар (USD)' },
{ value: 'EUR', label: '€ Евро (EUR)' },
{ value: 'GBP', label: '£ Фунт (GBP)' },
{ value: 'PLN', label: 'zł Злотый (PLN)' },
]
const CURRENCY_SYMBOLS: Record<string, string> = {
UAH: '₴',
USD: '$',
EUR: '€',
GBP: '£',
PLN: 'zł',
}
let activeCurrency = 'UAH'
export function setCurrency(currency: string): void {
activeCurrency = currency
}
export function currencySymbol(): string {
return CURRENCY_SYMBOLS[activeCurrency] ?? activeCurrency
}
// «5 000 ₴» — суммы задач; валюта берётся из глобальной настройки
export function formatMoney(amount: number | null): string {
if (amount === null) return ''
return `${amount.toLocaleString('ru-RU')} ${currencySymbol()}`
}
// --- Дедлайны и регулярность (ТЗ 3.4, 3.5) ---
export const DEADLINE_PERIODS: { value: string; label: string }[] = [
{ value: 'day', label: 'в течение дня' },
{ value: 'week', label: 'в течение недели' },
{ value: 'month', label: 'в течение месяца' },
{ value: 'year', label: 'в течение года' },
]
export const RECUR_KINDS: { value: string; label: string }[] = [
{ value: 'interval', label: 'Каждые N дней' },
{ value: 'weekdays', label: 'Дни недели' },
{ value: 'monthly', label: 'День месяца' },
]
const PERIOD_LABELS: Record<string, string> = {
day: 'в течение дня',
week: 'в течение недели',
month: 'в течение месяца',
year: 'в течение года',
}
const WEEKDAY_NAMES = ['пн', 'вт', 'ср', 'чт', 'пт', 'сб', 'вс']
export function deadlineLabel(task: { deadline_date: string | null; deadline_period: string | null }): string {
if (task.deadline_date) return `до ${task.deadline_date.split('-').reverse().join('.')}`
return PERIOD_LABELS[task.deadline_period ?? ''] ?? ''
}
export function deadlineOverdue(task: { deadline_date: string | null }): boolean {
if (!task.deadline_date) return false
const today = new Date().toISOString().slice(0, 10)
return task.deadline_date < today
}
export function recurrenceLabel(task: {
recur_kind: string | null
recur_interval_days: number | null
recur_weekdays: string | null
recur_day_of_month: number | null
}): string {
if (task.recur_kind === 'interval') {
const step = task.recur_interval_days ?? 1
if (step === 1) return 'ежедневно'
if (step === 7) return 'еженедельно'
return `каждые ${step} дн.`
}
if (task.recur_kind === 'weekdays') {
if (!task.recur_weekdays) return 'по дням недели'
return task.recur_weekdays
.split(',')
.map((d) => WEEKDAY_NAMES[Number(d) - 1])
.join(' ')
}
if (task.recur_kind === 'monthly') return `ежемесячно ${task.recur_day_of_month}-го`
return ''
}