@burdenoff/microfe-tours 2026.608.1 → 2026.625.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.
- package/dist/tours/ToursUserRoutes.js +3 -3
- package/dist/tours/ToursUserRoutes.js.map +1 -1
- package/dist/tours/components/RouteHelpers.js +6 -6
- package/dist/tours/components/RouteHelpers.js.map +1 -1
- package/dist/tours/pages/AnalyticsDashboardPage.js +80 -74
- package/dist/tours/pages/AnalyticsDashboardPage.js.map +1 -1
- package/dist/tours/pages/MediaLibraryPage.js +66 -64
- package/dist/tours/pages/MediaLibraryPage.js.map +1 -1
- package/dist/tours/pages/MyToursPage.js +37 -35
- package/dist/tours/pages/MyToursPage.js.map +1 -1
- package/dist/tours/pages/MyToursProgressPage.js +60 -56
- package/dist/tours/pages/MyToursProgressPage.js.map +1 -1
- package/dist/tours/pages/SchedulerPage.js +98 -92
- package/dist/tours/pages/SchedulerPage.js.map +1 -1
- package/dist/tours/pages/StepEditorPage.js +261 -260
- package/dist/tours/pages/StepEditorPage.js.map +1 -1
- package/dist/tours/pages/SystemAnalyticsPage.js +59 -53
- package/dist/tours/pages/SystemAnalyticsPage.js.map +1 -1
- package/dist/tours/pages/TemplateLibraryPage.js +71 -69
- package/dist/tours/pages/TemplateLibraryPage.js.map +1 -1
- package/dist/tours/pages/TourBuilderPage.js +181 -194
- package/dist/tours/pages/TourBuilderPage.js.map +1 -1
- package/dist/tours/pages/TourPreviewPage.js +92 -89
- package/dist/tours/pages/TourPreviewPage.js.map +1 -1
- package/dist/tours/pages/ToursListPage.js +171 -215
- package/dist/tours/pages/ToursListPage.js.map +1 -1
- package/package.json +2 -2
|
@@ -9,55 +9,56 @@ import { useEffect as s } from "react";
|
|
|
9
9
|
import { AlertCircle as c, ArrowLeft as l, CheckCircle as u, ChevronLeft as d, ChevronRight as f, Monitor as p, Smartphone as m, Tablet as h, X as g } from "lucide-react";
|
|
10
10
|
import { jsx as _, jsxs as v } from "react/jsx-runtime";
|
|
11
11
|
import { useNavigate as y, useParams as b } from "react-router-dom";
|
|
12
|
+
import { Button as x, GlassCard as S } from "@burdenoff/fe-libs/ui";
|
|
12
13
|
//#region src/tours/pages/TourPreviewPage.tsx
|
|
13
|
-
function
|
|
14
|
-
let { tr:
|
|
14
|
+
function C() {
|
|
15
|
+
let { tr: C } = i(), { tourId: w } = b(), T = y(), { basePath: E = "/" } = e(), { hasPermission: D } = n(), O = D(r.TOUR_READ), { tour: k, loadTour: A } = a(w), { devicePreview: j } = t(), { isPreviewActive: M, currentStepIndex: N, currentStep: P, totalSteps: F, canGoNext: I, canGoPrevious: L, validationResults: R, startPreview: z, stopPreview: B, nextStep: V, previousStep: H, changeDevice: U, validateForPreview: W } = o(k || void 0);
|
|
15
16
|
if (s(() => {
|
|
16
|
-
|
|
17
|
-
}, [
|
|
18
|
-
|
|
17
|
+
w && A(w);
|
|
18
|
+
}, [w, A]), s(() => {
|
|
19
|
+
k && W();
|
|
19
20
|
}, [
|
|
20
|
-
D,
|
|
21
21
|
k,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
j,
|
|
23
|
+
W
|
|
24
|
+
]), !O) return /* @__PURE__ */ _("div", {
|
|
25
|
+
className: "flex items-center justify-center h-screen bg-bg-sunken",
|
|
25
26
|
children: /* @__PURE__ */ v("div", {
|
|
26
27
|
className: "text-center",
|
|
27
28
|
children: [/* @__PURE__ */ _("h2", {
|
|
28
|
-
className: "text-lg font-semibold text-
|
|
29
|
-
children:
|
|
29
|
+
className: "text-lg font-semibold text-text-primary mb-2",
|
|
30
|
+
children: C("tourPreview.accessDeniedTitle")
|
|
30
31
|
}), /* @__PURE__ */ _("p", {
|
|
31
|
-
className: "text-sm text-
|
|
32
|
-
children:
|
|
32
|
+
className: "text-sm text-text-secondary",
|
|
33
|
+
children: C("tourPreview.accessDeniedMessage")
|
|
33
34
|
})]
|
|
34
35
|
})
|
|
35
36
|
});
|
|
36
|
-
if (!
|
|
37
|
-
className: "flex items-center justify-center h-screen bg-
|
|
37
|
+
if (!k) return /* @__PURE__ */ _("div", {
|
|
38
|
+
className: "flex items-center justify-center h-screen bg-bg-sunken",
|
|
38
39
|
children: /* @__PURE__ */ _("p", {
|
|
39
|
-
className: "text-
|
|
40
|
-
children:
|
|
40
|
+
className: "text-text-secondary",
|
|
41
|
+
children: C("tourPreview.loading")
|
|
41
42
|
})
|
|
42
43
|
});
|
|
43
|
-
let
|
|
44
|
-
|
|
45
|
-
},
|
|
44
|
+
let G = () => {
|
|
45
|
+
T(`${E}/${w}/edit`);
|
|
46
|
+
}, K = {
|
|
46
47
|
mobile: /* @__PURE__ */ _(m, { size: 20 }),
|
|
47
48
|
tablet: /* @__PURE__ */ _(h, { size: 20 }),
|
|
48
49
|
desktop: /* @__PURE__ */ _(p, { size: 20 })
|
|
49
50
|
};
|
|
50
51
|
return /* @__PURE__ */ v("div", {
|
|
51
|
-
className: "flex flex-col h-screen bg-
|
|
52
|
+
className: "flex flex-col h-screen bg-bg-sunken",
|
|
52
53
|
children: [
|
|
53
54
|
/* @__PURE__ */ v("div", {
|
|
54
|
-
className: "border-b border-border bg-
|
|
55
|
+
className: "border-b border-border-subtle bg-bg-surface p-3 sm:p-4 flex flex-wrap items-center gap-3 sm:gap-4",
|
|
55
56
|
children: [
|
|
56
57
|
/* @__PURE__ */ _("button", {
|
|
57
58
|
type: "button",
|
|
58
|
-
onClick:
|
|
59
|
+
onClick: G,
|
|
59
60
|
className: "p-2 min-h-[44px] min-w-[44px] hover:bg-accent rounded-md",
|
|
60
|
-
"aria-label":
|
|
61
|
+
"aria-label": C("tourBuilder.goBack"),
|
|
61
62
|
children: /* @__PURE__ */ _(l, { size: 20 })
|
|
62
63
|
}),
|
|
63
64
|
/* @__PURE__ */ v("div", {
|
|
@@ -65,75 +66,76 @@ function x() {
|
|
|
65
66
|
children: [/* @__PURE__ */ v("h1", {
|
|
66
67
|
className: "text-base sm:text-lg font-semibold truncate",
|
|
67
68
|
children: [
|
|
68
|
-
|
|
69
|
+
k?.name,
|
|
69
70
|
" - ",
|
|
70
|
-
|
|
71
|
+
C("tourPreview.previewSuffix")
|
|
71
72
|
]
|
|
72
|
-
}),
|
|
73
|
-
className: "text-sm text-
|
|
73
|
+
}), M && /* @__PURE__ */ v("p", {
|
|
74
|
+
className: "text-sm text-text-secondary",
|
|
74
75
|
children: [
|
|
75
|
-
|
|
76
|
+
C("tourPreview.stepOf"),
|
|
76
77
|
" ",
|
|
77
|
-
|
|
78
|
+
N + 1,
|
|
78
79
|
" ",
|
|
79
|
-
|
|
80
|
+
C("tourPreview.stepOfConnector"),
|
|
80
81
|
" ",
|
|
81
|
-
|
|
82
|
+
F
|
|
82
83
|
]
|
|
83
84
|
})]
|
|
84
85
|
}),
|
|
85
86
|
/* @__PURE__ */ _("div", {
|
|
86
|
-
className: "flex gap-2 border border-border rounded-md overflow-hidden",
|
|
87
|
+
className: "flex gap-2 border border-border-subtle rounded-md overflow-hidden",
|
|
87
88
|
children: [
|
|
88
89
|
"mobile",
|
|
89
90
|
"tablet",
|
|
90
91
|
"desktop"
|
|
91
92
|
].map((e) => /* @__PURE__ */ _("button", {
|
|
92
93
|
type: "button",
|
|
93
|
-
onClick: () =>
|
|
94
|
-
className: `px-3 py-2 min-h-[44px] min-w-[44px] ${
|
|
95
|
-
title:
|
|
96
|
-
"aria-label":
|
|
97
|
-
children:
|
|
94
|
+
onClick: () => U(e),
|
|
95
|
+
className: `px-3 py-2 min-h-[44px] min-w-[44px] ${j === e ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-surface hover:bg-accent"}`,
|
|
96
|
+
title: C(e === "mobile" ? "tourPreview.deviceMobile" : e === "tablet" ? "tourPreview.deviceTablet" : "tourPreview.deviceDesktop"),
|
|
97
|
+
"aria-label": C(e === "mobile" ? "tourPreview.deviceMobile" : e === "tablet" ? "tourPreview.deviceTablet" : "tourPreview.deviceDesktop"),
|
|
98
|
+
children: K[e]
|
|
98
99
|
}, e))
|
|
99
100
|
}),
|
|
100
|
-
|
|
101
|
+
M ? /* @__PURE__ */ v(x, {
|
|
101
102
|
type: "button",
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
variant: "outline",
|
|
104
|
+
onClick: B,
|
|
105
|
+
className: "min-h-[44px]",
|
|
106
|
+
children: [/* @__PURE__ */ _(g, { size: 20 }), C("tourPreview.stopPreview")]
|
|
107
|
+
}) : /* @__PURE__ */ _(x, {
|
|
106
108
|
type: "button",
|
|
107
|
-
onClick:
|
|
108
|
-
disabled: !
|
|
109
|
-
className: "
|
|
110
|
-
children:
|
|
109
|
+
onClick: z,
|
|
110
|
+
disabled: !R?.valid,
|
|
111
|
+
className: "min-h-[44px]",
|
|
112
|
+
children: C("tourPreview.startPreview")
|
|
111
113
|
})
|
|
112
114
|
]
|
|
113
115
|
}),
|
|
114
|
-
|
|
115
|
-
className: "bg-
|
|
116
|
+
R && !R.valid && /* @__PURE__ */ _("div", {
|
|
117
|
+
className: "bg-status-error-bg/10 border-b border-status-error-border px-3 sm:px-6 py-3",
|
|
116
118
|
children: /* @__PURE__ */ v("div", {
|
|
117
119
|
className: "flex items-start gap-3",
|
|
118
120
|
children: [/* @__PURE__ */ _(c, {
|
|
119
|
-
className: "text-
|
|
121
|
+
className: "text-status-error-text flex-shrink-0 mt-0.5",
|
|
120
122
|
size: 20
|
|
121
123
|
}), /* @__PURE__ */ v("div", {
|
|
122
124
|
className: "flex-1",
|
|
123
125
|
children: [/* @__PURE__ */ _("h3", {
|
|
124
|
-
className: "font-semibold text-
|
|
125
|
-
children:
|
|
126
|
+
className: "font-semibold text-status-error-text mb-1",
|
|
127
|
+
children: C("tourPreview.validationErrorsTitle")
|
|
126
128
|
}), /* @__PURE__ */ _("ul", {
|
|
127
129
|
className: "list-disc list-inside space-y-1",
|
|
128
|
-
children:
|
|
129
|
-
className: "text-sm text-
|
|
130
|
+
children: R.errors.map((e) => /* @__PURE__ */ _("li", {
|
|
131
|
+
className: "text-sm text-status-error-text",
|
|
130
132
|
children: e
|
|
131
133
|
}, e))
|
|
132
134
|
})]
|
|
133
135
|
})]
|
|
134
136
|
})
|
|
135
137
|
}),
|
|
136
|
-
|
|
138
|
+
R && R.warnings.length > 0 && /* @__PURE__ */ _("div", {
|
|
137
139
|
className: "bg-warning/10 border-b border-warning px-3 sm:px-6 py-3",
|
|
138
140
|
children: /* @__PURE__ */ v("div", {
|
|
139
141
|
className: "flex items-start gap-3",
|
|
@@ -144,10 +146,10 @@ function x() {
|
|
|
144
146
|
className: "flex-1",
|
|
145
147
|
children: [/* @__PURE__ */ _("h3", {
|
|
146
148
|
className: "font-semibold text-warning mb-1",
|
|
147
|
-
children:
|
|
149
|
+
children: C("tourPreview.warningsTitle")
|
|
148
150
|
}), /* @__PURE__ */ _("ul", {
|
|
149
151
|
className: "list-disc list-inside space-y-1",
|
|
150
|
-
children:
|
|
152
|
+
children: R.warnings.map((e) => /* @__PURE__ */ _("li", {
|
|
151
153
|
className: "text-sm text-warning",
|
|
152
154
|
children: e
|
|
153
155
|
}, e))
|
|
@@ -158,41 +160,42 @@ function x() {
|
|
|
158
160
|
/* @__PURE__ */ _("div", {
|
|
159
161
|
className: "flex-1 flex items-center justify-center p-3 sm:p-6 overflow-auto",
|
|
160
162
|
children: /* @__PURE__ */ _("div", {
|
|
161
|
-
className: `bg-
|
|
162
|
-
children:
|
|
163
|
+
className: `bg-bg-surface border-2 rounded-lg shadow-xl overflow-hidden ${j === "mobile" ? "w-[min(375px,calc(100vw-1.5rem))] h-[667px] max-h-full" : j === "tablet" ? "w-[min(768px,calc(100vw-1.5rem))] h-[1024px] max-h-full" : "w-full max-w-[1920px] h-full max-h-[1080px]"}`,
|
|
164
|
+
children: M && P ? /* @__PURE__ */ _("div", {
|
|
163
165
|
className: "h-full flex flex-col items-center justify-center p-4 sm:p-8",
|
|
164
|
-
children: /* @__PURE__ */ v(
|
|
165
|
-
|
|
166
|
+
children: /* @__PURE__ */ v(S, {
|
|
167
|
+
treatment: "glass",
|
|
168
|
+
className: "max-w-md border-border-seam p-4 sm:p-6 shadow-[var(--shadow-pop)]",
|
|
166
169
|
children: [
|
|
167
170
|
/* @__PURE__ */ _("h3", {
|
|
168
171
|
className: "text-lg font-semibold mb-3",
|
|
169
|
-
children:
|
|
172
|
+
children: P.title
|
|
170
173
|
}),
|
|
171
174
|
/* @__PURE__ */ _("p", {
|
|
172
|
-
className: "text-sm text-
|
|
173
|
-
children:
|
|
175
|
+
className: "text-sm text-text-secondary mb-4 whitespace-pre-wrap",
|
|
176
|
+
children: P.content
|
|
174
177
|
}),
|
|
175
178
|
/* @__PURE__ */ v("div", {
|
|
176
179
|
className: "flex gap-2",
|
|
177
180
|
children: [/* @__PURE__ */ _("button", {
|
|
178
181
|
type: "button",
|
|
179
|
-
onClick:
|
|
180
|
-
disabled: !
|
|
181
|
-
className: "px-3 py-2 min-h-[44px] min-w-[44px] border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed",
|
|
182
|
-
"aria-label":
|
|
182
|
+
onClick: H,
|
|
183
|
+
disabled: !L,
|
|
184
|
+
className: "px-3 py-2 min-h-[44px] min-w-[44px] border border-border-subtle rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed",
|
|
185
|
+
"aria-label": C("tourPreview.previous"),
|
|
183
186
|
children: /* @__PURE__ */ _(d, { size: 16 })
|
|
184
187
|
}), /* @__PURE__ */ _("button", {
|
|
185
188
|
type: "button",
|
|
186
|
-
onClick:
|
|
187
|
-
disabled: !
|
|
188
|
-
className: "flex-1 px-3 py-2 min-h-[44px] bg-primary text-primary-
|
|
189
|
-
children:
|
|
189
|
+
onClick: V,
|
|
190
|
+
disabled: !I,
|
|
191
|
+
className: "flex-1 px-3 py-2 min-h-[44px] bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg/90 disabled:opacity-50 disabled:cursor-not-allowed",
|
|
192
|
+
children: C(I ? "tourPreview.next" : "tourPreview.finish")
|
|
190
193
|
})]
|
|
191
194
|
})
|
|
192
195
|
]
|
|
193
196
|
})
|
|
194
197
|
}) : /* @__PURE__ */ _("div", {
|
|
195
|
-
className: "h-full flex items-center justify-center text-
|
|
198
|
+
className: "h-full flex items-center justify-center text-text-secondary",
|
|
196
199
|
children: /* @__PURE__ */ v("div", {
|
|
197
200
|
className: "text-center",
|
|
198
201
|
children: [
|
|
@@ -202,41 +205,41 @@ function x() {
|
|
|
202
205
|
}),
|
|
203
206
|
/* @__PURE__ */ _("p", {
|
|
204
207
|
className: "mb-2",
|
|
205
|
-
children:
|
|
208
|
+
children: C("tourPreview.readyTitle")
|
|
206
209
|
}),
|
|
207
210
|
/* @__PURE__ */ _("p", {
|
|
208
211
|
className: "text-sm",
|
|
209
|
-
children:
|
|
212
|
+
children: C("tourPreview.readyHint")
|
|
210
213
|
})
|
|
211
214
|
]
|
|
212
215
|
})
|
|
213
216
|
})
|
|
214
217
|
})
|
|
215
218
|
}),
|
|
216
|
-
|
|
217
|
-
className: "border-t border-border bg-
|
|
219
|
+
M && /* @__PURE__ */ v("div", {
|
|
220
|
+
className: "border-t border-border-subtle bg-bg-surface p-3 sm:p-4 flex items-center justify-center gap-3 sm:gap-4",
|
|
218
221
|
children: [
|
|
219
222
|
/* @__PURE__ */ v("button", {
|
|
220
223
|
type: "button",
|
|
221
|
-
onClick:
|
|
222
|
-
disabled: !
|
|
223
|
-
className: "px-4 py-2 min-h-[44px] border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2",
|
|
224
|
-
children: [/* @__PURE__ */ _(d, { size: 20 }),
|
|
224
|
+
onClick: H,
|
|
225
|
+
disabled: !L,
|
|
226
|
+
className: "px-4 py-2 min-h-[44px] border border-border-subtle rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2",
|
|
227
|
+
children: [/* @__PURE__ */ _(d, { size: 20 }), C("tourPreview.previous")]
|
|
225
228
|
}),
|
|
226
229
|
/* @__PURE__ */ v("div", {
|
|
227
|
-
className: "text-sm text-
|
|
230
|
+
className: "text-sm text-text-secondary",
|
|
228
231
|
children: [
|
|
229
|
-
|
|
232
|
+
N + 1,
|
|
230
233
|
" / ",
|
|
231
|
-
|
|
234
|
+
F
|
|
232
235
|
]
|
|
233
236
|
}),
|
|
234
237
|
/* @__PURE__ */ v("button", {
|
|
235
238
|
type: "button",
|
|
236
|
-
onClick:
|
|
237
|
-
disabled: !
|
|
238
|
-
className: "px-4 py-2 min-h-[44px] border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2",
|
|
239
|
-
children: [
|
|
239
|
+
onClick: V,
|
|
240
|
+
disabled: !I,
|
|
241
|
+
className: "px-4 py-2 min-h-[44px] border border-border-subtle rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2",
|
|
242
|
+
children: [C("tourPreview.nextFooter"), /* @__PURE__ */ _(f, { size: 20 })]
|
|
240
243
|
})
|
|
241
244
|
]
|
|
242
245
|
})
|
|
@@ -244,6 +247,6 @@ function x() {
|
|
|
244
247
|
});
|
|
245
248
|
}
|
|
246
249
|
//#endregion
|
|
247
|
-
export {
|
|
250
|
+
export { C as TourPreviewPage };
|
|
248
251
|
|
|
249
252
|
//# sourceMappingURL=TourPreviewPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TourPreviewPage.js","names":[],"sources":["../../../src/tours/pages/TourPreviewPage.tsx"],"sourcesContent":["import { useEffect } from 'react';\nimport { useParams, useNavigate } from 'react-router-dom';\nimport {\n ArrowLeft,\n ChevronLeft,\n ChevronRight,\n X,\n Smartphone,\n Tablet,\n Monitor,\n CheckCircle,\n AlertCircle,\n} from 'lucide-react';\nimport { useTourPreview } from '../hooks/useTourPreview';\nimport { useTourBuilder } from '../hooks/useTourBuilder';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { useToursStore } from '../store/toursStore';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport { useToursI18n } from '../i18n';\n\n/**\n * Tour preview page\n * Preview tour with device simulation and validation\n */\nexport function TourPreviewPage() {\n const { tr } = useToursI18n();\n const { tourId } = useParams();\n const navigate = useNavigate();\n const { basePath = '/' } = useToursContext();\n const { hasPermission } = useToursPermissionAccess();\n const canReadTour = hasPermission(TOUR_PERMISSIONS.TOUR_READ);\n const { tour, loadTour } = useTourBuilder(tourId);\n const { devicePreview } = useToursStore();\n\n const {\n isPreviewActive,\n currentStepIndex,\n currentStep,\n totalSteps,\n canGoNext,\n canGoPrevious,\n validationResults,\n startPreview,\n stopPreview,\n nextStep,\n previousStep,\n changeDevice,\n validateForPreview,\n } = useTourPreview(tour || undefined);\n\n useEffect(() => {\n if (tourId) {\n loadTour(tourId);\n }\n }, [tourId, loadTour]);\n\n useEffect(() => {\n if (tour) {\n validateForPreview();\n }\n }, [tour, devicePreview, validateForPreview]);\n\n if (!canReadTour) {\n return (\n <div className=\"flex items-center justify-center h-screen bg-muted\">\n <div className=\"text-center\">\n <h2 className=\"text-lg font-semibold text-foreground mb-2\">\n {tr('tourPreview.accessDeniedTitle')}\n </h2>\n <p className=\"text-sm text-muted-foreground\">{tr('tourPreview.accessDeniedMessage')}</p>\n </div>\n </div>\n );\n }\n\n if (!tour) {\n return (\n <div className=\"flex items-center justify-center h-screen bg-muted\">\n <p className=\"text-muted-foreground\">{tr('tourPreview.loading')}</p>\n </div>\n );\n }\n\n const handleBack = () => {\n navigate(`${basePath}/${tourId}/edit`);\n };\n\n const deviceIcons = {\n mobile: <Smartphone size={20} />,\n tablet: <Tablet size={20} />,\n desktop: <Monitor size={20} />,\n };\n\n return (\n <div className=\"flex flex-col h-screen bg-muted\">\n {/* Header */}\n <div className=\"border-b border-border bg-background p-3 sm:p-4 flex flex-wrap items-center gap-3 sm:gap-4\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"p-2 min-h-[44px] min-w-[44px] hover:bg-accent rounded-md\"\n aria-label={tr('tourBuilder.goBack')}\n >\n <ArrowLeft size={20} />\n </button>\n <div className=\"flex-1 min-w-[12rem]\">\n <h1 className=\"text-base sm:text-lg font-semibold truncate\">\n {tour?.name} - {tr('tourPreview.previewSuffix')}\n </h1>\n {isPreviewActive && (\n <p className=\"text-sm text-muted-foreground\">\n {tr('tourPreview.stepOf')} {currentStepIndex + 1} {tr('tourPreview.stepOfConnector')}{' '}\n {totalSteps}\n </p>\n )}\n </div>\n\n {/* Device Selector */}\n <div className=\"flex gap-2 border border-border rounded-md overflow-hidden\">\n {(['mobile', 'tablet', 'desktop'] as const).map((device) => (\n <button\n type=\"button\"\n key={device}\n onClick={() => changeDevice(device)}\n className={`px-3 py-2 min-h-[44px] min-w-[44px] ${\n devicePreview === device\n ? 'bg-primary text-primary-foreground'\n : 'bg-background hover:bg-accent'\n }`}\n title={\n device === 'mobile'\n ? tr('tourPreview.deviceMobile')\n : device === 'tablet'\n ? tr('tourPreview.deviceTablet')\n : tr('tourPreview.deviceDesktop')\n }\n aria-label={\n device === 'mobile'\n ? tr('tourPreview.deviceMobile')\n : device === 'tablet'\n ? tr('tourPreview.deviceTablet')\n : tr('tourPreview.deviceDesktop')\n }\n >\n {deviceIcons[device]}\n </button>\n ))}\n </div>\n\n {/* Preview Controls */}\n {!isPreviewActive ? (\n <button\n type=\"button\"\n onClick={startPreview}\n disabled={!validationResults?.valid}\n className=\"px-4 py-2 min-h-[44px] bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50\"\n >\n {tr('tourPreview.startPreview')}\n </button>\n ) : (\n <button\n type=\"button\"\n onClick={stopPreview}\n className=\"px-4 py-2 min-h-[44px] border border-border rounded-md hover:bg-accent flex items-center gap-2\"\n >\n <X size={20} />\n {tr('tourPreview.stopPreview')}\n </button>\n )}\n </div>\n\n {/* Validation Results */}\n {validationResults && !validationResults.valid && (\n <div className=\"bg-destructive/10 border-b border-destructive px-3 sm:px-6 py-3\">\n <div className=\"flex items-start gap-3\">\n <AlertCircle className=\"text-destructive flex-shrink-0 mt-0.5\" size={20} />\n <div className=\"flex-1\">\n <h3 className=\"font-semibold text-destructive mb-1\">\n {tr('tourPreview.validationErrorsTitle')}\n </h3>\n <ul className=\"list-disc list-inside space-y-1\">\n {validationResults.errors.map((error) => (\n <li key={error} className=\"text-sm text-destructive\">\n {error}\n </li>\n ))}\n </ul>\n </div>\n </div>\n </div>\n )}\n\n {/* Warnings */}\n {validationResults && validationResults.warnings.length > 0 && (\n <div className=\"bg-warning/10 border-b border-warning px-3 sm:px-6 py-3\">\n <div className=\"flex items-start gap-3\">\n <AlertCircle className=\"text-warning flex-shrink-0 mt-0.5\" size={20} />\n <div className=\"flex-1\">\n <h3 className=\"font-semibold text-warning mb-1\">{tr('tourPreview.warningsTitle')}</h3>\n <ul className=\"list-disc list-inside space-y-1\">\n {validationResults.warnings.map((warning) => (\n <li key={warning} className=\"text-sm text-warning\">\n {warning}\n </li>\n ))}\n </ul>\n </div>\n </div>\n </div>\n )}\n\n {/* Preview Area */}\n <div className=\"flex-1 flex items-center justify-center p-3 sm:p-6 overflow-auto\">\n <div\n className={`bg-background border-2 rounded-lg shadow-xl overflow-hidden ${\n devicePreview === 'mobile'\n ? 'w-[min(375px,calc(100vw-1.5rem))] h-[667px] max-h-full'\n : devicePreview === 'tablet'\n ? 'w-[min(768px,calc(100vw-1.5rem))] h-[1024px] max-h-full'\n : 'w-full max-w-[1920px] h-full max-h-[1080px]'\n }`}\n >\n {isPreviewActive && currentStep ? (\n <div className=\"h-full flex flex-col items-center justify-center p-4 sm:p-8\">\n {/* Simulated Tour Tooltip */}\n <div className=\"max-w-md border border-border rounded-lg shadow-lg bg-card p-4 sm:p-6\">\n <h3 className=\"text-lg font-semibold mb-3\">{currentStep.title}</h3>\n <p className=\"text-sm text-muted-foreground mb-4 whitespace-pre-wrap\">\n {currentStep.content}\n </p>\n <div className=\"flex gap-2\">\n <button\n type=\"button\"\n onClick={previousStep}\n disabled={!canGoPrevious}\n className=\"px-3 py-2 min-h-[44px] min-w-[44px] border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed\"\n aria-label={tr('tourPreview.previous')}\n >\n <ChevronLeft size={16} />\n </button>\n <button\n type=\"button\"\n onClick={nextStep}\n disabled={!canGoNext}\n className=\"flex-1 px-3 py-2 min-h-[44px] bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {canGoNext ? tr('tourPreview.next') : tr('tourPreview.finish')}\n </button>\n </div>\n </div>\n </div>\n ) : (\n <div className=\"h-full flex items-center justify-center text-muted-foreground\">\n <div className=\"text-center\">\n <CheckCircle className=\"mx-auto mb-4\" size={48} />\n <p className=\"mb-2\">{tr('tourPreview.readyTitle')}</p>\n <p className=\"text-sm\">{tr('tourPreview.readyHint')}</p>\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* Footer Controls */}\n {isPreviewActive && (\n <div className=\"border-t border-border bg-background p-3 sm:p-4 flex items-center justify-center gap-3 sm:gap-4\">\n <button\n type=\"button\"\n onClick={previousStep}\n disabled={!canGoPrevious}\n className=\"px-4 py-2 min-h-[44px] border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2\"\n >\n <ChevronLeft size={20} />\n {tr('tourPreview.previous')}\n </button>\n <div className=\"text-sm text-muted-foreground\">\n {currentStepIndex + 1} / {totalSteps}\n </div>\n <button\n type=\"button\"\n onClick={nextStep}\n disabled={!canGoNext}\n className=\"px-4 py-2 min-h-[44px] border border-border rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2\"\n >\n {tr('tourPreview.nextFooter')}\n <ChevronRight size={20} />\n </button>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TourPreviewPage.js","names":[],"sources":["../../../src/tours/pages/TourPreviewPage.tsx"],"sourcesContent":["import { useEffect } from 'react';\nimport { useParams, useNavigate } from 'react-router-dom';\nimport {\n ArrowLeft,\n ChevronLeft,\n ChevronRight,\n X,\n Smartphone,\n Tablet,\n Monitor,\n CheckCircle,\n AlertCircle,\n} from 'lucide-react';\nimport { Button, GlassCard } from '@burdenoff/fe-libs/ui';\nimport { useTourPreview } from '../hooks/useTourPreview';\nimport { useTourBuilder } from '../hooks/useTourBuilder';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { useToursStore } from '../store/toursStore';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport { useToursI18n } from '../i18n';\n\n/**\n * Tour preview page\n * Preview tour with device simulation and validation\n */\nexport function TourPreviewPage() {\n const { tr } = useToursI18n();\n const { tourId } = useParams();\n const navigate = useNavigate();\n const { basePath = '/' } = useToursContext();\n const { hasPermission } = useToursPermissionAccess();\n const canReadTour = hasPermission(TOUR_PERMISSIONS.TOUR_READ);\n const { tour, loadTour } = useTourBuilder(tourId);\n const { devicePreview } = useToursStore();\n\n const {\n isPreviewActive,\n currentStepIndex,\n currentStep,\n totalSteps,\n canGoNext,\n canGoPrevious,\n validationResults,\n startPreview,\n stopPreview,\n nextStep,\n previousStep,\n changeDevice,\n validateForPreview,\n } = useTourPreview(tour || undefined);\n\n useEffect(() => {\n if (tourId) {\n loadTour(tourId);\n }\n }, [tourId, loadTour]);\n\n useEffect(() => {\n if (tour) {\n validateForPreview();\n }\n }, [tour, devicePreview, validateForPreview]);\n\n if (!canReadTour) {\n return (\n <div className=\"flex items-center justify-center h-screen bg-bg-sunken\">\n <div className=\"text-center\">\n <h2 className=\"text-lg font-semibold text-text-primary mb-2\">\n {tr('tourPreview.accessDeniedTitle')}\n </h2>\n <p className=\"text-sm text-text-secondary\">{tr('tourPreview.accessDeniedMessage')}</p>\n </div>\n </div>\n );\n }\n\n if (!tour) {\n return (\n <div className=\"flex items-center justify-center h-screen bg-bg-sunken\">\n <p className=\"text-text-secondary\">{tr('tourPreview.loading')}</p>\n </div>\n );\n }\n\n const handleBack = () => {\n navigate(`${basePath}/${tourId}/edit`);\n };\n\n const deviceIcons = {\n mobile: <Smartphone size={20} />,\n tablet: <Tablet size={20} />,\n desktop: <Monitor size={20} />,\n };\n\n return (\n <div className=\"flex flex-col h-screen bg-bg-sunken\">\n {/* Header */}\n <div className=\"border-b border-border-subtle bg-bg-surface p-3 sm:p-4 flex flex-wrap items-center gap-3 sm:gap-4\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"p-2 min-h-[44px] min-w-[44px] hover:bg-accent rounded-md\"\n aria-label={tr('tourBuilder.goBack')}\n >\n <ArrowLeft size={20} />\n </button>\n <div className=\"flex-1 min-w-[12rem]\">\n <h1 className=\"text-base sm:text-lg font-semibold truncate\">\n {tour?.name} - {tr('tourPreview.previewSuffix')}\n </h1>\n {isPreviewActive && (\n <p className=\"text-sm text-text-secondary\">\n {tr('tourPreview.stepOf')} {currentStepIndex + 1} {tr('tourPreview.stepOfConnector')}{' '}\n {totalSteps}\n </p>\n )}\n </div>\n\n {/* Device Selector */}\n <div className=\"flex gap-2 border border-border-subtle rounded-md overflow-hidden\">\n {(['mobile', 'tablet', 'desktop'] as const).map((device) => (\n <button\n type=\"button\"\n key={device}\n onClick={() => changeDevice(device)}\n className={`px-3 py-2 min-h-[44px] min-w-[44px] ${\n devicePreview === device\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-surface hover:bg-accent'\n }`}\n title={\n device === 'mobile'\n ? tr('tourPreview.deviceMobile')\n : device === 'tablet'\n ? tr('tourPreview.deviceTablet')\n : tr('tourPreview.deviceDesktop')\n }\n aria-label={\n device === 'mobile'\n ? tr('tourPreview.deviceMobile')\n : device === 'tablet'\n ? tr('tourPreview.deviceTablet')\n : tr('tourPreview.deviceDesktop')\n }\n >\n {deviceIcons[device]}\n </button>\n ))}\n </div>\n\n {/* Preview Controls */}\n {!isPreviewActive ? (\n <Button\n type=\"button\"\n onClick={startPreview}\n disabled={!validationResults?.valid}\n className=\"min-h-[44px]\"\n >\n {tr('tourPreview.startPreview')}\n </Button>\n ) : (\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={stopPreview}\n className=\"min-h-[44px]\"\n >\n <X size={20} />\n {tr('tourPreview.stopPreview')}\n </Button>\n )}\n </div>\n\n {/* Validation Results */}\n {validationResults && !validationResults.valid && (\n <div className=\"bg-status-error-bg/10 border-b border-status-error-border px-3 sm:px-6 py-3\">\n <div className=\"flex items-start gap-3\">\n <AlertCircle className=\"text-status-error-text flex-shrink-0 mt-0.5\" size={20} />\n <div className=\"flex-1\">\n <h3 className=\"font-semibold text-status-error-text mb-1\">\n {tr('tourPreview.validationErrorsTitle')}\n </h3>\n <ul className=\"list-disc list-inside space-y-1\">\n {validationResults.errors.map((error) => (\n <li key={error} className=\"text-sm text-status-error-text\">\n {error}\n </li>\n ))}\n </ul>\n </div>\n </div>\n </div>\n )}\n\n {/* Warnings */}\n {validationResults && validationResults.warnings.length > 0 && (\n <div className=\"bg-warning/10 border-b border-warning px-3 sm:px-6 py-3\">\n <div className=\"flex items-start gap-3\">\n <AlertCircle className=\"text-warning flex-shrink-0 mt-0.5\" size={20} />\n <div className=\"flex-1\">\n <h3 className=\"font-semibold text-warning mb-1\">{tr('tourPreview.warningsTitle')}</h3>\n <ul className=\"list-disc list-inside space-y-1\">\n {validationResults.warnings.map((warning) => (\n <li key={warning} className=\"text-sm text-warning\">\n {warning}\n </li>\n ))}\n </ul>\n </div>\n </div>\n </div>\n )}\n\n {/* Preview Area */}\n <div className=\"flex-1 flex items-center justify-center p-3 sm:p-6 overflow-auto\">\n <div\n className={`bg-bg-surface border-2 rounded-lg shadow-xl overflow-hidden ${\n devicePreview === 'mobile'\n ? 'w-[min(375px,calc(100vw-1.5rem))] h-[667px] max-h-full'\n : devicePreview === 'tablet'\n ? 'w-[min(768px,calc(100vw-1.5rem))] h-[1024px] max-h-full'\n : 'w-full max-w-[1920px] h-full max-h-[1080px]'\n }`}\n >\n {isPreviewActive && currentStep ? (\n <div className=\"h-full flex flex-col items-center justify-center p-4 sm:p-8\">\n {/* Simulated Tour Tooltip */}\n <GlassCard\n treatment=\"glass\"\n className=\"max-w-md border-border-seam p-4 sm:p-6 shadow-[var(--shadow-pop)]\"\n >\n <h3 className=\"text-lg font-semibold mb-3\">{currentStep.title}</h3>\n <p className=\"text-sm text-text-secondary mb-4 whitespace-pre-wrap\">\n {currentStep.content}\n </p>\n <div className=\"flex gap-2\">\n <button\n type=\"button\"\n onClick={previousStep}\n disabled={!canGoPrevious}\n className=\"px-3 py-2 min-h-[44px] min-w-[44px] border border-border-subtle rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed\"\n aria-label={tr('tourPreview.previous')}\n >\n <ChevronLeft size={16} />\n </button>\n <button\n type=\"button\"\n onClick={nextStep}\n disabled={!canGoNext}\n className=\"flex-1 px-3 py-2 min-h-[44px] bg-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg/90 disabled:opacity-50 disabled:cursor-not-allowed\"\n >\n {canGoNext ? tr('tourPreview.next') : tr('tourPreview.finish')}\n </button>\n </div>\n </GlassCard>\n </div>\n ) : (\n <div className=\"h-full flex items-center justify-center text-text-secondary\">\n <div className=\"text-center\">\n <CheckCircle className=\"mx-auto mb-4\" size={48} />\n <p className=\"mb-2\">{tr('tourPreview.readyTitle')}</p>\n <p className=\"text-sm\">{tr('tourPreview.readyHint')}</p>\n </div>\n </div>\n )}\n </div>\n </div>\n\n {/* Footer Controls */}\n {isPreviewActive && (\n <div className=\"border-t border-border-subtle bg-bg-surface p-3 sm:p-4 flex items-center justify-center gap-3 sm:gap-4\">\n <button\n type=\"button\"\n onClick={previousStep}\n disabled={!canGoPrevious}\n className=\"px-4 py-2 min-h-[44px] border border-border-subtle rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2\"\n >\n <ChevronLeft size={20} />\n {tr('tourPreview.previous')}\n </button>\n <div className=\"text-sm text-text-secondary\">\n {currentStepIndex + 1} / {totalSteps}\n </div>\n <button\n type=\"button\"\n onClick={nextStep}\n disabled={!canGoNext}\n className=\"px-4 py-2 min-h-[44px] border border-border-subtle rounded-md hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2\"\n >\n {tr('tourPreview.nextFooter')}\n <ChevronRight size={20} />\n </button>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
|