@burdenoff/microfe-tours 2026.830.1 → 2026.830.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/tours/ToursAdminRoot.js +28 -27
- package/dist/tours/ToursAdminRoot.js.map +1 -1
- package/dist/tours/ToursAdminRoutes.js +56 -55
- package/dist/tours/ToursAdminRoutes.js.map +1 -1
- package/dist/tours/ToursUserRoot.js +34 -29
- package/dist/tours/ToursUserRoot.js.map +1 -1
- package/dist/tours/ToursUserRoutes.js +33 -33
- package/dist/tours/ToursUserRoutes.js.map +1 -1
- package/dist/tours/components/MarkdownEditor.js +85 -80
- package/dist/tours/components/MarkdownEditor.js.map +1 -1
- package/dist/tours/components/RouteHelpers.js +47 -42
- package/dist/tours/components/RouteHelpers.js.map +1 -1
- package/dist/tours/components/ToursAdminNavRegistrar.js +32 -27
- package/dist/tours/components/ToursAdminNavRegistrar.js.map +1 -1
- package/dist/tours/hooks/useStepSequencer.js +45 -36
- package/dist/tours/hooks/useStepSequencer.js.map +1 -1
- package/dist/tours/hooks/useTourBuilder.js +106 -93
- package/dist/tours/hooks/useTourBuilder.js.map +1 -1
- package/dist/tours/hooks/useTourPreview.js +51 -41
- package/dist/tours/hooks/useTourPreview.js.map +1 -1
- package/dist/tours/hooks/useToursList.js +28 -27
- package/dist/tours/hooks/useToursList.js.map +1 -1
- package/dist/tours/i18n.js +187 -5
- package/dist/tours/i18n.js.map +1 -1
- package/dist/tours/pages/AnalyticsDashboardPage.js +108 -109
- package/dist/tours/pages/AnalyticsDashboardPage.js.map +1 -1
- package/dist/tours/pages/MediaLibraryPage.js +58 -61
- package/dist/tours/pages/MediaLibraryPage.js.map +1 -1
- package/dist/tours/pages/MyToursPage.js +5 -5
- package/dist/tours/pages/MyToursProgressPage.js +5 -5
- package/dist/tours/pages/SchedulerPage.js +78 -81
- package/dist/tours/pages/SchedulerPage.js.map +1 -1
- package/dist/tours/pages/StepEditorPage.js +32 -32
- package/dist/tours/pages/StepEditorPage.js.map +1 -1
- package/dist/tours/pages/SystemAnalyticsPage.js +75 -79
- package/dist/tours/pages/SystemAnalyticsPage.js.map +1 -1
- package/dist/tours/pages/TemplateLibraryPage.js +8 -8
- package/dist/tours/pages/TourBuilderPage.js +279 -279
- package/dist/tours/pages/TourBuilderPage.js.map +1 -1
- package/dist/tours/pages/TourPreviewPage.js +6 -6
- package/dist/tours/pages/ToursListPage.js +155 -155
- package/dist/tours/pages/ToursListPage.js.map +1 -1
- package/dist/tours/store/toursStore.js +11 -7
- package/dist/tours/store/toursStore.js.map +1 -1
- package/dist/tours/utils/index.js +32 -19
- package/dist/tours/utils/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,221 +1,220 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
1
|
+
import { useToursI18n as e } from "../i18n.js";
|
|
2
|
+
import { useToursPermissionAccess as t } from "../hooks/useToursPermissionAccess.js";
|
|
3
|
+
import { TOUR_PERMISSIONS as n } from "../../constants/permissions.js";
|
|
4
|
+
import { useTourAnalytics as r } from "../hooks/useTourAnalytics.js";
|
|
5
|
+
import { useToursFormatters as i } from "../utils/index.js";
|
|
6
|
+
import { useEffect as a } from "react";
|
|
7
|
+
import { BarChart3 as o, Timer as s, TrendingUp as c, Users as l } from "lucide-react";
|
|
8
|
+
import { jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
9
|
+
import { useParams as f } from "react-router";
|
|
10
|
+
import { EmphasisPanel as p, GlassCard as m, IllustratedEmptyState as h, PagePurpose as g } from "@burdenoff/fe-libs/ui";
|
|
11
11
|
//#region src/tours/pages/AnalyticsDashboardPage.tsx
|
|
12
|
-
function
|
|
13
|
-
let {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}, [b]), { tourId: S } = m(), { hasPermission: C, isLoading: w } = e(), T = C(t.TOUR_ANALYTICS_READ), { analytics: E, loading: D, fetchAnalytics: O, getCompletionRate: k, getSkipRate: A } = n(S);
|
|
17
|
-
return s(() => {
|
|
18
|
-
w || !T || O();
|
|
12
|
+
function _() {
|
|
13
|
+
let { tr: _ } = e(), { tourId: v } = f(), { hasPermission: y, isLoading: b } = t(), x = y(n.TOUR_ANALYTICS_READ), { analytics: S, loading: C, fetchAnalytics: w, getCompletionRate: T, getSkipRate: E } = r(v), { formatNumber: D, formatPercentage: O, formatDuration: k } = i();
|
|
14
|
+
return a(() => {
|
|
15
|
+
b || !x || w();
|
|
19
16
|
}, [
|
|
20
|
-
O,
|
|
21
17
|
w,
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
b,
|
|
19
|
+
x
|
|
20
|
+
]), !b && !x ? /* @__PURE__ */ u("div", {
|
|
24
21
|
className: "flex items-center justify-center h-full p-3 sm:p-6",
|
|
25
|
-
children: /* @__PURE__ */
|
|
22
|
+
children: /* @__PURE__ */ d("div", {
|
|
26
23
|
className: "text-center",
|
|
27
|
-
children: [/* @__PURE__ */
|
|
24
|
+
children: [/* @__PURE__ */ u("h2", {
|
|
28
25
|
className: "text-lg font-semibold text-text-primary mb-2",
|
|
29
|
-
children:
|
|
30
|
-
}), /* @__PURE__ */
|
|
26
|
+
children: _("analyticsDashboard.accessDenied", "Access Denied")
|
|
27
|
+
}), /* @__PURE__ */ u("p", {
|
|
31
28
|
className: "text-sm text-text-secondary",
|
|
32
|
-
children:
|
|
29
|
+
children: _("analyticsDashboard.noPermission", "You do not have permission to view tour analytics.")
|
|
33
30
|
})]
|
|
34
31
|
})
|
|
35
|
-
}) :
|
|
32
|
+
}) : C ? /* @__PURE__ */ u("div", {
|
|
36
33
|
className: "flex items-center justify-center h-full",
|
|
37
|
-
children: /* @__PURE__ */
|
|
34
|
+
children: /* @__PURE__ */ u("p", {
|
|
38
35
|
className: "text-text-secondary",
|
|
39
|
-
children:
|
|
36
|
+
children: _("analyticsDashboard.loading", "Loading analytics...")
|
|
40
37
|
})
|
|
41
|
-
}) :
|
|
38
|
+
}) : S ? /* @__PURE__ */ d("div", {
|
|
42
39
|
className: "space-y-4 sm:space-y-6 p-3 sm:p-6",
|
|
43
40
|
children: [
|
|
44
|
-
/* @__PURE__ */
|
|
41
|
+
/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("h1", {
|
|
45
42
|
className: "text-xl sm:text-2xl font-bold",
|
|
46
|
-
children:
|
|
47
|
-
}), /* @__PURE__ */
|
|
43
|
+
children: _("analyticsDashboard.title", "Tour Analytics")
|
|
44
|
+
}), /* @__PURE__ */ u("p", {
|
|
48
45
|
className: "text-sm text-text-secondary",
|
|
49
|
-
children:
|
|
46
|
+
children: _("analyticsDashboard.subtitle", "Performance metrics and insights")
|
|
50
47
|
})] }),
|
|
51
|
-
/* @__PURE__ */
|
|
52
|
-
/* @__PURE__ */
|
|
48
|
+
/* @__PURE__ */ u(g, { children: _("analyticsDashboard.purpose", "See how this specific tour is performing: how many people viewed it, how many finished versus skipped, and exactly which step they drop off on. Use the per-step drop-off to find and fix the weak point in your walkthrough.") }),
|
|
49
|
+
/* @__PURE__ */ d("div", {
|
|
53
50
|
className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4",
|
|
54
51
|
children: [
|
|
55
|
-
/* @__PURE__ */
|
|
52
|
+
/* @__PURE__ */ d(m, {
|
|
56
53
|
treatment: "glass",
|
|
57
54
|
className: "p-4",
|
|
58
|
-
children: [/* @__PURE__ */
|
|
55
|
+
children: [/* @__PURE__ */ d("div", {
|
|
59
56
|
className: "flex items-center gap-3 mb-2",
|
|
60
|
-
children: [/* @__PURE__ */
|
|
57
|
+
children: [/* @__PURE__ */ u("div", {
|
|
61
58
|
className: "p-2 bg-action-primary-bg/10 rounded-md",
|
|
62
|
-
children: /* @__PURE__ */
|
|
59
|
+
children: /* @__PURE__ */ u(l, {
|
|
63
60
|
className: "text-primary",
|
|
64
61
|
size: 20
|
|
65
62
|
})
|
|
66
|
-
}), /* @__PURE__ */
|
|
63
|
+
}), /* @__PURE__ */ u("span", {
|
|
67
64
|
className: "text-sm text-text-secondary",
|
|
68
|
-
children:
|
|
65
|
+
children: _("analyticsDashboard.totalViews", "Total Views")
|
|
69
66
|
})]
|
|
70
|
-
}), /* @__PURE__ */
|
|
67
|
+
}), /* @__PURE__ */ u("div", {
|
|
71
68
|
className: "text-2xl font-bold tabular-nums",
|
|
72
|
-
children:
|
|
69
|
+
children: D(S.totalViews)
|
|
73
70
|
})]
|
|
74
71
|
}),
|
|
75
|
-
/* @__PURE__ */
|
|
72
|
+
/* @__PURE__ */ d(m, {
|
|
76
73
|
treatment: "metric",
|
|
77
74
|
className: "p-4",
|
|
78
|
-
children: [/* @__PURE__ */
|
|
75
|
+
children: [/* @__PURE__ */ d("div", {
|
|
79
76
|
className: "flex items-center gap-3 mb-2",
|
|
80
|
-
children: [/* @__PURE__ */
|
|
77
|
+
children: [/* @__PURE__ */ u("div", {
|
|
81
78
|
className: "p-2 bg-success/10 rounded-md",
|
|
82
|
-
children: /* @__PURE__ */
|
|
79
|
+
children: /* @__PURE__ */ u(c, {
|
|
83
80
|
className: "text-success",
|
|
84
81
|
size: 20
|
|
85
82
|
})
|
|
86
|
-
}), /* @__PURE__ */
|
|
83
|
+
}), /* @__PURE__ */ u("span", {
|
|
87
84
|
className: "text-sm text-text-secondary",
|
|
88
|
-
children:
|
|
85
|
+
children: _("analyticsDashboard.completionRate", "Completion Rate")
|
|
89
86
|
})]
|
|
90
|
-
}), /* @__PURE__ */
|
|
87
|
+
}), /* @__PURE__ */ u("div", {
|
|
91
88
|
className: "text-2xl font-bold tabular-nums",
|
|
92
|
-
children:
|
|
89
|
+
children: O(T())
|
|
93
90
|
})]
|
|
94
91
|
}),
|
|
95
|
-
/* @__PURE__ */
|
|
92
|
+
/* @__PURE__ */ d(m, {
|
|
96
93
|
treatment: "metric",
|
|
97
94
|
className: "p-4",
|
|
98
|
-
children: [/* @__PURE__ */
|
|
95
|
+
children: [/* @__PURE__ */ d("div", {
|
|
99
96
|
className: "flex items-center gap-3 mb-2",
|
|
100
|
-
children: [/* @__PURE__ */
|
|
97
|
+
children: [/* @__PURE__ */ u("div", {
|
|
101
98
|
className: "p-2 bg-warning/10 rounded-md",
|
|
102
|
-
children: /* @__PURE__ */
|
|
99
|
+
children: /* @__PURE__ */ u(o, {
|
|
103
100
|
className: "text-warning",
|
|
104
101
|
size: 20
|
|
105
102
|
})
|
|
106
|
-
}), /* @__PURE__ */
|
|
103
|
+
}), /* @__PURE__ */ u("span", {
|
|
107
104
|
className: "text-sm text-text-secondary",
|
|
108
|
-
children:
|
|
105
|
+
children: _("analyticsDashboard.skipRate", "Skip Rate")
|
|
109
106
|
})]
|
|
110
|
-
}), /* @__PURE__ */
|
|
107
|
+
}), /* @__PURE__ */ u("div", {
|
|
111
108
|
className: "text-2xl font-bold tabular-nums",
|
|
112
|
-
children:
|
|
109
|
+
children: O(E())
|
|
113
110
|
})]
|
|
114
111
|
}),
|
|
115
|
-
/* @__PURE__ */
|
|
112
|
+
/* @__PURE__ */ d(m, {
|
|
116
113
|
treatment: "metric",
|
|
117
114
|
className: "p-4",
|
|
118
|
-
children: [/* @__PURE__ */
|
|
115
|
+
children: [/* @__PURE__ */ d("div", {
|
|
119
116
|
className: "flex items-center gap-3 mb-2",
|
|
120
|
-
children: [/* @__PURE__ */
|
|
117
|
+
children: [/* @__PURE__ */ u("div", {
|
|
121
118
|
className: "p-2 bg-info/10 rounded-md",
|
|
122
|
-
children: /* @__PURE__ */
|
|
119
|
+
children: /* @__PURE__ */ u(s, {
|
|
123
120
|
className: "text-info",
|
|
124
121
|
size: 20
|
|
125
122
|
})
|
|
126
|
-
}), /* @__PURE__ */
|
|
123
|
+
}), /* @__PURE__ */ u("span", {
|
|
127
124
|
className: "text-sm text-text-secondary",
|
|
128
|
-
children:
|
|
125
|
+
children: _("analyticsDashboard.avgDuration", "Avg Duration")
|
|
129
126
|
})]
|
|
130
|
-
}), /* @__PURE__ */
|
|
127
|
+
}), /* @__PURE__ */ u("div", {
|
|
131
128
|
className: "text-2xl font-bold tabular-nums",
|
|
132
|
-
children:
|
|
129
|
+
children: k(S.averageDuration)
|
|
133
130
|
})]
|
|
134
131
|
})
|
|
135
132
|
]
|
|
136
133
|
}),
|
|
137
|
-
/* @__PURE__ */ p
|
|
134
|
+
/* @__PURE__ */ d(p, {
|
|
138
135
|
className: "p-4 sm:p-6",
|
|
139
|
-
children: [/* @__PURE__ */
|
|
136
|
+
children: [/* @__PURE__ */ u("h2", {
|
|
140
137
|
className: "text-lg font-semibold mb-4",
|
|
141
|
-
children:
|
|
142
|
-
}), /* @__PURE__ */
|
|
138
|
+
children: _("analyticsDashboard.deviceBreakdown", "Device Breakdown")
|
|
139
|
+
}), /* @__PURE__ */ u("div", {
|
|
143
140
|
className: "space-y-3",
|
|
144
|
-
children:
|
|
141
|
+
children: S.byDeviceType.map((e) => /* @__PURE__ */ d("div", { children: [/* @__PURE__ */ d("div", {
|
|
145
142
|
className: "flex items-center justify-between mb-2",
|
|
146
|
-
children: [/* @__PURE__ */
|
|
147
|
-
className: "text-sm
|
|
148
|
-
children: e.deviceType
|
|
149
|
-
}), /* @__PURE__ */
|
|
143
|
+
children: [/* @__PURE__ */ u("span", {
|
|
144
|
+
className: "text-sm",
|
|
145
|
+
children: _(`deviceType.${e.deviceType}`, e.deviceType)
|
|
146
|
+
}), /* @__PURE__ */ d("span", {
|
|
150
147
|
className: "text-sm text-text-secondary tabular-nums",
|
|
151
148
|
children: [
|
|
152
|
-
|
|
153
|
-
"
|
|
154
|
-
|
|
149
|
+
D(e.count),
|
|
150
|
+
" ",
|
|
151
|
+
_("analyticsDashboard.deviceViews", "views"),
|
|
152
|
+
" (",
|
|
153
|
+
O(e.completionRate),
|
|
155
154
|
")"
|
|
156
155
|
]
|
|
157
156
|
})]
|
|
158
|
-
}), /* @__PURE__ */
|
|
157
|
+
}), /* @__PURE__ */ u("div", {
|
|
159
158
|
className: "w-full bg-bg-sunken rounded-full h-2",
|
|
160
|
-
children: /* @__PURE__ */
|
|
159
|
+
children: /* @__PURE__ */ u("div", {
|
|
161
160
|
className: "bg-action-primary-bg h-2 rounded-full shadow-[var(--shadow-pop)]",
|
|
162
161
|
style: { width: `${e.completionRate}%` }
|
|
163
162
|
})
|
|
164
163
|
})] }, e.deviceType))
|
|
165
164
|
})]
|
|
166
165
|
}),
|
|
167
|
-
|
|
166
|
+
S.stepAnalytics && S.stepAnalytics.length > 0 && /* @__PURE__ */ d(m, {
|
|
168
167
|
treatment: "plain",
|
|
169
168
|
className: "p-4 sm:p-6 border-border-seam",
|
|
170
|
-
children: [/* @__PURE__ */
|
|
169
|
+
children: [/* @__PURE__ */ u("h2", {
|
|
171
170
|
className: "text-lg font-semibold mb-4",
|
|
172
|
-
children:
|
|
173
|
-
}), /* @__PURE__ */
|
|
171
|
+
children: _("analyticsDashboard.stepPerformance", "Step Performance")
|
|
172
|
+
}), /* @__PURE__ */ u("div", {
|
|
174
173
|
className: "overflow-x-auto",
|
|
175
|
-
children: /* @__PURE__ */
|
|
174
|
+
children: /* @__PURE__ */ d("table", {
|
|
176
175
|
className: "w-full",
|
|
177
|
-
children: [/* @__PURE__ */
|
|
176
|
+
children: [/* @__PURE__ */ u("thead", { children: /* @__PURE__ */ d("tr", {
|
|
178
177
|
className: "border-b border-border-seam",
|
|
179
178
|
children: [
|
|
180
|
-
/* @__PURE__ */
|
|
179
|
+
/* @__PURE__ */ u("th", {
|
|
181
180
|
className: "text-left py-2 px-4 text-sm font-medium text-text-secondary",
|
|
182
|
-
children:
|
|
181
|
+
children: _("analyticsDashboard.tableStep", "Step")
|
|
183
182
|
}),
|
|
184
|
-
/* @__PURE__ */
|
|
183
|
+
/* @__PURE__ */ u("th", {
|
|
185
184
|
className: "text-right py-2 px-4 text-sm font-medium text-text-secondary",
|
|
186
|
-
children:
|
|
185
|
+
children: _("analyticsDashboard.tableViews", "Views")
|
|
187
186
|
}),
|
|
188
|
-
/* @__PURE__ */
|
|
187
|
+
/* @__PURE__ */ u("th", {
|
|
189
188
|
className: "text-right py-2 px-4 text-sm font-medium text-text-secondary",
|
|
190
|
-
children:
|
|
189
|
+
children: _("analyticsDashboard.tableCompletions", "Completions")
|
|
191
190
|
}),
|
|
192
|
-
/* @__PURE__ */
|
|
191
|
+
/* @__PURE__ */ u("th", {
|
|
193
192
|
className: "text-right py-2 px-4 text-sm font-medium text-text-secondary",
|
|
194
|
-
children:
|
|
193
|
+
children: _("analyticsDashboard.tableDropOffRate", "Drop-off Rate")
|
|
195
194
|
})
|
|
196
195
|
]
|
|
197
|
-
}) }), /* @__PURE__ */
|
|
196
|
+
}) }), /* @__PURE__ */ u("tbody", { children: S.stepAnalytics.map((e) => /* @__PURE__ */ d("tr", {
|
|
198
197
|
className: "border-b border-border-seam",
|
|
199
198
|
children: [
|
|
200
|
-
/* @__PURE__ */
|
|
199
|
+
/* @__PURE__ */ d("td", {
|
|
201
200
|
className: "py-2 px-4 text-sm",
|
|
202
201
|
children: [
|
|
203
|
-
|
|
202
|
+
_("analyticsDashboard.stepLabel", "Step"),
|
|
204
203
|
" ",
|
|
205
204
|
e.stepOrder
|
|
206
205
|
]
|
|
207
206
|
}),
|
|
208
|
-
/* @__PURE__ */
|
|
207
|
+
/* @__PURE__ */ u("td", {
|
|
209
208
|
className: "text-right py-2 px-4 text-sm tabular-nums",
|
|
210
|
-
children:
|
|
209
|
+
children: D(e.views)
|
|
211
210
|
}),
|
|
212
|
-
/* @__PURE__ */
|
|
211
|
+
/* @__PURE__ */ u("td", {
|
|
213
212
|
className: "text-right py-2 px-4 text-sm tabular-nums",
|
|
214
|
-
children:
|
|
213
|
+
children: D(e.completions)
|
|
215
214
|
}),
|
|
216
|
-
/* @__PURE__ */
|
|
215
|
+
/* @__PURE__ */ u("td", {
|
|
217
216
|
className: "text-right py-2 px-4 text-sm tabular-nums",
|
|
218
|
-
children:
|
|
217
|
+
children: O(e.dropOffRate)
|
|
219
218
|
})
|
|
220
219
|
]
|
|
221
220
|
}, e.stepId)) })]
|
|
@@ -223,16 +222,16 @@ function b() {
|
|
|
223
222
|
})]
|
|
224
223
|
})
|
|
225
224
|
]
|
|
226
|
-
}) : /* @__PURE__ */
|
|
225
|
+
}) : /* @__PURE__ */ u("div", {
|
|
227
226
|
className: "p-3 sm:p-6",
|
|
228
|
-
children: /* @__PURE__ */
|
|
227
|
+
children: /* @__PURE__ */ u(h, {
|
|
229
228
|
illustration: "empty-data",
|
|
230
|
-
title:
|
|
231
|
-
description:
|
|
229
|
+
title: _("analyticsDashboard.noData", "No analytics data available"),
|
|
230
|
+
description: _("analyticsDashboard.noDataHint", "Analytics appear once this tour has been published and seen by users. Publish the tour and check back after it starts collecting views.")
|
|
232
231
|
})
|
|
233
232
|
});
|
|
234
233
|
}
|
|
235
234
|
//#endregion
|
|
236
|
-
export {
|
|
235
|
+
export { _ as AnalyticsDashboardPage };
|
|
237
236
|
|
|
238
237
|
//# sourceMappingURL=AnalyticsDashboardPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnalyticsDashboardPage.js","names":[],"sources":["../../../src/tours/pages/AnalyticsDashboardPage.tsx"],"sourcesContent":["import { useCallback, useEffect } from 'react';\nimport { useParams } from 'react-router';\nimport { BarChart3, TrendingUp, Users, Timer } from 'lucide-react';\nimport {\n GlassCard,\n EmphasisPanel,\n IllustratedEmptyState,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { useTourAnalytics } from '../hooks/useTourAnalytics';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport { formatNumber, formatPercentage, formatDuration } from '../utils';\n\n/**\n * Analytics dashboard page\n * Display tour performance metrics and charts\n */\nexport function AnalyticsDashboardPage() {\n const { t } = useI18n();\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n },\n [t]\n );\n\n const { tourId } = useParams();\n const { hasPermission, isLoading: permissionsLoading } = useToursPermissionAccess();\n const canViewAnalytics = hasPermission(TOUR_PERMISSIONS.TOUR_ANALYTICS_READ);\n\n const { analytics, loading, fetchAnalytics, getCompletionRate, getSkipRate } =\n useTourAnalytics(tourId);\n\n useEffect(() => {\n if (permissionsLoading || !canViewAnalytics) return;\n fetchAnalytics();\n }, [fetchAnalytics, permissionsLoading, canViewAnalytics]);\n\n if (!permissionsLoading && !canViewAnalytics) {\n return (\n <div className=\"flex items-center justify-center h-full p-3 sm:p-6\">\n <div className=\"text-center\">\n <h2 className=\"text-lg font-semibold text-text-primary mb-2\">\n {tr('analyticsDashboard.accessDenied', 'Access Denied')}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'analyticsDashboard.noPermission',\n 'You do not have permission to view tour analytics.'\n )}\n </p>\n </div>\n </div>\n );\n }\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <p className=\"text-text-secondary\">\n {tr('analyticsDashboard.loading', 'Loading analytics...')}\n </p>\n </div>\n );\n }\n\n if (!analytics) {\n return (\n <div className=\"p-3 sm:p-6\">\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={tr('analyticsDashboard.noData', 'No analytics data available')}\n description={tr(\n 'analyticsDashboard.noDataHint',\n 'Analytics appear once this tour has been published and seen by users. Publish the tour and check back after it starts collecting views.'\n )}\n />\n </div>\n );\n }\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n {/* Header */}\n <div>\n <h1 className=\"text-xl sm:text-2xl font-bold\">\n {tr('analyticsDashboard.title', 'Tour Analytics')}\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {tr('analyticsDashboard.subtitle', 'Performance metrics and insights')}\n </p>\n </div>\n\n <PagePurpose>\n {tr(\n 'analyticsDashboard.purpose',\n 'See how this specific tour is performing: how many people viewed it, how many finished versus skipped, and exactly which step they drop off on. Use the per-step drop-off to find and fix the weak point in your walkthrough.'\n )}\n </PagePurpose>\n\n {/* Summary Cards */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4\">\n <GlassCard treatment=\"glass\" className=\"p-4\">\n <div className=\"flex items-center gap-3 mb-2\">\n <div className=\"p-2 bg-action-primary-bg/10 rounded-md\">\n <Users className=\"text-primary\" size={20} />\n </div>\n <span className=\"text-sm text-text-secondary\">\n {tr('analyticsDashboard.totalViews', 'Total Views')}\n </span>\n </div>\n <div className=\"text-2xl font-bold tabular-nums\">\n {formatNumber(analytics.totalViews)}\n </div>\n </GlassCard>\n\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <div className=\"flex items-center gap-3 mb-2\">\n <div className=\"p-2 bg-success/10 rounded-md\">\n <TrendingUp className=\"text-success\" size={20} />\n </div>\n <span className=\"text-sm text-text-secondary\">\n {tr('analyticsDashboard.completionRate', 'Completion Rate')}\n </span>\n </div>\n <div className=\"text-2xl font-bold tabular-nums\">\n {formatPercentage(getCompletionRate())}\n </div>\n </GlassCard>\n\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <div className=\"flex items-center gap-3 mb-2\">\n <div className=\"p-2 bg-warning/10 rounded-md\">\n <BarChart3 className=\"text-warning\" size={20} />\n </div>\n <span className=\"text-sm text-text-secondary\">\n {tr('analyticsDashboard.skipRate', 'Skip Rate')}\n </span>\n </div>\n <div className=\"text-2xl font-bold tabular-nums\">{formatPercentage(getSkipRate())}</div>\n </GlassCard>\n\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <div className=\"flex items-center gap-3 mb-2\">\n <div className=\"p-2 bg-info/10 rounded-md\">\n <Timer className=\"text-info\" size={20} />\n </div>\n <span className=\"text-sm text-text-secondary\">\n {tr('analyticsDashboard.avgDuration', 'Avg Duration')}\n </span>\n </div>\n <div className=\"text-2xl font-bold tabular-nums\">\n {formatDuration(analytics.averageDuration)}\n </div>\n </GlassCard>\n </div>\n\n {/* Device Breakdown — the key soft-glow data-viz zone */}\n <EmphasisPanel className=\"p-4 sm:p-6\">\n <h2 className=\"text-lg font-semibold mb-4\">\n {tr('analyticsDashboard.deviceBreakdown', 'Device Breakdown')}\n </h2>\n <div className=\"space-y-3\">\n {analytics.byDeviceType.map((device) => (\n <div key={device.deviceType}>\n <div className=\"flex items-center justify-between mb-2\">\n <span className=\"text-sm capitalize\">{device.deviceType}</span>\n <span className=\"text-sm text-text-secondary tabular-nums\">\n {formatNumber(device.count)} views ({formatPercentage(device.completionRate)})\n </span>\n </div>\n <div className=\"w-full bg-bg-sunken rounded-full h-2\">\n <div\n className=\"bg-action-primary-bg h-2 rounded-full shadow-[var(--shadow-pop)]\"\n style={{ width: `${device.completionRate}%` }}\n />\n </div>\n </div>\n ))}\n </div>\n </EmphasisPanel>\n\n {/* Step Analytics */}\n {analytics.stepAnalytics && analytics.stepAnalytics.length > 0 && (\n <GlassCard treatment=\"plain\" className=\"p-4 sm:p-6 border-border-seam\">\n <h2 className=\"text-lg font-semibold mb-4\">\n {tr('analyticsDashboard.stepPerformance', 'Step Performance')}\n </h2>\n <div className=\"overflow-x-auto\">\n <table className=\"w-full\">\n <thead>\n <tr className=\"border-b border-border-seam\">\n <th className=\"text-left py-2 px-4 text-sm font-medium text-text-secondary\">\n {tr('analyticsDashboard.tableStep', 'Step')}\n </th>\n <th className=\"text-right py-2 px-4 text-sm font-medium text-text-secondary\">\n {tr('analyticsDashboard.tableViews', 'Views')}\n </th>\n <th className=\"text-right py-2 px-4 text-sm font-medium text-text-secondary\">\n {tr('analyticsDashboard.tableCompletions', 'Completions')}\n </th>\n <th className=\"text-right py-2 px-4 text-sm font-medium text-text-secondary\">\n {tr('analyticsDashboard.tableDropOffRate', 'Drop-off Rate')}\n </th>\n </tr>\n </thead>\n <tbody>\n {analytics.stepAnalytics.map((step) => (\n <tr key={step.stepId} className=\"border-b border-border-seam\">\n <td className=\"py-2 px-4 text-sm\">\n {tr('analyticsDashboard.stepLabel', 'Step')} {step.stepOrder}\n </td>\n <td className=\"text-right py-2 px-4 text-sm tabular-nums\">\n {formatNumber(step.views)}\n </td>\n <td className=\"text-right py-2 px-4 text-sm tabular-nums\">\n {formatNumber(step.completions)}\n </td>\n <td className=\"text-right py-2 px-4 text-sm tabular-nums\">\n {formatPercentage(step.dropOffRate)}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </GlassCard>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AnalyticsDashboardPage.js","names":[],"sources":["../../../src/tours/pages/AnalyticsDashboardPage.tsx"],"sourcesContent":["import { useEffect } from 'react';\nimport { useParams } from 'react-router';\nimport { BarChart3, TrendingUp, Users, Timer } from 'lucide-react';\nimport {\n GlassCard,\n EmphasisPanel,\n IllustratedEmptyState,\n PagePurpose,\n} from '@burdenoff/fe-libs/ui';\nimport { useToursI18n } from '../i18n';\nimport { useTourAnalytics } from '../hooks/useTourAnalytics';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport { useToursFormatters } from '../utils';\n\n/**\n * Analytics dashboard page\n * Display tour performance metrics and charts\n */\nexport function AnalyticsDashboardPage() {\n const { tr } = useToursI18n();\n\n const { tourId } = useParams();\n const { hasPermission, isLoading: permissionsLoading } = useToursPermissionAccess();\n const canViewAnalytics = hasPermission(TOUR_PERMISSIONS.TOUR_ANALYTICS_READ);\n\n const { analytics, loading, fetchAnalytics, getCompletionRate, getSkipRate } =\n useTourAnalytics(tourId);\n const { formatNumber, formatPercentage, formatDuration } = useToursFormatters();\n\n useEffect(() => {\n if (permissionsLoading || !canViewAnalytics) return;\n fetchAnalytics();\n }, [fetchAnalytics, permissionsLoading, canViewAnalytics]);\n\n if (!permissionsLoading && !canViewAnalytics) {\n return (\n <div className=\"flex items-center justify-center h-full p-3 sm:p-6\">\n <div className=\"text-center\">\n <h2 className=\"text-lg font-semibold text-text-primary mb-2\">\n {tr('analyticsDashboard.accessDenied', 'Access Denied')}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n 'analyticsDashboard.noPermission',\n 'You do not have permission to view tour analytics.'\n )}\n </p>\n </div>\n </div>\n );\n }\n\n if (loading) {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <p className=\"text-text-secondary\">\n {tr('analyticsDashboard.loading', 'Loading analytics...')}\n </p>\n </div>\n );\n }\n\n if (!analytics) {\n return (\n <div className=\"p-3 sm:p-6\">\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={tr('analyticsDashboard.noData', 'No analytics data available')}\n description={tr(\n 'analyticsDashboard.noDataHint',\n 'Analytics appear once this tour has been published and seen by users. Publish the tour and check back after it starts collecting views.'\n )}\n />\n </div>\n );\n }\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n {/* Header */}\n <div>\n <h1 className=\"text-xl sm:text-2xl font-bold\">\n {tr('analyticsDashboard.title', 'Tour Analytics')}\n </h1>\n <p className=\"text-sm text-text-secondary\">\n {tr('analyticsDashboard.subtitle', 'Performance metrics and insights')}\n </p>\n </div>\n\n <PagePurpose>\n {tr(\n 'analyticsDashboard.purpose',\n 'See how this specific tour is performing: how many people viewed it, how many finished versus skipped, and exactly which step they drop off on. Use the per-step drop-off to find and fix the weak point in your walkthrough.'\n )}\n </PagePurpose>\n\n {/* Summary Cards */}\n <div className=\"grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4\">\n <GlassCard treatment=\"glass\" className=\"p-4\">\n <div className=\"flex items-center gap-3 mb-2\">\n <div className=\"p-2 bg-action-primary-bg/10 rounded-md\">\n <Users className=\"text-primary\" size={20} />\n </div>\n <span className=\"text-sm text-text-secondary\">\n {tr('analyticsDashboard.totalViews', 'Total Views')}\n </span>\n </div>\n <div className=\"text-2xl font-bold tabular-nums\">\n {formatNumber(analytics.totalViews)}\n </div>\n </GlassCard>\n\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <div className=\"flex items-center gap-3 mb-2\">\n <div className=\"p-2 bg-success/10 rounded-md\">\n <TrendingUp className=\"text-success\" size={20} />\n </div>\n <span className=\"text-sm text-text-secondary\">\n {tr('analyticsDashboard.completionRate', 'Completion Rate')}\n </span>\n </div>\n <div className=\"text-2xl font-bold tabular-nums\">\n {formatPercentage(getCompletionRate())}\n </div>\n </GlassCard>\n\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <div className=\"flex items-center gap-3 mb-2\">\n <div className=\"p-2 bg-warning/10 rounded-md\">\n <BarChart3 className=\"text-warning\" size={20} />\n </div>\n <span className=\"text-sm text-text-secondary\">\n {tr('analyticsDashboard.skipRate', 'Skip Rate')}\n </span>\n </div>\n <div className=\"text-2xl font-bold tabular-nums\">{formatPercentage(getSkipRate())}</div>\n </GlassCard>\n\n <GlassCard treatment=\"metric\" className=\"p-4\">\n <div className=\"flex items-center gap-3 mb-2\">\n <div className=\"p-2 bg-info/10 rounded-md\">\n <Timer className=\"text-info\" size={20} />\n </div>\n <span className=\"text-sm text-text-secondary\">\n {tr('analyticsDashboard.avgDuration', 'Avg Duration')}\n </span>\n </div>\n <div className=\"text-2xl font-bold tabular-nums\">\n {formatDuration(analytics.averageDuration)}\n </div>\n </GlassCard>\n </div>\n\n {/* Device Breakdown — the key soft-glow data-viz zone */}\n <EmphasisPanel className=\"p-4 sm:p-6\">\n <h2 className=\"text-lg font-semibold mb-4\">\n {tr('analyticsDashboard.deviceBreakdown', 'Device Breakdown')}\n </h2>\n <div className=\"space-y-3\">\n {analytics.byDeviceType.map((device) => (\n <div key={device.deviceType}>\n <div className=\"flex items-center justify-between mb-2\">\n <span className=\"text-sm\">\n {tr(`deviceType.${device.deviceType}` as const, device.deviceType)}\n </span>\n <span className=\"text-sm text-text-secondary tabular-nums\">\n {formatNumber(device.count)} {tr('analyticsDashboard.deviceViews', 'views')} (\n {formatPercentage(device.completionRate)})\n </span>\n </div>\n <div className=\"w-full bg-bg-sunken rounded-full h-2\">\n <div\n className=\"bg-action-primary-bg h-2 rounded-full shadow-[var(--shadow-pop)]\"\n style={{ width: `${device.completionRate}%` }}\n />\n </div>\n </div>\n ))}\n </div>\n </EmphasisPanel>\n\n {/* Step Analytics */}\n {analytics.stepAnalytics && analytics.stepAnalytics.length > 0 && (\n <GlassCard treatment=\"plain\" className=\"p-4 sm:p-6 border-border-seam\">\n <h2 className=\"text-lg font-semibold mb-4\">\n {tr('analyticsDashboard.stepPerformance', 'Step Performance')}\n </h2>\n <div className=\"overflow-x-auto\">\n <table className=\"w-full\">\n <thead>\n <tr className=\"border-b border-border-seam\">\n <th className=\"text-left py-2 px-4 text-sm font-medium text-text-secondary\">\n {tr('analyticsDashboard.tableStep', 'Step')}\n </th>\n <th className=\"text-right py-2 px-4 text-sm font-medium text-text-secondary\">\n {tr('analyticsDashboard.tableViews', 'Views')}\n </th>\n <th className=\"text-right py-2 px-4 text-sm font-medium text-text-secondary\">\n {tr('analyticsDashboard.tableCompletions', 'Completions')}\n </th>\n <th className=\"text-right py-2 px-4 text-sm font-medium text-text-secondary\">\n {tr('analyticsDashboard.tableDropOffRate', 'Drop-off Rate')}\n </th>\n </tr>\n </thead>\n <tbody>\n {analytics.stepAnalytics.map((step) => (\n <tr key={step.stepId} className=\"border-b border-border-seam\">\n <td className=\"py-2 px-4 text-sm\">\n {tr('analyticsDashboard.stepLabel', 'Step')} {step.stepOrder}\n </td>\n <td className=\"text-right py-2 px-4 text-sm tabular-nums\">\n {formatNumber(step.views)}\n </td>\n <td className=\"text-right py-2 px-4 text-sm tabular-nums\">\n {formatNumber(step.completions)}\n </td>\n <td className=\"text-right py-2 px-4 text-sm tabular-nums\">\n {formatPercentage(step.dropOffRate)}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </GlassCard>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;AAmBA,SAAgB,IAAyB;CACvC,IAAM,EAAE,UAAO,GAAc,EAEvB,EAAE,cAAW,GAAW,EACxB,EAAE,kBAAe,WAAW,MAAuB,GAA0B,EAC7E,IAAmB,EAAc,EAAiB,oBAAoB,EAEtE,EAAE,cAAW,YAAS,mBAAgB,sBAAmB,mBAC7D,EAAiB,EAAO,EACpB,EAAE,iBAAc,qBAAkB,sBAAmB,GAAoB;AAkD/E,QAhDA,QAAgB;AACV,OAAsB,CAAC,KAC3B,GAAgB;IACf;EAAC;EAAgB;EAAoB;EAAiB,CAAC,EAEtD,CAAC,KAAsB,CAAC,IAExB,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,MAAD;IAAI,WAAU;cACX,EAAG,mCAAmC,gBAAgB;IACpD,CAAA,EACL,kBAAC,KAAD;IAAG,WAAU;cACV,EACC,mCACA,qDACD;IACC,CAAA,CACA;;EACF,CAAA,GAIN,IAEA,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,KAAD;GAAG,WAAU;aACV,EAAG,8BAA8B,uBAAuB;GACvD,CAAA;EACA,CAAA,GAIL,IAgBH,kBAAC,OAAD;EAAK,WAAU;YAAf;GAEE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;IAAI,WAAU;cACX,EAAG,4BAA4B,iBAAiB;IAC9C,CAAA,EACL,kBAAC,KAAD;IAAG,WAAU;cACV,EAAG,+BAA+B,mCAAmC;IACpE,CAAA,CACA,EAAA,CAAA;GAEN,kBAAC,GAAD,EAAA,UACG,EACC,8BACA,gOACD,EACW,CAAA;GAGd,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MAAW,WAAU;MAAQ,WAAU;gBAAvC,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD;QAAK,WAAU;kBACb,kBAAC,GAAD;SAAO,WAAU;SAAe,MAAM;SAAM,CAAA;QACxC,CAAA,EACN,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAG,iCAAiC,cAAc;QAC9C,CAAA,CACH;UACN,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAa,EAAU,WAAW;OAC/B,CAAA,CACI;;KAEZ,kBAAC,GAAD;MAAW,WAAU;MAAS,WAAU;gBAAxC,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD;QAAK,WAAU;kBACb,kBAAC,GAAD;SAAY,WAAU;SAAe,MAAM;SAAM,CAAA;QAC7C,CAAA,EACN,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAG,qCAAqC,kBAAkB;QACtD,CAAA,CACH;UACN,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAiB,GAAmB,CAAC;OAClC,CAAA,CACI;;KAEZ,kBAAC,GAAD;MAAW,WAAU;MAAS,WAAU;gBAAxC,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD;QAAK,WAAU;kBACb,kBAAC,GAAD;SAAW,WAAU;SAAe,MAAM;SAAM,CAAA;QAC5C,CAAA,EACN,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAG,+BAA+B,YAAY;QAC1C,CAAA,CACH;UACN,kBAAC,OAAD;OAAK,WAAU;iBAAmC,EAAiB,GAAa,CAAC;OAAO,CAAA,CAC9E;;KAEZ,kBAAC,GAAD;MAAW,WAAU;MAAS,WAAU;gBAAxC,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD;QAAK,WAAU;kBACb,kBAAC,GAAD;SAAO,WAAU;SAAY,MAAM;SAAM,CAAA;QACrC,CAAA,EACN,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAG,kCAAkC,eAAe;QAChD,CAAA,CACH;UACN,kBAAC,OAAD;OAAK,WAAU;iBACZ,EAAe,EAAU,gBAAgB;OACtC,CAAA,CACI;;KACR;;GAGN,kBAAC,GAAD;IAAe,WAAU;cAAzB,CACE,kBAAC,MAAD;KAAI,WAAU;eACX,EAAG,sCAAsC,mBAAmB;KAC1D,CAAA,EACL,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAU,aAAa,KAAK,MAC3B,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,QAAD;OAAM,WAAU;iBACb,EAAG,cAAc,EAAO,cAAuB,EAAO,WAAW;OAC7D,CAAA,EACP,kBAAC,QAAD;OAAM,WAAU;iBAAhB;QACG,EAAa,EAAO,MAAM;QAAC;QAAE,EAAG,kCAAkC,QAAQ;QAAC;QAC3E,EAAiB,EAAO,eAAe;QAAC;QACpC;SACH;SACN,kBAAC,OAAD;MAAK,WAAU;gBACb,kBAAC,OAAD;OACE,WAAU;OACV,OAAO,EAAE,OAAO,GAAG,EAAO,eAAe,IAAI;OAC7C,CAAA;MACE,CAAA,CACF,EAAA,EAhBI,EAAO,WAgBX,CACN;KACE,CAAA,CACQ;;GAGf,EAAU,iBAAiB,EAAU,cAAc,SAAS,KAC3D,kBAAC,GAAD;IAAW,WAAU;IAAQ,WAAU;cAAvC,CACE,kBAAC,MAAD;KAAI,WAAU;eACX,EAAG,sCAAsC,mBAAmB;KAC1D,CAAA,EACL,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,SAAD;MAAO,WAAU;gBAAjB,CACE,kBAAC,SAAD,EAAA,UACE,kBAAC,MAAD;OAAI,WAAU;iBAAd;QACE,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAG,gCAAgC,OAAO;SACxC,CAAA;QACL,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAG,iCAAiC,QAAQ;SAC1C,CAAA;QACL,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAG,uCAAuC,cAAc;SACtD,CAAA;QACL,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAG,uCAAuC,gBAAgB;SACxD,CAAA;QACF;UACC,CAAA,EACR,kBAAC,SAAD,EAAA,UACG,EAAU,cAAc,KAAK,MAC5B,kBAAC,MAAD;OAAsB,WAAU;iBAAhC;QACE,kBAAC,MAAD;SAAI,WAAU;mBAAd;UACG,EAAG,gCAAgC,OAAO;UAAC;UAAE,EAAK;UAChD;;QACL,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAa,EAAK,MAAM;SACtB,CAAA;QACL,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAa,EAAK,YAAY;SAC5B,CAAA;QACL,kBAAC,MAAD;SAAI,WAAU;mBACX,EAAiB,EAAK,YAAY;SAChC,CAAA;QACF;SAbI,EAAK,OAaT,CACL,EACI,CAAA,CACF;;KACJ,CAAA,CACI;;GAEV;MAnKJ,kBAAC,OAAD;EAAK,WAAU;YACb,kBAAC,GAAD;GACE,cAAa;GACb,OAAO,EAAG,6BAA6B,8BAA8B;GACrE,aAAa,EACX,iCACA,0IACD;GACD,CAAA;EACE,CAAA"}
|