@burdenoff/microfe-tours 2026.527.2 → 2026.527.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/tours/ToursUserRoutes.js +2 -4
- package/dist/tours/ToursUserRoutes.js.map +1 -1
- package/dist/tours/components/RouteHelpers.js +4 -4
- package/dist/tours/components/RouteHelpers.js.map +1 -1
- package/dist/tours/hooks/useTourPreview.js +39 -39
- package/dist/tours/hooks/useTourPreview.js.map +1 -1
- package/dist/tours/hooks/useToursList.js.map +1 -1
- package/dist/tours/pages/MediaLibraryPage.js +11 -8
- package/dist/tours/pages/MediaLibraryPage.js.map +1 -1
- package/dist/tours/pages/MyToursPage.js +59 -57
- package/dist/tours/pages/MyToursPage.js.map +1 -1
- package/dist/tours/pages/MyToursProgressPage.js +65 -61
- package/dist/tours/pages/MyToursProgressPage.js.map +1 -1
- package/dist/tours/pages/SchedulerPage.js +18 -4
- package/dist/tours/pages/SchedulerPage.js.map +1 -1
- package/dist/tours/pages/StepEditorPage.js +330 -276
- package/dist/tours/pages/StepEditorPage.js.map +1 -1
- package/dist/tours/pages/TemplateLibraryPage.js +7 -2
- package/dist/tours/pages/TemplateLibraryPage.js.map +1 -1
- package/dist/tours/pages/TourBuilderPage.js +25 -11
- package/dist/tours/pages/TourBuilderPage.js.map +1 -1
- package/dist/tours/pages/TourPreviewPage.js +12 -4
- package/dist/tours/pages/TourPreviewPage.js.map +1 -1
- package/dist/tours/pages/ToursListPage.js +165 -149
- package/dist/tours/pages/ToursListPage.js.map +1 -1
- package/dist/tours/providers/ToursProvider.js +1 -1
- package/dist/tours/providers/ToursProvider.js.map +1 -1
- package/dist/tours/utils/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,112 +1,116 @@
|
|
|
1
1
|
import { useToursContext as e } from "../providers/ToursProvider.js";
|
|
2
2
|
import { useGetUserTourProgressesQuery as t } from "../../generated/global-operations.js";
|
|
3
3
|
import { useToursI18n as n } from "../i18n.js";
|
|
4
|
-
import { useEffect as r, useMemo as i } from "react";
|
|
5
|
-
import { CheckCircle2 as
|
|
6
|
-
import { jsx as
|
|
7
|
-
import { useEventBus as
|
|
4
|
+
import { useEffect as r, useMemo as i, useRef as a } from "react";
|
|
5
|
+
import { CheckCircle2 as o, HelpCircle as s, MinusCircle as c, Play as l } from "lucide-react";
|
|
6
|
+
import { jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
7
|
+
import { useEventBus as f } from "@burdenoff/fe-libs/shared/events";
|
|
8
8
|
//#region src/tours/pages/MyToursProgressPage.tsx
|
|
9
|
-
function
|
|
10
|
-
let { tr:
|
|
9
|
+
function p() {
|
|
10
|
+
let { tr: p } = n(), { currentUser: h, productId: g, moduleId: _, pageId: v, workspaceId: y } = e(), b = f(), x = a(!1);
|
|
11
11
|
r(() => {
|
|
12
|
-
|
|
12
|
+
x.current || (x.current = !0, b.emit("tours.page.viewed", {
|
|
13
13
|
page: "/tours/progress",
|
|
14
|
-
productId:
|
|
15
|
-
moduleId:
|
|
16
|
-
pageId:
|
|
17
|
-
workspaceId:
|
|
18
|
-
});
|
|
19
|
-
}, [
|
|
20
|
-
|
|
14
|
+
productId: g,
|
|
15
|
+
moduleId: _,
|
|
16
|
+
pageId: v,
|
|
17
|
+
workspaceId: y
|
|
18
|
+
}));
|
|
19
|
+
}, [
|
|
20
|
+
b,
|
|
21
|
+
g,
|
|
22
|
+
_,
|
|
23
|
+
v,
|
|
24
|
+
y
|
|
25
|
+
]);
|
|
26
|
+
let { data: S, loading: C } = t({
|
|
21
27
|
variables: {
|
|
22
|
-
userId:
|
|
28
|
+
userId: h?.id,
|
|
23
29
|
pagination: {
|
|
24
30
|
limit: 100,
|
|
25
31
|
offset: 0
|
|
26
32
|
}
|
|
27
33
|
},
|
|
28
|
-
skip: !
|
|
34
|
+
skip: !h?.id,
|
|
29
35
|
fetchPolicy: "cache-and-network"
|
|
30
|
-
}),
|
|
36
|
+
}), w = i(() => {
|
|
31
37
|
let e = {
|
|
32
38
|
IN_PROGRESS: [],
|
|
33
39
|
COMPLETED: [],
|
|
34
40
|
SKIPPED: [],
|
|
35
41
|
OTHER: []
|
|
36
|
-
}, t = (
|
|
42
|
+
}, t = (S?.userTourProgresses ?? []).filter((e) => !(g && e.tour.productId !== g || _ && e.tour.moduleId && e.tour.moduleId !== _ || v && e.tour.pageId && e.tour.pageId !== v));
|
|
37
43
|
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);
|
|
38
44
|
return e;
|
|
39
45
|
}, [
|
|
40
|
-
|
|
41
|
-
h,
|
|
46
|
+
S,
|
|
42
47
|
g,
|
|
43
|
-
_
|
|
48
|
+
_,
|
|
49
|
+
v
|
|
44
50
|
]);
|
|
45
|
-
return /* @__PURE__ */
|
|
51
|
+
return /* @__PURE__ */ d("div", {
|
|
46
52
|
className: "space-y-4 sm:space-y-6 p-3 sm:p-6",
|
|
47
|
-
children: [/* @__PURE__ */
|
|
53
|
+
children: [/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("h1", {
|
|
48
54
|
className: "text-xl sm:text-2xl font-bold text-foreground",
|
|
49
|
-
children:
|
|
50
|
-
}), /* @__PURE__ */
|
|
55
|
+
children: p("myToursProgress.title")
|
|
56
|
+
}), /* @__PURE__ */ u("p", {
|
|
51
57
|
className: "text-sm sm:text-base text-muted-foreground",
|
|
52
|
-
children:
|
|
53
|
-
})] }),
|
|
58
|
+
children: p("myToursProgress.subtitle")
|
|
59
|
+
})] }), C && (S?.userTourProgresses?.length ?? 0) === 0 ? /* @__PURE__ */ u("output", {
|
|
54
60
|
className: "text-sm text-muted-foreground",
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
children: f("myToursProgress.loading")
|
|
58
|
-
}) : /* @__PURE__ */ u("div", {
|
|
61
|
+
children: p("myToursProgress.loading")
|
|
62
|
+
}) : /* @__PURE__ */ d("div", {
|
|
59
63
|
className: "space-y-6",
|
|
60
64
|
children: [
|
|
61
|
-
/* @__PURE__ */
|
|
62
|
-
title:
|
|
63
|
-
icon: /* @__PURE__ */ l
|
|
65
|
+
/* @__PURE__ */ u(m, {
|
|
66
|
+
title: p("myToursProgress.inProgress"),
|
|
67
|
+
icon: /* @__PURE__ */ u(l, {
|
|
64
68
|
size: 16,
|
|
65
69
|
className: "text-warning"
|
|
66
70
|
}),
|
|
67
|
-
rows:
|
|
68
|
-
emptyText:
|
|
71
|
+
rows: w.IN_PROGRESS,
|
|
72
|
+
emptyText: p("myToursProgress.emptyInProgress")
|
|
69
73
|
}),
|
|
70
|
-
/* @__PURE__ */
|
|
71
|
-
title:
|
|
72
|
-
icon: /* @__PURE__ */
|
|
74
|
+
/* @__PURE__ */ u(m, {
|
|
75
|
+
title: p("myToursProgress.completed"),
|
|
76
|
+
icon: /* @__PURE__ */ u(o, {
|
|
73
77
|
size: 16,
|
|
74
78
|
className: "text-success"
|
|
75
79
|
}),
|
|
76
|
-
rows:
|
|
77
|
-
emptyText:
|
|
80
|
+
rows: w.COMPLETED,
|
|
81
|
+
emptyText: p("myToursProgress.emptyCompleted")
|
|
78
82
|
}),
|
|
79
|
-
/* @__PURE__ */
|
|
80
|
-
title:
|
|
81
|
-
icon: /* @__PURE__ */
|
|
83
|
+
/* @__PURE__ */ u(m, {
|
|
84
|
+
title: p("myToursProgress.skipped"),
|
|
85
|
+
icon: /* @__PURE__ */ u(c, {
|
|
82
86
|
size: 16,
|
|
83
87
|
className: "text-muted-foreground"
|
|
84
88
|
}),
|
|
85
|
-
rows:
|
|
86
|
-
emptyText:
|
|
89
|
+
rows: w.SKIPPED,
|
|
90
|
+
emptyText: p("myToursProgress.emptySkipped")
|
|
87
91
|
}),
|
|
88
|
-
|
|
89
|
-
title:
|
|
90
|
-
icon: /* @__PURE__ */
|
|
92
|
+
w.OTHER.length > 0 ? /* @__PURE__ */ u(m, {
|
|
93
|
+
title: p("myToursProgress.other"),
|
|
94
|
+
icon: /* @__PURE__ */ u(s, {
|
|
91
95
|
size: 16,
|
|
92
96
|
className: "text-muted-foreground"
|
|
93
97
|
}),
|
|
94
|
-
rows:
|
|
95
|
-
emptyText:
|
|
98
|
+
rows: w.OTHER,
|
|
99
|
+
emptyText: p("myToursProgress.emptyOther")
|
|
96
100
|
}) : null
|
|
97
101
|
]
|
|
98
102
|
})]
|
|
99
103
|
});
|
|
100
104
|
}
|
|
101
|
-
function
|
|
102
|
-
return /* @__PURE__ */
|
|
105
|
+
function m({ title: e, icon: t, rows: n, emptyText: r }) {
|
|
106
|
+
return /* @__PURE__ */ d("section", {
|
|
103
107
|
className: "space-y-2",
|
|
104
|
-
children: [/* @__PURE__ */
|
|
108
|
+
children: [/* @__PURE__ */ d("h2", {
|
|
105
109
|
className: "flex items-center gap-2 text-sm font-semibold text-foreground",
|
|
106
110
|
children: [
|
|
107
111
|
t,
|
|
108
112
|
e,
|
|
109
|
-
/* @__PURE__ */
|
|
113
|
+
/* @__PURE__ */ d("span", {
|
|
110
114
|
className: "text-xs text-muted-foreground font-normal",
|
|
111
115
|
children: [
|
|
112
116
|
"(",
|
|
@@ -115,19 +119,19 @@ function p({ title: e, icon: t, rows: n, emptyText: r }) {
|
|
|
115
119
|
]
|
|
116
120
|
})
|
|
117
121
|
]
|
|
118
|
-
}), n.length === 0 ? /* @__PURE__ */
|
|
122
|
+
}), n.length === 0 ? /* @__PURE__ */ u("p", {
|
|
119
123
|
className: "text-sm text-muted-foreground",
|
|
120
124
|
role: "status",
|
|
121
125
|
"aria-live": "polite",
|
|
122
126
|
children: r
|
|
123
|
-
}) : /* @__PURE__ */
|
|
127
|
+
}) : /* @__PURE__ */ u("ul", {
|
|
124
128
|
className: "divide-y divide-border rounded-md border border-border",
|
|
125
|
-
children: n.map((e) => /* @__PURE__ */
|
|
129
|
+
children: n.map((e) => /* @__PURE__ */ d("li", {
|
|
126
130
|
className: "flex items-center justify-between gap-3 p-3",
|
|
127
|
-
children: [/* @__PURE__ */
|
|
131
|
+
children: [/* @__PURE__ */ u("span", {
|
|
128
132
|
className: "text-sm text-foreground line-clamp-1",
|
|
129
133
|
children: e.tour.name
|
|
130
|
-
}), e.lastViewedAt ? /* @__PURE__ */
|
|
134
|
+
}), e.lastViewedAt ? /* @__PURE__ */ u("time", {
|
|
131
135
|
className: "text-xs text-muted-foreground",
|
|
132
136
|
dateTime: e.lastViewedAt,
|
|
133
137
|
children: new Date(e.lastViewedAt).toLocaleDateString()
|
|
@@ -137,6 +141,6 @@ function p({ title: e, icon: t, rows: n, emptyText: r }) {
|
|
|
137
141
|
});
|
|
138
142
|
}
|
|
139
143
|
//#endregion
|
|
140
|
-
export {
|
|
144
|
+
export { p as MyToursProgressPage };
|
|
141
145
|
|
|
142
146
|
//# sourceMappingURL=MyToursProgressPage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MyToursProgressPage.js","names":[],"sources":["../../../src/tours/pages/MyToursProgressPage.tsx"],"sourcesContent":["import { useMemo, useEffect } 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
|
|
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-foreground\">\n {tr('myToursProgress.title')}\n </h1>\n <p className=\"text-sm sm:text-base text-muted-foreground\">\n {tr('myToursProgress.subtitle')}\n </p>\n </div>\n\n {loading && (data?.userTourProgresses?.length ?? 0) === 0 ? (\n <output className=\"text-sm text-muted-foreground\">{tr('myToursProgress.loading')}</output>\n ) : (\n <div className=\"space-y-6\">\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 <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-muted-foreground\" />}\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-muted-foreground\" />}\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-foreground\">\n {icon}\n {title}\n <span className=\"text-xs text-muted-foreground font-normal\">({rows.length})</span>\n </h2>\n {rows.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\" role=\"status\" aria-live=\"polite\">\n {emptyText}\n </p>\n ) : (\n <ul className=\"divide-y divide-border rounded-md border border-border\">\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-foreground line-clamp-1\">{row.tour.name}</span>\n {row.lastViewedAt ? (\n <time className=\"text-xs text-muted-foreground\" 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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"}
|
|
@@ -54,6 +54,7 @@ function y() {
|
|
|
54
54
|
/* @__PURE__ */ m("div", {
|
|
55
55
|
className: "flex items-center gap-3 sm:gap-4",
|
|
56
56
|
children: [/* @__PURE__ */ p("button", {
|
|
57
|
+
type: "button",
|
|
57
58
|
onClick: L,
|
|
58
59
|
className: "p-2 min-h-[44px] min-w-[44px] hover:bg-accent rounded-md",
|
|
59
60
|
"aria-label": b("tourScheduler.goBack", "Go back"),
|
|
@@ -110,9 +111,11 @@ function y() {
|
|
|
110
111
|
}), /* @__PURE__ */ m("div", {
|
|
111
112
|
className: "space-y-4",
|
|
112
113
|
children: [/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
114
|
+
htmlFor: "scheduler-start-date",
|
|
113
115
|
className: "block text-sm font-medium mb-2",
|
|
114
116
|
children: b("tourScheduler.labelStartDate", "Start Date *")
|
|
115
117
|
}), /* @__PURE__ */ p("input", {
|
|
118
|
+
id: "scheduler-start-date",
|
|
116
119
|
type: "datetime-local",
|
|
117
120
|
value: k.startDate,
|
|
118
121
|
onChange: (e) => A({
|
|
@@ -120,18 +123,22 @@ function y() {
|
|
|
120
123
|
startDate: e.target.value
|
|
121
124
|
}),
|
|
122
125
|
className: "w-full px-3 py-2 min-h-[44px] border border-border rounded-md bg-background",
|
|
123
|
-
required: !0
|
|
126
|
+
required: !0,
|
|
127
|
+
"aria-label": b("tourScheduler.labelStartDate", "Start Date *")
|
|
124
128
|
})] }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
129
|
+
htmlFor: "scheduler-end-date",
|
|
125
130
|
className: "block text-sm font-medium mb-2",
|
|
126
131
|
children: b("tourScheduler.labelEndDate", "End Date (Optional)")
|
|
127
132
|
}), /* @__PURE__ */ p("input", {
|
|
133
|
+
id: "scheduler-end-date",
|
|
128
134
|
type: "datetime-local",
|
|
129
135
|
value: k.endDate,
|
|
130
136
|
onChange: (e) => A({
|
|
131
137
|
...k,
|
|
132
138
|
endDate: e.target.value
|
|
133
139
|
}),
|
|
134
|
-
className: "w-full px-3 py-2 min-h-[44px] border border-border rounded-md bg-background"
|
|
140
|
+
className: "w-full px-3 py-2 min-h-[44px] border border-border rounded-md bg-background",
|
|
141
|
+
"aria-label": b("tourScheduler.labelEndDate", "End Date (Optional)")
|
|
135
142
|
})] })]
|
|
136
143
|
})]
|
|
137
144
|
}),
|
|
@@ -143,15 +150,18 @@ function y() {
|
|
|
143
150
|
}), /* @__PURE__ */ m("div", {
|
|
144
151
|
className: "space-y-4",
|
|
145
152
|
children: [/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
153
|
+
htmlFor: "scheduler-recurrence",
|
|
146
154
|
className: "block text-sm font-medium mb-2",
|
|
147
155
|
children: b("tourScheduler.labelRecurrencePattern", "Recurrence Pattern")
|
|
148
156
|
}), /* @__PURE__ */ m("select", {
|
|
157
|
+
id: "scheduler-recurrence",
|
|
149
158
|
value: k.recurrencePattern,
|
|
150
159
|
onChange: (e) => A({
|
|
151
160
|
...k,
|
|
152
161
|
recurrencePattern: e.target.value
|
|
153
162
|
}),
|
|
154
163
|
className: "w-full px-3 py-2 min-h-[44px] border border-border rounded-md bg-background",
|
|
164
|
+
"aria-label": b("tourScheduler.labelRecurrencePattern", "Recurrence Pattern"),
|
|
155
165
|
children: [
|
|
156
166
|
/* @__PURE__ */ p("option", {
|
|
157
167
|
value: "DAILY",
|
|
@@ -171,9 +181,11 @@ function y() {
|
|
|
171
181
|
})
|
|
172
182
|
]
|
|
173
183
|
})] }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
184
|
+
htmlFor: "scheduler-timezone",
|
|
174
185
|
className: "block text-sm font-medium mb-2",
|
|
175
186
|
children: b("tourScheduler.labelTimezone", "Timezone")
|
|
176
187
|
}), /* @__PURE__ */ p("input", {
|
|
188
|
+
id: "scheduler-timezone",
|
|
177
189
|
type: "text",
|
|
178
190
|
value: k.timezone,
|
|
179
191
|
onChange: (e) => A({
|
|
@@ -181,7 +193,8 @@ function y() {
|
|
|
181
193
|
timezone: e.target.value
|
|
182
194
|
}),
|
|
183
195
|
className: "w-full px-3 py-2 min-h-[44px] border border-border rounded-md bg-background",
|
|
184
|
-
readOnly: !0
|
|
196
|
+
readOnly: !0,
|
|
197
|
+
"aria-label": b("tourScheduler.labelTimezone", "Timezone")
|
|
185
198
|
})] })]
|
|
186
199
|
})]
|
|
187
200
|
}),
|
|
@@ -196,7 +209,8 @@ function y() {
|
|
|
196
209
|
...k,
|
|
197
210
|
isActive: e.target.checked
|
|
198
211
|
}),
|
|
199
|
-
className: "
|
|
212
|
+
className: "size-5 rounded",
|
|
213
|
+
"aria-label": b("tourScheduler.statusActiveLabel", "Active")
|
|
200
214
|
}), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("div", {
|
|
201
215
|
className: "font-medium",
|
|
202
216
|
children: b("tourScheduler.statusActiveLabel", "Active")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SchedulerPage.js","names":[],"sources":["../../../src/tours/pages/SchedulerPage.tsx"],"sourcesContent":["import { useCallback, useState } from 'react';\nimport { useParams, useNavigate } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Calendar, Clock, ArrowLeft, Save } from 'lucide-react';\nimport { PermissionGate } from '@burdenoff/fe-libs/shared/components';\nimport { useEventBus } from '@burdenoff/fe-libs/shared/events';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport type { RecurrencePattern } from '../types';\nimport { emitToursApiFailed } from '../telemetry';\nimport { useCreateTourScheduleMutation } from '../../generated/global-operations';\nimport { useGetTourSchedulesQuery } from '../../generated/global-operations';\n\n/**\n * Tour scheduler page\n * Configure tour scheduling and recurrence\n */\nexport function SchedulerPage() {\n const { t } = useI18n();\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n },\n [t]\n );\n const { tourId } = useParams();\n const navigate = useNavigate();\n const toursContext = useToursContext();\n const { basePath = '/' } = toursContext;\n const eventBus = useEventBus();\n const { hasPermission } = useToursPermissionAccess();\n const canCreateSchedule = hasPermission(TOUR_PERMISSIONS.TOUR_SCHEDULE_CREATE);\n const canListSchedules = hasPermission(TOUR_PERMISSIONS.TOUR_SCHEDULE_LIST);\n\n const [scheduleData, setScheduleData] = useState({\n startDate: '',\n endDate: '',\n recurrencePattern: 'DAILY' as RecurrencePattern,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n isActive: true,\n });\n\n const [saving, setSaving] = useState(false);\n\n const [createSchedule] = useCreateTourScheduleMutation();\n const { data: schedulesData } = useGetTourSchedulesQuery({\n variables: { tourId: tourId! },\n skip: !tourId || !canListSchedules,\n });\n const existingSchedules = schedulesData?.tourSchedules ?? [];\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!tourId) return;\n setSaving(true);\n try {\n // Convert recurrence pattern to RFC 5545 recurrence rule\n const recurrenceRule =\n scheduleData.recurrencePattern === 'DAILY'\n ? 'FREQ=DAILY'\n : scheduleData.recurrencePattern === 'WEEKLY'\n ? 'FREQ=WEEKLY'\n : scheduleData.recurrencePattern === 'MONTHLY'\n ? 'FREQ=MONTHLY'\n : undefined;\n\n await createSchedule({\n variables: {\n input: {\n tourId,\n startDate: new Date(scheduleData.startDate).toISOString(),\n endDate: scheduleData.endDate\n ? new Date(scheduleData.endDate).toISOString()\n : undefined,\n recurrenceRule,\n timezone: scheduleData.timezone,\n },\n },\n refetchQueries: ['GetTourSchedules'],\n });\n navigate(`${basePath}/${tourId}/edit`);\n } catch {\n emitToursApiFailed(eventBus, 'schedule.create', toursContext);\n } finally {\n setSaving(false);\n }\n };\n\n const handleBack = () => {\n navigate(`${basePath}/${tourId}/edit`);\n };\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6 max-w-3xl mx-auto\">\n {/* Header */}\n <div className=\"flex items-center gap-3 sm:gap-4\">\n <button\n onClick={handleBack}\n className=\"p-2 min-h-[44px] min-w-[44px] hover:bg-accent rounded-md\"\n aria-label={tr('tourScheduler.goBack', 'Go back')}\n >\n <ArrowLeft size={20} />\n </button>\n <div>\n <h1 className=\"text-xl sm:text-2xl font-bold\">\n {tr('tourScheduler.title', 'Schedule Tour')}\n </h1>\n <p className=\"text-sm text-muted-foreground\">\n {tr('tourScheduler.subtitle', 'Configure when this tour should be activated')}\n </p>\n </div>\n </div>\n\n {/* Existing Schedules */}\n {existingSchedules.length > 0 && (\n <div className=\"border border-border rounded-md p-4 sm:p-6 bg-card\">\n <h2 className=\"text-lg font-semibold mb-4\">\n {tr('tourScheduler.existingSchedules', 'Existing Schedules')}\n </h2>\n <div className=\"space-y-2\">\n {existingSchedules.map((schedule: (typeof existingSchedules)[number]) => (\n <div\n key={schedule.id}\n className=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between p-3 border border-border rounded-md\"\n >\n <div>\n <div className=\"text-sm font-medium\">\n {new Date(schedule.startDate).toLocaleDateString()}\n {schedule.endDate\n ? ` — ${new Date(schedule.endDate).toLocaleDateString()}`\n : ` — ${tr('tourScheduler.noEndDate', 'No end date')}`}\n </div>\n <div className=\"text-xs text-muted-foreground\">\n {schedule.recurrenceRule || tr('tourScheduler.oneTime', 'One-time')} ·{' '}\n {schedule.timezone}\n {schedule.isActive\n ? ` · ${tr('tourScheduler.active', 'Active')}`\n : ` · ${tr('tourScheduler.inactive', 'Inactive')}`}\n </div>\n </div>\n <div className=\"text-xs text-muted-foreground\">\n {tr('tourScheduler.runs', 'Runs')}: {schedule.executionCount}\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Form */}\n <form onSubmit={handleSubmit} className=\"space-y-6\">\n {/* Date Range */}\n <div className=\"border border-border rounded-md p-4 sm:p-6 bg-card\">\n <h2 className=\"text-lg font-semibold mb-4 flex items-center gap-2\">\n <Calendar size={20} />\n {tr('tourScheduler.sectionDateRange', 'Date Range')}\n </h2>\n\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium mb-2\">\n {tr('tourScheduler.labelStartDate', 'Start Date *')}\n </label>\n <input\n type=\"datetime-local\"\n value={scheduleData.startDate}\n onChange={(e) => setScheduleData({ ...scheduleData, startDate: e.target.value })}\n className=\"w-full px-3 py-2 min-h-[44px] border border-border rounded-md bg-background\"\n required\n />\n </div>\n\n <div>\n <label className=\"block text-sm font-medium mb-2\">\n {tr('tourScheduler.labelEndDate', 'End Date (Optional)')}\n </label>\n <input\n type=\"datetime-local\"\n value={scheduleData.endDate}\n onChange={(e) => setScheduleData({ ...scheduleData, endDate: e.target.value })}\n className=\"w-full px-3 py-2 min-h-[44px] border border-border rounded-md bg-background\"\n />\n </div>\n </div>\n </div>\n\n {/* Recurrence */}\n <div className=\"border border-border rounded-md p-4 sm:p-6 bg-card\">\n <h2 className=\"text-lg font-semibold mb-4 flex items-center gap-2\">\n <Clock size={20} />\n {tr('tourScheduler.sectionRecurrence', 'Recurrence')}\n </h2>\n\n <div className=\"space-y-4\">\n <div>\n <label className=\"block text-sm font-medium mb-2\">\n {tr('tourScheduler.labelRecurrencePattern', 'Recurrence Pattern')}\n </label>\n <select\n value={scheduleData.recurrencePattern}\n onChange={(e) =>\n setScheduleData({\n ...scheduleData,\n recurrencePattern: e.target.value as RecurrencePattern,\n })\n }\n className=\"w-full px-3 py-2 min-h-[44px] border border-border rounded-md bg-background\"\n >\n <option value=\"DAILY\">{tr('tourScheduler.recurrenceDaily', 'Daily')}</option>\n <option value=\"WEEKLY\">{tr('tourScheduler.recurrenceWeekly', 'Weekly')}</option>\n <option value=\"MONTHLY\">{tr('tourScheduler.recurrenceMonthly', 'Monthly')}</option>\n <option value=\"CUSTOM\">{tr('tourScheduler.recurrenceCustom', 'Custom')}</option>\n </select>\n </div>\n\n <div>\n <label className=\"block text-sm font-medium mb-2\">\n {tr('tourScheduler.labelTimezone', 'Timezone')}\n </label>\n <input\n type=\"text\"\n value={scheduleData.timezone}\n onChange={(e) => setScheduleData({ ...scheduleData, timezone: e.target.value })}\n className=\"w-full px-3 py-2 min-h-[44px] border border-border rounded-md bg-background\"\n readOnly\n />\n </div>\n </div>\n </div>\n\n {/* Status */}\n <div className=\"border border-border rounded-md p-4 sm:p-6 bg-card\">\n <label className=\"flex items-center gap-3 cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={scheduleData.isActive}\n onChange={(e) => setScheduleData({ ...scheduleData, isActive: e.target.checked })}\n className=\"w-5 h-5 rounded\"\n />\n <div>\n <div className=\"font-medium\">{tr('tourScheduler.statusActiveLabel', 'Active')}</div>\n <div className=\"text-sm text-muted-foreground\">\n {tr(\n 'tourScheduler.statusActiveDescription',\n 'Enable this schedule immediately after creation'\n )}\n </div>\n </div>\n </label>\n </div>\n\n {/* Actions */}\n <div className=\"flex flex-col sm:flex-row gap-3\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"flex-1 px-4 py-2 min-h-[44px] border border-border rounded-md hover:bg-accent\"\n >\n {tr('tourScheduler.cancel', 'Cancel')}\n </button>\n <PermissionGate permission={TOUR_PERMISSIONS.TOUR_SCHEDULE_CREATE}>\n <button\n type=\"submit\"\n disabled={saving || !canCreateSchedule}\n className=\"flex-1 px-4 py-2 min-h-[44px] bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50 flex items-center justify-center gap-2\"\n >\n <Save size={20} />\n {saving\n ? tr('tourScheduler.creating', 'Creating...')\n : tr('tourScheduler.createSchedule', 'Create Schedule')}\n </button>\n </PermissionGate>\n </div>\n </form>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SchedulerPage.js","names":[],"sources":["../../../src/tours/pages/SchedulerPage.tsx"],"sourcesContent":["import { useCallback, useState } from 'react';\nimport { useParams, useNavigate } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Calendar, Clock, ArrowLeft, Save } from 'lucide-react';\nimport { PermissionGate } from '@burdenoff/fe-libs/shared/components';\nimport { useEventBus } from '@burdenoff/fe-libs/shared/events';\nimport { useToursPermissionAccess } from '../hooks/useToursPermissionAccess';\nimport { useToursContext } from '../providers/ToursProvider';\nimport { TOUR_PERMISSIONS } from '../../constants/permissions';\nimport type { RecurrencePattern } from '../types';\nimport { emitToursApiFailed } from '../telemetry';\nimport { useCreateTourScheduleMutation } from '../../generated/global-operations';\nimport { useGetTourSchedulesQuery } from '../../generated/global-operations';\n\n/**\n * Tour scheduler page\n * Configure tour scheduling and recurrence\n */\nexport function SchedulerPage() {\n const { t } = useI18n();\n const tr = useCallback(\n (key: string, fallback: string): string => {\n const value = t(key);\n return value === key ? fallback : value;\n },\n [t]\n );\n const { tourId } = useParams();\n const navigate = useNavigate();\n const toursContext = useToursContext();\n const { basePath = '/' } = toursContext;\n const eventBus = useEventBus();\n const { hasPermission } = useToursPermissionAccess();\n const canCreateSchedule = hasPermission(TOUR_PERMISSIONS.TOUR_SCHEDULE_CREATE);\n const canListSchedules = hasPermission(TOUR_PERMISSIONS.TOUR_SCHEDULE_LIST);\n\n const [scheduleData, setScheduleData] = useState({\n startDate: '',\n endDate: '',\n recurrencePattern: 'DAILY' as RecurrencePattern,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n isActive: true,\n });\n\n const [saving, setSaving] = useState(false);\n\n const [createSchedule] = useCreateTourScheduleMutation();\n const { data: schedulesData } = useGetTourSchedulesQuery({\n variables: { tourId: tourId! },\n skip: !tourId || !canListSchedules,\n });\n const existingSchedules = schedulesData?.tourSchedules ?? [];\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!tourId) return;\n setSaving(true);\n try {\n // Convert recurrence pattern to RFC 5545 recurrence rule\n const recurrenceRule =\n scheduleData.recurrencePattern === 'DAILY'\n ? 'FREQ=DAILY'\n : scheduleData.recurrencePattern === 'WEEKLY'\n ? 'FREQ=WEEKLY'\n : scheduleData.recurrencePattern === 'MONTHLY'\n ? 'FREQ=MONTHLY'\n : undefined;\n\n await createSchedule({\n variables: {\n input: {\n tourId,\n startDate: new Date(scheduleData.startDate).toISOString(),\n endDate: scheduleData.endDate\n ? new Date(scheduleData.endDate).toISOString()\n : undefined,\n recurrenceRule,\n timezone: scheduleData.timezone,\n },\n },\n refetchQueries: ['GetTourSchedules'],\n });\n navigate(`${basePath}/${tourId}/edit`);\n } catch {\n emitToursApiFailed(eventBus, 'schedule.create', toursContext);\n } finally {\n setSaving(false);\n }\n };\n\n const handleBack = () => {\n navigate(`${basePath}/${tourId}/edit`);\n };\n\n return (\n <div className=\"space-y-4 sm:space-y-6 p-3 sm:p-6 max-w-3xl mx-auto\">\n {/* Header */}\n <div className=\"flex items-center gap-3 sm:gap-4\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"p-2 min-h-[44px] min-w-[44px] hover:bg-accent rounded-md\"\n aria-label={tr('tourScheduler.goBack', 'Go back')}\n >\n <ArrowLeft size={20} />\n </button>\n <div>\n <h1 className=\"text-xl sm:text-2xl font-bold\">\n {tr('tourScheduler.title', 'Schedule Tour')}\n </h1>\n <p className=\"text-sm text-muted-foreground\">\n {tr('tourScheduler.subtitle', 'Configure when this tour should be activated')}\n </p>\n </div>\n </div>\n\n {/* Existing Schedules */}\n {existingSchedules.length > 0 && (\n <div className=\"border border-border rounded-md p-4 sm:p-6 bg-card\">\n <h2 className=\"text-lg font-semibold mb-4\">\n {tr('tourScheduler.existingSchedules', 'Existing Schedules')}\n </h2>\n <div className=\"space-y-2\">\n {existingSchedules.map((schedule: (typeof existingSchedules)[number]) => (\n <div\n key={schedule.id}\n className=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between p-3 border border-border rounded-md\"\n >\n <div>\n <div className=\"text-sm font-medium\">\n {new Date(schedule.startDate).toLocaleDateString()}\n {schedule.endDate\n ? ` — ${new Date(schedule.endDate).toLocaleDateString()}`\n : ` — ${tr('tourScheduler.noEndDate', 'No end date')}`}\n </div>\n <div className=\"text-xs text-muted-foreground\">\n {schedule.recurrenceRule || tr('tourScheduler.oneTime', 'One-time')} ·{' '}\n {schedule.timezone}\n {schedule.isActive\n ? ` · ${tr('tourScheduler.active', 'Active')}`\n : ` · ${tr('tourScheduler.inactive', 'Inactive')}`}\n </div>\n </div>\n <div className=\"text-xs text-muted-foreground\">\n {tr('tourScheduler.runs', 'Runs')}: {schedule.executionCount}\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Form */}\n <form onSubmit={handleSubmit} className=\"space-y-6\">\n {/* Date Range */}\n <div className=\"border border-border rounded-md p-4 sm:p-6 bg-card\">\n <h2 className=\"text-lg font-semibold mb-4 flex items-center gap-2\">\n <Calendar size={20} />\n {tr('tourScheduler.sectionDateRange', 'Date Range')}\n </h2>\n\n <div className=\"space-y-4\">\n <div>\n <label htmlFor=\"scheduler-start-date\" className=\"block text-sm font-medium mb-2\">\n {tr('tourScheduler.labelStartDate', 'Start Date *')}\n </label>\n <input\n id=\"scheduler-start-date\"\n type=\"datetime-local\"\n value={scheduleData.startDate}\n onChange={(e) => setScheduleData({ ...scheduleData, startDate: e.target.value })}\n className=\"w-full px-3 py-2 min-h-[44px] border border-border rounded-md bg-background\"\n required\n aria-label={tr('tourScheduler.labelStartDate', 'Start Date *')}\n />\n </div>\n\n <div>\n <label htmlFor=\"scheduler-end-date\" className=\"block text-sm font-medium mb-2\">\n {tr('tourScheduler.labelEndDate', 'End Date (Optional)')}\n </label>\n <input\n id=\"scheduler-end-date\"\n type=\"datetime-local\"\n value={scheduleData.endDate}\n onChange={(e) => setScheduleData({ ...scheduleData, endDate: e.target.value })}\n className=\"w-full px-3 py-2 min-h-[44px] border border-border rounded-md bg-background\"\n aria-label={tr('tourScheduler.labelEndDate', 'End Date (Optional)')}\n />\n </div>\n </div>\n </div>\n\n {/* Recurrence */}\n <div className=\"border border-border rounded-md p-4 sm:p-6 bg-card\">\n <h2 className=\"text-lg font-semibold mb-4 flex items-center gap-2\">\n <Clock size={20} />\n {tr('tourScheduler.sectionRecurrence', 'Recurrence')}\n </h2>\n\n <div className=\"space-y-4\">\n <div>\n <label htmlFor=\"scheduler-recurrence\" className=\"block text-sm font-medium mb-2\">\n {tr('tourScheduler.labelRecurrencePattern', 'Recurrence Pattern')}\n </label>\n <select\n id=\"scheduler-recurrence\"\n value={scheduleData.recurrencePattern}\n onChange={(e) =>\n setScheduleData({\n ...scheduleData,\n recurrencePattern: e.target.value as RecurrencePattern,\n })\n }\n className=\"w-full px-3 py-2 min-h-[44px] border border-border rounded-md bg-background\"\n aria-label={tr('tourScheduler.labelRecurrencePattern', 'Recurrence Pattern')}\n >\n <option value=\"DAILY\">{tr('tourScheduler.recurrenceDaily', 'Daily')}</option>\n <option value=\"WEEKLY\">{tr('tourScheduler.recurrenceWeekly', 'Weekly')}</option>\n <option value=\"MONTHLY\">{tr('tourScheduler.recurrenceMonthly', 'Monthly')}</option>\n <option value=\"CUSTOM\">{tr('tourScheduler.recurrenceCustom', 'Custom')}</option>\n </select>\n </div>\n\n <div>\n <label htmlFor=\"scheduler-timezone\" className=\"block text-sm font-medium mb-2\">\n {tr('tourScheduler.labelTimezone', 'Timezone')}\n </label>\n <input\n id=\"scheduler-timezone\"\n type=\"text\"\n value={scheduleData.timezone}\n onChange={(e) => setScheduleData({ ...scheduleData, timezone: e.target.value })}\n className=\"w-full px-3 py-2 min-h-[44px] border border-border rounded-md bg-background\"\n readOnly\n aria-label={tr('tourScheduler.labelTimezone', 'Timezone')}\n />\n </div>\n </div>\n </div>\n\n {/* Status */}\n <div className=\"border border-border rounded-md p-4 sm:p-6 bg-card\">\n <label className=\"flex items-center gap-3 cursor-pointer\">\n <input\n type=\"checkbox\"\n checked={scheduleData.isActive}\n onChange={(e) => setScheduleData({ ...scheduleData, isActive: e.target.checked })}\n className=\"size-5 rounded\"\n aria-label={tr('tourScheduler.statusActiveLabel', 'Active')}\n />\n <div>\n <div className=\"font-medium\">{tr('tourScheduler.statusActiveLabel', 'Active')}</div>\n <div className=\"text-sm text-muted-foreground\">\n {tr(\n 'tourScheduler.statusActiveDescription',\n 'Enable this schedule immediately after creation'\n )}\n </div>\n </div>\n </label>\n </div>\n\n {/* Actions */}\n <div className=\"flex flex-col sm:flex-row gap-3\">\n <button\n type=\"button\"\n onClick={handleBack}\n className=\"flex-1 px-4 py-2 min-h-[44px] border border-border rounded-md hover:bg-accent\"\n >\n {tr('tourScheduler.cancel', 'Cancel')}\n </button>\n <PermissionGate permission={TOUR_PERMISSIONS.TOUR_SCHEDULE_CREATE}>\n <button\n type=\"submit\"\n disabled={saving || !canCreateSchedule}\n className=\"flex-1 px-4 py-2 min-h-[44px] bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50 flex items-center justify-center gap-2\"\n >\n <Save size={20} />\n {saving\n ? tr('tourScheduler.creating', 'Creating...')\n : tr('tourScheduler.createSchedule', 'Create Schedule')}\n </button>\n </PermissionGate>\n </div>\n </form>\n </div>\n );\n}\n"],"mappings":"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"}
|