Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
73 lines
2.9 KiB
TypeScript
73 lines
2.9 KiB
TypeScript
'use client'
|
|
|
|
import type { EventWizardFormData } from '@/components/events/create/types'
|
|
import { formatToman } from '@/components/events/create/types'
|
|
import { cn } from '@/lib/cn'
|
|
import { texts } from '@/texts'
|
|
|
|
interface CreateEventPreviewCardProps {
|
|
categoryName?: string
|
|
cityName?: string
|
|
data: EventWizardFormData
|
|
endsAt: string
|
|
startsAt: string
|
|
}
|
|
|
|
interface PreviewField {
|
|
full?: boolean
|
|
label: string
|
|
value: string
|
|
}
|
|
|
|
/** Read-only event card that mirrors the information guests see before booking. */
|
|
export default function CreateEventPreviewCard({ categoryName, cityName, data, endsAt, startsAt }: CreateEventPreviewCardProps) {
|
|
const fields = [
|
|
{ label: texts.common.category, value: categoryName || texts.status.empty },
|
|
{ label: texts.events.start, value: startsAt || texts.status.empty },
|
|
{ label: texts.events.end, value: endsAt || texts.status.empty },
|
|
{ label: texts.events.location, value: cityName || texts.status.empty },
|
|
{ label: texts.events.price, value: data.isFree ? texts.events.free : formatToman(data.price) },
|
|
{ label: texts.events.capacity, value: String(data.capacity) },
|
|
{ full: true, label: texts.events.address, value: data.address || texts.status.empty },
|
|
] satisfies PreviewField[]
|
|
const poster = [...data.media].sort((a, b) => a.sortOrder - b.sortOrder).find((item) => item.isPoster) ?? data.media[0]
|
|
|
|
return (
|
|
<article className="overflow-hidden rounded-consumer-surface bg-consumer-surface">
|
|
<div
|
|
aria-label={poster ? texts.events.posterAria : texts.events.noPosterAria}
|
|
className={cn(
|
|
'flex min-h-48 items-end bg-cover bg-center p-5 sm:min-h-60',
|
|
!poster && 'bg-gradient-to-br from-primary-100 to-primary-50'
|
|
)}
|
|
role="img"
|
|
style={
|
|
poster
|
|
? {
|
|
backgroundImage: `linear-gradient(to top, color-mix(in srgb, var(--color-secondary-10) 72%, transparent), transparent 62%), url("${poster.url}")`,
|
|
}
|
|
: undefined
|
|
}
|
|
>
|
|
<div className={poster ? 'text-white' : 'text-primary-900'}>
|
|
<p className="mb-2 text-xs font-semibold opacity-80">{categoryName || texts.events.eventCategoryFallback}</p>
|
|
<h3 className="text-xl font-extrabold sm:text-2xl">{data.title || texts.events.eventTitleLabel}</h3>
|
|
{data.shortDescription ? <p className="mt-2 max-w-2xl text-sm leading-6 opacity-90">{data.shortDescription}</p> : null}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid gap-2 grid-cols-2 mt-2">
|
|
{fields.map((field) => (
|
|
<div
|
|
key={field.label}
|
|
className={cn('rounded-2xl bg-consumer-surface-muted p-3', field.full && 'sm:col-span-2')}
|
|
>
|
|
<p className="mb-1 flex items-center gap-1 text-xs text-secondary-20">{field.label}</p>
|
|
<p className="text-sm font-semibold text-text-dark">{field.value}</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</article>
|
|
)
|
|
}
|