@burdenoff/microfe-eventfullymanaged 2026.625.1 → 2026.703.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 (57) hide show
  1. package/dist/eventfullymanaged/api/eventApi.js +83 -38
  2. package/dist/eventfullymanaged/api/eventApi.js.map +1 -1
  3. package/dist/eventfullymanaged/components/ImageUploadField.js +98 -0
  4. package/dist/eventfullymanaged/components/ImageUploadField.js.map +1 -0
  5. package/dist/eventfullymanaged/lib/mutationResult.js +12 -0
  6. package/dist/eventfullymanaged/lib/mutationResult.js.map +1 -0
  7. package/dist/eventfullymanaged/lib/toast.js +36 -0
  8. package/dist/eventfullymanaged/lib/toast.js.map +1 -0
  9. package/dist/eventfullymanaged/pages/dashboard/DashboardPage.js +88 -47
  10. package/dist/eventfullymanaged/pages/dashboard/DashboardPage.js.map +1 -1
  11. package/dist/eventfullymanaged/pages/modules/AnalyticsPage.js +63 -51
  12. package/dist/eventfullymanaged/pages/modules/AnalyticsPage.js.map +1 -1
  13. package/dist/eventfullymanaged/pages/modules/AttendeeProfilePage.js +137 -78
  14. package/dist/eventfullymanaged/pages/modules/AttendeeProfilePage.js.map +1 -1
  15. package/dist/eventfullymanaged/pages/modules/CommunicationPage.js +56 -45
  16. package/dist/eventfullymanaged/pages/modules/CommunicationPage.js.map +1 -1
  17. package/dist/eventfullymanaged/pages/modules/EventsPage.js +89 -52
  18. package/dist/eventfullymanaged/pages/modules/EventsPage.js.map +1 -1
  19. package/dist/eventfullymanaged/pages/modules/KioskPage.js +11 -10
  20. package/dist/eventfullymanaged/pages/modules/KioskPage.js.map +1 -1
  21. package/dist/eventfullymanaged/pages/modules/NetworkingPage.js +73 -24
  22. package/dist/eventfullymanaged/pages/modules/NetworkingPage.js.map +1 -1
  23. package/dist/eventfullymanaged/pages/modules/OperationsHubPage.js +135 -105
  24. package/dist/eventfullymanaged/pages/modules/OperationsHubPage.js.map +1 -1
  25. package/dist/eventfullymanaged/pages/modules/RegistrationPage.js +63 -33
  26. package/dist/eventfullymanaged/pages/modules/RegistrationPage.js.map +1 -1
  27. package/dist/eventfullymanaged/pages/modules/SponsorDetailsPage.js +132 -77
  28. package/dist/eventfullymanaged/pages/modules/SponsorDetailsPage.js.map +1 -1
  29. package/dist/eventfullymanaged/pages/modules/SponsorLeadsPage.js +54 -23
  30. package/dist/eventfullymanaged/pages/modules/SponsorLeadsPage.js.map +1 -1
  31. package/dist/eventfullymanaged/pages/modules/VenueResourcesPage.js +67 -37
  32. package/dist/eventfullymanaged/pages/modules/VenueResourcesPage.js.map +1 -1
  33. package/dist/eventfullymanaged/pages/modules/WorkflowsPage.js +81 -48
  34. package/dist/eventfullymanaged/pages/modules/WorkflowsPage.js.map +1 -1
  35. package/dist/eventfullymanaged/pages/sponsors/SponsorFormPage.js +161 -133
  36. package/dist/eventfullymanaged/pages/sponsors/SponsorFormPage.js.map +1 -1
  37. package/dist/eventfullymanaged/pages/sponsors/SponsorsListPage.js +22 -21
  38. package/dist/eventfullymanaged/pages/sponsors/SponsorsListPage.js.map +1 -1
  39. package/dist/eventfullymanaged/pages/venues/FloorPlansPage.js +103 -61
  40. package/dist/eventfullymanaged/pages/venues/FloorPlansPage.js.map +1 -1
  41. package/dist/eventfullymanaged/pages/venues/VenueDetailPage.js +67 -38
  42. package/dist/eventfullymanaged/pages/venues/VenueDetailPage.js.map +1 -1
  43. package/dist/eventfullymanaged/pages/venues/VenueFormPage.js +156 -147
  44. package/dist/eventfullymanaged/pages/venues/VenueFormPage.js.map +1 -1
  45. package/dist/eventfullymanaged/pages/venues/VenueListPage.js +23 -22
  46. package/dist/eventfullymanaged/pages/venues/VenueListPage.js.map +1 -1
  47. package/dist/node_modules/@apollo/client/react/context/ApolloContext.js.map +1 -1
  48. package/dist/node_modules/@apollo/client/react/hooks/internal/useDeepMemo.js.map +1 -1
  49. package/dist/node_modules/@apollo/client/react/hooks/internal/useIsomorphicLayoutEffect.js.map +1 -1
  50. package/dist/node_modules/@apollo/client/react/hooks/internal/wrapHook.js.map +1 -1
  51. package/dist/node_modules/@apollo/client/react/hooks/useApolloClient.js.map +1 -1
  52. package/dist/node_modules/@apollo/client/react/hooks/useMutation.js.map +1 -1
  53. package/dist/node_modules/@apollo/client/react/hooks/useQuery.js.map +1 -1
  54. package/dist/node_modules/@apollo/client/react/hooks/useSyncExternalStore.js.map +1 -1
  55. package/dist/node_modules/sonner/dist/index.js +163 -0
  56. package/dist/node_modules/sonner/dist/index.js.map +1 -0
  57. package/package.json +2 -2
