@burdenoff/microfe-eventfullymanaged 2026.828.1 → 2026.830.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.
@@ -1 +1 @@
1
- {"version":3,"file":"EventfullyManagedRoot.d.ts","sourceRoot":"","sources":["../../src/eventfullymanaged/EventfullyManagedRoot.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAC;AAqD1D,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,0BAA0B,2CAYtE"}
1
+ {"version":3,"file":"EventfullyManagedRoot.d.ts","sourceRoot":"","sources":["../../src/eventfullymanaged/EventfullyManagedRoot.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAC;AAwE1D,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,0BAA0B,2CAYtE"}
@@ -2,9 +2,10 @@ import { EventfullyManagedRoutes as e } from "./EventfullyManagedRoutes.js";
2
2
  import { EventfullyManagedProvider as t } from "./context/EventfullyManagedContext.js";
3
3
  import { Component as n } from "react";
4
4
  import { FeatureFlagProvider as r } from "@burdenoff/fe-libs/shared/feature-flags";
5
- import { jsx as i, jsxs as a } from "react/jsx-runtime";
5
+ import { useI18n as i } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
6
+ import { jsx as a, jsxs as o } from "react/jsx-runtime";
6
7
  //#region src/eventfullymanaged/EventfullyManagedRoot.tsx
7
- var o = class extends n {
8
+ var s = class extends n {
8
9
  constructor(e) {
9
10
  super(e), this.state = {
10
11
  hasError: !1,
@@ -22,52 +23,63 @@ var o = class extends n {
22
23
  this.setState({ errorInfo: t });
23
24
  }
24
25
  render() {
25
- return this.state.hasError ? /* @__PURE__ */ a("div", {
26
+ let { t: e } = this.props;
27
+ return this.state.hasError ? /* @__PURE__ */ o("div", {
26
28
  className: "p-6 bg-red-50 border border-red-200 rounded-lg m-4",
27
29
  children: [
28
- /* @__PURE__ */ i("h2", {
30
+ /* @__PURE__ */ a("h2", {
29
31
  className: "text-lg font-semibold text-red-800 mb-2",
30
- children: "Something went wrong"
32
+ children: e("eventfullymanaged.errors.boundary.title", "Something went wrong")
31
33
  }),
32
- /* @__PURE__ */ i("p", {
34
+ /* @__PURE__ */ a("p", {
33
35
  className: "text-red-700 mb-4",
34
- children: this.state.error?.message || "Unknown error"
36
+ children: this.state.error?.message || e("eventfullymanaged.errors.boundary.unknown", "Unknown error")
35
37
  }),
36
- /* @__PURE__ */ a("details", {
38
+ /* @__PURE__ */ o("details", {
37
39
  className: "text-sm text-red-600",
38
- children: [/* @__PURE__ */ i("summary", {
40
+ children: [/* @__PURE__ */ a("summary", {
39
41
  className: "cursor-pointer hover:underline",
40
- children: "Error details"
41
- }), /* @__PURE__ */ a("pre", {
42
+ children: e("eventfullymanaged.errors.boundary.details", "Error details")
43
+ }), /* @__PURE__ */ o("pre", {
42
44
  className: "mt-2 p-2 bg-red-100 rounded overflow-auto text-xs",
43
45
  children: [this.state.error?.stack, this.state.errorInfo?.componentStack]
44
46
  })]
45
47
  }),
46
- /* @__PURE__ */ i("button", {
48
+ /* @__PURE__ */ a("button", {
47
49
  type: "button",
48
50
  onClick: () => window.location.reload(),
49
51
  className: "mt-4 px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700",
50
- children: "Reload Page"
52
+ children: e("eventfullymanaged.errors.boundary.reload", "Reload Page")
51
53
  })
52
54
  ]
53
55
  }) : this.props.children;
54
56
  }
55
57
  };
56
- function s(n) {
57
- return /* @__PURE__ */ i(o, { children: /* @__PURE__ */ i(r, {
58
+ function c({ children: e }) {
59
+ let { t } = i();
60
+ return /* @__PURE__ */ a(s, {
61
+ t: (e, n) => {
62
+ let r = t(e);
63
+ return r === e ? n : r;
64
+ },
65
+ children: e
66
+ });
67
+ }
68
+ function l(n) {
69
+ return /* @__PURE__ */ a(c, { children: /* @__PURE__ */ a(r, {
58
70
  workspaceId: null,
59
71
  gateway: "global",
60
72
  defaultEnabled: !0,
61
- children: /* @__PURE__ */ i(t, {
73
+ children: /* @__PURE__ */ a(t, {
62
74
  props: n,
63
- children: /* @__PURE__ */ i("div", {
75
+ children: /* @__PURE__ */ a("div", {
64
76
  className: "eventfullymanaged-root h-full",
65
- children: /* @__PURE__ */ i(e, {})
77
+ children: /* @__PURE__ */ a(e, {})
66
78
  })
67
79
  })
68
80
  }) });
69
81
  }
70
82
  //#endregion
71
- export { s as EventfullyManagedRoot };
83
+ export { l as EventfullyManagedRoot };
72
84
 
73
85
  //# sourceMappingURL=EventfullyManagedRoot.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"EventfullyManagedRoot.js","names":[],"sources":["../../src/eventfullymanaged/EventfullyManagedRoot.tsx"],"sourcesContent":["import { Component, type ReactNode, type ErrorInfo } from 'react';\nimport { FeatureFlagProvider } from '@burdenoff/fe-libs/shared/feature-flags';\nimport type { EventfullyManagedRootProps } from './types';\nimport { EventfullyManagedRoutes } from './EventfullyManagedRoutes';\nimport { EventfullyManagedProvider } from './context/EventfullyManagedContext';\n\n// Error Boundary to catch and display errors\ninterface ErrorBoundaryState {\n hasError: boolean;\n error: Error | null;\n errorInfo: ErrorInfo | null;\n}\n\nclass EventfullyManagedErrorBoundary extends Component<{ children: ReactNode }, ErrorBoundaryState> {\n constructor(props: { children: ReactNode }) {\n super(props);\n this.state = { hasError: false, error: null, errorInfo: null };\n }\n\n static getDerivedStateFromError(error: Error): Partial<ErrorBoundaryState> {\n return { hasError: true, error };\n }\n\n componentDidCatch(error: Error, errorInfo: ErrorInfo) {\n this.setState({ errorInfo });\n }\n\n render() {\n if (this.state.hasError) {\n return (\n <div className=\"p-6 bg-red-50 border border-red-200 rounded-lg m-4\">\n <h2 className=\"text-lg font-semibold text-red-800 mb-2\">Something went wrong</h2>\n <p className=\"text-red-700 mb-4\">{this.state.error?.message || 'Unknown error'}</p>\n <details className=\"text-sm text-red-600\">\n <summary className=\"cursor-pointer hover:underline\">Error details</summary>\n <pre className=\"mt-2 p-2 bg-red-100 rounded overflow-auto text-xs\">\n {this.state.error?.stack}\n {this.state.errorInfo?.componentStack}\n </pre>\n </details>\n <button\n type=\"button\"\n onClick={() => window.location.reload()}\n className=\"mt-4 px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700\"\n >\n Reload Page\n </button>\n </div>\n );\n }\n\n return this.props.children;\n }\n}\n\nexport function EventfullyManagedRoot(props: EventfullyManagedRootProps) {\n return (\n <EventfullyManagedErrorBoundary>\n <FeatureFlagProvider workspaceId={null} gateway=\"global\" defaultEnabled={true}>\n <EventfullyManagedProvider props={props}>\n <div className=\"eventfullymanaged-root h-full\">\n <EventfullyManagedRoutes />\n </div>\n </EventfullyManagedProvider>\n </FeatureFlagProvider>\n </EventfullyManagedErrorBoundary>\n );\n}\n"],"mappings":";;;;;;AAaA,IAAM,IAAN,cAA6C,EAAuD;CAClG,YAAY,GAAgC;AAE1C,EADA,MAAM,EAAM,EACZ,KAAK,QAAQ;GAAE,UAAU;GAAO,OAAO;GAAM,WAAW;GAAM;;CAGhE,OAAO,yBAAyB,GAA2C;AACzE,SAAO;GAAE,UAAU;GAAM;GAAO;;CAGlC,kBAAkB,GAAc,GAAsB;AACpD,OAAK,SAAS,EAAE,cAAW,CAAC;;CAG9B,SAAS;AAwBP,SAvBI,KAAK,MAAM,WAEX,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,MAAD;KAAI,WAAU;eAA0C;KAAyB,CAAA;IACjF,kBAAC,KAAD;KAAG,WAAU;eAAqB,KAAK,MAAM,OAAO,WAAW;KAAoB,CAAA;IACnF,kBAAC,WAAD;KAAS,WAAU;eAAnB,CACE,kBAAC,WAAD;MAAS,WAAU;gBAAiC;MAAuB,CAAA,EAC3E,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACG,KAAK,MAAM,OAAO,OAClB,KAAK,MAAM,WAAW,eACnB;QACE;;IACV,kBAAC,UAAD;KACE,MAAK;KACL,eAAe,OAAO,SAAS,QAAQ;KACvC,WAAU;eACX;KAEQ,CAAA;IACL;OAIH,KAAK,MAAM;;;AAItB,SAAgB,EAAsB,GAAmC;AACvE,QACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;EAAqB,aAAa;EAAM,SAAQ;EAAS,gBAAgB;YACvE,kBAAC,GAAD;GAAkC;aAChC,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD,EAA2B,CAAA;IACvB,CAAA;GACoB,CAAA;EACR,CAAA,EACS,CAAA"}
1
+ {"version":3,"file":"EventfullyManagedRoot.js","names":[],"sources":["../../src/eventfullymanaged/EventfullyManagedRoot.tsx"],"sourcesContent":["import { Component, type ReactNode, type ErrorInfo } from 'react';\nimport { FeatureFlagProvider } from '@burdenoff/fe-libs/shared/feature-flags';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport type { EventfullyManagedRootProps } from './types';\nimport { EventfullyManagedRoutes } from './EventfullyManagedRoutes';\nimport { EventfullyManagedProvider } from './context/EventfullyManagedContext';\n\n// Error Boundary to catch and display errors\ninterface ErrorBoundaryState {\n hasError: boolean;\n error: Error | null;\n errorInfo: ErrorInfo | null;\n}\n\nclass EventfullyManagedErrorBoundary extends Component<\n { children: ReactNode; t: (key: string, fallback: string) => string },\n ErrorBoundaryState\n> {\n constructor(props: { children: ReactNode; t: (key: string, fallback: string) => string }) {\n super(props);\n this.state = { hasError: false, error: null, errorInfo: null };\n }\n\n static getDerivedStateFromError(error: Error): Partial<ErrorBoundaryState> {\n return { hasError: true, error };\n }\n\n componentDidCatch(error: Error, errorInfo: ErrorInfo) {\n this.setState({ errorInfo });\n }\n\n render() {\n const { t } = this.props;\n if (this.state.hasError) {\n return (\n <div className=\"p-6 bg-red-50 border border-red-200 rounded-lg m-4\">\n <h2 className=\"text-lg font-semibold text-red-800 mb-2\">\n {t('eventfullymanaged.errors.boundary.title', 'Something went wrong')}\n </h2>\n <p className=\"text-red-700 mb-4\">\n {this.state.error?.message || t('eventfullymanaged.errors.boundary.unknown', 'Unknown error')}\n </p>\n <details className=\"text-sm text-red-600\">\n <summary className=\"cursor-pointer hover:underline\">\n {t('eventfullymanaged.errors.boundary.details', 'Error details')}\n </summary>\n <pre className=\"mt-2 p-2 bg-red-100 rounded overflow-auto text-xs\">\n {this.state.error?.stack}\n {this.state.errorInfo?.componentStack}\n </pre>\n </details>\n <button\n type=\"button\"\n onClick={() => window.location.reload()}\n className=\"mt-4 px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700\"\n >\n {t('eventfullymanaged.errors.boundary.reload', 'Reload Page')}\n </button>\n </div>\n );\n }\n\n return this.props.children;\n }\n}\n\nfunction TranslatedBoundary({ children }: { children: ReactNode }) {\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 return <EventfullyManagedErrorBoundary t={t}>{children}</EventfullyManagedErrorBoundary>;\n}\n\nexport function EventfullyManagedRoot(props: EventfullyManagedRootProps) {\n return (\n <TranslatedBoundary>\n <FeatureFlagProvider workspaceId={null} gateway=\"global\" defaultEnabled={true}>\n <EventfullyManagedProvider props={props}>\n <div className=\"eventfullymanaged-root h-full\">\n <EventfullyManagedRoutes />\n </div>\n </EventfullyManagedProvider>\n </FeatureFlagProvider>\n </TranslatedBoundary>\n );\n}\n"],"mappings":";;;;;;;AAcA,IAAM,IAAN,cAA6C,EAG3C;CACA,YAAY,GAA8E;AAExF,EADA,MAAM,EAAM,EACZ,KAAK,QAAQ;GAAE,UAAU;GAAO,OAAO;GAAM,WAAW;GAAM;;CAGhE,OAAO,yBAAyB,GAA2C;AACzE,SAAO;GAAE,UAAU;GAAM;GAAO;;CAGlC,kBAAkB,GAAc,GAAsB;AACpD,OAAK,SAAS,EAAE,cAAW,CAAC;;CAG9B,SAAS;EACP,IAAM,EAAE,SAAM,KAAK;AA8BnB,SA7BI,KAAK,MAAM,WAEX,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,MAAD;KAAI,WAAU;eACX,EAAE,2CAA2C,uBAAuB;KAClE,CAAA;IACL,kBAAC,KAAD;KAAG,WAAU;eACV,KAAK,MAAM,OAAO,WAAW,EAAE,6CAA6C,gBAAgB;KAC3F,CAAA;IACJ,kBAAC,WAAD;KAAS,WAAU;eAAnB,CACE,kBAAC,WAAD;MAAS,WAAU;gBAChB,EAAE,6CAA6C,gBAAgB;MACxD,CAAA,EACV,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACG,KAAK,MAAM,OAAO,OAClB,KAAK,MAAM,WAAW,eACnB;QACE;;IACV,kBAAC,UAAD;KACE,MAAK;KACL,eAAe,OAAO,SAAS,QAAQ;KACvC,WAAU;eAET,EAAE,4CAA4C,cAAc;KACtD,CAAA;IACL;OAIH,KAAK,MAAM;;;AAItB,SAAS,EAAmB,EAAE,eAAqC;CACjE,IAAM,EAAK,MAAc,GAAS;AAKlC,QAAO,kBAAC,GAAD;EAAmC,IAJ/B,GAAa,MAAqB;GAC3C,IAAM,IAAQ,EAAU,EAAI;AAC5B,UAAO,MAAU,IAAM,IAAW;;EAEU;EAA0C,CAAA;;AAG1F,SAAgB,EAAsB,GAAmC;AACvE,QACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;EAAqB,aAAa;EAAM,SAAQ;EAAS,gBAAgB;YACvE,kBAAC,GAAD;GAAkC;aAChC,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,GAAD,EAA2B,CAAA;IACvB,CAAA;GACoB,CAAA;EACR,CAAA,EACH,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardPage.d.ts","sourceRoot":"","sources":["../../../../src/eventfullymanaged/pages/dashboard/DashboardPage.tsx"],"names":[],"mappings":"AA+HA,MAAM,CAAC,OAAO,UAAU,aAAa,4CAyQpC"}
1
+ {"version":3,"file":"DashboardPage.d.ts","sourceRoot":"","sources":["../../../../src/eventfullymanaged/pages/dashboard/DashboardPage.tsx"],"names":[],"mappings":"AA+HA,MAAM,CAAC,OAAO,UAAU,aAAa,4CAqQpC"}
@@ -1,14 +1,14 @@
1
1
  import { useEventfullyManaged as e } from "../../context/EventfullyManagedContext.js";
2
2
  import { gql as t } from "../../../node_modules/graphql-tag/lib/index.js";
3
3
  import { useQuery as n } from "../../../node_modules/@apollo/client/react/hooks/useQuery.js";
4
- import { useDashboardSummaryQuery as r } from "../../api/eventApi.js";
5
- import { EventAreaChart as i } from "../../components/EventCharts.js";
6
- import { PageLayout as a } from "../../components/PageLayout.js";
7
- import { formatDateTime as o } from "../events/eventFormUtils.js";
8
- import { useMemo as s, useState as c } from "react";
9
- import { jsx as l, jsxs as u } from "react/jsx-runtime";
10
- import { Building2 as d, CalendarClock as f, CalendarDays as p, ChevronRight as m, Handshake as h, PlayCircle as g, Ticket as _, UserPlus as v, Users as y } from "lucide-react";
11
- import { useI18n as b } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
4
+ import { useTr as r } from "../../../shared/hooks/useTr.js";
5
+ import { useDashboardSummaryQuery as i } from "../../api/eventApi.js";
6
+ import { EventAreaChart as a } from "../../components/EventCharts.js";
7
+ import { PageLayout as o } from "../../components/PageLayout.js";
8
+ import { formatDateTime as s } from "../events/eventFormUtils.js";
9
+ import { useMemo as c, useState as l } from "react";
10
+ import { jsx as u, jsxs as d } from "react/jsx-runtime";
11
+ import { Building2 as f, CalendarClock as p, CalendarDays as m, ChevronRight as h, Handshake as g, PlayCircle as _, Ticket as v, UserPlus as y, Users as b } from "lucide-react";
12
12
  import { GlassCard as x, GradientText as S, IllustratedEmptyState as C, NextSteps as w, PagePurpose as T, Skeleton as E } from "@burdenoff/fe-libs/ui";
13
13
  //#region src/eventfullymanaged/pages/dashboard/DashboardPage.tsx
14
14
  var D = t`
@@ -59,98 +59,95 @@ function j(e, t) {
59
59
  }));
60
60
  }
61
61
  function M() {
62
- let { t } = b(), k = (e, n) => {
63
- let r = t(e);
64
- return r === e ? n : r;
65
- }, { navigate: A } = e(), { data: M, loading: N } = r(), { data: P, loading: F } = n(D, { variables: { limit: 500 } }), { data: I, loading: L } = n(O, { variables: { limit: 100 } }), R = M?.dashboardSummary, [z] = c(() => Date.now()), B = s(() => j(P?.registrations?.items ?? [], z), [P, z]), V = s(() => (I?.eventSessions?.items ?? []).filter((e) => {
62
+ let t = r(), { navigate: k } = e(), { data: A, loading: M } = i(), { data: N, loading: P } = n(D, { variables: { limit: 500 } }), { data: F, loading: I } = n(O, { variables: { limit: 100 } }), L = A?.dashboardSummary, [R] = l(() => Date.now()), z = c(() => j(N?.registrations?.items ?? [], R), [N, R]), B = c(() => (F?.eventSessions?.items ?? []).filter((e) => {
66
63
  let t = new Date(e.startsAt).getTime();
67
- return !Number.isNaN(t) && t >= z;
68
- }).sort((e, t) => new Date(e.startsAt).getTime() - new Date(t.startsAt).getTime()).slice(0, 4), [I, z]), H = [
64
+ return !Number.isNaN(t) && t >= R;
65
+ }).sort((e, t) => new Date(e.startsAt).getTime() - new Date(t.startsAt).getTime()).slice(0, 4), [F, R]), V = [
69
66
  {
70
- label: k("eventfullymanaged.dashboard.cards.totalEvents", "Total Events"),
71
- value: R?.totalEvents ?? 0,
72
- sublabel: k("eventfullymanaged.dashboard.cards.totalEventsSub", "across your workspace"),
73
- icon: p,
67
+ label: t("eventfullymanaged.dashboard.cards.totalEvents", "Total Events"),
68
+ value: L?.totalEvents ?? 0,
69
+ sublabel: t("eventfullymanaged.dashboard.cards.totalEventsSub", "across your workspace"),
70
+ icon: m,
74
71
  path: "/events",
75
72
  featured: !0
76
73
  },
77
74
  {
78
- label: k("eventfullymanaged.dashboard.cards.activeEvents", "Active Events"),
79
- value: R?.activeEvents ?? 0,
80
- sublabel: k("eventfullymanaged.dashboard.cards.activeEventsSub", "live or published now"),
81
- icon: g,
75
+ label: t("eventfullymanaged.dashboard.cards.activeEvents", "Active Events"),
76
+ value: L?.activeEvents ?? 0,
77
+ sublabel: t("eventfullymanaged.dashboard.cards.activeEventsSub", "live or published now"),
78
+ icon: _,
82
79
  path: "/events"
83
80
  },
84
81
  {
85
- label: k("eventfullymanaged.dashboard.cards.registrations", "Registrations"),
86
- value: R?.totalRegistrations ?? 0,
87
- sublabel: k("eventfullymanaged.dashboard.cards.registrationsSub", "sign-ups received"),
88
- icon: v,
82
+ label: t("eventfullymanaged.dashboard.cards.registrations", "Registrations"),
83
+ value: L?.totalRegistrations ?? 0,
84
+ sublabel: t("eventfullymanaged.dashboard.cards.registrationsSub", "sign-ups received"),
85
+ icon: y,
89
86
  path: "/registration"
90
87
  },
91
88
  {
92
- label: k("eventfullymanaged.dashboard.cards.attendees", "Attendees"),
93
- value: R?.totalAttendees ?? 0,
94
- sublabel: k("eventfullymanaged.dashboard.cards.attendeesSub", "people in your audience"),
95
- icon: y,
89
+ label: t("eventfullymanaged.dashboard.cards.attendees", "Attendees"),
90
+ value: L?.totalAttendees ?? 0,
91
+ sublabel: t("eventfullymanaged.dashboard.cards.attendeesSub", "people in your audience"),
92
+ icon: b,
96
93
  path: "/registration"
97
94
  },
98
95
  {
99
- label: k("eventfullymanaged.dashboard.cards.venues", "Venues"),
100
- value: R?.totalVenues ?? 0,
101
- sublabel: k("eventfullymanaged.dashboard.cards.venuesSub", "spaces mapped"),
102
- icon: d,
96
+ label: t("eventfullymanaged.dashboard.cards.venues", "Venues"),
97
+ value: L?.totalVenues ?? 0,
98
+ sublabel: t("eventfullymanaged.dashboard.cards.venuesSub", "spaces mapped"),
99
+ icon: f,
103
100
  path: "/venues"
104
101
  },
105
102
  {
106
- label: k("eventfullymanaged.dashboard.cards.sponsors", "Sponsors"),
107
- value: R?.totalSponsors ?? 0,
108
- sublabel: k("eventfullymanaged.dashboard.cards.sponsorsSub", "partners onboarded"),
109
- icon: h,
103
+ label: t("eventfullymanaged.dashboard.cards.sponsors", "Sponsors"),
104
+ value: L?.totalSponsors ?? 0,
105
+ sublabel: t("eventfullymanaged.dashboard.cards.sponsorsSub", "partners onboarded"),
106
+ icon: g,
110
107
  path: "/sponsors"
111
108
  }
112
109
  ];
113
- return /* @__PURE__ */ u(a, {
110
+ return /* @__PURE__ */ d(o, {
114
111
  hero: !0,
115
- title: /* @__PURE__ */ l(S, {
112
+ title: /* @__PURE__ */ u(S, {
116
113
  as: "span",
117
- children: k("eventfullymanaged.dashboard.title", "Dashboard")
114
+ children: t("eventfullymanaged.dashboard.title", "Dashboard")
118
115
  }),
119
- description: N ? k("eventfullymanaged.dashboard.description.loading", "Loading real-time event operations summary…") : k("eventfullymanaged.dashboard.description.ready", "Your live event operations, at a glance."),
116
+ description: M ? t("eventfullymanaged.dashboard.description.loading", "Loading real-time event operations summary…") : t("eventfullymanaged.dashboard.description.ready", "Your live event operations, at a glance."),
120
117
  children: [
121
- /* @__PURE__ */ l(T, {
118
+ /* @__PURE__ */ u(T, {
122
119
  className: "mb-6",
123
- children: k("eventfullymanaged.dashboard.purpose", "Your event control center. Each tile below is a live count from a different part of your event operations. Open any tile to manage that area, watch registrations climb in the trend chart, and jump straight to the sessions coming up next.")
120
+ children: t("eventfullymanaged.dashboard.purpose", "Your event control center. Each tile below is a live count from a different part of your event operations. Open any tile to manage that area, watch registrations climb in the trend chart, and jump straight to the sessions coming up next.")
124
121
  }),
125
- /* @__PURE__ */ l("div", {
122
+ /* @__PURE__ */ u("div", {
126
123
  className: "grid grid-cols-2 gap-4 sm:grid-cols-3 xl:grid-cols-6",
127
- children: H.map((e) => {
124
+ children: V.map((e) => {
128
125
  let t = e.icon;
129
- return /* @__PURE__ */ u(x, {
126
+ return /* @__PURE__ */ d(x, {
130
127
  treatment: e.featured ? "glass" : "metric",
131
128
  glow: e.featured,
132
129
  role: "button",
133
130
  tabIndex: 0,
134
131
  "aria-label": `${e.label}: ${e.value.toLocaleString()}`,
135
- onClick: () => A(e.path),
132
+ onClick: () => k(e.path),
136
133
  onKeyDown: (t) => {
137
- (t.key === "Enter" || t.key === " ") && (t.preventDefault(), A(e.path));
134
+ (t.key === "Enter" || t.key === " ") && (t.preventDefault(), k(e.path));
138
135
  },
139
136
  className: "group cursor-pointer p-4 outline-none transition-[transform,box-shadow] duration-200 hover:shadow-elevation-1 focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]",
140
137
  children: [
141
- /* @__PURE__ */ l("span", {
138
+ /* @__PURE__ */ u("span", {
142
139
  className: "flex h-9 w-9 items-center justify-center rounded-button bg-accent-wash text-action-primary-bg",
143
- children: /* @__PURE__ */ l(t, { className: "h-5 w-5" })
140
+ children: /* @__PURE__ */ u(t, { className: "h-5 w-5" })
144
141
  }),
145
- /* @__PURE__ */ l("div", {
142
+ /* @__PURE__ */ u("div", {
146
143
  className: "mt-3 text-2xl font-semibold tabular-nums text-text-primary",
147
- children: N ? /* @__PURE__ */ l(E, { className: "h-7 w-14" }) : e.value.toLocaleString()
144
+ children: M ? /* @__PURE__ */ u(E, { className: "h-7 w-14" }) : e.value.toLocaleString()
148
145
  }),
149
- /* @__PURE__ */ l("div", {
146
+ /* @__PURE__ */ u("div", {
150
147
  className: "mt-1 text-sm font-medium text-text-primary",
151
148
  children: e.label
152
149
  }),
153
- /* @__PURE__ */ l("div", {
150
+ /* @__PURE__ */ u("div", {
154
151
  className: "mt-0.5 truncate text-xs text-text-muted",
155
152
  children: e.sublabel
156
153
  })
@@ -158,112 +155,112 @@ function M() {
158
155
  }, e.label);
159
156
  })
160
157
  }),
161
- /* @__PURE__ */ u("div", {
158
+ /* @__PURE__ */ d("div", {
162
159
  className: "mt-6 grid grid-cols-1 gap-4 lg:grid-cols-5",
163
- children: [/* @__PURE__ */ u(x, {
160
+ children: [/* @__PURE__ */ d(x, {
164
161
  treatment: "glass",
165
162
  className: "p-5 lg:col-span-3",
166
- children: [/* @__PURE__ */ u("div", {
163
+ children: [/* @__PURE__ */ d("div", {
167
164
  className: "flex items-start justify-between gap-4",
168
- children: [/* @__PURE__ */ u("div", { children: [/* @__PURE__ */ l("h2", {
165
+ children: [/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("h2", {
169
166
  className: "text-lg font-semibold text-text-primary",
170
- children: k("eventfullymanaged.dashboard.trend.title", "Registrations over time")
171
- }), /* @__PURE__ */ l("p", {
167
+ children: t("eventfullymanaged.dashboard.trend.title", "Registrations over time")
168
+ }), /* @__PURE__ */ u("p", {
172
169
  className: "mt-0.5 text-xs text-text-muted",
173
- children: k("eventfullymanaged.dashboard.trend.subtitle", "Cumulative sign-ups, last 30 days")
174
- })] }), /* @__PURE__ */ l("div", {
170
+ children: t("eventfullymanaged.dashboard.trend.subtitle", "Cumulative sign-ups, last 30 days")
171
+ })] }), /* @__PURE__ */ u("div", {
175
172
  className: "text-2xl font-semibold tabular-nums text-text-primary",
176
- children: (R?.totalRegistrations ?? 0).toLocaleString()
173
+ children: (L?.totalRegistrations ?? 0).toLocaleString()
177
174
  })]
178
- }), /* @__PURE__ */ l("div", {
175
+ }), /* @__PURE__ */ u("div", {
179
176
  className: "mt-4",
180
- children: F ? /* @__PURE__ */ l(E, { className: "h-[260px] w-full rounded-card" }) : B.some((e) => e.value > 0) ? /* @__PURE__ */ l(i, { data: B }) : /* @__PURE__ */ l(C, {
177
+ children: P ? /* @__PURE__ */ u(E, { className: "h-[260px] w-full rounded-card" }) : z.some((e) => e.value > 0) ? /* @__PURE__ */ u(a, { data: z }) : /* @__PURE__ */ u(C, {
181
178
  illustration: "empty-data",
182
- title: k("eventfullymanaged.dashboard.trend.empty", "No registrations yet."),
183
- description: k("eventfullymanaged.dashboard.trend.emptyHint", "Once attendees start signing up, their momentum shows here."),
179
+ title: t("eventfullymanaged.dashboard.trend.empty", "No registrations yet."),
180
+ description: t("eventfullymanaged.dashboard.trend.emptyHint", "Once attendees start signing up, their momentum shows here."),
184
181
  className: "py-10"
185
182
  })
186
183
  })]
187
- }), /* @__PURE__ */ u(x, {
184
+ }), /* @__PURE__ */ d(x, {
188
185
  treatment: "plain",
189
186
  className: "border-border-seam p-5 lg:col-span-2",
190
- children: [/* @__PURE__ */ l("h2", {
187
+ children: [/* @__PURE__ */ u("h2", {
191
188
  className: "text-lg font-semibold text-text-primary",
192
- children: k("eventfullymanaged.dashboard.upcoming.title", "Upcoming sessions")
193
- }), /* @__PURE__ */ l("div", {
189
+ children: t("eventfullymanaged.dashboard.upcoming.title", "Upcoming sessions")
190
+ }), /* @__PURE__ */ u("div", {
194
191
  className: "mt-3",
195
- children: L ? /* @__PURE__ */ u("div", {
192
+ children: I ? /* @__PURE__ */ d("div", {
196
193
  className: "space-y-3",
197
194
  children: [
198
- /* @__PURE__ */ l(E, { className: "h-14 w-full rounded-card" }),
199
- /* @__PURE__ */ l(E, { className: "h-14 w-full rounded-card" }),
200
- /* @__PURE__ */ l(E, { className: "h-14 w-full rounded-card" })
195
+ /* @__PURE__ */ u(E, { className: "h-14 w-full rounded-card" }),
196
+ /* @__PURE__ */ u(E, { className: "h-14 w-full rounded-card" }),
197
+ /* @__PURE__ */ u(E, { className: "h-14 w-full rounded-card" })
201
198
  ]
202
- }) : V.length === 0 ? /* @__PURE__ */ l(C, {
199
+ }) : B.length === 0 ? /* @__PURE__ */ u(C, {
203
200
  illustration: "empty-data",
204
- title: k("eventfullymanaged.dashboard.upcoming.empty", "Nothing scheduled yet."),
205
- description: k("eventfullymanaged.dashboard.upcoming.emptyHint", "Sessions you schedule will surface here as they approach."),
201
+ title: t("eventfullymanaged.dashboard.upcoming.empty", "Nothing scheduled yet."),
202
+ description: t("eventfullymanaged.dashboard.upcoming.emptyHint", "Sessions you schedule will surface here as they approach."),
206
203
  className: "py-8"
207
- }) : /* @__PURE__ */ l("ul", {
204
+ }) : /* @__PURE__ */ u("ul", {
208
205
  className: "divide-y divide-border-subtle",
209
- children: V.map((e) => /* @__PURE__ */ l("li", { children: /* @__PURE__ */ u("button", {
206
+ children: B.map((e) => /* @__PURE__ */ u("li", { children: /* @__PURE__ */ d("button", {
210
207
  type: "button",
211
- onClick: () => A(`/events/${e.eventId}`),
208
+ onClick: () => k(`/events/${e.eventId}`),
212
209
  className: "group flex w-full items-center gap-3 py-3 text-left outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]",
213
210
  children: [
214
- /* @__PURE__ */ l("span", {
211
+ /* @__PURE__ */ u("span", {
215
212
  className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-button bg-accent-wash text-action-primary-bg",
216
- children: /* @__PURE__ */ l(f, { className: "h-4 w-4" })
213
+ children: /* @__PURE__ */ u(p, { className: "h-4 w-4" })
217
214
  }),
218
- /* @__PURE__ */ u("span", {
215
+ /* @__PURE__ */ d("span", {
219
216
  className: "min-w-0 flex-1",
220
- children: [/* @__PURE__ */ l("span", {
217
+ children: [/* @__PURE__ */ u("span", {
221
218
  className: "block truncate text-sm font-medium text-text-primary",
222
219
  children: e.title
223
- }), /* @__PURE__ */ l("span", {
220
+ }), /* @__PURE__ */ u("span", {
224
221
  className: "mt-0.5 block truncate text-xs text-text-muted",
225
- children: [o(e.startsAt), e.track].filter(Boolean).join(" • ")
222
+ children: [s(e.startsAt), e.track].filter(Boolean).join(" • ")
226
223
  })]
227
224
  }),
228
- /* @__PURE__ */ l(m, { className: "h-4 w-4 shrink-0 text-text-muted transition-transform group-hover:translate-x-0.5" })
225
+ /* @__PURE__ */ u(h, { className: "h-4 w-4 shrink-0 text-text-muted transition-transform group-hover:translate-x-0.5" })
229
226
  ]
230
227
  }) }, e.id))
231
228
  })
232
229
  })]
233
230
  })]
234
231
  }),
235
- /* @__PURE__ */ l(w, {
232
+ /* @__PURE__ */ u(w, {
236
233
  className: "mt-6",
237
234
  storageKey: "eventfullymanaged-dashboard",
238
- title: k("eventfullymanaged.dashboard.nextSteps.title", "Get your first event running"),
235
+ title: t("eventfullymanaged.dashboard.nextSteps.title", "Get your first event running"),
239
236
  steps: [
240
237
  {
241
238
  id: "create-event",
242
- label: k("eventfullymanaged.dashboard.nextSteps.createEvent", "Create an event"),
243
- description: k("eventfullymanaged.dashboard.nextSteps.createEventDesc", "Start with the basics — name, dates and capacity."),
244
- icon: /* @__PURE__ */ l(p, { className: "h-4 w-4" }),
245
- onClick: () => A("/events/create")
239
+ label: t("eventfullymanaged.dashboard.nextSteps.createEvent", "Create an event"),
240
+ description: t("eventfullymanaged.dashboard.nextSteps.createEventDesc", "Start with the basics — name, dates and capacity."),
241
+ icon: /* @__PURE__ */ u(m, { className: "h-4 w-4" }),
242
+ onClick: () => k("/events/create")
246
243
  },
247
244
  {
248
245
  id: "add-venue",
249
- label: k("eventfullymanaged.dashboard.nextSteps.addVenue", "Add a venue"),
250
- description: k("eventfullymanaged.dashboard.nextSteps.addVenueDesc", "Map your event to a space with capacity and floor plans."),
251
- icon: /* @__PURE__ */ l(d, { className: "h-4 w-4" }),
252
- onClick: () => A("/venues/create")
246
+ label: t("eventfullymanaged.dashboard.nextSteps.addVenue", "Add a venue"),
247
+ description: t("eventfullymanaged.dashboard.nextSteps.addVenueDesc", "Map your event to a space with capacity and floor plans."),
248
+ icon: /* @__PURE__ */ u(f, { className: "h-4 w-4" }),
249
+ onClick: () => k("/venues/create")
253
250
  },
254
251
  {
255
252
  id: "open-registration",
256
- label: k("eventfullymanaged.dashboard.nextSteps.openRegistration", "Open registration"),
257
- description: k("eventfullymanaged.dashboard.nextSteps.openRegistrationDesc", "Set up ticket types and track attendee sign-ups."),
258
- icon: /* @__PURE__ */ l(_, { className: "h-4 w-4" }),
259
- onClick: () => A("/registration")
253
+ label: t("eventfullymanaged.dashboard.nextSteps.openRegistration", "Open registration"),
254
+ description: t("eventfullymanaged.dashboard.nextSteps.openRegistrationDesc", "Set up ticket types and track attendee sign-ups."),
255
+ icon: /* @__PURE__ */ u(v, { className: "h-4 w-4" }),
256
+ onClick: () => k("/registration")
260
257
  },
261
258
  {
262
259
  id: "invite-sponsors",
263
- label: k("eventfullymanaged.dashboard.nextSteps.inviteSponsors", "Onboard sponsors"),
264
- description: k("eventfullymanaged.dashboard.nextSteps.inviteSponsorsDesc", "Add sponsors and start tracking value and leads."),
265
- icon: /* @__PURE__ */ l(h, { className: "h-4 w-4" }),
266
- onClick: () => A("/sponsors")
260
+ label: t("eventfullymanaged.dashboard.nextSteps.inviteSponsors", "Onboard sponsors"),
261
+ description: t("eventfullymanaged.dashboard.nextSteps.inviteSponsorsDesc", "Add sponsors and start tracking value and leads."),
262
+ icon: /* @__PURE__ */ u(g, { className: "h-4 w-4" }),
263
+ onClick: () => k("/sponsors")
267
264
  }
268
265
  ]
269
266
  })
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../../src/eventfullymanaged/pages/dashboard/DashboardPage.tsx"],"sourcesContent":["import { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport {\n Building2,\n CalendarClock,\n CalendarDays,\n ChevronRight,\n Handshake,\n PlayCircle,\n Ticket,\n UserPlus,\n Users,\n} from 'lucide-react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n NextSteps,\n PagePurpose,\n Skeleton,\n} from '@burdenoff/fe-libs/ui';\nimport { useMemo, useState } from 'react';\n\nimport { useDashboardSummaryQuery } from '../../api/eventApi';\nimport { EventAreaChart, type AreaPoint } from '../../components/EventCharts';\nimport { PageLayout } from '../../components/PageLayout';\nimport { useEventfullyManaged } from '../../context/EventfullyManagedContext';\nimport { formatDateTime } from '../events/eventFormUtils';\n\n// ---------------------------------------------------------------------------\n// Real supporting data for the trend chart + upcoming-sessions panel. Both are\n// dedicated operations (distinct names) so they can select the exact fields the\n// dashboard needs without touching the shared list hooks.\n// ---------------------------------------------------------------------------\n\nconst DASHBOARD_REGISTRATIONS_QUERY = gql`\n query EventfullymanagedDashboardRegistrations($limit: Int) {\n registrations: eventfullyManagedRegistrations(limit: $limit, offset: 0) {\n total\n items {\n id\n status\n registeredAt\n }\n }\n }\n`;\n\nconst DASHBOARD_UPCOMING_SESSIONS_QUERY = gql`\n query EventfullymanagedDashboardUpcomingSessions($limit: Int) {\n eventSessions: eventfullyManagedEventSessions(limit: $limit, offset: 0) {\n total\n items {\n id\n eventId\n title\n sessionType\n track\n startsAt\n endsAt\n status\n }\n }\n }\n`;\n\ntype DashboardRegistration = { id: string; status: string; registeredAt: string };\ntype DashboardRegistrationsResponse = { registrations: { total: number; items: DashboardRegistration[] } };\n\ntype DashboardSession = {\n id: string;\n eventId: string;\n title: string;\n sessionType: string;\n track?: string | null;\n startsAt: string;\n endsAt: string;\n status: string;\n};\ntype DashboardSessionsResponse = { eventSessions: { total: number; items: DashboardSession[] } };\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\nconst TREND_DAYS = 30;\n\n/** Build a cumulative registrations-over-time series from real `registeredAt` timestamps. */\nfunction buildTrendSeries(registrations: DashboardRegistration[], nowMs: number): AreaPoint[] {\n const now = new Date(nowMs);\n const start = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n start.setTime(start.getTime() - (TREND_DAYS - 1) * DAY_MS);\n\n const perDay = new Array<number>(TREND_DAYS).fill(0);\n let baseline = 0; // registrations older than the window still count toward the cumulative total.\n\n for (const registration of registrations) {\n const when = new Date(registration.registeredAt);\n if (Number.isNaN(when.getTime())) {\n continue;\n }\n const dayIndex = Math.floor((when.getTime() - start.getTime()) / DAY_MS);\n if (dayIndex < 0) {\n baseline += 1;\n } else if (dayIndex < TREND_DAYS) {\n perDay[dayIndex] += 1;\n }\n }\n\n let running = baseline;\n return perDay.map((count, index) => {\n running += count;\n const day = new Date(start.getTime() + index * DAY_MS);\n return {\n label: day.toLocaleDateString(undefined, { month: 'short', day: 'numeric' }),\n value: running,\n };\n });\n}\n\ntype StatCard = {\n label: string;\n value: number;\n sublabel: string;\n icon: React.ComponentType<{ className?: string }>;\n path: string;\n featured?: boolean;\n};\n\nexport default function DashboardPage() {\n const { t: translate } = useI18n();\n const t = (key: string, fallback: string) => {\n const value = translate(key);\n return value === key ? fallback : value;\n };\n const { navigate } = useEventfullyManaged();\n const { data, loading } = useDashboardSummaryQuery();\n const { data: registrationsData, loading: registrationsLoading } = useQuery<\n DashboardRegistrationsResponse,\n { limit: number }\n >(DASHBOARD_REGISTRATIONS_QUERY, { variables: { limit: 500 } });\n const { data: sessionsData, loading: sessionsLoading } = useQuery<DashboardSessionsResponse, { limit: number }>(\n DASHBOARD_UPCOMING_SESSIONS_QUERY,\n { variables: { limit: 100 } }\n );\n\n const summary = data?.dashboardSummary;\n // Capture \"now\" once (state initialisers may run impure code) so the memoised\n // trend + upcoming filters stay pure across re-renders.\n const [nowMs] = useState(() => Date.now());\n\n const trend = useMemo(\n () => buildTrendSeries(registrationsData?.registrations?.items ?? [], nowMs),\n [registrationsData, nowMs]\n );\n\n const upcomingSessions = useMemo(() => {\n return (sessionsData?.eventSessions?.items ?? [])\n .filter((session) => {\n const startMs = new Date(session.startsAt).getTime();\n return !Number.isNaN(startMs) && startMs >= nowMs;\n })\n .sort((a, b) => new Date(a.startsAt).getTime() - new Date(b.startsAt).getTime())\n .slice(0, 4);\n }, [sessionsData, nowMs]);\n\n const cards: StatCard[] = [\n {\n label: t('eventfullymanaged.dashboard.cards.totalEvents', 'Total Events'),\n value: summary?.totalEvents ?? 0,\n sublabel: t('eventfullymanaged.dashboard.cards.totalEventsSub', 'across your workspace'),\n icon: CalendarDays,\n path: '/events',\n featured: true,\n },\n {\n label: t('eventfullymanaged.dashboard.cards.activeEvents', 'Active Events'),\n value: summary?.activeEvents ?? 0,\n sublabel: t('eventfullymanaged.dashboard.cards.activeEventsSub', 'live or published now'),\n icon: PlayCircle,\n path: '/events',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.registrations', 'Registrations'),\n value: summary?.totalRegistrations ?? 0,\n sublabel: t('eventfullymanaged.dashboard.cards.registrationsSub', 'sign-ups received'),\n icon: UserPlus,\n path: '/registration',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.attendees', 'Attendees'),\n value: summary?.totalAttendees ?? 0,\n sublabel: t('eventfullymanaged.dashboard.cards.attendeesSub', 'people in your audience'),\n icon: Users,\n path: '/registration',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.venues', 'Venues'),\n value: summary?.totalVenues ?? 0,\n sublabel: t('eventfullymanaged.dashboard.cards.venuesSub', 'spaces mapped'),\n icon: Building2,\n path: '/venues',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.sponsors', 'Sponsors'),\n value: summary?.totalSponsors ?? 0,\n sublabel: t('eventfullymanaged.dashboard.cards.sponsorsSub', 'partners onboarded'),\n icon: Handshake,\n path: '/sponsors',\n },\n ];\n\n return (\n <PageLayout\n hero\n title={<GradientText as=\"span\">{t('eventfullymanaged.dashboard.title', 'Dashboard')}</GradientText>}\n description={\n loading\n ? t('eventfullymanaged.dashboard.description.loading', 'Loading real-time event operations summary…')\n : t('eventfullymanaged.dashboard.description.ready', 'Your live event operations, at a glance.')\n }\n >\n <PagePurpose className=\"mb-6\">\n {t(\n 'eventfullymanaged.dashboard.purpose',\n 'Your event control center. Each tile below is a live count from a different part of your event operations. Open any tile to manage that area, watch registrations climb in the trend chart, and jump straight to the sessions coming up next.'\n )}\n </PagePurpose>\n\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3 xl:grid-cols-6\">\n {cards.map((card) => {\n const Icon = card.icon;\n return (\n <GlassCard\n key={card.label}\n treatment={card.featured ? 'glass' : 'metric'}\n glow={card.featured}\n role=\"button\"\n tabIndex={0}\n aria-label={`${card.label}: ${card.value.toLocaleString()}`}\n onClick={() => navigate(card.path)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n navigate(card.path);\n }\n }}\n className=\"group cursor-pointer p-4 outline-none transition-[transform,box-shadow] duration-200 hover:shadow-elevation-1 focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <span className=\"flex h-9 w-9 items-center justify-center rounded-button bg-accent-wash text-action-primary-bg\">\n <Icon className=\"h-5 w-5\" />\n </span>\n <div className=\"mt-3 text-2xl font-semibold tabular-nums text-text-primary\">\n {loading ? <Skeleton className=\"h-7 w-14\" /> : card.value.toLocaleString()}\n </div>\n <div className=\"mt-1 text-sm font-medium text-text-primary\">{card.label}</div>\n <div className=\"mt-0.5 truncate text-xs text-text-muted\">{card.sublabel}</div>\n </GlassCard>\n );\n })}\n </div>\n\n <div className=\"mt-6 grid grid-cols-1 gap-4 lg:grid-cols-5\">\n <GlassCard treatment=\"glass\" className=\"p-5 lg:col-span-3\">\n <div className=\"flex items-start justify-between gap-4\">\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {t('eventfullymanaged.dashboard.trend.title', 'Registrations over time')}\n </h2>\n <p className=\"mt-0.5 text-xs text-text-muted\">\n {t('eventfullymanaged.dashboard.trend.subtitle', 'Cumulative sign-ups, last 30 days')}\n </p>\n </div>\n <div className=\"text-2xl font-semibold tabular-nums text-text-primary\">\n {(summary?.totalRegistrations ?? 0).toLocaleString()}\n </div>\n </div>\n <div className=\"mt-4\">\n {registrationsLoading ? (\n <Skeleton className=\"h-[260px] w-full rounded-card\" />\n ) : trend.some((point) => point.value > 0) ? (\n <EventAreaChart data={trend} />\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('eventfullymanaged.dashboard.trend.empty', 'No registrations yet.')}\n description={t(\n 'eventfullymanaged.dashboard.trend.emptyHint',\n 'Once attendees start signing up, their momentum shows here.'\n )}\n className=\"py-10\"\n />\n )}\n </div>\n </GlassCard>\n\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-5 lg:col-span-2\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {t('eventfullymanaged.dashboard.upcoming.title', 'Upcoming sessions')}\n </h2>\n <div className=\"mt-3\">\n {sessionsLoading ? (\n <div className=\"space-y-3\">\n <Skeleton className=\"h-14 w-full rounded-card\" />\n <Skeleton className=\"h-14 w-full rounded-card\" />\n <Skeleton className=\"h-14 w-full rounded-card\" />\n </div>\n ) : upcomingSessions.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('eventfullymanaged.dashboard.upcoming.empty', 'Nothing scheduled yet.')}\n description={t(\n 'eventfullymanaged.dashboard.upcoming.emptyHint',\n 'Sessions you schedule will surface here as they approach.'\n )}\n className=\"py-8\"\n />\n ) : (\n <ul className=\"divide-y divide-border-subtle\">\n {upcomingSessions.map((session) => (\n <li key={session.id}>\n <button\n type=\"button\"\n onClick={() => navigate(`/events/${session.eventId}`)}\n className=\"group flex w-full items-center gap-3 py-3 text-left outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <span className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-button bg-accent-wash text-action-primary-bg\">\n <CalendarClock className=\"h-4 w-4\" />\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm font-medium text-text-primary\">{session.title}</span>\n <span className=\"mt-0.5 block truncate text-xs text-text-muted\">\n {[formatDateTime(session.startsAt), session.track].filter(Boolean).join(' • ')}\n </span>\n </span>\n <ChevronRight className=\"h-4 w-4 shrink-0 text-text-muted transition-transform group-hover:translate-x-0.5\" />\n </button>\n </li>\n ))}\n </ul>\n )}\n </div>\n </GlassCard>\n </div>\n\n <NextSteps\n className=\"mt-6\"\n storageKey=\"eventfullymanaged-dashboard\"\n title={t('eventfullymanaged.dashboard.nextSteps.title', 'Get your first event running')}\n steps={[\n {\n id: 'create-event',\n label: t('eventfullymanaged.dashboard.nextSteps.createEvent', 'Create an event'),\n description: t(\n 'eventfullymanaged.dashboard.nextSteps.createEventDesc',\n 'Start with the basics — name, dates and capacity.'\n ),\n icon: <CalendarDays className=\"h-4 w-4\" />,\n onClick: () => navigate('/events/create'),\n },\n {\n id: 'add-venue',\n label: t('eventfullymanaged.dashboard.nextSteps.addVenue', 'Add a venue'),\n description: t(\n 'eventfullymanaged.dashboard.nextSteps.addVenueDesc',\n 'Map your event to a space with capacity and floor plans.'\n ),\n icon: <Building2 className=\"h-4 w-4\" />,\n onClick: () => navigate('/venues/create'),\n },\n {\n id: 'open-registration',\n label: t('eventfullymanaged.dashboard.nextSteps.openRegistration', 'Open registration'),\n description: t(\n 'eventfullymanaged.dashboard.nextSteps.openRegistrationDesc',\n 'Set up ticket types and track attendee sign-ups.'\n ),\n icon: <Ticket className=\"h-4 w-4\" />,\n onClick: () => navigate('/registration'),\n },\n {\n id: 'invite-sponsors',\n label: t('eventfullymanaged.dashboard.nextSteps.inviteSponsors', 'Onboard sponsors'),\n description: t(\n 'eventfullymanaged.dashboard.nextSteps.inviteSponsorsDesc',\n 'Add sponsors and start tracking value and leads.'\n ),\n icon: <Handshake className=\"h-4 w-4\" />,\n onClick: () => navigate('/sponsors'),\n },\n ]}\n />\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"DashboardPage.js","names":[],"sources":["../../../../src/eventfullymanaged/pages/dashboard/DashboardPage.tsx"],"sourcesContent":["import { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport {\n Building2,\n CalendarClock,\n CalendarDays,\n ChevronRight,\n Handshake,\n PlayCircle,\n Ticket,\n UserPlus,\n Users,\n} from 'lucide-react';\nimport {\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n NextSteps,\n PagePurpose,\n Skeleton,\n} from '@burdenoff/fe-libs/ui';\nimport { useMemo, useState } from 'react';\n\nimport { useTr } from '../../../shared/hooks/useTr';\nimport { useDashboardSummaryQuery } from '../../api/eventApi';\nimport { EventAreaChart, type AreaPoint } from '../../components/EventCharts';\nimport { PageLayout } from '../../components/PageLayout';\nimport { useEventfullyManaged } from '../../context/EventfullyManagedContext';\nimport { formatDateTime } from '../events/eventFormUtils';\n\n// ---------------------------------------------------------------------------\n// Real supporting data for the trend chart + upcoming-sessions panel. Both are\n// dedicated operations (distinct names) so they can select the exact fields the\n// dashboard needs without touching the shared list hooks.\n// ---------------------------------------------------------------------------\n\nconst DASHBOARD_REGISTRATIONS_QUERY = gql`\n query EventfullymanagedDashboardRegistrations($limit: Int) {\n registrations: eventfullyManagedRegistrations(limit: $limit, offset: 0) {\n total\n items {\n id\n status\n registeredAt\n }\n }\n }\n`;\n\nconst DASHBOARD_UPCOMING_SESSIONS_QUERY = gql`\n query EventfullymanagedDashboardUpcomingSessions($limit: Int) {\n eventSessions: eventfullyManagedEventSessions(limit: $limit, offset: 0) {\n total\n items {\n id\n eventId\n title\n sessionType\n track\n startsAt\n endsAt\n status\n }\n }\n }\n`;\n\ntype DashboardRegistration = { id: string; status: string; registeredAt: string };\ntype DashboardRegistrationsResponse = { registrations: { total: number; items: DashboardRegistration[] } };\n\ntype DashboardSession = {\n id: string;\n eventId: string;\n title: string;\n sessionType: string;\n track?: string | null;\n startsAt: string;\n endsAt: string;\n status: string;\n};\ntype DashboardSessionsResponse = { eventSessions: { total: number; items: DashboardSession[] } };\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\nconst TREND_DAYS = 30;\n\n/** Build a cumulative registrations-over-time series from real `registeredAt` timestamps. */\nfunction buildTrendSeries(registrations: DashboardRegistration[], nowMs: number): AreaPoint[] {\n const now = new Date(nowMs);\n const start = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n start.setTime(start.getTime() - (TREND_DAYS - 1) * DAY_MS);\n\n const perDay = new Array<number>(TREND_DAYS).fill(0);\n let baseline = 0; // registrations older than the window still count toward the cumulative total.\n\n for (const registration of registrations) {\n const when = new Date(registration.registeredAt);\n if (Number.isNaN(when.getTime())) {\n continue;\n }\n const dayIndex = Math.floor((when.getTime() - start.getTime()) / DAY_MS);\n if (dayIndex < 0) {\n baseline += 1;\n } else if (dayIndex < TREND_DAYS) {\n perDay[dayIndex] += 1;\n }\n }\n\n let running = baseline;\n return perDay.map((count, index) => {\n running += count;\n const day = new Date(start.getTime() + index * DAY_MS);\n return {\n label: day.toLocaleDateString(undefined, { month: 'short', day: 'numeric' }),\n value: running,\n };\n });\n}\n\ntype StatCard = {\n label: string;\n value: number;\n sublabel: string;\n icon: React.ComponentType<{ className?: string }>;\n path: string;\n featured?: boolean;\n};\n\nexport default function DashboardPage() {\n const t = useTr();\n const { navigate } = useEventfullyManaged();\n const { data, loading } = useDashboardSummaryQuery();\n const { data: registrationsData, loading: registrationsLoading } = useQuery<\n DashboardRegistrationsResponse,\n { limit: number }\n >(DASHBOARD_REGISTRATIONS_QUERY, { variables: { limit: 500 } });\n const { data: sessionsData, loading: sessionsLoading } = useQuery<DashboardSessionsResponse, { limit: number }>(\n DASHBOARD_UPCOMING_SESSIONS_QUERY,\n { variables: { limit: 100 } }\n );\n\n const summary = data?.dashboardSummary;\n // Capture \"now\" once (state initialisers may run impure code) so the memoised\n // trend + upcoming filters stay pure across re-renders.\n const [nowMs] = useState(() => Date.now());\n\n const trend = useMemo(\n () => buildTrendSeries(registrationsData?.registrations?.items ?? [], nowMs),\n [registrationsData, nowMs]\n );\n\n const upcomingSessions = useMemo(() => {\n return (sessionsData?.eventSessions?.items ?? [])\n .filter((session) => {\n const startMs = new Date(session.startsAt).getTime();\n return !Number.isNaN(startMs) && startMs >= nowMs;\n })\n .sort((a, b) => new Date(a.startsAt).getTime() - new Date(b.startsAt).getTime())\n .slice(0, 4);\n }, [sessionsData, nowMs]);\n\n const cards: StatCard[] = [\n {\n label: t('eventfullymanaged.dashboard.cards.totalEvents', 'Total Events'),\n value: summary?.totalEvents ?? 0,\n sublabel: t('eventfullymanaged.dashboard.cards.totalEventsSub', 'across your workspace'),\n icon: CalendarDays,\n path: '/events',\n featured: true,\n },\n {\n label: t('eventfullymanaged.dashboard.cards.activeEvents', 'Active Events'),\n value: summary?.activeEvents ?? 0,\n sublabel: t('eventfullymanaged.dashboard.cards.activeEventsSub', 'live or published now'),\n icon: PlayCircle,\n path: '/events',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.registrations', 'Registrations'),\n value: summary?.totalRegistrations ?? 0,\n sublabel: t('eventfullymanaged.dashboard.cards.registrationsSub', 'sign-ups received'),\n icon: UserPlus,\n path: '/registration',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.attendees', 'Attendees'),\n value: summary?.totalAttendees ?? 0,\n sublabel: t('eventfullymanaged.dashboard.cards.attendeesSub', 'people in your audience'),\n icon: Users,\n path: '/registration',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.venues', 'Venues'),\n value: summary?.totalVenues ?? 0,\n sublabel: t('eventfullymanaged.dashboard.cards.venuesSub', 'spaces mapped'),\n icon: Building2,\n path: '/venues',\n },\n {\n label: t('eventfullymanaged.dashboard.cards.sponsors', 'Sponsors'),\n value: summary?.totalSponsors ?? 0,\n sublabel: t('eventfullymanaged.dashboard.cards.sponsorsSub', 'partners onboarded'),\n icon: Handshake,\n path: '/sponsors',\n },\n ];\n\n return (\n <PageLayout\n hero\n title={<GradientText as=\"span\">{t('eventfullymanaged.dashboard.title', 'Dashboard')}</GradientText>}\n description={\n loading\n ? t('eventfullymanaged.dashboard.description.loading', 'Loading real-time event operations summary…')\n : t('eventfullymanaged.dashboard.description.ready', 'Your live event operations, at a glance.')\n }\n >\n <PagePurpose className=\"mb-6\">\n {t(\n 'eventfullymanaged.dashboard.purpose',\n 'Your event control center. Each tile below is a live count from a different part of your event operations. Open any tile to manage that area, watch registrations climb in the trend chart, and jump straight to the sessions coming up next.'\n )}\n </PagePurpose>\n\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3 xl:grid-cols-6\">\n {cards.map((card) => {\n const Icon = card.icon;\n return (\n <GlassCard\n key={card.label}\n treatment={card.featured ? 'glass' : 'metric'}\n glow={card.featured}\n role=\"button\"\n tabIndex={0}\n aria-label={`${card.label}: ${card.value.toLocaleString()}`}\n onClick={() => navigate(card.path)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n navigate(card.path);\n }\n }}\n className=\"group cursor-pointer p-4 outline-none transition-[transform,box-shadow] duration-200 hover:shadow-elevation-1 focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <span className=\"flex h-9 w-9 items-center justify-center rounded-button bg-accent-wash text-action-primary-bg\">\n <Icon className=\"h-5 w-5\" />\n </span>\n <div className=\"mt-3 text-2xl font-semibold tabular-nums text-text-primary\">\n {loading ? <Skeleton className=\"h-7 w-14\" /> : card.value.toLocaleString()}\n </div>\n <div className=\"mt-1 text-sm font-medium text-text-primary\">{card.label}</div>\n <div className=\"mt-0.5 truncate text-xs text-text-muted\">{card.sublabel}</div>\n </GlassCard>\n );\n })}\n </div>\n\n <div className=\"mt-6 grid grid-cols-1 gap-4 lg:grid-cols-5\">\n <GlassCard treatment=\"glass\" className=\"p-5 lg:col-span-3\">\n <div className=\"flex items-start justify-between gap-4\">\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {t('eventfullymanaged.dashboard.trend.title', 'Registrations over time')}\n </h2>\n <p className=\"mt-0.5 text-xs text-text-muted\">\n {t('eventfullymanaged.dashboard.trend.subtitle', 'Cumulative sign-ups, last 30 days')}\n </p>\n </div>\n <div className=\"text-2xl font-semibold tabular-nums text-text-primary\">\n {(summary?.totalRegistrations ?? 0).toLocaleString()}\n </div>\n </div>\n <div className=\"mt-4\">\n {registrationsLoading ? (\n <Skeleton className=\"h-[260px] w-full rounded-card\" />\n ) : trend.some((point) => point.value > 0) ? (\n <EventAreaChart data={trend} />\n ) : (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('eventfullymanaged.dashboard.trend.empty', 'No registrations yet.')}\n description={t(\n 'eventfullymanaged.dashboard.trend.emptyHint',\n 'Once attendees start signing up, their momentum shows here.'\n )}\n className=\"py-10\"\n />\n )}\n </div>\n </GlassCard>\n\n <GlassCard treatment=\"plain\" className=\"border-border-seam p-5 lg:col-span-2\">\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {t('eventfullymanaged.dashboard.upcoming.title', 'Upcoming sessions')}\n </h2>\n <div className=\"mt-3\">\n {sessionsLoading ? (\n <div className=\"space-y-3\">\n <Skeleton className=\"h-14 w-full rounded-card\" />\n <Skeleton className=\"h-14 w-full rounded-card\" />\n <Skeleton className=\"h-14 w-full rounded-card\" />\n </div>\n ) : upcomingSessions.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={t('eventfullymanaged.dashboard.upcoming.empty', 'Nothing scheduled yet.')}\n description={t(\n 'eventfullymanaged.dashboard.upcoming.emptyHint',\n 'Sessions you schedule will surface here as they approach.'\n )}\n className=\"py-8\"\n />\n ) : (\n <ul className=\"divide-y divide-border-subtle\">\n {upcomingSessions.map((session) => (\n <li key={session.id}>\n <button\n type=\"button\"\n onClick={() => navigate(`/events/${session.eventId}`)}\n className=\"group flex w-full items-center gap-3 py-3 text-left outline-none focus-visible:ring-1 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <span className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-button bg-accent-wash text-action-primary-bg\">\n <CalendarClock className=\"h-4 w-4\" />\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-sm font-medium text-text-primary\">{session.title}</span>\n <span className=\"mt-0.5 block truncate text-xs text-text-muted\">\n {[formatDateTime(session.startsAt), session.track].filter(Boolean).join(' • ')}\n </span>\n </span>\n <ChevronRight className=\"h-4 w-4 shrink-0 text-text-muted transition-transform group-hover:translate-x-0.5\" />\n </button>\n </li>\n ))}\n </ul>\n )}\n </div>\n </GlassCard>\n </div>\n\n <NextSteps\n className=\"mt-6\"\n storageKey=\"eventfullymanaged-dashboard\"\n title={t('eventfullymanaged.dashboard.nextSteps.title', 'Get your first event running')}\n steps={[\n {\n id: 'create-event',\n label: t('eventfullymanaged.dashboard.nextSteps.createEvent', 'Create an event'),\n description: t(\n 'eventfullymanaged.dashboard.nextSteps.createEventDesc',\n 'Start with the basics — name, dates and capacity.'\n ),\n icon: <CalendarDays className=\"h-4 w-4\" />,\n onClick: () => navigate('/events/create'),\n },\n {\n id: 'add-venue',\n label: t('eventfullymanaged.dashboard.nextSteps.addVenue', 'Add a venue'),\n description: t(\n 'eventfullymanaged.dashboard.nextSteps.addVenueDesc',\n 'Map your event to a space with capacity and floor plans.'\n ),\n icon: <Building2 className=\"h-4 w-4\" />,\n onClick: () => navigate('/venues/create'),\n },\n {\n id: 'open-registration',\n label: t('eventfullymanaged.dashboard.nextSteps.openRegistration', 'Open registration'),\n description: t(\n 'eventfullymanaged.dashboard.nextSteps.openRegistrationDesc',\n 'Set up ticket types and track attendee sign-ups.'\n ),\n icon: <Ticket className=\"h-4 w-4\" />,\n onClick: () => navigate('/registration'),\n },\n {\n id: 'invite-sponsors',\n label: t('eventfullymanaged.dashboard.nextSteps.inviteSponsors', 'Onboard sponsors'),\n description: t(\n 'eventfullymanaged.dashboard.nextSteps.inviteSponsorsDesc',\n 'Add sponsors and start tracking value and leads.'\n ),\n icon: <Handshake className=\"h-4 w-4\" />,\n onClick: () => navigate('/sponsors'),\n },\n ]}\n />\n </PageLayout>\n );\n}\n"],"mappings":"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"}