import { formatNumber, t } from '@/i18n' import type { ActivitySummary, RangeKey } from '@/lib/activity' export type StripKey = 'total' | 'active' | 'failed' | 'security' export type StripTone = 'neutral' | 'error' | 'warning' | 'calm' export interface StripCard { key: StripKey label: string value: string subline: string icon: string | null tone: StripTone series: number[] } export const STRIP_KEYS: StripKey[] = ['total', 'active', 'failed', 'security'] export const MIN_BAR_HEIGHT = 2 function percent(part: number, whole: number) { return Math.round((Math.abs(part - whole) / whole) * 100) } function totalSubline(summary: ActivitySummary, range: RangeKey) { if (summary.total === 0) return { text: t('No data yet'), icon: null } if (summary.previous_total === 0) return { text: t('No earlier data'), icon: null } if (summary.total === summary.previous_total) return { text: t('No change'), icon: null } const value = formatNumber(percent(summary.total, summary.previous_total)) const text = range === 'today' ? t('{0}% vs previous day', [value]) : range === '30d' ? t('{0}% vs previous 30 days', [value]) : range === 'custom' ? t('{0}% vs previous period', [value]) : t('{0}% vs previous 7 days', [value]) const icon = summary.total >= summary.previous_total ? 'i-lucide-trending-up' : 'i-lucide-trending-down' return { text, icon } } function peopleSubline(summary: ActivitySummary) { if (summary.total === 0) return t('No data yet') const { users, api_keys: keys } = summary.active_people const people = users === 1 ? t('1 person') : t('{0} people', [formatNumber(users)]) const apiKeys = keys === 1 ? t('1 API key') : t('{0} API keys', [formatNumber(keys)]) return `${people}, ${apiKeys}` } function failedSubline(summary: ActivitySummary) { const ratio = (summary.failed / summary.total) * 100 return t('{0}% of all actions', [ formatNumber(ratio, { minimumFractionDigits: 1, maximumFractionDigits: 1, }), ]) } function flaggedSubline(count: number) { return count === 1 ? t('1 flagged') : t('{0} flagged', [formatNumber(count)]) } export function stripCards(summary: ActivitySummary, range: RangeKey): StripCard[] { const total = totalSubline(summary, range) const failedCalm = summary.failed === 0 const securityCalm = summary.security === 0 return [ { key: 'total', label: t('Total actions'), value: formatNumber(summary.total), subline: total.text, icon: total.icon, tone: 'neutral', series: summary.series.total, }, { key: 'active', label: t('Active people'), value: formatNumber(summary.active_people.users + summary.active_people.api_keys), subline: peopleSubline(summary), icon: null, tone: 'neutral', series: summary.series.active, }, { key: 'failed', label: t('Failed actions'), value: formatNumber(summary.failed), subline: failedCalm ? t('Nothing failed') : failedSubline(summary), icon: failedCalm ? 'i-lucide-circle-check' : 'i-lucide-circle-x', tone: failedCalm ? 'calm' : 'error', series: summary.series.failed, }, { key: 'security', label: t('Security events'), value: formatNumber(summary.security), subline: securityCalm ? t('Nothing to flag') : flaggedSubline(summary.security), icon: securityCalm ? 'i-lucide-circle-check' : 'i-lucide-shield-alert', tone: securityCalm ? 'calm' : 'warning', series: summary.series.security, }, ] } export function barHeights(series: number[], height: number) { const peak = Math.max(...series, 1) return series.map((value) => Math.max(MIN_BAR_HEIGHT, Math.round((value / peak) * height))) }