@@ -1,91 +1,150 @@
1
- import { useAttendeesQuery as e, useRegistrationsQuery as t } from "../../api/eventApi.js";
2
- import { EntityListSection as n } from "./EntityListSection.js";
3
- import { useMemo as r } from "react";
4
- import { useParams as i } from "react-router-dom";
5
- import { jsx as a, jsxs as o } from "react/jsx-runtime";
6
- import { EmphasisPanel as s, GlassCard as c, GradientText as l } from "@burdenoff/fe-libs/ui";
1
+ import { useEventfullyManaged as e } from "../../context/EventfullyManagedContext.js";
2
+ import { useAttendeesQuery as t, useRegistrationsQuery as n } from "../../api/eventApi.js";
3
+ import { EntityListSection as r } from "./EntityListSection.js";
4
+ import { useMemo as i, useRef as a } from "react";
5
+ import { useParams as o } from "react-router-dom";
6
+ import { jsx as s, jsxs as c } from "react/jsx-runtime";
7
+ import { MessageSquare as l, Ticket as u, Users as d } from "lucide-react";
8
+ import { EmphasisPanel as f, GlassCard as p, GradientText as m, NextSteps as h, PagePurpose as g } from "@burdenoff/fe-libs/ui";
9
+ import { ContextConversationWidget as _ } from "@burdenoff/fe-libs/shared";
10
+ import { useRegisterPageConversationContext as v } from "@burdenoff/fe-libs/shared/providers/shell";
7
11
  //#region src/eventfullymanaged/pages/modules/AttendeeProfilePage.tsx
