/** * presentEventCapacityBadge — label + tone for browse/discovery capacity chips. * * Purpose * - Shared remaining-capacity / ended / full presentation for medium cards. * - Separate from host progress UI (`presentHostCapacity`). */ import type { EventCapacityTone } from '@/features/events/eventCapacity' import { capacityToneFromRemaining, isOccupancyFull, remainingSeatCount } from '@/features/events/eventCapacity' import { isEventEnded } from '@/features/events/eventEditPolicy' import { formatNumber } from '@/helpers' import { format, texts } from '@/texts' export interface PresentEventCapacityBadgeInput { capacity: number bookedCount: number reservedCapacity?: number status?: string endsAt?: string } export interface PresentEventCapacityBadgeResult { label: string tone: EventCapacityTone } const formatRemainingCapacity = (remaining: number) => { if (remaining <= 0) return texts.discovery.capacityFull return format(texts.events.remainingCapacity, { count: formatNumber(remaining) }) } export function presentEventCapacityBadge(input: PresentEventCapacityBadgeInput): PresentEventCapacityBadgeResult { const reserved = input.reservedCapacity ?? 0 const remaining = remainingSeatCount(input.capacity, input.bookedCount, reserved) const isFull = isOccupancyFull(input.capacity, input.bookedCount, reserved) || input.status === 'full' // لغو/رد با «اتمام رویداد» فرق دارد؛ بج ظرفیت برای این وضعیت‌ها معنا ندارد. if (input.status === 'cancelled' || input.status === 'rejected') { return { label: '', tone: 'neutral' } } const isEnded = input.status != null && input.endsAt != null ? isEventEnded(input.status, input.endsAt) : false if (isEnded) { return { label: texts.events.eventEnded, tone: 'danger' } } return { label: formatRemainingCapacity(remaining), tone: isFull ? 'danger' : capacityToneFromRemaining(remaining, input.capacity), } }