admin/features/events/presentEventCapacityBadge.ts
alisaza e1eaf5eff5 feat: initial ghabilee-admin backoffice app
Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js
app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
2026-09-05 13:12:59 +03:30

55 lines
1.9 KiB
TypeScript

/**
* 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),
}
}