@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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutationResult.js","names":[],"sources":["../../../src/eventfullymanaged/lib/mutationResult.ts"],"sourcesContent":["import type { ErrorLike } from '@apollo/client';\n\nimport { notify } from './toast';\n\n/**\n * The shared gateway Apollo client runs mutations with `errorPolicy: 'all'`, so a\n * server-side failure is returned IN-BAND on `result.error` rather than thrown —\n * awaiting the mutation resolves successfully even when nothing was persisted.\n * Write forms must therefore inspect the resolved result before treating a call\n * as a success, or they silently report a fake success and drop the user's data.\n *\n * `mutationSucceeded` centralises that check: it returns `true` only when there is\n * no in-band error AND the expected success payload id is present. Otherwise it\n * surfaces the real reason via the platform toast and returns `false` so the\n * caller keeps the form inputs intact and does not navigate away.\n */\nexport function mutationSucceeded(\n result: { error?: ErrorLike } | null | undefined,\n successId: string | null | undefined,\n failureMessage: string\n): boolean {\n if (result?.error) {\n notify.error(failureMessage, result.error.message);\n return false;\n }\n if (!successId) {\n notify.error(failureMessage, 'The server did not confirm the change. Please try again.');\n return false;\n }\n return true;\n}\n\n/**\n * Normalises a thrown error (network failure, or a client configured with\n * `errorPolicy: 'none'`) into a human-readable description for the toast.\n */\nexport function describeError(error: unknown): string | undefined {\n if (error instanceof Error && error.message.length > 0) {\n return error.message;\n }\n return undefined;\n}\n"],"mappings":";;AAgBA,SAAgB,EACd,GACA,GACA,GACS;AAST,QARI,GAAQ,SACV,EAAO,MAAM,GAAgB,EAAO,MAAM,QAAQ,EAC3C,MAEJ,IAIE,MAHL,EAAO,MAAM,GAAgB,2DAA2D,EACjF;;AASX,SAAgB,EAAc,GAAoC;AAChE,KAAI,aAAiB,SAAS,EAAM,QAAQ,SAAS,EACnD,QAAO,EAAM"}
@@ -0,0 +1,36 @@
1
+ import { toast as e } from "../../node_modules/sonner/dist/index.js";
2
+ //#region src/eventfullymanaged/lib/toast.ts
3
+ var t = {
4
+ success(t, n) {
5
+ e.success(t, {
6
+ description: n,
7
+ duration: 4e3
8
+ });
9
+ },
10
+ info(t, n) {
11
+ e.info(t, {
12
+ description: n,
13
+ duration: 4e3
14
+ });
15
+ },
16
+ warning(t, n) {
17
+ e.warning(t, {
18
+ description: n,
19
+ duration: 8e3
20
+ });
21
+ },
22
+ error(t, n) {
23
+ e.error(t, {
24
+ description: n,
25
+ duration: Infinity,
26
+ closeButton: !0
27
+ });
28
+ },
29
+ dismiss(t) {
30
+ e.dismiss(t);
31
+ }
32
+ };
33
+ //#endregion
34
+ export { t as notify };
35
+
36
+ //# sourceMappingURL=toast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toast.js","names":[],"sources":["../../../src/eventfullymanaged/lib/toast.ts"],"sourcesContent":["import { toast } from 'sonner';\n\n/**\n * Module-wide toast API. sonner is a global singleton; the matching <Toaster>\n * is owned by the HOST app shell (mounted once via AppShellProvider). Every\n * page/component surfaces feedback through these helpers instead of hand-rolling\n * fixed-position toast markup, so success/error notifications stay consistent\n * with the rest of the platform.\n *\n * Durations follow the notification spec: success/info auto-dismiss, errors stay\n * until the user dismisses them (sonner renders a close button and announces via\n * aria-live).\n */\nexport const notify = {\n success(message: string, description?: string): void {\n toast.success(message, { description, duration: 4000 });\n },\n info(message: string, description?: string): void {\n toast.info(message, { description, duration: 4000 });\n },\n warning(message: string, description?: string): void {\n toast.warning(message, { description, duration: 8000 });\n },\n error(message: string, description?: string): void {\n toast.error(message, { description, duration: Infinity, closeButton: true });\n },\n dismiss(id?: string | number): void {\n toast.dismiss(id);\n },\n};\n\nexport { toast };\n"],"mappings":";;AAaA,IAAa,IAAS;CACpB,QAAQ,GAAiB,GAA4B;AACnD,IAAM,QAAQ,GAAS;GAAE;GAAa,UAAU;GAAM,CAAC;;CAEzD,KAAK,GAAiB,GAA4B;AAChD,IAAM,KAAK,GAAS;GAAE;GAAa,UAAU;GAAM,CAAC;;CAEtD,QAAQ,GAAiB,GAA4B;AACnD,IAAM,QAAQ,GAAS;GAAE;GAAa,UAAU;GAAM,CAAC;;CAEzD,MAAM,GAAiB,GAA4B;AACjD,IAAM,MAAM,GAAS;GAAE;GAAa,UAAU;GAAU,aAAa;GAAM,CAAC;;CAE9E,QAAQ,GAA4B;AAClC,IAAM,QAAQ,EAAG;;CAEpB"}
@@ -4,88 +4,129 @@ import { PageLayout as n } from "../../components/PageLayout.js";
4
4
  import { jsx as r, jsxs as i } from "react/jsx-runtime";
5
5
  import { BarChart3 as a, Building2 as o, CalendarDays as s, Megaphone as c, Ticket as l, Users as u } from "lucide-react";
