@easyteam/auto-scheduler-modal-ui 0.1.0

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/index.cjs ADDED
@@ -0,0 +1,2543 @@
1
+ 'use client'
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/index.ts
32
+ var src_exports = {};
33
+ __export(src_exports, {
34
+ AutoSchedulerModal: () => AutoSchedulerModal,
35
+ AutoSchedulerModalWithProvider: () => AutoSchedulerModalWithProvider,
36
+ RequestError: () => RequestError,
37
+ ViolatedConstraintsPanel: () => ViolatedConstraintsPanel,
38
+ ViolatedConstraintsPanelWithProvider: () => ViolatedConstraintsPanelWithProvider,
39
+ buildRulesPayload: () => buildRulesPayload,
40
+ buildSchedulePayload: () => buildSchedulePayload,
41
+ getFriendlyRuleName: () => getFriendlyRuleName
42
+ });
43
+ module.exports = __toCommonJS(src_exports);
44
+
45
+ // src/AutoSchedulerModal.tsx
46
+ var import_react3 = require("react");
47
+ var import_react4 = require("@chakra-ui/react");
48
+
49
+ // src/icons/AutoSchedulerIcons.tsx
50
+ var import_jsx_runtime = require("react/jsx-runtime");
51
+ function DotIcon({ size = 6, fill, stroke, ...props }) {
52
+ const useStroke = stroke != null;
53
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
54
+ "svg",
55
+ {
56
+ "aria-hidden": "true",
57
+ viewBox: "0 0 20 20",
58
+ fill: useStroke ? "none" : fill != null ? fill : "currentColor",
59
+ stroke,
60
+ width: size,
61
+ height: size,
62
+ ...props,
63
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "10", cy: "10", r: "10" })
64
+ }
65
+ );
66
+ }
67
+ function MagicIcon(props) {
68
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
69
+ "svg",
70
+ {
71
+ "aria-hidden": "true",
72
+ viewBox: "0 0 20 20",
73
+ fill: "currentColor",
74
+ width: "20",
75
+ height: "20",
76
+ ...props,
77
+ children: [
78
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M10 2.5l1.2 3.3 3.3 1.2-3.3 1.2-1.2 3.3-1.2-3.3-3.3-1.2 3.3-1.2L10 2.5z" }),
79
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4.5 11.2l.7 1.9 1.9.7-1.9.7-.7 1.9-.7-1.9-1.9-.7 1.9-.7.7-1.9z" }),
80
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M15.5 12.5l.6 1.7 1.7.6-1.7.6-.6 1.7-.6-1.7-1.7-.6 1.7-.6.6-1.7z" })
81
+ ]
82
+ }
83
+ );
84
+ }
85
+ function InfoIcon(props) {
86
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
87
+ "svg",
88
+ {
89
+ "aria-hidden": "true",
90
+ viewBox: "0 0 20 20",
91
+ fill: "currentColor",
92
+ width: "20",
93
+ height: "20",
94
+ ...props,
95
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M10 1.75a8.25 8.25 0 1 0 0 16.5 8.25 8.25 0 0 0 0-16.5zm0 3.75a1 1 0 1 1 0 2 1 1 0 0 1 0-2zm-1 4.25c0-.41.34-.75.75-.75h.5c.41 0 .75.34.75.75v5.25a.75.75 0 0 1-1.5 0v-4.5h-.25a.75.75 0 0 1-.75-.75z" })
96
+ }
97
+ );
98
+ }
99
+ function WarningIcon(props) {
100
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
101
+ "svg",
102
+ {
103
+ "aria-hidden": "true",
104
+ viewBox: "0 0 20 20",
105
+ fill: "none",
106
+ width: "20",
107
+ height: "20",
108
+ ...props,
109
+ children: [
110
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
111
+ "path",
112
+ {
113
+ d: "M9.25 3.6a.86.86 0 0 1 1.5 0l7.2 12.1a.86.86 0 0 1-.75 1.3H2.8a.86.86 0 0 1-.75-1.3l7.2-12.1z",
114
+ stroke: "currentColor",
115
+ strokeWidth: "1.4",
116
+ strokeLinejoin: "round"
117
+ }
118
+ ),
119
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
120
+ "path",
121
+ {
122
+ d: "M10 7v4.7",
123
+ stroke: "currentColor",
124
+ strokeWidth: "1.4",
125
+ strokeLinecap: "round"
126
+ }
127
+ ),
128
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "10", cy: "13.5", r: "0.9", fill: "currentColor" })
129
+ ]
130
+ }
131
+ );
132
+ }
133
+ function ChevronDownIcon(props) {
134
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
135
+ "svg",
136
+ {
137
+ "aria-hidden": "true",
138
+ viewBox: "0 0 20 20",
139
+ fill: "none",
140
+ width: "20",
141
+ height: "20",
142
+ ...props,
143
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
144
+ "path",
145
+ {
146
+ d: "M5 7.5l5 5 5-5",
147
+ stroke: "currentColor",
148
+ strokeWidth: "1.6",
149
+ strokeLinecap: "round",
150
+ strokeLinejoin: "round"
151
+ }
152
+ )
153
+ }
154
+ );
155
+ }
156
+ function CloseIcon(props) {
157
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
158
+ "svg",
159
+ {
160
+ "aria-hidden": "true",
161
+ viewBox: "0 0 20 20",
162
+ fill: "none",
163
+ width: "20",
164
+ height: "20",
165
+ ...props,
166
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
167
+ "path",
168
+ {
169
+ d: "M5.5 5.5l9 9m0-9l-9 9",
170
+ stroke: "currentColor",
171
+ strokeWidth: "1.6",
172
+ strokeLinecap: "round",
173
+ strokeLinejoin: "round"
174
+ }
175
+ )
176
+ }
177
+ );
178
+ }
179
+ function CheckIcon(props) {
180
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
181
+ "svg",
182
+ {
183
+ "aria-hidden": "true",
184
+ viewBox: "0 0 20 20",
185
+ fill: "none",
186
+ width: "20",
187
+ height: "20",
188
+ ...props,
189
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
190
+ "path",
191
+ {
192
+ d: "M5.5 10.5l3 3 6-6",
193
+ stroke: "currentColor",
194
+ strokeWidth: "1.6",
195
+ strokeLinecap: "round",
196
+ strokeLinejoin: "round"
197
+ }
198
+ )
199
+ }
200
+ );
201
+ }
202
+ function FailedIcon(props) {
203
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
204
+ "svg",
205
+ {
206
+ "aria-hidden": "true",
207
+ viewBox: "0 0 20 20",
208
+ fill: "none",
209
+ width: "20",
210
+ height: "20",
211
+ ...props,
212
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
213
+ "path",
214
+ {
215
+ d: "M6.5 6.5l7 7m0-7l-7 7",
216
+ stroke: "currentColor",
217
+ strokeWidth: "1.8",
218
+ strokeLinecap: "round",
219
+ strokeLinejoin: "round"
220
+ }
221
+ )
222
+ }
223
+ );
224
+ }
225
+
226
+ // src/theme/mergeTheme.ts
227
+ var componentNameMap = {
228
+ button: "Button",
229
+ input: "Input",
230
+ tooltip: "Tooltip",
231
+ modal: "Modal",
232
+ switch: "Switch",
233
+ drawer: "Drawer",
234
+ checkbox: "Checkbox",
235
+ radio: "Radio",
236
+ menu: "Menu",
237
+ tabs: "Tabs",
238
+ select: "Select",
239
+ numberinput: "NumberInput",
240
+ textarea: "Textarea",
241
+ popover: "Popover",
242
+ badge: "Badge",
243
+ text: "Text"
244
+ };
245
+ var isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
246
+ var mapComponentOverrides = (overrides) => {
247
+ const result = {};
248
+ Object.entries(overrides).forEach(([key, value]) => {
249
+ var _a, _b;
250
+ if (key === "components" && isRecord(value)) {
251
+ Object.assign(result, value);
252
+ return;
253
+ }
254
+ const normalizedKey = (_b = (_a = componentNameMap[key]) != null ? _a : componentNameMap[key.toLowerCase()]) != null ? _b : key;
255
+ result[normalizedKey] = value;
256
+ });
257
+ return result;
258
+ };
259
+ var deepMerge = (target, source) => {
260
+ const result = { ...target };
261
+ Object.entries(source).forEach(([key, value]) => {
262
+ if (isRecord(value) && isRecord(result[key])) {
263
+ result[key] = deepMerge(result[key], value);
264
+ return;
265
+ }
266
+ result[key] = value;
267
+ });
268
+ return result;
269
+ };
270
+ var resolveThemeParts = (theme) => {
271
+ if (!theme || !isRecord(theme)) {
272
+ return {};
273
+ }
274
+ const autoSchedulerModal = isRecord(theme.autoSchedulerModal) ? theme.autoSchedulerModal : void 0;
275
+ if ("tokens" in theme) {
276
+ const easyTheme = theme;
277
+ const { tokens, autoSchedulerModal: _ignored2, ...rest } = easyTheme;
278
+ const chakraOverride = {
279
+ ...isRecord(tokens) ? tokens : {},
280
+ components: mapComponentOverrides(rest)
281
+ };
282
+ return { chakraOverride, styleOverrides: autoSchedulerModal };
283
+ }
284
+ const { autoSchedulerModal: _ignored, ...override } = theme;
285
+ return { chakraOverride: override, styleOverrides: autoSchedulerModal };
286
+ };
287
+ var mergeThemeWithBase = (baseTheme, override) => {
288
+ if (!override) {
289
+ return baseTheme;
290
+ }
291
+ return deepMerge(baseTheme, override);
292
+ };
293
+
294
+ // src/constants.ts
295
+ var HARD_CONSTRAINT_DEFAULTS = {
296
+ max_weekly_hours: "40",
297
+ max_daily_hours: "8",
298
+ min_rest_between_shifts: "24",
299
+ max_work_days_per_week: "6"
300
+ };
301
+ var HARD_CONSTRAINT_OPTIONS = [
302
+ { id: "max_weekly_hours", name: "Maximum weekly hours" },
303
+ { id: "max_daily_hours", name: "Maximum daily hours" },
304
+ { id: "min_rest_between_shifts", name: "Minimum rest between shifts" },
305
+ { id: "max_work_days_per_week", name: "Maximum work days per week" }
306
+ // { id: "minor_max_daily_hours", name: "Minor maximum daily hours" },
307
+ // { id: "minor_late_hours_restriction", name: "Minor late hours restriction" },
308
+ // { id: "part_time_weekly_limit", name: "Part-time weekly limit" },
309
+ // { id: "min_staffing", name: "Minimum staffing" },
310
+ ];
311
+ var OPTIMIZATION_OPTION_GROUPS = [
312
+ {
313
+ id: "employee_happiness",
314
+ name: "Employee happiness",
315
+ options: [
316
+ {
317
+ id: "fair_hour_distribution",
318
+ title: "Fair hour distribution",
319
+ subtitle: "Distribute shifts evenly across all staff members"
320
+ },
321
+ {
322
+ id: "staff_preferences",
323
+ title: "Respect open shift preferences",
324
+ subtitle: "Consider staff requests and preferred shifts when assigning"
325
+ }
326
+ ]
327
+ },
328
+ {
329
+ id: "labor_cost_optimization",
330
+ name: "Labor cost optimization",
331
+ options: [
332
+ {
333
+ id: "minimize_overtime",
334
+ title: "Minimize overtime",
335
+ subtitle: "Reduce hours beyond standard work time"
336
+ },
337
+ {
338
+ id: "cost_to_sales_ratio",
339
+ title: "Cost-to-sales ratio",
340
+ subtitle: "Assign shifts based on total compensation (wages + commissions) compared to sales performance"
341
+ }
342
+ ]
343
+ },
344
+ {
345
+ id: "sales_optimization",
346
+ name: "Sales optimization",
347
+ options: [
348
+ {
349
+ id: "maximize_sales",
350
+ title: "Maximize sales",
351
+ subtitle: "Prioritize top-performing staff during peak hours"
352
+ }
353
+ ]
354
+ }
355
+ ];
356
+ var defaultStyles = {
357
+ overlay: {
358
+ bg: "rgba(0, 0, 0, 0.45)"
359
+ },
360
+ content: {
361
+ maxW: "600px",
362
+ bg: "white",
363
+ borderRadius: "20px",
364
+ boxShadow: "0px 20px 20px -8px rgba(26, 26, 26, 0.28), inset 0px 1px 0px rgba(204, 204, 204, 0.5), inset 0px -1px 0px rgba(0, 0, 0, 0.17), inset 1px 0px 0px rgba(0, 0, 0, 0.13), inset -1px 0px 0px rgba(0, 0, 0, 0.17)",
365
+ overflow: "hidden",
366
+ maxH: "calc(100vh - 32px)",
367
+ display: "flex",
368
+ flexDirection: "column"
369
+ },
370
+ header: {
371
+ bg: "#f3f3f3",
372
+ borderBottom: "1px solid #e3e3e3",
373
+ px: "16px",
374
+ py: "12px"
375
+ },
376
+ title: {
377
+ fontSize: "14px",
378
+ fontWeight: 600,
379
+ color: "#303030"
380
+ },
381
+ closeButton: {
382
+ color: "#5c5c5c",
383
+ borderRadius: "8px"
384
+ },
385
+ body: {
386
+ px: "16px",
387
+ py: "16px",
388
+ overflowY: "auto",
389
+ flex: "1 1 auto"
390
+ },
391
+ banner: {
392
+ backgroundColor: "#F5EFFF !important",
393
+ borderRadius: "8px",
394
+ px: "8px",
395
+ py: "8px",
396
+ display: "flex",
397
+ gap: "8px",
398
+ alignItems: "flex-start"
399
+ },
400
+ bannerIcon: {
401
+ color: "#5c2dbf"
402
+ },
403
+ bannerTitle: {
404
+ fontSize: "13px",
405
+ fontWeight: 700,
406
+ color: "#370e88",
407
+ lineHeight: "20px"
408
+ },
409
+ bannerText: {
410
+ fontSize: "13px",
411
+ color: "#370e88",
412
+ lineHeight: "20px"
413
+ },
414
+ locationSection: {},
415
+ locationLabelRow: {
416
+ alignItems: "center",
417
+ gap: "8px"
418
+ },
419
+ locationLabel: {
420
+ fontSize: "14px",
421
+ fontWeight: 600,
422
+ color: "#303030"
423
+ },
424
+ locationBadge: {
425
+ bg: "#e1e3e5",
426
+ color: "#303030",
427
+ borderRadius: "999px",
428
+ px: "6px",
429
+ py: "2px",
430
+ fontSize: "11px",
431
+ fontWeight: 600
432
+ },
433
+ locationSubtitle: {
434
+ fontSize: "12px",
435
+ color: "#616161"
436
+ },
437
+ locationTrigger: {
438
+ w: "100%",
439
+ justifyContent: "space-between",
440
+ px: "12px",
441
+ h: "32px",
442
+ borderRadius: "8px",
443
+ border: "1px solid rgb(185, 184, 184)"
444
+ },
445
+ locationTriggerText: {
446
+ fontSize: "13px",
447
+ fontWeight: 450,
448
+ color: "#616161"
449
+ },
450
+ popoverContent: {
451
+ w: "100%",
452
+ bg: "white",
453
+ borderRadius: "12px",
454
+ px: "6px",
455
+ py: "6px",
456
+ border: "none",
457
+ maxH: "260px",
458
+ overflowY: "auto",
459
+ boxShadow: "0px 4px 6px -2px rgba(26, 26, 26, 0.2), inset 0px 1px 0px rgba(204, 204, 204, 0.5), inset 0px -1px 0px rgba(0, 0, 0, 0.17), inset 1px 0px 0px rgba(0, 0, 0, 0.13), inset -1px 0px 0px rgba(0, 0, 0, 0.13)"
460
+ },
461
+ groupHeader: {
462
+ px: "6px",
463
+ pt: "2px",
464
+ pb: "4px",
465
+ fontSize: "13px",
466
+ fontWeight: 600,
467
+ color: "#303030"
468
+ },
469
+ optionRow: {
470
+ px: "6px",
471
+ py: "6px",
472
+ borderRadius: "8px",
473
+ alignItems: "center",
474
+ gap: "8px"
475
+ },
476
+ optionLabel: {
477
+ fontSize: "13px",
478
+ color: "#303030"
479
+ },
480
+ selectedBanner: {
481
+ bg: "#eaf4ff",
482
+ borderRadius: "8px",
483
+ px: "8px",
484
+ py: "8px",
485
+ display: "flex",
486
+ gap: "8px",
487
+ alignItems: "flex-start",
488
+ color: "#00527c"
489
+ },
490
+ selectedBannerIcon: {
491
+ color: "#00527c"
492
+ },
493
+ selectedBannerText: {
494
+ fontSize: "13px",
495
+ lineHeight: "20px",
496
+ color: "#00527c"
497
+ },
498
+ hardConstraintsSection: {},
499
+ hardConstraintsLabelRow: {
500
+ alignItems: "center",
501
+ gap: "8px"
502
+ },
503
+ hardConstraintsLabel: {
504
+ fontSize: "14px",
505
+ fontWeight: 600,
506
+ color: "#303030"
507
+ },
508
+ hardConstraintsBadge: {
509
+ bg: "rgba(0, 0, 0, 0.06)",
510
+ color: "#616161",
511
+ borderRadius: "8px",
512
+ px: "8px",
513
+ py: "2px",
514
+ fontSize: "12px",
515
+ fontWeight: 500
516
+ },
517
+ hardConstraintsSubtitle: {
518
+ fontSize: "13px",
519
+ color: "#616161"
520
+ },
521
+ hardConstraintsTrigger: {
522
+ w: "100%",
523
+ justifyContent: "space-between",
524
+ px: "12px",
525
+ h: "32px",
526
+ borderRadius: "8px",
527
+ border: "1px solid rgb(185, 184, 184)"
528
+ },
529
+ hardConstraintsTriggerText: {
530
+ fontSize: "13px",
531
+ fontWeight: 450,
532
+ color: "#616161"
533
+ },
534
+ hardConstraintsPopoverContent: {
535
+ w: "100%",
536
+ bg: "white",
537
+ borderRadius: "12px",
538
+ px: "6px",
539
+ py: "6px",
540
+ border: "none",
541
+ boxShadow: "0px 4px 6px -2px rgba(26, 26, 26, 0.2), inset 0px 1px 0px rgba(204, 204, 204, 0.5), inset 0px -1px 0px rgba(0, 0, 0, 0.17), inset 1px 0px 0px rgba(0, 0, 0, 0.13), inset -1px 0px 0px rgba(0, 0, 0, 0.13)"
542
+ },
543
+ hardConstraintsOptionRow: {
544
+ px: "6px",
545
+ py: "6px",
546
+ borderRadius: "8px",
547
+ alignItems: "center",
548
+ gap: "8px"
549
+ },
550
+ hardConstraintsOptionLabel: {
551
+ fontSize: "13px",
552
+ color: "#303030"
553
+ },
554
+ hardConstraintsInputsContainer: {
555
+ bg: "#f7f7f7",
556
+ border: "1px solid #ebebeb",
557
+ borderRadius: "8px",
558
+ px: "16px",
559
+ py: "16px"
560
+ },
561
+ hardConstraintsInputItem: {
562
+ gap: "4px",
563
+ maxW: "320px"
564
+ },
565
+ hardConstraintsInputLabel: {
566
+ fontSize: "13px",
567
+ color: "#303030"
568
+ },
569
+ hardConstraintsInputField: {
570
+ bg: "#fdfdfd",
571
+ border: "1px solid #8a8a8a",
572
+ borderTopLeftRadius: "8px",
573
+ borderBottomLeftRadius: "8px",
574
+ borderTopRightRadius: 0,
575
+ borderBottomRightRadius: 0,
576
+ h: "28px",
577
+ px: "12px"
578
+ },
579
+ optimizationSection: {},
580
+ optimizationLabelRow: {
581
+ alignItems: "center",
582
+ gap: "8px"
583
+ },
584
+ optimizationLabel: {
585
+ fontSize: "14px",
586
+ fontWeight: 600,
587
+ color: "#303030"
588
+ },
589
+ optimizationBadge: {
590
+ bg: "rgba(0, 0, 0, 0.06)",
591
+ color: "#616161",
592
+ borderRadius: "8px",
593
+ px: "8px",
594
+ py: "2px",
595
+ fontSize: "12px",
596
+ fontWeight: 500
597
+ },
598
+ optimizationSubtitle: {
599
+ fontSize: "13px",
600
+ color: "#616161"
601
+ },
602
+ optimizationTrigger: {
603
+ w: "100%",
604
+ justifyContent: "space-between",
605
+ px: "12px",
606
+ h: "32px",
607
+ borderRadius: "8px",
608
+ border: "1px solid rgb(185, 184, 184)"
609
+ },
610
+ optimizationTriggerText: {
611
+ fontSize: "13px",
612
+ fontWeight: 450,
613
+ color: "#616161"
614
+ },
615
+ optimizationPopoverContent: {
616
+ w: "100%",
617
+ bg: "white",
618
+ borderRadius: "12px",
619
+ px: "6px",
620
+ py: "6px",
621
+ border: "none",
622
+ boxShadow: "0px 4px 6px -2px rgba(26, 26, 26, 0.2), inset 0px 1px 0px rgba(204, 204, 204, 0.5), inset 0px -1px 0px rgba(0, 0, 0, 0.17), inset 1px 0px 0px rgba(0, 0, 0, 0.13), inset -1px 0px 0px rgba(0, 0, 0, 0.13)"
623
+ },
624
+ optimizationGroupHeader: {
625
+ px: "6px",
626
+ pt: "2px",
627
+ pb: "4px",
628
+ fontSize: "13px",
629
+ fontWeight: 600,
630
+ color: "#303030"
631
+ },
632
+ optimizationOptionRow: {
633
+ px: "6px",
634
+ py: "6px",
635
+ borderRadius: "8px",
636
+ alignItems: "flex-start",
637
+ gap: "8px"
638
+ },
639
+ optimizationOptionLabel: {
640
+ fontSize: "13px",
641
+ color: "#303030"
642
+ },
643
+ optimizationOptionHelp: {
644
+ fontSize: "13px",
645
+ color: "#616161",
646
+ ml: "1.5rem"
647
+ },
648
+ optimizationInputsContainer: {
649
+ bg: "#f7f7f7",
650
+ border: "1px solid #ebebeb",
651
+ borderRadius: "8px",
652
+ px: "16px",
653
+ py: "16px"
654
+ },
655
+ optimizationInputItem: {
656
+ gap: "4px",
657
+ maxW: "320px"
658
+ },
659
+ optimizationInputLabel: {
660
+ fontSize: "13px",
661
+ color: "#303030"
662
+ },
663
+ optimizationInputField: {
664
+ bg: "#fdfdfd",
665
+ border: "1px solid #8a8a8a",
666
+ borderTopLeftRadius: "8px",
667
+ borderBottomLeftRadius: "8px",
668
+ borderTopRightRadius: 0,
669
+ borderBottomRightRadius: 0,
670
+ h: "28px",
671
+ px: "12px"
672
+ },
673
+ optimizationSuffix: {
674
+ fontSize: "13px",
675
+ color: "#616161",
676
+ h: "28px",
677
+ bg: "#fdfdfd",
678
+ border: "1px solid #8a8a8a",
679
+ borderLeft: "none",
680
+ borderTopLeftRadius: 0,
681
+ borderBottomLeftRadius: 0,
682
+ borderTopRightRadius: "8px",
683
+ borderBottomRightRadius: "8px"
684
+ },
685
+ optimizationDivider: {
686
+ borderColor: "#ebebeb"
687
+ },
688
+ optimizationSummary: {
689
+ fontSize: "13px",
690
+ color: "#616161"
691
+ },
692
+ creatingBody: {
693
+ py: "20px"
694
+ },
695
+ stepsContainer: {},
696
+ stepsList: {},
697
+ stepRow: {
698
+ alignItems: "flex-start",
699
+ gap: "12px"
700
+ },
701
+ stepIcon: {
702
+ width: "20px",
703
+ height: "20px",
704
+ borderRadius: "999px",
705
+ border: "2px solid #d1d1d1",
706
+ display: "flex",
707
+ alignItems: "center",
708
+ justifyContent: "center",
709
+ color: "#616161",
710
+ flexShrink: 0
711
+ },
712
+ stepIconActive: {
713
+ border: "none",
714
+ color: "#303030"
715
+ },
716
+ stepIconDone: {
717
+ border: "none",
718
+ bg: "#008060",
719
+ color: "white",
720
+ borderRadius: "10px"
721
+ },
722
+ stepIconPending: {
723
+ borderColor: "#d1d1d1",
724
+ color: "#d1d1d1"
725
+ },
726
+ stepIconFailed: {
727
+ border: "none",
728
+ bg: "#d72c0d",
729
+ color: "white",
730
+ borderRadius: "10px"
731
+ },
732
+ stepTitle: {
733
+ fontSize: "13px",
734
+ fontWeight: 600,
735
+ color: "#303030"
736
+ },
737
+ stepTitleActive: {},
738
+ stepTitleDone: {
739
+ color: "#9b9b9b",
740
+ fontWeight: 500
741
+ },
742
+ stepTitlePending: {
743
+ color: "#9b9b9b",
744
+ fontWeight: 500
745
+ },
746
+ stepTitleFailed: {
747
+ color: "#d72c0d",
748
+ fontWeight: 600
749
+ },
750
+ stepSubtitle: {
751
+ fontSize: "12px",
752
+ color: "#616161"
753
+ },
754
+ violationPanel: {
755
+ border: "1px solid #e7e7e7",
756
+ borderRadius: "12px",
757
+ px: "12px",
758
+ py: "12px",
759
+ bg: "white"
760
+ },
761
+ violationHeaderRow: {
762
+ alignItems: "center",
763
+ justifyContent: "space-between"
764
+ },
765
+ violationHeader: {
766
+ alignItems: "center",
767
+ gap: "8px"
768
+ },
769
+ violationIcon: {
770
+ color: "#8E1F0B"
771
+ },
772
+ violationTitle: {
773
+ fontSize: "13px",
774
+ fontWeight: 600,
775
+ color: "#8E1F0B"
776
+ },
777
+ violationSubtitle: {
778
+ fontSize: "12px",
779
+ color: "#616161"
780
+ },
781
+ violationToggleButton: {
782
+ borderRadius: "8px",
783
+ color: "#5c5c5c"
784
+ },
785
+ violationToggleIcon: {
786
+ color: "#5c5c5c"
787
+ },
788
+ violationContent: {
789
+ pt: "8px"
790
+ },
791
+ violationItem: {
792
+ bg: "#fceaea",
793
+ borderRadius: "8px",
794
+ px: "10px",
795
+ py: "8px"
796
+ },
797
+ violationItemTitle: {
798
+ fontSize: "12px",
799
+ fontWeight: 600,
800
+ color: "#8E1F0B"
801
+ },
802
+ violationItemDetailRow: {
803
+ alignItems: "center"
804
+ },
805
+ violationItemDetail: {
806
+ fontSize: "12px",
807
+ color: "#b42318"
808
+ },
809
+ violationBullet: {
810
+ color: "#b42318",
811
+ flexShrink: 0
812
+ },
813
+ recommendationsBox: {
814
+ bg: "#eaf2ff",
815
+ borderRadius: "8px",
816
+ px: "10px",
817
+ py: "8px"
818
+ },
819
+ recommendationsTitle: {
820
+ fontSize: "12px",
821
+ fontWeight: 600,
822
+ color: "#1f4eb0",
823
+ mb: "4px"
824
+ },
825
+ recommendationsList: {},
826
+ recommendationsItem: {
827
+ fontSize: "12px",
828
+ color: "#1f4eb0"
829
+ },
830
+ recommendationsBullet: {
831
+ color: "#1f4eb0",
832
+ flexShrink: 0
833
+ },
834
+ recommendationsToggle: {
835
+ alignSelf: "flex-start",
836
+ borderRadius: "8px",
837
+ fontSize: "12px",
838
+ height: "28px",
839
+ px: "12px"
840
+ },
841
+ failedFooter: {
842
+ borderTop: "1px solid #e3e3e3",
843
+ px: "16px",
844
+ py: "16px",
845
+ justifyContent: "flex-end",
846
+ gap: "8px"
847
+ },
848
+ failedPrimaryButton: {
849
+ fontSize: "12px",
850
+ fontWeight: 600,
851
+ borderRadius: "8px",
852
+ bg: "#303030",
853
+ color: "white",
854
+ height: "30px"
855
+ },
856
+ failedSecondaryButton: {
857
+ fontSize: "12px",
858
+ fontWeight: 500,
859
+ borderRadius: "8px",
860
+ borderColor: "#e3e3e3",
861
+ color: "#303030",
862
+ height: "30px"
863
+ },
864
+ footer: {
865
+ borderTop: "1px solid #e3e3e3",
866
+ px: "16px",
867
+ py: "16px",
868
+ justifyContent: "flex-end",
869
+ gap: "8px"
870
+ },
871
+ cancelButton: {
872
+ fontSize: "12px",
873
+ fontWeight: 500,
874
+ borderRadius: "8px",
875
+ borderColor: "#e3e3e3",
876
+ color: "#303030",
877
+ height: "30px"
878
+ },
879
+ primaryButton: {
880
+ fontSize: "12px",
881
+ fontWeight: 600,
882
+ borderRadius: "8px",
883
+ bg: "#303030",
884
+ color: "white",
885
+ height: "30px"
886
+ },
887
+ violatedConstraintsSecondaryButton: {
888
+ fontWeight: 600
889
+ }
890
+ };
891
+ var SCHEDULE_STEPS = [
892
+ {
893
+ title: "Analyzing requirements",
894
+ subtitle: "Reviewing your required rules and optimization priorities."
895
+ },
896
+ {
897
+ title: "Validating required rules",
898
+ subtitle: "Ensuring all assigned shifts meet your required rules."
899
+ },
900
+ {
901
+ title: "Optimizing assigned shifts",
902
+ subtitle: "Applying optimization priorities to improve coverage and performance."
903
+ },
904
+ { title: "Checking schedule feasibility", subtitle: "Confirming the schedule is feasible and respects all required rules." },
905
+ { title: "Finalizing schedule" }
906
+ ];
907
+ var STEP_INTERVAL_MS = 1200;
908
+ var OPTIMIZING_STEP_INDEX = 2;
909
+ var NETWORK_ERROR_FAILURE = {
910
+ violatedConstraints: [
911
+ { title: "Something went wrong", detail: "Please try again or check your connection." }
912
+ ],
913
+ recommendedFixes: []
914
+ };
915
+
916
+ // src/utils/theme.ts
917
+ var buildStyles = (defaultStyles2, overrides) => ({
918
+ overlay: { ...defaultStyles2.overlay, ...overrides == null ? void 0 : overrides.overlay },
919
+ content: { ...defaultStyles2.content, ...overrides == null ? void 0 : overrides.content },
920
+ header: { ...defaultStyles2.header, ...overrides == null ? void 0 : overrides.header },
921
+ title: { ...defaultStyles2.title, ...overrides == null ? void 0 : overrides.title },
922
+ closeButton: { ...defaultStyles2.closeButton, ...overrides == null ? void 0 : overrides.closeButton },
923
+ body: { ...defaultStyles2.body, ...overrides == null ? void 0 : overrides.body },
924
+ banner: { ...defaultStyles2.banner, ...overrides == null ? void 0 : overrides.banner },
925
+ bannerIcon: { ...defaultStyles2.bannerIcon, ...overrides == null ? void 0 : overrides.bannerIcon },
926
+ bannerTitle: { ...defaultStyles2.bannerTitle, ...overrides == null ? void 0 : overrides.bannerTitle },
927
+ bannerText: { ...defaultStyles2.bannerText, ...overrides == null ? void 0 : overrides.bannerText },
928
+ locationSection: { ...defaultStyles2.locationSection, ...overrides == null ? void 0 : overrides.locationSection },
929
+ locationLabelRow: { ...defaultStyles2.locationLabelRow, ...overrides == null ? void 0 : overrides.locationLabelRow },
930
+ locationLabel: { ...defaultStyles2.locationLabel, ...overrides == null ? void 0 : overrides.locationLabel },
931
+ locationBadge: { ...defaultStyles2.locationBadge, ...overrides == null ? void 0 : overrides.locationBadge },
932
+ locationSubtitle: { ...defaultStyles2.locationSubtitle, ...overrides == null ? void 0 : overrides.locationSubtitle },
933
+ locationTrigger: { ...defaultStyles2.locationTrigger, ...overrides == null ? void 0 : overrides.locationTrigger },
934
+ locationTriggerText: {
935
+ ...defaultStyles2.locationTriggerText,
936
+ ...overrides == null ? void 0 : overrides.locationTriggerText
937
+ },
938
+ popoverContent: { ...defaultStyles2.popoverContent, ...overrides == null ? void 0 : overrides.popoverContent },
939
+ groupHeader: { ...defaultStyles2.groupHeader, ...overrides == null ? void 0 : overrides.groupHeader },
940
+ optionRow: { ...defaultStyles2.optionRow, ...overrides == null ? void 0 : overrides.optionRow },
941
+ optionLabel: { ...defaultStyles2.optionLabel, ...overrides == null ? void 0 : overrides.optionLabel },
942
+ selectedBanner: { ...defaultStyles2.selectedBanner, ...overrides == null ? void 0 : overrides.selectedBanner },
943
+ selectedBannerIcon: { ...defaultStyles2.selectedBannerIcon, ...overrides == null ? void 0 : overrides.selectedBannerIcon },
944
+ selectedBannerText: {
945
+ ...defaultStyles2.selectedBannerText,
946
+ ...overrides == null ? void 0 : overrides.selectedBannerText
947
+ },
948
+ hardConstraintsSection: {
949
+ ...defaultStyles2.hardConstraintsSection,
950
+ ...overrides == null ? void 0 : overrides.hardConstraintsSection
951
+ },
952
+ hardConstraintsLabelRow: {
953
+ ...defaultStyles2.hardConstraintsLabelRow,
954
+ ...overrides == null ? void 0 : overrides.hardConstraintsLabelRow
955
+ },
956
+ hardConstraintsLabel: {
957
+ ...defaultStyles2.hardConstraintsLabel,
958
+ ...overrides == null ? void 0 : overrides.hardConstraintsLabel
959
+ },
960
+ hardConstraintsBadge: {
961
+ ...defaultStyles2.hardConstraintsBadge,
962
+ ...overrides == null ? void 0 : overrides.hardConstraintsBadge
963
+ },
964
+ hardConstraintsSubtitle: {
965
+ ...defaultStyles2.hardConstraintsSubtitle,
966
+ ...overrides == null ? void 0 : overrides.hardConstraintsSubtitle
967
+ },
968
+ hardConstraintsTrigger: {
969
+ ...defaultStyles2.hardConstraintsTrigger,
970
+ ...overrides == null ? void 0 : overrides.hardConstraintsTrigger
971
+ },
972
+ hardConstraintsTriggerText: {
973
+ ...defaultStyles2.hardConstraintsTriggerText,
974
+ ...overrides == null ? void 0 : overrides.hardConstraintsTriggerText
975
+ },
976
+ hardConstraintsPopoverContent: {
977
+ ...defaultStyles2.hardConstraintsPopoverContent,
978
+ ...overrides == null ? void 0 : overrides.hardConstraintsPopoverContent
979
+ },
980
+ hardConstraintsOptionRow: {
981
+ ...defaultStyles2.hardConstraintsOptionRow,
982
+ ...overrides == null ? void 0 : overrides.hardConstraintsOptionRow
983
+ },
984
+ hardConstraintsOptionLabel: {
985
+ ...defaultStyles2.hardConstraintsOptionLabel,
986
+ ...overrides == null ? void 0 : overrides.hardConstraintsOptionLabel
987
+ },
988
+ hardConstraintsInputsContainer: {
989
+ ...defaultStyles2.hardConstraintsInputsContainer,
990
+ ...overrides == null ? void 0 : overrides.hardConstraintsInputsContainer
991
+ },
992
+ hardConstraintsInputItem: {
993
+ ...defaultStyles2.hardConstraintsInputItem,
994
+ ...overrides == null ? void 0 : overrides.hardConstraintsInputItem
995
+ },
996
+ hardConstraintsInputLabel: {
997
+ ...defaultStyles2.hardConstraintsInputLabel,
998
+ ...overrides == null ? void 0 : overrides.hardConstraintsInputLabel
999
+ },
1000
+ hardConstraintsInputField: {
1001
+ ...defaultStyles2.hardConstraintsInputField,
1002
+ ...overrides == null ? void 0 : overrides.hardConstraintsInputField
1003
+ },
1004
+ optimizationSection: {
1005
+ ...defaultStyles2.optimizationSection,
1006
+ ...overrides == null ? void 0 : overrides.optimizationSection
1007
+ },
1008
+ optimizationLabelRow: {
1009
+ ...defaultStyles2.optimizationLabelRow,
1010
+ ...overrides == null ? void 0 : overrides.optimizationLabelRow
1011
+ },
1012
+ optimizationLabel: {
1013
+ ...defaultStyles2.optimizationLabel,
1014
+ ...overrides == null ? void 0 : overrides.optimizationLabel
1015
+ },
1016
+ optimizationBadge: {
1017
+ ...defaultStyles2.optimizationBadge,
1018
+ ...overrides == null ? void 0 : overrides.optimizationBadge
1019
+ },
1020
+ optimizationSubtitle: {
1021
+ ...defaultStyles2.optimizationSubtitle,
1022
+ ...overrides == null ? void 0 : overrides.optimizationSubtitle
1023
+ },
1024
+ optimizationTrigger: {
1025
+ ...defaultStyles2.optimizationTrigger,
1026
+ ...overrides == null ? void 0 : overrides.optimizationTrigger
1027
+ },
1028
+ optimizationTriggerText: {
1029
+ ...defaultStyles2.optimizationTriggerText,
1030
+ ...overrides == null ? void 0 : overrides.optimizationTriggerText
1031
+ },
1032
+ optimizationPopoverContent: {
1033
+ ...defaultStyles2.optimizationPopoverContent,
1034
+ ...overrides == null ? void 0 : overrides.optimizationPopoverContent
1035
+ },
1036
+ optimizationGroupHeader: {
1037
+ ...defaultStyles2.optimizationGroupHeader,
1038
+ ...overrides == null ? void 0 : overrides.optimizationGroupHeader
1039
+ },
1040
+ optimizationOptionRow: {
1041
+ ...defaultStyles2.optimizationOptionRow,
1042
+ ...overrides == null ? void 0 : overrides.optimizationOptionRow
1043
+ },
1044
+ optimizationOptionLabel: {
1045
+ ...defaultStyles2.optimizationOptionLabel,
1046
+ ...overrides == null ? void 0 : overrides.optimizationOptionLabel
1047
+ },
1048
+ optimizationOptionHelp: {
1049
+ ...defaultStyles2.optimizationOptionHelp,
1050
+ ...overrides == null ? void 0 : overrides.optimizationOptionHelp
1051
+ },
1052
+ optimizationInputsContainer: {
1053
+ ...defaultStyles2.optimizationInputsContainer,
1054
+ ...overrides == null ? void 0 : overrides.optimizationInputsContainer
1055
+ },
1056
+ optimizationInputItem: {
1057
+ ...defaultStyles2.optimizationInputItem,
1058
+ ...overrides == null ? void 0 : overrides.optimizationInputItem
1059
+ },
1060
+ optimizationInputLabel: {
1061
+ ...defaultStyles2.optimizationInputLabel,
1062
+ ...overrides == null ? void 0 : overrides.optimizationInputLabel
1063
+ },
1064
+ optimizationInputField: {
1065
+ ...defaultStyles2.optimizationInputField,
1066
+ ...overrides == null ? void 0 : overrides.optimizationInputField
1067
+ },
1068
+ optimizationSuffix: {
1069
+ ...defaultStyles2.optimizationSuffix,
1070
+ ...overrides == null ? void 0 : overrides.optimizationSuffix
1071
+ },
1072
+ optimizationDivider: {
1073
+ ...defaultStyles2.optimizationDivider,
1074
+ ...overrides == null ? void 0 : overrides.optimizationDivider
1075
+ },
1076
+ optimizationSummary: {
1077
+ ...defaultStyles2.optimizationSummary,
1078
+ ...overrides == null ? void 0 : overrides.optimizationSummary
1079
+ },
1080
+ creatingBody: {
1081
+ ...defaultStyles2.creatingBody,
1082
+ ...overrides == null ? void 0 : overrides.creatingBody
1083
+ },
1084
+ stepsContainer: {
1085
+ ...defaultStyles2.stepsContainer,
1086
+ ...overrides == null ? void 0 : overrides.stepsContainer
1087
+ },
1088
+ stepsList: {
1089
+ ...defaultStyles2.stepsList,
1090
+ ...overrides == null ? void 0 : overrides.stepsList
1091
+ },
1092
+ stepRow: {
1093
+ ...defaultStyles2.stepRow,
1094
+ ...overrides == null ? void 0 : overrides.stepRow
1095
+ },
1096
+ stepIcon: {
1097
+ ...defaultStyles2.stepIcon,
1098
+ ...overrides == null ? void 0 : overrides.stepIcon
1099
+ },
1100
+ stepIconActive: {
1101
+ ...defaultStyles2.stepIconActive,
1102
+ ...overrides == null ? void 0 : overrides.stepIconActive
1103
+ },
1104
+ stepIconDone: {
1105
+ ...defaultStyles2.stepIconDone,
1106
+ ...overrides == null ? void 0 : overrides.stepIconDone
1107
+ },
1108
+ stepIconPending: {
1109
+ ...defaultStyles2.stepIconPending,
1110
+ ...overrides == null ? void 0 : overrides.stepIconPending
1111
+ },
1112
+ stepIconFailed: {
1113
+ ...defaultStyles2.stepIconFailed,
1114
+ ...overrides == null ? void 0 : overrides.stepIconFailed
1115
+ },
1116
+ stepTitle: {
1117
+ ...defaultStyles2.stepTitle,
1118
+ ...overrides == null ? void 0 : overrides.stepTitle
1119
+ },
1120
+ stepTitleActive: {
1121
+ ...defaultStyles2.stepTitleActive,
1122
+ ...overrides == null ? void 0 : overrides.stepTitleActive
1123
+ },
1124
+ stepTitleDone: {
1125
+ ...defaultStyles2.stepTitleDone,
1126
+ ...overrides == null ? void 0 : overrides.stepTitleDone
1127
+ },
1128
+ stepTitlePending: {
1129
+ ...defaultStyles2.stepTitlePending,
1130
+ ...overrides == null ? void 0 : overrides.stepTitlePending
1131
+ },
1132
+ stepTitleFailed: {
1133
+ ...defaultStyles2.stepTitleFailed,
1134
+ ...overrides == null ? void 0 : overrides.stepTitleFailed
1135
+ },
1136
+ stepSubtitle: {
1137
+ ...defaultStyles2.stepSubtitle,
1138
+ ...overrides == null ? void 0 : overrides.stepSubtitle
1139
+ },
1140
+ violationPanel: {
1141
+ ...defaultStyles2.violationPanel,
1142
+ ...overrides == null ? void 0 : overrides.violationPanel
1143
+ },
1144
+ violationHeaderRow: {
1145
+ ...defaultStyles2.violationHeaderRow,
1146
+ ...overrides == null ? void 0 : overrides.violationHeaderRow
1147
+ },
1148
+ violationHeader: {
1149
+ ...defaultStyles2.violationHeader,
1150
+ ...overrides == null ? void 0 : overrides.violationHeader
1151
+ },
1152
+ violationIcon: {
1153
+ ...defaultStyles2.violationIcon,
1154
+ ...overrides == null ? void 0 : overrides.violationIcon
1155
+ },
1156
+ violationTitle: {
1157
+ ...defaultStyles2.violationTitle,
1158
+ ...overrides == null ? void 0 : overrides.violationTitle
1159
+ },
1160
+ violationSubtitle: {
1161
+ ...defaultStyles2.violationSubtitle,
1162
+ ...overrides == null ? void 0 : overrides.violationSubtitle
1163
+ },
1164
+ violationToggleButton: {
1165
+ ...defaultStyles2.violationToggleButton,
1166
+ ...overrides == null ? void 0 : overrides.violationToggleButton
1167
+ },
1168
+ violationToggleIcon: {
1169
+ ...defaultStyles2.violationToggleIcon,
1170
+ ...overrides == null ? void 0 : overrides.violationToggleIcon
1171
+ },
1172
+ violationContent: {
1173
+ ...defaultStyles2.violationContent,
1174
+ ...overrides == null ? void 0 : overrides.violationContent
1175
+ },
1176
+ violationItem: {
1177
+ ...defaultStyles2.violationItem,
1178
+ ...overrides == null ? void 0 : overrides.violationItem
1179
+ },
1180
+ violationItemTitle: {
1181
+ ...defaultStyles2.violationItemTitle,
1182
+ ...overrides == null ? void 0 : overrides.violationItemTitle
1183
+ },
1184
+ violationItemDetailRow: {
1185
+ ...defaultStyles2.violationItemDetailRow,
1186
+ ...overrides == null ? void 0 : overrides.violationItemDetailRow
1187
+ },
1188
+ violationItemDetail: {
1189
+ ...defaultStyles2.violationItemDetail,
1190
+ ...overrides == null ? void 0 : overrides.violationItemDetail
1191
+ },
1192
+ violationBullet: {
1193
+ ...defaultStyles2.violationBullet,
1194
+ ...overrides == null ? void 0 : overrides.violationBullet
1195
+ },
1196
+ recommendationsBox: {
1197
+ ...defaultStyles2.recommendationsBox,
1198
+ ...overrides == null ? void 0 : overrides.recommendationsBox
1199
+ },
1200
+ recommendationsTitle: {
1201
+ ...defaultStyles2.recommendationsTitle,
1202
+ ...overrides == null ? void 0 : overrides.recommendationsTitle
1203
+ },
1204
+ recommendationsList: {
1205
+ ...defaultStyles2.recommendationsList,
1206
+ ...overrides == null ? void 0 : overrides.recommendationsList
1207
+ },
1208
+ recommendationsItem: {
1209
+ ...defaultStyles2.recommendationsItem,
1210
+ ...overrides == null ? void 0 : overrides.recommendationsItem
1211
+ },
1212
+ recommendationsBullet: {
1213
+ ...defaultStyles2.recommendationsBullet,
1214
+ ...overrides == null ? void 0 : overrides.recommendationsBullet
1215
+ },
1216
+ recommendationsToggle: {
1217
+ ...defaultStyles2.recommendationsToggle,
1218
+ ...overrides == null ? void 0 : overrides.recommendationsToggle
1219
+ },
1220
+ failedFooter: {
1221
+ ...defaultStyles2.failedFooter,
1222
+ ...overrides == null ? void 0 : overrides.failedFooter
1223
+ },
1224
+ failedPrimaryButton: {
1225
+ ...defaultStyles2.failedPrimaryButton,
1226
+ ...overrides == null ? void 0 : overrides.failedPrimaryButton
1227
+ },
1228
+ failedSecondaryButton: {
1229
+ ...defaultStyles2.failedSecondaryButton,
1230
+ ...overrides == null ? void 0 : overrides.failedSecondaryButton
1231
+ },
1232
+ footer: { ...defaultStyles2.footer, ...overrides == null ? void 0 : overrides.footer },
1233
+ cancelButton: { ...defaultStyles2.cancelButton, ...overrides == null ? void 0 : overrides.cancelButton },
1234
+ primaryButton: { ...defaultStyles2.primaryButton, ...overrides == null ? void 0 : overrides.primaryButton },
1235
+ violatedConstraintsSecondaryButton: {
1236
+ ...defaultStyles2.violatedConstraintsSecondaryButton,
1237
+ ...overrides == null ? void 0 : overrides.violatedConstraintsSecondaryButton
1238
+ }
1239
+ });
1240
+
1241
+ // src/buildSchedulePayload.ts
1242
+ var UI_TO_BACKEND_RULE_ID = {
1243
+ max_weekly_hours: "max-weekly-hours",
1244
+ max_daily_hours: "max-daily-hours",
1245
+ min_rest_between_shifts: "min-rest-between-shifts",
1246
+ max_work_days_per_week: "max-work-days-per-week",
1247
+ fair_hour_distribution: "fair-hour-distribution",
1248
+ minimize_overtime: "overtime-balance",
1249
+ cost_to_sales_ratio: "labor-cost-optimization",
1250
+ maximize_sales: "maximize-sales-performance",
1251
+ staff_preferences: "staff-open-shift-preferences"
1252
+ };
1253
+ var BACKEND_TO_UI_RULE_ID = Object.fromEntries(
1254
+ Object.entries(UI_TO_BACKEND_RULE_ID).map(([ui, backend]) => [backend, ui])
1255
+ );
1256
+ function toBackendRuleId(uiOptionId) {
1257
+ return UI_TO_BACKEND_RULE_ID[uiOptionId];
1258
+ }
1259
+ function buildParametersForRule(backendRuleId, constraintValues, _optimizationValues) {
1260
+ var _a, _b, _c, _d;
1261
+ const params = {};
1262
+ switch (backendRuleId) {
1263
+ case "max-weekly-hours": {
1264
+ const value = (_a = constraintValues["max_weekly_hours"]) == null ? void 0 : _a.trim();
1265
+ if (value) {
1266
+ const limitMinutes = Number(value) * 60;
1267
+ if (Number.isFinite(limitMinutes) && limitMinutes >= 1) {
1268
+ params.limitMinutes = limitMinutes;
1269
+ }
1270
+ }
1271
+ break;
1272
+ }
1273
+ case "max-daily-hours": {
1274
+ const value = (_b = constraintValues["max_daily_hours"]) == null ? void 0 : _b.trim();
1275
+ if (value) {
1276
+ const limitMinutes = Number(value) * 60;
1277
+ if (Number.isFinite(limitMinutes) && limitMinutes >= 1) {
1278
+ params.limitMinutes = limitMinutes;
1279
+ }
1280
+ }
1281
+ break;
1282
+ }
1283
+ case "min-rest-between-shifts": {
1284
+ const value = (_c = constraintValues["min_rest_between_shifts"]) == null ? void 0 : _c.trim();
1285
+ if (value) {
1286
+ const minGapMinutes = Number(value) * 60;
1287
+ if (Number.isFinite(minGapMinutes) && minGapMinutes >= 1) {
1288
+ params.minGapMinutes = minGapMinutes;
1289
+ }
1290
+ }
1291
+ break;
1292
+ }
1293
+ case "max-work-days-per-week": {
1294
+ const value = (_d = constraintValues["max_work_days_per_week"]) == null ? void 0 : _d.trim();
1295
+ if (value) {
1296
+ const maxWorkDays = Number(value);
1297
+ if (Number.isFinite(maxWorkDays) && maxWorkDays >= 1 && maxWorkDays <= 6) {
1298
+ params.limitDays = maxWorkDays;
1299
+ }
1300
+ }
1301
+ break;
1302
+ }
1303
+ default:
1304
+ break;
1305
+ }
1306
+ return params;
1307
+ }
1308
+ function hasAnyParameterOverrides(selectedConstraintIds, constraintValues, selectedOptimizationIds, optimizationValues) {
1309
+ var _a, _b, _c, _d, _e, _f;
1310
+ for (const id of selectedConstraintIds) {
1311
+ const value = (_a = constraintValues[id]) == null ? void 0 : _a.trim();
1312
+ if (value && Number.isFinite(Number(value))) return true;
1313
+ }
1314
+ for (const id of selectedOptimizationIds) {
1315
+ const weight = (_b = optimizationValues[`${id}_weightPoints`]) == null ? void 0 : _b.trim();
1316
+ if (weight && Number.isFinite(Number(weight))) return true;
1317
+ if (id === "fair_hour_distribution") {
1318
+ if (((_c = optimizationValues["fair_hour_distribution_balanceTarget"]) == null ? void 0 : _c.trim()) || ((_d = optimizationValues["fair_hour_distribution_period"]) == null ? void 0 : _d.trim())) {
1319
+ return true;
1320
+ }
1321
+ } else if (id === "minimize_overtime") {
1322
+ if (((_e = optimizationValues["minimize_overtime_thresholdMinutes"]) == null ? void 0 : _e.trim()) || ((_f = optimizationValues["minimize_overtime_period"]) == null ? void 0 : _f.trim())) return true;
1323
+ } else if (id === "cost_to_sales_ratio" || id === "maximize_sales") {
1324
+ return true;
1325
+ }
1326
+ }
1327
+ return false;
1328
+ }
1329
+ function buildRulesPayload(selectedConstraintIds, constraintValues, selectedOptimizationIds, optimizationValues) {
1330
+ const allSelectedRuleIds = [
1331
+ ...selectedConstraintIds.map(toBackendRuleId),
1332
+ ...selectedOptimizationIds.map(toBackendRuleId)
1333
+ ].filter((id) => Boolean(id));
1334
+ if (allSelectedRuleIds.length === 0) {
1335
+ return {};
1336
+ }
1337
+ const hasOverrides = hasAnyParameterOverrides(
1338
+ selectedConstraintIds,
1339
+ constraintValues,
1340
+ selectedOptimizationIds,
1341
+ optimizationValues
1342
+ );
1343
+ if (!hasOverrides) {
1344
+ return { ruleIds: allSelectedRuleIds };
1345
+ }
1346
+ const ruleOverrides = allSelectedRuleIds.map((ruleId) => {
1347
+ var _a;
1348
+ const params = buildParametersForRule(ruleId, constraintValues, optimizationValues);
1349
+ const uiId = BACKEND_TO_UI_RULE_ID[ruleId];
1350
+ const weightRaw = uiId ? (_a = optimizationValues[`${uiId}_weightPoints`]) == null ? void 0 : _a.trim() : void 0;
1351
+ const weightPoints = weightRaw ? Number(weightRaw) : void 0;
1352
+ if (weightPoints && Number.isFinite(weightPoints) && weightPoints >= 1) {
1353
+ params.weightPoints = weightPoints;
1354
+ }
1355
+ return {
1356
+ ruleId,
1357
+ ...Object.keys(params).length > 0 ? { parameters: params } : {}
1358
+ };
1359
+ });
1360
+ return { ruleIds: allSelectedRuleIds, ruleOverrides };
1361
+ }
1362
+ function toApiShift(shift, includeEmployeePreferences) {
1363
+ var _a, _b;
1364
+ const startDateTime = "startDateTime" in shift ? shift.startDateTime : shift.startTime;
1365
+ const endDateTime = "endDateTime" in shift ? shift.endDateTime : shift.endTime;
1366
+ return {
1367
+ id: shift.id,
1368
+ startDateTime,
1369
+ endDateTime,
1370
+ ...shift.employeeId ? { employeeId: String(shift.employeeId) } : {},
1371
+ requiredPosition: (_a = shift.requiredPosition) != null ? _a : void 0,
1372
+ requiredCount: (_b = shift.requiredCount) != null ? _b : 1,
1373
+ location: shift.location ? {
1374
+ id: String(shift.location.id),
1375
+ timezone: "timezone" in shift.location ? shift.location.timezone : void 0,
1376
+ tags: "tags" in shift.location ? shift.location.tags : void 0
1377
+ } : void 0,
1378
+ ...includeEmployeePreferences && shift.employeePreferences ? {
1379
+ employeePreferences: shift.employeePreferences.map((p) => ({
1380
+ employeeId: p.employeeId,
1381
+ level: p.level
1382
+ }))
1383
+ } : {}
1384
+ };
1385
+ }
1386
+ function toApiEmployee(employee) {
1387
+ var _a, _b, _c;
1388
+ return {
1389
+ id: String(employee.id),
1390
+ name: (_a = employee.name) != null ? _a : void 0,
1391
+ position: (_b = employee.position) != null ? _b : void 0,
1392
+ locationIds: (_c = employee.locationIds) != null ? _c : void 0,
1393
+ properties: employee.properties ? employee.properties : void 0
1394
+ };
1395
+ }
1396
+ function toApiLocation(location) {
1397
+ var _a, _b;
1398
+ return {
1399
+ id: String(location.id),
1400
+ timezone: (_a = location.timezone) != null ? _a : void 0,
1401
+ jurisdiction: (_b = location.jurisdiction) != null ? _b : void 0,
1402
+ tags: "tags" in location ? location.tags : void 0
1403
+ };
1404
+ }
1405
+ function buildSchedulePayload(input) {
1406
+ const {
1407
+ employees,
1408
+ openShifts,
1409
+ timeOffs,
1410
+ selectedLocationIds,
1411
+ jurisdictions,
1412
+ selectedConstraintIds,
1413
+ constraintValues,
1414
+ selectedOptimizationIds,
1415
+ optimizationValues
1416
+ } = input;
1417
+ const locationsMap = /* @__PURE__ */ new Map();
1418
+ for (const j of jurisdictions) {
1419
+ for (const loc of j.locations) {
1420
+ locationsMap.set(loc.id, loc);
1421
+ }
1422
+ }
1423
+ const selectedLocations = selectedLocationIds.map((id) => locationsMap.get(id)).filter((loc) => Boolean(loc));
1424
+ const rules = buildRulesPayload(
1425
+ selectedConstraintIds,
1426
+ constraintValues,
1427
+ selectedOptimizationIds,
1428
+ optimizationValues
1429
+ );
1430
+ const includeEmployeePreferences = selectedOptimizationIds.includes("staff_preferences");
1431
+ return {
1432
+ employees: employees.map(toApiEmployee),
1433
+ shifts: openShifts.map((shift) => toApiShift(shift, includeEmployeePreferences)),
1434
+ locations: selectedLocations.map(toApiLocation),
1435
+ ...timeOffs && timeOffs.length > 0 ? { timeOffs } : {},
1436
+ ...rules
1437
+ };
1438
+ }
1439
+
1440
+ // src/api/solveSchedule.ts
1441
+ var import_axios = __toESM(require("axios"), 1);
1442
+ var axiosInstance = import_axios.default.create({
1443
+ headers: { "Content-Type": "application/json" }
1444
+ });
1445
+ async function solveSchedule(baseURL, payload) {
1446
+ const cleanBaseUrl = baseURL.replace(/\/$/, "");
1447
+ const response = await axiosInstance.post(`${cleanBaseUrl}/api/schedule/solve`, payload);
1448
+ return response.data;
1449
+ }
1450
+
1451
+ // src/utils/violationMessages.ts
1452
+ var SYSTEM_CONSTRAINT_MESSAGES = {
1453
+ "system-unassigned-Hard": {
1454
+ title: "Not enough eligible staff to cover all shifts",
1455
+ detail: "Some open shifts require more team members with the required position than are currently available."
1456
+ },
1457
+ "system-position-Hard": {
1458
+ title: "Required position not matched",
1459
+ detail: "Some open shifts require a position that isn't assigned to the available team members."
1460
+ },
1461
+ "system-location-Hard": {
1462
+ title: "Location assignment mismatch",
1463
+ detail: "Some open shifts are set for a location that isn't assigned to the available team members."
1464
+ },
1465
+ "system-employee-unavailable-Hard": {
1466
+ title: "No eligible staff available for shift",
1467
+ detail: "Some open shifts don't have any remaining eligible team members available at that time."
1468
+ },
1469
+ "system-employee-unavailable-time-Hard": {
1470
+ title: "Unavailable time",
1471
+ detail: "Unavailable time"
1472
+ },
1473
+ "system-employee-available-time-Hard": {
1474
+ title: "Outside available time",
1475
+ detail: "Outside available time"
1476
+ },
1477
+ "system-employee-time-off-Hard": {
1478
+ title: "Time off prevents assignment",
1479
+ detail: "Some open shifts overlap with approved time off for the remaining eligible team members."
1480
+ }
1481
+ };
1482
+ var RULE_ID_MESSAGES = {
1483
+ "max-weekly-hours": {
1484
+ title: "Maximum weekly hours exceeded",
1485
+ detail: "Some team members would exceed weekly hour limits if all open shifts are assigned."
1486
+ },
1487
+ "max-daily-hours": {
1488
+ title: "Maximum daily hours exceeded",
1489
+ detail: "Some team members would exceed daily hour limits if all open shifts are assigned."
1490
+ },
1491
+ "min-rest-between-shifts": {
1492
+ title: "Minimum rest between shifts",
1493
+ detail: "Some team members would not receive the required rest time if all open shifts are assigned."
1494
+ },
1495
+ "min-days-off-per-week": {
1496
+ title: "Maximum work days per week exceeded",
1497
+ detail: "Some team members would exceed the allowed work days this week if all open shifts are assigned."
1498
+ },
1499
+ "fair-hour-distribution": {
1500
+ title: "Work distribution not balanced",
1501
+ detail: "Work distribution not balanced"
1502
+ },
1503
+ "overtime-balance": {
1504
+ title: "Overtime balance rule violated",
1505
+ detail: "Overtime balance rule violated"
1506
+ },
1507
+ "manager-cashier-ratio": {
1508
+ title: "Staffing ratio violated",
1509
+ detail: "Staffing ratio violated"
1510
+ },
1511
+ "min-staffing": {
1512
+ title: "Minimum staffing not met",
1513
+ detail: "Minimum staffing not met"
1514
+ },
1515
+ "shift-duration-limits": {
1516
+ title: "Shift duration outside allowed range",
1517
+ detail: "Shift duration outside allowed range"
1518
+ },
1519
+ "max-consecutive-days": {
1520
+ title: "Shift sequence rule violated",
1521
+ detail: "Shift sequence rule violated"
1522
+ },
1523
+ "some-transactional-rule": {
1524
+ title: "Policy rule violated",
1525
+ detail: "Policy rule violated"
1526
+ }
1527
+ };
1528
+ var ARCHETYPE_FALLBACK_MESSAGES = {
1529
+ "Accumulator violation (HARD)": {
1530
+ title: "Hours limit exceeded",
1531
+ detail: "Hours limit exceeded"
1532
+ },
1533
+ "Spacer violation (HARD)": {
1534
+ title: "Rest period not met",
1535
+ detail: "Rest period not met"
1536
+ },
1537
+ "Spacer periodic violation (HARD)": {
1538
+ title: "Required rest period not met",
1539
+ detail: "Required rest period not met"
1540
+ },
1541
+ "Composition violation (HARD)": {
1542
+ title: "Staffing ratio violated",
1543
+ detail: "Staffing ratio violated"
1544
+ },
1545
+ "Transactional violation (HARD)": {
1546
+ title: "Policy rule violated",
1547
+ detail: "Policy rule violated"
1548
+ },
1549
+ "Balancer violation (HARD)": {
1550
+ title: "Work distribution not balanced",
1551
+ detail: "Work distribution not balanced"
1552
+ },
1553
+ "Coverage violation (HARD)": {
1554
+ title: "Minimum staffing not met",
1555
+ detail: "Minimum staffing not met"
1556
+ },
1557
+ "Sizing violation (HARD)": {
1558
+ title: "Shift duration outside allowed range",
1559
+ detail: "Shift duration outside allowed range"
1560
+ },
1561
+ "Sequencer violation (HARD)": {
1562
+ title: "Shift sequence rule violated",
1563
+ detail: "Shift sequence rule violated"
1564
+ },
1565
+ "Overtime balance violation (HARD)": {
1566
+ title: "Overtime balance rule violated",
1567
+ detail: "Overtime balance rule violated"
1568
+ }
1569
+ };
1570
+ var FALLBACK_MESSAGE = {
1571
+ title: "Rule violated",
1572
+ detail: "Rule violated"
1573
+ };
1574
+ function getSystemConstraintMessage(constraintName, description) {
1575
+ if (constraintName && constraintName in SYSTEM_CONSTRAINT_MESSAGES) {
1576
+ return SYSTEM_CONSTRAINT_MESSAGES[constraintName];
1577
+ }
1578
+ if (description == null ? void 0 : description.trim()) {
1579
+ return { title: description, detail: description };
1580
+ }
1581
+ return FALLBACK_MESSAGE;
1582
+ }
1583
+ function getRuleBasedViolationMessage(ruleId, constraintName, description) {
1584
+ if (ruleId && ruleId in RULE_ID_MESSAGES) {
1585
+ return RULE_ID_MESSAGES[ruleId];
1586
+ }
1587
+ if (constraintName && constraintName in ARCHETYPE_FALLBACK_MESSAGES) {
1588
+ return ARCHETYPE_FALLBACK_MESSAGES[constraintName];
1589
+ }
1590
+ if (description == null ? void 0 : description.trim()) {
1591
+ return { title: description, detail: description };
1592
+ }
1593
+ return FALLBACK_MESSAGE;
1594
+ }
1595
+
1596
+ // src/utils/mapViolationsToResult.ts
1597
+ function mapViolationsToResult(violations, summary) {
1598
+ const hardViolations = violations.filter((v) => v.isHardViolation === true);
1599
+ const seenTitles = /* @__PURE__ */ new Set();
1600
+ const violatedConstraints = [];
1601
+ for (const v of hardViolations) {
1602
+ const hasRuleId = v.ruleId != null && v.ruleId !== void 0 && String(v.ruleId).trim() !== "";
1603
+ const msg = hasRuleId ? getRuleBasedViolationMessage(
1604
+ v.ruleId,
1605
+ v.constraintName,
1606
+ v.description
1607
+ ) : getSystemConstraintMessage(v.constraintName, v.description);
1608
+ if (!seenTitles.has(msg.title)) {
1609
+ seenTitles.add(msg.title);
1610
+ violatedConstraints.push(msg);
1611
+ }
1612
+ }
1613
+ const result = {
1614
+ violatedConstraints,
1615
+ recommendedFixes: []
1616
+ };
1617
+ if (violatedConstraints.length === 0 && (summary == null ? void 0 : summary.trim())) {
1618
+ result.violatedConstraints = [
1619
+ {
1620
+ title: "Schedule could not be created",
1621
+ detail: summary
1622
+ }
1623
+ ];
1624
+ } else if (violatedConstraints.length === 0) {
1625
+ result.violatedConstraints = [
1626
+ {
1627
+ title: "Schedule could not be created",
1628
+ detail: "Please adjust constraints and try again."
1629
+ }
1630
+ ];
1631
+ }
1632
+ return result;
1633
+ }
1634
+
1635
+ // src/ViolatedConstraintsPanel.tsx
1636
+ var import_react = require("react");
1637
+ var import_react2 = require("@chakra-ui/react");
1638
+ var import_axios2 = __toESM(require("axios"), 1);
1639
+ var import_jsx_runtime2 = require("react/jsx-runtime");
1640
+ var DEFAULT_TITLE = "Schedule can't be created";
1641
+ var DEFAULT_SUBTITLE = "Some required rules aren't being met. Review the issues below to continue.";
1642
+ function ViolatedConstraintsPanel({
1643
+ violatedConstraints,
1644
+ title = DEFAULT_TITLE,
1645
+ subtitle = DEFAULT_SUBTITLE,
1646
+ showSecondaryButton = false,
1647
+ secondaryButtonTitle,
1648
+ onSecondaryButtonClick,
1649
+ generateRecommendationsURLAndHeaders,
1650
+ styles: stylesProp,
1651
+ styleOverrides
1652
+ }) {
1653
+ const [showRecommendations, setShowRecommendations] = (0, import_react.useState)(false);
1654
+ const [isExpanded, setIsExpanded] = (0, import_react.useState)(true);
1655
+ const [recommendations, setRecommendations] = (0, import_react.useState)(null);
1656
+ const [isLoadingRecommendations, setIsLoadingRecommendations] = (0, import_react.useState)(false);
1657
+ const styles = (0, import_react.useMemo)(() => {
1658
+ if (stylesProp) return stylesProp;
1659
+ return buildStyles(defaultStyles, styleOverrides);
1660
+ }, [stylesProp, styleOverrides]);
1661
+ const canFetchRecommendations = Boolean(generateRecommendationsURLAndHeaders) && Boolean(violatedConstraints.recommendationPayload);
1662
+ const hasPreFetchedFixes = violatedConstraints.recommendedFixes.length > 0;
1663
+ const showRecommendationsButton = canFetchRecommendations || hasPreFetchedFixes;
1664
+ const displayRecommendations = recommendations !== null ? recommendations : violatedConstraints.recommendedFixes;
1665
+ const hasRecommendations = displayRecommendations.length > 0;
1666
+ const handleToggleRecommendations = (0, import_react.useCallback)(async () => {
1667
+ var _a, _b;
1668
+ if (showRecommendations) {
1669
+ setShowRecommendations(false);
1670
+ return;
1671
+ }
1672
+ setShowRecommendations(true);
1673
+ if (recommendations !== null) {
1674
+ return;
1675
+ }
1676
+ if (!canFetchRecommendations) {
1677
+ return;
1678
+ }
1679
+ const payload = violatedConstraints.recommendationPayload;
1680
+ setIsLoadingRecommendations(true);
1681
+ try {
1682
+ const recResponse = await import_axios2.default.post(
1683
+ generateRecommendationsURLAndHeaders.url,
1684
+ payload,
1685
+ {
1686
+ headers: {
1687
+ "Content-Type": "application/json",
1688
+ ...generateRecommendationsURLAndHeaders.headers
1689
+ }
1690
+ }
1691
+ );
1692
+ const data = (_b = (_a = recResponse.data) == null ? void 0 : _a.data) != null ? _b : recResponse.data;
1693
+ if (data) {
1694
+ setRecommendations(data.map((r) => r.recommendation));
1695
+ } else {
1696
+ setRecommendations([]);
1697
+ }
1698
+ } catch (recErr) {
1699
+ console.error("[ViolatedConstraintsPanel] failed to fetch recommendations:", recErr);
1700
+ setRecommendations([]);
1701
+ } finally {
1702
+ setIsLoadingRecommendations(false);
1703
+ }
1704
+ }, [
1705
+ showRecommendations,
1706
+ recommendations,
1707
+ canFetchRecommendations,
1708
+ violatedConstraints.recommendationPayload,
1709
+ generateRecommendationsURLAndHeaders
1710
+ ]);
1711
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react2.Box, { sx: styles.violationPanel, children: [
1712
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react2.HStack, { sx: styles.violationHeaderRow, children: [
1713
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react2.HStack, { sx: styles.violationHeader, children: [
1714
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react2.Box, { sx: styles.violationIcon, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(WarningIcon, {}) }),
1715
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react2.Box, { children: [
1716
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react2.Text, { sx: styles.violationTitle, children: title }),
1717
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react2.Text, { sx: styles.violationSubtitle, children: subtitle })
1718
+ ] })
1719
+ ] }),
1720
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1721
+ import_react2.IconButton,
1722
+ {
1723
+ "aria-label": isExpanded ? "Collapse" : "Expand",
1724
+ variant: "ghost",
1725
+ size: "sm",
1726
+ icon: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1727
+ import_react2.Box,
1728
+ {
1729
+ sx: styles.violationToggleIcon,
1730
+ transform: isExpanded ? "rotate(180deg)" : "rotate(0deg)",
1731
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ChevronDownIcon, {})
1732
+ }
1733
+ ),
1734
+ onClick: () => setIsExpanded((prev) => !prev),
1735
+ sx: styles.violationToggleButton
1736
+ }
1737
+ )
1738
+ ] }),
1739
+ isExpanded ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react2.Stack, { spacing: "8px", sx: styles.violationContent, children: [
1740
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react2.Stack, { spacing: "8px", children: violatedConstraints.violatedConstraints.map((constraint, index) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react2.Box, { sx: styles.violationItem, children: [
1741
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react2.Text, { sx: styles.violationItemTitle, children: constraint.title }),
1742
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react2.HStack, { spacing: "6px", sx: styles.violationItemDetailRow, children: [
1743
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react2.Box, { sx: styles.violationBullet, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(DotIcon, { size: 6 }) }),
1744
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react2.Text, { sx: styles.violationItemDetail, children: constraint.detail })
1745
+ ] })
1746
+ ] }, `${constraint.title}-${index}`)) }),
1747
+ showRecommendations && hasRecommendations ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react2.Box, { sx: styles.recommendationsBox, children: [
1748
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react2.Text, { sx: styles.recommendationsTitle, children: "Recommended fixes" }),
1749
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react2.Stack, { spacing: "4px", sx: styles.recommendationsList, children: displayRecommendations.map((fix, index) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react2.HStack, { spacing: "6px", children: [
1750
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react2.Box, { sx: styles.recommendationsBullet, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(DotIcon, { size: 6 }) }),
1751
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react2.Text, { sx: styles.recommendationsItem, children: fix })
1752
+ ] }, `${fix}-${index}`)) })
1753
+ ] }) : null,
1754
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react2.HStack, { spacing: "8px", flexWrap: "wrap", children: [
1755
+ showRecommendationsButton ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1756
+ import_react2.Button,
1757
+ {
1758
+ variant: "outline",
1759
+ size: "xs",
1760
+ onClick: handleToggleRecommendations,
1761
+ isDisabled: isLoadingRecommendations,
1762
+ sx: { ...styles.recommendationsToggle, minWidth: "140px" },
1763
+ children: isLoadingRecommendations ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react2.Spinner, { size: "sm", thickness: "2px" }) : showRecommendations ? "Hide recommendations" : "Show recommendations"
1764
+ }
1765
+ ) : null,
1766
+ showSecondaryButton && secondaryButtonTitle && onSecondaryButtonClick ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1767
+ import_react2.Button,
1768
+ {
1769
+ variant: "outline",
1770
+ size: "xs",
1771
+ onClick: onSecondaryButtonClick,
1772
+ sx: { ...styles.failedSecondaryButton, ...styles.violatedConstraintsSecondaryButton },
1773
+ children: secondaryButtonTitle
1774
+ }
1775
+ ) : null
1776
+ ] })
1777
+ ] }) : null
1778
+ ] });
1779
+ }
1780
+
1781
+ // src/AutoSchedulerModal.tsx
1782
+ var import_jsx_runtime3 = require("react/jsx-runtime");
1783
+ function AutoSchedulerModal({
1784
+ baseURL,
1785
+ isOpen,
1786
+ title = "Auto-scheduling",
1787
+ bannerText,
1788
+ jurisdictions,
1789
+ openShifts,
1790
+ employees,
1791
+ timeOffs,
1792
+ locationPlaceholder = "Select locations",
1793
+ onClose,
1794
+ cancelLabel = "Cancel",
1795
+ primaryActionLabel = "Create schedule",
1796
+ onPrimaryAction: _onPrimaryAction,
1797
+ onFixManually,
1798
+ initialConfig,
1799
+ theme,
1800
+ cssVarsRoot,
1801
+ generateRecommendationsURLAndHeaders,
1802
+ onSolution
1803
+ }) {
1804
+ const baseTheme = (0, import_react4.useTheme)();
1805
+ const { chakraOverride, styleOverrides } = (0, import_react3.useMemo)(
1806
+ () => resolveThemeParts(theme),
1807
+ [theme]
1808
+ );
1809
+ const mergedTheme = (0, import_react3.useMemo)(
1810
+ () => mergeThemeWithBase(baseTheme, chakraOverride),
1811
+ [baseTheme, chakraOverride]
1812
+ );
1813
+ const styles = (0, import_react3.useMemo)(() => buildStyles(defaultStyles, styleOverrides), [styleOverrides]);
1814
+ const [selectedConstraintIds, setSelectedConstraintIds] = (0, import_react3.useState)([]);
1815
+ const [constraintValues, setConstraintValues] = (0, import_react3.useState)({});
1816
+ const [selectedOptimizationIds, setSelectedOptimizationIds] = (0, import_react3.useState)([]);
1817
+ const [optimizationValues, setOptimizationValues] = (0, import_react3.useState)({});
1818
+ const [screen, setScreen] = (0, import_react3.useState)("configure");
1819
+ const [activeStepIndex, setActiveStepIndex] = (0, import_react3.useState)(0);
1820
+ const [completedStepIndex, setCompletedStepIndex] = (0, import_react3.useState)(-1);
1821
+ const [lastFailure, setLastFailure] = (0, import_react3.useState)(null);
1822
+ const [selectedLocationIds, setSelectedLocationIds] = (0, import_react3.useState)([]);
1823
+ const timersRef = (0, import_react3.useRef)([]);
1824
+ const runIdRef = (0, import_react3.useRef)(0);
1825
+ const selectedByJurisdiction = (0, import_react3.useMemo)(
1826
+ () => jurisdictions.map((jurisdiction) => ({
1827
+ ...jurisdiction,
1828
+ selectedLocations: jurisdiction.locations.filter(
1829
+ (location) => selectedLocationIds.includes(location.id)
1830
+ )
1831
+ })).filter((jurisdiction) => jurisdiction.selectedLocations.length > 0),
1832
+ [jurisdictions, selectedLocationIds]
1833
+ );
1834
+ const selectedCount = selectedByJurisdiction.reduce(
1835
+ (total, jurisdiction) => total + jurisdiction.selectedLocations.length,
1836
+ 0
1837
+ );
1838
+ const selectedConstraints = (0, import_react3.useMemo)(
1839
+ () => HARD_CONSTRAINT_OPTIONS.filter((option) => selectedConstraintIds.includes(option.id)),
1840
+ [selectedConstraintIds]
1841
+ );
1842
+ const optimizationOptions = (0, import_react3.useMemo)(
1843
+ () => OPTIMIZATION_OPTION_GROUPS.flatMap(
1844
+ (group) => group.options.map((option) => ({
1845
+ ...option,
1846
+ groupId: group.id,
1847
+ groupName: group.name
1848
+ }))
1849
+ ),
1850
+ []
1851
+ );
1852
+ const selectedOptimizationOptions = (0, import_react3.useMemo)(
1853
+ () => optimizationOptions.filter(
1854
+ (option) => selectedOptimizationIds.includes(option.id)
1855
+ ),
1856
+ [optimizationOptions, selectedOptimizationIds]
1857
+ );
1858
+ const hasEmptyInputs = (0, import_react3.useMemo)(() => {
1859
+ const hasEmptyConstraint = selectedConstraints.some(
1860
+ (opt) => {
1861
+ var _a;
1862
+ return !((_a = constraintValues[opt.id]) == null ? void 0 : _a.trim());
1863
+ }
1864
+ );
1865
+ const hasEmptyWeight = selectedOptimizationOptions.length >= 2 && selectedOptimizationOptions.some(
1866
+ (opt) => {
1867
+ var _a;
1868
+ return !((_a = optimizationValues[`${opt.id}_weightPoints`]) == null ? void 0 : _a.trim());
1869
+ }
1870
+ );
1871
+ return hasEmptyConstraint || hasEmptyWeight;
1872
+ }, [selectedConstraints, constraintValues, selectedOptimizationOptions, optimizationValues]);
1873
+ const allocationSummary = (0, import_react3.useMemo)(() => {
1874
+ if (selectedOptimizationOptions.length === 0) return "";
1875
+ const totalWeight = selectedOptimizationOptions.reduce(
1876
+ (sum, opt) => sum + (Number(optimizationValues[`${opt.id}_weightPoints`]) || 1),
1877
+ 0
1878
+ );
1879
+ const parts = selectedOptimizationOptions.map((opt) => {
1880
+ const weight = Number(optimizationValues[`${opt.id}_weightPoints`]) || 1;
1881
+ const pct = Math.round(weight / totalWeight * 100);
1882
+ return `${opt.title} ${pct}%`;
1883
+ });
1884
+ return `Scheduling priorities: ${parts.join(", ")}.`;
1885
+ }, [selectedOptimizationOptions, optimizationValues]);
1886
+ const clearTimers = () => {
1887
+ timersRef.current.forEach((timerId) => clearTimeout(timerId));
1888
+ timersRef.current = [];
1889
+ };
1890
+ const resetProgress = () => {
1891
+ setActiveStepIndex(0);
1892
+ setCompletedStepIndex(-1);
1893
+ };
1894
+ (0, import_react3.useEffect)(() => {
1895
+ if (!isOpen) {
1896
+ clearTimers();
1897
+ setScreen("configure");
1898
+ setLastFailure(null);
1899
+ setSelectedLocationIds([]);
1900
+ setSelectedOptimizationIds([]);
1901
+ setSelectedConstraintIds([]);
1902
+ setConstraintValues({});
1903
+ setOptimizationValues({});
1904
+ resetProgress();
1905
+ }
1906
+ }, [isOpen]);
1907
+ (0, import_react3.useEffect)(() => {
1908
+ if (isOpen && initialConfig) {
1909
+ setSelectedLocationIds(initialConfig.selectedLocationIds);
1910
+ setSelectedConstraintIds(initialConfig.selectedConstraintIds);
1911
+ setConstraintValues(initialConfig.constraintValues);
1912
+ setSelectedOptimizationIds(initialConfig.selectedOptimizationIds);
1913
+ setOptimizationValues(initialConfig.optimizationValues);
1914
+ if (initialConfig.failure) {
1915
+ setLastFailure(initialConfig.failure);
1916
+ }
1917
+ setScreen("configure");
1918
+ }
1919
+ }, [isOpen, initialConfig]);
1920
+ (0, import_react3.useEffect)(() => () => clearTimers(), []);
1921
+ const stepStatusForIndex = (index) => {
1922
+ if (index <= completedStepIndex) {
1923
+ return "done";
1924
+ }
1925
+ if (index === activeStepIndex) {
1926
+ return "active";
1927
+ }
1928
+ return "pending";
1929
+ };
1930
+ const resetBeforeSubmit = () => {
1931
+ clearTimers();
1932
+ setScreen("creating");
1933
+ setLastFailure(null);
1934
+ resetProgress();
1935
+ runIdRef.current += 1;
1936
+ return runIdRef.current;
1937
+ };
1938
+ const schedule = (delayMs, action, runId) => {
1939
+ const timerId = setTimeout(() => {
1940
+ if (runIdRef.current !== runId) {
1941
+ return;
1942
+ }
1943
+ action();
1944
+ }, delayMs);
1945
+ timersRef.current.push(timerId);
1946
+ };
1947
+ const afterSuccessSteps = (runId, response) => {
1948
+ schedule(STEP_INTERVAL_MS, () => {
1949
+ if (runIdRef.current !== runId) return;
1950
+ setCompletedStepIndex(2);
1951
+ setActiveStepIndex(3);
1952
+ }, runId);
1953
+ schedule(STEP_INTERVAL_MS * 2, () => {
1954
+ if (runIdRef.current !== runId) return;
1955
+ setCompletedStepIndex(3);
1956
+ setActiveStepIndex(4);
1957
+ }, runId);
1958
+ schedule(STEP_INTERVAL_MS * 3, async () => {
1959
+ if (runIdRef.current !== runId) return;
1960
+ try {
1961
+ await onSolution(response.solution);
1962
+ setCompletedStepIndex(4);
1963
+ setActiveStepIndex(4);
1964
+ } catch (err) {
1965
+ console.error(err);
1966
+ const defaultErrorMessage = "Failed to create schedule shifts";
1967
+ const detailedErrorMessage = err instanceof Error ? err.message || defaultErrorMessage : defaultErrorMessage;
1968
+ setLastFailure({
1969
+ violatedConstraints: [
1970
+ {
1971
+ title: "Something went wrong",
1972
+ detail: detailedErrorMessage
1973
+ }
1974
+ ],
1975
+ recommendedFixes: []
1976
+ });
1977
+ setScreen("failed");
1978
+ }
1979
+ }, runId);
1980
+ };
1981
+ const handleCreateSchedule = () => {
1982
+ if (selectedCount === 0) {
1983
+ return;
1984
+ }
1985
+ const payload = buildSchedulePayload({
1986
+ employees,
1987
+ openShifts,
1988
+ timeOffs,
1989
+ selectedLocationIds,
1990
+ jurisdictions,
1991
+ selectedConstraintIds,
1992
+ constraintValues,
1993
+ selectedOptimizationIds,
1994
+ optimizationValues
1995
+ });
1996
+ const solvePromise = solveSchedule(baseURL, payload);
1997
+ const runId = resetBeforeSubmit();
1998
+ schedule(STEP_INTERVAL_MS, async () => {
1999
+ var _a, _b;
2000
+ setCompletedStepIndex(0);
2001
+ setActiveStepIndex(1);
2002
+ try {
2003
+ const response = await solvePromise;
2004
+ if (runIdRef.current !== runId) {
2005
+ return;
2006
+ }
2007
+ if (!response.explanation.isFeasible) {
2008
+ const result = mapViolationsToResult(
2009
+ (_a = response.explanation.violations) != null ? _a : [],
2010
+ response.explanation.summary
2011
+ );
2012
+ const selectedLocations = jurisdictions.flatMap((j) => j.locations).filter(
2013
+ (l) => selectedLocationIds.includes(l.id)
2014
+ );
2015
+ const recommendationPayload = generateRecommendationsURLAndHeaders ? {
2016
+ context: {
2017
+ selectedLocationIds,
2018
+ selectedConstraintIds,
2019
+ constraintValues,
2020
+ selectedOptimizationIds,
2021
+ optimizationValues,
2022
+ timezone: (_b = selectedLocations[0]) == null ? void 0 : _b.timezone
2023
+ },
2024
+ locations: selectedLocations,
2025
+ employees,
2026
+ openShifts: openShifts.filter((s) => !s.employeeId),
2027
+ assignedShifts: openShifts.filter((s) => Boolean(s.employeeId)),
2028
+ timeOffs: timeOffs != null ? timeOffs : [],
2029
+ explanation: response.explanation
2030
+ } : void 0;
2031
+ setLastFailure({
2032
+ ...result,
2033
+ recommendedFixes: [],
2034
+ recommendationPayload
2035
+ });
2036
+ setScreen("failed");
2037
+ } else {
2038
+ setCompletedStepIndex(1);
2039
+ setActiveStepIndex(OPTIMIZING_STEP_INDEX);
2040
+ afterSuccessSteps(runId, response);
2041
+ }
2042
+ } catch (err) {
2043
+ if (runIdRef.current !== runId) {
2044
+ return;
2045
+ }
2046
+ console.error(err);
2047
+ setLastFailure(NETWORK_ERROR_FAILURE);
2048
+ setScreen("failed");
2049
+ }
2050
+ }, runId);
2051
+ };
2052
+ const handleAdjustConstraints = () => {
2053
+ clearTimers();
2054
+ setScreen("configure");
2055
+ };
2056
+ const handleToggleLocation = (locationId) => {
2057
+ if (selectedLocationIds.includes(locationId)) {
2058
+ setSelectedLocationIds(selectedLocationIds.filter((id) => id !== locationId));
2059
+ return;
2060
+ }
2061
+ setSelectedLocationIds([...selectedLocationIds, locationId]);
2062
+ };
2063
+ const handleToggleConstraint = (constraintId) => {
2064
+ setSelectedConstraintIds((prev) => {
2065
+ if (prev.includes(constraintId)) {
2066
+ setConstraintValues((values) => {
2067
+ const next = { ...values };
2068
+ delete next[constraintId];
2069
+ return next;
2070
+ });
2071
+ return prev.filter((id) => id !== constraintId);
2072
+ }
2073
+ if (HARD_CONSTRAINT_DEFAULTS[constraintId]) {
2074
+ setConstraintValues((values) => ({
2075
+ ...values,
2076
+ [constraintId]: HARD_CONSTRAINT_DEFAULTS[constraintId]
2077
+ }));
2078
+ }
2079
+ return [...prev, constraintId];
2080
+ });
2081
+ };
2082
+ const handleToggleOptimization = (optionId) => {
2083
+ setSelectedOptimizationIds((prev) => {
2084
+ if (prev.includes(optionId)) {
2085
+ setOptimizationValues((values) => {
2086
+ const next = { ...values };
2087
+ delete next[`${optionId}_weightPoints`];
2088
+ if (optionId === "fair_hour_distribution") {
2089
+ delete next["fair_hour_distribution_balanceTarget"];
2090
+ delete next["fair_hour_distribution_period"];
2091
+ } else if (optionId === "minimize_overtime") {
2092
+ delete next["minimize_overtime_thresholdMinutes"];
2093
+ delete next["minimize_overtime_period"];
2094
+ }
2095
+ return next;
2096
+ });
2097
+ return prev.filter((id) => id !== optionId);
2098
+ }
2099
+ if (prev.length >= 3) return prev;
2100
+ setOptimizationValues((values) => ({
2101
+ ...values,
2102
+ [`${optionId}_weightPoints`]: "1"
2103
+ }));
2104
+ return [...prev, optionId];
2105
+ });
2106
+ };
2107
+ const modalTitle = screen === "configure" ? title : "Creating schedule";
2108
+ const showConfiguration = screen === "configure";
2109
+ const showFailed = screen === "failed";
2110
+ const violationTitle = (0, import_react3.useMemo)(
2111
+ () => showFailed ? "Schedule can\u2019t be created" : "Validating compliance rules",
2112
+ [showFailed]
2113
+ );
2114
+ const violationPanel = lastFailure ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2115
+ ViolatedConstraintsPanel,
2116
+ {
2117
+ violatedConstraints: lastFailure,
2118
+ title: violationTitle,
2119
+ subtitle: "",
2120
+ generateRecommendationsURLAndHeaders,
2121
+ styles
2122
+ }
2123
+ ) : null;
2124
+ const configurationContent = /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Stack, { spacing: "20px", children: [
2125
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Box, { sx: styles.banner, children: [
2126
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Box, { sx: styles.bannerIcon, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MagicIcon, {}) }),
2127
+ bannerText ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Text, { sx: styles.bannerText, children: bannerText }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Stack, { spacing: "4px", flex: 1, children: [
2128
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Text, { sx: styles.bannerTitle, children: "Create a smarter retail schedule in seconds." }),
2129
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Text, { sx: styles.bannerText, children: "AI assigns open shifts using your rules, availability, and optimization priorities while keeping existing assigned shifts in place." })
2130
+ ] })
2131
+ ] }),
2132
+ openShifts.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2133
+ import_react4.Box,
2134
+ {
2135
+ sx: {
2136
+ bg: "#FFF4E5",
2137
+ borderRadius: "8px",
2138
+ px: "8px",
2139
+ py: "8px",
2140
+ display: "flex",
2141
+ gap: "8px",
2142
+ alignItems: "flex-start"
2143
+ },
2144
+ children: [
2145
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Box, { sx: { color: "#B76E00", flexShrink: 0, mt: "2px" }, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(WarningIcon, {}) }),
2146
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Text, { sx: { fontSize: "13px", color: "#7A4100", lineHeight: "20px" }, children: "There are no open shifts to schedule. Add open shifts before creating a schedule." })
2147
+ ]
2148
+ }
2149
+ ) : null,
2150
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Stack, { spacing: "8px", sx: styles.locationSection, children: [
2151
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Stack, { spacing: "4px", children: [
2152
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.HStack, { sx: styles.locationLabelRow, children: [
2153
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Text, { sx: styles.locationLabel, children: "Location" }),
2154
+ selectedCount > 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Badge, { sx: styles.locationBadge, children: selectedCount }) : null
2155
+ ] }),
2156
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Text, { sx: styles.locationSubtitle, children: "Select locations within the same labor jurisdiction. Locations from different jurisdictions cannot be combined." })
2157
+ ] }),
2158
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Popover, { placement: "bottom-start", matchWidth: true, isLazy: true, children: [
2159
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.PopoverTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Button, { variant: "unstyled", sx: styles.locationTrigger, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.HStack, { justify: "space-between", w: "full", children: [
2160
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2161
+ import_react4.Text,
2162
+ {
2163
+ sx: {
2164
+ ...styles.locationTriggerText,
2165
+ ...selectedLocationIds.length > 0 ? { color: "#303030" } : {}
2166
+ },
2167
+ noOfLines: 1,
2168
+ children: selectedLocationIds.length > 0 ? jurisdictions.flatMap((j) => j.locations).filter((l) => selectedLocationIds.includes(l.id)).map((l) => l.name).join(", ") : locationPlaceholder
2169
+ }
2170
+ ),
2171
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Box, { color: "#5c5c5c", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ChevronDownIcon, {}) })
2172
+ ] }) }) }),
2173
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.PopoverContent, { sx: styles.popoverContent, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.PopoverBody, { p: 0, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Stack, { spacing: "4px", children: jurisdictions.map((jurisdiction) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Box, { children: [
2174
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Text, { sx: styles.groupHeader, children: jurisdiction.title }),
2175
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Stack, { spacing: "2px", children: jurisdiction.locations.map((location) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2176
+ import_react4.HStack,
2177
+ {
2178
+ as: "label",
2179
+ sx: { ...styles.optionRow, cursor: "pointer" },
2180
+ children: [
2181
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2182
+ import_react4.Checkbox,
2183
+ {
2184
+ id: `location-${location.id}`,
2185
+ isChecked: selectedLocationIds.includes(location.id),
2186
+ onChange: () => handleToggleLocation(location.id)
2187
+ }
2188
+ ),
2189
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Text, { sx: styles.optionLabel, children: location.name })
2190
+ ]
2191
+ },
2192
+ location.id
2193
+ )) })
2194
+ ] }, jurisdiction.id)) }) }) })
2195
+ ] }),
2196
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Stack, { spacing: "8px", children: selectedByJurisdiction.map((jurisdiction) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Box, { sx: styles.selectedBanner, children: [
2197
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Box, { sx: styles.selectedBannerIcon, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(InfoIcon, {}) }),
2198
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Box, { sx: styles.selectedBannerText, children: [
2199
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Text, { fontWeight: 600, children: [
2200
+ "Compliance jurisdiction: ",
2201
+ jurisdiction.title
2202
+ ] }),
2203
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Text, { children: jurisdiction.selectedLocations.map((location) => location.name).join(", ") })
2204
+ ] })
2205
+ ] }, jurisdiction.id)) })
2206
+ ] }),
2207
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Stack, { spacing: "16px", sx: styles.hardConstraintsSection, children: [
2208
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Stack, { spacing: "4px", children: [
2209
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.HStack, { sx: styles.hardConstraintsLabelRow, children: [
2210
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Text, { sx: styles.hardConstraintsLabel, children: "Required rules" }),
2211
+ selectedConstraintIds.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Badge, { sx: styles.hardConstraintsBadge, children: selectedConstraintIds.length }) : null
2212
+ ] }),
2213
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Text, { sx: styles.hardConstraintsSubtitle, children: "Assigned shifts will be required to meet the following rules:" })
2214
+ ] }),
2215
+ showConfiguration && lastFailure ? violationPanel : null,
2216
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Popover, { placement: "bottom-start", matchWidth: true, isLazy: true, children: [
2217
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.PopoverTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Button, { variant: "unstyled", sx: styles.hardConstraintsTrigger, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.HStack, { justify: "space-between", w: "full", children: [
2218
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2219
+ import_react4.Text,
2220
+ {
2221
+ sx: {
2222
+ ...styles.hardConstraintsTriggerText,
2223
+ ...selectedConstraintIds.length > 0 ? { color: "#303030" } : {}
2224
+ },
2225
+ noOfLines: 1,
2226
+ children: selectedConstraintIds.length > 0 ? HARD_CONSTRAINT_OPTIONS.filter((o) => selectedConstraintIds.includes(o.id)).map((o) => o.name).join(", ") : "Select rules"
2227
+ }
2228
+ ),
2229
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Box, { color: "#5c5c5c", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ChevronDownIcon, {}) })
2230
+ ] }) }) }),
2231
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.PopoverContent, { sx: styles.hardConstraintsPopoverContent, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.PopoverBody, { p: 0, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Stack, { spacing: "4px", children: HARD_CONSTRAINT_OPTIONS.map((option) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2232
+ import_react4.HStack,
2233
+ {
2234
+ as: "label",
2235
+ sx: { ...styles.hardConstraintsOptionRow, cursor: "pointer" },
2236
+ children: [
2237
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2238
+ import_react4.Checkbox,
2239
+ {
2240
+ id: `constraint-${option.id}`,
2241
+ isChecked: selectedConstraintIds.includes(option.id),
2242
+ onChange: () => handleToggleConstraint(option.id)
2243
+ }
2244
+ ),
2245
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Text, { sx: styles.hardConstraintsOptionLabel, children: option.name })
2246
+ ]
2247
+ },
2248
+ option.id
2249
+ )) }) }) })
2250
+ ] }),
2251
+ selectedConstraints.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Box, { sx: styles.hardConstraintsInputsContainer, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Stack, { spacing: "16px", children: selectedConstraints.map((option, index) => {
2252
+ var _a;
2253
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Stack, { sx: styles.hardConstraintsInputItem, children: [
2254
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Text, { sx: styles.hardConstraintsInputLabel, children: [
2255
+ index + 1,
2256
+ ". ",
2257
+ option.name
2258
+ ] }),
2259
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.InputGroup, { children: [
2260
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2261
+ import_react4.Input,
2262
+ {
2263
+ type: "number",
2264
+ value: (_a = constraintValues[option.id]) != null ? _a : "",
2265
+ onChange: (event) => setConstraintValues((prev) => ({
2266
+ ...prev,
2267
+ [option.id]: event.target.value
2268
+ })),
2269
+ min: option.id === "max_work_days_per_week" ? 1 : void 0,
2270
+ max: option.id === "max_work_days_per_week" ? 6 : void 0,
2271
+ step: option.id === "max_work_days_per_week" ? void 0 : "any",
2272
+ sx: styles.hardConstraintsInputField
2273
+ }
2274
+ ),
2275
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.InputRightAddon, { sx: styles.optimizationSuffix, children: option.id === "max_work_days_per_week" ? "days" : "hours" })
2276
+ ] })
2277
+ ] }, option.id);
2278
+ }) }) }) : null
2279
+ ] }),
2280
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Stack, { spacing: "16px", sx: styles.optimizationSection, children: [
2281
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Stack, { spacing: "4px", children: [
2282
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.HStack, { sx: styles.optimizationLabelRow, children: [
2283
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Text, { sx: styles.optimizationLabel, children: "Optimization" }),
2284
+ selectedOptimizationIds.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Badge, { sx: styles.optimizationBadge, children: selectedOptimizationIds.length }) : null
2285
+ ] }),
2286
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Text, { sx: styles.optimizationSubtitle, children: "Your schedule will be optimized based on the following priorities:" })
2287
+ ] }),
2288
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Popover, { placement: "bottom-start", matchWidth: true, isLazy: true, children: [
2289
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.PopoverTrigger, { children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Button, { variant: "unstyled", sx: styles.optimizationTrigger, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.HStack, { justify: "space-between", w: "full", children: [
2290
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2291
+ import_react4.Text,
2292
+ {
2293
+ sx: {
2294
+ ...styles.optimizationTriggerText,
2295
+ ...selectedOptimizationIds.length > 0 ? { color: "#303030" } : {}
2296
+ },
2297
+ noOfLines: 1,
2298
+ children: selectedOptimizationIds.length > 0 ? optimizationOptions.filter((o) => selectedOptimizationIds.includes(o.id)).map((o) => o.title).join(", ") : "Select optimization priorities"
2299
+ }
2300
+ ),
2301
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Box, { color: "#5c5c5c", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ChevronDownIcon, {}) })
2302
+ ] }) }) }),
2303
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.PopoverContent, { sx: styles.optimizationPopoverContent, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.PopoverBody, { p: 0, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Stack, { spacing: "4px", children: OPTIMIZATION_OPTION_GROUPS.map((group) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Box, { children: [
2304
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Text, { sx: styles.optimizationGroupHeader, children: group.name }),
2305
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Stack, { spacing: "2px", children: group.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
2306
+ import_react4.Stack,
2307
+ {
2308
+ as: "label",
2309
+ spacing: "2px",
2310
+ sx: { ...styles.optimizationOptionRow, cursor: "pointer" },
2311
+ children: [
2312
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.HStack, { spacing: "8px", children: [
2313
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2314
+ import_react4.Checkbox,
2315
+ {
2316
+ id: `optimization-${option.id}`,
2317
+ isChecked: selectedOptimizationIds.includes(option.id),
2318
+ isDisabled: !selectedOptimizationIds.includes(option.id) && selectedOptimizationIds.length >= 3,
2319
+ onChange: () => handleToggleOptimization(option.id)
2320
+ }
2321
+ ),
2322
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Text, { sx: styles.optimizationOptionLabel, children: option.title })
2323
+ ] }),
2324
+ option.subtitle ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Text, { sx: styles.optimizationOptionHelp, children: option.subtitle }) : null
2325
+ ]
2326
+ },
2327
+ option.id
2328
+ )) })
2329
+ ] }, group.id)) }) }) })
2330
+ ] }),
2331
+ selectedOptimizationOptions.length >= 2 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Box, { sx: styles.optimizationInputsContainer, children: [
2332
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Stack, { spacing: "16px", children: selectedOptimizationOptions.map((option, index) => {
2333
+ var _a;
2334
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2335
+ import_react4.Stack,
2336
+ {
2337
+ sx: styles.optimizationInputItem,
2338
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Stack, { sx: styles.hardConstraintsInputItem, children: [
2339
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Text, { sx: styles.hardConstraintsInputLabel, children: [
2340
+ index + 1,
2341
+ ". ",
2342
+ option.title
2343
+ ] }),
2344
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.InputGroup, { children: [
2345
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2346
+ import_react4.Input,
2347
+ {
2348
+ type: "text",
2349
+ value: (_a = optimizationValues[`${option.id}_weightPoints`]) != null ? _a : "1",
2350
+ onChange: (e) => {
2351
+ const val = e.target.value;
2352
+ if (val !== "" && (!/^\d+$/.test(val) || Number(val) < 1)) return;
2353
+ setOptimizationValues((prev) => ({
2354
+ ...prev,
2355
+ [`${option.id}_weightPoints`]: val
2356
+ }));
2357
+ },
2358
+ sx: styles.hardConstraintsInputField
2359
+ }
2360
+ ),
2361
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.InputRightAddon, { sx: styles.optimizationSuffix, children: "points" })
2362
+ ] })
2363
+ ] })
2364
+ },
2365
+ option.id
2366
+ );
2367
+ }) }),
2368
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Divider, { sx: { ...styles.optimizationDivider, my: "16px" } }),
2369
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Text, { sx: styles.optimizationSummary, children: allocationSummary })
2370
+ ] }) : null
2371
+ ] })
2372
+ ] });
2373
+ const stepsContent = /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Stack, { spacing: "16px", sx: styles.stepsContainer, children: [
2374
+ showFailed ? violationPanel : null,
2375
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Stack, { spacing: "14px", sx: styles.stepsList, children: SCHEDULE_STEPS.map((step, index) => {
2376
+ const status = stepStatusForIndex(index);
2377
+ const isFailedStep = showFailed && index === activeStepIndex;
2378
+ const iconStyles = {
2379
+ ...styles.stepIcon,
2380
+ ...status === "active" ? styles.stepIconActive : null,
2381
+ ...status === "done" ? styles.stepIconDone : null,
2382
+ ...status === "pending" ? styles.stepIconPending : null,
2383
+ ...isFailedStep ? styles.stepIconFailed : null
2384
+ };
2385
+ const titleStyles = {
2386
+ ...styles.stepTitle,
2387
+ ...status === "active" ? styles.stepTitleActive : null,
2388
+ ...status === "done" ? styles.stepTitleDone : null,
2389
+ ...status === "pending" ? styles.stepTitlePending : null,
2390
+ ...isFailedStep ? styles.stepTitleFailed : null
2391
+ };
2392
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.HStack, { sx: styles.stepRow, children: [
2393
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Box, { sx: iconStyles, children: isFailedStep ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(FailedIcon, { width: 12, height: 12 }) : status === "active" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Spinner, { size: "sm", thickness: "2px", speed: "0.7s" }) : status === "done" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CheckIcon, { width: 12, height: 12 }) : null }),
2394
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Box, { children: [
2395
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Text, { sx: titleStyles, children: step.title }),
2396
+ status === "active" && step.subtitle ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Text, { sx: styles.stepSubtitle, children: step.subtitle }) : null
2397
+ ] })
2398
+ ] }, step.title);
2399
+ }) })
2400
+ ] });
2401
+ const modalFooter = showConfiguration ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.ModalFooter, { sx: styles.footer, children: [
2402
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Button, { variant: "outline", onClick: onClose, sx: styles.cancelButton, children: cancelLabel }),
2403
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2404
+ import_react4.Button,
2405
+ {
2406
+ onClick: handleCreateSchedule,
2407
+ isDisabled: selectedCount === 0 || openShifts.length === 0 || hasEmptyInputs,
2408
+ sx: styles.primaryButton,
2409
+ children: primaryActionLabel
2410
+ }
2411
+ )
2412
+ ] }) : showFailed ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.ModalFooter, { sx: styles.failedFooter, children: [
2413
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2414
+ import_react4.Button,
2415
+ {
2416
+ variant: "outline",
2417
+ onClick: () => {
2418
+ if (lastFailure) {
2419
+ onFixManually == null ? void 0 : onFixManually(lastFailure, {
2420
+ selectedLocationIds,
2421
+ selectedConstraintIds,
2422
+ constraintValues,
2423
+ selectedOptimizationIds,
2424
+ optimizationValues
2425
+ });
2426
+ }
2427
+ onClose();
2428
+ },
2429
+ sx: styles.failedSecondaryButton,
2430
+ children: "Fix manually on schedule"
2431
+ }
2432
+ ),
2433
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Button, { onClick: handleAdjustConstraints, sx: styles.failedPrimaryButton, children: "Adjust constraints" })
2434
+ ] }) : null;
2435
+ const modalContent = /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.Modal, { isOpen, onClose, isCentered: true, motionPreset: "scale", closeOnOverlayClick: false, closeOnEsc: false, children: [
2436
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.ModalOverlay, { sx: styles.overlay }),
2437
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.ModalContent, { sx: styles.content, children: [
2438
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.ModalHeader, { sx: styles.header, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_react4.HStack, { justify: "space-between", w: "full", children: [
2439
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Text, { sx: styles.title, children: modalTitle }),
2440
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
2441
+ import_react4.IconButton,
2442
+ {
2443
+ "aria-label": "Close modal",
2444
+ variant: "ghost",
2445
+ size: "sm",
2446
+ icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CloseIcon, {}),
2447
+ onClick: onClose,
2448
+ sx: styles.closeButton
2449
+ }
2450
+ )
2451
+ ] }) }),
2452
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.ModalBody, { sx: showConfiguration ? styles.body : { ...styles.body, ...styles.creatingBody }, children: showConfiguration ? configurationContent : stepsContent }),
2453
+ modalFooter
2454
+ ] })
2455
+ ] });
2456
+ if (theme || cssVarsRoot) {
2457
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.ChakraProvider, { theme: mergedTheme, cssVarsRoot, children: modalContent });
2458
+ }
2459
+ return modalContent;
2460
+ }
2461
+
2462
+ // src/AutoSchedulerModalWithProvider.tsx
2463
+ var import_react5 = require("@chakra-ui/react");
2464
+ var import_jsx_runtime4 = require("react/jsx-runtime");
2465
+ function AutoSchedulerModalWithProvider(props) {
2466
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react5.ChakraProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AutoSchedulerModal, { ...props }) });
2467
+ }
2468
+
2469
+ // src/ViolatedConstraintsPanelWithProvider.tsx
2470
+ var import_react6 = require("@chakra-ui/react");
2471
+ var import_jsx_runtime5 = require("react/jsx-runtime");
2472
+ function ViolatedConstraintsPanelWithProvider(props) {
2473
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react6.ChakraProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ViolatedConstraintsPanel, { ...props }) });
2474
+ }
2475
+
2476
+ // src/utils/ruleIdFriendlyNames.ts
2477
+ var RULE_ID_FRIENDLY_NAMES = {
2478
+ // System soft constraints (format: system-{type}-soft)
2479
+ "system-employee-preference-soft": "Staff preferences",
2480
+ "system-employee-prefer-not-time-soft": "Prefer-not availability",
2481
+ "system-no-overlapping-shifts-soft": "No overlapping shifts",
2482
+ "system-overtime-soft": "Expected overtime",
2483
+ // Archetype soft constraints (format: {archetype}-soft)
2484
+ "accumulator-soft": "Hours limit",
2485
+ "accumulatordays-soft": "Work days limit",
2486
+ "spacer-soft": "Rest between shifts",
2487
+ "spacerperiodic-soft": "Required rest period",
2488
+ "composition-soft": "Staffing ratio",
2489
+ "transactional-soft": "Policy rule",
2490
+ "balancer-medium": "Fair work distribution",
2491
+ "balancerovertime-medium": "Minimize overtime",
2492
+ "coverage-soft": "Minimum staffing",
2493
+ "sizing-soft": "Shift duration limit",
2494
+ "sequencer-soft": "Shift sequence",
2495
+ "optimizerminimize-soft": "Minimize target",
2496
+ "optimizermaximize-soft": "Maximize target",
2497
+ // Rule IDs (from rules JSON)
2498
+ "max-weekly-hours": "Max weekly hours",
2499
+ "max-daily-hours": "Max daily hours",
2500
+ "min-rest-between-shifts": "Min rest between shifts",
2501
+ "min-days-off-per-week": "Min days off per week",
2502
+ "max-work-days-per-week": "Max work days per week",
2503
+ "fair-hour-distribution": "Fair hour distribution",
2504
+ "overtime-balance": "Overtime balance",
2505
+ "labor-cost-optimization": "Labor cost optimization",
2506
+ "maximize-sales-performance": "Maximize sales performance",
2507
+ "split-shift-penalty": "Split shift penalty",
2508
+ "shift-continuity-penalty": "Shift continuity penalty",
2509
+ "manager-cashier-ratio": "Staffing ratio",
2510
+ "min-staffing": "Minimum staffing",
2511
+ "shift-duration-limits": "Shift duration limit",
2512
+ "max-consecutive-days": "Shift sequence",
2513
+ "some-transactional-rule": "Policy rule"
2514
+ };
2515
+ function getFriendlyRuleName(ruleIdOrConstraintName) {
2516
+ const trimmed = ruleIdOrConstraintName == null ? void 0 : ruleIdOrConstraintName.trim();
2517
+ if (!trimmed) return "Unknown";
2518
+ const mapped = RULE_ID_FRIENDLY_NAMES[trimmed.toLocaleLowerCase()];
2519
+ if (mapped) return mapped;
2520
+ return trimmed.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(" ");
2521
+ }
2522
+
2523
+ // src/api/types.ts
2524
+ var RequestError = class extends Error {
2525
+ constructor(message, status, payload) {
2526
+ super(message);
2527
+ this.name = "RequestError";
2528
+ this.status = status;
2529
+ this.payload = payload;
2530
+ }
2531
+ };
2532
+ // Annotate the CommonJS export names for ESM import in node:
2533
+ 0 && (module.exports = {
2534
+ AutoSchedulerModal,
2535
+ AutoSchedulerModalWithProvider,
2536
+ RequestError,
2537
+ ViolatedConstraintsPanel,
2538
+ ViolatedConstraintsPanelWithProvider,
2539
+ buildRulesPayload,
2540
+ buildSchedulePayload,
2541
+ getFriendlyRuleName
2542
+ });
2543
+ //# sourceMappingURL=index.cjs.map