@burdenoff/microfe-tours 2026.830.1 → 2026.918.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 (47) hide show
  1. package/dist/tours/ToursAdminRoot.js +28 -27
  2. package/dist/tours/ToursAdminRoot.js.map +1 -1
  3. package/dist/tours/ToursAdminRoutes.js +56 -55
  4. package/dist/tours/ToursAdminRoutes.js.map +1 -1
  5. package/dist/tours/ToursUserRoot.js +34 -29
  6. package/dist/tours/ToursUserRoot.js.map +1 -1
  7. package/dist/tours/ToursUserRoutes.js +33 -33
  8. package/dist/tours/ToursUserRoutes.js.map +1 -1
  9. package/dist/tours/components/MarkdownEditor.js +85 -80
  10. package/dist/tours/components/MarkdownEditor.js.map +1 -1
  11. package/dist/tours/components/RouteHelpers.js +47 -42
  12. package/dist/tours/components/RouteHelpers.js.map +1 -1
  13. package/dist/tours/components/ToursAdminNavRegistrar.js +32 -27
  14. package/dist/tours/components/ToursAdminNavRegistrar.js.map +1 -1
  15. package/dist/tours/hooks/useStepSequencer.js +45 -36
  16. package/dist/tours/hooks/useStepSequencer.js.map +1 -1
  17. package/dist/tours/hooks/useTourBuilder.js +106 -93
  18. package/dist/tours/hooks/useTourBuilder.js.map +1 -1
  19. package/dist/tours/hooks/useTourPreview.js +51 -41
  20. package/dist/tours/hooks/useTourPreview.js.map +1 -1
  21. package/dist/tours/hooks/useToursList.js +28 -27
  22. package/dist/tours/hooks/useToursList.js.map +1 -1
  23. package/dist/tours/i18n.js +187 -5
  24. package/dist/tours/i18n.js.map +1 -1
  25. package/dist/tours/pages/AnalyticsDashboardPage.js +108 -109
  26. package/dist/tours/pages/AnalyticsDashboardPage.js.map +1 -1
  27. package/dist/tours/pages/MediaLibraryPage.js +58 -61
  28. package/dist/tours/pages/MediaLibraryPage.js.map +1 -1
  29. package/dist/tours/pages/MyToursPage.js +5 -5
  30. package/dist/tours/pages/MyToursProgressPage.js +5 -5
  31. package/dist/tours/pages/SchedulerPage.js +78 -81
  32. package/dist/tours/pages/SchedulerPage.js.map +1 -1
  33. package/dist/tours/pages/StepEditorPage.js +32 -32
  34. package/dist/tours/pages/StepEditorPage.js.map +1 -1
  35. package/dist/tours/pages/SystemAnalyticsPage.js +75 -79
  36. package/dist/tours/pages/SystemAnalyticsPage.js.map +1 -1
  37. package/dist/tours/pages/TemplateLibraryPage.js +8 -8
  38. package/dist/tours/pages/TourBuilderPage.js +295 -279
  39. package/dist/tours/pages/TourBuilderPage.js.map +1 -1
  40. package/dist/tours/pages/TourPreviewPage.js +6 -6
  41. package/dist/tours/pages/ToursListPage.js +155 -155
  42. package/dist/tours/pages/ToursListPage.js.map +1 -1
  43. package/dist/tours/store/toursStore.js +11 -7
  44. package/dist/tours/store/toursStore.js.map +1 -1
  45. package/dist/tours/utils/index.js +32 -19
  46. package/dist/tours/utils/index.js.map +1 -1
  47. package/package.json +1 -1
@@ -1,285 +1,285 @@
1
- import { useToursContext as e } from "../providers/ToursProvider.js";
2
- import { useToursStore as t } from "../store/toursStore.js";
3
- import { useDeleteTourMutation as n } from "../../generated/global-operations.js";
4
- import { useToursList as r } from "../hooks/useToursList.js";
5
- import { useTourLifecycle as i } from "../hooks/useTourLifecycle.js";
6
- import { useToursPermissionAccess as a } from "../hooks/useToursPermissionAccess.js";
7
- import { TOUR_PERMISSIONS as o } from "../../constants/permissions.js";
8
- import { useToursI18n as s } from "../i18n.js";
9
- import { isNative as c, nativeConfirm as l, nativeImpact as u, nativeNotify as d, nativeToast as f } from "../../utils/nativeBridge.js";
10
- import { useEffect as p, useState as m } from "react";
11
- import { Markdown as h, PermissionGate as g } from "@burdenoff/fe-libs/shared/components";
12
- import { Eye as _, Grid as v, List as y, ListOrdered as b, Plus as x, Search as S, Settings as C } from "lucide-react";
13
- import { jsx as w, jsxs as T } from "react/jsx-runtime";
14
- import { useNavigate as E } from "react-router";
15
- import { AuroraBackground as D, Button as O, CTAOverflowMenu as ee, GlassCard as k, GradientText as te, IllustratedEmptyState as A, PagePurpose as j } from "@burdenoff/fe-libs/ui";
1
+ import { useToursI18n as e } from "../i18n.js";
2
+ import { useToursContext as t } from "../providers/ToursProvider.js";
3
+ import { useToursStore as n } from "../store/toursStore.js";
4
+ import { useDeleteTourMutation as r } from "../../generated/global-operations.js";
5
+ import { useToursList as i } from "../hooks/useToursList.js";
6
+ import { useTourLifecycle as a } from "../hooks/useTourLifecycle.js";
7
+ import { useToursPermissionAccess as o } from "../hooks/useToursPermissionAccess.js";
8
+ import { TOUR_PERMISSIONS as s } from "../../constants/permissions.js";
9
+ import { isNative as c, nativeConfirm as ee, nativeImpact as l, nativeNotify as u, nativeToast as d } from "../../utils/nativeBridge.js";
10
+ import { useEffect as f, useState as p } from "react";
11
+ import { Markdown as m, PermissionGate as h } from "@burdenoff/fe-libs/shared/components";
12
+ import { Eye as g, Grid as _, List as v, ListOrdered as y, Plus as b, Search as x, Settings as S } from "lucide-react";
13
+ import { jsx as C, jsxs as w } from "react/jsx-runtime";
14
+ import { useNavigate as T } from "react-router";
15
+ import { AuroraBackground as E, Button as D, CTAOverflowMenu as te, GlassCard as O, GradientText as ne, IllustratedEmptyState as k, PagePurpose as A } from "@burdenoff/fe-libs/ui";
16
16
  //#region src/tours/pages/ToursListPage.tsx