6
6
  import { useI18n as d } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
7
- import { GlassCard as f, GradientText as p } from "@burdenoff/fe-libs/ui";
7
+ import { GlassCard as f, GradientText as p, NextSteps as m, PagePurpose as h } from "@burdenoff/fe-libs/ui";
8
8
  //#region src/eventfullymanaged/pages/dashboard/DashboardPage.tsx
9
- function m() {
10
- let { t: m } = d(), h = (e, t) => {
11
- let n = m(e);
9
+ function g() {
10
+ let { t: g } = d(), _ = (e, t) => {
11
+ let n = g(e);
12
12
  return n === e ? t : n;
13
- }, { navigate: g } = e(), { data: _, loading: v } = t(), y = _?.dashboardSummary, b = [
13
+ }, { navigate: v } = e(), { data: y, loading: b } = t(), x = y?.dashboardSummary, S = [
14
14
  {
15
- label: h("eventfullymanaged.dashboard.cards.activeEvents", "Active Events"),
16
- value: y?.activeEvents ?? 0,
15
+ label: _("eventfullymanaged.dashboard.cards.activeEvents", "Active Events"),
16
+ value: x?.activeEvents ?? 0,
17
17
  icon: s,
18
18
  path: "/events"
19
19
  },
20
20
  {
21
- label: h("eventfullymanaged.dashboard.cards.venues", "Venues"),
22
- value: y?.totalVenues ?? 0,
21
+ label: _("eventfullymanaged.dashboard.cards.venues", "Venues"),
22
+ value: x?.totalVenues ?? 0,
23
23
  icon: o,
24
24
  path: "/venues"
25
25
  },
26
26
  {
27
- label: h("eventfullymanaged.dashboard.cards.registrations", "Registrations"),
28
- value: y?.totalRegistrations ?? 0,
27
+ label: _("eventfullymanaged.dashboard.cards.registrations", "Registrations"),
28
+ value: x?.totalRegistrations ?? 0,
29
29
  icon: l,
30
30
  path: "/registration"
31
31
  },
32
32
  {
33
- label: h("eventfullymanaged.dashboard.cards.campaigns", "Campaigns"),
34
- value: y?.totalSponsors ?? 0,
33
+ label: _("eventfullymanaged.dashboard.cards.campaigns", "Campaigns"),
34
+ value: x?.totalSponsors ?? 0,
35
35
  icon: c,
36
36
  path: "/communication"
37
37
  },
38
38
  {
39
- label: h("eventfullymanaged.dashboard.cards.analyticsReports", "Analytics Reports"),
40
- value: y?.totalEvents ?? 0,
39
+ label: _("eventfullymanaged.dashboard.cards.analyticsReports", "Analytics Reports"),
40
+ value: x?.totalEvents ?? 0,
41
41
  icon: a,
42
42
  path: "/analytics"
43
43
  },
44
44
  {
45
- label: h("eventfullymanaged.dashboard.cards.networkMatches", "Network Matches"),
46
- value: y?.upcomingSessions ?? 0,
45
+ label: _("eventfullymanaged.dashboard.cards.networkMatches", "Network Matches"),
46
+ value: x?.upcomingSessions ?? 0,
47
47
  icon: u,
48
48
  path: "/networking"
49
49
  }
50
50
  ];
51
- return /* @__PURE__ */ r(n, {
51
+ return /* @__PURE__ */ i(n, {
52
52
  hero: !0,
53
53
  title: /* @__PURE__ */ r(p, {
54
54
  as: "span",
55
- children: h("eventfullymanaged.dashboard.title", "EventfullyManaged")
55
+ children: _("eventfullymanaged.dashboard.title", "EventfullyManaged")
56
56
  }),
57
- description: v ? h("eventfullymanaged.dashboard.description.loading", "Loading real-time event operations summary...") : h("eventfullymanaged.dashboard.description.ready", "Unified event operations dashboard."),
58
- children: /* @__PURE__ */ r("div", {
59
- className: "grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3",
60
- children: b.map((e, t) => {
61
- let n = e.icon, a = t === 0;
62
- return /* @__PURE__ */ i(f, {
63
- treatment: a ? "glass" : "metric",
64
- glow: a,
65
- role: "button",
66
- tabIndex: 0,
67
- "aria-label": `${e.label}: ${e.value.toLocaleString()}`,
68
- onClick: () => g(e.path),
69
- onKeyDown: (t) => {
70
- (t.key === "Enter" || t.key === " ") && (t.preventDefault(), g(e.path));
57
+ description: b ? _("eventfullymanaged.dashboard.description.loading", "Loading real-time event operations summary...") : _("eventfullymanaged.dashboard.description.ready", "Unified event operations dashboard."),
58
+ children: [
59
+ /* @__PURE__ */ r(h, {
60
+ className: "mb-6",
61
+ children: _("eventfullymanaged.dashboard.purpose", "Your event control center. Each tile below is a live count from a different part of your event operations — events, venues, registrations, campaigns, analytics and networking. Open any tile to manage that area, or follow the suggested next steps to set up a new event end to end.")
62
+ }),
63
+ /* @__PURE__ */ r("div", {
64
+ className: "grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3",
65
+ children: S.map((e, t) => {
66
+ let n = e.icon, a = t === 0;
67
+ return /* @__PURE__ */ i(f, {
68
+ treatment: a ? "glass" : "metric",
69
+ glow: a,
70
+ role: "button",
71
+ tabIndex: 0,
72
+ "aria-label": `${e.label}: ${e.value.toLocaleString()}`,
73
+ onClick: () => v(e.path),
74
+ onKeyDown: (t) => {
75
+ (t.key === "Enter" || t.key === " ") && (t.preventDefault(), v(e.path));
76
+ },
77
+ className: "cursor-pointer p-5 outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]",
78
+ children: [/* @__PURE__ */ i("div", {
79
+ className: "flex items-center justify-between",
80
+ children: [/* @__PURE__ */ r("span", {
81
+ className: "text-sm text-text-secondary",
82
+ children: e.label
83
+ }), /* @__PURE__ */ r(n, { className: "h-5 w-5 text-action-primary-bg" })]
84
+ }), /* @__PURE__ */ r("div", {
85
+ className: "mt-3 text-3xl font-semibold tabular-nums text-text-primary",
86
+ children: e.value.toLocaleString()
87
+ })]
88
+ }, e.label);
89
+ })
90
+ }),
91
+ /* @__PURE__ */ r(m, {
92
+ className: "mt-6",
93
+ storageKey: "eventfullymanaged-dashboard",
94
+ title: _("eventfullymanaged.dashboard.nextSteps.title", "Get your first event running"),
95
+ steps: [
96
+ {
97
+ id: "create-event",
98
+ label: _("eventfullymanaged.dashboard.nextSteps.createEvent", "Create an event"),
99
+ description: _("eventfullymanaged.dashboard.nextSteps.createEventDesc", "Start with the basics — name, dates and capacity."),
100
+ icon: /* @__PURE__ */ r(s, { className: "h-4 w-4" }),
101
+ onClick: () => v("/events")
71
102
  },
72
- className: "cursor-pointer p-5 outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]",
73
- children: [/* @__PURE__ */ i("div", {
74
- className: "flex items-center justify-between",
75
- children: [/* @__PURE__ */ r("span", {
76
- className: "text-sm text-text-secondary",
77
- children: e.label
78
- }), /* @__PURE__ */ r(n, { className: "h-5 w-5 text-action-primary-bg" })]
79
- }), /* @__PURE__ */ r("div", {
80
- className: "mt-3 text-3xl font-semibold tabular-nums text-text-primary",
81
- children: e.value.toLocaleString()
82
- })]
83
- }, e.label);
103
+ {
104
+ id: "add-venue",
105
+ label: _("eventfullymanaged.dashboard.nextSteps.addVenue", "Add a venue"),
106
+ description: _("eventfullymanaged.dashboard.nextSteps.addVenueDesc", "Map your event to a space with capacity and floor plans."),
107
+ icon: /* @__PURE__ */ r(o, { className: "h-4 w-4" }),
108
+ onClick: () => v("/venues/create")
109
+ },
110
+ {
111
+ id: "open-registration",
112
+ label: _("eventfullymanaged.dashboard.nextSteps.openRegistration", "Open registration"),
113
+ description: _("eventfullymanaged.dashboard.nextSteps.openRegistrationDesc", "Set up ticket types and track attendee sign-ups."),
114
+ icon: /* @__PURE__ */ r(l, { className: "h-4 w-4" }),
115
+ onClick: () => v("/registration")
116
+ },
117
+ {
118
+ id: "invite-sponsors",
119
+ label: _("eventfullymanaged.dashboard.nextSteps.inviteSponsors", "Onboard sponsors"),
120
+ description: _("eventfullymanaged.dashboard.nextSteps.inviteSponsorsDesc", "Add sponsors and start tracking value and leads."),
121
+ icon: /* @__PURE__ */ r(c, { className: "h-4 w-4" }),
122
+ onClick: () => v("/communication")
123
+ }
124
+ ]
84
125
  })
85
- })
126
+ ]
86
127
  });
87
128
  }
88
129
  //#endregion
89
- export { m as default };
130
+ export { g as default };
90
131
 
91
132
  //# sourceMappingURL=DashboardPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../../src/eventfullymanaged/pages/dashboard/DashboardPage.tsx"],"sourcesContent":["import { BarChart3, Building2, CalendarDays, Megaphone, Ticket, Users } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { GlassCard, GradientText } from '@burdenoff/fe-libs/ui';\n\nimport { useDashboardSummaryQuery } from '../../api/eventApi';\nimport { PageLayout } from '../../components/PageLayout';\nimport { useEventfullyManaged } from '../../context/EventfullyManagedContext';\n\ntype StatCard = {\n label: string;\n value: number;\n icon: React.ComponentType<{ className?: string }>;\n path: string;\n};\n\nexport default function DashboardPage() {\n const { t: translate } = useI18n();\n const t = (key: string, fallback: string) => {\n const value = translate(key);\n return value === key ? fallback : value;\n };\n const { navigate } = useEventfullyManaged();\n const { data, loading } = useDashboardSummaryQuery();\n\n const summary = data?.dashboardSummary;\n const cards: StatCard[] = [\n {\n label: t('eventfullymanaged.dashboard.cards.activeEvents', 'Active Events'),\n value: summary?.activeEvents ?? 0,\n icon: CalendarDays,\n path: '/events',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.venues', 'Venues'),\n value: summary?.totalVenues ?? 0,\n icon: Building2,\n path: '/venues',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.registrations', 'Registrations'),\n value: summary?.totalRegistrations ?? 0,\n icon: Ticket,\n path: '/registration',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.campaigns', 'Campaigns'),\n value: summary?.totalSponsors ?? 0,\n icon: Megaphone,\n path: '/communication',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.analyticsReports', 'Analytics Reports'),\n value: summary?.totalEvents ?? 0,\n icon: BarChart3,\n path: '/analytics',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.networkMatches', 'Network Matches'),\n value: summary?.upcomingSessions ?? 0,\n icon: Users,\n path: '/networking',\n },\n ];\n\n return (\n <PageLayout\n hero\n title={<GradientText as=\"span\">{t('eventfullymanaged.dashboard.title', 'EventfullyManaged')}</GradientText>}\n description={\n loading\n ? t('eventfullymanaged.dashboard.description.loading', 'Loading real-time event operations summary...')\n : t('eventfullymanaged.dashboard.description.ready', 'Unified event operations dashboard.')\n }\n >\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3\">\n {cards.map((card, index) => {\n const Icon = card.icon;\n const featured = index === 0;\n return (\n <GlassCard\n key={card.label}\n treatment={featured ? 'glass' : 'metric'}\n glow={featured}\n role=\"button\"\n tabIndex={0}\n aria-label={`${card.label}: ${card.value.toLocaleString()}`}\n onClick={() => navigate(card.path)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n navigate(card.path);\n }\n }}\n className=\"cursor-pointer p-5 outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm text-text-secondary\">{card.label}</span>\n <Icon className=\"h-5 w-5 text-action-primary-bg\" />\n </div>\n <div className=\"mt-3 text-3xl font-semibold tabular-nums text-text-primary\">\n {card.value.toLocaleString()}\n </div>\n </GlassCard>\n );\n })}\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;AAeA,SAAwB,IAAgB;CACtC,IAAM,EAAE,GAAG,MAAc,GAAS,EAC5B,KAAK,GAAa,MAAqB;EAC3C,IAAM,IAAQ,EAAU,EAAI;AAC5B,SAAO,MAAU,IAAM,IAAW;IAE9B,EAAE,gBAAa,GAAsB,EACrC,EAAE,SAAM,eAAY,GAA0B,EAE9C,IAAU,GAAM,kBAChB,IAAoB;EACxB;GACE,OAAO,EAAE,kDAAkD,gBAAgB;GAC3E,OAAO,GAAS,gBAAgB;GAChC,MAAM;GACN,MAAM;GACP;EACD;GACE,OAAO,EAAE,4CAA4C,SAAS;GAC9D,OAAO,GAAS,eAAe;GAC/B,MAAM;GACN,MAAM;GACP;EACD;GACE,OAAO,EAAE,mDAAmD,gBAAgB;GAC5E,OAAO,GAAS,sBAAsB;GACtC,MAAM;GACN,MAAM;GACP;EACD;GACE,OAAO,EAAE,+CAA+C,YAAY;GACpE,OAAO,GAAS,iBAAiB;GACjC,MAAM;GACN,MAAM;GACP;EACD;GACE,OAAO,EAAE,sDAAsD,oBAAoB;GACnF,OAAO,GAAS,eAAe;GAC/B,MAAM;GACN,MAAM;GACP;EACD;GACE,OAAO,EAAE,oDAAoD,kBAAkB;GAC/E,OAAO,GAAS,oBAAoB;GACpC,MAAM;GACN,MAAM;GACP;EACF;AAED,QACE,kBAAC,GAAD;EACE,MAAA;EACA,OAAO,kBAAC,GAAD;GAAc,IAAG;aAAQ,EAAE,qCAAqC,oBAAoB;GAAgB,CAAA;EAC3G,aACE,IACI,EAAE,mDAAmD,gDAAgD,GACrG,EAAE,iDAAiD,sCAAsC;YAG/F,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAM,KAAK,GAAM,MAAU;IAC1B,IAAM,IAAO,EAAK,MACZ,IAAW,MAAU;AAC3B,WACE,kBAAC,GAAD;KAEE,WAAW,IAAW,UAAU;KAChC,MAAM;KACN,MAAK;KACL,UAAU;KACV,cAAY,GAAG,EAAK,MAAM,IAAI,EAAK,MAAM,gBAAgB;KACzD,eAAe,EAAS,EAAK,KAAK;KAClC,YAAY,MAAU;AACpB,OAAI,EAAM,QAAQ,WAAW,EAAM,QAAQ,SACzC,EAAM,gBAAgB,EACtB,EAAS,EAAK,KAAK;;KAGvB,WAAU;eAdZ,CAgBE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,QAAD;OAAM,WAAU;iBAA+B,EAAK;OAAa,CAAA,EACjE,kBAAC,GAAD,EAAM,WAAU,kCAAmC,CAAA,CAC/C;SACN,kBAAC,OAAD;MAAK,WAAU;gBACZ,EAAK,MAAM,gBAAgB;MACxB,CAAA,CACI;OAtBL,EAAK,MAsBA;KAEd;GACE,CAAA;EACK,CAAA"}
1
+ {"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../../src/eventfullymanaged/pages/dashboard/DashboardPage.tsx"],"sourcesContent":["import { BarChart3, Building2, CalendarDays, Megaphone, Ticket, Users } from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { GlassCard, GradientText, NextSteps, PagePurpose } from '@burdenoff/fe-libs/ui';\n\nimport { useDashboardSummaryQuery } from '../../api/eventApi';\nimport { PageLayout } from '../../components/PageLayout';\nimport { useEventfullyManaged } from '../../context/EventfullyManagedContext';\n\ntype StatCard = {\n label: string;\n value: number;\n icon: React.ComponentType<{ className?: string }>;\n path: string;\n};\n\nexport default function DashboardPage() {\n const { t: translate } = useI18n();\n const t = (key: string, fallback: string) => {\n const value = translate(key);\n return value === key ? fallback : value;\n };\n const { navigate } = useEventfullyManaged();\n const { data, loading } = useDashboardSummaryQuery();\n\n const summary = data?.dashboardSummary;\n const cards: StatCard[] = [\n {\n label: t('eventfullymanaged.dashboard.cards.activeEvents', 'Active Events'),\n value: summary?.activeEvents ?? 0,\n icon: CalendarDays,\n path: '/events',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.venues', 'Venues'),\n value: summary?.totalVenues ?? 0,\n icon: Building2,\n path: '/venues',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.registrations', 'Registrations'),\n value: summary?.totalRegistrations ?? 0,\n icon: Ticket,\n path: '/registration',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.campaigns', 'Campaigns'),\n value: summary?.totalSponsors ?? 0,\n icon: Megaphone,\n path: '/communication',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.analyticsReports', 'Analytics Reports'),\n value: summary?.totalEvents ?? 0,\n icon: BarChart3,\n path: '/analytics',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.networkMatches', 'Network Matches'),\n value: summary?.upcomingSessions ?? 0,\n icon: Users,\n path: '/networking',\n },\n ];\n\n return (\n <PageLayout\n hero\n title={<GradientText as=\"span\">{t('eventfullymanaged.dashboard.title', 'EventfullyManaged')}</GradientText>}\n description={\n loading\n ? t('eventfullymanaged.dashboard.description.loading', 'Loading real-time event operations summary...')\n : t('eventfullymanaged.dashboard.description.ready', 'Unified event operations dashboard.')\n }\n >\n <PagePurpose className=\"mb-6\">\n {t(\n 'eventfullymanaged.dashboard.purpose',\n 'Your event control center. Each tile below is a live count from a different part of your event operations — events, venues, registrations, campaigns, analytics and networking. Open any tile to manage that area, or follow the suggested next steps to set up a new event end to end.'\n )}\n </PagePurpose>\n\n <div className=\"grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3\">\n {cards.map((card, index) => {\n const Icon = card.icon;\n const featured = index === 0;\n return (\n <GlassCard\n key={card.label}\n treatment={featured ? 'glass' : 'metric'}\n glow={featured}\n role=\"button\"\n tabIndex={0}\n aria-label={`${card.label}: ${card.value.toLocaleString()}`}\n onClick={() => navigate(card.path)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n navigate(card.path);\n }\n }}\n className=\"cursor-pointer p-5 outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm text-text-secondary\">{card.label}</span>\n <Icon className=\"h-5 w-5 text-action-primary-bg\" />\n </div>\n <div className=\"mt-3 text-3xl font-semibold tabular-nums text-text-primary\">\n {card.value.toLocaleString()}\n </div>\n </GlassCard>\n );\n })}\n </div>\n\n <NextSteps\n className=\"mt-6\"\n storageKey=\"eventfullymanaged-dashboard\"\n title={t('eventfullymanaged.dashboard.nextSteps.title', 'Get your first event running')}\n steps={[\n {\n id: 'create-event',\n label: t('eventfullymanaged.dashboard.nextSteps.createEvent', 'Create an event'),\n description: t(\n 'eventfullymanaged.dashboard.nextSteps.createEventDesc',\n 'Start with the basics — name, dates and capacity.'\n ),\n icon: <CalendarDays className=\"h-4 w-4\" />,\n onClick: () => navigate('/events'),\n },\n {\n id: 'add-venue',\n label: t('eventfullymanaged.dashboard.nextSteps.addVenue', 'Add a venue'),\n description: t(\n 'eventfullymanaged.dashboard.nextSteps.addVenueDesc',\n 'Map your event to a space with capacity and floor plans.'\n ),\n icon: <Building2 className=\"h-4 w-4\" />,\n onClick: () => navigate('/venues/create'),\n },\n {\n id: 'open-registration',\n label: t('eventfullymanaged.dashboard.nextSteps.openRegistration', 'Open registration'),\n description: t(\n 'eventfullymanaged.dashboard.nextSteps.openRegistrationDesc',\n 'Set up ticket types and track attendee sign-ups.'\n ),\n icon: <Ticket className=\"h-4 w-4\" />,\n onClick: () => navigate('/registration'),\n },\n {\n id: 'invite-sponsors',\n label: t('eventfullymanaged.dashboard.nextSteps.inviteSponsors', 'Onboard sponsors'),\n description: t(\n 'eventfullymanaged.dashboard.nextSteps.inviteSponsorsDesc',\n 'Add sponsors and start tracking value and leads.'\n ),\n icon: <Megaphone className=\"h-4 w-4\" />,\n onClick: () => navigate('/communication'),\n },\n ]}\n />\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -1,61 +1,73 @@
1
- import { useAnalyticsSnapshotsQuery as e, useUpsertAnalyticsSnapshotMutation as t } from "../../api/eventApi.js";
2
- import { EntityListSection as n } from "./EntityListSection.js";
3
- import { useMemo as r, useState as i } from "react";
4
- import { jsx as a, jsxs as o } from "react/jsx-runtime";
5
- import { BarChart3 as s } from "lucide-react";
6
- import { Button as c, EmphasisPanel as l, GradientText as u, Input as d } from "@burdenoff/fe-libs/ui";
1
+ import { notify as e } from "../../lib/toast.js";
2
+ import { useAnalyticsSnapshotsQuery as t, useUpsertAnalyticsSnapshotMutation as n } from "../../api/eventApi.js";
3
+ import { describeError as r, mutationSucceeded as i } from "../../lib/mutationResult.js";
4
+ import { EntityListSection as a } from "./EntityListSection.js";
5
+ import { useMemo as o, useState as s } from "react";
6
+ import { jsx as c, jsxs as l } from "react/jsx-runtime";
7
+ import { BarChart3 as u } from "lucide-react";
8
+ import { Button as d, EmphasisPanel as f, GradientText as p, Input as m, PagePurpose as h } from "@burdenoff/fe-libs/ui";
7
9
  //#region src/eventfullymanaged/pages/modules/AnalyticsPage.tsx
8
- function f() {
9
- let f = e({
10
+ function g() {
11
+ let g = t({
10
12
  limit: 100,
11
13
  offset: 0
12
- }), [p, { loading: m }] = t(), [h, g] = i("overview"), _ = r(() => f.data?.analyticsSnapshots.items ?? [], [f.data]);
13
- return /* @__PURE__ */ o("div", {
14
+ }), [_, { loading: v }] = n(), [y, b] = s("overview"), x = o(() => g.data?.analyticsSnapshots.items ?? [], [g.data]);
15
+ return /* @__PURE__ */ l("div", {
14
16
  className: "space-y-6 p-6",
15
- children: [/* @__PURE__ */ o(l, { children: [
16
- /* @__PURE__ */ a("h1", {
17
- className: "text-2xl font-bold text-text-primary",
18
- children: /* @__PURE__ */ a(u, { children: "Analytics" })
19
- }),
20
- /* @__PURE__ */ a("p", {
21
- className: "mt-1 text-sm text-text-secondary",
22
- children: "Generate and track analytics snapshots from event operations data."
23
- }),
24
- /* @__PURE__ */ o("div", {
25
- className: "mt-4 flex flex-col gap-3 sm:flex-row",
26
- children: [/* @__PURE__ */ a(d, {
27
- value: h,
28
- onChange: (e) => g(e.target.value),
29
- placeholder: "daily-summary",
30
- "aria-label": "Snapshot name",
31
- className: "flex-1"
32
- }), /* @__PURE__ */ o(c, {
33
- type: "button",
34
- disabled: m,
35
- onClick: async () => {
36
- h.trim() && await p({ variables: { input: {
37
- name: h,
38
- title: h,
39
- status: "created",
40
- metadata: {}
41
- } } });
42
- },
43
- children: [/* @__PURE__ */ a(s, { className: "h-4 w-4" }), m ? "Generating..." : "Generate Snapshot"]
44
- })]
17
+ children: [
18
+ /* @__PURE__ */ c(h, { children: "Snapshots capture a point-in-time picture of how your events are performing — registrations, attendance, revenue and engagement frozen at the moment you generate them. Use this page to take a daily or post-event snapshot so you can compare trends over time and report on outcomes." }),
19
+ /* @__PURE__ */ l(f, { children: [
20
+ /* @__PURE__ */ c("h1", {
21
+ className: "text-2xl font-bold text-text-primary",
22
+ children: /* @__PURE__ */ c(p, { children: "Analytics" })
23
+ }),
24
+ /* @__PURE__ */ c("p", {
25
+ className: "mt-1 text-sm text-text-secondary",
26
+ children: "Generate and track analytics snapshots from event operations data."
27
+ }),
28
+ /* @__PURE__ */ l("div", {
29
+ className: "mt-4 flex flex-col gap-3 sm:flex-row",
30
+ children: [/* @__PURE__ */ c(m, {
31
+ value: y,
32
+ onChange: (e) => b(e.target.value),
33
+ placeholder: "daily-summary",
34
+ "aria-label": "Snapshot name",
35
+ className: "flex-1"
36
+ }), /* @__PURE__ */ l(d, {
37
+ type: "button",
38
+ disabled: v,
39
+ onClick: async () => {
40
+ if (y.trim()) try {
41
+ let t = await _({ variables: { input: {
42
+ name: y,
43
+ title: y,
44
+ status: "created",
45
+ metadata: {}
46
+ } } });
47
+ if (!i(t, t.data?.upsertAnalyticsSnapshot?.id, "Could not generate snapshot")) return;
48
+ e.success("Snapshot generated");
49
+ } catch (t) {
50
+ e.error("Could not generate snapshot", r(t));
51
+ }
52
+ },
53
+ children: [/* @__PURE__ */ c(u, { className: "h-4 w-4" }), v ? "Generating..." : "Generate Snapshot"]
54
+ })]
55
+ })
56
+ ] }),
57
+ /* @__PURE__ */ c(a, {
58
+ heading: g.loading ? "Loading snapshots..." : `Snapshots (${x.length})`,
59
+ emptyLabel: "No analytics snapshots available yet.",
60
+ emptyIllustration: "empty-data",
61
+ rows: x.map((e) => ({
62
+ id: e.id,
63
+ title: e.title ?? e.name ?? `Snapshot ${e.id}`,
64
+ status: e.status ?? void 0
65
+ }))
45
66
  })
46
- ] }), /* @__PURE__ */ a(n, {
47
- heading: f.loading ? "Loading snapshots..." : `Snapshots (${_.length})`,
48
- emptyLabel: "No analytics snapshots available yet.",
49
- emptyIllustration: "empty-data",
50
- rows: _.map((e) => ({
51
- id: e.id,
52
- title: e.title ?? e.name ?? `Snapshot ${e.id}`,
53
- status: e.status ?? void 0
54
- }))
55
- })]
67
+ ]
56
68
  });
57
69
  }
58
70
  //#endregion
59
- export { f as default };
71
+ export { g as default };
60
72
 
61
73
  //# sourceMappingURL=AnalyticsPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AnalyticsPage.js","names":[],"sources":["../../../../src/eventfullymanaged/pages/modules/AnalyticsPage.tsx"],"sourcesContent":["import { BarChart3 } from 'lucide-react';\nimport { Button, EmphasisPanel, GradientText, Input } from '@burdenoff/fe-libs/ui';\nimport { useMemo, useState } from 'react';\n\nimport { useAnalyticsSnapshotsQuery, useUpsertAnalyticsSnapshotMutation } from '../../api/eventApi';\nimport { EntityListSection } from './EntityListSection';\n\ntype SnapshotRow = {\n id: string;\n name?: string;\n title?: string;\n status?: string;\n};\n\nexport default function AnalyticsPage() {\n const snapshotsQuery = useAnalyticsSnapshotsQuery({ limit: 100, offset: 0 });\n const [upsertSnapshot, { loading: creating }] = useUpsertAnalyticsSnapshotMutation();\n const [snapshotName, setSnapshotName] = useState('overview');\n\n const snapshots = useMemo(\n () => (snapshotsQuery.data?.analyticsSnapshots.items ?? []) as SnapshotRow[],\n [snapshotsQuery.data]\n );\n\n const onCreate = async () => {\n if (!snapshotName.trim()) return;\n await upsertSnapshot({\n variables: {\n input: {\n name: snapshotName,\n title: snapshotName,\n status: 'created',\n metadata: {},\n },\n },\n });\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>Analytics</GradientText>\n </h1>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Generate and track analytics snapshots from event operations data.\n </p>\n <div className=\"mt-4 flex flex-col gap-3 sm:flex-row\">\n <Input\n value={snapshotName}\n onChange={(e) => setSnapshotName(e.target.value)}\n placeholder=\"daily-summary\"\n aria-label=\"Snapshot name\"\n className=\"flex-1\"\n />\n <Button type=\"button\" disabled={creating} onClick={onCreate}>\n <BarChart3 className=\"h-4 w-4\" />\n {creating ? 'Generating...' : 'Generate Snapshot'}\n </Button>\n </div>\n </EmphasisPanel>\n\n <EntityListSection\n heading={snapshotsQuery.loading ? 'Loading snapshots...' : `Snapshots (${snapshots.length})`}\n emptyLabel=\"No analytics snapshots available yet.\"\n emptyIllustration=\"empty-data\"\n rows={snapshots.map((row) => ({\n id: row.id,\n title: row.title ?? row.name ?? `Snapshot ${row.id}`,\n status: row.status ?? undefined,\n }))}\n />\n </div>\n );\n}\n"],"mappings":";;;;;;;AAcA,SAAwB,IAAgB;CACtC,IAAM,IAAiB,EAA2B;EAAE,OAAO;EAAK,QAAQ;EAAG,CAAC,EACtE,CAAC,GAAgB,EAAE,SAAS,OAAc,GAAoC,EAC9E,CAAC,GAAc,KAAmB,EAAS,WAAW,EAEtD,IAAY,QACT,EAAe,MAAM,mBAAmB,SAAS,EAAE,EAC1D,CAAC,EAAe,KAAK,CACtB;AAgBD,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,GAAD,EAAA,UAAA;GACE,kBAAC,MAAD;IAAI,WAAU;cACZ,kBAAC,GAAD,EAAA,UAAc,aAAwB,CAAA;IACnC,CAAA;GACL,kBAAC,KAAD;IAAG,WAAU;cAAmC;IAE5C,CAAA;GACJ,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,GAAD;KACE,OAAO;KACP,WAAW,MAAM,EAAgB,EAAE,OAAO,MAAM;KAChD,aAAY;KACZ,cAAW;KACX,WAAU;KACV,CAAA,EACF,kBAAC,GAAD;KAAQ,MAAK;KAAS,UAAU;KAAU,SA/BjC,YAAY;AACtB,QAAa,MAAM,IACxB,MAAM,EAAe,EACnB,WAAW,EACT,OAAO;OACL,MAAM;OACN,OAAO;OACP,QAAQ;OACR,UAAU,EAAE;OACb,EACF,EACF,CAAC;;eAoBI,CACE,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA,EAChC,IAAW,kBAAkB,oBACvB;OACL;;GACQ,EAAA,CAAA,EAEhB,kBAAC,GAAD;GACE,SAAS,EAAe,UAAU,yBAAyB,cAAc,EAAU,OAAO;GAC1F,YAAW;GACX,mBAAkB;GAClB,MAAM,EAAU,KAAK,OAAS;IAC5B,IAAI,EAAI;IACR,OAAO,EAAI,SAAS,EAAI,QAAQ,YAAY,EAAI;IAChD,QAAQ,EAAI,UAAU,KAAA;IACvB,EAAE;GACH,CAAA,CACE"}
1
+ {"version":3,"file":"AnalyticsPage.js","names":[],"sources":["../../../../src/eventfullymanaged/pages/modules/AnalyticsPage.tsx"],"sourcesContent":["import { BarChart3 } from 'lucide-react';\nimport { Button, EmphasisPanel, GradientText, Input, PagePurpose } from '@burdenoff/fe-libs/ui';\nimport { useMemo, useState } from 'react';\n\nimport { useAnalyticsSnapshotsQuery, useUpsertAnalyticsSnapshotMutation } from '../../api/eventApi';\nimport { describeError, mutationSucceeded } from '../../lib/mutationResult';\nimport { notify } from '../../lib/toast';\nimport { EntityListSection } from './EntityListSection';\n\ntype SnapshotRow = {\n id: string;\n name?: string;\n title?: string;\n status?: string;\n};\n\nexport default function AnalyticsPage() {\n const snapshotsQuery = useAnalyticsSnapshotsQuery({ limit: 100, offset: 0 });\n const [upsertSnapshot, { loading: creating }] = useUpsertAnalyticsSnapshotMutation();\n const [snapshotName, setSnapshotName] = useState('overview');\n\n const snapshots = useMemo(\n () => (snapshotsQuery.data?.analyticsSnapshots.items ?? []) as SnapshotRow[],\n [snapshotsQuery.data]\n );\n\n const onCreate = async () => {\n if (!snapshotName.trim()) return;\n try {\n const response = await upsertSnapshot({\n variables: {\n input: {\n name: snapshotName,\n title: snapshotName,\n status: 'created',\n metadata: {},\n },\n },\n });\n if (!mutationSucceeded(response, response.data?.upsertAnalyticsSnapshot?.id, 'Could not generate snapshot')) {\n return;\n }\n notify.success('Snapshot generated');\n } catch (error) {\n notify.error('Could not generate snapshot', describeError(error));\n }\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n <PagePurpose>\n Snapshots capture a point-in-time picture of how your events are performing — registrations, attendance, revenue\n and engagement frozen at the moment you generate them. Use this page to take a daily or post-event snapshot so\n you can compare trends over time and report on outcomes.\n </PagePurpose>\n\n <EmphasisPanel>\n <h1 className=\"text-2xl font-bold text-text-primary\">\n <GradientText>Analytics</GradientText>\n </h1>\n <p className=\"mt-1 text-sm text-text-secondary\">\n Generate and track analytics snapshots from event operations data.\n </p>\n <div className=\"mt-4 flex flex-col gap-3 sm:flex-row\">\n <Input\n value={snapshotName}\n onChange={(e) => setSnapshotName(e.target.value)}\n placeholder=\"daily-summary\"\n aria-label=\"Snapshot name\"\n className=\"flex-1\"\n />\n <Button type=\"button\" disabled={creating} onClick={onCreate}>\n <BarChart3 className=\"h-4 w-4\" />\n {creating ? 'Generating...' : 'Generate Snapshot'}\n </Button>\n </div>\n </EmphasisPanel>\n\n <EntityListSection\n heading={snapshotsQuery.loading ? 'Loading snapshots...' : `Snapshots (${snapshots.length})`}\n emptyLabel=\"No analytics snapshots available yet.\"\n emptyIllustration=\"empty-data\"\n rows={snapshots.map((row) => ({\n id: row.id,\n title: row.title ?? row.name ?? `Snapshot ${row.id}`,\n status: row.status ?? undefined,\n }))}\n />\n </div>\n );\n}\n"],"mappings":";;;;;;;;;AAgBA,SAAwB,IAAgB;CACtC,IAAM,IAAiB,EAA2B;EAAE,OAAO;EAAK,QAAQ;EAAG,CAAC,EACtE,CAAC,GAAgB,EAAE,SAAS,OAAc,GAAoC,EAC9E,CAAC,GAAc,KAAmB,EAAS,WAAW,EAEtD,IAAY,QACT,EAAe,MAAM,mBAAmB,SAAS,EAAE,EAC1D,CAAC,EAAe,KAAK,CACtB;AAwBD,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GACE,kBAAC,GAAD,EAAA,UAAa,4RAIC,CAAA;GAEd,kBAAC,GAAD,EAAA,UAAA;IACE,kBAAC,MAAD;KAAI,WAAU;eACZ,kBAAC,GAAD,EAAA,UAAc,aAAwB,CAAA;KACnC,CAAA;IACL,kBAAC,KAAD;KAAG,WAAU;eAAmC;KAE5C,CAAA;IACJ,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD;MACE,OAAO;MACP,WAAW,MAAM,EAAgB,EAAE,OAAO,MAAM;MAChD,aAAY;MACZ,cAAW;MACX,WAAU;MACV,CAAA,EACF,kBAAC,GAAD;MAAQ,MAAK;MAAS,UAAU;MAAU,SA7CjC,YAAY;AACtB,aAAa,MAAM,CACxB,KAAI;QACF,IAAM,IAAW,MAAM,EAAe,EACpC,WAAW,EACT,OAAO;SACL,MAAM;SACN,OAAO;SACP,QAAQ;SACR,UAAU,EAAE;SACb,EACF,EACF,CAAC;AACF,YAAI,CAAC,EAAkB,GAAU,EAAS,MAAM,yBAAyB,IAAI,8BAA8B,CACzG;AAEF,UAAO,QAAQ,qBAAqB;gBAC7B,GAAO;AACd,UAAO,MAAM,+BAA+B,EAAc,EAAM,CAAC;;;gBA2B7D,CACE,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA,EAChC,IAAW,kBAAkB,oBACvB;QACL;;IACQ,EAAA,CAAA;GAEhB,kBAAC,GAAD;IACE,SAAS,EAAe,UAAU,yBAAyB,cAAc,EAAU,OAAO;IAC1F,YAAW;IACX,mBAAkB;IAClB,MAAM,EAAU,KAAK,OAAS;KAC5B,IAAI,EAAI;KACR,OAAO,EAAI,SAAS,EAAI,QAAQ,YAAY,EAAI;KAChD,QAAQ,EAAI,UAAU,KAAA;KACvB,EAAE;IACH,CAAA;GACE"}