@burdenoff/microfe-eventfullymanaged 2026.704.7 → 2026.710.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/dist/dev/main.d.ts +2 -0
  2. package/dist/dev/main.d.ts.map +1 -0
  3. package/dist/eventfullymanaged/EventfullyManagedRoot.d.ts +4 -0
  4. package/dist/eventfullymanaged/EventfullyManagedRoot.d.ts.map +1 -0
  5. package/dist/eventfullymanaged/EventfullyManagedRoutes.d.ts +2 -0
  6. package/dist/eventfullymanaged/EventfullyManagedRoutes.d.ts.map +1 -0
  7. package/dist/eventfullymanaged/api/eventApi.d.ts +1185 -0
  8. package/dist/eventfullymanaged/api/eventApi.d.ts.map +1 -0
  9. package/dist/eventfullymanaged/components/ActionMenu.d.ts +45 -0
  10. package/dist/eventfullymanaged/components/ActionMenu.d.ts.map +1 -0
  11. package/dist/eventfullymanaged/components/EntityFormShell.d.ts +27 -0
  12. package/dist/eventfullymanaged/components/EntityFormShell.d.ts.map +1 -0
  13. package/dist/eventfullymanaged/components/EntityTagsField.d.ts +19 -0
  14. package/dist/eventfullymanaged/components/EntityTagsField.d.ts.map +1 -0
  15. package/dist/eventfullymanaged/components/EventCharts.d.ts +44 -0
  16. package/dist/eventfullymanaged/components/EventCharts.d.ts.map +1 -0
  17. package/dist/eventfullymanaged/components/EventCharts.js.map +1 -1
  18. package/dist/eventfullymanaged/components/ImageUploadField.d.ts +24 -0
  19. package/dist/eventfullymanaged/components/ImageUploadField.d.ts.map +1 -0
  20. package/dist/eventfullymanaged/components/PageLayout.d.ts +14 -0
  21. package/dist/eventfullymanaged/components/PageLayout.d.ts.map +1 -0
  22. package/dist/eventfullymanaged/components/Pagination.d.ts +41 -0
  23. package/dist/eventfullymanaged/components/Pagination.d.ts.map +1 -0
  24. package/dist/eventfullymanaged/components/SafeLink.d.ts +30 -0
  25. package/dist/eventfullymanaged/components/SafeLink.d.ts.map +1 -0
  26. package/dist/eventfullymanaged/components/index.d.ts +13 -0
  27. package/dist/eventfullymanaged/components/index.d.ts.map +1 -0
  28. package/dist/eventfullymanaged/context/EventfullyManagedContext.d.ts +25 -0
  29. package/dist/eventfullymanaged/context/EventfullyManagedContext.d.ts.map +1 -0
  30. package/dist/eventfullymanaged/hooks/index.d.ts +3 -0
  31. package/dist/eventfullymanaged/hooks/index.d.ts.map +1 -0
  32. package/dist/eventfullymanaged/index.d.ts +27 -0
  33. package/dist/eventfullymanaged/index.d.ts.map +1 -0
  34. package/dist/eventfullymanaged/lib/format.d.ts +18 -0
  35. package/dist/eventfullymanaged/lib/format.d.ts.map +1 -0
  36. package/dist/eventfullymanaged/lib/mutationResult.d.ts +23 -0
  37. package/dist/eventfullymanaged/lib/mutationResult.d.ts.map +1 -0
  38. package/dist/eventfullymanaged/lib/toast.d.ts +22 -0
  39. package/dist/eventfullymanaged/lib/toast.d.ts.map +1 -0
  40. package/dist/eventfullymanaged/pages/dashboard/DashboardPage.d.ts +2 -0
  41. package/dist/eventfullymanaged/pages/dashboard/DashboardPage.d.ts.map +1 -0
  42. package/dist/eventfullymanaged/pages/dashboard/DashboardPage.js.map +1 -1
  43. package/dist/eventfullymanaged/pages/events/EventDetailPage.d.ts +2 -0
  44. package/dist/eventfullymanaged/pages/events/EventDetailPage.d.ts.map +1 -0
  45. package/dist/eventfullymanaged/pages/events/EventDetailPage.js +1 -2
  46. package/dist/eventfullymanaged/pages/events/EventDetailPage.js.map +1 -1
  47. package/dist/eventfullymanaged/pages/events/EventFormPage.d.ts +2 -0
  48. package/dist/eventfullymanaged/pages/events/EventFormPage.d.ts.map +1 -0
  49. package/dist/eventfullymanaged/pages/events/SessionFormPage.d.ts +2 -0
  50. package/dist/eventfullymanaged/pages/events/SessionFormPage.d.ts.map +1 -0
  51. package/dist/eventfullymanaged/pages/events/TicketTypeFormPage.d.ts +2 -0
  52. package/dist/eventfullymanaged/pages/events/TicketTypeFormPage.d.ts.map +1 -0
  53. package/dist/eventfullymanaged/pages/events/eventFormUtils.d.ts +40 -0
  54. package/dist/eventfullymanaged/pages/events/eventFormUtils.d.ts.map +1 -0
  55. package/dist/eventfullymanaged/pages/exhibitors/ExhibitorFormPage.d.ts +2 -0
  56. package/dist/eventfullymanaged/pages/exhibitors/ExhibitorFormPage.d.ts.map +1 -0
  57. package/dist/eventfullymanaged/pages/exhibitors/ExhibitorsPage.d.ts +2 -0
  58. package/dist/eventfullymanaged/pages/exhibitors/ExhibitorsPage.d.ts.map +1 -0
  59. package/dist/eventfullymanaged/pages/leads/LeadCaptureDialog.d.ts +23 -0
  60. package/dist/eventfullymanaged/pages/leads/LeadCaptureDialog.d.ts.map +1 -0
  61. package/dist/eventfullymanaged/pages/modules/AnalyticsPage.d.ts +2 -0
  62. package/dist/eventfullymanaged/pages/modules/AnalyticsPage.d.ts.map +1 -0
  63. package/dist/eventfullymanaged/pages/modules/AnalyticsPage.js.map +1 -1
  64. package/dist/eventfullymanaged/pages/modules/AttendeeProfilePage.d.ts +2 -0
  65. package/dist/eventfullymanaged/pages/modules/AttendeeProfilePage.d.ts.map +1 -0
  66. package/dist/eventfullymanaged/pages/modules/CommunicationPage.d.ts +2 -0
  67. package/dist/eventfullymanaged/pages/modules/CommunicationPage.d.ts.map +1 -0
  68. package/dist/eventfullymanaged/pages/modules/CommunicationPage.js.map +1 -1
  69. package/dist/eventfullymanaged/pages/modules/EntityListSection.d.ts +16 -0
  70. package/dist/eventfullymanaged/pages/modules/EntityListSection.d.ts.map +1 -0
  71. package/dist/eventfullymanaged/pages/modules/EventsPage.d.ts +2 -0
  72. package/dist/eventfullymanaged/pages/modules/EventsPage.d.ts.map +1 -0
  73. package/dist/eventfullymanaged/pages/modules/EventsPage.js +223 -118
  74. package/dist/eventfullymanaged/pages/modules/EventsPage.js.map +1 -1
  75. package/dist/eventfullymanaged/pages/modules/KioskPage.d.ts +19 -0
  76. package/dist/eventfullymanaged/pages/modules/KioskPage.d.ts.map +1 -0
  77. package/dist/eventfullymanaged/pages/modules/NetworkingPage.d.ts +2 -0
  78. package/dist/eventfullymanaged/pages/modules/NetworkingPage.d.ts.map +1 -0
  79. package/dist/eventfullymanaged/pages/modules/OperationsHubPage.d.ts +9 -0
  80. package/dist/eventfullymanaged/pages/modules/OperationsHubPage.d.ts.map +1 -0
  81. package/dist/eventfullymanaged/pages/modules/RegistrationPage.d.ts +2 -0
  82. package/dist/eventfullymanaged/pages/modules/RegistrationPage.d.ts.map +1 -0
  83. package/dist/eventfullymanaged/pages/modules/RegistrationPage.js.map +1 -1
  84. package/dist/eventfullymanaged/pages/modules/RoadmapPanel.d.ts +24 -0
  85. package/dist/eventfullymanaged/pages/modules/RoadmapPanel.d.ts.map +1 -0
  86. package/dist/eventfullymanaged/pages/modules/SponsorDetailsPage.d.ts +2 -0
  87. package/dist/eventfullymanaged/pages/modules/SponsorDetailsPage.d.ts.map +1 -0
  88. package/dist/eventfullymanaged/pages/modules/SponsorDetailsPage.js.map +1 -1
  89. package/dist/eventfullymanaged/pages/modules/SponsorLeadsPage.d.ts +2 -0
  90. package/dist/eventfullymanaged/pages/modules/SponsorLeadsPage.d.ts.map +1 -0
  91. package/dist/eventfullymanaged/pages/modules/VenueResourcesPage.d.ts +2 -0
  92. package/dist/eventfullymanaged/pages/modules/VenueResourcesPage.d.ts.map +1 -0
  93. package/dist/eventfullymanaged/pages/modules/WorkflowsPage.d.ts +2 -0
  94. package/dist/eventfullymanaged/pages/modules/WorkflowsPage.d.ts.map +1 -0
  95. package/dist/eventfullymanaged/pages/networking/MeetingFormPage.d.ts +2 -0
  96. package/dist/eventfullymanaged/pages/networking/MeetingFormPage.d.ts.map +1 -0
  97. package/dist/eventfullymanaged/pages/networking/NetworkingProfileFormPage.d.ts +2 -0
  98. package/dist/eventfullymanaged/pages/networking/NetworkingProfileFormPage.d.ts.map +1 -0
  99. package/dist/eventfullymanaged/pages/registration/AttendeeFormPage.d.ts +2 -0
  100. package/dist/eventfullymanaged/pages/registration/AttendeeFormPage.d.ts.map +1 -0
  101. package/dist/eventfullymanaged/pages/registration/AttendeeFormPage.js.map +1 -1
  102. package/dist/eventfullymanaged/pages/registration/PromoCodeFormPage.d.ts +2 -0
  103. package/dist/eventfullymanaged/pages/registration/PromoCodeFormPage.d.ts.map +1 -0
  104. package/dist/eventfullymanaged/pages/registration/RegisterAttendeePage.d.ts +2 -0
  105. package/dist/eventfullymanaged/pages/registration/RegisterAttendeePage.d.ts.map +1 -0
  106. package/dist/eventfullymanaged/pages/registration/RegisterAttendeePage.js.map +1 -1
  107. package/dist/eventfullymanaged/pages/speakers/SpeakerFormPage.d.ts +2 -0
  108. package/dist/eventfullymanaged/pages/speakers/SpeakerFormPage.d.ts.map +1 -0
  109. package/dist/eventfullymanaged/pages/speakers/SpeakersPage.d.ts +2 -0
  110. package/dist/eventfullymanaged/pages/speakers/SpeakersPage.d.ts.map +1 -0
  111. package/dist/eventfullymanaged/pages/speakers/SpeakersPage.js.map +1 -1
  112. package/dist/eventfullymanaged/pages/sponsors/SponsorFormPage.d.ts +2 -0
  113. package/dist/eventfullymanaged/pages/sponsors/SponsorFormPage.d.ts.map +1 -0
  114. package/dist/eventfullymanaged/pages/sponsors/SponsorsListPage.d.ts +2 -0
  115. package/dist/eventfullymanaged/pages/sponsors/SponsorsListPage.d.ts.map +1 -0
  116. package/dist/eventfullymanaged/pages/sponsors/SponsorsListPage.js.map +1 -1
  117. package/dist/eventfullymanaged/pages/venues/FloorPlansPage.d.ts +2 -0
  118. package/dist/eventfullymanaged/pages/venues/FloorPlansPage.d.ts.map +1 -0
  119. package/dist/eventfullymanaged/pages/venues/FloorPlansPage.js.map +1 -1
  120. package/dist/eventfullymanaged/pages/venues/VenueDetailPage.d.ts +2 -0
  121. package/dist/eventfullymanaged/pages/venues/VenueDetailPage.d.ts.map +1 -0
  122. package/dist/eventfullymanaged/pages/venues/VenueDetailPage.js.map +1 -1
  123. package/dist/eventfullymanaged/pages/venues/VenueFormPage.d.ts +2 -0
  124. package/dist/eventfullymanaged/pages/venues/VenueFormPage.d.ts.map +1 -0
  125. package/dist/eventfullymanaged/pages/venues/VenueListPage.d.ts +2 -0
  126. package/dist/eventfullymanaged/pages/venues/VenueListPage.d.ts.map +1 -0
  127. package/dist/eventfullymanaged/store/eventfullyManagedStore.d.ts +47 -0
  128. package/dist/eventfullymanaged/store/eventfullyManagedStore.d.ts.map +1 -0
  129. package/dist/eventfullymanaged/types/index.d.ts +3649 -0
  130. package/dist/eventfullymanaged/types/index.d.ts.map +1 -0
  131. package/dist/eventfullymanaged/utils/cn.d.ts +2 -0
  132. package/dist/eventfullymanaged/utils/cn.d.ts.map +1 -0
  133. package/dist/eventfullymanaged/utils/constants.d.ts +3 -0
  134. package/dist/eventfullymanaged/utils/constants.d.ts.map +1 -0
  135. package/dist/eventfullymanaged/utils/navigation.d.ts +2 -0
  136. package/dist/eventfullymanaged/utils/navigation.d.ts.map +1 -0
  137. package/dist/generated/global-operations.d.ts +2 -0
  138. package/dist/generated/global-operations.d.ts.map +1 -0
  139. package/dist/generated/global-types.d.ts +23527 -0
  140. package/dist/generated/global-types.d.ts.map +1 -0
  141. package/dist/generated/wspace-operations.d.ts +2 -0
  142. package/dist/generated/wspace-operations.d.ts.map +1 -0
  143. package/dist/generated/wspace-types.d.ts +57851 -0
  144. package/dist/generated/wspace-types.d.ts.map +1 -0
  145. package/dist/index.d.ts +9 -0
  146. package/dist/index.d.ts.map +1 -0
  147. package/dist/index.js +2 -1
  148. package/dist/services/createSandboxAssistantTransport.d.ts +33 -0
  149. package/dist/services/createSandboxAssistantTransport.d.ts.map +1 -0
  150. package/dist/services/createSandboxAssistantTransport.js +19 -0
  151. package/dist/services/createSandboxAssistantTransport.js.map +1 -0
  152. package/package.json +7 -3
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../../src/eventfullymanaged/pages/dashboard/DashboardPage.tsx"],"sourcesContent":["import { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport {\n Building2,\n CalendarClock,\n CalendarDays,\n ChevronRight,\n Handshake,\n PlayCircle,\n Ticket,\n UserPlus,\n Users,\n} from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { GlassCard, GradientText, IllustratedEmptyState, NextSteps, PagePurpose, Skeleton } from '@burdenoff/fe-libs/ui';\nimport { useMemo, useState } from 'react';\n\nimport { useDashboardSummaryQuery } from '../../api/eventApi';\nimport { EventAreaChart, type AreaPoint } from '../../components/EventCharts';\nimport { PageLayout } from '../../components/PageLayout';\nimport { useEventfullyManaged } from '../../context/EventfullyManagedContext';\nimport { formatDateTime } from '../events/eventFormUtils';\n\n// ---------------------------------------------------------------------------\n// Real supporting data for the trend chart + upcoming-sessions panel. Both are\n// dedicated operations (distinct names) so they can select the exact fields the\n// dashboard needs without touching the shared list hooks.\n// ---------------------------------------------------------------------------\n\nconst DASHBOARD_REGISTRATIONS_QUERY = gql`\n query EventfullymanagedDashboardRegistrations($limit: Int) {\n registrations: eventfullyManagedRegistrations(limit: $limit, offset: 0) {\n total\n items {\n id\n status\n registeredAt\n }\n }\n }\n`;\n\nconst DASHBOARD_UPCOMING_SESSIONS_QUERY = gql`\n query EventfullymanagedDashboardUpcomingSessions($limit: Int) {\n eventSessions: eventfullyManagedEventSessions(limit: $limit, offset: 0) {\n total\n items {\n id\n eventId\n title\n sessionType\n track\n startsAt\n endsAt\n status\n }\n }\n }\n`;\n\ntype DashboardRegistration = { id: string; status: string; registeredAt: string };\ntype DashboardRegistrationsResponse = { registrations: { total: number; items: DashboardRegistration[] } };\n\ntype DashboardSession = {\n id: string;\n eventId: string;\n title: string;\n sessionType: string;\n track?: string | null;\n startsAt: string;\n endsAt: string;\n status: string;\n};\ntype DashboardSessionsResponse = { eventSessions: { total: number; items: DashboardSession[] } };\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\nconst TREND_DAYS = 30;\n\n/** Build a cumulative registrations-over-time series from real `registeredAt` timestamps. */\nfunction buildTrendSeries(registrations: DashboardRegistration[], nowMs: number): AreaPoint[] {\n const now = new Date(nowMs);\n const start = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n start.setTime(start.getTime() - (TREND_DAYS - 1) * DAY_MS);\n\n const perDay = new Array<number>(TREND_DAYS).fill(0);\n let baseline = 0; // registrations older than the window still count toward the cumulative total.\n\n for (const registration of registrations) {\n const when = new Date(registration.registeredAt);\n if (Number.isNaN(when.getTime())) {\n continue;\n }\n const dayIndex = Math.floor((when.getTime() - start.getTime()) / DAY_MS);\n if (dayIndex < 0) {\n baseline += 1;\n } else if (dayIndex < TREND_DAYS) {\n perDay[dayIndex] += 1;\n }\n }\n\n let running = baseline;\n return perDay.map((count, index) => {\n running += count;\n const day = new Date(start.getTime() + index * DAY_MS);\n return {\n label: day.toLocaleDateString(undefined, { month: 'short', day: 'numeric' }),\n value: running,\n };\n });\n}\n\ntype StatCard = {\n label: string;\n value: number;\n sublabel: string;\n icon: React.ComponentType<{ className?: string }>;\n path: string;\n featured?: boolean;\n};\n\nexport default function DashboardPage() {\n const { t: translate } = useI18n();\n const t = (key: string, fallback: string) => {\n const value = translate(key);\n return value === key ? fallback : value;\n };\n const { navigate } = useEventfullyManaged();\n const { data, loading } = useDashboardSummaryQuery();\n const { data: registrationsData, loading: registrationsLoading } = useQuery<\n DashboardRegistrationsResponse,\n { limit: number }\n >(DASHBOARD_REGISTRATIONS_QUERY, { variables: { limit: 500 } });\n const { data: sessionsData, loading: sessionsLoading } = useQuery<DashboardSessionsResponse, { limit: number }>(\n DASHBOARD_UPCOMING_SESSIONS_QUERY,\n { variables: { limit: 100 } }\n );\n\n const summary = data?.dashboardSummary;\n // Capture \"now\" once (state initialisers may run impure code) so the memoised\n // trend + upcoming filters stay pure across re-renders.\n const [nowMs] = useState(() => Date.now());\n\n const trend = useMemo(\n () => buildTrendSeries(registrationsData?.registrations?.items ?? [], nowMs),\n [registrationsData, nowMs]\n );\n\n const upcomingSessions = useMemo(() => {\n return (sessionsData?.eventSessions?.items ?? [])\n .filter((session) => {\n const startMs = new Date(session.startsAt).getTime();\n return !Number.isNaN(startMs) && startMs >= nowMs;\n })\n .sort((a, b) => new Date(a.startsAt).getTime() - new Date(b.startsAt).getTime())\n .slice(0, 4);\n }, [sessionsData, nowMs]);\n\n const cards: StatCard[] = [\n {\n label: t('eventfullymanaged.dashboard.cards.totalEvents', 'Total Events'),\n value: summary?.totalEvents ?? 0,\n sublabel: t('eventfullymanaged.dashboard.cards.totalEventsSub', 'across your workspace'),\n icon: CalendarDays,\n path: '/events',\n featured: true,\n },\n {\n label: t('eventfullymanaged.dashboard.cards.activeEvents', 'Active Events'),\n value: summary?.activeEvents ?? 0,\n sublabel: t('eventfullymanaged.dashboard.cards.activeEventsSub', 'live or published now'),\n icon: PlayCircle,\n path: '/events',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.registrations', 'Registrations'),\n value: summary?.totalRegistrations ?? 0,\n sublabel: t('eventfullymanaged.dashboard.cards.registrationsSub', 'sign-ups received'),\n icon: UserPlus,\n path: '/registration',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.attendees', 'Attendees'),\n value: summary?.totalAttendees ?? 0,\n sublabel: t('eventfullymanaged.dashboard.cards.attendeesSub', 'people in your audience'),\n icon: Users,\n path: '/registration',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.venues', 'Venues'),\n value: summary?.totalVenues ?? 0,\n sublabel: t('eventfullymanaged.dashboard.cards.venuesSub', 'spaces mapped'),\n icon: Building2,\n path: '/venues',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.sponsors', 'Sponsors'),\n value: summary?.totalSponsors ?? 0,\n sublabel: t('eventfullymanaged.dashboard.cards.sponsorsSub', 'partners onboarded'),\n icon: Handshake,\n path: '/sponsors',\n },\n ];\n\n return (\n <PageLayout\n hero\n title={<GradientText as=\"span\">{t('eventfullymanaged.dashboard.title', 'Dashboard')}</GradientText>}\n description={\n loading\n ? t('eventfullymanaged.dashboard.description.loading', 'Loading real-time event operations summary…')\n : t('eventfullymanaged.dashboard.description.ready', 'Your live event operations, at a glance.')\n }\n >\n <PagePurpose className=\"mb-6\">\n {t(\n 'eventfullymanaged.dashboard.purpose',\n 'Your event control center. Each tile below is a live count from a different part of your event operations. Open any tile to manage that area, watch registrations climb in the trend chart, and jump straight to the sessions coming up next.'\n )}\n </PagePurpose>\n\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3 xl:grid-cols-6\">\n {cards.map((card) => {\n const Icon = card.icon;\n return (\n <GlassCard\n key={card.label}\n treatment={card.featured ? 'glass' : 'metric'}\n glow={card.featured}\n role=\"button\"\n tabIndex={0}\n aria-label={`${card.label}: ${card.value.toLocaleString()}`}\n onClick={() => navigate(card.path)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n navigate(card.path);\n }\n }}\n className=\"group cursor-pointer p-4 outline-none transition-[transform,box-shadow] duration-200 hover:shadow-elevation-1 focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <span className=\"flex h-9 w-9 items-center justify-center rounded-button bg-accent-wash text-action-primary-bg\">\n <Icon className=\"h-5 w-5\" />\n </span>\n <div className=\"mt-3 text-2xl font-semibold tabular-nums text-text-primary\">\n {loading ? <Skeleton className=\"h-7 w-14\" /> : card.value.toLocaleString()}\n </div>\n <div className=\"mt-1 text-sm font-medium text-text-primary\">{card.label}</div>\n <div className=\"mt-0.5 truncate text-xs text-text-muted\">{card.sublabel}</div>\n </GlassCard>\n );\n })}\n </div>\n\n <div className=\"mt-6 grid grid-cols-1 gap-4 lg:grid-cols-5\">\n <GlassCard treatment=\"glass\" className=\"p-5 lg:col-span-3\">\n <div className=\"flex items-start justify-between gap-4\">\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {t('eventfullymanaged.dashboard.trend.title', 'Registrations over time')}\n </h2>\n <p className=\"mt-0.5 text-xs text-text-muted\">\n {t('eventfullymanaged.dashboard.trend.subtitle', 'Cumulative sign-ups, last 30 days')}\n </p>\n </div>\n <div className=\"text-2xl font-semibold tabular-nums text-text-primary\">\n {(summary?.totalRegistrations ?? 0).toLocaleString()}\n </div>\n </div>\n <div className=\"mt-4\">\n {registrationsLoading ? (\n <Skeleton className=\"h-[260px] w-full rounded-card\" />\n ) : trend.some((point) => point.value > 0) ? (\n <EventAreaChart data={trend} />\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('eventfullymanaged.dashboard.trend.empty', 'No registrations yet.')}\n description={t(\n 'eventfullymanaged.dashboard.trend.emptyHint',\n 'Once attendees start signing up, their momentum shows here.'\n )}\n className=\"py-10\"\n />\n )}\n </div>\n </GlassCard>\n\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-5 lg:col-span-2\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {t('eventfullymanaged.dashboard.upcoming.title', 'Upcoming sessions')}\n </h2>\n <div className=\"mt-3\">\n {sessionsLoading ? (\n <div className=\"space-y-3\">\n <Skeleton className=\"h-14 w-full rounded-card\" />\n <Skeleton className=\"h-14 w-full rounded-card\" />\n <Skeleton className=\"h-14 w-full rounded-card\" />\n </div>\n ) : upcomingSessions.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('eventfullymanaged.dashboard.upcoming.empty', 'Nothing scheduled yet.')}\n description={t(\n 'eventfullymanaged.dashboard.upcoming.emptyHint',\n 'Sessions you schedule will surface here as they approach.'\n )}\n className=\"py-8\"\n />\n ) : (\n <ul className=\"divide-y divide-border-subtle\">\n {upcomingSessions.map((session) => (\n <li key={session.id}>\n <button\n type=\"button\"\n onClick={() => navigate(`/events/${session.eventId}`)}\n className=\"group flex w-full items-center gap-3 py-3 text-left outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <span className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-button bg-accent-wash text-action-primary-bg\">\n <CalendarClock className=\"h-4 w-4\" />\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm font-medium text-text-primary\">{session.title}</span>\n <span className=\"mt-0.5 block truncate text-xs text-text-muted\">\n {[formatDateTime(session.startsAt), session.track].filter(Boolean).join(' • ')}\n </span>\n </span>\n <ChevronRight className=\"h-4 w-4 shrink-0 text-text-muted transition-transform group-hover:translate-x-0.5\" />\n </button>\n </li>\n ))}\n </ul>\n )}\n </div>\n </GlassCard>\n </div>\n\n <NextSteps\n className=\"mt-6\"\n storageKey=\"eventfullymanaged-dashboard\"\n title={t('eventfullymanaged.dashboard.nextSteps.title', 'Get your first event running')}\n steps={[\n {\n id: 'create-event',\n label: t('eventfullymanaged.dashboard.nextSteps.createEvent', 'Create an event'),\n description: t(\n 'eventfullymanaged.dashboard.nextSteps.createEventDesc',\n 'Start with the basics — name, dates and capacity.'\n ),\n icon: <CalendarDays className=\"h-4 w-4\" />,\n onClick: () => navigate('/events/create'),\n },\n {\n id: 'add-venue',\n label: t('eventfullymanaged.dashboard.nextSteps.addVenue', 'Add a venue'),\n description: t(\n 'eventfullymanaged.dashboard.nextSteps.addVenueDesc',\n 'Map your event to a space with capacity and floor plans.'\n ),\n icon: <Building2 className=\"h-4 w-4\" />,\n onClick: () => navigate('/venues/create'),\n },\n {\n id: 'open-registration',\n label: t('eventfullymanaged.dashboard.nextSteps.openRegistration', 'Open registration'),\n description: t(\n 'eventfullymanaged.dashboard.nextSteps.openRegistrationDesc',\n 'Set up ticket types and track attendee sign-ups.'\n ),\n icon: <Ticket className=\"h-4 w-4\" />,\n onClick: () => navigate('/registration'),\n },\n {\n id: 'invite-sponsors',\n label: t('eventfullymanaged.dashboard.nextSteps.inviteSponsors', 'Onboard sponsors'),\n description: t(\n 'eventfullymanaged.dashboard.nextSteps.inviteSponsorsDesc',\n 'Add sponsors and start tracking value and leads.'\n ),\n icon: <Handshake className=\"h-4 w-4\" />,\n onClick: () => navigate('/sponsors'),\n },\n ]}\n />\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../../src/eventfullymanaged/pages/dashboard/DashboardPage.tsx"],"sourcesContent":["import { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport {\n Building2,\n CalendarClock,\n CalendarDays,\n ChevronRight,\n Handshake,\n PlayCircle,\n Ticket,\n UserPlus,\n Users,\n} from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n NextSteps,\n PagePurpose,\n Skeleton,\n} from '@burdenoff/fe-libs/ui';\nimport { useMemo, useState } from 'react';\n\nimport { useDashboardSummaryQuery } from '../../api/eventApi';\nimport { EventAreaChart, type AreaPoint } from '../../components/EventCharts';\nimport { PageLayout } from '../../components/PageLayout';\nimport { useEventfullyManaged } from '../../context/EventfullyManagedContext';\nimport { formatDateTime } from '../events/eventFormUtils';\n\n// ---------------------------------------------------------------------------\n// Real supporting data for the trend chart + upcoming-sessions panel. Both are\n// dedicated operations (distinct names) so they can select the exact fields the\n// dashboard needs without touching the shared list hooks.\n// ---------------------------------------------------------------------------\n\nconst DASHBOARD_REGISTRATIONS_QUERY = gql`\n query EventfullymanagedDashboardRegistrations($limit: Int) {\n registrations: eventfullyManagedRegistrations(limit: $limit, offset: 0) {\n total\n items {\n id\n status\n registeredAt\n }\n }\n }\n`;\n\nconst DASHBOARD_UPCOMING_SESSIONS_QUERY = gql`\n query EventfullymanagedDashboardUpcomingSessions($limit: Int) {\n eventSessions: eventfullyManagedEventSessions(limit: $limit, offset: 0) {\n total\n items {\n id\n eventId\n title\n sessionType\n track\n startsAt\n endsAt\n status\n }\n }\n }\n`;\n\ntype DashboardRegistration = { id: string; status: string; registeredAt: string };\ntype DashboardRegistrationsResponse = { registrations: { total: number; items: DashboardRegistration[] } };\n\ntype DashboardSession = {\n id: string;\n eventId: string;\n title: string;\n sessionType: string;\n track?: string | null;\n startsAt: string;\n endsAt: string;\n status: string;\n};\ntype DashboardSessionsResponse = { eventSessions: { total: number; items: DashboardSession[] } };\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\nconst TREND_DAYS = 30;\n\n/** Build a cumulative registrations-over-time series from real `registeredAt` timestamps. */\nfunction buildTrendSeries(registrations: DashboardRegistration[], nowMs: number): AreaPoint[] {\n const now = new Date(nowMs);\n const start = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n start.setTime(start.getTime() - (TREND_DAYS - 1) * DAY_MS);\n\n const perDay = new Array<number>(TREND_DAYS).fill(0);\n let baseline = 0; // registrations older than the window still count toward the cumulative total.\n\n for (const registration of registrations) {\n const when = new Date(registration.registeredAt);\n if (Number.isNaN(when.getTime())) {\n continue;\n }\n const dayIndex = Math.floor((when.getTime() - start.getTime()) / DAY_MS);\n if (dayIndex < 0) {\n baseline += 1;\n } else if (dayIndex < TREND_DAYS) {\n perDay[dayIndex] += 1;\n }\n }\n\n let running = baseline;\n return perDay.map((count, index) => {\n running += count;\n const day = new Date(start.getTime() + index * DAY_MS);\n return {\n label: day.toLocaleDateString(undefined, { month: 'short', day: 'numeric' }),\n value: running,\n };\n });\n}\n\ntype StatCard = {\n label: string;\n value: number;\n sublabel: string;\n icon: React.ComponentType<{ className?: string }>;\n path: string;\n featured?: boolean;\n};\n\nexport default function DashboardPage() {\n const { t: translate } = useI18n();\n const t = (key: string, fallback: string) => {\n const value = translate(key);\n return value === key ? fallback : value;\n };\n const { navigate } = useEventfullyManaged();\n const { data, loading } = useDashboardSummaryQuery();\n const { data: registrationsData, loading: registrationsLoading } = useQuery<\n DashboardRegistrationsResponse,\n { limit: number }\n >(DASHBOARD_REGISTRATIONS_QUERY, { variables: { limit: 500 } });\n const { data: sessionsData, loading: sessionsLoading } = useQuery<DashboardSessionsResponse, { limit: number }>(\n DASHBOARD_UPCOMING_SESSIONS_QUERY,\n { variables: { limit: 100 } }\n );\n\n const summary = data?.dashboardSummary;\n // Capture \"now\" once (state initialisers may run impure code) so the memoised\n // trend + upcoming filters stay pure across re-renders.\n const [nowMs] = useState(() => Date.now());\n\n const trend = useMemo(\n () => buildTrendSeries(registrationsData?.registrations?.items ?? [], nowMs),\n [registrationsData, nowMs]\n );\n\n const upcomingSessions = useMemo(() => {\n return (sessionsData?.eventSessions?.items ?? [])\n .filter((session) => {\n const startMs = new Date(session.startsAt).getTime();\n return !Number.isNaN(startMs) && startMs >= nowMs;\n })\n .sort((a, b) => new Date(a.startsAt).getTime() - new Date(b.startsAt).getTime())\n .slice(0, 4);\n }, [sessionsData, nowMs]);\n\n const cards: StatCard[] = [\n {\n label: t('eventfullymanaged.dashboard.cards.totalEvents', 'Total Events'),\n value: summary?.totalEvents ?? 0,\n sublabel: t('eventfullymanaged.dashboard.cards.totalEventsSub', 'across your workspace'),\n icon: CalendarDays,\n path: '/events',\n featured: true,\n },\n {\n label: t('eventfullymanaged.dashboard.cards.activeEvents', 'Active Events'),\n value: summary?.activeEvents ?? 0,\n sublabel: t('eventfullymanaged.dashboard.cards.activeEventsSub', 'live or published now'),\n icon: PlayCircle,\n path: '/events',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.registrations', 'Registrations'),\n value: summary?.totalRegistrations ?? 0,\n sublabel: t('eventfullymanaged.dashboard.cards.registrationsSub', 'sign-ups received'),\n icon: UserPlus,\n path: '/registration',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.attendees', 'Attendees'),\n value: summary?.totalAttendees ?? 0,\n sublabel: t('eventfullymanaged.dashboard.cards.attendeesSub', 'people in your audience'),\n icon: Users,\n path: '/registration',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.venues', 'Venues'),\n value: summary?.totalVenues ?? 0,\n sublabel: t('eventfullymanaged.dashboard.cards.venuesSub', 'spaces mapped'),\n icon: Building2,\n path: '/venues',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.sponsors', 'Sponsors'),\n value: summary?.totalSponsors ?? 0,\n sublabel: t('eventfullymanaged.dashboard.cards.sponsorsSub', 'partners onboarded'),\n icon: Handshake,\n path: '/sponsors',\n },\n ];\n\n return (\n <PageLayout\n hero\n title={<GradientText as=\"span\">{t('eventfullymanaged.dashboard.title', 'Dashboard')}</GradientText>}\n description={\n loading\n ? t('eventfullymanaged.dashboard.description.loading', 'Loading real-time event operations summary…')\n : t('eventfullymanaged.dashboard.description.ready', 'Your live event operations, at a glance.')\n }\n >\n <PagePurpose className=\"mb-6\">\n {t(\n 'eventfullymanaged.dashboard.purpose',\n 'Your event control center. Each tile below is a live count from a different part of your event operations. Open any tile to manage that area, watch registrations climb in the trend chart, and jump straight to the sessions coming up next.'\n )}\n </PagePurpose>\n\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3 xl:grid-cols-6\">\n {cards.map((card) => {\n const Icon = card.icon;\n return (\n <GlassCard\n key={card.label}\n treatment={card.featured ? 'glass' : 'metric'}\n glow={card.featured}\n role=\"button\"\n tabIndex={0}\n aria-label={`${card.label}: ${card.value.toLocaleString()}`}\n onClick={() => navigate(card.path)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n navigate(card.path);\n }\n }}\n className=\"group cursor-pointer p-4 outline-none transition-[transform,box-shadow] duration-200 hover:shadow-elevation-1 focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <span className=\"flex h-9 w-9 items-center justify-center rounded-button bg-accent-wash text-action-primary-bg\">\n <Icon className=\"h-5 w-5\" />\n </span>\n <div className=\"mt-3 text-2xl font-semibold tabular-nums text-text-primary\">\n {loading ? <Skeleton className=\"h-7 w-14\" /> : card.value.toLocaleString()}\n </div>\n <div className=\"mt-1 text-sm font-medium text-text-primary\">{card.label}</div>\n <div className=\"mt-0.5 truncate text-xs text-text-muted\">{card.sublabel}</div>\n </GlassCard>\n );\n })}\n </div>\n\n <div className=\"mt-6 grid grid-cols-1 gap-4 lg:grid-cols-5\">\n <GlassCard treatment=\"glass\" className=\"p-5 lg:col-span-3\">\n <div className=\"flex items-start justify-between gap-4\">\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {t('eventfullymanaged.dashboard.trend.title', 'Registrations over time')}\n </h2>\n <p className=\"mt-0.5 text-xs text-text-muted\">\n {t('eventfullymanaged.dashboard.trend.subtitle', 'Cumulative sign-ups, last 30 days')}\n </p>\n </div>\n <div className=\"text-2xl font-semibold tabular-nums text-text-primary\">\n {(summary?.totalRegistrations ?? 0).toLocaleString()}\n </div>\n </div>\n <div className=\"mt-4\">\n {registrationsLoading ? (\n <Skeleton className=\"h-[260px] w-full rounded-card\" />\n ) : trend.some((point) => point.value > 0) ? (\n <EventAreaChart data={trend} />\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('eventfullymanaged.dashboard.trend.empty', 'No registrations yet.')}\n description={t(\n 'eventfullymanaged.dashboard.trend.emptyHint',\n 'Once attendees start signing up, their momentum shows here.'\n )}\n className=\"py-10\"\n />\n )}\n </div>\n </GlassCard>\n\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-5 lg:col-span-2\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {t('eventfullymanaged.dashboard.upcoming.title', 'Upcoming sessions')}\n </h2>\n <div className=\"mt-3\">\n {sessionsLoading ? (\n <div className=\"space-y-3\">\n <Skeleton className=\"h-14 w-full rounded-card\" />\n <Skeleton className=\"h-14 w-full rounded-card\" />\n <Skeleton className=\"h-14 w-full rounded-card\" />\n </div>\n ) : upcomingSessions.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('eventfullymanaged.dashboard.upcoming.empty', 'Nothing scheduled yet.')}\n description={t(\n 'eventfullymanaged.dashboard.upcoming.emptyHint',\n 'Sessions you schedule will surface here as they approach.'\n )}\n className=\"py-8\"\n />\n ) : (\n <ul className=\"divide-y divide-border-subtle\">\n {upcomingSessions.map((session) => (\n <li key={session.id}>\n <button\n type=\"button\"\n onClick={() => navigate(`/events/${session.eventId}`)}\n className=\"group flex w-full items-center gap-3 py-3 text-left outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <span className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-button bg-accent-wash text-action-primary-bg\">\n <CalendarClock className=\"h-4 w-4\" />\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm font-medium text-text-primary\">{session.title}</span>\n <span className=\"mt-0.5 block truncate text-xs text-text-muted\">\n {[formatDateTime(session.startsAt), session.track].filter(Boolean).join(' • ')}\n </span>\n </span>\n <ChevronRight className=\"h-4 w-4 shrink-0 text-text-muted transition-transform group-hover:translate-x-0.5\" />\n </button>\n </li>\n ))}\n </ul>\n )}\n </div>\n </GlassCard>\n </div>\n\n <NextSteps\n className=\"mt-6\"\n storageKey=\"eventfullymanaged-dashboard\"\n title={t('eventfullymanaged.dashboard.nextSteps.title', 'Get your first event running')}\n steps={[\n {\n id: 'create-event',\n label: t('eventfullymanaged.dashboard.nextSteps.createEvent', 'Create an event'),\n description: t(\n 'eventfullymanaged.dashboard.nextSteps.createEventDesc',\n 'Start with the basics — name, dates and capacity.'\n ),\n icon: <CalendarDays className=\"h-4 w-4\" />,\n onClick: () => navigate('/events/create'),\n },\n {\n id: 'add-venue',\n label: t('eventfullymanaged.dashboard.nextSteps.addVenue', 'Add a venue'),\n description: t(\n 'eventfullymanaged.dashboard.nextSteps.addVenueDesc',\n 'Map your event to a space with capacity and floor plans.'\n ),\n icon: <Building2 className=\"h-4 w-4\" />,\n onClick: () => navigate('/venues/create'),\n },\n {\n id: 'open-registration',\n label: t('eventfullymanaged.dashboard.nextSteps.openRegistration', 'Open registration'),\n description: t(\n 'eventfullymanaged.dashboard.nextSteps.openRegistrationDesc',\n 'Set up ticket types and track attendee sign-ups.'\n ),\n icon: <Ticket className=\"h-4 w-4\" />,\n onClick: () => navigate('/registration'),\n },\n {\n id: 'invite-sponsors',\n label: t('eventfullymanaged.dashboard.nextSteps.inviteSponsors', 'Onboard sponsors'),\n description: t(\n 'eventfullymanaged.dashboard.nextSteps.inviteSponsorsDesc',\n 'Add sponsors and start tracking value and leads.'\n ),\n icon: <Handshake className=\"h-4 w-4\" />,\n onClick: () => navigate('/sponsors'),\n },\n ]}\n />\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export default function EventDetailPage(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=EventDetailPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EventDetailPage.d.ts","sourceRoot":"","sources":["../../../../src/eventfullymanaged/pages/events/EventDetailPage.tsx"],"names":[],"mappings":"AA6qBA,MAAM,CAAC,OAAO,UAAU,eAAe,4CAyNtC"}
@@ -446,8 +446,7 @@ function Z({ eventId: t }) {
446
446
  " ",
447
447
  "sold",
448
448
  r ? /* @__PURE__ */ x(y, { children: [
449
- " ",
450
- "/ ",
449
+ " / ",
451
450
  e.capacity.toLocaleString(),
452
451
  " capacity"
453
452
  ] }) : " • unlimited capacity"
@@ -1 +1 @@
1
- {"version":3,"file":"EventDetailPage.js","names":[],"sources":["../../../../src/eventfullymanaged/pages/events/EventDetailPage.tsx"],"sourcesContent":["import { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport {\n ArrowLeft,\n CalendarClock,\n Clock,\n Edit,\n Eye,\n MapPin,\n Mic2,\n Plus,\n Ticket as TicketIcon,\n Users,\n} from 'lucide-react';\nimport {\n Badge,\n Button,\n GlassCard,\n IllustratedEmptyState,\n Skeleton,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport { useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\n\nimport {\n useDeleteEventSessionMutation,\n useDeleteSpeakerMutation,\n useDeleteTicketTypeMutation,\n useEventQuery,\n useSpeakersQuery,\n useTicketTypesQuery,\n useVenuesQuery,\n type TicketTypeGql,\n} from '../../api/eventApi';\nimport { ActionMenu } from '../../components/ActionMenu';\nimport { CHART_COLORS } from '../../components/EventCharts';\nimport { Pagination, usePagination } from '../../components/Pagination';\nimport { useEventfullyManaged } from '../../context/EventfullyManagedContext';\nimport { notify } from '../../lib/toast';\nimport { formatDateTime } from './eventFormUtils';\n\nfunction statusVariant(status: string): 'success' | 'warning' | 'secondary' | 'info' {\n const value = status.toLowerCase();\n if (['active', 'published', 'live', 'confirmed', 'completed', 'approved'].includes(value)) {\n return 'success';\n }\n if (['inactive', 'cancelled', 'archived', 'closed', 'expired'].includes(value)) {\n return 'warning';\n }\n if (['draft', 'created', 'pending', 'scheduled'].includes(value)) {\n return 'info';\n }\n return 'secondary';\n}\n\nfunction formatDuration(startsAt: string, endsAt: string): string {\n const start = new Date(startsAt).getTime();\n const end = new Date(endsAt).getTime();\n if (Number.isNaN(start) || Number.isNaN(end) || end <= start) {\n return '';\n }\n const totalMinutes = Math.round((end - start) / 60000);\n const hours = Math.floor(totalMinutes / 60);\n const minutes = totalMinutes % 60;\n if (hours && minutes) {\n return `${hours}h ${minutes}m`;\n }\n if (hours) {\n return `${hours}h`;\n }\n return `${minutes}m`;\n}\n\nfunction formatHour(hour: number): string {\n const period = hour < 12 ? 'AM' : 'PM';\n const display = hour % 12 === 0 ? 12 : hour % 12;\n return `${display}:00 ${period}`;\n}\n\nfunction formatClock(iso: string): string {\n const date = new Date(iso);\n if (Number.isNaN(date.getTime())) {\n return '';\n }\n return date.toLocaleTimeString(undefined, { hour: 'numeric', minute: '2-digit' });\n}\n\n// ---------------------------------------------------------------------------\n// Sessions tab — multi-track schedule grid.\n//\n// The shared EVENT_SESSIONS_QUERY omits `metadata` (which carries speakerId) and\n// `description`/`capacity`, so this tab owns a fuller read that selects them; the\n// grid resolves room names from venues and speaker names from speakers.\n// ---------------------------------------------------------------------------\n\nconst SCHEDULE_SESSIONS_QUERY = gql`\n query EventfullymanagedScheduleSessions($eventId: ID, $limit: Int, $offset: Int) {\n eventSessions: eventfullyManagedEventSessions(eventId: $eventId, limit: $limit, offset: $offset) {\n total\n items {\n id\n eventId\n venueId\n title\n sessionType\n track\n startsAt\n endsAt\n status\n metadata\n }\n }\n }\n`;\n\ntype ScheduleSession = {\n id: string;\n eventId: string;\n venueId?: string | null;\n title: string;\n sessionType: string;\n track?: string | null;\n startsAt: string;\n endsAt: string;\n status: string;\n metadata?: Record<string, unknown> | null;\n};\n\ntype ScheduleSessionsResponse = { eventSessions: { total: number; items: ScheduleSession[] } };\n\nconst UNTRACKED = 'General';\n\nfunction dayKey(iso: string): string {\n const date = new Date(iso);\n return Number.isNaN(date.getTime()) ? 'unknown' : date.toISOString().slice(0, 10);\n}\n\nfunction SessionBlock({\n session,\n color,\n speakerName,\n roomName,\n onEdit,\n onDelete,\n}: {\n session: ScheduleSession;\n color: string;\n speakerName?: string;\n roomName?: string;\n onEdit: () => void;\n onDelete: () => void | Promise<void>;\n}) {\n const duration = formatDuration(session.startsAt, session.endsAt);\n return (\n <div\n className=\"relative rounded-card border border-border-subtle p-3 shadow-elevation-1\"\n style={{\n borderLeftWidth: '3px',\n borderLeftColor: color,\n background: `color-mix(in srgb, ${color} 8%, var(--color-bg-surface))`,\n }}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <p className=\"min-w-0 pr-1 text-sm font-semibold leading-snug text-text-primary\">{session.title}</p>\n <div className=\"-mr-1 -mt-1 shrink-0\">\n <ActionMenu\n ariaLabel={`Session actions for ${session.title}`}\n entityName={session.title}\n deleteLabel=\"Delete session\"\n onEdit={onEdit}\n onDelete={onDelete}\n />\n </div>\n </div>\n <dl className=\"mt-2 space-y-1 text-xs text-text-secondary\">\n <div className=\"flex items-center gap-1.5\">\n <Mic2 className=\"h-3.5 w-3.5 shrink-0 text-text-muted\" />\n <span className=\"truncate\">{speakerName ?? 'Speaker TBD'}</span>\n </div>\n {roomName ? (\n <div className=\"flex items-center gap-1.5\">\n <MapPin className=\"h-3.5 w-3.5 shrink-0 text-text-muted\" />\n <span className=\"truncate\">{roomName}</span>\n </div>\n ) : null}\n <div className=\"flex items-center gap-1.5\">\n <Clock className=\"h-3.5 w-3.5 shrink-0 text-text-muted\" />\n <span>\n {formatClock(session.startsAt)}\n {duration ? ` · ${duration}` : ''}\n </span>\n </div>\n </dl>\n </div>\n );\n}\n\nfunction SessionsTab({ eventId }: { eventId: string }) {\n const { navigate } = useEventfullyManaged();\n const pagination = usePagination();\n const { data, loading, refetch } = useQuery<\n ScheduleSessionsResponse,\n { eventId?: string; limit?: number; offset?: number }\n >(SCHEDULE_SESSIONS_QUERY, {\n variables: { eventId, limit: pagination.limit, offset: pagination.offset },\n });\n const { data: venuesData } = useVenuesQuery({ limit: 100, offset: 0 });\n const { data: speakersData } = useSpeakersQuery({ limit: 100, offset: 0 });\n const [deleteEventSession] = useDeleteEventSessionMutation();\n\n const total = data?.eventSessions?.total ?? 0;\n const rows = useMemo(() => data?.eventSessions?.items ?? [], [data]);\n\n const venueNameById = useMemo(() => {\n const map = new Map<string, string>();\n for (const venue of venuesData?.venues?.items ?? []) {\n map.set(venue.id, venue.name);\n }\n return map;\n }, [venuesData]);\n\n const speakerNameById = useMemo(() => {\n const map = new Map<string, string>();\n for (const speaker of speakersData?.speakers?.items ?? []) {\n map.set(speaker.id, speaker.fullName);\n }\n return map;\n }, [speakersData]);\n\n // Distinct tracks (ordered by first appearance) → stable colour per track.\n const trackColor = useMemo(() => {\n const map = new Map<string, string>();\n let index = 0;\n for (const session of rows) {\n const track = session.track?.trim() || UNTRACKED;\n if (!map.has(track)) {\n map.set(track, CHART_COLORS[index % CHART_COLORS.length]);\n index += 1;\n }\n }\n return map;\n }, [rows]);\n\n // Group sessions by day, then by track, keyed by the hour they start.\n const days = useMemo(() => {\n const byDay = new Map<string, ScheduleSession[]>();\n for (const session of [...rows].sort((a, b) => new Date(a.startsAt).getTime() - new Date(b.startsAt).getTime())) {\n const key = dayKey(session.startsAt);\n const list = byDay.get(key) ?? [];\n list.push(session);\n byDay.set(key, list);\n }\n return Array.from(byDay.entries()).map(([key, sessions]) => {\n const tracks = Array.from(new Set(sessions.map((s) => s.track?.trim() || UNTRACKED)));\n const hours = sessions\n .map((s) => new Date(s.startsAt).getHours())\n .filter((h) => !Number.isNaN(h));\n const minHour = hours.length ? Math.min(...hours) : 9;\n const maxHour = hours.length ? Math.max(...hours) : 17;\n const hourRange: number[] = [];\n for (let hour = minHour; hour <= maxHour; hour += 1) {\n hourRange.push(hour);\n }\n return { key, sessions, tracks, hourRange };\n });\n }, [rows]);\n\n const onDelete = async (session: ScheduleSession) => {\n const response = await deleteEventSession({ variables: { id: session.id } });\n if (response.error) {\n notify.error('Could not delete session', response.error.message);\n throw response.error;\n }\n if (!response.data?.deleteEventSession) {\n notify.error('Could not delete session', 'The server did not confirm the change.');\n throw new Error('delete-unconfirmed');\n }\n notify.success('Session deleted', session.title);\n await refetch();\n };\n\n const resolveSpeaker = (session: ScheduleSession): string | undefined => {\n const metadata = (session.metadata ?? {}) as Record<string, unknown>;\n const speakerId = typeof metadata.speakerId === 'string' ? metadata.speakerId : '';\n return speakerId ? speakerNameById.get(speakerId) : undefined;\n };\n const resolveRoom = (session: ScheduleSession): string | undefined =>\n session.venueId ? venueNameById.get(session.venueId) : undefined;\n\n return (\n <div className=\"space-y-5\">\n <div className=\"flex items-center justify-between gap-3\">\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">Agenda &amp; Sessions</h2>\n <p className=\"text-sm text-text-secondary\">A multi-track schedule of everything happening on the day.</p>\n </div>\n <Button type=\"button\" size=\"sm\" onClick={() => navigate(`/events/${eventId}/sessions/create`)}>\n <Plus className=\"h-4 w-4\" />\n New Session\n </Button>\n </div>\n\n {loading ? (\n <Skeleton className=\"h-64 w-full rounded-card\" />\n ) : rows.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No sessions yet.\"\n description=\"Build the agenda by adding your first session.\"\n action={\n <Button type=\"button\" size=\"sm\" onClick={() => navigate(`/events/${eventId}/sessions/create`)}>\n <Plus className=\"h-4 w-4\" />\n New Session\n </Button>\n }\n className=\"py-10\"\n />\n ) : (\n <div className=\"space-y-8\">\n {days.map((day) => (\n <section key={day.key} className=\"space-y-3\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {new Date(`${day.key}T00:00:00`).toLocaleDateString(undefined, {\n weekday: 'long',\n month: 'long',\n day: 'numeric',\n })}\n </h3>\n\n {/* Desktop / tablet: multi-track grid */}\n <div className=\"hidden overflow-x-auto rounded-card border border-border-seam md:block\">\n <div\n className=\"grid min-w-max\"\n style={{ gridTemplateColumns: `88px repeat(${day.tracks.length}, minmax(200px, 1fr))` }}\n >\n {/* Header row */}\n <div className=\"sticky left-0 z-10 border-b border-border-seam bg-bg-sunken px-3 py-2.5\" />\n {day.tracks.map((track) => (\n <div\n key={track}\n className=\"border-b border-l border-border-seam bg-bg-sunken px-3 py-2.5 text-center text-sm font-semibold text-text-primary\"\n >\n <span className=\"inline-flex items-center gap-2\">\n <span\n className=\"h-2 w-2 rounded-full\"\n style={{ background: trackColor.get(track) }}\n aria-hidden=\"true\"\n />\n {track}\n </span>\n </div>\n ))}\n\n {/* Hour rows */}\n {day.hourRange.map((hour) => (\n <div key={hour} className=\"contents\">\n <div className=\"sticky left-0 z-10 border-b border-border-subtle bg-bg-surface px-3 py-3 text-xs font-medium text-text-muted\">\n {formatHour(hour)}\n </div>\n {day.tracks.map((track) => {\n const cellSessions = day.sessions.filter(\n (session) =>\n (session.track?.trim() || UNTRACKED) === track &&\n new Date(session.startsAt).getHours() === hour\n );\n return (\n <div\n key={`${hour}-${track}`}\n className=\"space-y-2 border-b border-l border-border-subtle p-2 align-top\"\n >\n {cellSessions.map((session) => (\n <SessionBlock\n key={session.id}\n session={session}\n color={trackColor.get(track) ?? CHART_COLORS[0]}\n speakerName={resolveSpeaker(session)}\n roomName={resolveRoom(session)}\n onEdit={() => navigate(`/events/${eventId}/sessions/${session.id}/edit`)}\n onDelete={() => onDelete(session)}\n />\n ))}\n </div>\n );\n })}\n </div>\n ))}\n </div>\n </div>\n\n {/* Mobile: clean time-ordered day list */}\n <ul className=\"space-y-2.5 md:hidden\">\n {day.sessions.map((session) => {\n const track = session.track?.trim() || UNTRACKED;\n return (\n <li key={session.id}>\n <SessionBlock\n session={session}\n color={trackColor.get(track) ?? CHART_COLORS[0]}\n speakerName={resolveSpeaker(session)}\n roomName={resolveRoom(session) ?? track}\n onEdit={() => navigate(`/events/${eventId}/sessions/${session.id}/edit`)}\n onDelete={() => onDelete(session)}\n />\n </li>\n );\n })}\n </ul>\n </section>\n ))}\n </div>\n )}\n\n <Pagination\n offset={pagination.offset}\n limit={pagination.limit}\n loadedCount={rows.length}\n total={total}\n onPrev={pagination.prevPage}\n onNext={pagination.nextPage}\n itemLabel=\"sessions\"\n loading={loading}\n />\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n\ntype SpeakerRow = { id: string; fullName: string; title?: string | null; organization?: string | null };\n\nfunction SpeakersTab() {\n const { navigate } = useEventfullyManaged();\n const pagination = usePagination();\n const { data, loading, refetch } = useSpeakersQuery({ limit: pagination.limit, offset: pagination.offset });\n const [deleteSpeaker] = useDeleteSpeakerMutation();\n\n const total = data?.speakers?.total ?? 0;\n const rows = (data?.speakers?.items ?? []) as unknown as SpeakerRow[];\n\n const onDelete = async (speaker: SpeakerRow) => {\n const response = await deleteSpeaker({ variables: { id: speaker.id } });\n if (response.error) {\n notify.error('Could not delete speaker', response.error.message);\n throw response.error;\n }\n if (!response.data?.deleteSpeaker) {\n notify.error('Could not delete speaker', 'The server did not confirm the change.');\n throw new Error('delete-unconfirmed');\n }\n notify.success('Speaker deleted', speaker.fullName);\n await refetch();\n };\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between gap-3\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Speakers</h2>\n <div className=\"flex items-center gap-2\">\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => navigate('/speakers')}>\n Manage speakers\n </Button>\n <Button type=\"button\" size=\"sm\" onClick={() => navigate('/speakers/create')}>\n <Plus className=\"h-4 w-4\" />\n New Speaker\n </Button>\n </div>\n </div>\n\n {loading ? (\n <Skeleton className=\"h-40 w-full rounded-card\" />\n ) : rows.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-people\"\n title=\"No speakers yet.\"\n description=\"Add speakers so you can assign them to sessions.\"\n className=\"py-8\"\n />\n ) : (\n <ul className=\"grid grid-cols-1 gap-2.5 sm:grid-cols-2\">\n {rows.map((speaker) => (\n <li\n key={speaker.id}\n className=\"rounded-card border border-border-seam bg-bg-surface p-3 transition-[box-shadow,border-color] duration-200 hover:border-border-strong hover:shadow-elevation-1\"\n >\n <div className=\"flex items-center justify-between gap-3\">\n <div className=\"flex min-w-0 items-center gap-3\">\n <span className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-accent-wash text-sm font-semibold text-action-primary-bg\">\n {speaker.fullName.slice(0, 1).toUpperCase()}\n </span>\n <div className=\"min-w-0\">\n <p className=\"truncate font-medium text-text-primary\">{speaker.fullName}</p>\n <p className=\"mt-0.5 truncate text-sm text-text-secondary\">\n {[speaker.title, speaker.organization].filter(Boolean).join(' • ') || 'Speaker'}\n </p>\n </div>\n </div>\n <ActionMenu\n ariaLabel={`Speaker actions for ${speaker.fullName}`}\n entityName={speaker.fullName}\n deleteLabel=\"Delete speaker\"\n onEdit={() => navigate(`/speakers/${speaker.id}/edit`)}\n onDelete={() => onDelete(speaker)}\n />\n </div>\n </li>\n ))}\n </ul>\n )}\n\n <Pagination\n offset={pagination.offset}\n limit={pagination.limit}\n loadedCount={rows.length}\n total={total}\n onPrev={pagination.prevPage}\n onNext={pagination.nextPage}\n itemLabel=\"speakers\"\n loading={loading}\n />\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n\nfunction TicketsTab({ eventId }: { eventId: string }) {\n const { navigate } = useEventfullyManaged();\n const pagination = usePagination();\n const { data, loading, refetch } = useTicketTypesQuery({\n eventId,\n limit: pagination.limit,\n offset: pagination.offset,\n });\n const [deleteTicketType] = useDeleteTicketTypeMutation();\n\n const total = data?.ticketTypes?.total ?? 0;\n const rows = (data?.ticketTypes?.items ?? []) as TicketTypeGql[];\n\n const onDelete = async (ticket: TicketTypeGql) => {\n const response = await deleteTicketType({ variables: { id: ticket.id } });\n if (response.error) {\n notify.error('Could not delete ticket type', response.error.message);\n throw response.error;\n }\n if (!response.data?.deleteTicketType) {\n notify.error('Could not delete ticket type', 'The server did not confirm the change.');\n throw new Error('delete-unconfirmed');\n }\n notify.success('Ticket type deleted');\n await refetch();\n };\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between gap-3\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Ticket Types</h2>\n <Button type=\"button\" size=\"sm\" onClick={() => navigate(`/events/${eventId}/tickets/create`)}>\n <Plus className=\"h-4 w-4\" />\n New Ticket Type\n </Button>\n </div>\n\n {loading ? (\n <Skeleton className=\"h-40 w-full rounded-card\" />\n ) : rows.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No ticket types yet.\"\n description=\"Add a ticket type so attendees can register.\"\n className=\"py-8\"\n />\n ) : (\n <ul className=\"space-y-3\">\n {rows.map((ticket) => {\n const hasCapacity = ticket.capacity != null && ticket.capacity > 0;\n const pct = hasCapacity ? Math.min(100, Math.round((ticket.soldCount / (ticket.capacity as number)) * 100)) : 0;\n const nearlyFull = pct >= 90;\n return (\n <li\n key={ticket.id}\n className=\"rounded-card border border-border-seam bg-bg-surface p-4 transition-[box-shadow,border-color] duration-200 hover:border-border-strong hover:shadow-elevation-1\"\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <p className=\"truncate font-medium text-text-primary\">{ticket.name}</p>\n <p className=\"mt-0.5 text-sm text-text-secondary\">\n {ticket.price} {ticket.currency}\n </p>\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n <Badge variant={ticket.isActive ? 'success' : 'warning'} className=\"uppercase\">\n {ticket.isActive ? 'Active' : 'Inactive'}\n </Badge>\n <ActionMenu\n ariaLabel={`Ticket actions for ${ticket.name}`}\n entityName={ticket.name}\n deleteLabel=\"Delete ticket type\"\n onEdit={() => navigate(`/events/${eventId}/tickets/${ticket.id}/edit`)}\n onDelete={() => onDelete(ticket)}\n />\n </div>\n </div>\n\n <div className=\"mt-3\">\n <div className=\"flex items-center justify-between text-xs text-text-secondary\">\n <span>\n <span className=\"font-medium tabular-nums text-text-primary\">\n {ticket.soldCount.toLocaleString()}\n </span>{' '}\n sold\n {hasCapacity ? (\n <>\n {' '}\n / {(ticket.capacity as number).toLocaleString()} capacity\n </>\n ) : (\n ' • unlimited capacity'\n )}\n </span>\n {hasCapacity ? (\n <span className={nearlyFull ? 'font-medium text-text-primary' : ''}>{pct}%</span>\n ) : null}\n </div>\n {hasCapacity ? (\n <div\n className=\"mt-1.5 h-2 overflow-hidden rounded-full bg-bg-sunken\"\n role=\"progressbar\"\n aria-valuenow={pct}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={`${ticket.name} sold`}\n >\n <div\n className=\"h-full rounded-full transition-[width] duration-500\"\n style={{\n width: `${pct}%`,\n background: 'linear-gradient(90deg, var(--color-chart-1), var(--color-chart-2))',\n }}\n />\n </div>\n ) : null}\n </div>\n </li>\n );\n })}\n </ul>\n )}\n\n <Pagination\n offset={pagination.offset}\n limit={pagination.limit}\n loadedCount={rows.length}\n total={total}\n onPrev={pagination.prevPage}\n onNext={pagination.nextPage}\n itemLabel=\"ticket types\"\n loading={loading}\n />\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n\nfunction MetricTile({ label, value, icon: Icon }: { label: string; value: string; icon: React.ComponentType<{ className?: string }> }) {\n return (\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <span className=\"flex h-8 w-8 items-center justify-center rounded-button bg-accent-wash text-action-primary-bg\">\n <Icon className=\"h-4 w-4\" />\n </span>\n <div className=\"mt-2.5 text-xl font-semibold tabular-nums text-text-primary\">{value}</div>\n <div className=\"mt-0.5 text-xs text-text-muted\">{label}</div>\n </GlassCard>\n );\n}\n\nexport default function EventDetailPage() {\n const { id = '' } = useParams<{ id: string }>();\n const { navigate } = useEventfullyManaged();\n const { data, loading } = useEventQuery(id);\n const { data: sessionsData } = useQuery<ScheduleSessionsResponse, { eventId?: string; limit?: number }>(\n SCHEDULE_SESSIONS_QUERY,\n { variables: { eventId: id, limit: 200 }, skip: !id }\n );\n const { data: ticketsData } = useTicketTypesQuery({ eventId: id, limit: 100, offset: 0 });\n const { data: venuesData } = useVenuesQuery({ limit: 100, offset: 0 });\n const [tab, setTab] = useState('overview');\n\n const event = data?.event ?? null;\n const venueId = useMemo(() => {\n const metadata = (event?.metadata ?? {}) as Record<string, unknown>;\n return typeof metadata.venueId === 'string' ? (metadata.venueId as string) : '';\n }, [event]);\n const venueName = useMemo(\n () => (venueId ? venuesData?.venues?.items?.find((venue) => venue.id === venueId)?.name : undefined),\n [venueId, venuesData]\n );\n\n const sessionCount = sessionsData?.eventSessions?.total ?? 0;\n const ticketsSold = useMemo(\n () => (ticketsData?.ticketTypes?.items ?? []).reduce((sum, ticket) => sum + (ticket.soldCount ?? 0), 0),\n [ticketsData]\n );\n\n if (loading) {\n return (\n <div className=\"space-y-4 p-6\">\n <Skeleton className=\"h-8 w-40\" />\n <Skeleton className=\"h-24 w-full rounded-card\" />\n <Skeleton className=\"h-64 w-full rounded-card\" />\n </div>\n );\n }\n\n if (!event) {\n return (\n <div className=\"space-y-4 p-6\">\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => navigate('/events')}>\n <ArrowLeft className=\"h-4 w-4\" />\n Back to Events\n </Button>\n <GlassCard treatment=\"plain\" className=\"border-border-seam\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"Event not found.\"\n description=\"This event may have been removed or is outside your current scope.\"\n />\n </GlassCard>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"space-y-3\">\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => navigate('/events')}>\n <ArrowLeft className=\"h-4 w-4\" />\n Back to Events\n </Button>\n <div>\n <div className=\"flex flex-wrap items-center gap-3\">\n <h1 className=\"text-2xl font-bold text-text-primary\">{event.name}</h1>\n <Badge variant={statusVariant(event.status)} className=\"uppercase\">\n {event.status}\n </Badge>\n </div>\n <p className=\"mt-1 flex flex-wrap items-center gap-x-4 gap-y-1 text-sm text-text-secondary\">\n <span className=\"flex items-center gap-1.5\">\n <CalendarClock className=\"h-4 w-4 text-text-muted\" />\n {formatDateTime(event.startAt)} — {formatDateTime(event.endAt)}\n </span>\n {venueName ? (\n <span className=\"flex items-center gap-1.5\">\n <MapPin className=\"h-4 w-4 text-text-muted\" />\n {venueName}\n </span>\n ) : null}\n </p>\n </div>\n </div>\n <Button type=\"button\" onClick={() => navigate(`/events/${id}/edit`)}>\n <Edit className=\"h-4 w-4\" />\n Edit Event\n </Button>\n </div>\n\n {/* Metrics strip */}\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <MetricTile label=\"Capacity\" value={(event.capacity ?? 0).toLocaleString()} icon={Users} />\n <MetricTile label=\"Sessions\" value={sessionCount.toLocaleString()} icon={CalendarClock} />\n <MetricTile label=\"Ticket types\" value={(ticketsData?.ticketTypes?.total ?? 0).toLocaleString()} icon={TicketIcon} />\n <MetricTile label=\"Tickets sold\" value={ticketsSold.toLocaleString()} icon={Eye} />\n </div>\n\n <Tabs value={tab} onValueChange={setTab}>\n <TabsList>\n <TabsTrigger value=\"overview\">Overview</TabsTrigger>\n <TabsTrigger value=\"sessions\">Sessions</TabsTrigger>\n <TabsTrigger value=\"speakers\">Speakers</TabsTrigger>\n <TabsTrigger value=\"tickets\">Tickets</TabsTrigger>\n </TabsList>\n\n <TabsContent value=\"overview\" className=\"mt-4\">\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-3\">\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-5 lg:col-span-2\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Event Details</h2>\n <dl className=\"mt-4 space-y-4 text-sm\">\n <div className=\"grid grid-cols-1 gap-1 sm:grid-cols-[140px_1fr]\">\n <dt className=\"text-text-muted\">Dates</dt>\n <dd className=\"text-text-primary\">\n {formatDateTime(event.startAt)} — {formatDateTime(event.endAt)}\n </dd>\n </div>\n <div className=\"grid grid-cols-1 gap-1 sm:grid-cols-[140px_1fr]\">\n <dt className=\"text-text-muted\">Venue</dt>\n <dd className=\"text-text-primary\">\n {venueName ? (\n <Button\n type=\"button\"\n variant=\"link\"\n size=\"sm\"\n className=\"h-auto p-0\"\n onClick={() => navigate(`/venues/${venueId}`)}\n >\n {venueName}\n </Button>\n ) : (\n 'No venue assigned'\n )}\n </dd>\n </div>\n <div className=\"grid grid-cols-1 gap-1 sm:grid-cols-[140px_1fr]\">\n <dt className=\"text-text-muted\">Capacity</dt>\n <dd className=\"text-text-primary\">{(event.capacity ?? 0).toLocaleString()} attendees</dd>\n </div>\n <div className=\"grid grid-cols-1 gap-1 sm:grid-cols-[140px_1fr]\">\n <dt className=\"text-text-muted\">Type</dt>\n <dd className=\"capitalize text-text-primary\">{event.type.toLowerCase().replace(/_/g, ' ')}</dd>\n </div>\n <div className=\"grid grid-cols-1 gap-1 sm:grid-cols-[140px_1fr]\">\n <dt className=\"text-text-muted\">Timezone</dt>\n <dd className=\"text-text-primary\">{event.timezone}</dd>\n </div>\n <div className=\"grid grid-cols-1 gap-1 sm:grid-cols-[140px_1fr]\">\n <dt className=\"text-text-muted\">Visibility</dt>\n <dd className=\"capitalize text-text-primary\">{event.visibility}</dd>\n </div>\n <div className=\"grid grid-cols-1 gap-1 sm:grid-cols-[140px_1fr]\">\n <dt className=\"text-text-muted\">Description</dt>\n <dd className=\"text-text-secondary\">\n {event.description?.trim() ? event.description : 'No description provided.'}\n </dd>\n </div>\n </dl>\n <div className=\"mt-5\">\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => navigate(`/events/${id}/edit`)}>\n <Edit className=\"h-4 w-4\" />\n Edit event details\n </Button>\n </div>\n </GlassCard>\n\n <GlassCard treatment=\"glass\" glow className=\"p-5\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Key Metrics</h2>\n <dl className=\"mt-4 space-y-4\">\n <div>\n <dt className=\"text-sm text-text-secondary\">Capacity</dt>\n <dd className=\"text-2xl font-semibold tabular-nums text-text-primary\">\n {(event.capacity ?? 0).toLocaleString()}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm text-text-secondary\">Sessions</dt>\n <dd className=\"text-2xl font-semibold tabular-nums text-text-primary\">\n {sessionCount.toLocaleString()}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm text-text-secondary\">Ticket types</dt>\n <dd className=\"text-2xl font-semibold tabular-nums text-text-primary\">\n {(ticketsData?.ticketTypes?.total ?? 0).toLocaleString()}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm text-text-secondary\">Tickets sold</dt>\n <dd className=\"text-2xl font-semibold tabular-nums text-text-primary\">\n {ticketsSold.toLocaleString()}\n </dd>\n </div>\n </dl>\n </GlassCard>\n </div>\n </TabsContent>\n\n <TabsContent value=\"sessions\" className=\"mt-4\">\n <SessionsTab eventId={id} />\n </TabsContent>\n\n <TabsContent value=\"speakers\" className=\"mt-4\">\n <SpeakersTab />\n </TabsContent>\n\n <TabsContent value=\"tickets\" className=\"mt-4\">\n <TicketsTab eventId={id} />\n </TabsContent>\n </Tabs>\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"EventDetailPage.js","names":[],"sources":["../../../../src/eventfullymanaged/pages/events/EventDetailPage.tsx"],"sourcesContent":["import { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport {\n ArrowLeft,\n CalendarClock,\n Clock,\n Edit,\n Eye,\n MapPin,\n Mic2,\n Plus,\n Ticket as TicketIcon,\n Users,\n} from 'lucide-react';\nimport {\n Badge,\n Button,\n GlassCard,\n IllustratedEmptyState,\n Skeleton,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n} from '@burdenoff/fe-libs/ui';\nimport { useMemo, useState } from 'react';\nimport { useParams } from 'react-router-dom';\n\nimport {\n useDeleteEventSessionMutation,\n useDeleteSpeakerMutation,\n useDeleteTicketTypeMutation,\n useEventQuery,\n useSpeakersQuery,\n useTicketTypesQuery,\n useVenuesQuery,\n type TicketTypeGql,\n} from '../../api/eventApi';\nimport { ActionMenu } from '../../components/ActionMenu';\nimport { CHART_COLORS } from '../../components/EventCharts';\nimport { Pagination, usePagination } from '../../components/Pagination';\nimport { useEventfullyManaged } from '../../context/EventfullyManagedContext';\nimport { notify } from '../../lib/toast';\nimport { formatDateTime } from './eventFormUtils';\n\nfunction statusVariant(status: string): 'success' | 'warning' | 'secondary' | 'info' {\n const value = status.toLowerCase();\n if (['active', 'published', 'live', 'confirmed', 'completed', 'approved'].includes(value)) {\n return 'success';\n }\n if (['inactive', 'cancelled', 'archived', 'closed', 'expired'].includes(value)) {\n return 'warning';\n }\n if (['draft', 'created', 'pending', 'scheduled'].includes(value)) {\n return 'info';\n }\n return 'secondary';\n}\n\nfunction formatDuration(startsAt: string, endsAt: string): string {\n const start = new Date(startsAt).getTime();\n const end = new Date(endsAt).getTime();\n if (Number.isNaN(start) || Number.isNaN(end) || end <= start) {\n return '';\n }\n const totalMinutes = Math.round((end - start) / 60000);\n const hours = Math.floor(totalMinutes / 60);\n const minutes = totalMinutes % 60;\n if (hours && minutes) {\n return `${hours}h ${minutes}m`;\n }\n if (hours) {\n return `${hours}h`;\n }\n return `${minutes}m`;\n}\n\nfunction formatHour(hour: number): string {\n const period = hour < 12 ? 'AM' : 'PM';\n const display = hour % 12 === 0 ? 12 : hour % 12;\n return `${display}:00 ${period}`;\n}\n\nfunction formatClock(iso: string): string {\n const date = new Date(iso);\n if (Number.isNaN(date.getTime())) {\n return '';\n }\n return date.toLocaleTimeString(undefined, { hour: 'numeric', minute: '2-digit' });\n}\n\n// ---------------------------------------------------------------------------\n// Sessions tab — multi-track schedule grid.\n//\n// The shared EVENT_SESSIONS_QUERY omits `metadata` (which carries speakerId) and\n// `description`/`capacity`, so this tab owns a fuller read that selects them; the\n// grid resolves room names from venues and speaker names from speakers.\n// ---------------------------------------------------------------------------\n\nconst SCHEDULE_SESSIONS_QUERY = gql`\n query EventfullymanagedScheduleSessions($eventId: ID, $limit: Int, $offset: Int) {\n eventSessions: eventfullyManagedEventSessions(eventId: $eventId, limit: $limit, offset: $offset) {\n total\n items {\n id\n eventId\n venueId\n title\n sessionType\n track\n startsAt\n endsAt\n status\n metadata\n }\n }\n }\n`;\n\ntype ScheduleSession = {\n id: string;\n eventId: string;\n venueId?: string | null;\n title: string;\n sessionType: string;\n track?: string | null;\n startsAt: string;\n endsAt: string;\n status: string;\n metadata?: Record<string, unknown> | null;\n};\n\ntype ScheduleSessionsResponse = { eventSessions: { total: number; items: ScheduleSession[] } };\n\nconst UNTRACKED = 'General';\n\nfunction dayKey(iso: string): string {\n const date = new Date(iso);\n return Number.isNaN(date.getTime()) ? 'unknown' : date.toISOString().slice(0, 10);\n}\n\nfunction SessionBlock({\n session,\n color,\n speakerName,\n roomName,\n onEdit,\n onDelete,\n}: {\n session: ScheduleSession;\n color: string;\n speakerName?: string;\n roomName?: string;\n onEdit: () => void;\n onDelete: () => void | Promise<void>;\n}) {\n const duration = formatDuration(session.startsAt, session.endsAt);\n return (\n <div\n className=\"relative rounded-card border border-border-subtle p-3 shadow-elevation-1\"\n style={{\n borderLeftWidth: '3px',\n borderLeftColor: color,\n background: `color-mix(in srgb, ${color} 8%, var(--color-bg-surface))`,\n }}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <p className=\"min-w-0 pr-1 text-sm font-semibold leading-snug text-text-primary\">{session.title}</p>\n <div className=\"-mr-1 -mt-1 shrink-0\">\n <ActionMenu\n ariaLabel={`Session actions for ${session.title}`}\n entityName={session.title}\n deleteLabel=\"Delete session\"\n onEdit={onEdit}\n onDelete={onDelete}\n />\n </div>\n </div>\n <dl className=\"mt-2 space-y-1 text-xs text-text-secondary\">\n <div className=\"flex items-center gap-1.5\">\n <Mic2 className=\"h-3.5 w-3.5 shrink-0 text-text-muted\" />\n <span className=\"truncate\">{speakerName ?? 'Speaker TBD'}</span>\n </div>\n {roomName ? (\n <div className=\"flex items-center gap-1.5\">\n <MapPin className=\"h-3.5 w-3.5 shrink-0 text-text-muted\" />\n <span className=\"truncate\">{roomName}</span>\n </div>\n ) : null}\n <div className=\"flex items-center gap-1.5\">\n <Clock className=\"h-3.5 w-3.5 shrink-0 text-text-muted\" />\n <span>\n {formatClock(session.startsAt)}\n {duration ? ` · ${duration}` : ''}\n </span>\n </div>\n </dl>\n </div>\n );\n}\n\nfunction SessionsTab({ eventId }: { eventId: string }) {\n const { navigate } = useEventfullyManaged();\n const pagination = usePagination();\n const { data, loading, refetch } = useQuery<\n ScheduleSessionsResponse,\n { eventId?: string; limit?: number; offset?: number }\n >(SCHEDULE_SESSIONS_QUERY, {\n variables: { eventId, limit: pagination.limit, offset: pagination.offset },\n });\n const { data: venuesData } = useVenuesQuery({ limit: 100, offset: 0 });\n const { data: speakersData } = useSpeakersQuery({ limit: 100, offset: 0 });\n const [deleteEventSession] = useDeleteEventSessionMutation();\n\n const total = data?.eventSessions?.total ?? 0;\n const rows = useMemo(() => data?.eventSessions?.items ?? [], [data]);\n\n const venueNameById = useMemo(() => {\n const map = new Map<string, string>();\n for (const venue of venuesData?.venues?.items ?? []) {\n map.set(venue.id, venue.name);\n }\n return map;\n }, [venuesData]);\n\n const speakerNameById = useMemo(() => {\n const map = new Map<string, string>();\n for (const speaker of speakersData?.speakers?.items ?? []) {\n map.set(speaker.id, speaker.fullName);\n }\n return map;\n }, [speakersData]);\n\n // Distinct tracks (ordered by first appearance) → stable colour per track.\n const trackColor = useMemo(() => {\n const map = new Map<string, string>();\n let index = 0;\n for (const session of rows) {\n const track = session.track?.trim() || UNTRACKED;\n if (!map.has(track)) {\n map.set(track, CHART_COLORS[index % CHART_COLORS.length]);\n index += 1;\n }\n }\n return map;\n }, [rows]);\n\n // Group sessions by day, then by track, keyed by the hour they start.\n const days = useMemo(() => {\n const byDay = new Map<string, ScheduleSession[]>();\n for (const session of [...rows].sort((a, b) => new Date(a.startsAt).getTime() - new Date(b.startsAt).getTime())) {\n const key = dayKey(session.startsAt);\n const list = byDay.get(key) ?? [];\n list.push(session);\n byDay.set(key, list);\n }\n return Array.from(byDay.entries()).map(([key, sessions]) => {\n const tracks = Array.from(new Set(sessions.map((s) => s.track?.trim() || UNTRACKED)));\n const hours = sessions.map((s) => new Date(s.startsAt).getHours()).filter((h) => !Number.isNaN(h));\n const minHour = hours.length ? Math.min(...hours) : 9;\n const maxHour = hours.length ? Math.max(...hours) : 17;\n const hourRange: number[] = [];\n for (let hour = minHour; hour <= maxHour; hour += 1) {\n hourRange.push(hour);\n }\n return { key, sessions, tracks, hourRange };\n });\n }, [rows]);\n\n const onDelete = async (session: ScheduleSession) => {\n const response = await deleteEventSession({ variables: { id: session.id } });\n if (response.error) {\n notify.error('Could not delete session', response.error.message);\n throw response.error;\n }\n if (!response.data?.deleteEventSession) {\n notify.error('Could not delete session', 'The server did not confirm the change.');\n throw new Error('delete-unconfirmed');\n }\n notify.success('Session deleted', session.title);\n await refetch();\n };\n\n const resolveSpeaker = (session: ScheduleSession): string | undefined => {\n const metadata = (session.metadata ?? {}) as Record<string, unknown>;\n const speakerId = typeof metadata.speakerId === 'string' ? metadata.speakerId : '';\n return speakerId ? speakerNameById.get(speakerId) : undefined;\n };\n const resolveRoom = (session: ScheduleSession): string | undefined =>\n session.venueId ? venueNameById.get(session.venueId) : undefined;\n\n return (\n <div className=\"space-y-5\">\n <div className=\"flex items-center justify-between gap-3\">\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">Agenda &amp; Sessions</h2>\n <p className=\"text-sm text-text-secondary\">A multi-track schedule of everything happening on the day.</p>\n </div>\n <Button type=\"button\" size=\"sm\" onClick={() => navigate(`/events/${eventId}/sessions/create`)}>\n <Plus className=\"h-4 w-4\" />\n New Session\n </Button>\n </div>\n\n {loading ? (\n <Skeleton className=\"h-64 w-full rounded-card\" />\n ) : rows.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No sessions yet.\"\n description=\"Build the agenda by adding your first session.\"\n action={\n <Button type=\"button\" size=\"sm\" onClick={() => navigate(`/events/${eventId}/sessions/create`)}>\n <Plus className=\"h-4 w-4\" />\n New Session\n </Button>\n }\n className=\"py-10\"\n />\n ) : (\n <div className=\"space-y-8\">\n {days.map((day) => (\n <section key={day.key} className=\"space-y-3\">\n <h3 className=\"text-sm font-semibold text-text-primary\">\n {new Date(`${day.key}T00:00:00`).toLocaleDateString(undefined, {\n weekday: 'long',\n month: 'long',\n day: 'numeric',\n })}\n </h3>\n\n {/* Desktop / tablet: multi-track grid */}\n <div className=\"hidden overflow-x-auto rounded-card border border-border-seam md:block\">\n <div\n className=\"grid min-w-max\"\n style={{ gridTemplateColumns: `88px repeat(${day.tracks.length}, minmax(200px, 1fr))` }}\n >\n {/* Header row */}\n <div className=\"sticky left-0 z-10 border-b border-border-seam bg-bg-sunken px-3 py-2.5\" />\n {day.tracks.map((track) => (\n <div\n key={track}\n className=\"border-b border-l border-border-seam bg-bg-sunken px-3 py-2.5 text-center text-sm font-semibold text-text-primary\"\n >\n <span className=\"inline-flex items-center gap-2\">\n <span\n className=\"h-2 w-2 rounded-full\"\n style={{ background: trackColor.get(track) }}\n aria-hidden=\"true\"\n />\n {track}\n </span>\n </div>\n ))}\n\n {/* Hour rows */}\n {day.hourRange.map((hour) => (\n <div key={hour} className=\"contents\">\n <div className=\"sticky left-0 z-10 border-b border-border-subtle bg-bg-surface px-3 py-3 text-xs font-medium text-text-muted\">\n {formatHour(hour)}\n </div>\n {day.tracks.map((track) => {\n const cellSessions = day.sessions.filter(\n (session) =>\n (session.track?.trim() || UNTRACKED) === track &&\n new Date(session.startsAt).getHours() === hour\n );\n return (\n <div\n key={`${hour}-${track}`}\n className=\"space-y-2 border-b border-l border-border-subtle p-2 align-top\"\n >\n {cellSessions.map((session) => (\n <SessionBlock\n key={session.id}\n session={session}\n color={trackColor.get(track) ?? CHART_COLORS[0]}\n speakerName={resolveSpeaker(session)}\n roomName={resolveRoom(session)}\n onEdit={() => navigate(`/events/${eventId}/sessions/${session.id}/edit`)}\n onDelete={() => onDelete(session)}\n />\n ))}\n </div>\n );\n })}\n </div>\n ))}\n </div>\n </div>\n\n {/* Mobile: clean time-ordered day list */}\n <ul className=\"space-y-2.5 md:hidden\">\n {day.sessions.map((session) => {\n const track = session.track?.trim() || UNTRACKED;\n return (\n <li key={session.id}>\n <SessionBlock\n session={session}\n color={trackColor.get(track) ?? CHART_COLORS[0]}\n speakerName={resolveSpeaker(session)}\n roomName={resolveRoom(session) ?? track}\n onEdit={() => navigate(`/events/${eventId}/sessions/${session.id}/edit`)}\n onDelete={() => onDelete(session)}\n />\n </li>\n );\n })}\n </ul>\n </section>\n ))}\n </div>\n )}\n\n <Pagination\n offset={pagination.offset}\n limit={pagination.limit}\n loadedCount={rows.length}\n total={total}\n onPrev={pagination.prevPage}\n onNext={pagination.nextPage}\n itemLabel=\"sessions\"\n loading={loading}\n />\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n\ntype SpeakerRow = { id: string; fullName: string; title?: string | null; organization?: string | null };\n\nfunction SpeakersTab() {\n const { navigate } = useEventfullyManaged();\n const pagination = usePagination();\n const { data, loading, refetch } = useSpeakersQuery({ limit: pagination.limit, offset: pagination.offset });\n const [deleteSpeaker] = useDeleteSpeakerMutation();\n\n const total = data?.speakers?.total ?? 0;\n const rows = (data?.speakers?.items ?? []) as unknown as SpeakerRow[];\n\n const onDelete = async (speaker: SpeakerRow) => {\n const response = await deleteSpeaker({ variables: { id: speaker.id } });\n if (response.error) {\n notify.error('Could not delete speaker', response.error.message);\n throw response.error;\n }\n if (!response.data?.deleteSpeaker) {\n notify.error('Could not delete speaker', 'The server did not confirm the change.');\n throw new Error('delete-unconfirmed');\n }\n notify.success('Speaker deleted', speaker.fullName);\n await refetch();\n };\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between gap-3\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Speakers</h2>\n <div className=\"flex items-center gap-2\">\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => navigate('/speakers')}>\n Manage speakers\n </Button>\n <Button type=\"button\" size=\"sm\" onClick={() => navigate('/speakers/create')}>\n <Plus className=\"h-4 w-4\" />\n New Speaker\n </Button>\n </div>\n </div>\n\n {loading ? (\n <Skeleton className=\"h-40 w-full rounded-card\" />\n ) : rows.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-people\"\n title=\"No speakers yet.\"\n description=\"Add speakers so you can assign them to sessions.\"\n className=\"py-8\"\n />\n ) : (\n <ul className=\"grid grid-cols-1 gap-2.5 sm:grid-cols-2\">\n {rows.map((speaker) => (\n <li\n key={speaker.id}\n className=\"rounded-card border border-border-seam bg-bg-surface p-3 transition-[box-shadow,border-color] duration-200 hover:border-border-strong hover:shadow-elevation-1\"\n >\n <div className=\"flex items-center justify-between gap-3\">\n <div className=\"flex min-w-0 items-center gap-3\">\n <span className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-accent-wash text-sm font-semibold text-action-primary-bg\">\n {speaker.fullName.slice(0, 1).toUpperCase()}\n </span>\n <div className=\"min-w-0\">\n <p className=\"truncate font-medium text-text-primary\">{speaker.fullName}</p>\n <p className=\"mt-0.5 truncate text-sm text-text-secondary\">\n {[speaker.title, speaker.organization].filter(Boolean).join(' • ') || 'Speaker'}\n </p>\n </div>\n </div>\n <ActionMenu\n ariaLabel={`Speaker actions for ${speaker.fullName}`}\n entityName={speaker.fullName}\n deleteLabel=\"Delete speaker\"\n onEdit={() => navigate(`/speakers/${speaker.id}/edit`)}\n onDelete={() => onDelete(speaker)}\n />\n </div>\n </li>\n ))}\n </ul>\n )}\n\n <Pagination\n offset={pagination.offset}\n limit={pagination.limit}\n loadedCount={rows.length}\n total={total}\n onPrev={pagination.prevPage}\n onNext={pagination.nextPage}\n itemLabel=\"speakers\"\n loading={loading}\n />\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n\nfunction TicketsTab({ eventId }: { eventId: string }) {\n const { navigate } = useEventfullyManaged();\n const pagination = usePagination();\n const { data, loading, refetch } = useTicketTypesQuery({\n eventId,\n limit: pagination.limit,\n offset: pagination.offset,\n });\n const [deleteTicketType] = useDeleteTicketTypeMutation();\n\n const total = data?.ticketTypes?.total ?? 0;\n const rows = (data?.ticketTypes?.items ?? []) as TicketTypeGql[];\n\n const onDelete = async (ticket: TicketTypeGql) => {\n const response = await deleteTicketType({ variables: { id: ticket.id } });\n if (response.error) {\n notify.error('Could not delete ticket type', response.error.message);\n throw response.error;\n }\n if (!response.data?.deleteTicketType) {\n notify.error('Could not delete ticket type', 'The server did not confirm the change.');\n throw new Error('delete-unconfirmed');\n }\n notify.success('Ticket type deleted');\n await refetch();\n };\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between gap-3\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Ticket Types</h2>\n <Button type=\"button\" size=\"sm\" onClick={() => navigate(`/events/${eventId}/tickets/create`)}>\n <Plus className=\"h-4 w-4\" />\n New Ticket Type\n </Button>\n </div>\n\n {loading ? (\n <Skeleton className=\"h-40 w-full rounded-card\" />\n ) : rows.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title=\"No ticket types yet.\"\n description=\"Add a ticket type so attendees can register.\"\n className=\"py-8\"\n />\n ) : (\n <ul className=\"space-y-3\">\n {rows.map((ticket) => {\n const hasCapacity = ticket.capacity != null && ticket.capacity > 0;\n const pct = hasCapacity\n ? Math.min(100, Math.round((ticket.soldCount / (ticket.capacity as number)) * 100))\n : 0;\n const nearlyFull = pct >= 90;\n return (\n <li\n key={ticket.id}\n className=\"rounded-card border border-border-seam bg-bg-surface p-4 transition-[box-shadow,border-color] duration-200 hover:border-border-strong hover:shadow-elevation-1\"\n >\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <p className=\"truncate font-medium text-text-primary\">{ticket.name}</p>\n <p className=\"mt-0.5 text-sm text-text-secondary\">\n {ticket.price} {ticket.currency}\n </p>\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n <Badge variant={ticket.isActive ? 'success' : 'warning'} className=\"uppercase\">\n {ticket.isActive ? 'Active' : 'Inactive'}\n </Badge>\n <ActionMenu\n ariaLabel={`Ticket actions for ${ticket.name}`}\n entityName={ticket.name}\n deleteLabel=\"Delete ticket type\"\n onEdit={() => navigate(`/events/${eventId}/tickets/${ticket.id}/edit`)}\n onDelete={() => onDelete(ticket)}\n />\n </div>\n </div>\n\n <div className=\"mt-3\">\n <div className=\"flex items-center justify-between text-xs text-text-secondary\">\n <span>\n <span className=\"font-medium tabular-nums text-text-primary\">\n {ticket.soldCount.toLocaleString()}\n </span>{' '}\n sold\n {hasCapacity ? (\n <> / {(ticket.capacity as number).toLocaleString()} capacity</>\n ) : (\n ' • unlimited capacity'\n )}\n </span>\n {hasCapacity ? (\n <span className={nearlyFull ? 'font-medium text-text-primary' : ''}>{pct}%</span>\n ) : null}\n </div>\n {hasCapacity ? (\n <div\n className=\"mt-1.5 h-2 overflow-hidden rounded-full bg-bg-sunken\"\n role=\"progressbar\"\n aria-valuenow={pct}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={`${ticket.name} sold`}\n >\n <div\n className=\"h-full rounded-full transition-[width] duration-500\"\n style={{\n width: `${pct}%`,\n background: 'linear-gradient(90deg, var(--color-chart-1), var(--color-chart-2))',\n }}\n />\n </div>\n ) : null}\n </div>\n </li>\n );\n })}\n </ul>\n )}\n\n <Pagination\n offset={pagination.offset}\n limit={pagination.limit}\n loadedCount={rows.length}\n total={total}\n onPrev={pagination.prevPage}\n onNext={pagination.nextPage}\n itemLabel=\"ticket types\"\n loading={loading}\n />\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n\nfunction MetricTile({\n label,\n value,\n icon: Icon,\n}: {\n label: string;\n value: string;\n icon: React.ComponentType<{ className?: string }>;\n}) {\n return (\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <span className=\"flex h-8 w-8 items-center justify-center rounded-button bg-accent-wash text-action-primary-bg\">\n <Icon className=\"h-4 w-4\" />\n </span>\n <div className=\"mt-2.5 text-xl font-semibold tabular-nums text-text-primary\">{value}</div>\n <div className=\"mt-0.5 text-xs text-text-muted\">{label}</div>\n </GlassCard>\n );\n}\n\nexport default function EventDetailPage() {\n const { id = '' } = useParams<{ id: string }>();\n const { navigate } = useEventfullyManaged();\n const { data, loading } = useEventQuery(id);\n const { data: sessionsData } = useQuery<ScheduleSessionsResponse, { eventId?: string; limit?: number }>(\n SCHEDULE_SESSIONS_QUERY,\n { variables: { eventId: id, limit: 200 }, skip: !id }\n );\n const { data: ticketsData } = useTicketTypesQuery({ eventId: id, limit: 100, offset: 0 });\n const { data: venuesData } = useVenuesQuery({ limit: 100, offset: 0 });\n const [tab, setTab] = useState('overview');\n\n const event = data?.event ?? null;\n const venueId = useMemo(() => {\n const metadata = (event?.metadata ?? {}) as Record<string, unknown>;\n return typeof metadata.venueId === 'string' ? (metadata.venueId as string) : '';\n }, [event]);\n const venueName = useMemo(\n () => (venueId ? venuesData?.venues?.items?.find((venue) => venue.id === venueId)?.name : undefined),\n [venueId, venuesData]\n );\n\n const sessionCount = sessionsData?.eventSessions?.total ?? 0;\n const ticketsSold = useMemo(\n () => (ticketsData?.ticketTypes?.items ?? []).reduce((sum, ticket) => sum + (ticket.soldCount ?? 0), 0),\n [ticketsData]\n );\n\n if (loading) {\n return (\n <div className=\"space-y-4 p-6\">\n <Skeleton className=\"h-8 w-40\" />\n <Skeleton className=\"h-24 w-full rounded-card\" />\n <Skeleton className=\"h-64 w-full rounded-card\" />\n </div>\n );\n }\n\n if (!event) {\n return (\n <div className=\"space-y-4 p-6\">\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => navigate('/events')}>\n <ArrowLeft className=\"h-4 w-4\" />\n Back to Events\n </Button>\n <GlassCard treatment=\"plain\" className=\"border-border-seam\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"Event not found.\"\n description=\"This event may have been removed or is outside your current scope.\"\n />\n </GlassCard>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-6 p-6\">\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"space-y-3\">\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={() => navigate('/events')}>\n <ArrowLeft className=\"h-4 w-4\" />\n Back to Events\n </Button>\n <div>\n <div className=\"flex flex-wrap items-center gap-3\">\n <h1 className=\"text-2xl font-bold text-text-primary\">{event.name}</h1>\n <Badge variant={statusVariant(event.status)} className=\"uppercase\">\n {event.status}\n </Badge>\n </div>\n <p className=\"mt-1 flex flex-wrap items-center gap-x-4 gap-y-1 text-sm text-text-secondary\">\n <span className=\"flex items-center gap-1.5\">\n <CalendarClock className=\"h-4 w-4 text-text-muted\" />\n {formatDateTime(event.startAt)} — {formatDateTime(event.endAt)}\n </span>\n {venueName ? (\n <span className=\"flex items-center gap-1.5\">\n <MapPin className=\"h-4 w-4 text-text-muted\" />\n {venueName}\n </span>\n ) : null}\n </p>\n </div>\n </div>\n <Button type=\"button\" onClick={() => navigate(`/events/${id}/edit`)}>\n <Edit className=\"h-4 w-4\" />\n Edit Event\n </Button>\n </div>\n\n {/* Metrics strip */}\n <div className=\"grid grid-cols-2 gap-3 sm:grid-cols-4\">\n <MetricTile label=\"Capacity\" value={(event.capacity ?? 0).toLocaleString()} icon={Users} />\n <MetricTile label=\"Sessions\" value={sessionCount.toLocaleString()} icon={CalendarClock} />\n <MetricTile\n label=\"Ticket types\"\n value={(ticketsData?.ticketTypes?.total ?? 0).toLocaleString()}\n icon={TicketIcon}\n />\n <MetricTile label=\"Tickets sold\" value={ticketsSold.toLocaleString()} icon={Eye} />\n </div>\n\n <Tabs value={tab} onValueChange={setTab}>\n <TabsList>\n <TabsTrigger value=\"overview\">Overview</TabsTrigger>\n <TabsTrigger value=\"sessions\">Sessions</TabsTrigger>\n <TabsTrigger value=\"speakers\">Speakers</TabsTrigger>\n <TabsTrigger value=\"tickets\">Tickets</TabsTrigger>\n </TabsList>\n\n <TabsContent value=\"overview\" className=\"mt-4\">\n <div className=\"grid grid-cols-1 gap-4 lg:grid-cols-3\">\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-5 lg:col-span-2\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Event Details</h2>\n <dl className=\"mt-4 space-y-4 text-sm\">\n <div className=\"grid grid-cols-1 gap-1 sm:grid-cols-[140px_1fr]\">\n <dt className=\"text-text-muted\">Dates</dt>\n <dd className=\"text-text-primary\">\n {formatDateTime(event.startAt)} — {formatDateTime(event.endAt)}\n </dd>\n </div>\n <div className=\"grid grid-cols-1 gap-1 sm:grid-cols-[140px_1fr]\">\n <dt className=\"text-text-muted\">Venue</dt>\n <dd className=\"text-text-primary\">\n {venueName ? (\n <Button\n type=\"button\"\n variant=\"link\"\n size=\"sm\"\n className=\"h-auto p-0\"\n onClick={() => navigate(`/venues/${venueId}`)}\n >\n {venueName}\n </Button>\n ) : (\n 'No venue assigned'\n )}\n </dd>\n </div>\n <div className=\"grid grid-cols-1 gap-1 sm:grid-cols-[140px_1fr]\">\n <dt className=\"text-text-muted\">Capacity</dt>\n <dd className=\"text-text-primary\">{(event.capacity ?? 0).toLocaleString()} attendees</dd>\n </div>\n <div className=\"grid grid-cols-1 gap-1 sm:grid-cols-[140px_1fr]\">\n <dt className=\"text-text-muted\">Type</dt>\n <dd className=\"capitalize text-text-primary\">{event.type.toLowerCase().replace(/_/g, ' ')}</dd>\n </div>\n <div className=\"grid grid-cols-1 gap-1 sm:grid-cols-[140px_1fr]\">\n <dt className=\"text-text-muted\">Timezone</dt>\n <dd className=\"text-text-primary\">{event.timezone}</dd>\n </div>\n <div className=\"grid grid-cols-1 gap-1 sm:grid-cols-[140px_1fr]\">\n <dt className=\"text-text-muted\">Visibility</dt>\n <dd className=\"capitalize text-text-primary\">{event.visibility}</dd>\n </div>\n <div className=\"grid grid-cols-1 gap-1 sm:grid-cols-[140px_1fr]\">\n <dt className=\"text-text-muted\">Description</dt>\n <dd className=\"text-text-secondary\">\n {event.description?.trim() ? event.description : 'No description provided.'}\n </dd>\n </div>\n </dl>\n <div className=\"mt-5\">\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => navigate(`/events/${id}/edit`)}>\n <Edit className=\"h-4 w-4\" />\n Edit event details\n </Button>\n </div>\n </GlassCard>\n\n <GlassCard treatment=\"glass\" glow className=\"p-5\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Key Metrics</h2>\n <dl className=\"mt-4 space-y-4\">\n <div>\n <dt className=\"text-sm text-text-secondary\">Capacity</dt>\n <dd className=\"text-2xl font-semibold tabular-nums text-text-primary\">\n {(event.capacity ?? 0).toLocaleString()}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm text-text-secondary\">Sessions</dt>\n <dd className=\"text-2xl font-semibold tabular-nums text-text-primary\">\n {sessionCount.toLocaleString()}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm text-text-secondary\">Ticket types</dt>\n <dd className=\"text-2xl font-semibold tabular-nums text-text-primary\">\n {(ticketsData?.ticketTypes?.total ?? 0).toLocaleString()}\n </dd>\n </div>\n <div>\n <dt className=\"text-sm text-text-secondary\">Tickets sold</dt>\n <dd className=\"text-2xl font-semibold tabular-nums text-text-primary\">\n {ticketsSold.toLocaleString()}\n </dd>\n </div>\n </dl>\n </GlassCard>\n </div>\n </TabsContent>\n\n <TabsContent value=\"sessions\" className=\"mt-4\">\n <SessionsTab eventId={id} />\n </TabsContent>\n\n <TabsContent value=\"speakers\" className=\"mt-4\">\n <SpeakersTab />\n </TabsContent>\n\n <TabsContent value=\"tickets\" className=\"mt-4\">\n <TicketsTab eventId={id} />\n </TabsContent>\n </Tabs>\n </div>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export default function EventFormPage(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=EventFormPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EventFormPage.d.ts","sourceRoot":"","sources":["../../../../src/eventfullymanaged/pages/events/EventFormPage.tsx"],"names":[],"mappings":"AAkDA,MAAM,CAAC,OAAO,UAAU,aAAa,4CA6NpC"}
@@ -0,0 +1,2 @@
1
+ export default function SessionFormPage(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=SessionFormPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SessionFormPage.d.ts","sourceRoot":"","sources":["../../../../src/eventfullymanaged/pages/events/SessionFormPage.tsx"],"names":[],"mappings":"AAmGA,MAAM,CAAC,OAAO,UAAU,eAAe,4CA8OtC"}
@@ -0,0 +1,2 @@
1
+ export default function TicketTypeFormPage(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=TicketTypeFormPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TicketTypeFormPage.d.ts","sourceRoot":"","sources":["../../../../src/eventfullymanaged/pages/events/TicketTypeFormPage.tsx"],"names":[],"mappings":"AAiDA,MAAM,CAAC,OAAO,UAAU,kBAAkB,4CAyLzC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Shared helpers for the event-scoped forms (event, session, ticket-type).
3
+ *
4
+ * The backend persists all timestamps as ISO-8601 `DateTime` scalar strings,
5
+ * while the browser `<input type="datetime-local">` control speaks the
6
+ * `YYYY-MM-DDTHH:mm` local-time format. These two helpers are the single choke
7
+ * point that converts between them so every form treats dates consistently and
8
+ * never sends an unparseable value to the resolver.
9
+ */
10
+ /** ISO string → `datetime-local` input value (local time). Empty on bad input. */
11
+ export declare function isoToInputValue(iso: string | null | undefined): string;
12
+ /** `datetime-local` input value → ISO string. Empty string when unset/invalid. */
13
+ export declare function inputValueToIso(value: string): string;
14
+ /** Human-friendly label for event/session headers. Empty when unparseable. */
15
+ export declare function formatDateTime(iso: string | null | undefined): string;
16
+ export declare const EVENT_TYPE_OPTIONS: ReadonlyArray<{
17
+ value: string;
18
+ label: string;
19
+ }>;
20
+ export declare const EVENT_STATUS_OPTIONS: ReadonlyArray<{
21
+ value: string;
22
+ label: string;
23
+ }>;
24
+ export declare const EVENT_VISIBILITY_OPTIONS: ReadonlyArray<{
25
+ value: string;
26
+ label: string;
27
+ }>;
28
+ export declare const SESSION_TYPE_OPTIONS: ReadonlyArray<{
29
+ value: string;
30
+ label: string;
31
+ }>;
32
+ export declare const SESSION_STATUS_OPTIONS: ReadonlyArray<{
33
+ value: string;
34
+ label: string;
35
+ }>;
36
+ export declare const CURRENCY_OPTIONS: ReadonlyArray<{
37
+ value: string;
38
+ label: string;
39
+ }>;
40
+ //# sourceMappingURL=eventFormUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eventFormUtils.d.ts","sourceRoot":"","sources":["../../../../src/eventfullymanaged/pages/events/eventFormUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAWtE;AAED,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CASrD;AAED,8EAA8E;AAC9E,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CASrE;AAED,eAAO,MAAM,kBAAkB,EAAE,aAAa,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAI9E,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,aAAa,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAMhF,CAAC;AAEF,eAAO,MAAM,wBAAwB,EAAE,aAAa,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAIpF,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,aAAa,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAOhF,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,aAAa,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAKlF,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,aAAa,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAK5E,CAAC"}
@@ -0,0 +1,2 @@
1
+ export default function ExhibitorFormPage(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=ExhibitorFormPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExhibitorFormPage.d.ts","sourceRoot":"","sources":["../../../../src/eventfullymanaged/pages/exhibitors/ExhibitorFormPage.tsx"],"names":[],"mappings":"AA8CA,MAAM,CAAC,OAAO,UAAU,iBAAiB,4CA4KxC"}
@@ -0,0 +1,2 @@
1
+ export default function ExhibitorsPage(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=ExhibitorsPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExhibitorsPage.d.ts","sourceRoot":"","sources":["../../../../src/eventfullymanaged/pages/exhibitors/ExhibitorsPage.tsx"],"names":[],"mappings":"AAwEA,MAAM,CAAC,OAAO,UAAU,cAAc,4CAmRrC"}
@@ -0,0 +1,23 @@
1
+ export interface LeadCaptureDialogProps {
2
+ open: boolean;
3
+ onOpenChange: (open: boolean) => void;
4
+ /** Event the lead belongs to. */
5
+ eventId: string;
6
+ /** Booth/exhibitor that scanned the lead (mutually exclusive with sponsorId). */
7
+ exhibitorId?: string;
8
+ /** Sponsor that captured the lead. */
9
+ sponsorId?: string;
10
+ /** Friendly name shown in the dialog title, e.g. the exhibitor or sponsor name. */
11
+ contextLabel: string;
12
+ /** Fired after a lead is successfully persisted so the caller can refetch. */
13
+ onCreated?: () => void;
14
+ }
15
+ /**
16
+ * Booth/sponsor lead-capture dialog. Records the person a booth just scanned as
17
+ * an EventfullyManaged lead via `useCreateLeadMutation`, attaching either the
18
+ * `exhibitorId` or `sponsorId` context. The captured company is preserved in
19
+ * `metadata.company` (no first-class column) and `scannedAt` maps to the
20
+ * backend `capturedAt` timestamp.
21
+ */
22
+ export declare function LeadCaptureDialog({ open, onOpenChange, eventId, exhibitorId, sponsorId, contextLabel, onCreated, }: LeadCaptureDialogProps): import("react/jsx-runtime").JSX.Element;
23
+ //# sourceMappingURL=LeadCaptureDialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LeadCaptureDialog.d.ts","sourceRoot":"","sources":["../../../../src/eventfullymanaged/pages/leads/LeadCaptureDialog.tsx"],"names":[],"mappings":"AA0BA,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mFAAmF;IACnF,YAAY,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB;AAoBD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,IAAI,EACJ,YAAY,EACZ,OAAO,EACP,WAAW,EACX,SAAS,EACT,YAAY,EACZ,SAAS,GACV,EAAE,sBAAsB,2CAmIxB"}
@@ -0,0 +1,2 @@
1
+ export default function AnalyticsPage(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=AnalyticsPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnalyticsPage.d.ts","sourceRoot":"","sources":["../../../../src/eventfullymanaged/pages/modules/AnalyticsPage.tsx"],"names":[],"mappings":"AAwIA,MAAM,CAAC,OAAO,UAAU,aAAa,4CAuRpC"}