@burdenoff/microfe-eventfullymanaged 2026.704.2 → 2026.704.3
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.
- package/dist/eventfullymanaged/pages/modules/AttendeeProfilePage.js +2 -2
- package/dist/eventfullymanaged/pages/modules/AttendeeProfilePage.js.map +1 -1
- package/dist/eventfullymanaged/pages/modules/NetworkingPage.js +13 -12
- package/dist/eventfullymanaged/pages/modules/NetworkingPage.js.map +1 -1
- package/dist/eventfullymanaged/pages/modules/SponsorDetailsPage.js +2 -2
- package/dist/eventfullymanaged/pages/modules/SponsorDetailsPage.js.map +1 -1
- package/package.json +1 -1
|
@@ -10,11 +10,11 @@ import { ContextConversationWidget as _ } from "@burdenoff/fe-libs/shared";
|
|
|
10
10
|
import { useRegisterPageConversationContext as v } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
11
11
|
//#region src/eventfullymanaged/pages/modules/AttendeeProfilePage.tsx
|
|
12
12
|
function y({ attendeeId: e, attendeeName: t }) {
|
|
13
|
-
return v({
|
|
13
|
+
return v(i(() => ({
|
|
14
14
|
entityType: "EVENTFULLYMANAGED_ATTENDEE",
|
|
15
15
|
entityId: e,
|
|
16
16
|
contextTitle: `Attendee · ${t}`
|
|
17
|
-
}), /* @__PURE__ */ s(_, { widgetKey: "attendee-message" });
|
|
17
|
+
}), [e, t])), /* @__PURE__ */ s(_, { widgetKey: "attendee-message" });
|
|
18
18
|
}
|
|
19
19
|
function b() {
|
|
20
20
|
let { id: _ = "" } = o(), { navigate: v } = e(), b = t({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AttendeeProfilePage.js","names":[],"sources":["../../../../src/eventfullymanaged/pages/modules/AttendeeProfilePage.tsx"],"sourcesContent":["import { MessageSquare, Ticket, Users } from 'lucide-react';\nimport { ContextConversationWidget } from '@burdenoff/fe-libs/shared';\nimport { useRegisterPageConversationContext } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { EmphasisPanel, GlassCard, GradientText, NextSteps, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { useMemo, useRef } from 'react';\nimport { useParams } from 'react-router-dom';\n\nimport { useAttendeesQuery, useRegistrationsQuery } from '../../api/eventApi';\nimport { useEventfullyManaged } from '../../context/EventfullyManagedContext';\nimport { EntityListSection } from './EntityListSection';\n\n/**\n * Direct message thread with a single attendee, backed by wspace-conversations-svc.\n * Kept as a dedicated component so `useRegisterPageConversationContext` scopes the\n * thread to this attendee (entityType + entityId) and unregisters on unmount.\n */\nfunction AttendeeConversation({ attendeeId, attendeeName }: { attendeeId: string; attendeeName: string }) {\n useRegisterPageConversationContext({\n entityType: 'EVENTFULLYMANAGED_ATTENDEE',\n entityId: attendeeId,\n contextTitle: `Attendee · ${attendeeName}`,\n });\n return <ContextConversationWidget widgetKey=\"attendee-message\" />;\n}\n\ntype AttendeeRow = {\n id: string;\n fullName?: string;\n email?: string;\n company?: string;\n role?: string;\n};\n\ntype RegistrationRow = {\n id: string;\n attendeeId?: string;\n status?: string;\n quantity?: number;\n currency?: string;\n totalAmount?: string;\n};\n\nexport default function AttendeeProfilePage() {\n const { id = '' } = useParams();\n const { navigate } = useEventfullyManaged();\n const attendeesQuery = useAttendeesQuery({ limit: 100, offset: 0 });\n const registrationsQuery = useRegistrationsQuery({ limit: 100, offset: 0 });\n const conversationRef = useRef<HTMLDivElement | null>(null);\n\n const attendee = useMemo(\n () => ((attendeesQuery.data?.attendees.items ?? []) as AttendeeRow[]).find((item) => item.id === id),\n [id, attendeesQuery.data]\n );\n const registrations = useMemo(\n () =>\n ((registrationsQuery.data?.registrations.items ?? []) as RegistrationRow[]).filter(\n (registration) => registration.attendeeId === id\n ),\n [id, registrationsQuery.data]\n );\n\n return (\n <div className=\"space-y-6 p-6\">\n <PagePurpose>\n A single view of one attendee — who they are and everything they have registered for. Use this when you need to\n look someone up: verify their ticket, answer a support question, or understand their history with your events\n before reaching out.\n </PagePurpose>\n\n <EmphasisPanel>\n <h1 className=\"text-2xl font-bold text-text-primary\">\n <GradientText>Attendee</GradientText> Profile\n </h1>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {attendeesQuery.loading\n ? 'Loading attendee profile...'\n : attendee\n ? `${attendee.fullName ?? attendee.id} profile from registration and attendee APIs.`\n : 'Attendee not found in current query scope.'}\n </p>\n {attendee ? (\n <div className=\"mt-4 grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n <GlassCard treatment=\"metric\" className=\"p-3\">\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">Name</p>\n <p className=\"mt-1 font-medium text-text-primary\">{attendee.fullName ?? attendee.id}</p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-3\">\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">Email</p>\n <p className=\"mt-1 font-medium text-text-primary\">{attendee.email ?? 'Unavailable'}</p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-3\">\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">Company</p>\n <p className=\"mt-1 font-medium text-text-primary\">{attendee.company ?? 'Unavailable'}</p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-3\">\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">Role</p>\n <p className=\"mt-1 font-medium text-text-primary\">{attendee.role ?? 'Unavailable'}</p>\n </GlassCard>\n </div>\n ) : null}\n </EmphasisPanel>\n\n <EntityListSection\n heading={\n registrationsQuery.loading ? 'Loading attendee registrations...' : `Registrations (${registrations.length})`\n }\n emptyLabel=\"No registrations linked to this attendee.\"\n rows={registrations.map((registration) => ({\n id: registration.id,\n title: `Registration ${registration.id}`,\n subtitle: [\n registration.quantity ? `Qty ${registration.quantity}` : undefined,\n registration.totalAmount ? `${registration.totalAmount} ${registration.currency ?? ''}` : undefined,\n ]\n .filter(Boolean)\n .join(' • '),\n status: registration.status,\n }))}\n />\n\n {id ? (\n <div ref={conversationRef} className=\"space-y-3\">\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">Messages</h2>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Start a direct conversation with this attendee. Threads and attachments are handled by the shared\n conversations service.\n </p>\n </div>\n <AttendeeConversation attendeeId={id} attendeeName={attendee?.fullName ?? attendee?.id ?? id} />\n </div>\n ) : null}\n\n <NextSteps\n storageKey=\"eventfullymanaged-attendee-profile\"\n title=\"Act on this attendee\"\n steps={[\n {\n id: 'view-registrations',\n label: 'Review all registrations',\n description: 'See the full registration list to manage tickets and payments.',\n icon: <Ticket className=\"h-4 w-4\" />,\n onClick: () => navigate('/registration'),\n },\n {\n id: 'networking',\n label: 'Find networking matches',\n description: 'Connect this attendee with relevant people and meetings.',\n icon: <Users className=\"h-4 w-4\" />,\n onClick: () => navigate('/networking'),\n },\n {\n id: 'reach-out',\n label: 'Send a message',\n description: 'Open a direct conversation thread with this attendee.',\n icon: <MessageSquare className=\"h-4 w-4\" />,\n onClick: () => conversationRef.current?.scrollIntoView({ behavior: 'smooth', block: 'start' }),\n },\n ]}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AttendeeProfilePage.js","names":[],"sources":["../../../../src/eventfullymanaged/pages/modules/AttendeeProfilePage.tsx"],"sourcesContent":["import { MessageSquare, Ticket, Users } from 'lucide-react';\nimport { ContextConversationWidget } from '@burdenoff/fe-libs/shared';\nimport { useRegisterPageConversationContext } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { EmphasisPanel, GlassCard, GradientText, NextSteps, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { useMemo, useRef } from 'react';\nimport { useParams } from 'react-router-dom';\n\nimport { useAttendeesQuery, useRegistrationsQuery } from '../../api/eventApi';\nimport { useEventfullyManaged } from '../../context/EventfullyManagedContext';\nimport { EntityListSection } from './EntityListSection';\n\n/**\n * Direct message thread with a single attendee, backed by wspace-conversations-svc.\n * Kept as a dedicated component so `useRegisterPageConversationContext` scopes the\n * thread to this attendee (entityType + entityId) and unregisters on unmount.\n */\nfunction AttendeeConversation({ attendeeId, attendeeName }: { attendeeId: string; attendeeName: string }) {\n // Stable reference: `useRegisterPageConversationContext` keys its effect on this\n // object's identity, so a fresh inline object every render would loop the shared\n // PageConversationContextProvider (see NetworkingPage for the full rationale).\n const conversationContext = useMemo(\n () => ({\n entityType: 'EVENTFULLYMANAGED_ATTENDEE',\n entityId: attendeeId,\n contextTitle: `Attendee · ${attendeeName}`,\n }),\n [attendeeId, attendeeName]\n );\n useRegisterPageConversationContext(conversationContext);\n return <ContextConversationWidget widgetKey=\"attendee-message\" />;\n}\n\ntype AttendeeRow = {\n id: string;\n fullName?: string;\n email?: string;\n company?: string;\n role?: string;\n};\n\ntype RegistrationRow = {\n id: string;\n attendeeId?: string;\n status?: string;\n quantity?: number;\n currency?: string;\n totalAmount?: string;\n};\n\nexport default function AttendeeProfilePage() {\n const { id = '' } = useParams();\n const { navigate } = useEventfullyManaged();\n const attendeesQuery = useAttendeesQuery({ limit: 100, offset: 0 });\n const registrationsQuery = useRegistrationsQuery({ limit: 100, offset: 0 });\n const conversationRef = useRef<HTMLDivElement | null>(null);\n\n const attendee = useMemo(\n () => ((attendeesQuery.data?.attendees.items ?? []) as AttendeeRow[]).find((item) => item.id === id),\n [id, attendeesQuery.data]\n );\n const registrations = useMemo(\n () =>\n ((registrationsQuery.data?.registrations.items ?? []) as RegistrationRow[]).filter(\n (registration) => registration.attendeeId === id\n ),\n [id, registrationsQuery.data]\n );\n\n return (\n <div className=\"space-y-6 p-6\">\n <PagePurpose>\n A single view of one attendee — who they are and everything they have registered for. Use this when you need to\n look someone up: verify their ticket, answer a support question, or understand their history with your events\n before reaching out.\n </PagePurpose>\n\n <EmphasisPanel>\n <h1 className=\"text-2xl font-bold text-text-primary\">\n <GradientText>Attendee</GradientText> Profile\n </h1>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {attendeesQuery.loading\n ? 'Loading attendee profile...'\n : attendee\n ? `${attendee.fullName ?? attendee.id} profile from registration and attendee APIs.`\n : 'Attendee not found in current query scope.'}\n </p>\n {attendee ? (\n <div className=\"mt-4 grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n <GlassCard treatment=\"metric\" className=\"p-3\">\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">Name</p>\n <p className=\"mt-1 font-medium text-text-primary\">{attendee.fullName ?? attendee.id}</p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-3\">\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">Email</p>\n <p className=\"mt-1 font-medium text-text-primary\">{attendee.email ?? 'Unavailable'}</p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-3\">\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">Company</p>\n <p className=\"mt-1 font-medium text-text-primary\">{attendee.company ?? 'Unavailable'}</p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-3\">\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">Role</p>\n <p className=\"mt-1 font-medium text-text-primary\">{attendee.role ?? 'Unavailable'}</p>\n </GlassCard>\n </div>\n ) : null}\n </EmphasisPanel>\n\n <EntityListSection\n heading={\n registrationsQuery.loading ? 'Loading attendee registrations...' : `Registrations (${registrations.length})`\n }\n emptyLabel=\"No registrations linked to this attendee.\"\n rows={registrations.map((registration) => ({\n id: registration.id,\n title: `Registration ${registration.id}`,\n subtitle: [\n registration.quantity ? `Qty ${registration.quantity}` : undefined,\n registration.totalAmount ? `${registration.totalAmount} ${registration.currency ?? ''}` : undefined,\n ]\n .filter(Boolean)\n .join(' • '),\n status: registration.status,\n }))}\n />\n\n {id ? (\n <div ref={conversationRef} className=\"space-y-3\">\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">Messages</h2>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Start a direct conversation with this attendee. Threads and attachments are handled by the shared\n conversations service.\n </p>\n </div>\n <AttendeeConversation attendeeId={id} attendeeName={attendee?.fullName ?? attendee?.id ?? id} />\n </div>\n ) : null}\n\n <NextSteps\n storageKey=\"eventfullymanaged-attendee-profile\"\n title=\"Act on this attendee\"\n steps={[\n {\n id: 'view-registrations',\n label: 'Review all registrations',\n description: 'See the full registration list to manage tickets and payments.',\n icon: <Ticket className=\"h-4 w-4\" />,\n onClick: () => navigate('/registration'),\n },\n {\n id: 'networking',\n label: 'Find networking matches',\n description: 'Connect this attendee with relevant people and meetings.',\n icon: <Users className=\"h-4 w-4\" />,\n onClick: () => navigate('/networking'),\n },\n {\n id: 'reach-out',\n label: 'Send a message',\n description: 'Open a direct conversation thread with this attendee.',\n icon: <MessageSquare className=\"h-4 w-4\" />,\n onClick: () => conversationRef.current?.scrollIntoView({ behavior: 'smooth', block: 'start' }),\n },\n ]}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -90,14 +90,15 @@ function j({ heading: e, loading: t, rows: n, total: r, emptyLabel: i, itemLabel
|
|
|
90
90
|
]
|
|
91
91
|
});
|
|
92
92
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}), /* @__PURE__ */ p(O, { widgetKey: "networking-lounge" });
|
|
99
|
-
}
|
|
93
|
+
var M = {
|
|
94
|
+
entityType: "EVENTFULLYMANAGED_NETWORKING_LOUNGE",
|
|
95
|
+
entityId: "general",
|
|
96
|
+
contextTitle: "Networking Lounge"
|
|
97
|
+
};
|
|
100
98
|
function N() {
|
|
99
|
+
return k(M), /* @__PURE__ */ p(O, { widgetKey: "networking-lounge" });
|
|
100
|
+
}
|
|
101
|
+
function P() {
|
|
101
102
|
let { navigate: c } = e(), b = l(), C = l(), T = l(), O = o({
|
|
102
103
|
limit: b.limit,
|
|
103
104
|
offset: b.offset
|
|
@@ -107,14 +108,14 @@ function N() {
|
|
|
107
108
|
}), A = i({
|
|
108
109
|
limit: T.limit,
|
|
109
110
|
offset: T.offset
|
|
110
|
-
}), { data:
|
|
111
|
+
}), { data: M } = n({
|
|
111
112
|
limit: 100,
|
|
112
113
|
offset: 0
|
|
113
114
|
}), [P] = r(), F = f(() => {
|
|
114
115
|
let e = /* @__PURE__ */ new Map();
|
|
115
|
-
for (let t of
|
|
116
|
+
for (let t of M?.attendees?.items ?? []) e.set(t.id, t.fullName);
|
|
116
117
|
return e;
|
|
117
|
-
}, [
|
|
118
|
+
}, [M]), I = f(() => O.data?.networkingProfiles.items ?? [], [O.data]), L = f(() => k.data?.networkingMatches.items ?? [], [k.data]), R = f(() => A.data?.meetings.items ?? [], [A.data]), z = I.map((e) => ({
|
|
118
119
|
id: e.id,
|
|
119
120
|
title: F.get(e.attendeeId) ?? (e.attendeeId ? `Attendee ${e.attendeeId}` : `Profile ${e.id}`),
|
|
120
121
|
subtitle: [e.role, e.industry].filter(Boolean).join(" • ") || void 0,
|
|
@@ -217,7 +218,7 @@ function N() {
|
|
|
217
218
|
}), /* @__PURE__ */ p("p", {
|
|
218
219
|
className: "mt-1 text-sm text-text-secondary",
|
|
219
220
|
children: "A shared space for attendees and organizers to connect, backed by the conversations service."
|
|
220
|
-
})] }), /* @__PURE__ */ p(
|
|
221
|
+
})] }), /* @__PURE__ */ p(N, {})]
|
|
221
222
|
}),
|
|
222
223
|
/* @__PURE__ */ p(E, {
|
|
223
224
|
storageKey: "eventfullymanaged-networking",
|
|
@@ -250,6 +251,6 @@ function N() {
|
|
|
250
251
|
});
|
|
251
252
|
}
|
|
252
253
|
//#endregion
|
|
253
|
-
export {
|
|
254
|
+
export { P as default };
|
|
254
255
|
|
|
255
256
|
//# sourceMappingURL=NetworkingPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NetworkingPage.js","names":[],"sources":["../../../../src/eventfullymanaged/pages/modules/NetworkingPage.tsx"],"sourcesContent":["import { CalendarDays, CalendarPlus, Megaphone, UserPlus, Users } from 'lucide-react';\nimport { ContextConversationWidget } from '@burdenoff/fe-libs/shared';\nimport { useRegisterPageConversationContext } from '@burdenoff/fe-libs/shared/providers/shell';\nimport {\n Badge,\n Button,\n EmphasisPanel,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n NextSteps,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { useMemo, type ReactNode } from 'react';\n\nimport {\n useAttendeesQuery,\n useDeleteMeetingMutation,\n useMeetingsQuery,\n useNetworkingMatchesQuery,\n useNetworkingProfilesQuery,\n} from '../../api/eventApi';\nimport { ActionMenu } from '../../components/ActionMenu';\nimport { Pagination, usePagination, type UsePaginationResult } from '../../components/Pagination';\nimport { useEventfullyManaged } from '../../context/EventfullyManagedContext';\nimport { describeError, mutationSucceeded } from '../../lib/mutationResult';\nimport { notify } from '../../lib/toast';\n\ntype SimpleRow = {\n id: string;\n name?: string;\n title?: string;\n status?: string;\n};\n\ntype ListRow = {\n id: string;\n title: string;\n subtitle?: string;\n status?: string;\n};\n\nfunction statusVariant(status: string): 'success' | 'warning' | 'secondary' | 'info' {\n const value = status.toLowerCase();\n if (['active', 'published', 'live', 'confirmed', 'completed', 'approved', 'public'].includes(value)) {\n return 'success';\n }\n if (['inactive', 'cancelled', 'archived', 'closed', 'expired', 'private'].includes(value)) {\n return 'warning';\n }\n if (['draft', 'created', 'pending', 'scheduled'].includes(value)) {\n return 'info';\n }\n return 'secondary';\n}\n\ninterface NetworkingListProps {\n heading: string;\n loading: boolean;\n rows: ListRow[];\n total: number;\n emptyLabel: string;\n itemLabel: string;\n pagination: UsePaginationResult;\n renderActions?: (row: ListRow) => ReactNode;\n}\n\nfunction NetworkingList({\n heading,\n loading,\n rows,\n total,\n emptyLabel,\n itemLabel,\n pagination,\n renderActions,\n}: NetworkingListProps) {\n return (\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-5\">\n <h2 className=\"text-lg font-semibold text-text-primary\">{loading ? `${heading}…` : `${heading} (${total})`}</h2>\n <div className=\"mt-4\">\n {rows.length === 0 ? (\n <IllustratedEmptyState illustration=\"empty-people\" title={emptyLabel} className=\"py-8\" />\n ) : (\n <ul className=\"space-y-2.5\">\n {rows.map((row) => (\n <li\n key={row.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=\"min-w-0\">\n <p className=\"truncate font-medium text-text-primary\">{row.title}</p>\n {row.subtitle ? (\n <p className=\"mt-0.5 truncate text-sm text-text-secondary\">{row.subtitle}</p>\n ) : null}\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n {row.status ? (\n <Badge variant={statusVariant(row.status)} className=\"uppercase\">\n {row.status}\n </Badge>\n ) : null}\n {renderActions?.(row)}\n </div>\n </div>\n </li>\n ))}\n </ul>\n )}\n </div>\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={itemLabel}\n loading={loading}\n />\n </GlassCard>\n );\n}\n\n/**\n * Shared networking lounge chat, backed by wspace-conversations-svc. Scoped by a\n * stable networking entity so every organizer/attendee on this workspace lands in\n * the same thread.\n */\nfunction NetworkingLounge() {\n useRegisterPageConversationContext({\n entityType: 'EVENTFULLYMANAGED_NETWORKING_LOUNGE',\n entityId: 'general',\n contextTitle: 'Networking Lounge',\n });\n return <ContextConversationWidget widgetKey=\"networking-lounge\" />;\n}\n\nexport default function NetworkingPage() {\n const { navigate } = useEventfullyManaged();\n\n const profilesPagination = usePagination();\n const matchesPagination = usePagination();\n const meetingsPagination = usePagination();\n\n const profilesQuery = useNetworkingProfilesQuery({\n limit: profilesPagination.limit,\n offset: profilesPagination.offset,\n });\n const matchesQuery = useNetworkingMatchesQuery({\n limit: matchesPagination.limit,\n offset: matchesPagination.offset,\n });\n const meetingsQuery = useMeetingsQuery({\n limit: meetingsPagination.limit,\n offset: meetingsPagination.offset,\n });\n const { data: attendeesData } = useAttendeesQuery({ limit: 100, offset: 0 });\n\n const [deleteMeeting] = useDeleteMeetingMutation();\n\n const attendeeNames = useMemo(() => {\n const map = new Map<string, string>();\n for (const attendee of attendeesData?.attendees?.items ?? []) {\n map.set(attendee.id, attendee.fullName);\n }\n return map;\n }, [attendeesData]);\n\n const profiles = useMemo(() => profilesQuery.data?.networkingProfiles.items ?? [], [profilesQuery.data]);\n const matches = useMemo(() => (matchesQuery.data?.networkingMatches.items ?? []) as SimpleRow[], [matchesQuery.data]);\n const meetings = useMemo(() => (meetingsQuery.data?.meetings.items ?? []) as SimpleRow[], [meetingsQuery.data]);\n\n const profileRows: ListRow[] = profiles.map((row) => ({\n id: row.id,\n title: attendeeNames.get(row.attendeeId) ?? (row.attendeeId ? `Attendee ${row.attendeeId}` : `Profile ${row.id}`),\n subtitle: [row.role, row.industry].filter(Boolean).join(' • ') || undefined,\n status: row.visibility,\n }));\n\n const matchRows: ListRow[] = matches.map((row) => ({\n id: row.id,\n title: row.name ?? row.title ?? `Match ${row.id}`,\n subtitle: 'Suggested by networking engine',\n status: row.status ?? undefined,\n }));\n\n const meetingRows: ListRow[] = meetings.map((row) => ({\n id: row.id,\n title: row.title ?? row.name ?? `Meeting ${row.id}`,\n status: row.status ?? undefined,\n }));\n\n const onDeleteMeeting = async (row: ListRow) => {\n try {\n const response = await deleteMeeting({ variables: { id: row.id } });\n const deleted = response.data?.deleteMeeting === true;\n if (!mutationSucceeded(response, deleted ? row.id : undefined, 'Could not delete meeting')) {\n return;\n }\n notify.success('Meeting removed', `${row.title} was deleted.`);\n await meetingsQuery.refetch();\n } catch (error) {\n notify.error('Could not delete meeting', describeError(error));\n }\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <PagePurpose>\n Networking turns attendees into connections. Profiles describe who each attendee is and what they are looking\n for, matches are the suggestions the engine makes between them, and meetings are the 1:1s they book. Opt an\n attendee in, review strong matches, and book meetings that mirror straight into the calendar.\n </PagePurpose>\n\n <EmphasisPanel className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h1 className=\"text-2xl font-bold text-text-primary\">\n <GradientText>Networking</GradientText>\n </h1>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Manage profiles, matches and meeting schedules from live backend data.\n </p>\n </div>\n <div className=\"flex flex-wrap gap-2\">\n <Button type=\"button\" variant=\"outline\" onClick={() => navigate('/networking/profiles/create')}>\n <UserPlus className=\"h-4 w-4\" />\n Opt in a profile\n </Button>\n <Button type=\"button\" onClick={() => navigate('/networking/meetings/create')}>\n <CalendarPlus className=\"h-4 w-4\" />\n Book a meeting\n </Button>\n </div>\n </EmphasisPanel>\n\n <NetworkingList\n heading=\"Profiles\"\n loading={profilesQuery.loading}\n rows={profileRows}\n total={profilesQuery.data?.networkingProfiles.total ?? 0}\n emptyLabel=\"No networking profiles yet. Opt an attendee in to get started.\"\n itemLabel=\"profiles\"\n pagination={profilesPagination}\n renderActions={(row) => (\n <ActionMenu\n ariaLabel={`${row.title} actions`}\n onEdit={() => navigate(`/networking/profiles/${row.id}/edit`)}\n />\n )}\n />\n\n <NetworkingList\n heading=\"Matches\"\n loading={matchesQuery.loading}\n rows={matchRows}\n total={matchesQuery.data?.networkingMatches.total ?? 0}\n emptyLabel=\"No networking matches yet.\"\n itemLabel=\"matches\"\n pagination={matchesPagination}\n renderActions={(row) => (\n <ActionMenu\n ariaLabel={`${row.title} actions`}\n extraItems={[\n {\n key: 'book',\n label: 'Book meeting',\n icon: CalendarPlus,\n onSelect: () => navigate('/networking/meetings/create'),\n },\n ]}\n />\n )}\n />\n\n <NetworkingList\n heading=\"Meetings\"\n loading={meetingsQuery.loading}\n rows={meetingRows}\n total={meetingsQuery.data?.meetings.total ?? 0}\n emptyLabel=\"No meetings scheduled yet.\"\n itemLabel=\"meetings\"\n pagination={meetingsPagination}\n renderActions={(row) => (\n <ActionMenu\n ariaLabel={`${row.title} actions`}\n entityName={row.title}\n onEdit={() => navigate(`/networking/meetings/${row.id}/edit`)}\n onDelete={() => onDeleteMeeting(row)}\n />\n )}\n />\n\n <div className=\"space-y-3\">\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">Networking chat</h2>\n <p className=\"mt-1 text-sm text-text-secondary\">\n A shared space for attendees and organizers to connect, backed by the conversations service.\n </p>\n </div>\n <NetworkingLounge />\n </div>\n\n <NextSteps\n storageKey=\"eventfullymanaged-networking\"\n title=\"Make networking land\"\n steps={[\n {\n id: 'grow-attendees',\n label: 'Bring in more attendees',\n description: 'More registered attendees means richer matches and meetings.',\n icon: <Users className=\"h-4 w-4\" />,\n onClick: () => navigate('/registration'),\n },\n {\n id: 'announce-networking',\n label: 'Announce networking sessions',\n description: 'Let attendees know how and when to connect.',\n icon: <Megaphone className=\"h-4 w-4\" />,\n onClick: () => navigate('/communication'),\n },\n {\n id: 'review-event',\n label: 'Review the event schedule',\n description: 'Make sure networking slots fit around your sessions.',\n icon: <CalendarDays className=\"h-4 w-4\" />,\n onClick: () => navigate('/events'),\n },\n ]}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"NetworkingPage.js","names":[],"sources":["../../../../src/eventfullymanaged/pages/modules/NetworkingPage.tsx"],"sourcesContent":["import { CalendarDays, CalendarPlus, Megaphone, UserPlus, Users } from 'lucide-react';\nimport { ContextConversationWidget } from '@burdenoff/fe-libs/shared';\nimport { useRegisterPageConversationContext } from '@burdenoff/fe-libs/shared/providers/shell';\nimport {\n Badge,\n Button,\n EmphasisPanel,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n NextSteps,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { useMemo, type ReactNode } from 'react';\n\nimport {\n useAttendeesQuery,\n useDeleteMeetingMutation,\n useMeetingsQuery,\n useNetworkingMatchesQuery,\n useNetworkingProfilesQuery,\n} from '../../api/eventApi';\nimport { ActionMenu } from '../../components/ActionMenu';\nimport { Pagination, usePagination, type UsePaginationResult } from '../../components/Pagination';\nimport { useEventfullyManaged } from '../../context/EventfullyManagedContext';\nimport { describeError, mutationSucceeded } from '../../lib/mutationResult';\nimport { notify } from '../../lib/toast';\n\ntype SimpleRow = {\n id: string;\n name?: string;\n title?: string;\n status?: string;\n};\n\ntype ListRow = {\n id: string;\n title: string;\n subtitle?: string;\n status?: string;\n};\n\nfunction statusVariant(status: string): 'success' | 'warning' | 'secondary' | 'info' {\n const value = status.toLowerCase();\n if (['active', 'published', 'live', 'confirmed', 'completed', 'approved', 'public'].includes(value)) {\n return 'success';\n }\n if (['inactive', 'cancelled', 'archived', 'closed', 'expired', 'private'].includes(value)) {\n return 'warning';\n }\n if (['draft', 'created', 'pending', 'scheduled'].includes(value)) {\n return 'info';\n }\n return 'secondary';\n}\n\ninterface NetworkingListProps {\n heading: string;\n loading: boolean;\n rows: ListRow[];\n total: number;\n emptyLabel: string;\n itemLabel: string;\n pagination: UsePaginationResult;\n renderActions?: (row: ListRow) => ReactNode;\n}\n\nfunction NetworkingList({\n heading,\n loading,\n rows,\n total,\n emptyLabel,\n itemLabel,\n pagination,\n renderActions,\n}: NetworkingListProps) {\n return (\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-5\">\n <h2 className=\"text-lg font-semibold text-text-primary\">{loading ? `${heading}…` : `${heading} (${total})`}</h2>\n <div className=\"mt-4\">\n {rows.length === 0 ? (\n <IllustratedEmptyState illustration=\"empty-people\" title={emptyLabel} className=\"py-8\" />\n ) : (\n <ul className=\"space-y-2.5\">\n {rows.map((row) => (\n <li\n key={row.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=\"min-w-0\">\n <p className=\"truncate font-medium text-text-primary\">{row.title}</p>\n {row.subtitle ? (\n <p className=\"mt-0.5 truncate text-sm text-text-secondary\">{row.subtitle}</p>\n ) : null}\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n {row.status ? (\n <Badge variant={statusVariant(row.status)} className=\"uppercase\">\n {row.status}\n </Badge>\n ) : null}\n {renderActions?.(row)}\n </div>\n </div>\n </li>\n ))}\n </ul>\n )}\n </div>\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={itemLabel}\n loading={loading}\n />\n </GlassCard>\n );\n}\n\n/**\n * Registration payload for the networking lounge conversation context.\n *\n * MUST be a stable (module-level) reference. `useRegisterPageConversationContext`\n * keys its effect on this object's identity; passing a fresh inline object on\n * every render makes the effect re-run each render, which toggles state on the\n * shared PageConversationContextProvider (an ancestor of this MFE's <Routes> in\n * the app shell). That perpetual re-render loop races client-side navigations\n * dispatched from this page, so links like \"Opt in a profile\" / \"Book a meeting\"\n * changed the URL but never re-matched the create route. Keeping the reference\n * constant lets the effect settle after the first run.\n */\nconst NETWORKING_LOUNGE_CONTEXT = {\n entityType: 'EVENTFULLYMANAGED_NETWORKING_LOUNGE',\n entityId: 'general',\n contextTitle: 'Networking Lounge',\n};\n\n/**\n * Shared networking lounge chat, backed by wspace-conversations-svc. Scoped by a\n * stable networking entity so every organizer/attendee on this workspace lands in\n * the same thread.\n */\nfunction NetworkingLounge() {\n useRegisterPageConversationContext(NETWORKING_LOUNGE_CONTEXT);\n return <ContextConversationWidget widgetKey=\"networking-lounge\" />;\n}\n\nexport default function NetworkingPage() {\n const { navigate } = useEventfullyManaged();\n\n const profilesPagination = usePagination();\n const matchesPagination = usePagination();\n const meetingsPagination = usePagination();\n\n const profilesQuery = useNetworkingProfilesQuery({\n limit: profilesPagination.limit,\n offset: profilesPagination.offset,\n });\n const matchesQuery = useNetworkingMatchesQuery({\n limit: matchesPagination.limit,\n offset: matchesPagination.offset,\n });\n const meetingsQuery = useMeetingsQuery({\n limit: meetingsPagination.limit,\n offset: meetingsPagination.offset,\n });\n const { data: attendeesData } = useAttendeesQuery({ limit: 100, offset: 0 });\n\n const [deleteMeeting] = useDeleteMeetingMutation();\n\n const attendeeNames = useMemo(() => {\n const map = new Map<string, string>();\n for (const attendee of attendeesData?.attendees?.items ?? []) {\n map.set(attendee.id, attendee.fullName);\n }\n return map;\n }, [attendeesData]);\n\n const profiles = useMemo(() => profilesQuery.data?.networkingProfiles.items ?? [], [profilesQuery.data]);\n const matches = useMemo(() => (matchesQuery.data?.networkingMatches.items ?? []) as SimpleRow[], [matchesQuery.data]);\n const meetings = useMemo(() => (meetingsQuery.data?.meetings.items ?? []) as SimpleRow[], [meetingsQuery.data]);\n\n const profileRows: ListRow[] = profiles.map((row) => ({\n id: row.id,\n title: attendeeNames.get(row.attendeeId) ?? (row.attendeeId ? `Attendee ${row.attendeeId}` : `Profile ${row.id}`),\n subtitle: [row.role, row.industry].filter(Boolean).join(' • ') || undefined,\n status: row.visibility,\n }));\n\n const matchRows: ListRow[] = matches.map((row) => ({\n id: row.id,\n title: row.name ?? row.title ?? `Match ${row.id}`,\n subtitle: 'Suggested by networking engine',\n status: row.status ?? undefined,\n }));\n\n const meetingRows: ListRow[] = meetings.map((row) => ({\n id: row.id,\n title: row.title ?? row.name ?? `Meeting ${row.id}`,\n status: row.status ?? undefined,\n }));\n\n const onDeleteMeeting = async (row: ListRow) => {\n try {\n const response = await deleteMeeting({ variables: { id: row.id } });\n const deleted = response.data?.deleteMeeting === true;\n if (!mutationSucceeded(response, deleted ? row.id : undefined, 'Could not delete meeting')) {\n return;\n }\n notify.success('Meeting removed', `${row.title} was deleted.`);\n await meetingsQuery.refetch();\n } catch (error) {\n notify.error('Could not delete meeting', describeError(error));\n }\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <PagePurpose>\n Networking turns attendees into connections. Profiles describe who each attendee is and what they are looking\n for, matches are the suggestions the engine makes between them, and meetings are the 1:1s they book. Opt an\n attendee in, review strong matches, and book meetings that mirror straight into the calendar.\n </PagePurpose>\n\n <EmphasisPanel className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h1 className=\"text-2xl font-bold text-text-primary\">\n <GradientText>Networking</GradientText>\n </h1>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Manage profiles, matches and meeting schedules from live backend data.\n </p>\n </div>\n <div className=\"flex flex-wrap gap-2\">\n <Button type=\"button\" variant=\"outline\" onClick={() => navigate('/networking/profiles/create')}>\n <UserPlus className=\"h-4 w-4\" />\n Opt in a profile\n </Button>\n <Button type=\"button\" onClick={() => navigate('/networking/meetings/create')}>\n <CalendarPlus className=\"h-4 w-4\" />\n Book a meeting\n </Button>\n </div>\n </EmphasisPanel>\n\n <NetworkingList\n heading=\"Profiles\"\n loading={profilesQuery.loading}\n rows={profileRows}\n total={profilesQuery.data?.networkingProfiles.total ?? 0}\n emptyLabel=\"No networking profiles yet. Opt an attendee in to get started.\"\n itemLabel=\"profiles\"\n pagination={profilesPagination}\n renderActions={(row) => (\n <ActionMenu\n ariaLabel={`${row.title} actions`}\n onEdit={() => navigate(`/networking/profiles/${row.id}/edit`)}\n />\n )}\n />\n\n <NetworkingList\n heading=\"Matches\"\n loading={matchesQuery.loading}\n rows={matchRows}\n total={matchesQuery.data?.networkingMatches.total ?? 0}\n emptyLabel=\"No networking matches yet.\"\n itemLabel=\"matches\"\n pagination={matchesPagination}\n renderActions={(row) => (\n <ActionMenu\n ariaLabel={`${row.title} actions`}\n extraItems={[\n {\n key: 'book',\n label: 'Book meeting',\n icon: CalendarPlus,\n onSelect: () => navigate('/networking/meetings/create'),\n },\n ]}\n />\n )}\n />\n\n <NetworkingList\n heading=\"Meetings\"\n loading={meetingsQuery.loading}\n rows={meetingRows}\n total={meetingsQuery.data?.meetings.total ?? 0}\n emptyLabel=\"No meetings scheduled yet.\"\n itemLabel=\"meetings\"\n pagination={meetingsPagination}\n renderActions={(row) => (\n <ActionMenu\n ariaLabel={`${row.title} actions`}\n entityName={row.title}\n onEdit={() => navigate(`/networking/meetings/${row.id}/edit`)}\n onDelete={() => onDeleteMeeting(row)}\n />\n )}\n />\n\n <div className=\"space-y-3\">\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">Networking chat</h2>\n <p className=\"mt-1 text-sm text-text-secondary\">\n A shared space for attendees and organizers to connect, backed by the conversations service.\n </p>\n </div>\n <NetworkingLounge />\n </div>\n\n <NextSteps\n storageKey=\"eventfullymanaged-networking\"\n title=\"Make networking land\"\n steps={[\n {\n id: 'grow-attendees',\n label: 'Bring in more attendees',\n description: 'More registered attendees means richer matches and meetings.',\n icon: <Users className=\"h-4 w-4\" />,\n onClick: () => navigate('/registration'),\n },\n {\n id: 'announce-networking',\n label: 'Announce networking sessions',\n description: 'Let attendees know how and when to connect.',\n icon: <Megaphone className=\"h-4 w-4\" />,\n onClick: () => navigate('/communication'),\n },\n {\n id: 'review-event',\n label: 'Review the event schedule',\n description: 'Make sure networking slots fit around your sessions.',\n icon: <CalendarDays className=\"h-4 w-4\" />,\n onClick: () => navigate('/events'),\n },\n ]}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -11,11 +11,11 @@ import { ContextConversationWidget as _ } from "@burdenoff/fe-libs/shared";
|
|
|
11
11
|
import { useRegisterPageConversationContext as v } from "@burdenoff/fe-libs/shared/providers/shell";
|
|
12
12
|
//#region src/eventfullymanaged/pages/modules/SponsorDetailsPage.tsx
|
|
13
13
|
function y({ sponsorId: e, sponsorName: t }) {
|
|
14
|
-
return v({
|
|
14
|
+
return v(a(() => ({
|
|
15
15
|
entityType: "EVENTFULLYMANAGED_SPONSOR",
|
|
16
16
|
entityId: e,
|
|
17
17
|
contextTitle: `Sponsor · ${t}`
|
|
18
|
-
}), /* @__PURE__ */ s(_, { widgetKey: "sponsor-message" });
|
|
18
|
+
}), [e, t])), /* @__PURE__ */ s(_, { widgetKey: "sponsor-message" });
|
|
19
19
|
}
|
|
20
20
|
function b() {
|
|
21
21
|
let { id: _ = "" } = o(), { navigate: v } = e(), b = n({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SponsorDetailsPage.js","names":[],"sources":["../../../../src/eventfullymanaged/pages/modules/SponsorDetailsPage.tsx"],"sourcesContent":["import { Megaphone, Pencil, TrendingUp } from 'lucide-react';\nimport { ContextConversationWidget } from '@burdenoff/fe-libs/shared';\nimport { useRegisterPageConversationContext } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { EmphasisPanel, GlassCard, GradientText, NextSteps, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { useMemo } from 'react';\nimport { useParams } from 'react-router-dom';\n\nimport { useCommunicationCampaignsQuery, useSponsorsQuery } from '../../api/eventApi';\nimport { EntityTagsField } from '../../components/EntityTagsField';\nimport { useEventfullyManaged } from '../../context/EventfullyManagedContext';\nimport { EntityListSection } from './EntityListSection';\n\n/**\n * Sponsor ↔ organizer message thread, backed by wspace-conversations-svc and\n * scoped to this sponsor so the conversation follows the partnership.\n */\nfunction SponsorConversation({ sponsorId, sponsorName }: { sponsorId: string; sponsorName: string }) {\n useRegisterPageConversationContext({\n
|
|
1
|
+
{"version":3,"file":"SponsorDetailsPage.js","names":[],"sources":["../../../../src/eventfullymanaged/pages/modules/SponsorDetailsPage.tsx"],"sourcesContent":["import { Megaphone, Pencil, TrendingUp } from 'lucide-react';\nimport { ContextConversationWidget } from '@burdenoff/fe-libs/shared';\nimport { useRegisterPageConversationContext } from '@burdenoff/fe-libs/shared/providers/shell';\nimport { EmphasisPanel, GlassCard, GradientText, NextSteps, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { useMemo } from 'react';\nimport { useParams } from 'react-router-dom';\n\nimport { useCommunicationCampaignsQuery, useSponsorsQuery } from '../../api/eventApi';\nimport { EntityTagsField } from '../../components/EntityTagsField';\nimport { useEventfullyManaged } from '../../context/EventfullyManagedContext';\nimport { EntityListSection } from './EntityListSection';\n\n/**\n * Sponsor ↔ organizer message thread, backed by wspace-conversations-svc and\n * scoped to this sponsor so the conversation follows the partnership.\n */\nfunction SponsorConversation({ sponsorId, sponsorName }: { sponsorId: string; sponsorName: string }) {\n // Stable reference: `useRegisterPageConversationContext` keys its effect on this\n // object's identity, so a fresh inline object every render would loop the shared\n // PageConversationContextProvider (see NetworkingPage for the full rationale).\n const conversationContext = useMemo(\n () => ({\n entityType: 'EVENTFULLYMANAGED_SPONSOR',\n entityId: sponsorId,\n contextTitle: `Sponsor · ${sponsorName}`,\n }),\n [sponsorId, sponsorName]\n );\n useRegisterPageConversationContext(conversationContext);\n return <ContextConversationWidget widgetKey=\"sponsor-message\" />;\n}\n\ntype SponsorRow = {\n id: string;\n name: string;\n level: string;\n website?: string | null;\n contactName?: string | null;\n contactEmail?: string | null;\n};\n\ntype CampaignRow = {\n id: string;\n name?: string;\n title?: string;\n status?: string;\n};\n\nexport default function SponsorDetailsPage() {\n const { id = '' } = useParams();\n const { navigate } = useEventfullyManaged();\n const sponsorsQuery = useSponsorsQuery({ limit: 100, offset: 0 });\n const campaignsQuery = useCommunicationCampaignsQuery({ limit: 100, offset: 0 });\n\n const sponsor = useMemo(\n () => ((sponsorsQuery.data?.sponsors.items ?? []) as SponsorRow[]).find((item) => item.id === id),\n [id, sponsorsQuery.data]\n );\n const campaigns = useMemo(\n () => (campaignsQuery.data?.communicationCampaigns.items ?? []) as CampaignRow[],\n [campaignsQuery.data]\n );\n\n return (\n <div className=\"space-y-6 p-6\">\n <PagePurpose>\n Everything about one sponsor in one place — their tier, contacts, and the campaigns they appear in. Use this to\n prep for a sponsor conversation, confirm their contact details, or check how their branded campaigns are\n performing.\n </PagePurpose>\n\n <EmphasisPanel>\n <h1 className=\"text-2xl font-bold text-text-primary\">\n <GradientText>Sponsor</GradientText> Details\n </h1>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {sponsorsQuery.loading\n ? 'Loading sponsor details...'\n : sponsor\n ? `Live sponsor profile for ${sponsor.name}.`\n : 'Sponsor not found in current query scope.'}\n </p>\n {sponsor ? (\n <div className=\"mt-4 grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4\">\n <GlassCard treatment=\"metric\" className=\"p-3\">\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">Level</p>\n <p className=\"mt-1 font-medium text-text-primary\">{sponsor.level}</p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-3\">\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">Contact</p>\n <p className=\"mt-1 font-medium text-text-primary\">{sponsor.contactName ?? 'Unassigned'}</p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-3\">\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">Email</p>\n <p className=\"mt-1 font-medium text-text-primary\">{sponsor.contactEmail ?? 'Unavailable'}</p>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"p-3\">\n <p className=\"text-xs uppercase tracking-wide text-text-secondary\">Website</p>\n <p className=\"mt-1 truncate font-medium text-text-primary\">{sponsor.website ?? 'Unavailable'}</p>\n </GlassCard>\n </div>\n ) : null}\n </EmphasisPanel>\n\n {sponsor ? (\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-5\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Tags</h2>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Label this sponsor so you can segment your portfolio — for example by industry, tier or renewal status.\n </p>\n <EntityTagsField entityType=\"sponsor\" entityId={sponsor.id} label=\"Sponsor tags\" className=\"mt-3\" />\n </GlassCard>\n ) : null}\n\n <EntityListSection\n heading={campaignsQuery.loading ? 'Loading campaigns...' : `Campaign Activity (${campaigns.length})`}\n emptyLabel=\"No communication campaigns available for sponsor tracking.\"\n rows={campaigns.map((campaign) => ({\n id: campaign.id,\n title: campaign.title ?? campaign.name ?? `Campaign ${campaign.id}`,\n status: campaign.status,\n }))}\n />\n\n {sponsor ? (\n <div className=\"space-y-3\">\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">Sponsor messages</h2>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Coordinate with this sponsor in a dedicated thread, backed by the conversations service.\n </p>\n </div>\n <SponsorConversation sponsorId={sponsor.id} sponsorName={sponsor.name} />\n </div>\n ) : null}\n\n <NextSteps\n storageKey=\"eventfullymanaged-sponsor-details\"\n title=\"Grow this partnership\"\n steps={[\n {\n id: 'edit-sponsor',\n label: 'Update sponsor details',\n description: 'Keep tier, contacts and contract value current.',\n icon: <Pencil className=\"h-4 w-4\" />,\n onClick: () => navigate(id ? `/sponsors/${id}/edit` : '/sponsors'),\n },\n {\n id: 'track-leads',\n label: 'Track sponsor leads',\n description: 'See the leads this sponsor is generating at the event.',\n icon: <TrendingUp className=\"h-4 w-4\" />,\n onClick: () => navigate(id ? `/sponsors/${id}/leads` : '/sponsors'),\n },\n {\n id: 'run-campaign',\n label: 'Run a co-branded campaign',\n description: 'Promote this sponsor through a communication campaign.',\n icon: <Megaphone className=\"h-4 w-4\" />,\n onClick: () => navigate('/communication'),\n },\n ]}\n />\n </div>\n );\n}\n"],"mappings":"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"}
|