17
- function M() {
18
- let { tr: M } = s(), N = E(), { basePath: P = "/" } = e(), { viewMode: F, tourFilter: I, toursListRevision: L, setViewMode: R, updateTourFilter: z, notifyToursListChanged: B } = t(), { hasPermission: V, isLoading: H } = a(), U = V(o.TOUR_UPDATE), W = V(o.TOUR_STEP_UPDATE), G = V(o.TOUR_READ), K = V(o.TOUR_DELETE), q = V(o.TOUR_PUBLISH), J = V(o.TOUR_ARCHIVE), Y = V(o.TOUR_DUPLICATE), { tours: X, loading: Z, fetchTours: Q } = r(), { publishTour: ne, unpublishTour: re, archiveTour: ie, duplicateTour: ae } = i(), [oe] = n(), [se, ce] = m(""), [le, ue] = m("all");
19
- p(() => {
20
- H || Q({ ...I });
17
+ function j() {
18
+ let { tr: j } = e(), M = T(), { basePath: N = "/" } = t(), { viewMode: P, tourFilter: F, toursListRevision: I, setViewMode: L, updateTourFilter: R, notifyToursListChanged: z } = n(), { hasPermission: B, isLoading: V } = o(), H = B(s.TOUR_UPDATE), U = B(s.TOUR_STEP_UPDATE), W = B(s.TOUR_READ), G = B(s.TOUR_DELETE), K = B(s.TOUR_PUBLISH), q = B(s.TOUR_ARCHIVE), J = B(s.TOUR_DUPLICATE), { tours: Y, loading: X, fetchTours: Z } = i(), { publishTour: re, unpublishTour: ie, archiveTour: ae, duplicateTour: oe } = a(), [se] = r(), [ce, le] = p(""), [ue, de] = p("all");
19
+ f(() => {
20
+ V || Z({ ...F });
21
21
  }, [
22
- Q,
22
+ Z,
23
+ F,
23
24
  I,
24
- L,
25
- H
25
+ V
26
26
  ]);
27
- let de = (e) => {
28
- ce(e), z({ search: e });
29
- }, fe = (e) => {
30
- ue(e), z({ status: e });
31
- }, $ = () => {
32
- N(P.endsWith("/") ? `${P}new` : `${P}/new`);
27
+ let fe = (e) => {
28
+ le(e), R({ search: e });
33
29
  }, pe = (e) => {
30
+ de(e), R({ status: e });
31
+ }, Q = () => {
32
+ M(N.endsWith("/") ? `${N}new` : `${N}/new`);
33
+ }, me = (e) => {
34
34
  switch (e) {
35
- case "DRAFT": return M("toursList.statusDraft");
36
- case "PUBLISHED": return M("toursList.statusPublished");
37
- case "ARCHIVED": return M("toursList.statusArchived");
38
- case "SCHEDULED": return M("toursList.statusScheduled");
35
+ case "DRAFT": return j("toursList.statusDraft");
36
+ case "PUBLISHED": return j("toursList.statusPublished");
37
+ case "ARCHIVED": return j("toursList.statusArchived");
38
+ case "SCHEDULED": return j("toursList.statusScheduled");
39
39
  }
40
- }, me = async (e) => {
41
- u("light");
40
+ }, he = async (e) => {
41
+ l("light");
42
42
  try {
43
- await ne(e), d("success");
43
+ await re(e), u("success");
44
44
  } catch {
45
- d("error"), c() ? f(M("toursList.errorPublish")) : alert(M("toursList.errorPublish"));
45
+ u("error"), c() ? d(j("toursList.errorPublish")) : alert(j("toursList.errorPublish"));
46
46
  }
47
- }, he = async (e) => {
48
- u("light");
47
+ }, $ = async (e) => {
48
+ l("light");
49
49
  try {
50
- await re(e), d("success");
50
+ await ie(e), u("success");
51
51
  } catch {
52
- d("error"), c() ? f(M("toursList.errorUnpublish")) : alert(M("toursList.errorUnpublish"));
52
+ u("error"), c() ? d(j("toursList.errorUnpublish")) : alert(j("toursList.errorUnpublish"));
53
53
  }
54
54
  }, ge = async (e) => {
55
- u("light");
55
+ l("light");
56
56
  try {
57
- await ie(e), d("success");
57
+ await ae(e), u("success");
58
58
  } catch {
59
- d("error"), c() ? f(M("toursList.errorArchive")) : alert(M("toursList.errorArchive"));
59
+ u("error"), c() ? d(j("toursList.errorArchive")) : alert(j("toursList.errorArchive"));
60
60
  }
61
61
  }, _e = async (e) => {
62
- u("light");
62
+ l("light");
63
63
  try {
64
- await ae(e), d("success");
64
+ await oe(e), u("success");
65
65
  } catch {
66
- d("error"), c() ? f(M("toursList.errorDuplicate")) : alert(M("toursList.errorDuplicate"));
66
+ u("error"), c() ? d(j("toursList.errorDuplicate")) : alert(j("toursList.errorDuplicate"));
67
67
  }
68
68
  }, ve = async (e) => {
69
- u("medium");
70
- let t = M("toursList.confirmDelete"), n = await l({
71
- title: M("toursList.actionDelete"),
69
+ l("medium");
70
+ let t = j("toursList.confirmDelete"), n = await ee({
71
+ title: j("toursList.actionDelete"),
72
72
  message: t,
73
- okButtonTitle: M("toursList.actionDelete")
73
+ okButtonTitle: j("toursList.actionDelete")
74
74
  });
75
75
  if (n === null ? window.confirm(t) : n) try {
76
- await oe({ variables: { id: e } }), B(), d("success");
76
+ await se({ variables: { id: e } }), z(), u("success");
77
77
  } catch {
78
- d("error"), c() ? f(M("toursList.errorDelete")) : alert(M("toursList.errorDelete"));
78
+ u("error"), c() ? d(j("toursList.errorDelete")) : alert(j("toursList.errorDelete"));
79
79
  }
80
80
  };
81
- return /* @__PURE__ */ T("div", {
81
+ return /* @__PURE__ */ w("div", {
82
82
  className: "space-y-4 sm:space-y-6 p-3 sm:p-6",
83
83
  children: [
84
- /* @__PURE__ */ T("div", {
84
+ /* @__PURE__ */ w("div", {
85
85
  className: "relative overflow-hidden rounded-xl",
86
- children: [/* @__PURE__ */ w(D, { intensity: "subtle" }), /* @__PURE__ */ T("div", {
86
+ children: [/* @__PURE__ */ C(E, { intensity: "subtle" }), /* @__PURE__ */ w("div", {
87
87
  className: "flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 p-1 sm:p-2",
88
- children: [/* @__PURE__ */ T("div", {
88
+ children: [/* @__PURE__ */ w("div", {
89
89
  className: "flex-1 min-w-0",
90
- children: [/* @__PURE__ */ w("h1", {
90
+ children: [/* @__PURE__ */ C("h1", {
91
91
  className: "text-xl sm:text-2xl font-bold text-text-primary",
92
- children: /* @__PURE__ */ w(te, { children: M("toursList.title") })
93
- }), /* @__PURE__ */ w("p", {
92
+ children: /* @__PURE__ */ C(ne, { children: j("toursList.title") })
93
+ }), /* @__PURE__ */ C("p", {
94
94
  className: "text-sm sm:text-base text-text-secondary",
95
- children: M("toursList.subtitle")
95
+ children: j("toursList.subtitle")
96
96
  })]
97
- }), /* @__PURE__ */ w(g, {
98
- permission: o.TOUR_CREATE,
99
- children: /* @__PURE__ */ T(O, {
97
+ }), /* @__PURE__ */ C(h, {
98
+ permission: s.TOUR_CREATE,
99
+ children: /* @__PURE__ */ w(D, {
100
100
  type: "button",
101
- onClick: $,
101
+ onClick: Q,
102
102
  className: "w-full sm:w-auto min-h-[44px]",
103
- children: [/* @__PURE__ */ w(x, { size: 20 }), M("toursList.createTour")]
103
+ children: [/* @__PURE__ */ C(b, { size: 20 }), j("toursList.createTour")]
104
104
  })
105
105
  })]
106
106
  })]
107
107
  }),
108
- /* @__PURE__ */ w(j, { children: M("toursList.purpose") }),
109
- /* @__PURE__ */ T("div", {
108
+ /* @__PURE__ */ C(A, { children: j("toursList.purpose") }),
109
+ /* @__PURE__ */ w("div", {
110
110
  className: "flex flex-col sm:flex-row gap-3 sm:gap-4",
111
- children: [/* @__PURE__ */ T("div", {
111
+ children: [/* @__PURE__ */ w("div", {
112
112
  className: "flex-1 relative",
113
- children: [/* @__PURE__ */ w(S, {
113
+ children: [/* @__PURE__ */ C(x, {
114
114
  className: "absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary",
115
115
  size: 20
116
- }), /* @__PURE__ */ w("input", {
116
+ }), /* @__PURE__ */ C("input", {
117
117
  type: "text",
118
- placeholder: M("toursList.searchPlaceholder"),
119
- value: se,
120
- onChange: (e) => de(e.target.value),
118
+ placeholder: j("toursList.searchPlaceholder"),
119
+ value: ce,
120
+ onChange: (e) => fe(e.target.value),
121
121
  className: "w-full pl-[3.25rem] pr-4 py-2 min-h-[44px] border border-border-subtle rounded-md bg-bg-surface text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]",
122
- "aria-label": M("toursList.searchPlaceholder")
122
+ "aria-label": j("toursList.searchPlaceholder")
123
123
  })]
124
- }), /* @__PURE__ */ T("div", {
124
+ }), /* @__PURE__ */ w("div", {
125
125
  className: "flex gap-2",
126
- children: [/* @__PURE__ */ T("select", {
127
- value: le,
128
- onChange: (e) => fe(e.target.value),
126
+ children: [/* @__PURE__ */ w("select", {
127
+ value: ue,
128
+ onChange: (e) => pe(e.target.value),
129
129
  className: "px-4 py-2 min-h-[44px] border border-border-subtle rounded-md bg-bg-surface text-text-primary",
130
- "aria-label": M("toursList.statusAll"),
130
+ "aria-label": j("toursList.statusAll"),
131
131
  children: [
132
- /* @__PURE__ */ w("option", {
132
+ /* @__PURE__ */ C("option", {
133
133
  value: "all",
134
- children: M("toursList.statusAll")
134
+ children: j("toursList.statusAll")
135
135
  }),
136
- /* @__PURE__ */ w("option", {
136
+ /* @__PURE__ */ C("option", {
137
137
  value: "DRAFT",
138
- children: M("toursList.statusDraft")
138
+ children: j("toursList.statusDraft")
139
139
  }),
140
- /* @__PURE__ */ w("option", {
140
+ /* @__PURE__ */ C("option", {
141
141
  value: "PUBLISHED",
142
- children: M("toursList.statusPublished")
142
+ children: j("toursList.statusPublished")
143
143
  }),
144
- /* @__PURE__ */ w("option", {
144
+ /* @__PURE__ */ C("option", {
145
145
  value: "ARCHIVED",
146
- children: M("toursList.statusArchived")
146
+ children: j("toursList.statusArchived")
147
147
  }),
148
- /* @__PURE__ */ w("option", {
148
+ /* @__PURE__ */ C("option", {
149
149
  value: "SCHEDULED",
150
- children: M("toursList.statusScheduled")
150
+ children: j("toursList.statusScheduled")
151
151
  })
152
152
  ]
153
- }), /* @__PURE__ */ T("div", {
153
+ }), /* @__PURE__ */ w("div", {
154
154
  className: "flex border border-border-subtle rounded-md overflow-hidden",
155
- children: [/* @__PURE__ */ w("button", {
155
+ children: [/* @__PURE__ */ C("button", {
156
156
  type: "button",
157
- onClick: () => R("grid"),
158
- className: `px-3 py-2 min-h-[44px] ${F === "grid" ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-surface text-text-primary hover:bg-accent"}`,
159
- "aria-label": M("toursList.gridView"),
160
- title: M("toursList.gridView"),
161
- children: /* @__PURE__ */ w(v, { size: 20 })
162
- }), /* @__PURE__ */ w("button", {
157
+ onClick: () => L("grid"),
158
+ className: `px-3 py-2 min-h-[44px] ${P === "grid" ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-surface text-text-primary hover:bg-accent"}`,
159
+ "aria-label": j("toursList.gridView"),
160
+ title: j("toursList.gridView"),
161
+ children: /* @__PURE__ */ C(_, { size: 20 })
162
+ }), /* @__PURE__ */ C("button", {
163
163
  type: "button",
164
- onClick: () => R("list"),
165
- className: `px-3 py-2 min-h-[44px] ${F === "list" ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-surface text-text-primary hover:bg-accent"}`,
166
- "aria-label": M("toursList.listView"),
167
- title: M("toursList.listView"),
168
- children: /* @__PURE__ */ w(y, { size: 20 })
164
+ onClick: () => L("list"),
165
+ className: `px-3 py-2 min-h-[44px] ${P === "list" ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-surface text-text-primary hover:bg-accent"}`,
166
+ "aria-label": j("toursList.listView"),
167
+ title: j("toursList.listView"),
168
+ children: /* @__PURE__ */ C(v, { size: 20 })
169
169
  })]
170
170
  })]
171
171
  })]
172
172
  }),
173
- Z ? /* @__PURE__ */ w("div", {
173
+ X ? /* @__PURE__ */ C("div", {
174
174
  className: "text-center py-12",
175
- children: /* @__PURE__ */ w("p", {
175
+ children: /* @__PURE__ */ C("p", {
176
176
  className: "text-sm sm:text-base text-text-secondary",
177
- children: M("toursList.loading")
177
+ children: j("toursList.loading")
178
178
  })
179
- }) : X.length > 0 ? /* @__PURE__ */ w("div", {
180
- className: F === "grid" ? "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4" : "space-y-3",
181
- children: X.map((e) => {
182
- let t = e.status, n = t === "DRAFT" && q, r = t === "PUBLISHED" && q, i = t !== "ARCHIVED" && J, a = [];
179
+ }) : Y.length > 0 ? /* @__PURE__ */ C("div", {
180
+ className: P === "grid" ? "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4" : "space-y-3",
181
+ children: Y.map((e) => {
182
+ let t = e.status, n = t === "DRAFT" && K, r = t === "PUBLISHED" && K, i = t !== "ARCHIVED" && q, a = [];
183
183
  return n && a.push({
184
- label: M("toursList.actionPublish"),
185
- onSelect: () => void me(e.id)
186
- }), r && a.push({
187
- label: M("toursList.actionUnpublish"),
184
+ label: j("toursList.actionPublish"),
188
185
  onSelect: () => void he(e.id)
189
- }), Y && a.push({
190
- label: M("toursList.actionDuplicate"),
186
+ }), r && a.push({
187
+ label: j("toursList.actionUnpublish"),
188
+ onSelect: () => void $(e.id)
189
+ }), J && a.push({
190
+ label: j("toursList.actionDuplicate"),
191
191
  onSelect: () => void _e(e.id)
192
192
  }), i && a.push({
193
- label: M("toursList.actionArchive"),
193
+ label: j("toursList.actionArchive"),
194
194
  onSelect: () => void ge(e.id)
195
- }), K && a.push({
196
- label: M("toursList.actionDelete"),
195
+ }), G && a.push({
196
+ label: j("toursList.actionDelete"),
197
197
  onSelect: () => void ve(e.id),
198
198
  intent: "destructive"
199
- }), /* @__PURE__ */ T(k, {
199
+ }), /* @__PURE__ */ w(O, {
200
200
  treatment: "plain",
201
201
  className: "p-4 border-border-seam shadow-[var(--shadow-pop)]",
202
202
  children: [
203
- /* @__PURE__ */ T("div", {
203
+ /* @__PURE__ */ w("div", {
204
204
  className: "flex items-start justify-between mb-2",
205
- children: [/* @__PURE__ */ w("h3", {
205
+ children: [/* @__PURE__ */ C("h3", {
206
206
  className: "font-semibold text-text-primary",
207
- children: U ? /* @__PURE__ */ w("button", {
207
+ children: H ? /* @__PURE__ */ C("button", {
208
208
  type: "button",
209
209
  className: "cursor-pointer hover:text-primary bg-transparent border-0 p-0 text-left font-inherit",
210
- onClick: () => N(`${P}/${e.id}/edit`),
210
+ onClick: () => M(`${N}/${e.id}/edit`),
211
211
  children: e.name
212
212
  }) : e.name
213
- }), /* @__PURE__ */ w("span", {
213
+ }), /* @__PURE__ */ C("span", {
214
214
  className: `px-2 py-1 text-xs rounded-full ${e.status === "PUBLISHED" ? "bg-success/10 text-success motion-safe:animate-vc-glow-pulse" : e.status === "DRAFT" ? "bg-bg-sunken text-text-secondary" : "bg-warning/10 text-warning"}`,
215
- children: pe(t)
215
+ children: me(t)
216
216
  })]
217
217
  }),
218
- e.description && /* @__PURE__ */ w(h, {
218
+ e.description && /* @__PURE__ */ C(m, {
219
219
  inline: !0,
220
220
  className: "text-sm text-text-secondary mb-3",
221
221
  children: e.description
222
222
  }),
223
- /* @__PURE__ */ T("div", {
223
+ /* @__PURE__ */ w("div", {
224
224
  className: "flex items-center justify-between text-xs text-text-secondary mb-3",
225
- children: [/* @__PURE__ */ T("span", { children: [
225
+ children: [/* @__PURE__ */ w("span", { children: [
226
226
  e.steps?.length || 0,
227
227
  " ",
228
- M("toursList.steps")
229
- ] }), /* @__PURE__ */ T("span", { children: [
228
+ j("toursList.steps")
229
+ ] }), /* @__PURE__ */ w("span", { children: [
230
230
  e.viewCount,
231
231
  " ",
232
- M("toursList.views")
232
+ j("toursList.views")
233
233
  ] })]
234
234
  }),
235
- /* @__PURE__ */ T("div", {
235
+ /* @__PURE__ */ w("div", {
236
236
  className: "flex flex-wrap items-center gap-2 pt-3 border-t border-border-seam",
237
237
  children: [
238
- W && /* @__PURE__ */ T("button", {
238
+ U && /* @__PURE__ */ w("button", {
239
239
  type: "button",
240
240
  onClick: (t) => {
241
- t.stopPropagation(), N(`${P}/${e.id}/steps`);
241
+ t.stopPropagation(), M(`${N}/${e.id}/steps`);
242
242
  },
243
243
  className: "flex-1 min-w-[6.5rem] px-3 py-2 min-h-[44px] text-xs bg-secondary text-secondary-foreground rounded hover:bg-secondary/80 flex items-center justify-center gap-1.5",
244
- title: M("toursList.editStepsTitle"),
245
- children: [/* @__PURE__ */ w(b, { size: 14 }), M("toursList.stepsButton")]
244
+ title: j("toursList.editStepsTitle"),
245
+ children: [/* @__PURE__ */ C(y, { size: 14 }), j("toursList.stepsButton")]
246
246
  }),
247
- G && /* @__PURE__ */ T("button", {
247
+ W && /* @__PURE__ */ w("button", {
248
248
  type: "button",
249
249
  onClick: (t) => {
250
- t.stopPropagation(), N(`${P}/${e.id}/preview`);
250
+ t.stopPropagation(), M(`${N}/${e.id}/preview`);
251
251
  },
252
252
  className: "flex-1 min-w-[6.5rem] px-3 py-2 min-h-[44px] text-xs border border-border-seam rounded hover:bg-accent flex items-center justify-center gap-1.5",
253
- title: M("toursList.previewTitle"),
254
- children: [/* @__PURE__ */ w(_, { size: 14 }), M("toursList.previewButton")]
253
+ title: j("toursList.previewTitle"),
254
+ children: [/* @__PURE__ */ C(g, { size: 14 }), j("toursList.previewButton")]
255
255
  }),
256
- U && /* @__PURE__ */ w("button", {
256
+ H && /* @__PURE__ */ C("button", {
257
257
  type: "button",
258
258
  onClick: (t) => {
259
- t.stopPropagation(), N(`${P}/${e.id}/edit`);
259
+ t.stopPropagation(), M(`${N}/${e.id}/edit`);
260
260
  },
261
261
  className: "p-2 min-h-[44px] min-w-[44px] text-xs border border-border-seam rounded hover:bg-accent",
262
- title: M("toursList.settingsTitle"),
263
- "aria-label": M("toursList.settingsTitle"),
264
- children: /* @__PURE__ */ w(C, { size: 14 })
262
+ title: j("toursList.settingsTitle"),
263
+ "aria-label": j("toursList.settingsTitle"),
264
+ children: /* @__PURE__ */ C(S, { size: 14 })
265
265
  }),
266
- a.length > 0 && /* @__PURE__ */ w(ee, { actions: a })
266
+ a.length > 0 && /* @__PURE__ */ C(te, { actions: a })
267
267
  ]
268
268
  })
269
269
  ]
270
270
  }, e.id);
271
271
  })
272
- }) : /* @__PURE__ */ w(A, {
272
+ }) : /* @__PURE__ */ C(k, {
273
273
  illustration: "onboarding",
274
- title: M("toursList.emptyTitle"),
275
- description: M("toursList.emptySubtitle"),
276
- action: /* @__PURE__ */ w(g, {
277
- permission: o.TOUR_CREATE,
278
- children: /* @__PURE__ */ T(O, {
274
+ title: j("toursList.emptyTitle"),
275
+ description: j("toursList.emptySubtitle"),
276
+ action: /* @__PURE__ */ C(h, {
277
+ permission: s.TOUR_CREATE,
278
+ children: /* @__PURE__ */ w(D, {
279
279
  type: "button",
280
- onClick: $,
280
+ onClick: Q,
281
281
  className: "min-h-[44px]",
282
- children: [/* @__PURE__ */ w(x, { size: 20 }), M("toursList.createTour")]
282
+ children: [/* @__PURE__ */ C(b, { size: 20 }), j("toursList.createTour")]
283
283
  })
284
284
  })
285
285
  })
@@ -287,6 +287,6 @@ function M() {
287
287
  });
288
288
  }
289
289
  //#endregion
290
- export { M as ToursListPage };
290
+ export { j as ToursListPage };
291
291
 
292
292
  //# sourceMappingURL=ToursListPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ToursListPage.js","names":[],"sources":["../../../src/tours/pages/ToursListPage.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { useNavigate } from 'react-router';\nimport { Plus, Search, Grid, List as ListIcon, ListOrdered, Eye, Settings } from 'lucide-react';\nimport { Markdown, PermissionGate } from '@burdenoff/fe-libs/shared/components';\nimport {\n AuroraBackground,\n Button,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n CTAOverflowMenu,\n type CTAAction,\n} from '@burdenoff/fe-libs/ui';\nimport { useToursList } from '../hooks/useToursList';\nimport { useTourLifecycle } from '../hooks/useTourLifecycle';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { useToursStore } from '../store/toursStore';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { useDeleteTourMutation } from '../../generated/global-operations';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport type { TourStatus } from '../types';\nimport type { Tour } from '../../generated/global-types';\nimport { useToursI18n } from '../i18n';\nimport {\n isNative,\n nativeConfirm,\n nativeImpact,\n nativeNotify,\n nativeToast,\n} from '../../utils/nativeBridge';\n\n/**\n * Tours list page\n * Displays all tours with filtering and search\n */\nexport function ToursListPage() {\n const { tr } = useToursI18n();\n const navigate = useNavigate();\n const { basePath = '/' } = useToursContext();\n const {\n viewMode,\n tourFilter,\n toursListRevision,\n setViewMode,\n updateTourFilter,\n notifyToursListChanged,\n } = useToursStore();\n const { hasPermission, isLoading: permissionsLoading } = useToursPermissionAccess();\n\n const canUpdateTour = hasPermission(TOUR_PERMISSIONS.TOUR_UPDATE);\n const canUpdateTourSteps = hasPermission(TOUR_PERMISSIONS.TOUR_STEP_UPDATE);\n const canPreviewTour = hasPermission(TOUR_PERMISSIONS.TOUR_READ);\n const canDeleteTour = hasPermission(TOUR_PERMISSIONS.TOUR_DELETE);\n const canPublishTour = hasPermission(TOUR_PERMISSIONS.TOUR_PUBLISH);\n const canArchiveTour = hasPermission(TOUR_PERMISSIONS.TOUR_ARCHIVE);\n const canDuplicateTour = hasPermission(TOUR_PERMISSIONS.TOUR_DUPLICATE);\n\n // Fetch tours (includes both workspace-specific and global tours)\n const { tours, loading, fetchTours } = useToursList();\n\n const { publishTour, unpublishTour, archiveTour, duplicateTour } = useTourLifecycle();\n const [deleteTourMutation] = useDeleteTourMutation();\n\n const [searchQuery, setSearchQuery] = useState('');\n const [statusFilter, setStatusFilter] = useState<TourStatus | 'all'>('all');\n\n // Fetch tours when filter changes. The list page is also the user-facing\n // tour browser, so backend permissions remain authoritative for actions while\n // normal users can still see published tours returned by the API.\n useEffect(() => {\n if (permissionsLoading) return;\n fetchTours({ ...tourFilter });\n }, [fetchTours, tourFilter, toursListRevision, permissionsLoading]);\n\n const handleSearch = (query: string) => {\n setSearchQuery(query);\n updateTourFilter({ search: query });\n };\n\n const handleStatusFilter = (status: TourStatus | 'all') => {\n setStatusFilter(status);\n updateTourFilter({ status });\n };\n\n const handleCreateTour = () => {\n const newPath = basePath.endsWith('/') ? `${basePath}new` : `${basePath}/new`;\n navigate(newPath);\n };\n\n const getStatusLabel = (status: TourStatus) => {\n switch (status) {\n case 'DRAFT':\n return tr('toursList.statusDraft');\n case 'PUBLISHED':\n return tr('toursList.statusPublished');\n case 'ARCHIVED':\n return tr('toursList.statusArchived');\n case 'SCHEDULED':\n return tr('toursList.statusScheduled');\n }\n };\n\n const handlePublish = async (id: string) => {\n nativeImpact('light');\n try {\n await publishTour(id);\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n if (isNative()) void nativeToast(tr('toursList.errorPublish'));\n else alert(tr('toursList.errorPublish'));\n }\n };\n\n const handleUnpublish = async (id: string) => {\n nativeImpact('light');\n try {\n await unpublishTour(id);\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n if (isNative()) void nativeToast(tr('toursList.errorUnpublish'));\n else alert(tr('toursList.errorUnpublish'));\n }\n };\n\n const handleArchive = async (id: string) => {\n nativeImpact('light');\n try {\n await archiveTour(id);\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n if (isNative()) void nativeToast(tr('toursList.errorArchive'));\n else alert(tr('toursList.errorArchive'));\n }\n };\n\n const handleDuplicate = async (id: string) => {\n nativeImpact('light');\n try {\n await duplicateTour(id);\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n if (isNative()) void nativeToast(tr('toursList.errorDuplicate'));\n else alert(tr('toursList.errorDuplicate'));\n }\n };\n\n const handleDelete = async (id: string) => {\n nativeImpact('medium');\n const confirmMsg = tr('toursList.confirmDelete');\n const nativeResult = await nativeConfirm({\n title: tr('toursList.actionDelete'),\n message: confirmMsg,\n okButtonTitle: tr('toursList.actionDelete'),\n });\n const confirmed = nativeResult === null ? window.confirm(confirmMsg) : nativeResult;\n if (!confirmed) return;\n try {\n await deleteTourMutation({ variables: { id } });\n notifyToursListChanged();\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n if (isNative()) void nativeToast(tr('toursList.errorDelete'));\n else alert(tr('toursList.errorDelete'));\n }\n };\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n {/* Header */}\n <div className=\"relative overflow-hidden rounded-xl\">\n <AuroraBackground intensity=\"subtle\" />\n <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 p-1 sm:p-2\">\n <div className=\"flex-1 min-w-0\">\n <h1 className=\"text-xl sm:text-2xl font-bold text-text-primary\">\n <GradientText>{tr('toursList.title')}</GradientText>\n </h1>\n <p className=\"text-sm sm:text-base text-text-secondary\">{tr('toursList.subtitle')}</p>\n </div>\n <PermissionGate permission={TOUR_PERMISSIONS.TOUR_CREATE}>\n <Button\n type=\"button\"\n onClick={handleCreateTour}\n className=\"w-full sm:w-auto min-h-[44px]\"\n >\n <Plus size={20} />\n {tr('toursList.createTour')}\n </Button>\n </PermissionGate>\n </div>\n </div>\n\n <PagePurpose>{tr('toursList.purpose')}</PagePurpose>\n\n {/* Filters and Search */}\n <div className=\"flex flex-col sm:flex-row gap-3 sm:gap-4\">\n {/* Search */}\n <div className=\"flex-1 relative\">\n <Search\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary\"\n size={20}\n />\n <input\n type=\"text\"\n placeholder={tr('toursList.searchPlaceholder')}\n value={searchQuery}\n onChange={(e) => handleSearch(e.target.value)}\n className=\"w-full pl-[3.25rem] pr-4 py-2 min-h-[44px] border border-border-subtle rounded-md bg-bg-surface text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n aria-label={tr('toursList.searchPlaceholder')}\n />\n </div>\n\n {/* Status Filter */}\n <div className=\"flex gap-2\">\n <select\n value={statusFilter}\n onChange={(e) => handleStatusFilter(e.target.value as TourStatus | 'all')}\n className=\"px-4 py-2 min-h-[44px] border border-border-subtle rounded-md bg-bg-surface text-text-primary\"\n aria-label={tr('toursList.statusAll')}\n >\n <option value=\"all\">{tr('toursList.statusAll')}</option>\n <option value=\"DRAFT\">{tr('toursList.statusDraft')}</option>\n <option value=\"PUBLISHED\">{tr('toursList.statusPublished')}</option>\n <option value=\"ARCHIVED\">{tr('toursList.statusArchived')}</option>\n <option value=\"SCHEDULED\">{tr('toursList.statusScheduled')}</option>\n </select>\n\n {/* View Mode Toggle */}\n <div className=\"flex border border-border-subtle rounded-md overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => setViewMode('grid')}\n className={`px-3 py-2 min-h-[44px] ${\n viewMode === 'grid'\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-surface text-text-primary hover:bg-accent'\n }`}\n aria-label={tr('toursList.gridView')}\n title={tr('toursList.gridView')}\n >\n <Grid size={20} />\n </button>\n <button\n type=\"button\"\n onClick={() => setViewMode('list')}\n className={`px-3 py-2 min-h-[44px] ${\n viewMode === 'list'\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-surface text-text-primary hover:bg-accent'\n }`}\n aria-label={tr('toursList.listView')}\n title={tr('toursList.listView')}\n >\n <ListIcon size={20} />\n </button>\n </div>\n </div>\n </div>\n\n {/* Tours List */}\n {loading ? (\n <div className=\"text-center py-12\">\n <p className=\"text-sm sm:text-base text-text-secondary\">{tr('toursList.loading')}</p>\n </div>\n ) : tours.length > 0 ? (\n <div\n className={\n viewMode === 'grid'\n ? 'grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4'\n : 'space-y-3'\n }\n >\n {tours.map((tour: Tour) => {\n const status = tour.status as TourStatus;\n const canShowPublishAction = status === 'DRAFT' && canPublishTour;\n const canShowUnpublishAction = status === 'PUBLISHED' && canPublishTour;\n const canShowArchiveAction = status !== 'ARCHIVED' && canArchiveTour;\n\n const overflowActions: CTAAction[] = [];\n if (canShowPublishAction) {\n overflowActions.push({\n label: tr('toursList.actionPublish'),\n onSelect: () => void handlePublish(tour.id),\n });\n }\n if (canShowUnpublishAction) {\n overflowActions.push({\n label: tr('toursList.actionUnpublish'),\n onSelect: () => void handleUnpublish(tour.id),\n });\n }\n if (canDuplicateTour) {\n overflowActions.push({\n label: tr('toursList.actionDuplicate'),\n onSelect: () => void handleDuplicate(tour.id),\n });\n }\n if (canShowArchiveAction) {\n overflowActions.push({\n label: tr('toursList.actionArchive'),\n onSelect: () => void handleArchive(tour.id),\n });\n }\n if (canDeleteTour) {\n overflowActions.push({\n label: tr('toursList.actionDelete'),\n onSelect: () => void handleDelete(tour.id),\n intent: 'destructive',\n });\n }\n\n return (\n <GlassCard\n key={tour.id}\n treatment=\"plain\"\n className=\"p-4 border-border-seam shadow-[var(--shadow-pop)]\"\n >\n <div className=\"flex items-start justify-between mb-2\">\n <h3 className=\"font-semibold text-text-primary\">\n {canUpdateTour ? (\n <button\n type=\"button\"\n className=\"cursor-pointer hover:text-primary bg-transparent border-0 p-0 text-left font-inherit\"\n onClick={() => navigate(`${basePath}/${tour.id}/edit`)}\n >\n {tour.name}\n </button>\n ) : (\n tour.name\n )}\n </h3>\n <span\n className={`px-2 py-1 text-xs rounded-full ${\n tour.status === 'PUBLISHED'\n ? 'bg-success/10 text-success motion-safe:animate-vc-glow-pulse'\n : tour.status === 'DRAFT'\n ? 'bg-bg-sunken text-text-secondary'\n : 'bg-warning/10 text-warning'\n }`}\n >\n {getStatusLabel(status)}\n </span>\n </div>\n {tour.description && (\n <Markdown inline className=\"text-sm text-text-secondary mb-3\">\n {tour.description}\n </Markdown>\n )}\n <div className=\"flex items-center justify-between text-xs text-text-secondary mb-3\">\n <span>\n {tour.steps?.length || 0} {tr('toursList.steps')}\n </span>\n <span>\n {tour.viewCount} {tr('toursList.views')}\n </span>\n </div>\n {/* Quick Actions */}\n <div className=\"flex flex-wrap items-center gap-2 pt-3 border-t border-border-seam\">\n {canUpdateTourSteps && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n navigate(`${basePath}/${tour.id}/steps`);\n }}\n className=\"flex-1 min-w-[6.5rem] px-3 py-2 min-h-[44px] text-xs bg-secondary text-secondary-foreground rounded hover:bg-secondary/80 flex items-center justify-center gap-1.5\"\n title={tr('toursList.editStepsTitle')}\n >\n <ListOrdered size={14} />\n {tr('toursList.stepsButton')}\n </button>\n )}\n {canPreviewTour && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n navigate(`${basePath}/${tour.id}/preview`);\n }}\n className=\"flex-1 min-w-[6.5rem] px-3 py-2 min-h-[44px] text-xs border border-border-seam rounded hover:bg-accent flex items-center justify-center gap-1.5\"\n title={tr('toursList.previewTitle')}\n >\n <Eye size={14} />\n {tr('toursList.previewButton')}\n </button>\n )}\n {canUpdateTour && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n navigate(`${basePath}/${tour.id}/edit`);\n }}\n className=\"p-2 min-h-[44px] min-w-[44px] text-xs border border-border-seam rounded hover:bg-accent\"\n title={tr('toursList.settingsTitle')}\n aria-label={tr('toursList.settingsTitle')}\n >\n <Settings size={14} />\n </button>\n )}\n {/* Lifecycle actions collapsed into the overflow menu */}\n {overflowActions.length > 0 && <CTAOverflowMenu actions={overflowActions} />}\n </div>\n </GlassCard>\n );\n })}\n </div>\n ) : (\n <IllustratedEmptyState\n illustration=\"onboarding\"\n title={tr('toursList.emptyTitle')}\n description={tr('toursList.emptySubtitle')}\n action={\n <PermissionGate permission={TOUR_PERMISSIONS.TOUR_CREATE}>\n <Button type=\"button\" onClick={handleCreateTour} className=\"min-h-[44px]\">\n <Plus size={20} />\n {tr('toursList.createTour')}\n </Button>\n </PermissionGate>\n }\n />\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ToursListPage.js","names":[],"sources":["../../../src/tours/pages/ToursListPage.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { useNavigate } from 'react-router';\nimport { Plus, Search, Grid, List as ListIcon, ListOrdered, Eye, Settings } from 'lucide-react';\nimport { Markdown, PermissionGate } from '@burdenoff/fe-libs/shared/components';\nimport {\n AuroraBackground,\n Button,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\n PagePurpose,\n CTAOverflowMenu,\n type CTAAction,\n} from '@burdenoff/fe-libs/ui';\nimport { useToursList } from '../hooks/useToursList';\nimport { useTourLifecycle } from '../hooks/useTourLifecycle';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { useToursStore } from '../store/toursStore';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { useDeleteTourMutation } from '../../generated/global-operations';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport type { TourStatus } from '../types';\nimport type { Tour } from '../../generated/global-types';\nimport { useToursI18n } from '../i18n';\nimport {\n isNative,\n nativeConfirm,\n nativeImpact,\n nativeNotify,\n nativeToast,\n} from '../../utils/nativeBridge';\n\n/**\n * Tours list page\n * Displays all tours with filtering and search\n */\nexport function ToursListPage() {\n const { tr } = useToursI18n();\n const navigate = useNavigate();\n const { basePath = '/' } = useToursContext();\n const {\n viewMode,\n tourFilter,\n toursListRevision,\n setViewMode,\n updateTourFilter,\n notifyToursListChanged,\n } = useToursStore();\n const { hasPermission, isLoading: permissionsLoading } = useToursPermissionAccess();\n\n const canUpdateTour = hasPermission(TOUR_PERMISSIONS.TOUR_UPDATE);\n const canUpdateTourSteps = hasPermission(TOUR_PERMISSIONS.TOUR_STEP_UPDATE);\n const canPreviewTour = hasPermission(TOUR_PERMISSIONS.TOUR_READ);\n const canDeleteTour = hasPermission(TOUR_PERMISSIONS.TOUR_DELETE);\n const canPublishTour = hasPermission(TOUR_PERMISSIONS.TOUR_PUBLISH);\n const canArchiveTour = hasPermission(TOUR_PERMISSIONS.TOUR_ARCHIVE);\n const canDuplicateTour = hasPermission(TOUR_PERMISSIONS.TOUR_DUPLICATE);\n\n // Fetch tours (includes both workspace-specific and global tours)\n const { tours, loading, fetchTours } = useToursList();\n\n const { publishTour, unpublishTour, archiveTour, duplicateTour } = useTourLifecycle();\n const [deleteTourMutation] = useDeleteTourMutation();\n\n const [searchQuery, setSearchQuery] = useState('');\n const [statusFilter, setStatusFilter] = useState<TourStatus | 'all'>('all');\n\n // Fetch tours when filter changes. The list page is also the user-facing\n // tour browser, so backend permissions remain authoritative for actions while\n // normal users can still see published tours returned by the API.\n useEffect(() => {\n if (permissionsLoading) return;\n fetchTours({ ...tourFilter });\n }, [fetchTours, tourFilter, toursListRevision, permissionsLoading]);\n\n const handleSearch = (query: string) => {\n setSearchQuery(query);\n updateTourFilter({ search: query });\n };\n\n const handleStatusFilter = (status: TourStatus | 'all') => {\n setStatusFilter(status);\n updateTourFilter({ status });\n };\n\n const handleCreateTour = () => {\n const newPath = basePath.endsWith('/') ? `${basePath}new` : `${basePath}/new`;\n navigate(newPath);\n };\n\n const getStatusLabel = (status: TourStatus) => {\n switch (status) {\n case 'DRAFT':\n return tr('toursList.statusDraft');\n case 'PUBLISHED':\n return tr('toursList.statusPublished');\n case 'ARCHIVED':\n return tr('toursList.statusArchived');\n case 'SCHEDULED':\n return tr('toursList.statusScheduled');\n }\n };\n\n const handlePublish = async (id: string) => {\n nativeImpact('light');\n try {\n await publishTour(id);\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n if (isNative()) void nativeToast(tr('toursList.errorPublish'));\n else alert(tr('toursList.errorPublish'));\n }\n };\n\n const handleUnpublish = async (id: string) => {\n nativeImpact('light');\n try {\n await unpublishTour(id);\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n if (isNative()) void nativeToast(tr('toursList.errorUnpublish'));\n else alert(tr('toursList.errorUnpublish'));\n }\n };\n\n const handleArchive = async (id: string) => {\n nativeImpact('light');\n try {\n await archiveTour(id);\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n if (isNative()) void nativeToast(tr('toursList.errorArchive'));\n else alert(tr('toursList.errorArchive'));\n }\n };\n\n const handleDuplicate = async (id: string) => {\n nativeImpact('light');\n try {\n await duplicateTour(id);\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n if (isNative()) void nativeToast(tr('toursList.errorDuplicate'));\n else alert(tr('toursList.errorDuplicate'));\n }\n };\n\n const handleDelete = async (id: string) => {\n nativeImpact('medium');\n const confirmMsg = tr('toursList.confirmDelete');\n const nativeResult = await nativeConfirm({\n title: tr('toursList.actionDelete'),\n message: confirmMsg,\n okButtonTitle: tr('toursList.actionDelete'),\n });\n const confirmed = nativeResult === null ? window.confirm(confirmMsg) : nativeResult;\n if (!confirmed) return;\n try {\n await deleteTourMutation({ variables: { id } });\n notifyToursListChanged();\n void nativeNotify('success');\n } catch {\n void nativeNotify('error');\n if (isNative()) void nativeToast(tr('toursList.errorDelete'));\n else alert(tr('toursList.errorDelete'));\n }\n };\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n {/* Header */}\n <div className=\"relative overflow-hidden rounded-xl\">\n <AuroraBackground intensity=\"subtle\" />\n <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 p-1 sm:p-2\">\n <div className=\"flex-1 min-w-0\">\n <h1 className=\"text-xl sm:text-2xl font-bold text-text-primary\">\n <GradientText>{tr('toursList.title')}</GradientText>\n </h1>\n <p className=\"text-sm sm:text-base text-text-secondary\">{tr('toursList.subtitle')}</p>\n </div>\n <PermissionGate permission={TOUR_PERMISSIONS.TOUR_CREATE}>\n <Button\n type=\"button\"\n onClick={handleCreateTour}\n className=\"w-full sm:w-auto min-h-[44px]\"\n >\n <Plus size={20} />\n {tr('toursList.createTour')}\n </Button>\n </PermissionGate>\n </div>\n </div>\n\n <PagePurpose>{tr('toursList.purpose')}</PagePurpose>\n\n {/* Filters and Search */}\n <div className=\"flex flex-col sm:flex-row gap-3 sm:gap-4\">\n {/* Search */}\n <div className=\"flex-1 relative\">\n <Search\n className=\"absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary\"\n size={20}\n />\n <input\n type=\"text\"\n placeholder={tr('toursList.searchPlaceholder')}\n value={searchQuery}\n onChange={(e) => handleSearch(e.target.value)}\n className=\"w-full pl-[3.25rem] pr-4 py-2 min-h-[44px] border border-border-subtle rounded-md bg-bg-surface text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n aria-label={tr('toursList.searchPlaceholder')}\n />\n </div>\n\n {/* Status Filter */}\n <div className=\"flex gap-2\">\n <select\n value={statusFilter}\n onChange={(e) => handleStatusFilter(e.target.value as TourStatus | 'all')}\n className=\"px-4 py-2 min-h-[44px] border border-border-subtle rounded-md bg-bg-surface text-text-primary\"\n aria-label={tr('toursList.statusAll')}\n >\n <option value=\"all\">{tr('toursList.statusAll')}</option>\n <option value=\"DRAFT\">{tr('toursList.statusDraft')}</option>\n <option value=\"PUBLISHED\">{tr('toursList.statusPublished')}</option>\n <option value=\"ARCHIVED\">{tr('toursList.statusArchived')}</option>\n <option value=\"SCHEDULED\">{tr('toursList.statusScheduled')}</option>\n </select>\n\n {/* View Mode Toggle */}\n <div className=\"flex border border-border-subtle rounded-md overflow-hidden\">\n <button\n type=\"button\"\n onClick={() => setViewMode('grid')}\n className={`px-3 py-2 min-h-[44px] ${\n viewMode === 'grid'\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-surface text-text-primary hover:bg-accent'\n }`}\n aria-label={tr('toursList.gridView')}\n title={tr('toursList.gridView')}\n >\n <Grid size={20} />\n </button>\n <button\n type=\"button\"\n onClick={() => setViewMode('list')}\n className={`px-3 py-2 min-h-[44px] ${\n viewMode === 'list'\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-surface text-text-primary hover:bg-accent'\n }`}\n aria-label={tr('toursList.listView')}\n title={tr('toursList.listView')}\n >\n <ListIcon size={20} />\n </button>\n </div>\n </div>\n </div>\n\n {/* Tours List */}\n {loading ? (\n <div className=\"text-center py-12\">\n <p className=\"text-sm sm:text-base text-text-secondary\">{tr('toursList.loading')}</p>\n </div>\n ) : tours.length > 0 ? (\n <div\n className={\n viewMode === 'grid'\n ? 'grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4'\n : 'space-y-3'\n }\n >\n {tours.map((tour: Tour) => {\n const status = tour.status as TourStatus;\n const canShowPublishAction = status === 'DRAFT' && canPublishTour;\n const canShowUnpublishAction = status === 'PUBLISHED' && canPublishTour;\n const canShowArchiveAction = status !== 'ARCHIVED' && canArchiveTour;\n\n const overflowActions: CTAAction[] = [];\n if (canShowPublishAction) {\n overflowActions.push({\n label: tr('toursList.actionPublish'),\n onSelect: () => void handlePublish(tour.id),\n });\n }\n if (canShowUnpublishAction) {\n overflowActions.push({\n label: tr('toursList.actionUnpublish'),\n onSelect: () => void handleUnpublish(tour.id),\n });\n }\n if (canDuplicateTour) {\n overflowActions.push({\n label: tr('toursList.actionDuplicate'),\n onSelect: () => void handleDuplicate(tour.id),\n });\n }\n if (canShowArchiveAction) {\n overflowActions.push({\n label: tr('toursList.actionArchive'),\n onSelect: () => void handleArchive(tour.id),\n });\n }\n if (canDeleteTour) {\n overflowActions.push({\n label: tr('toursList.actionDelete'),\n onSelect: () => void handleDelete(tour.id),\n intent: 'destructive',\n });\n }\n\n return (\n <GlassCard\n key={tour.id}\n treatment=\"plain\"\n className=\"p-4 border-border-seam shadow-[var(--shadow-pop)]\"\n >\n <div className=\"flex items-start justify-between mb-2\">\n <h3 className=\"font-semibold text-text-primary\">\n {canUpdateTour ? (\n <button\n type=\"button\"\n className=\"cursor-pointer hover:text-primary bg-transparent border-0 p-0 text-left font-inherit\"\n onClick={() => navigate(`${basePath}/${tour.id}/edit`)}\n >\n {tour.name}\n </button>\n ) : (\n tour.name\n )}\n </h3>\n <span\n className={`px-2 py-1 text-xs rounded-full ${\n tour.status === 'PUBLISHED'\n ? 'bg-success/10 text-success motion-safe:animate-vc-glow-pulse'\n : tour.status === 'DRAFT'\n ? 'bg-bg-sunken text-text-secondary'\n : 'bg-warning/10 text-warning'\n }`}\n >\n {getStatusLabel(status)}\n </span>\n </div>\n {tour.description && (\n <Markdown inline className=\"text-sm text-text-secondary mb-3\">\n {tour.description}\n </Markdown>\n )}\n <div className=\"flex items-center justify-between text-xs text-text-secondary mb-3\">\n <span>\n {tour.steps?.length || 0} {tr('toursList.steps')}\n </span>\n <span>\n {tour.viewCount} {tr('toursList.views')}\n </span>\n </div>\n {/* Quick Actions */}\n <div className=\"flex flex-wrap items-center gap-2 pt-3 border-t border-border-seam\">\n {canUpdateTourSteps && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n navigate(`${basePath}/${tour.id}/steps`);\n }}\n className=\"flex-1 min-w-[6.5rem] px-3 py-2 min-h-[44px] text-xs bg-secondary text-secondary-foreground rounded hover:bg-secondary/80 flex items-center justify-center gap-1.5\"\n title={tr('toursList.editStepsTitle')}\n >\n <ListOrdered size={14} />\n {tr('toursList.stepsButton')}\n </button>\n )}\n {canPreviewTour && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n navigate(`${basePath}/${tour.id}/preview`);\n }}\n className=\"flex-1 min-w-[6.5rem] px-3 py-2 min-h-[44px] text-xs border border-border-seam rounded hover:bg-accent flex items-center justify-center gap-1.5\"\n title={tr('toursList.previewTitle')}\n >\n <Eye size={14} />\n {tr('toursList.previewButton')}\n </button>\n )}\n {canUpdateTour && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n navigate(`${basePath}/${tour.id}/edit`);\n }}\n className=\"p-2 min-h-[44px] min-w-[44px] text-xs border border-border-seam rounded hover:bg-accent\"\n title={tr('toursList.settingsTitle')}\n aria-label={tr('toursList.settingsTitle')}\n >\n <Settings size={14} />\n </button>\n )}\n {/* Lifecycle actions collapsed into the overflow menu */}\n {overflowActions.length > 0 && <CTAOverflowMenu actions={overflowActions} />}\n </div>\n </GlassCard>\n );\n })}\n </div>\n ) : (\n <IllustratedEmptyState\n illustration=\"onboarding\"\n title={tr('toursList.emptyTitle')}\n description={tr('toursList.emptySubtitle')}\n action={\n <PermissionGate permission={TOUR_PERMISSIONS.TOUR_CREATE}>\n <Button type=\"button\" onClick={handleCreateTour} className=\"min-h-[44px]\">\n <Plus size={20} />\n {tr('toursList.createTour')}\n </Button>\n </PermissionGate>\n }\n />\n )}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -110,27 +110,31 @@ var t = {
110
110
  let t = [], { selectedTour: r, stepSequence: i } = n();
111
111
  return r ? ((!r.name || r.name.trim() === "") && t.push({
112
112
  field: "name",
113
- message: "Tour name is required"
113
+ message: "validation.tourNameRequired"
114
114
  }), r.productId || t.push({
115
115
  field: "productId",
116
- message: "Product ID is required"
116
+ message: "validation.productIdRequired"
117
117
  }), i.length === 0 && t.push({
118
118
  field: "steps",
119
- message: "At least one step is required"
119
+ message: "validation.stepsRequired"
120
120
  }), i.forEach((e, n) => {
121
+ let r = n + 1;
121
122
  (!e.title || e.title.trim() === "") && t.push({
122
123
  field: `step[${n}].title`,
123
- message: `Step ${n + 1} title is required`
124
+ message: "validation.stepTitleRequired",
125
+ params: { number: r }
124
126
  }), (!e.content || e.content.trim() === "") && t.push({
125
127
  field: `step[${n}].content`,
126
- message: `Step ${n + 1} content is required`
128
+ message: "validation.stepContentRequired",
129
+ params: { number: r }
127
130
  }), e.placement !== "CENTER" && (!e.targetSelector || e.targetSelector.trim() === "") && t.push({
128
131
  field: `step[${n}].targetSelector`,
129
- message: `Step ${n + 1} selector is required`
132
+ message: "validation.stepSelectorRequired",
133
+ params: { number: r }
130
134
  });
131
135
  }), e({ validationErrors: t }), t) : (t.push({
132
136
  field: "tour",
133
- message: "No tour selected"
137
+ message: "validation.noTourSelected"
134
138
  }), e({ validationErrors: t }), t);
135
139
  },
136
140
  clearValidationErrors: () => e({ validationErrors: [] }),