8
- function u() {
9
- let { id: u = "" } = i(), d = e({
12
+ function y({ attendeeId: e, attendeeName: t }) {
13
+ return v({
14
+ entityType: "EVENTFULLYMANAGED_ATTENDEE",
15
+ entityId: e,
16
+ contextTitle: `Attendee · ${t}`
17
+ }), /* @__PURE__ */ s(_, { widgetKey: "attendee-message" });
18
+ }
19
+ function b() {
20
+ let { id: _ = "" } = o(), { navigate: v } = e(), b = t({
10
21
  limit: 100,
11
22
  offset: 0
12
- }), f = t({
23
+ }), x = n({
13
24
  limit: 100,
14
25
  offset: 0
15
- }), p = r(() => (d.data?.attendees.items ?? []).find((e) => e.id === u), [u, d.data]), m = r(() => (f.data?.registrations.items ?? []).filter((e) => e.attendeeId === u), [u, f.data]);
16
- return /* @__PURE__ */ o("div", {
26
+ }), S = a(null), C = i(() => (b.data?.attendees.items ?? []).find((e) => e.id === _), [_, b.data]), w = i(() => (x.data?.registrations.items ?? []).filter((e) => e.attendeeId === _), [_, x.data]);
27
+ return /* @__PURE__ */ c("div", {
17
28
  className: "space-y-6 p-6",
18
- children: [/* @__PURE__ */ o(s, { children: [
19
- /* @__PURE__ */ o("h1", {
20
- className: "text-2xl font-bold text-text-primary",
21
- children: [/* @__PURE__ */ a(l, { children: "Attendee" }), " Profile"]
22
- }),
23
- /* @__PURE__ */ a("p", {
24
- className: "mt-1 text-sm text-text-secondary",
25
- children: d.loading ? "Loading attendee profile..." : p ? `${p.fullName ?? p.id} profile from registration and attendee APIs.` : "Attendee not found in current query scope."
29
+ children: [
30
+ /* @__PURE__ */ s(g, { children: "A single view of one attendee — who they are and everything they have registered for. Use this when you need to look someone up: verify their ticket, answer a support question, or understand their history with your events before reaching out." }),
31
+ /* @__PURE__ */ c(f, { children: [
32
+ /* @__PURE__ */ c("h1", {
33
+ className: "text-2xl font-bold text-text-primary",
34
+ children: [/* @__PURE__ */ s(m, { children: "Attendee" }), " Profile"]
35
+ }),
36
+ /* @__PURE__ */ s("p", {
37
+ className: "mt-1 text-sm text-text-secondary",
38
+ children: b.loading ? "Loading attendee profile..." : C ? `${C.fullName ?? C.id} profile from registration and attendee APIs.` : "Attendee not found in current query scope."
39
+ }),
40
+ C ? /* @__PURE__ */ c("div", {
41
+ className: "mt-4 grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4",
42
+ children: [
43
+ /* @__PURE__ */ c(p, {
44
+ treatment: "metric",
45
+ className: "p-3",
46
+ children: [/* @__PURE__ */ s("p", {
47
+ className: "text-xs uppercase tracking-wide text-text-secondary",
48
+ children: "Name"
49
+ }), /* @__PURE__ */ s("p", {
50
+ className: "mt-1 font-medium text-text-primary",
51
+ children: C.fullName ?? C.id
52
+ })]
53
+ }),
54
+ /* @__PURE__ */ c(p, {
55
+ treatment: "metric",
56
+ className: "p-3",
57
+ children: [/* @__PURE__ */ s("p", {
58
+ className: "text-xs uppercase tracking-wide text-text-secondary",
59
+ children: "Email"
60
+ }), /* @__PURE__ */ s("p", {
61
+ className: "mt-1 font-medium text-text-primary",
62
+ children: C.email ?? "Unavailable"
63
+ })]
64
+ }),
65
+ /* @__PURE__ */ c(p, {
66
+ treatment: "metric",
67
+ className: "p-3",
68
+ children: [/* @__PURE__ */ s("p", {
69
+ className: "text-xs uppercase tracking-wide text-text-secondary",
70
+ children: "Company"
71
+ }), /* @__PURE__ */ s("p", {
72
+ className: "mt-1 font-medium text-text-primary",
73
+ children: C.company ?? "Unavailable"
74
+ })]
75
+ }),
76
+ /* @__PURE__ */ c(p, {
77
+ treatment: "metric",
78
+ className: "p-3",
79
+ children: [/* @__PURE__ */ s("p", {
80
+ className: "text-xs uppercase tracking-wide text-text-secondary",
81
+ children: "Role"
82
+ }), /* @__PURE__ */ s("p", {
83
+ className: "mt-1 font-medium text-text-primary",
84
+ children: C.role ?? "Unavailable"
85
+ })]
86
+ })
87
+ ]
88
+ }) : null
89
+ ] }),
90
+ /* @__PURE__ */ s(r, {
91
+ heading: x.loading ? "Loading attendee registrations..." : `Registrations (${w.length})`,
92
+ emptyLabel: "No registrations linked to this attendee.",
93
+ rows: w.map((e) => ({
94
+ id: e.id,
95
+ title: `Registration ${e.id}`,
96
+ subtitle: [e.quantity ? `Qty ${e.quantity}` : void 0, e.totalAmount ? `${e.totalAmount} ${e.currency ?? ""}` : void 0].filter(Boolean).join(" • "),
97
+ status: e.status
98
+ }))
26
99
  }),
27
- p ? /* @__PURE__ */ o("div", {
28
- className: "mt-4 grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4",
29
- children: [
30
- /* @__PURE__ */ o(c, {
31
- treatment: "metric",
32
- className: "p-3",
33
- children: [/* @__PURE__ */ a("p", {
34
- className: "text-xs uppercase tracking-wide text-text-secondary",
35
- children: "Name"
36
- }), /* @__PURE__ */ a("p", {
37
- className: "mt-1 font-medium text-text-primary",
38
- children: p.fullName ?? p.id
39
- })]
40
- }),
41
- /* @__PURE__ */ o(c, {
42
- treatment: "metric",
43
- className: "p-3",
44
- children: [/* @__PURE__ */ a("p", {
45
- className: "text-xs uppercase tracking-wide text-text-secondary",
46
- children: "Email"
47
- }), /* @__PURE__ */ a("p", {
48
- className: "mt-1 font-medium text-text-primary",
49
- children: p.email ?? "Unavailable"
50
- })]
51
- }),
52
- /* @__PURE__ */ o(c, {
53
- treatment: "metric",
54
- className: "p-3",
55
- children: [/* @__PURE__ */ a("p", {
56
- className: "text-xs uppercase tracking-wide text-text-secondary",
57
- children: "Company"
58
- }), /* @__PURE__ */ a("p", {
59
- className: "mt-1 font-medium text-text-primary",
60
- children: p.company ?? "Unavailable"
61
- })]
62
- }),
63
- /* @__PURE__ */ o(c, {
64
- treatment: "metric",
65
- className: "p-3",
66
- children: [/* @__PURE__ */ a("p", {
67
- className: "text-xs uppercase tracking-wide text-text-secondary",
68
- children: "Role"
69
- }), /* @__PURE__ */ a("p", {
70
- className: "mt-1 font-medium text-text-primary",
71
- children: p.role ?? "Unavailable"
72
- })]
73
- })
100
+ _ ? /* @__PURE__ */ c("div", {
101
+ ref: S,
102
+ className: "space-y-3",
103
+ children: [/* @__PURE__ */ c("div", { children: [/* @__PURE__ */ s("h2", {
104
+ className: "text-lg font-semibold text-text-primary",
105
+ children: "Messages"
106
+ }), /* @__PURE__ */ s("p", {
107
+ className: "mt-1 text-sm text-text-secondary",
108
+ children: "Start a direct conversation with this attendee. Threads and attachments are handled by the shared conversations service."
109
+ })] }), /* @__PURE__ */ s(y, {
110
+ attendeeId: _,
111
+ attendeeName: C?.fullName ?? C?.id ?? _
112
+ })]
113
+ }) : null,
114
+ /* @__PURE__ */ s(h, {
115
+ storageKey: "eventfullymanaged-attendee-profile",
116
+ title: "Act on this attendee",
117
+ steps: [
118
+ {
119
+ id: "view-registrations",
120
+ label: "Review all registrations",
121
+ description: "See the full registration list to manage tickets and payments.",
122
+ icon: /* @__PURE__ */ s(u, { className: "h-4 w-4" }),
123
+ onClick: () => v("/registration")
124
+ },
125
+ {
126
+ id: "networking",
127
+ label: "Find networking matches",
128
+ description: "Connect this attendee with relevant people and meetings.",
129
+ icon: /* @__PURE__ */ s(d, { className: "h-4 w-4" }),
130
+ onClick: () => v("/networking")
131
+ },
132
+ {
133
+ id: "reach-out",
134
+ label: "Send a message",
135
+ description: "Open a direct conversation thread with this attendee.",
136
+ icon: /* @__PURE__ */ s(l, { className: "h-4 w-4" }),
137
+ onClick: () => S.current?.scrollIntoView({
138
+ behavior: "smooth",
139
+ block: "start"
140
+ })
141
+ }
74
142
  ]
75
- }) : null
76
- ] }), /* @__PURE__ */ a(n, {
77
- heading: f.loading ? "Loading attendee registrations..." : `Registrations (${m.length})`,
78
- emptyLabel: "No registrations linked to this attendee.",
79
- rows: m.map((e) => ({
80
- id: e.id,
81
- title: `Registration ${e.id}`,
82
- subtitle: [e.quantity ? `Qty ${e.quantity}` : void 0, e.totalAmount ? `${e.totalAmount} ${e.currency ?? ""}` : void 0].filter(Boolean).join(" • "),
83
- status: e.status
84
- }))
85
- })]
143
+ })
144
+ ]
86
145
  });
87
146
  }
88
147
  //#endregion
89
- export { u as default };
148
+ export { b as default };
90
149
 
91
150
  //# sourceMappingURL=AttendeeProfilePage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AttendeeProfilePage.js","names":[],"sources":["../../../../src/eventfullymanaged/pages/modules/AttendeeProfilePage.tsx"],"sourcesContent":["import { EmphasisPanel, GlassCard, GradientText } from '@burdenoff/fe-libs/ui';\nimport { useMemo } from 'react';\nimport { useParams } from 'react-router-dom';\n\nimport { useAttendeesQuery, useRegistrationsQuery } from '../../api/eventApi';\nimport { EntityListSection } from './EntityListSection';\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 attendeesQuery = useAttendeesQuery({ limit: 100, offset: 0 });\n const registrationsQuery = useRegistrationsQuery({ limit: 100, offset: 0 });\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 <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 </div>\n );\n}\n"],"mappings":";;;;;;;AAwBA,SAAwB,IAAsB;CAC5C,IAAM,EAAE,QAAK,OAAO,GAAW,EACzB,IAAiB,EAAkB;EAAE,OAAO;EAAK,QAAQ;EAAG,CAAC,EAC7D,IAAqB,EAAsB;EAAE,OAAO;EAAK,QAAQ;EAAG,CAAC,EAErE,IAAW,SACP,EAAe,MAAM,UAAU,SAAS,EAAE,EAAoB,MAAM,MAAS,EAAK,OAAO,EAAG,EACpG,CAAC,GAAI,EAAe,KAAK,CAC1B,EACK,IAAgB,SAEhB,EAAmB,MAAM,cAAc,SAAS,EAAE,EAAwB,QACzE,MAAiB,EAAa,eAAe,EAC/C,EACH,CAAC,GAAI,EAAmB,KAAK,CAC9B;AAED,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,GAAD,EAAA,UAAA;GACE,kBAAC,MAAD;IAAI,WAAU;cAAd,CACE,kBAAC,GAAD,EAAA,UAAc,YAAuB,CAAA,EAAA,WAClC;;GACL,kBAAC,KAAD;IAAG,WAAU;cACV,EAAe,UACZ,gCACA,IACE,GAAG,EAAS,YAAY,EAAS,GAAG,iDACpC;IACJ,CAAA;GACH,IACC,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MAAW,WAAU;MAAS,WAAU;gBAAxC,CACE,kBAAC,KAAD;OAAG,WAAU;iBAAsD;OAAQ,CAAA,EAC3E,kBAAC,KAAD;OAAG,WAAU;iBAAsC,EAAS,YAAY,EAAS;OAAO,CAAA,CAC9E;;KACZ,kBAAC,GAAD;MAAW,WAAU;MAAS,WAAU;gBAAxC,CACE,kBAAC,KAAD;OAAG,WAAU;iBAAsD;OAAS,CAAA,EAC5E,kBAAC,KAAD;OAAG,WAAU;iBAAsC,EAAS,SAAS;OAAkB,CAAA,CAC7E;;KACZ,kBAAC,GAAD;MAAW,WAAU;MAAS,WAAU;gBAAxC,CACE,kBAAC,KAAD;OAAG,WAAU;iBAAsD;OAAW,CAAA,EAC9E,kBAAC,KAAD;OAAG,WAAU;iBAAsC,EAAS,WAAW;OAAkB,CAAA,CAC/E;;KACZ,kBAAC,GAAD;MAAW,WAAU;MAAS,WAAU;gBAAxC,CACE,kBAAC,KAAD;OAAG,WAAU;iBAAsD;OAAQ,CAAA,EAC3E,kBAAC,KAAD;OAAG,WAAU;iBAAsC,EAAS,QAAQ;OAAkB,CAAA,CAC5E;;KACR;QACJ;GACU,EAAA,CAAA,EAEhB,kBAAC,GAAD;GACE,SACE,EAAmB,UAAU,sCAAsC,kBAAkB,EAAc,OAAO;GAE5G,YAAW;GACX,MAAM,EAAc,KAAK,OAAkB;IACzC,IAAI,EAAa;IACjB,OAAO,gBAAgB,EAAa;IACpC,UAAU,CACR,EAAa,WAAW,OAAO,EAAa,aAAa,KAAA,GACzD,EAAa,cAAc,GAAG,EAAa,YAAY,GAAG,EAAa,YAAY,OAAO,KAAA,EAC3F,CACE,OAAO,QAAQ,CACf,KAAK,MAAM;IACd,QAAQ,EAAa;IACtB,EAAE;GACH,CAAA,CACE"}
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":";;;;;;;;;;;AAgBA,SAAS,EAAqB,EAAE,eAAY,mBAA8D;AAMxG,QALA,EAAmC;EACjC,YAAY;EACZ,UAAU;EACV,cAAc,cAAc;EAC7B,CAAC,EACK,kBAAC,GAAD,EAA2B,WAAU,oBAAqB,CAAA;;AAoBnE,SAAwB,IAAsB;CAC5C,IAAM,EAAE,QAAK,OAAO,GAAW,EACzB,EAAE,gBAAa,GAAsB,EACrC,IAAiB,EAAkB;EAAE,OAAO;EAAK,QAAQ;EAAG,CAAC,EAC7D,IAAqB,EAAsB;EAAE,OAAO;EAAK,QAAQ;EAAG,CAAC,EACrE,IAAkB,EAA8B,KAAK,EAErD,IAAW,SACP,EAAe,MAAM,UAAU,SAAS,EAAE,EAAoB,MAAM,MAAS,EAAK,OAAO,EAAG,EACpG,CAAC,GAAI,EAAe,KAAK,CAC1B,EACK,IAAgB,SAEhB,EAAmB,MAAM,cAAc,SAAS,EAAE,EAAwB,QACzE,MAAiB,EAAa,eAAe,EAC/C,EACH,CAAC,GAAI,EAAmB,KAAK,CAC9B;AAED,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,GAAD,EAAA,UAAa,sPAIC,CAAA;GAEd,kBAAC,GAAD,EAAA,UAAA;IACE,kBAAC,MAAD;KAAI,WAAU;eAAd,CACE,kBAAC,GAAD,EAAA,UAAc,YAAuB,CAAA,EAAA,WAClC;;IACL,kBAAC,KAAD;KAAG,WAAU;eACV,EAAe,UACZ,gCACA,IACE,GAAG,EAAS,YAAY,EAAS,GAAG,iDACpC;KACJ,CAAA;IACH,IACC,kBAAC,OAAD;KAAK,WAAU;eAAf;MACE,kBAAC,GAAD;OAAW,WAAU;OAAS,WAAU;iBAAxC,CACE,kBAAC,KAAD;QAAG,WAAU;kBAAsD;QAAQ,CAAA,EAC3E,kBAAC,KAAD;QAAG,WAAU;kBAAsC,EAAS,YAAY,EAAS;QAAO,CAAA,CAC9E;;MACZ,kBAAC,GAAD;OAAW,WAAU;OAAS,WAAU;iBAAxC,CACE,kBAAC,KAAD;QAAG,WAAU;kBAAsD;QAAS,CAAA,EAC5E,kBAAC,KAAD;QAAG,WAAU;kBAAsC,EAAS,SAAS;QAAkB,CAAA,CAC7E;;MACZ,kBAAC,GAAD;OAAW,WAAU;OAAS,WAAU;iBAAxC,CACE,kBAAC,KAAD;QAAG,WAAU;kBAAsD;QAAW,CAAA,EAC9E,kBAAC,KAAD;QAAG,WAAU;kBAAsC,EAAS,WAAW;QAAkB,CAAA,CAC/E;;MACZ,kBAAC,GAAD;OAAW,WAAU;OAAS,WAAU;iBAAxC,CACE,kBAAC,KAAD;QAAG,WAAU;kBAAsD;QAAQ,CAAA,EAC3E,kBAAC,KAAD;QAAG,WAAU;kBAAsC,EAAS,QAAQ;QAAkB,CAAA,CAC5E;;MACR;SACJ;IACU,EAAA,CAAA;GAEhB,kBAAC,GAAD;IACE,SACE,EAAmB,UAAU,sCAAsC,kBAAkB,EAAc,OAAO;IAE5G,YAAW;IACX,MAAM,EAAc,KAAK,OAAkB;KACzC,IAAI,EAAa;KACjB,OAAO,gBAAgB,EAAa;KACpC,UAAU,CACR,EAAa,WAAW,OAAO,EAAa,aAAa,KAAA,GACzD,EAAa,cAAc,GAAG,EAAa,YAAY,GAAG,EAAa,YAAY,OAAO,KAAA,EAC3F,CACE,OAAO,QAAQ,CACf,KAAK,MAAM;KACd,QAAQ,EAAa;KACtB,EAAE;IACH,CAAA;GAED,IACC,kBAAC,OAAD;IAAK,KAAK;IAAiB,WAAU;cAArC,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;eAA0C;KAAa,CAAA,EACrE,kBAAC,KAAD;KAAG,WAAU;eAAmC;KAG5C,CAAA,CACA,EAAA,CAAA,EACN,kBAAC,GAAD;KAAsB,YAAY;KAAI,cAAc,GAAU,YAAY,GAAU,MAAM;KAAM,CAAA,CAC5F;QACJ;GAEJ,kBAAC,GAAD;IACE,YAAW;IACX,OAAM;IACN,OAAO;KACL;MACE,IAAI;MACJ,OAAO;MACP,aAAa;MACb,MAAM,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA;MACpC,eAAe,EAAS,gBAAgB;MACzC;KACD;MACE,IAAI;MACJ,OAAO;MACP,aAAa;MACb,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;MACnC,eAAe,EAAS,cAAc;MACvC;KACD;MACE,IAAI;MACJ,OAAO;MACP,aAAa;MACb,MAAM,kBAAC,GAAD,EAAe,WAAU,WAAY,CAAA;MAC3C,eAAe,EAAgB,SAAS,eAAe;OAAE,UAAU;OAAU,OAAO;OAAS,CAAC;MAC/F;KACF;IACD,CAAA;GACE"}
@@ -1,72 +1,83 @@
1
- import { useAnnouncementsQuery as e, useCommunicationCampaignsQuery as t, useUpsertAnnouncementMutation as n } from "../../api/eventApi.js";
2
- import { EntityListSection as r } from "./EntityListSection.js";
3
- import { useMemo as i, useState as a } from "react";
4
- import { jsx as o, jsxs as s } from "react/jsx-runtime";
5
- import { Megaphone as c } from "lucide-react";
6
- import { useI18n as l } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
7
- import { Button as u, EmphasisPanel as d, GradientText as f, Input as p } from "@burdenoff/fe-libs/ui";
1
+ import { notify as e } from "../../lib/toast.js";
2
+ import { useAnnouncementsQuery as t, useCommunicationCampaignsQuery as n, useUpsertAnnouncementMutation as r } from "../../api/eventApi.js";
3
+ import { describeError as i, mutationSucceeded as a } from "../../lib/mutationResult.js";
4
+ import { EntityListSection as o } from "./EntityListSection.js";
5
+ import { useMemo as s, useState as c } from "react";
6
+ import { jsx as l, jsxs as u } from "react/jsx-runtime";
7
+ import { Megaphone as d } from "lucide-react";
8
+ import { useI18n as f } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
9
+ import { Button as p, EmphasisPanel as m, GradientText as h, Input as g, PagePurpose as _ } from "@burdenoff/fe-libs/ui";
8
10
  //#region src/eventfullymanaged/pages/modules/CommunicationPage.tsx
9
- function m() {
10
- let { t: m } = l(), h = (e, t) => {
11
- let n = m(e);
11
+ function v() {
12
+ let { t: v } = f(), y = (e, t) => {
13
+ let n = v(e);
12
14
  return n === e ? t : n;
13
- }, g = e({
15
+ }, b = t({
14
16
  limit: 100,
15
17
  offset: 0
16
- }), _ = t({
18
+ }), x = n({
17
19
  limit: 100,
18
20
  offset: 0
19
- }), [v, { loading: y }] = n(), [b, x] = a(""), S = i(() => g.data?.announcements.items ?? [], [g.data]), C = i(() => _.data?.communicationCampaigns.items ?? [], [_.data]);
20
- return /* @__PURE__ */ s("div", {
21
+ }), [S, { loading: C }] = r(), [w, T] = c(""), E = s(() => b.data?.announcements.items ?? [], [b.data]), D = s(() => x.data?.communicationCampaigns.items ?? [], [x.data]);
22
+ return /* @__PURE__ */ u("div", {
21
23
  className: "space-y-6 p-6",
22
24
  children: [
23
- /* @__PURE__ */ s(d, { children: [
24
- /* @__PURE__ */ o("h1", {
25
+ /* @__PURE__ */ l(_, { children: y("eventfullymanaged.communication.purpose", "Keep attendees informed and engaged. Announcements are one-off broadcasts (a schedule change, a welcome message); campaigns are scheduled, multi-step outreach (reminder emails, follow-ups). Use this page to draft and publish everything you need to say before, during and after an event.") }),
26
+ /* @__PURE__ */ u(m, { children: [
27
+ /* @__PURE__ */ l("h1", {
25
28
  className: "text-2xl font-bold text-text-primary",
26
- children: /* @__PURE__ */ o(f, { children: h("eventfullymanaged.communication.title", "Communication") })
29
+ children: /* @__PURE__ */ l(h, { children: y("eventfullymanaged.communication.title", "Communication") })
27
30
  }),
28
- /* @__PURE__ */ o("p", {
31
+ /* @__PURE__ */ l("p", {
29
32
  className: "mt-1 text-sm text-text-secondary",
30
- children: h("eventfullymanaged.communication.description", "Announcements and campaigns managed via workspace APIs.")
33
+ children: y("eventfullymanaged.communication.description", "Announcements and campaigns managed via workspace APIs.")
31
34
  }),
32
- /* @__PURE__ */ s("div", {
35
+ /* @__PURE__ */ u("div", {
33
36
  className: "mt-4 flex flex-col gap-3 sm:flex-row",
34
- children: [/* @__PURE__ */ o(p, {
35
- value: b,
36
- onChange: (e) => x(e.target.value),
37
- placeholder: h("eventfullymanaged.communication.inputPlaceholder", "Emergency schedule update"),
38
- "aria-label": h("eventfullymanaged.communication.inputPlaceholder", "Emergency schedule update"),
37
+ children: [/* @__PURE__ */ l(g, {
38
+ value: w,
39
+ onChange: (e) => T(e.target.value),
40
+ placeholder: y("eventfullymanaged.communication.inputPlaceholder", "Emergency schedule update"),
41
+ "aria-label": y("eventfullymanaged.communication.inputPlaceholder", "Emergency schedule update"),
39
42
  className: "flex-1"
40
- }), /* @__PURE__ */ s(u, {
43
+ }), /* @__PURE__ */ u(p, {
41
44
  type: "button",
42
- disabled: y,
45
+ disabled: C,
43
46
  onClick: async () => {
44
- b.trim() && (await v({ variables: { input: {
45
- title: b,
46
- name: b,
47
- status: "draft",
48
- metadata: {}
49
- } } }), x(""));
47
+ if (!w.trim()) return;
48
+ let t = y("eventfullymanaged.communication.errors.create", "Could not create announcement");
49
+ try {
50
+ let n = await S({ variables: { input: {
51
+ title: w,
52
+ name: w,
53
+ status: "draft",
54
+ metadata: {}
55
+ } } });
56
+ if (!a(n, n.data?.upsertAnnouncement?.id, t)) return;
57
+ T(""), e.success(y("eventfullymanaged.communication.created", "Announcement created"));
58
+ } catch (n) {
59
+ e.error(t, i(n));
60
+ }
50
61
  },
51
- children: [/* @__PURE__ */ o(c, { className: "h-4 w-4" }), y ? h("eventfullymanaged.communication.actions.creating", "Creating...") : h("eventfullymanaged.communication.actions.createAnnouncement", "Create Announcement")]
62
+ children: [/* @__PURE__ */ l(d, { className: "h-4 w-4" }), C ? y("eventfullymanaged.communication.actions.creating", "Creating...") : y("eventfullymanaged.communication.actions.createAnnouncement", "Create Announcement")]
52
63
  })]
53
64
  })
54
65
  ] }),
55
- /* @__PURE__ */ o(r, {
56
- heading: g.loading ? h("eventfullymanaged.communication.announcements.loading", "Loading announcements...") : `${h("eventfullymanaged.communication.announcements.heading", "Announcements")} (${S.length})`,
57
- emptyLabel: h("eventfullymanaged.communication.announcements.empty", "No announcements published yet."),
58
- rows: S.map((e) => ({
66
+ /* @__PURE__ */ l(o, {
67
+ heading: b.loading ? y("eventfullymanaged.communication.announcements.loading", "Loading announcements...") : `${y("eventfullymanaged.communication.announcements.heading", "Announcements")} (${E.length})`,
68
+ emptyLabel: y("eventfullymanaged.communication.announcements.empty", "No announcements published yet."),
69
+ rows: E.map((e) => ({
59
70
  id: e.id,
60
- title: e.title ?? e.name ?? `${h("eventfullymanaged.communication.announcements.itemPrefix", "Announcement")} ${e.id}`,
71
+ title: e.title ?? e.name ?? `${y("eventfullymanaged.communication.announcements.itemPrefix", "Announcement")} ${e.id}`,
61
72
  status: e.status ?? void 0
62
73
  }))
63
74
  }),
64
- /* @__PURE__ */ o(r, {
65
- heading: _.loading ? h("eventfullymanaged.communication.campaigns.loading", "Loading campaigns...") : `${h("eventfullymanaged.communication.campaigns.heading", "Campaigns")} (${C.length})`,
66
- emptyLabel: h("eventfullymanaged.communication.campaigns.empty", "No communication campaigns created yet."),
67
- rows: C.map((e) => ({
75
+ /* @__PURE__ */ l(o, {
76
+ heading: x.loading ? y("eventfullymanaged.communication.campaigns.loading", "Loading campaigns...") : `${y("eventfullymanaged.communication.campaigns.heading", "Campaigns")} (${D.length})`,
77
+ emptyLabel: y("eventfullymanaged.communication.campaigns.empty", "No communication campaigns created yet."),
78
+ rows: D.map((e) => ({
68
79
  id: e.id,
69
- title: e.title ?? e.name ?? `${h("eventfullymanaged.communication.campaigns.itemPrefix", "Campaign")} ${e.id}`,
80
+ title: e.title ?? e.name ?? `${y("eventfullymanaged.communication.campaigns.itemPrefix", "Campaign")} ${e.id}`,
70
81
  status: e.status ?? void 0
71
82
  }))
72
83
  })
@@ -74,6 +85,6 @@ function m() {
74
85
  });
75
86
  }
76
87
  //#endregion
77
- export { m as default };
88
+ export { v as default };
78
89
 
79
90
  //# sourceMappingURL=CommunicationPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CommunicationPage.js","names":[],"sources":["../../../../src/eventfullymanaged/pages/modules/CommunicationPage.tsx"],"sourcesContent":["import { Megaphone } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Button, EmphasisPanel, GradientText, Input } from '@burdenoff/fe-libs/ui';\nimport { useMemo, useState } from 'react';\n\nimport {\n useAnnouncementsQuery,\n useCommunicationCampaignsQuery,\n useUpsertAnnouncementMutation,\n} from '../../api/eventApi';\nimport { EntityListSection } from './EntityListSection';\n\ntype SimpleRow = {\n id: string;\n name?: string;\n title?: string;\n status?: string;\n};\n\nexport default function CommunicationPage() {\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 announcementsQuery = useAnnouncementsQuery({ limit: 100, offset: 0 });\n const campaignsQuery = useCommunicationCampaignsQuery({ limit: 100, offset: 0 });\n const [createAnnouncement, { loading: creating }] = useUpsertAnnouncementMutation();\n const [announcementTitle, setAnnouncementTitle] = useState('');\n\n const announcements = useMemo(\n () => (announcementsQuery.data?.announcements.items ?? []) as SimpleRow[],\n [announcementsQuery.data]\n );\n const campaigns = useMemo(\n () => (campaignsQuery.data?.communicationCampaigns.items ?? []) as SimpleRow[],\n [campaignsQuery.data]\n );\n\n const onCreate = async () => {\n if (!announcementTitle.trim()) return;\n await createAnnouncement({\n variables: {\n input: {\n title: announcementTitle,\n name: announcementTitle,\n status: 'draft',\n metadata: {},\n },\n },\n });\n setAnnouncementTitle('');\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <EmphasisPanel>\n <h1 className=\"text-2xl font-bold text-text-primary\">\n <GradientText>{t('eventfullymanaged.communication.title', 'Communication')}</GradientText>\n </h1>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {t('eventfullymanaged.communication.description', 'Announcements and campaigns managed via workspace APIs.')}\n </p>\n <div className=\"mt-4 flex flex-col gap-3 sm:flex-row\">\n <Input\n value={announcementTitle}\n onChange={(e) => setAnnouncementTitle(e.target.value)}\n placeholder={t('eventfullymanaged.communication.inputPlaceholder', 'Emergency schedule update')}\n aria-label={t('eventfullymanaged.communication.inputPlaceholder', 'Emergency schedule update')}\n className=\"flex-1\"\n />\n <Button type=\"button\" disabled={creating} onClick={onCreate}>\n <Megaphone className=\"h-4 w-4\" />\n {creating\n ? t('eventfullymanaged.communication.actions.creating', 'Creating...')\n : t('eventfullymanaged.communication.actions.createAnnouncement', 'Create Announcement')}\n </Button>\n </div>\n </EmphasisPanel>\n\n <EntityListSection\n heading={\n announcementsQuery.loading\n ? t('eventfullymanaged.communication.announcements.loading', 'Loading announcements...')\n : `${t('eventfullymanaged.communication.announcements.heading', 'Announcements')} (${announcements.length})`\n }\n emptyLabel={t('eventfullymanaged.communication.announcements.empty', 'No announcements published yet.')}\n rows={announcements.map((row) => ({\n id: row.id,\n title:\n row.title ??\n row.name ??\n `${t('eventfullymanaged.communication.announcements.itemPrefix', 'Announcement')} ${row.id}`,\n status: row.status ?? undefined,\n }))}\n />\n\n <EntityListSection\n heading={\n campaignsQuery.loading\n ? t('eventfullymanaged.communication.campaigns.loading', 'Loading campaigns...')\n : `${t('eventfullymanaged.communication.campaigns.heading', 'Campaigns')} (${campaigns.length})`\n }\n emptyLabel={t('eventfullymanaged.communication.campaigns.empty', 'No communication campaigns created yet.')}\n rows={campaigns.map((row) => ({\n id: row.id,\n title:\n row.title ??\n row.name ??\n `${t('eventfullymanaged.communication.campaigns.itemPrefix', 'Campaign')} ${row.id}`,\n status: row.status ?? undefined,\n }))}\n />\n </div>\n );\n}\n"],"mappings":";;;;;;;;AAmBA,SAAwB,IAAoB;CAC1C,IAAM,EAAE,GAAG,MAAc,GAAS,EAC5B,KAAK,GAAa,MAAqB;EAC3C,IAAM,IAAQ,EAAU,EAAI;AAC5B,SAAO,MAAU,IAAM,IAAW;IAE9B,IAAqB,EAAsB;EAAE,OAAO;EAAK,QAAQ;EAAG,CAAC,EACrE,IAAiB,EAA+B;EAAE,OAAO;EAAK,QAAQ;EAAG,CAAC,EAC1E,CAAC,GAAoB,EAAE,SAAS,OAAc,GAA+B,EAC7E,CAAC,GAAmB,KAAwB,EAAS,GAAG,EAExD,IAAgB,QACb,EAAmB,MAAM,cAAc,SAAS,EAAE,EACzD,CAAC,EAAmB,KAAK,CAC1B,EACK,IAAY,QACT,EAAe,MAAM,uBAAuB,SAAS,EAAE,EAC9D,CAAC,EAAe,KAAK,CACtB;AAiBD,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,GAAD,EAAA,UAAA;IACE,kBAAC,MAAD;KAAI,WAAU;eACZ,kBAAC,GAAD,EAAA,UAAe,EAAE,yCAAyC,gBAAgB,EAAgB,CAAA;KACvF,CAAA;IACL,kBAAC,KAAD;KAAG,WAAU;eACV,EAAE,+CAA+C,0DAA0D;KAC1G,CAAA;IACJ,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MACE,OAAO;MACP,WAAW,MAAM,EAAqB,EAAE,OAAO,MAAM;MACrD,aAAa,EAAE,oDAAoD,4BAA4B;MAC/F,cAAY,EAAE,oDAAoD,4BAA4B;MAC9F,WAAU;MACV,CAAA,EACF,kBAAC,GAAD;MAAQ,MAAK;MAAS,UAAU;MAAU,SAhCjC,YAAY;AACtB,SAAkB,MAAM,KAC7B,MAAM,EAAmB,EACvB,WAAW,EACT,OAAO;QACL,OAAO;QACP,MAAM;QACN,QAAQ;QACR,UAAU,EAAE;QACb,EACF,EACF,CAAC,EACF,EAAqB,GAAG;;gBAoBlB,CACE,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA,EAChC,IACG,EAAE,oDAAoD,cAAc,GACpE,EAAE,8DAA8D,sBAAsB,CACnF;QACL;;IACQ,EAAA,CAAA;GAEhB,kBAAC,GAAD;IACE,SACE,EAAmB,UACf,EAAE,yDAAyD,2BAA2B,GACtF,GAAG,EAAE,yDAAyD,gBAAgB,CAAC,IAAI,EAAc,OAAO;IAE9G,YAAY,EAAE,uDAAuD,kCAAkC;IACvG,MAAM,EAAc,KAAK,OAAS;KAChC,IAAI,EAAI;KACR,OACE,EAAI,SACJ,EAAI,QACJ,GAAG,EAAE,4DAA4D,eAAe,CAAC,GAAG,EAAI;KAC1F,QAAQ,EAAI,UAAU,KAAA;KACvB,EAAE;IACH,CAAA;GAEF,kBAAC,GAAD;IACE,SACE,EAAe,UACX,EAAE,qDAAqD,uBAAuB,GAC9E,GAAG,EAAE,qDAAqD,YAAY,CAAC,IAAI,EAAU,OAAO;IAElG,YAAY,EAAE,mDAAmD,0CAA0C;IAC3G,MAAM,EAAU,KAAK,OAAS;KAC5B,IAAI,EAAI;KACR,OACE,EAAI,SACJ,EAAI,QACJ,GAAG,EAAE,wDAAwD,WAAW,CAAC,GAAG,EAAI;KAClF,QAAQ,EAAI,UAAU,KAAA;KACvB,EAAE;IACH,CAAA;GACE"}
1
+ {"version":3,"file":"CommunicationPage.js","names":[],"sources":["../../../../src/eventfullymanaged/pages/modules/CommunicationPage.tsx"],"sourcesContent":["import { Megaphone } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Button, EmphasisPanel, GradientText, Input, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { useMemo, useState } from 'react';\n\nimport {\n useAnnouncementsQuery,\n useCommunicationCampaignsQuery,\n useUpsertAnnouncementMutation,\n} from '../../api/eventApi';\nimport { describeError, mutationSucceeded } from '../../lib/mutationResult';\nimport { notify } from '../../lib/toast';\nimport { EntityListSection } from './EntityListSection';\n\ntype SimpleRow = {\n id: string;\n name?: string;\n title?: string;\n status?: string;\n};\n\nexport default function CommunicationPage() {\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 announcementsQuery = useAnnouncementsQuery({ limit: 100, offset: 0 });\n const campaignsQuery = useCommunicationCampaignsQuery({ limit: 100, offset: 0 });\n const [createAnnouncement, { loading: creating }] = useUpsertAnnouncementMutation();\n const [announcementTitle, setAnnouncementTitle] = useState('');\n\n const announcements = useMemo(\n () => (announcementsQuery.data?.announcements.items ?? []) as SimpleRow[],\n [announcementsQuery.data]\n );\n const campaigns = useMemo(\n () => (campaignsQuery.data?.communicationCampaigns.items ?? []) as SimpleRow[],\n [campaignsQuery.data]\n );\n\n const onCreate = async () => {\n if (!announcementTitle.trim()) return;\n const failureMessage = t('eventfullymanaged.communication.errors.create', 'Could not create announcement');\n try {\n const response = await createAnnouncement({\n variables: {\n input: {\n title: announcementTitle,\n name: announcementTitle,\n status: 'draft',\n metadata: {},\n },\n },\n });\n if (!mutationSucceeded(response, response.data?.upsertAnnouncement?.id, failureMessage)) {\n return;\n }\n setAnnouncementTitle('');\n notify.success(t('eventfullymanaged.communication.created', 'Announcement created'));\n } catch (error) {\n notify.error(failureMessage, describeError(error));\n }\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <PagePurpose>\n {t(\n 'eventfullymanaged.communication.purpose',\n 'Keep attendees informed and engaged. Announcements are one-off broadcasts (a schedule change, a welcome message); campaigns are scheduled, multi-step outreach (reminder emails, follow-ups). Use this page to draft and publish everything you need to say before, during and after an event.'\n )}\n </PagePurpose>\n\n <EmphasisPanel>\n <h1 className=\"text-2xl font-bold text-text-primary\">\n <GradientText>{t('eventfullymanaged.communication.title', 'Communication')}</GradientText>\n </h1>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {t('eventfullymanaged.communication.description', 'Announcements and campaigns managed via workspace APIs.')}\n </p>\n <div className=\"mt-4 flex flex-col gap-3 sm:flex-row\">\n <Input\n value={announcementTitle}\n onChange={(e) => setAnnouncementTitle(e.target.value)}\n placeholder={t('eventfullymanaged.communication.inputPlaceholder', 'Emergency schedule update')}\n aria-label={t('eventfullymanaged.communication.inputPlaceholder', 'Emergency schedule update')}\n className=\"flex-1\"\n />\n <Button type=\"button\" disabled={creating} onClick={onCreate}>\n <Megaphone className=\"h-4 w-4\" />\n {creating\n ? t('eventfullymanaged.communication.actions.creating', 'Creating...')\n : t('eventfullymanaged.communication.actions.createAnnouncement', 'Create Announcement')}\n </Button>\n </div>\n </EmphasisPanel>\n\n <EntityListSection\n heading={\n announcementsQuery.loading\n ? t('eventfullymanaged.communication.announcements.loading', 'Loading announcements...')\n : `${t('eventfullymanaged.communication.announcements.heading', 'Announcements')} (${announcements.length})`\n }\n emptyLabel={t('eventfullymanaged.communication.announcements.empty', 'No announcements published yet.')}\n rows={announcements.map((row) => ({\n id: row.id,\n title:\n row.title ??\n row.name ??\n `${t('eventfullymanaged.communication.announcements.itemPrefix', 'Announcement')} ${row.id}`,\n status: row.status ?? undefined,\n }))}\n />\n\n <EntityListSection\n heading={\n campaignsQuery.loading\n ? t('eventfullymanaged.communication.campaigns.loading', 'Loading campaigns...')\n : `${t('eventfullymanaged.communication.campaigns.heading', 'Campaigns')} (${campaigns.length})`\n }\n emptyLabel={t('eventfullymanaged.communication.campaigns.empty', 'No communication campaigns created yet.')}\n rows={campaigns.map((row) => ({\n id: row.id,\n title:\n row.title ??\n row.name ??\n `${t('eventfullymanaged.communication.campaigns.itemPrefix', 'Campaign')} ${row.id}`,\n status: row.status ?? undefined,\n }))}\n />\n </div>\n );\n}\n"],"mappings":"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"}