@burdenoff/microfe-admin 2026.625.1 → 2026.626.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 (70) hide show
  1. package/dist/admin/components/AccessDenied.js +2 -2
  2. package/dist/admin/components/AccessDenied.js.map +1 -1
  3. package/dist/admin/components/ActivityFeed.js +4 -4
  4. package/dist/admin/components/ActivityFeed.js.map +1 -1
  5. package/dist/admin/components/Charts.js.map +1 -1
  6. package/dist/admin/components/ConfirmDialog.js +1 -1
  7. package/dist/admin/components/ConfirmDialog.js.map +1 -1
  8. package/dist/admin/components/FormSheet.js +1 -1
  9. package/dist/admin/components/FormSheet.js.map +1 -1
  10. package/dist/admin/components/TenantSsoPanel.js +1 -1
  11. package/dist/admin/components/TenantSsoPanel.js.map +1 -1
  12. package/dist/admin/components/Toast.js +11 -11
  13. package/dist/admin/components/Toast.js.map +1 -1
  14. package/dist/admin/components/forms/SubscriptionForm.js +2 -2
  15. package/dist/admin/components/forms/SubscriptionForm.js.map +1 -1
  16. package/dist/admin/components/forms/TenantForm.js +1 -1
  17. package/dist/admin/components/forms/UserForm.js +1 -1
  18. package/dist/admin/components/ui.js +3 -3
  19. package/dist/admin/components/ui.js.map +1 -1
  20. package/dist/admin/constants/index.js +33 -24
  21. package/dist/admin/constants/index.js.map +1 -1
  22. package/dist/admin/pages/AuditLogsPage.js +92 -77
  23. package/dist/admin/pages/AuditLogsPage.js.map +1 -1
  24. package/dist/admin/pages/BillingPage.js +95 -51
  25. package/dist/admin/pages/BillingPage.js.map +1 -1
  26. package/dist/admin/pages/CommunicationsPage.js +97 -92
  27. package/dist/admin/pages/CommunicationsPage.js.map +1 -1
  28. package/dist/admin/pages/ContentPagesPage.js +274 -259
  29. package/dist/admin/pages/ContentPagesPage.js.map +1 -1
  30. package/dist/admin/pages/DashboardPage.js +113 -84
  31. package/dist/admin/pages/DashboardPage.js.map +1 -1
  32. package/dist/admin/pages/FeatureFlagsPage.js +93 -75
  33. package/dist/admin/pages/FeatureFlagsPage.js.map +1 -1
  34. package/dist/admin/pages/OrganizationsListPage.js +105 -87
  35. package/dist/admin/pages/OrganizationsListPage.js.map +1 -1
  36. package/dist/admin/pages/ProductsPage.js +138 -130
  37. package/dist/admin/pages/ProductsPage.js.map +1 -1
  38. package/dist/admin/pages/ReferralsPage.js +70 -52
  39. package/dist/admin/pages/ReferralsPage.js.map +1 -1
  40. package/dist/admin/pages/RolesPermissionsPage.js +136 -118
  41. package/dist/admin/pages/RolesPermissionsPage.js.map +1 -1
  42. package/dist/admin/pages/SREPage.js +34 -32
  43. package/dist/admin/pages/SREPage.js.map +1 -1
  44. package/dist/admin/pages/SandboxSettingsPage.js +360 -322
  45. package/dist/admin/pages/SandboxSettingsPage.js.map +1 -1
  46. package/dist/admin/pages/SettingsPage.js +63 -60
  47. package/dist/admin/pages/SettingsPage.js.map +1 -1
  48. package/dist/admin/pages/SyncFailuresPage.js +120 -118
  49. package/dist/admin/pages/SyncFailuresPage.js.map +1 -1
  50. package/dist/admin/pages/TenantDetailPage.js +261 -218
  51. package/dist/admin/pages/TenantDetailPage.js.map +1 -1
  52. package/dist/admin/pages/TenantFormRoutePage.js +65 -61
  53. package/dist/admin/pages/TenantFormRoutePage.js.map +1 -1
  54. package/dist/admin/pages/TenantsListPage.js +86 -71
  55. package/dist/admin/pages/TenantsListPage.js.map +1 -1
  56. package/dist/admin/pages/UsersListPage.js +128 -113
  57. package/dist/admin/pages/UsersListPage.js.map +1 -1
  58. package/dist/admin/pages/WaitlistPage.js +78 -63
  59. package/dist/admin/pages/WaitlistPage.js.map +1 -1
  60. package/dist/admin/pages/WorkflowsPage.js +107 -102
  61. package/dist/admin/pages/WorkflowsPage.js.map +1 -1
  62. package/dist/admin/pages/WorkspacesListPage.js +61 -49
  63. package/dist/admin/pages/WorkspacesListPage.js.map +1 -1
  64. package/dist/node_modules/@hookform/resolvers/dist/resolvers.js +2 -2
  65. package/dist/node_modules/@hookform/resolvers/dist/resolvers.js.map +1 -1
  66. package/dist/node_modules/@hookform/resolvers/zod/dist/zod.js +35 -26
  67. package/dist/node_modules/@hookform/resolvers/zod/dist/zod.js.map +1 -1
  68. package/dist/node_modules/react-hook-form/dist/index.esm.js +609 -516
  69. package/dist/node_modules/react-hook-form/dist/index.esm.js.map +1 -1
  70. package/package.json +2 -2
@@ -1,76 +1,100 @@
1
- import { Badge as e } from "../components/ui.js";
2
- import { PageLayout as t } from "../components/PageLayout.js";
3
- import { formatCurrency as n, formatDateTime as r } from "../utils/formatters.js";
4
- import { MetricCard as i, MetricsGrid as a } from "../components/MetricCard.js";
5
- import { DataTable as o } from "../components/DataTable.js";
1
+ import { Badge as e, EmptyState as t } from "../components/ui.js";
2
+ import { PageLayout as n } from "../components/PageLayout.js";
3
+ import { formatCurrency as r, formatDateTime as i } from "../utils/formatters.js";
4
+ import { MetricCard as a, MetricsGrid as o } from "../components/MetricCard.js";
5
+ import { DataTable as s } from "../components/DataTable.js";
6
6
  import "../components/index.js";
7
- import { useListAllPlansQuery as s, useListAllQuotasQuery as c, useListRefundRecordsQuery as l } from "../../generated/global-operations.js";
8
- import { ArrowUpRight as u, CreditCard as d, Download as f, Plus as p, Receipt as m, Shield as h } from "lucide-react";
9
- import { jsx as g, jsxs as _ } from "react/jsx-runtime";
10
- import { CTAOverflowMenu as v } from "@burdenoff/fe-libs/ui";
7
+ import { useListAllPlansQuery as c, useListAllQuotasQuery as l, useListRefundRecordsQuery as u } from "../../generated/global-operations.js";
8
+ import { ArrowUpRight as d, CreditCard as f, Download as p, Plus as m, Receipt as h, Shield as g } from "lucide-react";
9
+ import { jsx as _, jsxs as v } from "react/jsx-runtime";
10
+ import { CTAOverflowMenu as y, NextSteps as b, PagePurpose as x } from "@burdenoff/fe-libs/ui";
11
11
  //#region src/admin/pages/BillingPage.tsx
