@burdenoff/microfe-tours 2026.624.1 → 2026.625.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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 { useI18n as _ } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
12
- import { useEventBus as v } from "@burdenoff/fe-libs/shared/events";
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 y() {
15
- let { t: y } = _(), b = o((e, t) => {
16
- let n = y(e);
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
- }, [y]), { tourId: x } = g(), S = h(), C = e(), { basePath: w = "/" } = C, T = v(), { hasPermission: E } = r(), D = E(i.TOUR_SCHEDULE_CREATE), O = E(i.TOUR_SCHEDULE_LIST), [k, A] = s({
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
- }), [j, M] = s(!1), [N] = t(), { data: P } = n({
25
- variables: { tourId: x },
26
- skip: !x || !O
27
- }), F = P?.tourSchedules ?? [], I = async (e) => {
28
- if (e.preventDefault(), x) {
29
- M(!0);
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 = k.recurrencePattern === "DAILY" ? "FREQ=DAILY" : k.recurrencePattern === "WEEKLY" ? "FREQ=WEEKLY" : k.recurrencePattern === "MONTHLY" ? "FREQ=MONTHLY" : void 0;
32
- await N({
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: x,
35
- startDate: new Date(k.startDate).toISOString(),
36
- endDate: k.endDate ? new Date(k.endDate).toISOString() : void 0,
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: k.timezone
39
+ timezone: j.timezone
39
40
  } },
40
41
  refetchQueries: ["GetTourSchedules"]
41
- }), S(`${w}/${x}/edit`);
42
+ }), w(`${E}/${C}/edit`);
42
43
  } catch {
43
- a(T, "schedule.create", C);
44
+ a(D, "schedule.create", T);
44
45
  } finally {
45
- M(!1);
46
+ P(!1);
46
47
  }
47
48
  }
48
- }, L = () => {
49
- S(`${w}/${x}/edit`);
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: L,
59
+ onClick: z,
59
60
  className: "p-2 min-h-[44px] min-w-[44px] hover:bg-accent rounded-md",
60
- "aria-label": b("tourScheduler.goBack", "Go back"),
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: b("tourScheduler.title", "Schedule Tour")
65
+ children: S("tourScheduler.title", "Schedule Tour")
65
66
  }), /* @__PURE__ */ p("p", {
66
67
  className: "text-sm text-text-secondary",
67
- children: b("tourScheduler.subtitle", "Configure when this tour should be activated")
68
+ children: S("tourScheduler.subtitle", "Configure when this tour should be activated")
68
69
  })] })]
69
70
  }),
