@burdenoff/microfe-tours 2026.625.1 → 2026.625.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.
|
@@ -5,62 +5,59 @@ import { useEffect as r, useRef as i } from "react";
|
|
|
5
5
|
import { CheckCircle2 as a, Circle as o, MinusCircle as s, Play as c } from "lucide-react";
|
|
6
6
|
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
7
7
|
import { useSearchParams as d } from "react-router-dom";
|
|
8
|
-
import { GlassCard as f } from "@burdenoff/fe-libs/ui";
|
|
9
|
-
import { useEventBus as
|
|
8
|
+
import { GlassCard as f, GradientText as p, IllustratedEmptyState as m } from "@burdenoff/fe-libs/ui";
|
|
9
|
+
import { useEventBus as h } from "@burdenoff/fe-libs/shared/events";
|
|
10
10
|
//#region src/tours/pages/MyToursPage.tsx
|
|
11
|
-
var
|
|
12
|
-
function
|
|
13
|
-
return e &&
|
|
11
|
+
var g = /^[a-zA-Z0-9_-]+$/, _ = /^[a-zA-Z0-9_\-/]+$/;
|
|
12
|
+
function v(e, t) {
|
|
13
|
+
return e && g.test(e) ? e : t;
|
|
14
14
|
}
|
|
15
|
-
function
|
|
16
|
-
return e &&
|
|
15
|
+
function y(e, t) {
|
|
16
|
+
return e && _.test(e) ? e : t;
|
|
17
17
|
}
|
|
18
|
-
function
|
|
19
|
-
let { tr: a } = n(), { productId: o, moduleId: s, pageId: c, workspaceId:
|
|
18
|
+
function b() {
|
|
19
|
+
let { tr: a } = n(), { productId: o, moduleId: s, pageId: c, workspaceId: g } = e(), [_] = d(), b = h(), S = i(!1);
|
|
20
20
|
r(() => {
|
|
21
|
-
|
|
21
|
+
S.current || (S.current = !0, b.emit("tours.page.viewed", {
|
|
22
22
|
page: "/tours",
|
|
23
23
|
productId: o,
|
|
24
24
|
moduleId: s,
|
|
25
25
|
pageId: c,
|
|
26
|
-
workspaceId:
|
|
26
|
+
workspaceId: g
|
|
27
27
|
}));
|
|
28
28
|
}, [
|
|
29
|
-
|
|
29
|
+
b,
|
|
30
30
|
o,
|
|
31
31
|
s,
|
|
32
32
|
c,
|
|
33
|
-
|
|
33
|
+
g
|
|
34
34
|
]);
|
|
35
|
-
let
|
|
36
|
-
variables:
|
|
37
|
-
productId:
|
|
38
|
-
moduleId:
|
|
39
|
-
pageId:
|
|
35
|
+
let C = v(o, void 0) ?? v(_.get("productId"), void 0), w = v(s, void 0) ?? v(_.get("moduleId"), void 0), T = y(c, void 0) ?? y(_.get("pageId"), void 0), { data: E, loading: D } = t({
|
|
36
|
+
variables: C ? { context: {
|
|
37
|
+
productId: C,
|
|
38
|
+
moduleId: w,
|
|
39
|
+
pageId: T
|
|
40
40
|
} } : void 0,
|
|
41
|
-
skip: !
|
|
41
|
+
skip: !C,
|
|
42
42
|
fetchPolicy: "cache-and-network"
|
|
43
|
-
}),
|
|
43
|
+
}), O = E?.toursForContext ?? [], k = D;
|
|
44
44
|
return /* @__PURE__ */ u("div", {
|
|
45
45
|
className: "space-y-4 sm:space-y-6 p-3 sm:p-6",
|
|
46
46
|
children: [/* @__PURE__ */ u("div", { children: [/* @__PURE__ */ l("h1", {
|
|
47
47
|
className: "text-xl sm:text-2xl font-bold text-text-primary",
|
|
48
|
-
children: a("myTours.title")
|
|
48
|
+
children: /* @__PURE__ */ l(p, { children: a("myTours.title") })
|
|
49
49
|
}), /* @__PURE__ */ l("p", {
|
|
50
50
|
className: "text-sm sm:text-base text-text-secondary",
|
|
51
51
|
children: a("myTours.subtitle")
|
|
52
|
-
})] }),
|
|
52
|
+
})] }), k && O.length === 0 ? /* @__PURE__ */ l("output", {
|
|
53
53
|
className: "text-sm text-text-secondary",
|
|
54
54
|
children: a("myTours.loading")
|
|
55
|
-
}) :
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
className: "block text-sm text-text-secondary",
|
|
59
|
-
children: a("myTours.empty")
|
|
60
|
-
})
|
|
55
|
+
}) : O.length === 0 ? /* @__PURE__ */ l(m, {
|
|
56
|
+
illustration: "empty-generic",
|
|
57
|
+
title: a("myTours.empty")
|
|
61
58
|
}) : /* @__PURE__ */ l("ul", {
|
|
62
59
|
className: "grid gap-3 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
|
|
63
|
-
children:
|
|
60
|
+
children: O.map((e) => /* @__PURE__ */ l("li", { children: /* @__PURE__ */ u(f, {
|
|
64
61
|
treatment: "plain",
|
|
65
62
|
className: "h-full p-4 flex flex-col gap-2 border-border-seam shadow-[var(--shadow-pop)]",
|
|
66
63
|
children: [/* @__PURE__ */ u("div", {
|
|
@@ -68,7 +65,7 @@ function v() {
|
|
|
68
65
|
children: [/* @__PURE__ */ l("h2", {
|
|
69
66
|
className: "font-semibold text-text-primary line-clamp-2",
|
|
70
67
|
children: e.name
|
|
71
|
-
}), /* @__PURE__ */ l(
|
|
68
|
+
}), /* @__PURE__ */ l(x, {
|
|
72
69
|
status: e.myProgress?.status,
|
|
73
70
|
tr: a
|
|
74
71
|
})]
|
|
@@ -80,14 +77,14 @@ function v() {
|
|
|
80
77
|
})]
|
|
81
78
|
});
|
|
82
79
|
}
|
|
83
|
-
function
|
|
80
|
+
function x({ status: e, tr: t }) {
|
|
84
81
|
switch (e) {
|
|
85
82
|
case "COMPLETED": return /* @__PURE__ */ u("span", {
|
|
86
83
|
className: "inline-flex items-center gap-1 text-xs text-success",
|
|
87
84
|
children: [/* @__PURE__ */ l(a, { size: 14 }), t("myTours.status.completed")]
|
|
88
85
|
});
|
|
89
86
|
case "IN_PROGRESS": return /* @__PURE__ */ u("span", {
|
|
90
|
-
className: "inline-flex items-center gap-1 text-xs text-warning",
|
|
87
|
+
className: "inline-flex items-center gap-1 text-xs text-warning motion-safe:animate-vc-glow-pulse",
|
|
91
88
|
children: [/* @__PURE__ */ l(c, { size: 14 }), t("myTours.status.inProgress")]
|
|
92
89
|
});
|
|
93
90
|
case "SKIPPED":
|
|
@@ -102,6 +99,6 @@ function y({ status: e, tr: t }) {
|
|
|
102
99
|
}
|
|
103
100
|
}
|
|
104
101
|
//#endregion
|
|
105
|
-
export {
|
|
102
|
+
export { b as MyToursPage };
|
|
106
103
|
|
|
107
104
|
//# sourceMappingURL=MyToursPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MyToursPage.js","names":[],"sources":["../../../src/tours/pages/MyToursPage.tsx"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { CheckCircle2, Circle, MinusCircle, Play } from 'lucide-react';\nimport {\n useGetToursForContextQuery,\n type GetToursForContextQuery,\n} from '../../generated/global-operations';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { useToursI18n, type ToursTranslationKey } from '../i18n';\nimport { useEventBus } from '@burdenoff/fe-libs/shared/events';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\n\ntype TourSummary = GetToursForContextQuery['toursForContext'][number];\n\n// Plain slug validator for productId and moduleId.\nconst SLUG_PATTERN = /^[a-zA-Z0-9_-]+$/;\n\n// pageId is documented with path-style values like \"settings/team\" per\n// ToursRootProps — tighten to URL-safe characters only, but permit `/`.\nconst PAGE_PATH_PATTERN = /^[a-zA-Z0-9_\\-/]+$/;\n\nfunction safeSlug<T extends string | undefined>(\n raw: string | null | undefined,\n fallback: T\n): string | T {\n if (raw && SLUG_PATTERN.test(raw)) return raw;\n return fallback;\n}\n\nfunction safePageId<T extends string | undefined>(\n raw: string | null | undefined,\n fallback: T\n): string | T {\n if (raw && PAGE_PATH_PATTERN.test(raw)) return raw;\n return fallback;\n}\n\n/**\n * MyToursPage — user-facing browse for available tours.\n *\n * Lists tours returned by `toursForContext` (filtered to the current\n * product/module/page surface) and decorates each with the requesting\n * user's `TourUserProgress` status (Completed / In progress / Skipped /\n * Not started). Read-only — tours are actually played via the SDK overlay,\n * not via mutations on this page.\n */\nexport function MyToursPage() {\n const { tr } = useToursI18n();\n const {\n productId: shellProductId,\n moduleId: shellModuleId,\n pageId: shellPageId,\n workspaceId,\n } = useToursContext();\n const [searchParams] = useSearchParams();\n const eventBus = useEventBus();\n\n // Emit page view event exactly once per mount. A ref guard keeps the effect\n // semantically mount-only while satisfying exhaustive-deps with the real\n // dependency list, so we don't have to disable the lint rule.\n const pageViewedRef = useRef(false);\n useEffect(() => {\n if (pageViewedRef.current) return;\n pageViewedRef.current = true;\n eventBus.emit('tours.page.viewed', {\n page: '/tours',\n productId: shellProductId,\n moduleId: shellModuleId,\n pageId: shellPageId,\n workspaceId,\n });\n }, [eventBus, shellProductId, shellModuleId, shellPageId, workspaceId]);\n\n // Preferred source is the shell's productId prop (the host app knows\n // which product it is — \"workspaces\", \"vibecontrols\", \"bigconsole\", etc.).\n // Fall back to a query-param override for deep-link scenarios, but only\n // after passing a plain-slug validator so we never forward arbitrary\n // strings into the GraphQL variables. No hardcoded product default —\n // if neither source provides one, skip the query entirely so non-\n // workspaces integrations don't get workspaces tours.\n const productId =\n safeSlug(shellProductId, undefined) ?? safeSlug(searchParams.get('productId'), undefined);\n const moduleId =\n safeSlug(shellModuleId, undefined) ?? safeSlug(searchParams.get('moduleId'), undefined);\n const pageId =\n safePageId(shellPageId, undefined) ?? safePageId(searchParams.get('pageId'), undefined);\n\n const { data: toursData, loading: toursLoading } = useGetToursForContextQuery({\n variables: productId ? { context: { productId, moduleId, pageId } } : undefined,\n skip: !productId,\n fetchPolicy: 'cache-and-network',\n });\n\n const tours = toursData?.toursForContext ?? [];\n const isLoading = toursLoading;\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n <div>\n <h1 className=\"text-xl sm:text-2xl font-bold text-text-primary\">{tr('myTours.title')}</h1>\n <p className=\"text-sm sm:text-base text-text-secondary\">{tr('myTours.subtitle')}</p>\n </div>\n\n {isLoading && tours.length === 0 ? (\n <output className=\"text-sm text-text-secondary\">{tr('myTours.loading')}</output>\n ) : tours.length === 0 ? (\n <
|
|
1
|
+
{"version":3,"file":"MyToursPage.js","names":[],"sources":["../../../src/tours/pages/MyToursPage.tsx"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport { useSearchParams } from 'react-router-dom';\nimport { CheckCircle2, Circle, MinusCircle, Play } from 'lucide-react';\nimport {\n useGetToursForContextQuery,\n type GetToursForContextQuery,\n} from '../../generated/global-operations';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { useToursI18n, type ToursTranslationKey } from '../i18n';\nimport { useEventBus } from '@burdenoff/fe-libs/shared/events';\nimport { GlassCard, GradientText, IllustratedEmptyState } from '@burdenoff/fe-libs/ui';\n\ntype TourSummary = GetToursForContextQuery['toursForContext'][number];\n\n// Plain slug validator for productId and moduleId.\nconst SLUG_PATTERN = /^[a-zA-Z0-9_-]+$/;\n\n// pageId is documented with path-style values like \"settings/team\" per\n// ToursRootProps — tighten to URL-safe characters only, but permit `/`.\nconst PAGE_PATH_PATTERN = /^[a-zA-Z0-9_\\-/]+$/;\n\nfunction safeSlug<T extends string | undefined>(\n raw: string | null | undefined,\n fallback: T\n): string | T {\n if (raw && SLUG_PATTERN.test(raw)) return raw;\n return fallback;\n}\n\nfunction safePageId<T extends string | undefined>(\n raw: string | null | undefined,\n fallback: T\n): string | T {\n if (raw && PAGE_PATH_PATTERN.test(raw)) return raw;\n return fallback;\n}\n\n/**\n * MyToursPage — user-facing browse for available tours.\n *\n * Lists tours returned by `toursForContext` (filtered to the current\n * product/module/page surface) and decorates each with the requesting\n * user's `TourUserProgress` status (Completed / In progress / Skipped /\n * Not started). Read-only — tours are actually played via the SDK overlay,\n * not via mutations on this page.\n */\nexport function MyToursPage() {\n const { tr } = useToursI18n();\n const {\n productId: shellProductId,\n moduleId: shellModuleId,\n pageId: shellPageId,\n workspaceId,\n } = useToursContext();\n const [searchParams] = useSearchParams();\n const eventBus = useEventBus();\n\n // Emit page view event exactly once per mount. A ref guard keeps the effect\n // semantically mount-only while satisfying exhaustive-deps with the real\n // dependency list, so we don't have to disable the lint rule.\n const pageViewedRef = useRef(false);\n useEffect(() => {\n if (pageViewedRef.current) return;\n pageViewedRef.current = true;\n eventBus.emit('tours.page.viewed', {\n page: '/tours',\n productId: shellProductId,\n moduleId: shellModuleId,\n pageId: shellPageId,\n workspaceId,\n });\n }, [eventBus, shellProductId, shellModuleId, shellPageId, workspaceId]);\n\n // Preferred source is the shell's productId prop (the host app knows\n // which product it is — \"workspaces\", \"vibecontrols\", \"bigconsole\", etc.).\n // Fall back to a query-param override for deep-link scenarios, but only\n // after passing a plain-slug validator so we never forward arbitrary\n // strings into the GraphQL variables. No hardcoded product default —\n // if neither source provides one, skip the query entirely so non-\n // workspaces integrations don't get workspaces tours.\n const productId =\n safeSlug(shellProductId, undefined) ?? safeSlug(searchParams.get('productId'), undefined);\n const moduleId =\n safeSlug(shellModuleId, undefined) ?? safeSlug(searchParams.get('moduleId'), undefined);\n const pageId =\n safePageId(shellPageId, undefined) ?? safePageId(searchParams.get('pageId'), undefined);\n\n const { data: toursData, loading: toursLoading } = useGetToursForContextQuery({\n variables: productId ? { context: { productId, moduleId, pageId } } : undefined,\n skip: !productId,\n fetchPolicy: 'cache-and-network',\n });\n\n const tours = toursData?.toursForContext ?? [];\n const isLoading = toursLoading;\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6\">\n <div>\n <h1 className=\"text-xl sm:text-2xl font-bold text-text-primary\">\n <GradientText>{tr('myTours.title')}</GradientText>\n </h1>\n <p className=\"text-sm sm:text-base text-text-secondary\">{tr('myTours.subtitle')}</p>\n </div>\n\n {isLoading && tours.length === 0 ? (\n <output className=\"text-sm text-text-secondary\">{tr('myTours.loading')}</output>\n ) : tours.length === 0 ? (\n <IllustratedEmptyState\n illustration=\"empty-generic\"\n title={tr('myTours.empty')}\n />\n ) : (\n <ul className=\"grid gap-3 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3\">\n {tours.map((tour: TourSummary) => (\n <li key={tour.id}>\n <GlassCard\n treatment=\"plain\"\n className=\"h-full p-4 flex flex-col gap-2 border-border-seam shadow-[var(--shadow-pop)]\"\n >\n <div className=\"flex items-start justify-between gap-2\">\n <h2 className=\"font-semibold text-text-primary line-clamp-2\">{tour.name}</h2>\n <ProgressBadge status={tour.myProgress?.status} tr={tr} />\n </div>\n {tour.description ? (\n <p className=\"text-sm text-text-secondary line-clamp-3\">{tour.description}</p>\n ) : null}\n </GlassCard>\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n}\n\nfunction ProgressBadge({\n status,\n tr,\n}: {\n status: string | undefined;\n tr: (key: ToursTranslationKey) => string;\n}) {\n switch (status) {\n case 'COMPLETED':\n return (\n <span className=\"inline-flex items-center gap-1 text-xs text-success\">\n <CheckCircle2 size={14} />\n {tr('myTours.status.completed')}\n </span>\n );\n case 'IN_PROGRESS':\n return (\n <span className=\"inline-flex items-center gap-1 text-xs text-warning motion-safe:animate-vc-glow-pulse\">\n <Play size={14} />\n {tr('myTours.status.inProgress')}\n </span>\n );\n case 'SKIPPED':\n case 'DISMISSED':\n return (\n <span className=\"inline-flex items-center gap-1 text-xs text-text-secondary\">\n <MinusCircle size={14} />\n {tr('myTours.status.skipped')}\n </span>\n );\n default:\n return (\n <span className=\"inline-flex items-center gap-1 text-xs text-text-secondary\">\n <Circle size={14} />\n {tr('myTours.status.notStarted')}\n </span>\n );\n }\n}\n"],"mappings":"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"}
|
|
@@ -6,278 +6,285 @@ import { useTourLifecycle as i } from "../hooks/useTourLifecycle.js";
|
|
|
6
6
|
import { useToursPermissionAccess as a } from "../hooks/useToursPermissionAccess.js";
|
|
7
7
|
import { TOUR_PERMISSIONS as o } from "../../constants/permissions.js";
|
|
8
8
|
import { useToursI18n as s } from "../i18n.js";
|
|
9
|
-
import { isNative as c, nativeConfirm as
|
|
10
|
-
import { useEffect as
|
|
11
|
-
import { PermissionGate as
|
|
12
|
-
import { Eye as
|
|
13
|
-
import { jsx as
|
|
14
|
-
import { useNavigate as
|
|
15
|
-
import { Button as E, CTAOverflowMenu as D, GlassCard as O } from "@burdenoff/fe-libs/ui";
|
|
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 { PermissionGate as m } from "@burdenoff/fe-libs/shared/components";
|
|
12
|
+
import { Eye as h, Grid as g, List as _, ListOrdered as v, Plus as y, Search as b, Settings as x } from "lucide-react";
|
|
13
|
+
import { jsx as S, jsxs as C } from "react/jsx-runtime";
|
|
14
|
+
import { useNavigate as w } from "react-router-dom";
|
|
15
|
+
import { AuroraBackground as T, Button as E, CTAOverflowMenu as D, GlassCard as O, GradientText as k, IllustratedEmptyState as A } from "@burdenoff/fe-libs/ui";
|
|
16
16
|
//#region src/tours/pages/ToursListPage.tsx
|
|
17
|
-
function
|
|
18
|
-
let { tr:
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
function j() {
|
|
18
|
+
let { tr: j } = s(), M = w(), { basePath: N = "/" } = e(), { viewMode: P, tourFilter: F, toursListRevision: I, setViewMode: L, updateTourFilter: R, notifyToursListChanged: z } = t(), { hasPermission: B, isLoading: V } = a(), H = B(o.TOUR_UPDATE), U = B(o.TOUR_STEP_UPDATE), W = B(o.TOUR_READ), G = B(o.TOUR_DELETE), K = B(o.TOUR_PUBLISH), te = B(o.TOUR_ARCHIVE), q = B(o.TOUR_DUPLICATE), { tours: J, loading: Y, fetchTours: X } = r(), { publishTour: Z, unpublishTour: Q, archiveTour: ne, duplicateTour: re } = i(), [ie] = n(), [ae, oe] = p(""), [se, ce] = p("all");
|
|
19
|
+
f(() => {
|
|
20
|
+
V || X({ ...F });
|
|
21
21
|
}, [
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
X,
|
|
23
|
+
F,
|
|
24
|
+
I,
|
|
25
|
+
V
|
|
26
26
|
]);
|
|
27
|
-
let
|
|
28
|
-
|
|
29
|
-
},
|
|
30
|
-
|
|
31
|
-
},
|
|
32
|
-
|
|
33
|
-
},
|
|
27
|
+
let le = (e) => {
|
|
28
|
+
oe(e), R({ search: e });
|
|
29
|
+
}, ue = (e) => {
|
|
30
|
+
ce(e), R({ status: e });
|
|
31
|
+
}, $ = () => {
|
|
32
|
+
M(N.endsWith("/") ? `${N}new` : `${N}/new`);
|
|
33
|
+
}, de = (e) => {
|
|
34
34
|
switch (e) {
|
|
35
|
-
case "DRAFT": return
|
|
36
|
-
case "PUBLISHED": return
|
|
37
|
-
case "ARCHIVED": return
|
|
38
|
-
case "SCHEDULED": return
|
|
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
|
-
},
|
|
41
|
-
|
|
40
|
+
}, fe = async (e) => {
|
|
41
|
+
l("light");
|
|
42
42
|
try {
|
|
43
|
-
await
|
|
43
|
+
await Z(e), u("success");
|
|
44
44
|
} catch {
|
|
45
|
-
|
|
45
|
+
u("error"), c() ? d(j("toursList.errorPublish")) : alert(j("toursList.errorPublish"));
|
|
46
46
|
}
|
|
47
|
-
},
|
|
48
|
-
|
|
47
|
+
}, pe = async (e) => {
|
|
48
|
+
l("light");
|
|
49
49
|
try {
|
|
50
|
-
await
|
|
50
|
+
await Q(e), u("success");
|
|
51
51
|
} catch {
|
|
52
|
-
|
|
52
|
+
u("error"), c() ? d(j("toursList.errorUnpublish")) : alert(j("toursList.errorUnpublish"));
|
|
53
53
|
}
|
|
54
|
-
},
|
|
55
|
-
|
|
54
|
+
}, me = async (e) => {
|
|
55
|
+
l("light");
|
|
56
56
|
try {
|
|
57
|
-
await
|
|
57
|
+
await ne(e), u("success");
|
|
58
58
|
} catch {
|
|
59
|
-
|
|
59
|
+
u("error"), c() ? d(j("toursList.errorArchive")) : alert(j("toursList.errorArchive"));
|
|
60
60
|
}
|
|
61
|
-
},
|
|
62
|
-
|
|
61
|
+
}, he = async (e) => {
|
|
62
|
+
l("light");
|
|
63
63
|
try {
|
|
64
|
-
await
|
|
64
|
+
await re(e), u("success");
|
|
65
65
|
} catch {
|
|
66
|
-
|
|
66
|
+
u("error"), c() ? d(j("toursList.errorDuplicate")) : alert(j("toursList.errorDuplicate"));
|
|
67
67
|
}
|
|
68
|
-
},
|
|
69
|
-
|
|
70
|
-
let t =
|
|
71
|
-
title:
|
|
68
|
+
}, ge = async (e) => {
|
|
69
|
+
l("medium");
|
|
70
|
+
let t = j("toursList.confirmDelete"), n = await ee({
|
|
71
|
+
title: j("toursList.actionDelete"),
|
|
72
72
|
message: t,
|
|
73
|
-
okButtonTitle:
|
|
73
|
+
okButtonTitle: j("toursList.actionDelete")
|
|
74
74
|
});
|
|
75
75
|
if (n === null ? window.confirm(t) : n) try {
|
|
76
|
-
await
|
|
76
|
+
await ie({ variables: { id: e } }), z(), u("success");
|
|
77
77
|
} catch {
|
|
78
|
-
|
|
78
|
+
u("error"), c() ? d(j("toursList.errorDelete")) : alert(j("toursList.errorDelete"));
|
|
79
79
|
}
|
|
80
80
|
};
|
|
81
|
-
return /* @__PURE__ */
|
|
81
|
+
return /* @__PURE__ */ C("div", {
|
|
82
82
|
className: "space-y-4 sm:space-y-6 p-3 sm:p-6",
|
|
83
83
|
children: [
|
|
84
|
-
/* @__PURE__ */
|
|
85
|
-
className: "
|
|
86
|
-
children: [/* @__PURE__ */
|
|
87
|
-
className: "flex-1
|
|
88
|
-
children: [/* @__PURE__ */ C("
|
|
89
|
-
className: "
|
|
90
|
-
children:
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
84
|
+
/* @__PURE__ */ C("div", {
|
|
85
|
+
className: "relative overflow-hidden rounded-xl",
|
|
86
|
+
children: [/* @__PURE__ */ S(T, { intensity: "subtle" }), /* @__PURE__ */ C("div", {
|
|
87
|
+
className: "flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 p-1 sm:p-2",
|
|
88
|
+
children: [/* @__PURE__ */ C("div", {
|
|
89
|
+
className: "flex-1 min-w-0",
|
|
90
|
+
children: [/* @__PURE__ */ S("h1", {
|
|
91
|
+
className: "text-xl sm:text-2xl font-bold text-text-primary",
|
|
92
|
+
children: /* @__PURE__ */ S(k, { children: j("toursList.title") })
|
|
93
|
+
}), /* @__PURE__ */ S("p", {
|
|
94
|
+
className: "text-sm sm:text-base text-text-secondary",
|
|
95
|
+
children: j("toursList.subtitle")
|
|
96
|
+
})]
|
|
97
|
+
}), /* @__PURE__ */ S(m, {
|
|
98
|
+
permission: o.TOUR_CREATE,
|
|
99
|
+
children: /* @__PURE__ */ C(E, {
|
|
100
|
+
type: "button",
|
|
101
|
+
onClick: $,
|
|
102
|
+
className: "w-full sm:w-auto min-h-[44px]",
|
|
103
|
+
children: [/* @__PURE__ */ S(y, { size: 20 }), j("toursList.createTour")]
|
|
104
|
+
})
|
|
94
105
|
})]
|
|
95
|
-
}), /* @__PURE__ */ C(h, {
|
|
96
|
-
permission: o.TOUR_CREATE,
|
|
97
|
-
children: /* @__PURE__ */ w(E, {
|
|
98
|
-
type: "button",
|
|
99
|
-
onClick: se,
|
|
100
|
-
className: "w-full sm:w-auto min-h-[44px]",
|
|
101
|
-
children: [/* @__PURE__ */ C(b, { size: 20 }), k("toursList.createTour")]
|
|
102
|
-
})
|
|
103
106
|
})]
|
|
104
107
|
}),
|
|
105
|
-
/* @__PURE__ */
|
|
108
|
+
/* @__PURE__ */ C("div", {
|
|
106
109
|
className: "flex flex-col sm:flex-row gap-3 sm:gap-4",
|
|
107
|
-
children: [/* @__PURE__ */
|
|
110
|
+
children: [/* @__PURE__ */ C("div", {
|
|
108
111
|
className: "flex-1 relative",
|
|
109
|
-
children: [/* @__PURE__ */
|
|
112
|
+
children: [/* @__PURE__ */ S(b, {
|
|
110
113
|
className: "absolute left-3 top-1/2 -translate-y-1/2 text-text-secondary",
|
|
111
114
|
size: 20
|
|
112
|
-
}), /* @__PURE__ */
|
|
115
|
+
}), /* @__PURE__ */ S("input", {
|
|
113
116
|
type: "text",
|
|
114
|
-
placeholder:
|
|
115
|
-
value:
|
|
116
|
-
onChange: (e) =>
|
|
117
|
+
placeholder: j("toursList.searchPlaceholder"),
|
|
118
|
+
value: ae,
|
|
119
|
+
onChange: (e) => le(e.target.value),
|
|
117
120
|
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)]",
|
|
118
|
-
"aria-label":
|
|
121
|
+
"aria-label": j("toursList.searchPlaceholder")
|
|
119
122
|
})]
|
|
120
|
-
}), /* @__PURE__ */
|
|
123
|
+
}), /* @__PURE__ */ C("div", {
|
|
121
124
|
className: "flex gap-2",
|
|
122
|
-
children: [/* @__PURE__ */
|
|
123
|
-
value:
|
|
124
|
-
onChange: (e) =>
|
|
125
|
+
children: [/* @__PURE__ */ C("select", {
|
|
126
|
+
value: se,
|
|
127
|
+
onChange: (e) => ue(e.target.value),
|
|
125
128
|
className: "px-4 py-2 min-h-[44px] border border-border-subtle rounded-md bg-bg-surface text-text-primary",
|
|
126
|
-
"aria-label":
|
|
129
|
+
"aria-label": j("toursList.statusAll"),
|
|
127
130
|
children: [
|
|
128
|
-
/* @__PURE__ */
|
|
131
|
+
/* @__PURE__ */ S("option", {
|
|
129
132
|
value: "all",
|
|
130
|
-
children:
|
|
133
|
+
children: j("toursList.statusAll")
|
|
131
134
|
}),
|
|
132
|
-
/* @__PURE__ */
|
|
135
|
+
/* @__PURE__ */ S("option", {
|
|
133
136
|
value: "DRAFT",
|
|
134
|
-
children:
|
|
137
|
+
children: j("toursList.statusDraft")
|
|
135
138
|
}),
|
|
136
|
-
/* @__PURE__ */
|
|
139
|
+
/* @__PURE__ */ S("option", {
|
|
137
140
|
value: "PUBLISHED",
|
|
138
|
-
children:
|
|
141
|
+
children: j("toursList.statusPublished")
|
|
139
142
|
}),
|
|
140
|
-
/* @__PURE__ */
|
|
143
|
+
/* @__PURE__ */ S("option", {
|
|
141
144
|
value: "ARCHIVED",
|
|
142
|
-
children:
|
|
145
|
+
children: j("toursList.statusArchived")
|
|
143
146
|
}),
|
|
144
|
-
/* @__PURE__ */
|
|
147
|
+
/* @__PURE__ */ S("option", {
|
|
145
148
|
value: "SCHEDULED",
|
|
146
|
-
children:
|
|
149
|
+
children: j("toursList.statusScheduled")
|
|
147
150
|
})
|
|
148
151
|
]
|
|
149
|
-
}), /* @__PURE__ */
|
|
152
|
+
}), /* @__PURE__ */ C("div", {
|
|
150
153
|
className: "flex border border-border-subtle rounded-md overflow-hidden",
|
|
151
|
-
children: [/* @__PURE__ */
|
|
154
|
+
children: [/* @__PURE__ */ S("button", {
|
|
152
155
|
type: "button",
|
|
153
|
-
onClick: () =>
|
|
154
|
-
className: `px-3 py-2 min-h-[44px] ${
|
|
155
|
-
"aria-label":
|
|
156
|
-
title:
|
|
157
|
-
children: /* @__PURE__ */
|
|
158
|
-
}), /* @__PURE__ */
|
|
156
|
+
onClick: () => L("grid"),
|
|
157
|
+
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"}`,
|
|
158
|
+
"aria-label": j("toursList.gridView"),
|
|
159
|
+
title: j("toursList.gridView"),
|
|
160
|
+
children: /* @__PURE__ */ S(g, { size: 20 })
|
|
161
|
+
}), /* @__PURE__ */ S("button", {
|
|
159
162
|
type: "button",
|
|
160
|
-
onClick: () =>
|
|
161
|
-
className: `px-3 py-2 min-h-[44px] ${
|
|
162
|
-
"aria-label":
|
|
163
|
-
title:
|
|
164
|
-
children: /* @__PURE__ */
|
|
163
|
+
onClick: () => L("list"),
|
|
164
|
+
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"}`,
|
|
165
|
+
"aria-label": j("toursList.listView"),
|
|
166
|
+
title: j("toursList.listView"),
|
|
167
|
+
children: /* @__PURE__ */ S(_, { size: 20 })
|
|
165
168
|
})]
|
|
166
169
|
})]
|
|
167
170
|
})]
|
|
168
171
|
}),
|
|
169
|
-
|
|
172
|
+
Y ? /* @__PURE__ */ S("div", {
|
|
170
173
|
className: "text-center py-12",
|
|
171
|
-
children: /* @__PURE__ */
|
|
174
|
+
children: /* @__PURE__ */ S("p", {
|
|
172
175
|
className: "text-sm sm:text-base text-text-secondary",
|
|
173
|
-
children:
|
|
176
|
+
children: j("toursList.loading")
|
|
174
177
|
})
|
|
175
|
-
}) :
|
|
176
|
-
className:
|
|
177
|
-
children:
|
|
178
|
-
let t = e.status, n = t === "DRAFT" &&
|
|
178
|
+
}) : J.length > 0 ? /* @__PURE__ */ S("div", {
|
|
179
|
+
className: P === "grid" ? "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 sm:gap-4" : "space-y-3",
|
|
180
|
+
children: J.map((e) => {
|
|
181
|
+
let t = e.status, n = t === "DRAFT" && K, r = t === "PUBLISHED" && K, i = t !== "ARCHIVED" && te, a = [];
|
|
179
182
|
return n && a.push({
|
|
180
|
-
label:
|
|
181
|
-
onSelect: () => void le(e.id)
|
|
182
|
-
}), r && a.push({
|
|
183
|
-
label: k("toursList.actionUnpublish"),
|
|
184
|
-
onSelect: () => void ue(e.id)
|
|
185
|
-
}), K && a.push({
|
|
186
|
-
label: k("toursList.actionDuplicate"),
|
|
183
|
+
label: j("toursList.actionPublish"),
|
|
187
184
|
onSelect: () => void fe(e.id)
|
|
185
|
+
}), r && a.push({
|
|
186
|
+
label: j("toursList.actionUnpublish"),
|
|
187
|
+
onSelect: () => void pe(e.id)
|
|
188
|
+
}), q && a.push({
|
|
189
|
+
label: j("toursList.actionDuplicate"),
|
|
190
|
+
onSelect: () => void he(e.id)
|
|
188
191
|
}), i && a.push({
|
|
189
|
-
label:
|
|
190
|
-
onSelect: () => void
|
|
191
|
-
}),
|
|
192
|
-
label:
|
|
193
|
-
onSelect: () => void
|
|
192
|
+
label: j("toursList.actionArchive"),
|
|
193
|
+
onSelect: () => void me(e.id)
|
|
194
|
+
}), G && a.push({
|
|
195
|
+
label: j("toursList.actionDelete"),
|
|
196
|
+
onSelect: () => void ge(e.id),
|
|
194
197
|
intent: "destructive"
|
|
195
|
-
}), /* @__PURE__ */
|
|
198
|
+
}), /* @__PURE__ */ C(O, {
|
|
196
199
|
treatment: "plain",
|
|
197
200
|
className: "p-4 border-border-seam shadow-[var(--shadow-pop)]",
|
|
198
201
|
children: [
|
|
199
|
-
/* @__PURE__ */
|
|
202
|
+
/* @__PURE__ */ C("div", {
|
|
200
203
|
className: "flex items-start justify-between mb-2",
|
|
201
|
-
children: [/* @__PURE__ */
|
|
204
|
+
children: [/* @__PURE__ */ S("h3", {
|
|
202
205
|
className: "font-semibold text-text-primary",
|
|
203
|
-
children:
|
|
206
|
+
children: H ? /* @__PURE__ */ S("button", {
|
|
204
207
|
type: "button",
|
|
205
208
|
className: "cursor-pointer hover:text-primary bg-transparent border-0 p-0 text-left font-inherit",
|
|
206
|
-
onClick: () =>
|
|
209
|
+
onClick: () => M(`${N}/${e.id}/edit`),
|
|
207
210
|
children: e.name
|
|
208
211
|
}) : e.name
|
|
209
|
-
}), /* @__PURE__ */
|
|
210
|
-
className: `px-2 py-1 text-xs rounded-full ${e.status === "PUBLISHED" ? "bg-success/10 text-success" : e.status === "DRAFT" ? "bg-bg-sunken text-text-secondary" : "bg-warning/10 text-warning"}`,
|
|
211
|
-
children:
|
|
212
|
+
}), /* @__PURE__ */ S("span", {
|
|
213
|
+
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"}`,
|
|
214
|
+
children: de(t)
|
|
212
215
|
})]
|
|
213
216
|
}),
|
|
214
|
-
e.description && /* @__PURE__ */
|
|
217
|
+
e.description && /* @__PURE__ */ S("p", {
|
|
215
218
|
className: "text-sm text-text-secondary mb-3",
|
|
216
219
|
children: e.description
|
|
217
220
|
}),
|
|
218
|
-
/* @__PURE__ */
|
|
221
|
+
/* @__PURE__ */ C("div", {
|
|
219
222
|
className: "flex items-center justify-between text-xs text-text-secondary mb-3",
|
|
220
|
-
children: [/* @__PURE__ */
|
|
223
|
+
children: [/* @__PURE__ */ C("span", { children: [
|
|
221
224
|
e.steps?.length || 0,
|
|
222
225
|
" ",
|
|
223
|
-
|
|
224
|
-
] }), /* @__PURE__ */
|
|
226
|
+
j("toursList.steps")
|
|
227
|
+
] }), /* @__PURE__ */ C("span", { children: [
|
|
225
228
|
e.viewCount,
|
|
226
229
|
" ",
|
|
227
|
-
|
|
230
|
+
j("toursList.views")
|
|
228
231
|
] })]
|
|
229
232
|
}),
|
|
230
|
-
/* @__PURE__ */
|
|
233
|
+
/* @__PURE__ */ C("div", {
|
|
231
234
|
className: "flex flex-wrap items-center gap-2 pt-3 border-t border-border-seam",
|
|
232
235
|
children: [
|
|
233
|
-
|
|
236
|
+
U && /* @__PURE__ */ C("button", {
|
|
234
237
|
type: "button",
|
|
235
238
|
onClick: (t) => {
|
|
236
|
-
t.stopPropagation(),
|
|
239
|
+
t.stopPropagation(), M(`${N}/${e.id}/steps`);
|
|
237
240
|
},
|
|
238
241
|
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",
|
|
239
|
-
title:
|
|
240
|
-
children: [/* @__PURE__ */
|
|
242
|
+
title: j("toursList.editStepsTitle"),
|
|
243
|
+
children: [/* @__PURE__ */ S(v, { size: 14 }), j("toursList.stepsButton")]
|
|
241
244
|
}),
|
|
242
|
-
|
|
245
|
+
W && /* @__PURE__ */ C("button", {
|
|
243
246
|
type: "button",
|
|
244
247
|
onClick: (t) => {
|
|
245
|
-
t.stopPropagation(),
|
|
248
|
+
t.stopPropagation(), M(`${N}/${e.id}/preview`);
|
|
246
249
|
},
|
|
247
250
|
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",
|
|
248
|
-
title:
|
|
249
|
-
children: [/* @__PURE__ */
|
|
251
|
+
title: j("toursList.previewTitle"),
|
|
252
|
+
children: [/* @__PURE__ */ S(h, { size: 14 }), j("toursList.previewButton")]
|
|
250
253
|
}),
|
|
251
|
-
|
|
254
|
+
H && /* @__PURE__ */ S("button", {
|
|
252
255
|
type: "button",
|
|
253
256
|
onClick: (t) => {
|
|
254
|
-
t.stopPropagation(),
|
|
257
|
+
t.stopPropagation(), M(`${N}/${e.id}/edit`);
|
|
255
258
|
},
|
|
256
259
|
className: "p-2 min-h-[44px] min-w-[44px] text-xs border border-border-seam rounded hover:bg-accent",
|
|
257
|
-
title:
|
|
258
|
-
"aria-label":
|
|
259
|
-
children: /* @__PURE__ */
|
|
260
|
+
title: j("toursList.settingsTitle"),
|
|
261
|
+
"aria-label": j("toursList.settingsTitle"),
|
|
262
|
+
children: /* @__PURE__ */ S(x, { size: 14 })
|
|
260
263
|
}),
|
|
261
|
-
a.length > 0 && /* @__PURE__ */
|
|
264
|
+
a.length > 0 && /* @__PURE__ */ S(D, { actions: a })
|
|
262
265
|
]
|
|
263
266
|
})
|
|
264
267
|
]
|
|
265
268
|
}, e.id);
|
|
266
269
|
})
|
|
267
|
-
}) : /* @__PURE__ */
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
270
|
+
}) : /* @__PURE__ */ S(A, {
|
|
271
|
+
illustration: "onboarding",
|
|
272
|
+
title: j("toursList.emptyTitle"),
|
|
273
|
+
description: j("toursList.emptySubtitle"),
|
|
274
|
+
action: /* @__PURE__ */ S(m, {
|
|
275
|
+
permission: o.TOUR_CREATE,
|
|
276
|
+
children: /* @__PURE__ */ C(E, {
|
|
277
|
+
type: "button",
|
|
278
|
+
onClick: $,
|
|
279
|
+
className: "min-h-[44px]",
|
|
280
|
+
children: [/* @__PURE__ */ S(y, { size: 20 }), j("toursList.createTour")]
|
|
281
|
+
})
|
|
282
|
+
})
|
|
276
283
|
})
|
|
277
284
|
]
|
|
278
285
|
});
|
|
279
286
|
}
|
|
280
287
|
//#endregion
|
|
281
|
-
export {
|
|
288
|
+
export { j as ToursListPage };
|
|
282
289
|
|
|
283
290
|
//# 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-dom';\nimport { Plus, Search, Grid, List as ListIcon, ListOrdered, Eye, Settings } from 'lucide-react';\nimport { PermissionGate } from '@burdenoff/fe-libs/shared/components';\nimport { Button, GlassCard, CTAOverflowMenu, type CTAAction } 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=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3\">\n <div className=\"flex-1 min-w-0\">\n <h1 className=\"text-xl sm:text-2xl font-bold text-text-primary\">{tr('toursList.title')}</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\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'\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 <p className=\"text-sm text-text-secondary mb-3\">{tour.description}</p>\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 && (\n <CTAOverflowMenu actions={overflowActions} />\n )}\n </div>\n </GlassCard>\n );\n })}\n </div>\n ) : (\n <div className=\"text-center py-12 border border-dashed border-border-subtle rounded-md\">\n <p className=\"text-sm sm:text-base text-text-secondary mb-2\">\n {tr('toursList.emptyTitle')}\n </p>\n <p className=\"text-xs sm:text-sm text-text-secondary\">\n {tr('toursList.emptySubtitle')}\n </p>\n </div>\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-dom';\nimport { Plus, Search, Grid, List as ListIcon, ListOrdered, Eye, Settings } from 'lucide-react';\nimport { PermissionGate } from '@burdenoff/fe-libs/shared/components';\nimport {\n AuroraBackground,\n Button,\n GlassCard,\n GradientText,\n IllustratedEmptyState,\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 {/* 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 <p className=\"text-sm text-text-secondary mb-3\">{tour.description}</p>\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 && (\n <CTAOverflowMenu actions={overflowActions} />\n )}\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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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@burdenoff/microfe-tours",
|
|
3
|
-
"version": "2026.625.
|
|
3
|
+
"version": "2026.625.2",
|
|
4
4
|
"description": "Burdenoff Tours Microfrontend - Complete product tours and onboarding interface",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@apollo/client": "^3.12.0",
|
|
46
|
-
"@burdenoff/fe-libs": "2026.625.
|
|
46
|
+
"@burdenoff/fe-libs": "2026.625.3",
|
|
47
47
|
"@tanstack/react-query": "^5.90.16",
|
|
48
48
|
"clsx": "^2.1.1",
|
|
49
49
|
"graphql": "^16.10.0",
|