12
- function y() {
13
- let { data: y, loading: b } = s(), { data: x, loading: S } = c(), { data: C, loading: w } = l({ variables: {
12
+ function S() {
13
+ let { data: S, loading: C } = c(), { data: w, loading: T } = l(), { data: E, loading: D } = u({ variables: {
14
14
  page: 1,
15
15
  pageSize: 10
16
- } }), T = y?.getAllPlans || [], E = x?.getAllQuotas || [], D = C?.getRefundRecords?.records || [];
17
- return /* @__PURE__ */ g(t, {
16
+ } }), O = S?.getAllPlans || [], k = w?.getAllQuotas || [], A = E?.getRefundRecords?.records || [];
17
+ return /* @__PURE__ */ _(n, {
18
18
  title: "Billing & Subscriptions",
19
19
  gradientWord: "Subscriptions",
20
20
  description: "Manage platform-wide plans, quotas, and refunds",
21
- actions: /* @__PURE__ */ g(v, {
21
+ actions: /* @__PURE__ */ _(y, {
22
22
  primary: {
23
23
  label: "Create Plan",
24
- icon: /* @__PURE__ */ g(p, { className: "mr-2 h-4 w-4" }),
24
+ icon: /* @__PURE__ */ _(m, { className: "mr-2 h-4 w-4" }),
25
25
  onSelect: () => {}
26
26
  },
27
27
  actions: [{
28
28
  label: "Export Audit",
29
- icon: /* @__PURE__ */ g(f, { className: "h-4 w-4" }),
29
+ icon: /* @__PURE__ */ _(p, { className: "h-4 w-4" }),
30
30
  onSelect: () => {}
31
31
  }]
32
32
  }),
33
- children: /* @__PURE__ */ _("div", {
33
+ children: /* @__PURE__ */ v("div", {
34
34
  className: "space-y-8",
35
35
  children: [
36
- /* @__PURE__ */ _(a, { children: [
37
- /* @__PURE__ */ g(i, {
36
+ /* @__PURE__ */ _(x, { children: "The money side of the platform in one place. Define the plans customers can buy, set the resource quotas each plan grants, and review refunds — so you can launch a new pricing tier or resolve a billing dispute without leaving the console." }),
37
+ /* @__PURE__ */ _(b, {
38
+ storageKey: "admin-billing",
39
+ steps: [
40
+ {
41
+ id: "create-plan",
42
+ label: "Create a plan",
43
+ description: "Define a new pricing tier customers can subscribe to.",
44
+ onClick: () => {}
45
+ },
46
+ {
47
+ id: "review-refunds",
48
+ label: "Review pending refunds",
49
+ description: "Approve or investigate refunds awaiting a decision.",
50
+ href: "#refunds"
51
+ },
52
+ {
53
+ id: "check-quotas",
54
+ label: "Check resource quotas",
55
+ description: "Make sure each plan grants the limits you intend.",
56
+ href: "#quotas"
57
+ }
58
+ ]
59
+ }),
60
+ /* @__PURE__ */ v(o, { children: [
61
+ /* @__PURE__ */ _(a, {
38
62
  title: "Total Revenue (30d)",
39
63
  hero: !0,
40
64
  value: "$124,500",
41
- icon: /* @__PURE__ */ g(d, { className: "h-4 w-4" }),
65
+ icon: /* @__PURE__ */ _(f, { className: "h-4 w-4" }),
42
66
  trend: "up"
43
67
  }),
44
- /* @__PURE__ */ g(i, {
68
+ /* @__PURE__ */ _(a, {
45
69
  title: "Active Subscriptions",
46
70
  value: "1,248",
47
- icon: /* @__PURE__ */ g(h, { className: "h-4 w-4" })
71
+ icon: /* @__PURE__ */ _(g, { className: "h-4 w-4" })
48
72
  }),
49
- /* @__PURE__ */ g(i, {
73
+ /* @__PURE__ */ _(a, {
50
74
  title: "Pending Refunds",
51
- value: C?.getRefundRecords?.totalCount ?? 0,
52
- icon: /* @__PURE__ */ g(u, { className: "h-4 w-4" }),
75
+ value: E?.getRefundRecords?.totalCount ?? 0,
76
+ icon: /* @__PURE__ */ _(d, { className: "h-4 w-4" }),
53
77
  priority: "high"
54
78
  }),
55
- /* @__PURE__ */ g(i, {
79
+ /* @__PURE__ */ _(a, {
56
80
  title: "Upcoming Invoices",
57
81
  value: "42",
58
- icon: /* @__PURE__ */ g(m, { className: "h-4 w-4" })
82
+ icon: /* @__PURE__ */ _(h, { className: "h-4 w-4" })
59
83
  })
60
84
  ] }),
61
- /* @__PURE__ */ _("div", {
85
+ /* @__PURE__ */ v("div", {
62
86
  className: "grid gap-8 lg:grid-cols-2",
63
- children: [/* @__PURE__ */ _("div", {
87
+ children: [/* @__PURE__ */ v("div", {
64
88
  className: "space-y-4",
65
- children: [/* @__PURE__ */ g("h2", {
89
+ children: [/* @__PURE__ */ _("h2", {
66
90
  className: "text-lg font-semibold",
67
91
  children: "Platform Plans"
68
- }), /* @__PURE__ */ g(o, {
92
+ }), /* @__PURE__ */ _(s, {
69
93
  columns: [
70
94
  {
71
95
  key: "name",
72
96
  header: "Plan Name",
73
- render: (e) => /* @__PURE__ */ g("span", {
97
+ render: (e) => /* @__PURE__ */ _("span", {
74
98
  className: "font-medium",
75
99
  children: e.name
76
100
  })
@@ -78,7 +102,7 @@ function y() {
78
102
  {
79
103
  key: "price",
80
104
  header: "Price",
81
- render: (e) => n(e.price, e.currency)
105
+ render: (e) => r(e.price, e.currency)
82
106
  },
83
107
  {
84
108
  key: "duration",
@@ -87,22 +111,29 @@ function y() {
87
111
  {
88
112
  key: "isActive",
89
113
  header: "Status",
90
- render: (t) => /* @__PURE__ */ g(e, {
114
+ render: (t) => /* @__PURE__ */ _(e, {
91
115
  variant: t.isActive ? "success" : "secondary",
92
116
  children: t.isActive ? "Active" : "Inactive"
93
117
  })
94
118
  }
95
119
  ],
96
- data: T,
120
+ data: O,
97
121
  keyExtractor: (e) => e.id,
98
- loading: b
122
+ loading: C,
123
+ emptyState: /* @__PURE__ */ _(t, {
124
+ illustration: "empty-data",
125
+ icon: /* @__PURE__ */ _(f, { className: "h-8 w-8" }),
126
+ title: "No plans yet",
127
+ description: "Create your first pricing plan to let customers subscribe."
128
+ })
99
129
  })]
100
- }), /* @__PURE__ */ _("div", {
130
+ }), /* @__PURE__ */ v("div", {
131
+ id: "quotas",
101
132
  className: "space-y-4",
102
- children: [/* @__PURE__ */ g("h2", {
133
+ children: [/* @__PURE__ */ _("h2", {
103
134
  className: "text-lg font-semibold",
104
135
  children: "Resource Quotas"
105
- }), /* @__PURE__ */ g(o, {
136
+ }), /* @__PURE__ */ _(s, {
106
137
  columns: [
107
138
  {
108
139
  key: "name",
@@ -115,34 +146,41 @@ function y() {
115
146
  {
116
147
  key: "isActive",
117
148
  header: "Status",
118
- render: (t) => /* @__PURE__ */ g(e, {
149
+ render: (t) => /* @__PURE__ */ _(e, {
119
150
  variant: t.isActive ? "success" : "secondary",
120
151
  children: t.isActive ? "Active" : "Inactive"
121
152
  })
122
153
  }
123
154
  ],
124
- data: E,
155
+ data: k,
125
156
  keyExtractor: (e) => e.id,
126
- loading: S
157
+ loading: T,
158
+ emptyState: /* @__PURE__ */ _(t, {
159
+ illustration: "empty-data",
160
+ icon: /* @__PURE__ */ _(g, { className: "h-8 w-8" }),
161
+ title: "No quotas defined",
162
+ description: "Resource quotas you create will appear here."
163
+ })
127
164
  })]
128
165
  })]
129
166
  }),
130
- /* @__PURE__ */ _("div", {
167
+ /* @__PURE__ */ v("div", {
168
+ id: "refunds",
131
169
  className: "space-y-4",
132
- children: [/* @__PURE__ */ g("h2", {
170
+ children: [/* @__PURE__ */ _("h2", {
133
171
  className: "text-lg font-semibold",
134
172
  children: "Recent Refund Records"
135
- }), /* @__PURE__ */ g(o, {
173
+ }), /* @__PURE__ */ _(s, {
136
174
  columns: [
137
175
  {
138
176
  key: "amount",
139
177
  header: "Amount",
140
- render: (e) => n(e.amount, e.currency)
178
+ render: (e) => r(e.amount, e.currency)
141
179
  },
142
180
  {
143
181
  key: "status",
144
182
  header: "Status",
145
- render: (t) => /* @__PURE__ */ g(e, {
183
+ render: (t) => /* @__PURE__ */ _(e, {
146
184
  variant: t.status === "COMPLETED" ? "success" : "warning",
147
185
  children: t.status
148
186
  })
@@ -154,12 +192,18 @@ function y() {
154
192
  {
155
193
  key: "createdAt",
156
194
  header: "Date",
157
- render: (e) => r(e.createdAt)
195
+ render: (e) => i(e.createdAt)
158
196
  }
159
197
  ],
160
- data: D,
198
+ data: A,
161
199
  keyExtractor: (e) => e.id,
162
- loading: w
200
+ loading: D,
201
+ emptyState: /* @__PURE__ */ _(t, {
202
+ illustration: "empty-generic",
203
+ icon: /* @__PURE__ */ _(h, { className: "h-8 w-8" }),
204
+ title: "No refunds recorded",
205
+ description: "Refund activity will show up here as it happens."
206
+ })
163
207
  })]
164
208
  })
165
209
  ]
@@ -167,6 +211,6 @@ function y() {
167
211
  });
168
212
  }
169
213
  //#endregion
170
- export { y as BillingPage };
214
+ export { S as BillingPage };
171
215
 
172
216
  //# sourceMappingURL=BillingPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"BillingPage.js","names":[],"sources":["../../../src/admin/pages/BillingPage.tsx"],"sourcesContent":["import { CreditCard, Plus, ArrowUpRight, Shield, Receipt, Download } from 'lucide-react';\nimport { CTAOverflowMenu } from '@burdenoff/fe-libs/ui';\nimport { PageLayout, DataTable, Badge, MetricCard, MetricsGrid } from '../components';\nimport {\n useListAllPlansQuery,\n useListAllQuotasQuery,\n useListRefundRecordsQuery,\n} from '../../generated/global-operations';\nimport { formatCurrency, formatDateTime } from '../utils/formatters';\n\nexport function BillingPage() {\n const { data: plansData, loading: plansLoading } = useListAllPlansQuery();\n const { data: quotasData, loading: quotasLoading } = useListAllQuotasQuery();\n const { data: refundsData, loading: refundsLoading } = useListRefundRecordsQuery({\n variables: { page: 1, pageSize: 10 },\n });\n\n const plans = plansData?.getAllPlans || [];\n const quotas = quotasData?.getAllQuotas || [];\n const refunds = refundsData?.getRefundRecords?.records || [];\n\n const planColumns = [\n {\n key: 'name',\n header: 'Plan Name',\n render: (plan: any) => <span className=\"font-medium\">{plan.name}</span>,\n },\n {\n key: 'price',\n header: 'Price',\n render: (plan: any) => formatCurrency(plan.price, plan.currency),\n },\n {\n key: 'duration',\n header: 'Interval',\n },\n {\n key: 'isActive',\n header: 'Status',\n render: (plan: any) => (\n <Badge variant={plan.isActive ? 'success' : 'secondary'}>\n {plan.isActive ? 'Active' : 'Inactive'}\n </Badge>\n ),\n },\n ];\n\n const quotaColumns = [\n {\n key: 'name',\n header: 'Quota Name',\n },\n {\n key: 'quotaType',\n header: 'Metric Type',\n },\n {\n key: 'isActive',\n header: 'Status',\n render: (quota: any) => (\n <Badge variant={quota.isActive ? 'success' : 'secondary'}>\n {quota.isActive ? 'Active' : 'Inactive'}\n </Badge>\n ),\n },\n ];\n\n const refundColumns = [\n {\n key: 'amount',\n header: 'Amount',\n render: (refund: any) => formatCurrency(refund.amount, refund.currency),\n },\n {\n key: 'status',\n header: 'Status',\n render: (refund: any) => (\n <Badge variant={refund.status === 'COMPLETED' ? 'success' : 'warning'}>\n {refund.status}\n </Badge>\n ),\n },\n {\n key: 'reason',\n header: 'Reason',\n },\n {\n key: 'createdAt',\n header: 'Date',\n render: (refund: any) => formatDateTime(refund.createdAt),\n },\n ];\n\n return (\n <PageLayout\n title=\"Billing & Subscriptions\"\n gradientWord=\"Subscriptions\"\n description=\"Manage platform-wide plans, quotas, and refunds\"\n actions={\n <CTAOverflowMenu\n primary={{\n label: 'Create Plan',\n icon: <Plus className=\"mr-2 h-4 w-4\" />,\n onSelect: () => {},\n }}\n actions={[\n {\n label: 'Export Audit',\n icon: <Download className=\"h-4 w-4\" />,\n onSelect: () => {},\n },\n ]}\n />\n }\n >\n <div className=\"space-y-8\">\n <MetricsGrid>\n <MetricCard\n title=\"Total Revenue (30d)\"\n hero\n value=\"$124,500\"\n icon={<CreditCard className=\"h-4 w-4\" />}\n trend=\"up\"\n />\n <MetricCard\n title=\"Active Subscriptions\"\n value=\"1,248\"\n icon={<Shield className=\"h-4 w-4\" />}\n />\n <MetricCard\n title=\"Pending Refunds\"\n value={refundsData?.getRefundRecords?.totalCount ?? 0}\n icon={<ArrowUpRight className=\"h-4 w-4\" />}\n priority=\"high\"\n />\n <MetricCard title=\"Upcoming Invoices\" value=\"42\" icon={<Receipt className=\"h-4 w-4\" />} />\n </MetricsGrid>\n\n <div className=\"grid gap-8 lg:grid-cols-2\">\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-semibold\">Platform Plans</h2>\n <DataTable\n columns={planColumns}\n data={plans}\n keyExtractor={(p) => p.id}\n loading={plansLoading}\n />\n </div>\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-semibold\">Resource Quotas</h2>\n <DataTable\n columns={quotaColumns}\n data={quotas}\n keyExtractor={(q) => q.id}\n loading={quotasLoading}\n />\n </div>\n </div>\n\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-semibold\">Recent Refund Records</h2>\n <DataTable\n columns={refundColumns}\n data={refunds}\n keyExtractor={(r) => r.id}\n loading={refundsLoading}\n />\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"BillingPage.js","names":[],"sources":["../../../src/admin/pages/BillingPage.tsx"],"sourcesContent":["import { CreditCard, Plus, ArrowUpRight, Shield, Receipt, Download } from 'lucide-react';\nimport { CTAOverflowMenu, PagePurpose, NextSteps } from '@burdenoff/fe-libs/ui';\nimport { PageLayout, DataTable, Badge, MetricCard, MetricsGrid, EmptyState } from '../components';\nimport {\n useListAllPlansQuery,\n useListAllQuotasQuery,\n useListRefundRecordsQuery,\n} from '../../generated/global-operations';\nimport { formatCurrency, formatDateTime } from '../utils/formatters';\n\nexport function BillingPage() {\n const { data: plansData, loading: plansLoading } = useListAllPlansQuery();\n const { data: quotasData, loading: quotasLoading } = useListAllQuotasQuery();\n const { data: refundsData, loading: refundsLoading } = useListRefundRecordsQuery({\n variables: { page: 1, pageSize: 10 },\n });\n\n const plans = plansData?.getAllPlans || [];\n const quotas = quotasData?.getAllQuotas || [];\n const refunds = refundsData?.getRefundRecords?.records || [];\n\n const planColumns = [\n {\n key: 'name',\n header: 'Plan Name',\n render: (plan: any) => <span className=\"font-medium\">{plan.name}</span>,\n },\n {\n key: 'price',\n header: 'Price',\n render: (plan: any) => formatCurrency(plan.price, plan.currency),\n },\n {\n key: 'duration',\n header: 'Interval',\n },\n {\n key: 'isActive',\n header: 'Status',\n render: (plan: any) => (\n <Badge variant={plan.isActive ? 'success' : 'secondary'}>\n {plan.isActive ? 'Active' : 'Inactive'}\n </Badge>\n ),\n },\n ];\n\n const quotaColumns = [\n {\n key: 'name',\n header: 'Quota Name',\n },\n {\n key: 'quotaType',\n header: 'Metric Type',\n },\n {\n key: 'isActive',\n header: 'Status',\n render: (quota: any) => (\n <Badge variant={quota.isActive ? 'success' : 'secondary'}>\n {quota.isActive ? 'Active' : 'Inactive'}\n </Badge>\n ),\n },\n ];\n\n const refundColumns = [\n {\n key: 'amount',\n header: 'Amount',\n render: (refund: any) => formatCurrency(refund.amount, refund.currency),\n },\n {\n key: 'status',\n header: 'Status',\n render: (refund: any) => (\n <Badge variant={refund.status === 'COMPLETED' ? 'success' : 'warning'}>\n {refund.status}\n </Badge>\n ),\n },\n {\n key: 'reason',\n header: 'Reason',\n },\n {\n key: 'createdAt',\n header: 'Date',\n render: (refund: any) => formatDateTime(refund.createdAt),\n },\n ];\n\n return (\n <PageLayout\n title=\"Billing & Subscriptions\"\n gradientWord=\"Subscriptions\"\n description=\"Manage platform-wide plans, quotas, and refunds\"\n actions={\n <CTAOverflowMenu\n primary={{\n label: 'Create Plan',\n icon: <Plus className=\"mr-2 h-4 w-4\" />,\n onSelect: () => {},\n }}\n actions={[\n {\n label: 'Export Audit',\n icon: <Download className=\"h-4 w-4\" />,\n onSelect: () => {},\n },\n ]}\n />\n }\n >\n <div className=\"space-y-8\">\n <PagePurpose>\n The money side of the platform in one place. Define the plans customers can buy, set the\n resource quotas each plan grants, and review refunds — so you can launch a new pricing\n tier or resolve a billing dispute without leaving the console.\n </PagePurpose>\n\n <NextSteps\n storageKey=\"admin-billing\"\n steps={[\n {\n id: 'create-plan',\n label: 'Create a plan',\n description: 'Define a new pricing tier customers can subscribe to.',\n onClick: () => {},\n },\n {\n id: 'review-refunds',\n label: 'Review pending refunds',\n description: 'Approve or investigate refunds awaiting a decision.',\n href: '#refunds',\n },\n {\n id: 'check-quotas',\n label: 'Check resource quotas',\n description: 'Make sure each plan grants the limits you intend.',\n href: '#quotas',\n },\n ]}\n />\n\n <MetricsGrid>\n <MetricCard\n title=\"Total Revenue (30d)\"\n hero\n value=\"$124,500\"\n icon={<CreditCard className=\"h-4 w-4\" />}\n trend=\"up\"\n />\n <MetricCard\n title=\"Active Subscriptions\"\n value=\"1,248\"\n icon={<Shield className=\"h-4 w-4\" />}\n />\n <MetricCard\n title=\"Pending Refunds\"\n value={refundsData?.getRefundRecords?.totalCount ?? 0}\n icon={<ArrowUpRight className=\"h-4 w-4\" />}\n priority=\"high\"\n />\n <MetricCard title=\"Upcoming Invoices\" value=\"42\" icon={<Receipt className=\"h-4 w-4\" />} />\n </MetricsGrid>\n\n <div className=\"grid gap-8 lg:grid-cols-2\">\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-semibold\">Platform Plans</h2>\n <DataTable\n columns={planColumns}\n data={plans}\n keyExtractor={(p) => p.id}\n loading={plansLoading}\n emptyState={\n <EmptyState\n illustration=\"empty-data\"\n icon={<CreditCard className=\"h-8 w-8\" />}\n title=\"No plans yet\"\n description=\"Create your first pricing plan to let customers subscribe.\"\n />\n }\n />\n </div>\n <div id=\"quotas\" className=\"space-y-4\">\n <h2 className=\"text-lg font-semibold\">Resource Quotas</h2>\n <DataTable\n columns={quotaColumns}\n data={quotas}\n keyExtractor={(q) => q.id}\n loading={quotasLoading}\n emptyState={\n <EmptyState\n illustration=\"empty-data\"\n icon={<Shield className=\"h-8 w-8\" />}\n title=\"No quotas defined\"\n description=\"Resource quotas you create will appear here.\"\n />\n }\n />\n </div>\n </div>\n\n <div id=\"refunds\" className=\"space-y-4\">\n <h2 className=\"text-lg font-semibold\">Recent Refund Records</h2>\n <DataTable\n columns={refundColumns}\n data={refunds}\n keyExtractor={(r) => r.id}\n loading={refundsLoading}\n emptyState={\n <EmptyState\n illustration=\"empty-generic\"\n icon={<Receipt className=\"h-8 w-8\" />}\n title=\"No refunds recorded\"\n description=\"Refund activity will show up here as it happens.\"\n />\n }\n />\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -7,11 +7,12 @@ import "../components/index.js";
7
7
  import { useGetNewsletterStatsQuery as l, useListNewslettersQuery as u, useSendNewsletterMutation as d } from "../../generated/global-operations.js";
8
8
  import { Eye as f, Mail as p, MousePointer2 as m, Plus as h, Send as g, Users as _ } from "lucide-react";
9
9
  import { jsx as v, jsxs as y } from "react/jsx-runtime";
10
+ import { PagePurpose as b } from "@burdenoff/fe-libs/ui";
10
11
  //#region src/admin/pages/CommunicationsPage.tsx
11
- function b() {
12
- let { data: b, loading: x } = l(), { data: S, loading: C, refetch: w } = u({ variables: { limit: 50 } }), [T] = d(), E = b?.newsletterStats, D = S?.newsletters || [], O = async (e) => {
12
+ function x() {
13
+ let { data: x, loading: S } = l(), { data: C, loading: w, refetch: T } = u({ variables: { limit: 50 } }), [E] = d(), D = x?.newsletterStats, O = C?.newsletters || [], k = async (e) => {
13
14
  if (confirm("Are you sure you want to send this newsletter to all subscribers?")) try {
14
- await T({ variables: { id: e } }), w();
15
+ await E({ variables: { id: e } }), T();
15
16
  } catch (e) {
16
17
  console.error("Failed to send newsletter:", e);
17
18
  }
@@ -23,99 +24,103 @@ function b() {
23
24
  actions: /* @__PURE__ */ y(t, { children: [/* @__PURE__ */ v(h, { className: "mr-2 h-4 w-4" }), "Create Newsletter"] }),
24
25
  children: /* @__PURE__ */ y("div", {
25
26
  className: "space-y-8",
26
- children: [/* @__PURE__ */ y(s, { children: [
27
- /* @__PURE__ */ v(o, {
28
- title: "Total Subscribers",
29
- hero: !0,
30
- value: E?.totalSubscribers ?? 0,
31
- loading: x,
32
- icon: /* @__PURE__ */ v(_, { className: "h-4 w-4" })
33
- }),
34
- /* @__PURE__ */ v(o, {
35
- title: "Newsletters Sent",
36
- value: E?.totalSent ?? 0,
37
- loading: x,
38
- icon: /* @__PURE__ */ v(g, { className: "h-4 w-4" })
39
- }),
40
- /* @__PURE__ */ v(o, {
41
- title: "Avg. Open Rate",
42
- value: a(E?.averageOpenRate ?? 0),
43
- loading: x,
44
- icon: /* @__PURE__ */ v(f, { className: "h-4 w-4" })
45
- }),
46
- /* @__PURE__ */ v(o, {
47
- title: "Avg. Click Rate",
48
- value: a(E?.averageClickRate ?? 0),
49
- loading: x,
50
- icon: /* @__PURE__ */ v(m, { className: "h-4 w-4" })
51
- })
52
- ] }), /* @__PURE__ */ y("div", {
53
- className: "space-y-4",
54
- children: [/* @__PURE__ */ v("h2", {
55
- className: "text-lg font-semibold",
56
- children: "Newsletters"
57
- }), /* @__PURE__ */ v(c, {
58
- columns: [
59
- {
60
- key: "title",
61
- header: "Title",
62
- render: (e) => /* @__PURE__ */ y("div", {
63
- className: "flex flex-col",
64
- children: [/* @__PURE__ */ v("span", {
65
- className: "font-medium text-text-primary",
66
- children: e.title
67
- }), /* @__PURE__ */ v("span", {
68
- className: "text-xs text-text-secondary",
69
- children: e.subject
70
- })]
71
- })
72
- },
73
- {
74
- key: "status",
75
- header: "Status",
76
- render: (t) => /* @__PURE__ */ v(e, {
77
- variant: {
78
- SENT: "success",
79
- SCHEDULED: "warning",
80
- DRAFT: "secondary"
81
- }[t.status] || "outline",
82
- children: t.status
83
- })
84
- },
85
- {
86
- key: "sentAt",
87
- header: "Sent Date",
88
- render: (e) => e.sentAt ? i(e.sentAt) : "-"
89
- },
90
- {
91
- key: "actions",
92
- header: "",
93
- align: "right",
94
- render: (e) => /* @__PURE__ */ v("div", {
95
- className: "flex justify-end gap-2",
96
- children: e.status === "DRAFT" && /* @__PURE__ */ y(t, {
97
- size: "sm",
98
- onClick: () => O(e.id),
99
- children: [/* @__PURE__ */ v(g, { className: "mr-2 h-3 w-3" }), "Send Now"]
100
- })
101
- })
102
- }
103
- ],
104
- data: D,
105
- keyExtractor: (e) => e.id,
106
- loading: C,
107
- emptyState: /* @__PURE__ */ v(n, {
108
- illustration: "empty-notifications",
109
- icon: /* @__PURE__ */ v(p, { className: "h-8 w-8" }),
110
- title: "No newsletters found",
111
- description: "Create your first newsletter to communicate with users"
27
+ children: [
28
+ /* @__PURE__ */ v(b, { children: "Reach your users directly. Draft newsletters, send them to your subscriber base, and track how many people opened and clicked — use it to announce launches, share product updates, or run a re-engagement campaign." }),
29
+ /* @__PURE__ */ y(s, { children: [
30
+ /* @__PURE__ */ v(o, {
31
+ title: "Total Subscribers",
32
+ hero: !0,
33
+ value: D?.totalSubscribers ?? 0,
34
+ loading: S,
35
+ icon: /* @__PURE__ */ v(_, { className: "h-4 w-4" })
36
+ }),
37
+ /* @__PURE__ */ v(o, {
38
+ title: "Newsletters Sent",
39
+ value: D?.totalSent ?? 0,
40
+ loading: S,
41
+ icon: /* @__PURE__ */ v(g, { className: "h-4 w-4" })
42
+ }),
43
+ /* @__PURE__ */ v(o, {
44
+ title: "Avg. Open Rate",
45
+ value: a(D?.averageOpenRate ?? 0),
46
+ loading: S,
47
+ icon: /* @__PURE__ */ v(f, { className: "h-4 w-4" })
48
+ }),
49
+ /* @__PURE__ */ v(o, {
50
+ title: "Avg. Click Rate",
51
+ value: a(D?.averageClickRate ?? 0),
52
+ loading: S,
53
+ icon: /* @__PURE__ */ v(m, { className: "h-4 w-4" })
112
54
  })
113
- })]
114
- })]
55
+ ] }),
56
+ /* @__PURE__ */ y("div", {
57
+ className: "space-y-4",
58
+ children: [/* @__PURE__ */ v("h2", {
59
+ className: "text-lg font-semibold",
60
+ children: "Newsletters"
61
+ }), /* @__PURE__ */ v(c, {
62
+ columns: [
63
+ {
64
+ key: "title",
65
+ header: "Title",
66
+ render: (e) => /* @__PURE__ */ y("div", {
67
+ className: "flex flex-col",
68
+ children: [/* @__PURE__ */ v("span", {
69
+ className: "font-medium text-text-primary",
70
+ children: e.title
71
+ }), /* @__PURE__ */ v("span", {
72
+ className: "text-xs text-text-secondary",
73
+ children: e.subject
74
+ })]
75
+ })
76
+ },
77
+ {
78
+ key: "status",
79
+ header: "Status",
80
+ render: (t) => /* @__PURE__ */ v(e, {
81
+ variant: {
82
+ SENT: "success",
83
+ SCHEDULED: "warning",
84
+ DRAFT: "secondary"
85
+ }[t.status] || "outline",
86
+ children: t.status
87
+ })
88
+ },
89
+ {
90
+ key: "sentAt",
91
+ header: "Sent Date",
92
+ render: (e) => e.sentAt ? i(e.sentAt) : "-"
93
+ },
94
+ {
95
+ key: "actions",
96
+ header: "",
97
+ align: "right",
98
+ render: (e) => /* @__PURE__ */ v("div", {
99
+ className: "flex justify-end gap-2",
100
+ children: e.status === "DRAFT" && /* @__PURE__ */ y(t, {
101
+ size: "sm",
102
+ onClick: () => k(e.id),
103
+ children: [/* @__PURE__ */ v(g, { className: "mr-2 h-3 w-3" }), "Send Now"]
104
+ })
105
+ })
106
+ }
107
+ ],
108
+ data: O,
109
+ keyExtractor: (e) => e.id,
110
+ loading: w,
111
+ emptyState: /* @__PURE__ */ v(n, {
112
+ illustration: "empty-notifications",
113
+ icon: /* @__PURE__ */ v(p, { className: "h-8 w-8" }),
114
+ title: "No newsletters found",
115
+ description: "Create your first newsletter to communicate with users"
116
+ })
117
+ })]
118
+ })
119
+ ]
115
120
  })
116
121
  });
117
122
  }
118
123
  //#endregion
119
- export { b as CommunicationsPage };
124
+ export { x as CommunicationsPage };
120
125
 
121
126
  //# sourceMappingURL=CommunicationsPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CommunicationsPage.js","names":[],"sources":["../../../src/admin/pages/CommunicationsPage.tsx"],"sourcesContent":["import { Mail, Plus, Send, Users, Eye, MousePointer2 } from 'lucide-react';\nimport {\n PageLayout,\n Button,\n DataTable,\n Badge,\n MetricCard,\n MetricsGrid,\n EmptyState,\n} from '../components';\nimport {\n useListNewslettersQuery,\n useGetNewsletterStatsQuery,\n useSendNewsletterMutation,\n} from '../../generated/global-operations';\nimport { formatDateTime, formatPercentage } from '../utils/formatters';\n\nexport function CommunicationsPage() {\n const { data: statsData, loading: statsLoading } = useGetNewsletterStatsQuery();\n const {\n data: listData,\n loading: listLoading,\n refetch,\n } = useListNewslettersQuery({\n variables: { limit: 50 },\n });\n\n const [sendNewsletter] = useSendNewsletterMutation();\n\n const stats = statsData?.newsletterStats;\n const newsletters = listData?.newsletters || [];\n\n const handleSend = async (id: string) => {\n if (confirm('Are you sure you want to send this newsletter to all subscribers?')) {\n try {\n await sendNewsletter({ variables: { id } });\n refetch();\n } catch (err) {\n console.error('Failed to send newsletter:', err);\n }\n }\n };\n\n const columns = [\n {\n key: 'title',\n header: 'Title',\n render: (news: any) => (\n <div className=\"flex flex-col\">\n <span className=\"font-medium text-text-primary\">{news.title}</span>\n <span className=\"text-xs text-text-secondary\">{news.subject}</span>\n </div>\n ),\n },\n {\n key: 'status',\n header: 'Status',\n render: (news: any) => {\n const variants: Record<\n string,\n 'default' | 'secondary' | 'success' | 'warning' | 'destructive' | 'outline'\n > = {\n SENT: 'success',\n SCHEDULED: 'warning',\n DRAFT: 'secondary',\n };\n return <Badge variant={variants[news.status] || 'outline'}>{news.status}</Badge>;\n },\n },\n {\n key: 'sentAt',\n header: 'Sent Date',\n render: (news: any) => (news.sentAt ? formatDateTime(news.sentAt) : '-'),\n },\n {\n key: 'actions',\n header: '',\n align: 'right' as const,\n render: (news: any) => (\n <div className=\"flex justify-end gap-2\">\n {news.status === 'DRAFT' && (\n <Button size=\"sm\" onClick={() => handleSend(news.id)}>\n <Send className=\"mr-2 h-3 w-3\" />\n Send Now\n </Button>\n )}\n </div>\n ),\n },\n ];\n\n return (\n <PageLayout\n title=\"Communications\"\n gradientWord=\"Communications\"\n description=\"Manage platform newsletters and system notifications\"\n actions={\n <Button>\n <Plus className=\"mr-2 h-4 w-4\" />\n Create Newsletter\n </Button>\n }\n >\n <div className=\"space-y-8\">\n <MetricsGrid>\n <MetricCard\n title=\"Total Subscribers\"\n hero\n value={stats?.totalSubscribers ?? 0}\n loading={statsLoading}\n icon={<Users className=\"h-4 w-4\" />}\n />\n <MetricCard\n title=\"Newsletters Sent\"\n value={stats?.totalSent ?? 0}\n loading={statsLoading}\n icon={<Send className=\"h-4 w-4\" />}\n />\n <MetricCard\n title=\"Avg. Open Rate\"\n value={formatPercentage(stats?.averageOpenRate ?? 0)}\n loading={statsLoading}\n icon={<Eye className=\"h-4 w-4\" />}\n />\n <MetricCard\n title=\"Avg. Click Rate\"\n value={formatPercentage(stats?.averageClickRate ?? 0)}\n loading={statsLoading}\n icon={<MousePointer2 className=\"h-4 w-4\" />}\n />\n </MetricsGrid>\n\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-semibold\">Newsletters</h2>\n <DataTable\n columns={columns}\n data={newsletters}\n keyExtractor={(n) => n.id}\n loading={listLoading}\n emptyState={\n <EmptyState\n illustration=\"empty-notifications\"\n icon={<Mail className=\"h-8 w-8\" />}\n title=\"No newsletters found\"\n description=\"Create your first newsletter to communicate with users\"\n />\n }\n />\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;AAiBA,SAAgB,IAAqB;CACnC,IAAM,EAAE,MAAM,GAAW,SAAS,MAAiB,GAA4B,EACzE,EACJ,MAAM,GACN,SAAS,GACT,eACE,EAAwB,EAC1B,WAAW,EAAE,OAAO,IAAI,EACzB,CAAC,EAEI,CAAC,KAAkB,GAA2B,EAE9C,IAAQ,GAAW,iBACnB,IAAc,GAAU,eAAe,EAAE,EAEzC,IAAa,OAAO,MAAe;AACvC,MAAI,QAAQ,oEAAoE,CAC9E,KAAI;AAEF,GADA,MAAM,EAAe,EAAE,WAAW,EAAE,OAAI,EAAE,CAAC,EAC3C,GAAS;WACF,GAAK;AACZ,WAAQ,MAAM,8BAA8B,EAAI;;;AAqDtD,QACE,kBAAC,GAAD;EACE,OAAM;EACN,cAAa;EACb,aAAY;EACZ,SACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EAAA,oBAE1B,EAAA,CAAA;YAGX,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,GAAD,EAAA,UAAA;IACE,kBAAC,GAAD;KACE,OAAM;KACN,MAAA;KACA,OAAO,GAAO,oBAAoB;KAClC,SAAS;KACT,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;KACnC,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,GAAO,aAAa;KAC3B,SAAS;KACT,MAAM,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA;KAClC,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,EAAiB,GAAO,mBAAmB,EAAE;KACpD,SAAS;KACT,MAAM,kBAAC,GAAD,EAAK,WAAU,WAAY,CAAA;KACjC,CAAA;IACF,kBAAC,GAAD;KACE,OAAM;KACN,OAAO,EAAiB,GAAO,oBAAoB,EAAE;KACrD,SAAS;KACT,MAAM,kBAAC,GAAD,EAAe,WAAU,WAAY,CAAA;KAC3C,CAAA;IACU,EAAA,CAAA,EAEd,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,MAAD;KAAI,WAAU;eAAwB;KAAgB,CAAA,EACtD,kBAAC,GAAD;KACW,SA5FH;MACd;OACE,KAAK;OACL,QAAQ;OACR,SAAS,MACP,kBAAC,OAAD;QAAK,WAAU;kBAAf,CACE,kBAAC,QAAD;SAAM,WAAU;mBAAiC,EAAK;SAAa,CAAA,EACnE,kBAAC,QAAD;SAAM,WAAU;mBAA+B,EAAK;SAAe,CAAA,CAC/D;;OAET;MACD;OACE,KAAK;OACL,QAAQ;OACR,SAAS,MASA,kBAAC,GAAD;QAAO,SALV;SACF,MAAM;SACN,WAAW;SACX,OAAO;SACR,CAC+B,EAAK,WAAW;kBAAY,EAAK;QAAe,CAAA;OAEnF;MACD;OACE,KAAK;OACL,QAAQ;OACR,SAAS,MAAe,EAAK,SAAS,EAAe,EAAK,OAAO,GAAG;OACrE;MACD;OACE,KAAK;OACL,QAAQ;OACR,OAAO;OACP,SAAS,MACP,kBAAC,OAAD;QAAK,WAAU;kBACZ,EAAK,WAAW,WACf,kBAAC,GAAD;SAAQ,MAAK;SAAK,eAAe,EAAW,EAAK,GAAG;mBAApD,CACE,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EAAA,WAE1B;;QAEP,CAAA;OAET;MACF;KA+CS,MAAM;KACN,eAAe,MAAM,EAAE;KACvB,SAAS;KACT,YACE,kBAAC,GAAD;MACE,cAAa;MACb,MAAM,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA;MAClC,OAAM;MACN,aAAY;MACZ,CAAA;KAEJ,CAAA,CACE;MACF;;EACK,CAAA"}
1
+ {"version":3,"file":"CommunicationsPage.js","names":[],"sources":["../../../src/admin/pages/CommunicationsPage.tsx"],"sourcesContent":["import { Mail, Plus, Send, Users, Eye, MousePointer2 } from 'lucide-react';\nimport {\n PageLayout,\n Button,\n DataTable,\n Badge,\n MetricCard,\n MetricsGrid,\n EmptyState,\n} from '../components';\nimport {\n useListNewslettersQuery,\n useGetNewsletterStatsQuery,\n useSendNewsletterMutation,\n} from '../../generated/global-operations';\nimport { formatDateTime, formatPercentage } from '../utils/formatters';\nimport { PagePurpose } from '@burdenoff/fe-libs/ui';\n\nexport function CommunicationsPage() {\n const { data: statsData, loading: statsLoading } = useGetNewsletterStatsQuery();\n const {\n data: listData,\n loading: listLoading,\n refetch,\n } = useListNewslettersQuery({\n variables: { limit: 50 },\n });\n\n const [sendNewsletter] = useSendNewsletterMutation();\n\n const stats = statsData?.newsletterStats;\n const newsletters = listData?.newsletters || [];\n\n const handleSend = async (id: string) => {\n if (confirm('Are you sure you want to send this newsletter to all subscribers?')) {\n try {\n await sendNewsletter({ variables: { id } });\n refetch();\n } catch (err) {\n console.error('Failed to send newsletter:', err);\n }\n }\n };\n\n const columns = [\n {\n key: 'title',\n header: 'Title',\n render: (news: any) => (\n <div className=\"flex flex-col\">\n <span className=\"font-medium text-text-primary\">{news.title}</span>\n <span className=\"text-xs text-text-secondary\">{news.subject}</span>\n </div>\n ),\n },\n {\n key: 'status',\n header: 'Status',\n render: (news: any) => {\n const variants: Record<\n string,\n 'default' | 'secondary' | 'success' | 'warning' | 'destructive' | 'outline'\n > = {\n SENT: 'success',\n SCHEDULED: 'warning',\n DRAFT: 'secondary',\n };\n return <Badge variant={variants[news.status] || 'outline'}>{news.status}</Badge>;\n },\n },\n {\n key: 'sentAt',\n header: 'Sent Date',\n render: (news: any) => (news.sentAt ? formatDateTime(news.sentAt) : '-'),\n },\n {\n key: 'actions',\n header: '',\n align: 'right' as const,\n render: (news: any) => (\n <div className=\"flex justify-end gap-2\">\n {news.status === 'DRAFT' && (\n <Button size=\"sm\" onClick={() => handleSend(news.id)}>\n <Send className=\"mr-2 h-3 w-3\" />\n Send Now\n </Button>\n )}\n </div>\n ),\n },\n ];\n\n return (\n <PageLayout\n title=\"Communications\"\n gradientWord=\"Communications\"\n description=\"Manage platform newsletters and system notifications\"\n actions={\n <Button>\n <Plus className=\"mr-2 h-4 w-4\" />\n Create Newsletter\n </Button>\n }\n >\n <div className=\"space-y-8\">\n <PagePurpose>\n Reach your users directly. Draft newsletters, send them to your subscriber base, and\n track how many people opened and clicked — use it to announce launches, share product\n updates, or run a re-engagement campaign.\n </PagePurpose>\n\n <MetricsGrid>\n <MetricCard\n title=\"Total Subscribers\"\n hero\n value={stats?.totalSubscribers ?? 0}\n loading={statsLoading}\n icon={<Users className=\"h-4 w-4\" />}\n />\n <MetricCard\n title=\"Newsletters Sent\"\n value={stats?.totalSent ?? 0}\n loading={statsLoading}\n icon={<Send className=\"h-4 w-4\" />}\n />\n <MetricCard\n title=\"Avg. Open Rate\"\n value={formatPercentage(stats?.averageOpenRate ?? 0)}\n loading={statsLoading}\n icon={<Eye className=\"h-4 w-4\" />}\n />\n <MetricCard\n title=\"Avg. Click Rate\"\n value={formatPercentage(stats?.averageClickRate ?? 0)}\n loading={statsLoading}\n icon={<MousePointer2 className=\"h-4 w-4\" />}\n />\n </MetricsGrid>\n\n <div className=\"space-y-4\">\n <h2 className=\"text-lg font-semibold\">Newsletters</h2>\n <DataTable\n columns={columns}\n data={newsletters}\n keyExtractor={(n) => n.id}\n loading={listLoading}\n emptyState={\n <EmptyState\n illustration=\"empty-notifications\"\n icon={<Mail className=\"h-8 w-8\" />}\n title=\"No newsletters found\"\n description=\"Create your first newsletter to communicate with users\"\n />\n }\n />\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;AAkBA,SAAgB,IAAqB;CACnC,IAAM,EAAE,MAAM,GAAW,SAAS,MAAiB,GAA4B,EACzE,EACJ,MAAM,GACN,SAAS,GACT,eACE,EAAwB,EAC1B,WAAW,EAAE,OAAO,IAAI,EACzB,CAAC,EAEI,CAAC,KAAkB,GAA2B,EAE9C,IAAQ,GAAW,iBACnB,IAAc,GAAU,eAAe,EAAE,EAEzC,IAAa,OAAO,MAAe;AACvC,MAAI,QAAQ,oEAAoE,CAC9E,KAAI;AAEF,GADA,MAAM,EAAe,EAAE,WAAW,EAAE,OAAI,EAAE,CAAC,EAC3C,GAAS;WACF,GAAK;AACZ,WAAQ,MAAM,8BAA8B,EAAI;;;AAqDtD,QACE,kBAAC,GAAD;EACE,OAAM;EACN,cAAa;EACb,aAAY;EACZ,SACE,kBAAC,GAAD,EAAA,UAAA,CACE,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EAAA,oBAE1B,EAAA,CAAA;YAGX,kBAAC,OAAD;GAAK,WAAU;aAAf;IACE,kBAAC,GAAD,EAAA,UAAa,wNAIC,CAAA;IAEd,kBAAC,GAAD,EAAA,UAAA;KACE,kBAAC,GAAD;MACE,OAAM;MACN,MAAA;MACA,OAAO,GAAO,oBAAoB;MAClC,SAAS;MACT,MAAM,kBAAC,GAAD,EAAO,WAAU,WAAY,CAAA;MACnC,CAAA;KACF,kBAAC,GAAD;MACE,OAAM;MACN,OAAO,GAAO,aAAa;MAC3B,SAAS;MACT,MAAM,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA;MAClC,CAAA;KACF,kBAAC,GAAD;MACE,OAAM;MACN,OAAO,EAAiB,GAAO,mBAAmB,EAAE;MACpD,SAAS;MACT,MAAM,kBAAC,GAAD,EAAK,WAAU,WAAY,CAAA;MACjC,CAAA;KACF,kBAAC,GAAD;MACE,OAAM;MACN,OAAO,EAAiB,GAAO,oBAAoB,EAAE;MACrD,SAAS;MACT,MAAM,kBAAC,GAAD,EAAe,WAAU,WAAY,CAAA;MAC3C,CAAA;KACU,EAAA,CAAA;IAEd,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,MAAD;MAAI,WAAU;gBAAwB;MAAgB,CAAA,EACtD,kBAAC,GAAD;MACW,SAlGH;OACd;QACE,KAAK;QACL,QAAQ;QACR,SAAS,MACP,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,QAAD;UAAM,WAAU;oBAAiC,EAAK;UAAa,CAAA,EACnE,kBAAC,QAAD;UAAM,WAAU;oBAA+B,EAAK;UAAe,CAAA,CAC/D;;QAET;OACD;QACE,KAAK;QACL,QAAQ;QACR,SAAS,MASA,kBAAC,GAAD;SAAO,SALV;UACF,MAAM;UACN,WAAW;UACX,OAAO;UACR,CAC+B,EAAK,WAAW;mBAAY,EAAK;SAAe,CAAA;QAEnF;OACD;QACE,KAAK;QACL,QAAQ;QACR,SAAS,MAAe,EAAK,SAAS,EAAe,EAAK,OAAO,GAAG;QACrE;OACD;QACE,KAAK;QACL,QAAQ;QACR,OAAO;QACP,SAAS,MACP,kBAAC,OAAD;SAAK,WAAU;mBACZ,EAAK,WAAW,WACf,kBAAC,GAAD;UAAQ,MAAK;UAAK,eAAe,EAAW,EAAK,GAAG;oBAApD,CACE,kBAAC,GAAD,EAAM,WAAU,gBAAiB,CAAA,EAAA,WAE1B;;SAEP,CAAA;QAET;OACF;MAqDS,MAAM;MACN,eAAe,MAAM,EAAE;MACvB,SAAS;MACT,YACE,kBAAC,GAAD;OACE,cAAa;OACb,MAAM,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA;OAClC,OAAM;OACN,aAAY;OACZ,CAAA;MAEJ,CAAA,CACE;;IACF;;EACK,CAAA"}