70
- F.length > 0 && /* @__PURE__ */ m("div", {
71
- className: "border border-border-subtle rounded-md p-4 sm:p-6 bg-bg-surface",
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: b("tourScheduler.existingSchedules", "Existing Schedules")
76
+ children: S("tourScheduler.existingSchedules", "Existing Schedules")
75
77
  }), /* @__PURE__ */ p("div", {
76
78
  className: "space-y-2",
77
- children: F.map((e) => /* @__PURE__ */ m("div", {
78
- className: "flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between p-3 border border-border-subtle rounded-md",
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()}` : ` — ${b("tourScheduler.noEndDate", "No end date")}`]
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 || b("tourScheduler.oneTime", "One-time"),
87
+ e.recurrenceRule || S("tourScheduler.oneTime", "One-time"),
86
88
  " ·",
87
89
  " ",
88
90
  e.timezone,
89
- e.isActive ? ` · ${b("tourScheduler.active", "Active")}` : ` · ${b("tourScheduler.inactive", "Inactive")}`
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
- b("tourScheduler.runs", "Runs"),
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: I,
105
+ onSubmit: R,
104
106
  className: "space-y-6",
105
107
  children: [
106
- /* @__PURE__ */ m("div", {
107
- className: "border border-border-subtle rounded-md p-4 sm:p-6 bg-bg-surface",
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 }), b("tourScheduler.sectionDateRange", "Date Range")]
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: b("tourScheduler.labelStartDate", "Start Date *")
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: k.startDate,
121
- onChange: (e) => A({
122
- ...k,
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": b("tourScheduler.labelStartDate", "Start Date *")
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: b("tourScheduler.labelEndDate", "End Date (Optional)")
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: k.endDate,
136
- onChange: (e) => A({
137
- ...k,
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": b("tourScheduler.labelEndDate", "End Date (Optional)")
144
+ "aria-label": S("tourScheduler.labelEndDate", "End Date (Optional)")
142
145
  })] })]
143
146
  })]
144
147
  }),
145
- /* @__PURE__ */ m("div", {
146
- className: "border border-border-subtle rounded-md p-4 sm:p-6 bg-bg-surface",
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 }), b("tourScheduler.sectionRecurrence", "Recurrence")]
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: b("tourScheduler.labelRecurrencePattern", "Recurrence Pattern")
159
+ children: S("tourScheduler.labelRecurrencePattern", "Recurrence Pattern")
156
160
  }), /* @__PURE__ */ m("select", {
157
161
  id: "scheduler-recurrence",
158
- value: k.recurrencePattern,
159
- onChange: (e) => A({
160
- ...k,
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": b("tourScheduler.labelRecurrencePattern", "Recurrence Pattern"),
168
+ "aria-label": S("tourScheduler.labelRecurrencePattern", "Recurrence Pattern"),
165
169
  children: [
166
170
  /* @__PURE__ */ p("option", {
167
171
  value: "DAILY",
168
- children: b("tourScheduler.recurrenceDaily", "Daily")
172
+ children: S("tourScheduler.recurrenceDaily", "Daily")
169
173
  }),
170
174
  /* @__PURE__ */ p("option", {
171
175
  value: "WEEKLY",
172
- children: b("tourScheduler.recurrenceWeekly", "Weekly")
176
+ children: S("tourScheduler.recurrenceWeekly", "Weekly")
173
177
  }),
174
178
  /* @__PURE__ */ p("option", {
175
179
  value: "MONTHLY",
176
- children: b("tourScheduler.recurrenceMonthly", "Monthly")
180
+ children: S("tourScheduler.recurrenceMonthly", "Monthly")
177
181
  }),
178
182
  /* @__PURE__ */ p("option", {
179
183
  value: "CUSTOM",
180
- children: b("tourScheduler.recurrenceCustom", "Custom")
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: b("tourScheduler.labelTimezone", "Timezone")
190
+ children: S("tourScheduler.labelTimezone", "Timezone")
187
191
  }), /* @__PURE__ */ p("input", {
188
192
  id: "scheduler-timezone",
189
193
  type: "text",
190
- value: k.timezone,
191
- onChange: (e) => A({
192
- ...k,
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": b("tourScheduler.labelTimezone", "Timezone")
201
+ "aria-label": S("tourScheduler.labelTimezone", "Timezone")
198
202
  })] })]
199
203
  })]
200
204
  }),
201
- /* @__PURE__ */ p("div", {
202
- className: "border border-border-subtle rounded-md p-4 sm:p-6 bg-bg-surface",
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: k.isActive,
208
- onChange: (e) => A({
209
- ...k,
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": b("tourScheduler.statusActiveLabel", "Active")
218
+ "aria-label": S("tourScheduler.statusActiveLabel", "Active")
214
219
  }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("div", {
215
220
  className: "font-medium",
216
- children: b("tourScheduler.statusActiveLabel", "Active")
221
+ children: S("tourScheduler.statusActiveLabel", "Active")
217
222
  }), /* @__PURE__ */ p("div", {
218
223
  className: "text-sm text-text-secondary",
219
- children: b("tourScheduler.statusActiveDescription", "Enable this schedule immediately after creation")
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("button", {
230
+ children: [/* @__PURE__ */ p(_, {
226
231
  type: "button",
227
- onClick: L,
228
- className: "flex-1 px-4 py-2 min-h-[44px] border border-border-subtle rounded-md hover:bg-accent",
229
- children: b("tourScheduler.cancel", "Cancel")
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("button", {
238
+ children: /* @__PURE__ */ m(_, {
233
239
  type: "submit",
234
- disabled: j || !D,
235
- 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",
236
- children: [/* @__PURE__ */ p(f, { size: 20 }), j ? b("tourScheduler.creating", "Creating...") : b("tourScheduler.createSchedule", "Create Schedule")]
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 { y as SchedulerPage };
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":";;;;;;;;;;;;;;AAmBA,SAAgB,IAAgB;CAC9B,IAAM,EAAE,SAAM,GAAS,EACjB,IAAK,GACR,GAAa,MAA6B;EACzC,IAAM,IAAQ,EAAE,EAAI;AACpB,SAAO,MAAU,IAAM,IAAW;IAEpC,CAAC,EAAE,CACJ,EACK,EAAE,cAAW,GAAW,EACxB,IAAW,GAAa,EACxB,IAAe,GAAiB,EAChC,EAAE,cAAW,QAAQ,GACrB,IAAW,GAAa,EACxB,EAAE,qBAAkB,GAA0B,EAC9C,IAAoB,EAAc,EAAiB,qBAAqB,EACxE,IAAmB,EAAc,EAAiB,mBAAmB,EAErE,CAAC,GAAc,KAAmB,EAAS;EAC/C,WAAW;EACX,SAAS;EACT,mBAAmB;EACnB,UAAU,KAAK,gBAAgB,CAAC,iBAAiB,CAAC;EAClD,UAAU;EACX,CAAC,EAEI,CAAC,GAAQ,KAAa,EAAS,GAAM,EAErC,CAAC,KAAkB,GAA+B,EAClD,EAAE,MAAM,MAAkB,EAAyB;EACvD,WAAW,EAAU,WAAS;EAC9B,MAAM,CAAC,KAAU,CAAC;EACnB,CAAC,EACI,IAAoB,GAAe,iBAAiB,EAAE,EAEtD,IAAe,OAAO,MAAuB;AACjD,QAAE,gBAAgB,EACb,GACL;KAAU,GAAK;AACf,OAAI;IAEF,IAAM,IACJ,EAAa,sBAAsB,UAC/B,eACA,EAAa,sBAAsB,WACjC,gBACA,EAAa,sBAAsB,YACjC,iBACA,KAAA;AAgBV,IAdA,MAAM,EAAe;KACnB,WAAW,EACT,OAAO;MACL;MACA,WAAW,IAAI,KAAK,EAAa,UAAU,CAAC,aAAa;MACzD,SAAS,EAAa,UAClB,IAAI,KAAK,EAAa,QAAQ,CAAC,aAAa,GAC5C,KAAA;MACJ;MACA,UAAU,EAAa;MACxB,EACF;KACD,gBAAgB,CAAC,mBAAmB;KACrC,CAAC,EACF,EAAS,GAAG,EAAS,GAAG,EAAO,OAAO;WAChC;AACN,MAAmB,GAAU,mBAAmB,EAAa;aACrD;AACR,MAAU,GAAM;;;IAId,UAAmB;AACvB,IAAS,GAAG,EAAS,GAAG,EAAO,OAAO;;AAGxC,QACE,kBAAC,OAAD;EAAK,WAAU;YAAf;GAEE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,UAAD;KACE,MAAK;KACL,SAAS;KACT,WAAU;KACV,cAAY,EAAG,wBAAwB,UAAU;eAEjD,kBAAC,GAAD,EAAW,MAAM,IAAM,CAAA;KAChB,CAAA,EACT,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;KAAI,WAAU;eACX,EAAG,uBAAuB,gBAAgB;KACxC,CAAA,EACL,kBAAC,KAAD;KAAG,WAAU;eACV,EAAG,0BAA0B,+CAA+C;KAC3E,CAAA,CACA,EAAA,CAAA,CACF;;GAGL,EAAkB,SAAS,KAC1B,kBAAC,GAAD;IAAW,WAAU;IAAQ,WAAU;cAAvC,CACE,kBAAC,MAAD;KAAI,WAAU;eACX,EAAG,mCAAmC,qBAAqB;KACzD,CAAA,EACL,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAkB,KAAK,MACtB,kBAAC,OAAD;MAEE,WAAU;gBAFZ,CAIE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACG,IAAI,KAAK,EAAS,UAAU,CAAC,oBAAoB,EACjD,EAAS,UACN,MAAM,IAAI,KAAK,EAAS,QAAQ,CAAC,oBAAoB,KACrD,MAAM,EAAG,2BAA2B,cAAc,GAClD;UACN,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACG,EAAS,kBAAkB,EAAG,yBAAyB,WAAW;QAAC;QAAG;QACtE,EAAS;QACT,EAAS,WACN,MAAM,EAAG,wBAAwB,SAAS,KAC1C,MAAM,EAAG,0BAA0B,WAAW;QAC9C;SACF,EAAA,CAAA,EACN,kBAAC,OAAD;OAAK,WAAU;iBAAf;QACG,EAAG,sBAAsB,OAAO;QAAC;QAAG,EAAS;QAC1C;SACF;QArBC,EAAS,GAqBV,CACN;KACE,CAAA,CACI;;GAId,kBAAC,QAAD;IAAM,UAAU;IAAc,WAAU;cAAxC;KAEE,kBAAC,GAAD;MAAW,WAAU;MAAQ,WAAU;gBAAvC,CACE,kBAAC,MAAD;OAAI,WAAU;iBAAd,CACE,kBAAC,GAAD,EAAU,MAAM,IAAM,CAAA,EACrB,EAAG,kCAAkC,aAAa,CAChD;UAEL,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,SAAQ;QAAuB,WAAU;kBAC7C,EAAG,gCAAgC,eAAe;QAC7C,CAAA,EACR,kBAAC,SAAD;QACE,IAAG;QACH,MAAK;QACL,OAAO,EAAa;QACpB,WAAW,MAAM,EAAgB;SAAE,GAAG;SAAc,WAAW,EAAE,OAAO;SAAO,CAAC;QAChF,WAAU;QACV,UAAA;QACA,cAAY,EAAG,gCAAgC,eAAe;QAC9D,CAAA,CACE,EAAA,CAAA,EAEN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,SAAQ;QAAqB,WAAU;kBAC3C,EAAG,8BAA8B,sBAAsB;QAClD,CAAA,EACR,kBAAC,SAAD;QACE,IAAG;QACH,MAAK;QACL,OAAO,EAAa;QACpB,WAAW,MAAM,EAAgB;SAAE,GAAG;SAAc,SAAS,EAAE,OAAO;SAAO,CAAC;QAC9E,WAAU;QACV,cAAY,EAAG,8BAA8B,sBAAsB;QACnE,CAAA,CACE,EAAA,CAAA,CACF;SACI;;KAGZ,kBAAC,GAAD;MAAW,WAAU;MAAQ,WAAU;gBAAvC,CACE,kBAAC,MAAD;OAAI,WAAU;iBAAd,CACE,kBAAC,GAAD,EAAO,MAAM,IAAM,CAAA,EAClB,EAAG,mCAAmC,aAAa,CACjD;UAEL,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,SAAQ;QAAuB,WAAU;kBAC7C,EAAG,wCAAwC,qBAAqB;QAC3D,CAAA,EACR,kBAAC,UAAD;QACE,IAAG;QACH,OAAO,EAAa;QACpB,WAAW,MACT,EAAgB;SACd,GAAG;SACH,mBAAmB,EAAE,OAAO;SAC7B,CAAC;QAEJ,WAAU;QACV,cAAY,EAAG,wCAAwC,qBAAqB;kBAV9E;SAYE,kBAAC,UAAD;UAAQ,OAAM;oBAAS,EAAG,iCAAiC,QAAQ;UAAU,CAAA;SAC7E,kBAAC,UAAD;UAAQ,OAAM;oBAAU,EAAG,kCAAkC,SAAS;UAAU,CAAA;SAChF,kBAAC,UAAD;UAAQ,OAAM;oBAAW,EAAG,mCAAmC,UAAU;UAAU,CAAA;SACnF,kBAAC,UAAD;UAAQ,OAAM;oBAAU,EAAG,kCAAkC,SAAS;UAAU,CAAA;SACzE;UACL,EAAA,CAAA,EAEN,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,SAAD;QAAO,SAAQ;QAAqB,WAAU;kBAC3C,EAAG,+BAA+B,WAAW;QACxC,CAAA,EACR,kBAAC,SAAD;QACE,IAAG;QACH,MAAK;QACL,OAAO,EAAa;QACpB,WAAW,MAAM,EAAgB;SAAE,GAAG;SAAc,UAAU,EAAE,OAAO;SAAO,CAAC;QAC/E,WAAU;QACV,UAAA;QACA,cAAY,EAAG,+BAA+B,WAAW;QACzD,CAAA,CACE,EAAA,CAAA,CACF;SACI;;KAGZ,kBAAC,GAAD;MAAW,WAAU;MAAQ,WAAU;gBACrC,kBAAC,SAAD;OAAO,WAAU;iBAAjB,CACE,kBAAC,SAAD;QACE,MAAK;QACL,SAAS,EAAa;QACtB,WAAW,MAAM,EAAgB;SAAE,GAAG;SAAc,UAAU,EAAE,OAAO;SAAS,CAAC;QACjF,WAAU;QACV,cAAY,EAAG,mCAAmC,SAAS;QAC3D,CAAA,EACF,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,OAAD;QAAK,WAAU;kBAAe,EAAG,mCAAmC,SAAS;QAAO,CAAA,EACpF,kBAAC,OAAD;QAAK,WAAU;kBACZ,EACC,yCACA,kDACD;QACG,CAAA,CACF,EAAA,CAAA,CACA;;MACE,CAAA;KAGZ,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,GAAD;OACE,MAAK;OACL,SAAQ;OACR,SAAS;OACT,WAAU;iBAET,EAAG,wBAAwB,SAAS;OAC9B,CAAA,EACT,kBAAC,GAAD;OAAgB,YAAY,EAAiB;iBAC3C,kBAAC,GAAD;QACE,MAAK;QACL,UAAU,KAAU,CAAC;QACrB,WAAU;kBAHZ,CAKE,kBAAC,GAAD,EAAM,MAAM,IAAM,CAAA,EACjB,IACG,EAAG,0BAA0B,cAAc,GAC3C,EAAG,gCAAgC,kBAAkB,CAClD;;OACM,CAAA,CACb;;KACD;;GACH"}