@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
|
@@ -8,45 +8,46 @@ import { PermissionGate as c } from "@burdenoff/fe-libs/shared/components";
|
|
|
8
8
|
import { ArrowLeft as l, Calendar as u, Clock as d, Save as f } from "lucide-react";
|
|
9
9
|
import { jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
10
10
|
import { useNavigate as h, useParams as g } from "react-router-dom";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
11
|
+
import { Button as _, GlassCard as v } from "@burdenoff/fe-libs/ui";
|
|
12
|
+
import { useI18n as y } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
13
|
+
import { useEventBus as b } from "@burdenoff/fe-libs/shared/events";
|
|
13
14
|
//#region src/tours/pages/SchedulerPage.tsx
|
|
14
|
-
function
|
|
15
|
-
let { t:
|
|
16
|
-
let n =
|
|
15
|
+
function x() {
|
|
16
|
+
let { t: x } = y(), S = o((e, t) => {
|
|
17
|
+
let n = x(e);
|
|
17
18
|
return n === e ? t : n;
|
|
18
|
-
}, [
|
|
19
|
+
}, [x]), { tourId: C } = g(), w = h(), T = e(), { basePath: E = "/" } = T, D = b(), { hasPermission: O } = r(), k = O(i.TOUR_SCHEDULE_CREATE), A = O(i.TOUR_SCHEDULE_LIST), [j, M] = s({
|
|
19
20
|
startDate: "",
|
|
20
21
|
endDate: "",
|
|
21
22
|
recurrencePattern: "DAILY",
|
|
22
23
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
23
24
|
isActive: !0
|
|
24
|
-
}), [
|
|
25
|
-
variables: { tourId:
|
|
26
|
-
skip: !
|
|
27
|
-
}),
|
|
28
|
-
if (e.preventDefault(),
|
|
29
|
-
|
|
25
|
+
}), [N, P] = s(!1), [F] = t(), { data: I } = n({
|
|
26
|
+
variables: { tourId: C },
|
|
27
|
+
skip: !C || !A
|
|
28
|
+
}), L = I?.tourSchedules ?? [], R = async (e) => {
|
|
29
|
+
if (e.preventDefault(), C) {
|
|
30
|
+
P(!0);
|
|
30
31
|
try {
|
|
31
|
-
let e =
|
|
32
|
-
await
|
|
32
|
+
let e = j.recurrencePattern === "DAILY" ? "FREQ=DAILY" : j.recurrencePattern === "WEEKLY" ? "FREQ=WEEKLY" : j.recurrencePattern === "MONTHLY" ? "FREQ=MONTHLY" : void 0;
|
|
33
|
+
await F({
|
|
33
34
|
variables: { input: {
|
|
34
|
-
tourId:
|
|
35
|
-
startDate: new Date(
|
|
36
|
-
endDate:
|
|
35
|
+
tourId: C,
|
|
36
|
+
startDate: new Date(j.startDate).toISOString(),
|
|
37
|
+
endDate: j.endDate ? new Date(j.endDate).toISOString() : void 0,
|
|
37
38
|
recurrenceRule: e,
|
|
38
|
-
timezone:
|
|
39
|
+
timezone: j.timezone
|
|
39
40
|
} },
|
|
40
41
|
refetchQueries: ["GetTourSchedules"]
|
|
41
|
-
}),
|
|
42
|
+
}), w(`${E}/${C}/edit`);
|
|
42
43
|
} catch {
|
|
43
|
-
a(
|
|
44
|
+
a(D, "schedule.create", T);
|
|
44
45
|
} finally {
|
|
45
|
-
|
|
46
|
+
P(!1);
|
|
46
47
|
}
|
|
47
48
|
}
|
|
48
|
-
},
|
|
49
|
-
|
|
49
|
+
}, z = () => {
|
|
50
|
+
w(`${E}/${C}/edit`);
|
|
50
51
|
};
|
|
51
52
|
return /* @__PURE__ */ m("div", {
|
|
52
53
|
className: "space-y-4 sm:space-y-6 p-3 sm:p-6 max-w-3xl mx-auto",
|
|
@@ -55,43 +56,44 @@ function y() {
|
|
|
55
56
|
className: "flex items-center gap-3 sm:gap-4",
|
|
56
57
|
children: [/* @__PURE__ */ p("button", {
|
|
57
58
|
type: "button",
|
|
58
|
-
onClick:
|
|
59
|
+
onClick: z,
|
|
59
60
|
className: "p-2 min-h-[44px] min-w-[44px] hover:bg-accent rounded-md",
|
|
60
|
-
"aria-label":
|
|
61
|
+
"aria-label": S("tourScheduler.goBack", "Go back"),
|
|
61
62
|
children: /* @__PURE__ */ p(l, { size: 20 })
|
|
62
63
|
}), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("h1", {
|
|
63
64
|
className: "text-xl sm:text-2xl font-bold",
|
|
64
|
-
children:
|
|
65
|
+
children: S("tourScheduler.title", "Schedule Tour")
|
|
65
66
|
}), /* @__PURE__ */ p("p", {
|
|
66
67
|
className: "text-sm text-text-secondary",
|
|
67
|
-
children:
|
|
68
|
+
children: S("tourScheduler.subtitle", "Configure when this tour should be activated")
|
|
68
69
|
})] })]
|
|
69
70
|
}),
|
|
70
|
-
|
|
71
|
-
|
|
71
|
+
L.length > 0 && /* @__PURE__ */ m(v, {
|
|
72
|
+
treatment: "plain",
|
|
73
|
+
className: "p-4 sm:p-6 border-border-seam",
|
|
72
74
|
children: [/* @__PURE__ */ p("h2", {
|
|
73
75
|
className: "text-lg font-semibold mb-4",
|
|
74
|
-
children:
|
|
76
|
+
children: S("tourScheduler.existingSchedules", "Existing Schedules")
|
|
75
77
|
}), /* @__PURE__ */ p("div", {
|
|
76
78
|
className: "space-y-2",
|
|
77
|
-
children:
|
|
78
|
-
className: "flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between p-3 border border-border-
|
|
79
|
+
children: L.map((e) => /* @__PURE__ */ m("div", {
|
|
80
|
+
className: "flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between p-3 border border-border-seam rounded-md",
|
|
79
81
|
children: [/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ m("div", {
|
|
80
82
|
className: "text-sm font-medium",
|
|
81
|
-
children: [new Date(e.startDate).toLocaleDateString(), e.endDate ? ` — ${new Date(e.endDate).toLocaleDateString()}` : ` — ${
|
|
83
|
+
children: [new Date(e.startDate).toLocaleDateString(), e.endDate ? ` — ${new Date(e.endDate).toLocaleDateString()}` : ` — ${S("tourScheduler.noEndDate", "No end date")}`]
|
|
82
84
|
}), /* @__PURE__ */ m("div", {
|
|
83
85
|
className: "text-xs text-text-secondary",
|
|
84
86
|
children: [
|
|
85
|
-
e.recurrenceRule ||
|
|
87
|
+
e.recurrenceRule || S("tourScheduler.oneTime", "One-time"),
|
|
86
88
|
" ·",
|
|
87
89
|
" ",
|
|
88
90
|
e.timezone,
|
|
89
|
-
e.isActive ? ` · ${
|
|
91
|
+
e.isActive ? ` · ${S("tourScheduler.active", "Active")}` : ` · ${S("tourScheduler.inactive", "Inactive")}`
|
|
90
92
|
]
|
|
91
93
|
})] }), /* @__PURE__ */ m("div", {
|
|
92
|
-
className: "text-xs text-text-secondary",
|
|
94
|
+
className: "text-xs text-text-secondary tabular-nums",
|
|
93
95
|
children: [
|
|
94
|
-
|
|
96
|
+
S("tourScheduler.runs", "Runs"),
|
|
95
97
|
": ",
|
|
96
98
|
e.executionCount
|
|
97
99
|
]
|
|
@@ -100,140 +102,144 @@ function y() {
|
|
|
100
102
|
})]
|
|
101
103
|
}),
|
|
102
104
|
/* @__PURE__ */ m("form", {
|
|
103
|
-
onSubmit:
|
|
105
|
+
onSubmit: R,
|
|
104
106
|
className: "space-y-6",
|
|
105
107
|
children: [
|
|
106
|
-
/* @__PURE__ */ m(
|
|
107
|
-
|
|
108
|
+
/* @__PURE__ */ m(v, {
|
|
109
|
+
treatment: "plain",
|
|
110
|
+
className: "p-4 sm:p-6 border-border-seam",
|
|
108
111
|
children: [/* @__PURE__ */ m("h2", {
|
|
109
112
|
className: "text-lg font-semibold mb-4 flex items-center gap-2",
|
|
110
|
-
children: [/* @__PURE__ */ p(u, { size: 20 }),
|
|
113
|
+
children: [/* @__PURE__ */ p(u, { size: 20 }), S("tourScheduler.sectionDateRange", "Date Range")]
|
|
111
114
|
}), /* @__PURE__ */ m("div", {
|
|
112
115
|
className: "space-y-4",
|
|
113
116
|
children: [/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
114
117
|
htmlFor: "scheduler-start-date",
|
|
115
118
|
className: "block text-sm font-medium mb-2",
|
|
116
|
-
children:
|
|
119
|
+
children: S("tourScheduler.labelStartDate", "Start Date *")
|
|
117
120
|
}), /* @__PURE__ */ p("input", {
|
|
118
121
|
id: "scheduler-start-date",
|
|
119
122
|
type: "datetime-local",
|
|
120
|
-
value:
|
|
121
|
-
onChange: (e) =>
|
|
122
|
-
...
|
|
123
|
+
value: j.startDate,
|
|
124
|
+
onChange: (e) => M({
|
|
125
|
+
...j,
|
|
123
126
|
startDate: e.target.value
|
|
124
127
|
}),
|
|
125
128
|
className: "w-full px-3 py-2 min-h-[44px] border border-border-subtle rounded-md bg-bg-surface",
|
|
126
129
|
required: !0,
|
|
127
|
-
"aria-label":
|
|
130
|
+
"aria-label": S("tourScheduler.labelStartDate", "Start Date *")
|
|
128
131
|
})] }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
129
132
|
htmlFor: "scheduler-end-date",
|
|
130
133
|
className: "block text-sm font-medium mb-2",
|
|
131
|
-
children:
|
|
134
|
+
children: S("tourScheduler.labelEndDate", "End Date (Optional)")
|
|
132
135
|
}), /* @__PURE__ */ p("input", {
|
|
133
136
|
id: "scheduler-end-date",
|
|
134
137
|
type: "datetime-local",
|
|
135
|
-
value:
|
|
136
|
-
onChange: (e) =>
|
|
137
|
-
...
|
|
138
|
+
value: j.endDate,
|
|
139
|
+
onChange: (e) => M({
|
|
140
|
+
...j,
|
|
138
141
|
endDate: e.target.value
|
|
139
142
|
}),
|
|
140
143
|
className: "w-full px-3 py-2 min-h-[44px] border border-border-subtle rounded-md bg-bg-surface",
|
|
141
|
-
"aria-label":
|
|
144
|
+
"aria-label": S("tourScheduler.labelEndDate", "End Date (Optional)")
|
|
142
145
|
})] })]
|
|
143
146
|
})]
|
|
144
147
|
}),
|
|
145
|
-
/* @__PURE__ */ m(
|
|
146
|
-
|
|
148
|
+
/* @__PURE__ */ m(v, {
|
|
149
|
+
treatment: "plain",
|
|
150
|
+
className: "p-4 sm:p-6 border-border-seam",
|
|
147
151
|
children: [/* @__PURE__ */ m("h2", {
|
|
148
152
|
className: "text-lg font-semibold mb-4 flex items-center gap-2",
|
|
149
|
-
children: [/* @__PURE__ */ p(d, { size: 20 }),
|
|
153
|
+
children: [/* @__PURE__ */ p(d, { size: 20 }), S("tourScheduler.sectionRecurrence", "Recurrence")]
|
|
150
154
|
}), /* @__PURE__ */ m("div", {
|
|
151
155
|
className: "space-y-4",
|
|
152
156
|
children: [/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
153
157
|
htmlFor: "scheduler-recurrence",
|
|
154
158
|
className: "block text-sm font-medium mb-2",
|
|
155
|
-
children:
|
|
159
|
+
children: S("tourScheduler.labelRecurrencePattern", "Recurrence Pattern")
|
|
156
160
|
}), /* @__PURE__ */ m("select", {
|
|
157
161
|
id: "scheduler-recurrence",
|
|
158
|
-
value:
|
|
159
|
-
onChange: (e) =>
|
|
160
|
-
...
|
|
162
|
+
value: j.recurrencePattern,
|
|
163
|
+
onChange: (e) => M({
|
|
164
|
+
...j,
|
|
161
165
|
recurrencePattern: e.target.value
|
|
162
166
|
}),
|
|
163
167
|
className: "w-full px-3 py-2 min-h-[44px] border border-border-subtle rounded-md bg-bg-surface",
|
|
164
|
-
"aria-label":
|
|
168
|
+
"aria-label": S("tourScheduler.labelRecurrencePattern", "Recurrence Pattern"),
|
|
165
169
|
children: [
|
|
166
170
|
/* @__PURE__ */ p("option", {
|
|
167
171
|
value: "DAILY",
|
|
168
|
-
children:
|
|
172
|
+
children: S("tourScheduler.recurrenceDaily", "Daily")
|
|
169
173
|
}),
|
|
170
174
|
/* @__PURE__ */ p("option", {
|
|
171
175
|
value: "WEEKLY",
|
|
172
|
-
children:
|
|
176
|
+
children: S("tourScheduler.recurrenceWeekly", "Weekly")
|
|
173
177
|
}),
|
|
174
178
|
/* @__PURE__ */ p("option", {
|
|
175
179
|
value: "MONTHLY",
|
|
176
|
-
children:
|
|
180
|
+
children: S("tourScheduler.recurrenceMonthly", "Monthly")
|
|
177
181
|
}),
|
|
178
182
|
/* @__PURE__ */ p("option", {
|
|
179
183
|
value: "CUSTOM",
|
|
180
|
-
children:
|
|
184
|
+
children: S("tourScheduler.recurrenceCustom", "Custom")
|
|
181
185
|
})
|
|
182
186
|
]
|
|
183
187
|
})] }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("label", {
|
|
184
188
|
htmlFor: "scheduler-timezone",
|
|
185
189
|
className: "block text-sm font-medium mb-2",
|
|
186
|
-
children:
|
|
190
|
+
children: S("tourScheduler.labelTimezone", "Timezone")
|
|
187
191
|
}), /* @__PURE__ */ p("input", {
|
|
188
192
|
id: "scheduler-timezone",
|
|
189
193
|
type: "text",
|
|
190
|
-
value:
|
|
191
|
-
onChange: (e) =>
|
|
192
|
-
...
|
|
194
|
+
value: j.timezone,
|
|
195
|
+
onChange: (e) => M({
|
|
196
|
+
...j,
|
|
193
197
|
timezone: e.target.value
|
|
194
198
|
}),
|
|
195
199
|
className: "w-full px-3 py-2 min-h-[44px] border border-border-subtle rounded-md bg-bg-surface",
|
|
196
200
|
readOnly: !0,
|
|
197
|
-
"aria-label":
|
|
201
|
+
"aria-label": S("tourScheduler.labelTimezone", "Timezone")
|
|
198
202
|
})] })]
|
|
199
203
|
})]
|
|
200
204
|
}),
|
|
201
|
-
/* @__PURE__ */ p(
|
|
202
|
-
|
|
205
|
+
/* @__PURE__ */ p(v, {
|
|
206
|
+
treatment: "plain",
|
|
207
|
+
className: "p-4 sm:p-6 border-border-seam",
|
|
203
208
|
children: /* @__PURE__ */ m("label", {
|
|
204
209
|
className: "flex items-center gap-3 cursor-pointer",
|
|
205
210
|
children: [/* @__PURE__ */ p("input", {
|
|
206
211
|
type: "checkbox",
|
|
207
|
-
checked:
|
|
208
|
-
onChange: (e) =>
|
|
209
|
-
...
|
|
212
|
+
checked: j.isActive,
|
|
213
|
+
onChange: (e) => M({
|
|
214
|
+
...j,
|
|
210
215
|
isActive: e.target.checked
|
|
211
216
|
}),
|
|
212
217
|
className: "size-5 rounded",
|
|
213
|
-
"aria-label":
|
|
218
|
+
"aria-label": S("tourScheduler.statusActiveLabel", "Active")
|
|
214
219
|
}), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("div", {
|
|
215
220
|
className: "font-medium",
|
|
216
|
-
children:
|
|
221
|
+
children: S("tourScheduler.statusActiveLabel", "Active")
|
|
217
222
|
}), /* @__PURE__ */ p("div", {
|
|
218
223
|
className: "text-sm text-text-secondary",
|
|
219
|
-
children:
|
|
224
|
+
children: S("tourScheduler.statusActiveDescription", "Enable this schedule immediately after creation")
|
|
220
225
|
})] })]
|
|
221
226
|
})
|
|
222
227
|
}),
|
|
223
228
|
/* @__PURE__ */ m("div", {
|
|
224
229
|
className: "flex flex-col sm:flex-row gap-3",
|
|
225
|
-
children: [/* @__PURE__ */ p(
|
|
230
|
+
children: [/* @__PURE__ */ p(_, {
|
|
226
231
|
type: "button",
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
232
|
+
variant: "outline",
|
|
233
|
+
onClick: z,
|
|
234
|
+
className: "flex-1 min-h-[44px]",
|
|
235
|
+
children: S("tourScheduler.cancel", "Cancel")
|
|
230
236
|
}), /* @__PURE__ */ p(c, {
|
|
231
237
|
permission: i.TOUR_SCHEDULE_CREATE,
|
|
232
|
-
children: /* @__PURE__ */ m(
|
|
238
|
+
children: /* @__PURE__ */ m(_, {
|
|
233
239
|
type: "submit",
|
|
234
|
-
disabled:
|
|
235
|
-
className: "flex-1
|
|
236
|
-
children: [/* @__PURE__ */ p(f, { size: 20 }),
|
|
240
|
+
disabled: N || !k,
|
|
241
|
+
className: "flex-1 min-h-[44px]",
|
|
242
|
+
children: [/* @__PURE__ */ p(f, { size: 20 }), N ? S("tourScheduler.creating", "Creating...") : S("tourScheduler.createSchedule", "Create Schedule")]
|
|
237
243
|
})
|
|
238
244
|
})]
|
|
239
245
|
})
|
|
@@ -243,6 +249,6 @@ function y() {
|
|
|
243
249
|
});
|
|
244
250
|
}
|
|
245
251
|
//#endregion
|
|
246
|
-
export {
|
|
252
|
+
export { x as SchedulerPage };
|
|
247
253
|
|
|
248
254
|
//# sourceMappingURL=SchedulerPage.js.map
|
|
@@ -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 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-text-secondary\">\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-subtle rounded-md p-4 sm:p-6 bg-bg-surface\">\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-subtle 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-text-secondary\">\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-text-secondary\">\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-subtle rounded-md p-4 sm:p-6 bg-bg-surface\">\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-subtle rounded-md bg-bg-surface\"\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-subtle rounded-md bg-bg-surface\"\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-subtle rounded-md p-4 sm:p-6 bg-bg-surface\">\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-subtle rounded-md bg-bg-surface\"\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-subtle rounded-md bg-bg-surface\"\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-subtle rounded-md p-4 sm:p-6 bg-bg-surface\">\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-text-secondary\">\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-subtle 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-action-primary-bg text-action-primary-text rounded-md hover:bg-action-primary-bg/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 { Button, GlassCard } from '@burdenoff/fe-libs/ui';\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-text-secondary\">\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 <GlassCard treatment=\"plain\" className=\"p-4 sm:p-6 border-border-seam\">\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-seam 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-text-secondary\">\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-text-secondary tabular-nums\">\n {tr('tourScheduler.runs', 'Runs')}: {schedule.executionCount}\n </div>\n </div>\n ))}\n </div>\n </GlassCard>\n )}\n\n {/* Form */}\n <form onSubmit={handleSubmit} className=\"space-y-6\">\n {/* Date Range */}\n <GlassCard treatment=\"plain\" className=\"p-4 sm:p-6 border-border-seam\">\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-subtle rounded-md bg-bg-surface\"\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-subtle rounded-md bg-bg-surface\"\n aria-label={tr('tourScheduler.labelEndDate', 'End Date (Optional)')}\n />\n </div>\n </div>\n </GlassCard>\n\n {/* Recurrence */}\n <GlassCard treatment=\"plain\" className=\"p-4 sm:p-6 border-border-seam\">\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-subtle rounded-md bg-bg-surface\"\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-subtle rounded-md bg-bg-surface\"\n readOnly\n aria-label={tr('tourScheduler.labelTimezone', 'Timezone')}\n />\n </div>\n </div>\n </GlassCard>\n\n {/* Status */}\n <GlassCard treatment=\"plain\" className=\"p-4 sm:p-6 border-border-seam\">\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-text-secondary\">\n {tr(\n 'tourScheduler.statusActiveDescription',\n 'Enable this schedule immediately after creation'\n )}\n </div>\n </div>\n </label>\n </GlassCard>\n\n {/* Actions */}\n <div className=\"flex flex-col sm:flex-row gap-3\">\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={handleBack}\n className=\"flex-1 min-h-[44px]\"\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 min-h-[44px]\"\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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"}
|