@burdenoff/microfe-tours 2026.624.1 → 2026.625.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/tours/pages/AnalyticsDashboardPage.js +69 -63
- package/dist/tours/pages/AnalyticsDashboardPage.js.map +1 -1
- package/dist/tours/pages/MediaLibraryPage.js +49 -47
- package/dist/tours/pages/MediaLibraryPage.js.map +1 -1
- package/dist/tours/pages/MyToursPage.js +28 -26
- package/dist/tours/pages/MyToursPage.js.map +1 -1
- package/dist/tours/pages/MyToursProgressPage.js +50 -46
- package/dist/tours/pages/MyToursProgressPage.js.map +1 -1
- package/dist/tours/pages/SchedulerPage.js +91 -85
- package/dist/tours/pages/SchedulerPage.js.map +1 -1
- package/dist/tours/pages/StepEditorPage.js +217 -216
- package/dist/tours/pages/StepEditorPage.js.map +1 -1
- package/dist/tours/pages/SystemAnalyticsPage.js +47 -41
- package/dist/tours/pages/SystemAnalyticsPage.js.map +1 -1
- package/dist/tours/pages/TemplateLibraryPage.js +53 -51
- package/dist/tours/pages/TemplateLibraryPage.js.map +1 -1
- package/dist/tours/pages/TourBuilderPage.js +152 -165
- package/dist/tours/pages/TourBuilderPage.js.map +1 -1
- package/dist/tours/pages/TourPreviewPage.js +71 -68
- package/dist/tours/pages/TourPreviewPage.js.map +1 -1
- package/dist/tours/pages/ToursListPage.js +157 -201
- package/dist/tours/pages/ToursListPage.js.map +1 -1
- package/package.json +2 -2
|
@@ -5,41 +5,42 @@ 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 {
|
|
8
|
+
import { GlassCard as f } from "@burdenoff/fe-libs/ui";
|
|
9
|
+
import { useEventBus as p } from "@burdenoff/fe-libs/shared/events";
|
|
9
10
|
//#region src/tours/pages/MyToursPage.tsx
|
|
10
|
-
var
|
|
11
|
-
function h(e, t) {
|
|
12
|
-
return e && p.test(e) ? e : t;
|
|
13
|
-
}
|
|
11
|
+
var m = /^[a-zA-Z0-9_-]+$/, h = /^[a-zA-Z0-9_\-/]+$/;
|
|
14
12
|
function g(e, t) {
|
|
15
13
|
return e && m.test(e) ? e : t;
|
|
16
14
|
}
|
|
17
|
-
function _() {
|
|
18
|
-
|
|
15
|
+
function _(e, t) {
|
|
16
|
+
return e && h.test(e) ? e : t;
|
|
17
|
+
}
|
|
18
|
+
function v() {
|
|
19
|
+
let { tr: a } = n(), { productId: o, moduleId: s, pageId: c, workspaceId: m } = e(), [h] = d(), v = p(), b = i(!1);
|
|
19
20
|
r(() => {
|
|
20
|
-
|
|
21
|
+
b.current || (b.current = !0, v.emit("tours.page.viewed", {
|
|
21
22
|
page: "/tours",
|
|
22
23
|
productId: o,
|
|
23
24
|
moduleId: s,
|
|
24
25
|
pageId: c,
|
|
25
|
-
workspaceId:
|
|
26
|
+
workspaceId: m
|
|
26
27
|
}));
|
|
27
28
|
}, [
|
|
28
|
-
|
|
29
|
+
v,
|
|
29
30
|
o,
|
|
30
31
|
s,
|
|
31
32
|
c,
|
|
32
|
-
|
|
33
|
+
m
|
|
33
34
|
]);
|
|
34
|
-
let
|
|
35
|
-
variables:
|
|
36
|
-
productId:
|
|
37
|
-
moduleId:
|
|
38
|
-
pageId:
|
|
35
|
+
let x = g(o, void 0) ?? g(h.get("productId"), void 0), S = g(s, void 0) ?? g(h.get("moduleId"), void 0), C = _(c, void 0) ?? _(h.get("pageId"), void 0), { data: w, loading: T } = t({
|
|
36
|
+
variables: x ? { context: {
|
|
37
|
+
productId: x,
|
|
38
|
+
moduleId: S,
|
|
39
|
+
pageId: C
|
|
39
40
|
} } : void 0,
|
|
40
|
-
skip: !
|
|
41
|
+
skip: !x,
|
|
41
42
|
fetchPolicy: "cache-and-network"
|
|
42
|
-
}),
|
|
43
|
+
}), E = w?.toursForContext ?? [], D = T;
|
|
43
44
|
return /* @__PURE__ */ u("div", {
|
|
44
45
|
className: "space-y-4 sm:space-y-6 p-3 sm:p-6",
|
|
45
46
|
children: [/* @__PURE__ */ u("div", { children: [/* @__PURE__ */ l("h1", {
|
|
@@ -48,10 +49,10 @@ function _() {
|
|
|
48
49
|
}), /* @__PURE__ */ l("p", {
|
|
49
50
|
className: "text-sm sm:text-base text-text-secondary",
|
|
50
51
|
children: a("myTours.subtitle")
|
|
51
|
-
})] }),
|
|
52
|
+
})] }), D && E.length === 0 ? /* @__PURE__ */ l("output", {
|
|
52
53
|
className: "text-sm text-text-secondary",
|
|
53
54
|
children: a("myTours.loading")
|
|
54
|
-
}) :
|
|
55
|
+
}) : E.length === 0 ? /* @__PURE__ */ l("div", {
|
|
55
56
|
className: "rounded-lg border border-dashed border-border-subtle p-8 text-center",
|
|
56
57
|
children: /* @__PURE__ */ l("output", {
|
|
57
58
|
className: "block text-sm text-text-secondary",
|
|
@@ -59,14 +60,15 @@ function _() {
|
|
|
59
60
|
})
|
|
60
61
|
}) : /* @__PURE__ */ l("ul", {
|
|
61
62
|
className: "grid gap-3 grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
|
|
62
|
-
children:
|
|
63
|
-
|
|
63
|
+
children: E.map((e) => /* @__PURE__ */ l("li", { children: /* @__PURE__ */ u(f, {
|
|
64
|
+
treatment: "plain",
|
|
65
|
+
className: "h-full p-4 flex flex-col gap-2 border-border-seam shadow-[var(--shadow-pop)]",
|
|
64
66
|
children: [/* @__PURE__ */ u("div", {
|
|
65
67
|
className: "flex items-start justify-between gap-2",
|
|
66
68
|
children: [/* @__PURE__ */ l("h2", {
|
|
67
69
|
className: "font-semibold text-text-primary line-clamp-2",
|
|
68
70
|
children: e.name
|
|
69
|
-
}), /* @__PURE__ */ l(
|
|
71
|
+
}), /* @__PURE__ */ l(y, {
|
|
70
72
|
status: e.myProgress?.status,
|
|
71
73
|
tr: a
|
|
72
74
|
})]
|
|
@@ -74,11 +76,11 @@ function _() {
|
|
|
74
76
|
className: "text-sm text-text-secondary line-clamp-3",
|
|
75
77
|
children: e.description
|
|
76
78
|
}) : null]
|
|
77
|
-
}, e.id))
|
|
79
|
+
}) }, e.id))
|
|
78
80
|
})]
|
|
79
81
|
});
|
|
80
82
|
}
|
|
81
|
-
function
|
|
83
|
+
function y({ status: e, tr: t }) {
|
|
82
84
|
switch (e) {
|
|
83
85
|
case "COMPLETED": return /* @__PURE__ */ u("span", {
|
|
84
86
|
className: "inline-flex items-center gap-1 text-xs text-success",
|
|
@@ -100,6 +102,6 @@ function v({ status: e, tr: t }) {
|
|
|
100
102
|
}
|
|
101
103
|
}
|
|
102
104
|
//#endregion
|
|
103
|
-
export {
|
|
105
|
+
export { v as MyToursPage };
|
|
104
106
|
|
|
105
107
|
//# 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';\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 <div className=\"rounded-lg border border-dashed border-border-subtle p-8 text-center\">\n <output className=\"block text-sm text-text-secondary\">{tr('myTours.empty')}</output>\n </div>\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
|
|
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 <div className=\"rounded-lg border border-dashed border-border-subtle p-8 text-center\">\n <output className=\"block text-sm text-text-secondary\">{tr('myTours.empty')}</output>\n </div>\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\">\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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"}
|
|
@@ -4,105 +4,109 @@ import { useToursI18n as n } from "../i18n.js";
|
|
|
4
4
|
import { useEffect as r, useMemo as i, useRef as a } from "react";
|
|
5
5
|
import { CheckCircle2 as o, HelpCircle as s, MinusCircle as c, Play as l } from "lucide-react";
|
|
6
6
|
import { jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
7
|
-
import {
|
|
7
|
+
import { EmphasisPanel as f } from "@burdenoff/fe-libs/ui";
|
|
8
|
+
import { useEventBus as p } from "@burdenoff/fe-libs/shared/events";
|
|
8
9
|
//#region src/tours/pages/MyToursProgressPage.tsx
|
|
9
|
-
function
|
|
10
|
-
let { tr:
|
|
10
|
+
function m() {
|
|
11
|
+
let { tr: m } = n(), { currentUser: g, productId: _, moduleId: v, pageId: y, workspaceId: b } = e(), x = p(), S = a(!1);
|
|
11
12
|
r(() => {
|
|
12
|
-
|
|
13
|
+
S.current || (S.current = !0, x.emit("tours.page.viewed", {
|
|
13
14
|
page: "/tours/progress",
|
|
14
|
-
productId:
|
|
15
|
-
moduleId:
|
|
16
|
-
pageId:
|
|
17
|
-
workspaceId:
|
|
15
|
+
productId: _,
|
|
16
|
+
moduleId: v,
|
|
17
|
+
pageId: y,
|
|
18
|
+
workspaceId: b
|
|
18
19
|
}));
|
|
19
20
|
}, [
|
|
20
|
-
|
|
21
|
-
g,
|
|
21
|
+
x,
|
|
22
22
|
_,
|
|
23
23
|
v,
|
|
24
|
-
y
|
|
24
|
+
y,
|
|
25
|
+
b
|
|
25
26
|
]);
|
|
26
|
-
let { data:
|
|
27
|
+
let { data: C, loading: w } = t({
|
|
27
28
|
variables: {
|
|
28
|
-
userId:
|
|
29
|
+
userId: g?.id,
|
|
29
30
|
pagination: {
|
|
30
31
|
limit: 100,
|
|
31
32
|
offset: 0
|
|
32
33
|
}
|
|
33
34
|
},
|
|
34
|
-
skip: !
|
|
35
|
+
skip: !g?.id,
|
|
35
36
|
fetchPolicy: "cache-and-network"
|
|
36
|
-
}),
|
|
37
|
+
}), T = i(() => {
|
|
37
38
|
let e = {
|
|
38
39
|
IN_PROGRESS: [],
|
|
39
40
|
COMPLETED: [],
|
|
40
41
|
SKIPPED: [],
|
|
41
42
|
OTHER: []
|
|
42
|
-
}, t = (
|
|
43
|
+
}, t = (C?.userTourProgresses ?? []).filter((e) => !(_ && e.tour.productId !== _ || v && e.tour.moduleId && e.tour.moduleId !== v || y && e.tour.pageId && e.tour.pageId !== y));
|
|
43
44
|
for (let n of t) n.status === "COMPLETED" ? e.COMPLETED.push(n) : n.status === "IN_PROGRESS" ? e.IN_PROGRESS.push(n) : n.status === "SKIPPED" || n.status === "DISMISSED" ? e.SKIPPED.push(n) : e.OTHER.push(n);
|
|
44
45
|
return e;
|
|
45
46
|
}, [
|
|
46
|
-
|
|
47
|
-
g,
|
|
47
|
+
C,
|
|
48
48
|
_,
|
|
49
|
-
v
|
|
49
|
+
v,
|
|
50
|
+
y
|
|
50
51
|
]);
|
|
51
52
|
return /* @__PURE__ */ d("div", {
|
|
52
53
|
className: "space-y-4 sm:space-y-6 p-3 sm:p-6",
|
|
53
54
|
children: [/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("h1", {
|
|
54
55
|
className: "text-xl sm:text-2xl font-bold text-text-primary",
|
|
55
|
-
children:
|
|
56
|
+
children: m("myToursProgress.title")
|
|
56
57
|
}), /* @__PURE__ */ u("p", {
|
|
57
58
|
className: "text-sm sm:text-base text-text-secondary",
|
|
58
|
-
children:
|
|
59
|
-
})] }),
|
|
59
|
+
children: m("myToursProgress.subtitle")
|
|
60
|
+
})] }), w && (C?.userTourProgresses?.length ?? 0) === 0 ? /* @__PURE__ */ u("output", {
|
|
60
61
|
className: "text-sm text-text-secondary",
|
|
61
|
-
children:
|
|
62
|
+
children: m("myToursProgress.loading")
|
|
62
63
|
}) : /* @__PURE__ */ d("div", {
|
|
63
64
|
className: "space-y-6",
|
|
64
65
|
children: [
|
|
65
|
-
/* @__PURE__ */ u(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
66
|
+
/* @__PURE__ */ u(f, {
|
|
67
|
+
className: "p-4 sm:p-5",
|
|
68
|
+
children: /* @__PURE__ */ u(h, {
|
|
69
|
+
title: m("myToursProgress.inProgress"),
|
|
70
|
+
icon: /* @__PURE__ */ u(l, {
|
|
71
|
+
size: 16,
|
|
72
|
+
className: "text-warning"
|
|
73
|
+
}),
|
|
74
|
+
rows: T.IN_PROGRESS,
|
|
75
|
+
emptyText: m("myToursProgress.emptyInProgress")
|
|
76
|
+
})
|
|
73
77
|
}),
|
|
74
|
-
/* @__PURE__ */ u(
|
|
75
|
-
title:
|
|
78
|
+
/* @__PURE__ */ u(h, {
|
|
79
|
+
title: m("myToursProgress.completed"),
|
|
76
80
|
icon: /* @__PURE__ */ u(o, {
|
|
77
81
|
size: 16,
|
|
78
82
|
className: "text-success"
|
|
79
83
|
}),
|
|
80
|
-
rows:
|
|
81
|
-
emptyText:
|
|
84
|
+
rows: T.COMPLETED,
|
|
85
|
+
emptyText: m("myToursProgress.emptyCompleted")
|
|
82
86
|
}),
|
|
83
|
-
/* @__PURE__ */ u(
|
|
84
|
-
title:
|
|
87
|
+
/* @__PURE__ */ u(h, {
|
|
88
|
+
title: m("myToursProgress.skipped"),
|
|
85
89
|
icon: /* @__PURE__ */ u(c, {
|
|
86
90
|
size: 16,
|
|
87
91
|
className: "text-text-secondary"
|
|
88
92
|
}),
|
|
89
|
-
rows:
|
|
90
|
-
emptyText:
|
|
93
|
+
rows: T.SKIPPED,
|
|
94
|
+
emptyText: m("myToursProgress.emptySkipped")
|
|
91
95
|
}),
|
|
92
|
-
|
|
93
|
-
title:
|
|
96
|
+
T.OTHER.length > 0 ? /* @__PURE__ */ u(h, {
|
|
97
|
+
title: m("myToursProgress.other"),
|
|
94
98
|
icon: /* @__PURE__ */ u(s, {
|
|
95
99
|
size: 16,
|
|
96
100
|
className: "text-text-secondary"
|
|
97
101
|
}),
|
|
98
|
-
rows:
|
|
99
|
-
emptyText:
|
|
102
|
+
rows: T.OTHER,
|
|
103
|
+
emptyText: m("myToursProgress.emptyOther")
|
|
100
104
|
}) : null
|
|
101
105
|
]
|
|
102
106
|
})]
|
|
103
107
|
});
|
|
104
108
|
}
|
|
105
|
-
function
|
|
109
|
+
function h({ title: e, icon: t, rows: n, emptyText: r }) {
|
|
106
110
|
return /* @__PURE__ */ d("section", {
|
|
107
111
|
className: "space-y-2",
|
|
108
112
|
children: [/* @__PURE__ */ d("h2", {
|
|
@@ -125,7 +129,7 @@ function m({ title: e, icon: t, rows: n, emptyText: r }) {
|
|
|
125
129
|
"aria-live": "polite",
|
|
126
130
|
children: r
|
|
127
131
|
}) : /* @__PURE__ */ u("ul", {
|
|
128
|
-
className: "divide-y divide-border rounded-md border border-border-
|
|
132
|
+
className: "divide-y divide-border-seam rounded-md border border-border-seam",
|
|
129
133
|
children: n.map((e) => /* @__PURE__ */ d("li", {
|
|
130
134
|
className: "flex items-center justify-between gap-3 p-3",
|
|
131
135
|
children: [/* @__PURE__ */ u("span", {
|
|
@@ -141,6 +145,6 @@ function m({ title: e, icon: t, rows: n, emptyText: r }) {
|
|
|
141
145
|
});
|
|
142
146
|
}
|
|
143
147
|
//#endregion
|
|
144
|
-
export {
|
|
148
|
+
export { m as MyToursProgressPage };
|
|
145
149
|
|
|
146
150
|
//# sourceMappingURL=MyToursProgressPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MyToursProgressPage.js","names":[],"sources":["../../../src/tours/pages/MyToursProgressPage.tsx"],"sourcesContent":["import { useMemo, useEffect, useRef } from 'react';\nimport { CheckCircle2, HelpCircle, MinusCircle, Play } from 'lucide-react';\nimport { useGetUserTourProgressesQuery } from '../../generated/global-operations';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { useToursI18n } from '../i18n';\nimport { useEventBus } from '@burdenoff/fe-libs/shared/events';\n\ntype ProgressGroup = 'IN_PROGRESS' | 'COMPLETED' | 'SKIPPED' | 'OTHER';\n\ntype ProgressRow = {\n id: string;\n status: string;\n tour: { id: string; name: string; productId?: string; moduleId?: string; pageId?: string };\n lastViewedAt?: string | null;\n};\n\n/**\n * MyToursProgressPage — user-facing read-only view of the current user's\n * tour interactions, grouped by status (In progress / Completed / Skipped).\n */\nexport function MyToursProgressPage() {\n const { tr } = useToursI18n();\n const {\n currentUser,\n productId: shellProductId,\n moduleId: shellModuleId,\n pageId: shellPageId,\n workspaceId,\n } = useToursContext();\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/progress',\n productId: shellProductId,\n moduleId: shellModuleId,\n pageId: shellPageId,\n workspaceId,\n });\n }, [eventBus, shellProductId, shellModuleId, shellPageId, workspaceId]);\n\n const { data, loading } = useGetUserTourProgressesQuery({\n variables: { userId: currentUser?.id, pagination: { limit: 100, offset: 0 } },\n skip: !currentUser?.id,\n fetchPolicy: 'cache-and-network',\n });\n\n const grouped = useMemo(() => {\n const result: Record<ProgressGroup, NonNullable<typeof data>['userTourProgresses']> = {\n IN_PROGRESS: [],\n COMPLETED: [],\n SKIPPED: [],\n OTHER: [],\n };\n // Filter the raw progress list to the shell's product/module/page context\n // so a user's vibecontrols session doesn't see workspaces / bigconsole\n // progress rows. `userTourProgresses` returns everything scoped by userId;\n // this MFE is mounted per-shell so we narrow to what the shell advertises.\n // When the shell didn't supply a filter, the corresponding level is not\n // checked (e.g., no shellModuleId → accept any moduleId).\n const rows = (data?.userTourProgresses ?? []).filter((row: ProgressRow) => {\n if (shellProductId && row.tour.productId !== shellProductId) return false;\n if (shellModuleId && row.tour.moduleId && row.tour.moduleId !== shellModuleId) return false;\n if (shellPageId && row.tour.pageId && row.tour.pageId !== shellPageId) return false;\n return true;\n });\n for (const row of rows) {\n if (row.status === 'COMPLETED') result.COMPLETED.push(row);\n else if (row.status === 'IN_PROGRESS') result.IN_PROGRESS.push(row);\n else if (row.status === 'SKIPPED' || row.status === 'DISMISSED') result.SKIPPED.push(row);\n // Unknown / future status values fall through here so nothing is\n // silently dropped if the backend introduces a new state.\n else result.OTHER.push(row);\n }\n return result;\n }, [data, shellProductId, shellModuleId, shellPageId]);\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 {tr('myToursProgress.title')}\n </h1>\n <p className=\"text-sm sm:text-base text-text-secondary\">\n {tr('myToursProgress.subtitle')}\n </p>\n </div>\n\n {loading && (data?.userTourProgresses?.length ?? 0) === 0 ? (\n <output className=\"text-sm text-text-secondary\">{tr('myToursProgress.loading')}</output>\n ) : (\n <div className=\"space-y-6\">\n <ProgressSection\n
|
|
1
|
+
{"version":3,"file":"MyToursProgressPage.js","names":[],"sources":["../../../src/tours/pages/MyToursProgressPage.tsx"],"sourcesContent":["import { useMemo, useEffect, useRef } from 'react';\nimport { CheckCircle2, HelpCircle, MinusCircle, Play } from 'lucide-react';\nimport { useGetUserTourProgressesQuery } from '../../generated/global-operations';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { useToursI18n } from '../i18n';\nimport { useEventBus } from '@burdenoff/fe-libs/shared/events';\nimport { EmphasisPanel } from '@burdenoff/fe-libs/ui';\n\ntype ProgressGroup = 'IN_PROGRESS' | 'COMPLETED' | 'SKIPPED' | 'OTHER';\n\ntype ProgressRow = {\n id: string;\n status: string;\n tour: { id: string; name: string; productId?: string; moduleId?: string; pageId?: string };\n lastViewedAt?: string | null;\n};\n\n/**\n * MyToursProgressPage — user-facing read-only view of the current user's\n * tour interactions, grouped by status (In progress / Completed / Skipped).\n */\nexport function MyToursProgressPage() {\n const { tr } = useToursI18n();\n const {\n currentUser,\n productId: shellProductId,\n moduleId: shellModuleId,\n pageId: shellPageId,\n workspaceId,\n } = useToursContext();\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/progress',\n productId: shellProductId,\n moduleId: shellModuleId,\n pageId: shellPageId,\n workspaceId,\n });\n }, [eventBus, shellProductId, shellModuleId, shellPageId, workspaceId]);\n\n const { data, loading } = useGetUserTourProgressesQuery({\n variables: { userId: currentUser?.id, pagination: { limit: 100, offset: 0 } },\n skip: !currentUser?.id,\n fetchPolicy: 'cache-and-network',\n });\n\n const grouped = useMemo(() => {\n const result: Record<ProgressGroup, NonNullable<typeof data>['userTourProgresses']> = {\n IN_PROGRESS: [],\n COMPLETED: [],\n SKIPPED: [],\n OTHER: [],\n };\n // Filter the raw progress list to the shell's product/module/page context\n // so a user's vibecontrols session doesn't see workspaces / bigconsole\n // progress rows. `userTourProgresses` returns everything scoped by userId;\n // this MFE is mounted per-shell so we narrow to what the shell advertises.\n // When the shell didn't supply a filter, the corresponding level is not\n // checked (e.g., no shellModuleId → accept any moduleId).\n const rows = (data?.userTourProgresses ?? []).filter((row: ProgressRow) => {\n if (shellProductId && row.tour.productId !== shellProductId) return false;\n if (shellModuleId && row.tour.moduleId && row.tour.moduleId !== shellModuleId) return false;\n if (shellPageId && row.tour.pageId && row.tour.pageId !== shellPageId) return false;\n return true;\n });\n for (const row of rows) {\n if (row.status === 'COMPLETED') result.COMPLETED.push(row);\n else if (row.status === 'IN_PROGRESS') result.IN_PROGRESS.push(row);\n else if (row.status === 'SKIPPED' || row.status === 'DISMISSED') result.SKIPPED.push(row);\n // Unknown / future status values fall through here so nothing is\n // silently dropped if the backend introduces a new state.\n else result.OTHER.push(row);\n }\n return result;\n }, [data, shellProductId, shellModuleId, shellPageId]);\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 {tr('myToursProgress.title')}\n </h1>\n <p className=\"text-sm sm:text-base text-text-secondary\">\n {tr('myToursProgress.subtitle')}\n </p>\n </div>\n\n {loading && (data?.userTourProgresses?.length ?? 0) === 0 ? (\n <output className=\"text-sm text-text-secondary\">{tr('myToursProgress.loading')}</output>\n ) : (\n <div className=\"space-y-6\">\n <EmphasisPanel className=\"p-4 sm:p-5\">\n <ProgressSection\n title={tr('myToursProgress.inProgress')}\n icon={<Play size={16} className=\"text-warning\" />}\n rows={grouped.IN_PROGRESS}\n emptyText={tr('myToursProgress.emptyInProgress')}\n />\n </EmphasisPanel>\n <ProgressSection\n title={tr('myToursProgress.completed')}\n icon={<CheckCircle2 size={16} className=\"text-success\" />}\n rows={grouped.COMPLETED}\n emptyText={tr('myToursProgress.emptyCompleted')}\n />\n <ProgressSection\n title={tr('myToursProgress.skipped')}\n icon={<MinusCircle size={16} className=\"text-text-secondary\" />}\n rows={grouped.SKIPPED}\n emptyText={tr('myToursProgress.emptySkipped')}\n />\n {grouped.OTHER.length > 0 ? (\n <ProgressSection\n title={tr('myToursProgress.other')}\n icon={<HelpCircle size={16} className=\"text-text-secondary\" />}\n rows={grouped.OTHER}\n emptyText={tr('myToursProgress.emptyOther')}\n />\n ) : null}\n </div>\n )}\n </div>\n );\n}\n\nfunction ProgressSection({\n title,\n icon,\n rows,\n emptyText,\n}: {\n title: string;\n icon: React.ReactNode;\n rows: Array<{ id: string; tour: { id: string; name: string }; lastViewedAt?: string | null }>;\n emptyText: string;\n}) {\n return (\n <section className=\"space-y-2\">\n <h2 className=\"flex items-center gap-2 text-sm font-semibold text-text-primary\">\n {icon}\n {title}\n <span className=\"text-xs text-text-secondary font-normal\">({rows.length})</span>\n </h2>\n {rows.length === 0 ? (\n <p className=\"text-sm text-text-secondary\" role=\"status\" aria-live=\"polite\">\n {emptyText}\n </p>\n ) : (\n <ul className=\"divide-y divide-border-seam rounded-md border border-border-seam\">\n {rows.map((row) => (\n <li key={row.id} className=\"flex items-center justify-between gap-3 p-3\">\n <span className=\"text-sm text-text-primary line-clamp-1\">{row.tour.name}</span>\n {row.lastViewedAt ? (\n <time className=\"text-xs text-text-secondary\" dateTime={row.lastViewedAt}>\n {new Date(row.lastViewedAt).toLocaleDateString()}\n </time>\n ) : null}\n </li>\n ))}\n </ul>\n )}\n </section>\n );\n}\n"],"mappings":"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"}
|