admin/components/events/EventGuestListAccessPanel.tsx
alisaza 82593dc18c refactor(events): update event management components and remove unused files
- Replaced `LIST_PUBLIC_CATEGORIES` with `LIST_ADMIN_CATEGORIES_FLAT` in `ArticleFormModal.tsx`.
- Removed the "Add Event" button from the dashboard page.
- Simplified the `EventsPage` by removing the button and adjusting the layout.
- Cleaned up the `AdminEventEditPage` by removing unnecessary props.
- Deleted unused layout and page files related to event creation.
- Updated `AdminAuthContent` to use `useAdminCitiesQuery` instead of `useDiscoveryCitiesQuery`.
- Refactored `EventGuestListAccessPanel` to remove the `accessMode` prop and adjust API calls accordingly.
- Removed several unused components and tests related to event creation, enhancing project maintainability.
2026-09-07 18:09:55 +03:30

130 lines
4.8 KiB
TypeScript

'use client'
import { useEffect, useState } from 'react'
import { Card, CardBody, CardHeader } from '@/components/heroui/Card'
import { formatNumber, formatPersonName } from '@/helpers'
import { formatIranianMobile, formatPersianDate } from '@/lib/formatters'
import {
fetchEventGuestListLinks,
fetchEventInvitedGuests,
type EventGuestListLink,
type EventInvitedGuest,
} from '@/services/eventGuestListAccess'
import { format, texts } from '@/texts'
interface EventGuestListAccessPanelProps {
eventId: string
}
const EventGuestListAccessPanel = ({ eventId }: EventGuestListAccessPanelProps) => {
const [links, setLinks] = useState<EventGuestListLink[]>([])
const [invitedGuests, setInvitedGuests] = useState<EventInvitedGuest[]>([])
const [isLoading, setIsLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
useEffect(() => {
let cancelled = false
const load = async () => {
try {
setIsLoading(true)
setError(null)
const [nextLinks, nextInvitedGuests] = await Promise.all([
fetchEventGuestListLinks(eventId),
fetchEventInvitedGuests(eventId),
])
if (!cancelled) {
setLinks(nextLinks)
setInvitedGuests(nextInvitedGuests)
}
} catch {
if (!cancelled) setError(texts.events.guestAccessLoadFailed)
} finally {
if (!cancelled) setIsLoading(false)
}
}
void load()
return () => {
cancelled = true
}
}, [eventId])
return (
<Card className="admin-surface">
<CardHeader className="border-b border-consumer-border px-4 py-3 text-sm font-bold text-consumer-text">
{texts.events.guestAccessTitle}
</CardHeader>
<CardBody className="space-y-5 p-3">
{isLoading ? <p className="text-sm text-secondary-20">{texts.events.guestAccessLoading}</p> : null}
{error ? <p className="text-sm text-fourth-900">{error}</p> : null}
{!isLoading && !error ? (
<>
<section>
<div className="mb-2 flex items-center justify-between gap-3">
<h2 className="text-sm font-bold text-consumer-text">{texts.events.guestListsConnected}</h2>
<span className="text-xs text-secondary-20">
{format(texts.events.guestListsCount, { count: formatNumber(links.length) })}
</span>
</div>
{links.length ? (
<div className="grid gap-2">
{links.map((link) => (
<div
key={link.listId}
className="rounded-consumer-control border border-consumer-border bg-consumer-surface-muted/60 p-3"
>
<p className="text-sm font-semibold text-consumer-text">{link.listName ?? texts.events.guestListFallback}</p>
<p className="mt-1 text-xs text-secondary-20">
{link.notifiedAt
? format(texts.events.guestListNotifiedAt, { date: formatPersianDate(String(link.notifiedAt)) })
: texts.events.guestListNotNotified}
</p>
</div>
))}
</div>
) : (
<p className="text-sm text-secondary-20">{texts.events.guestListsEmpty}</p>
)}
</section>
<section>
<div className="mb-2 flex items-center justify-between gap-3">
<h2 className="text-sm font-bold text-consumer-text">{texts.events.invitedGuestsTitle}</h2>
<span className="text-xs text-secondary-20">
{format(texts.events.personCount, { count: formatNumber(invitedGuests.length) })}
</span>
</div>
{invitedGuests.length ? (
<div className="grid gap-2">
{invitedGuests.map((guest, index) => (
<div
key={guest.userId ?? `${guest.mobile}-${index}`}
className="rounded-consumer-control border border-consumer-border bg-consumer-surface-muted/60 p-3"
>
<p className="text-sm font-semibold text-consumer-text">{formatPersonName(guest.firstName, guest.lastName)}</p>
<p
className="mt-1 text-xs text-secondary-20"
dir="ltr"
>
{formatIranianMobile(guest.mobile)}
</p>
</div>
))}
</div>
) : (
<p className="text-sm text-secondary-20">{texts.events.invitedGuestsEmpty}</p>
)}
</section>
</>
) : null}
</CardBody>
</Card>
)
}
export default EventGuestListAccessPanel