@glatam/calendar-ui 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1518 +0,0 @@
1
- import { css as E, LitElement as O, html as d } from "lit";
2
- import { property as s, customElement as T, state as m } from "lit/decorators.js";
3
- import { isTimeBlocked as M, formatISODate as N, generateMonthDays as j, generateWeekDays as _ } from "@glatam/calendar-core";
4
- import { formatISODate as st, isTimeBlocked as lt, parseISODate as nt } from "@glatam/calendar-core";
5
- import { classMap as I } from "lit/directives/class-map.js";
6
- const A = E`
7
- :host {
8
- /* Fonts */
9
- --glatam-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
10
-
11
- /* Colors - Premium Apple Light Theme */
12
- --glatam-primary: #5856d6;
13
- --glatam-primary-hover: #4745b4;
14
- --glatam-primary-light: rgba(88, 86, 214, 0.1);
15
- --glatam-primary-light-hover: rgba(88, 86, 214, 0.25);
16
-
17
- --glatam-bg: #ffffff;
18
- --glatam-surface: #f5f5f7;
19
- --glatam-border: #e5e5ea;
20
- --glatam-text: #1d1d1f;
21
- --glatam-text-secondary: #86868b;
22
- --glatam-text-light: #ffffff;
23
-
24
- /* Blocked/Unavailable states */
25
- --glatam-blocked-bg: #fcfcfd;
26
- --glatam-blocked-stripe: #f2f2f7;
27
- --glatam-blocked-text: #aeaeae;
28
- --glatam-blocked-border: #e5e5ea;
29
-
30
- /* Selection Colors */
31
- --glatam-selection-bg: rgba(88, 86, 214, 0.15);
32
- --glatam-selection-border: #5856d6;
33
-
34
- /* Today highlighting */
35
- --glatam-today-text: #5856d6;
36
- --glatam-today-bg: rgba(88, 86, 214, 0.08);
37
-
38
- /* Dimensions & Layout */
39
- --glatam-border-radius: 12px;
40
- --glatam-padding: 16px;
41
- --glatam-grid-border-radius: 8px;
42
- --glatam-day-min-height: 72px;
43
- --glatam-time-col-width: 60px;
44
- --glatam-slot-height: 48px;
45
-
46
- /* Animation duration */
47
- --glatam-transition-fast: 0.15s ease;
48
- --glatam-transition-normal: 0.25s ease;
49
- }
50
-
51
- :host(.dark-mode) {
52
- /* Colors - Premium Apple Dark Theme */
53
- --glatam-primary: #5e5ce6;
54
- --glatam-primary-hover: #7d7aff;
55
- --glatam-primary-light: rgba(94, 92, 230, 0.15);
56
- --glatam-primary-light-hover: rgba(94, 92, 230, 0.3);
57
-
58
- --glatam-bg: #1c1c1e;
59
- --glatam-surface: #2c2c2e;
60
- --glatam-border: #38383a;
61
- --glatam-text: #f5f5f7;
62
- --glatam-text-secondary: #8e8e93;
63
-
64
- /* Blocked/Unavailable states */
65
- --glatam-blocked-bg: #242426;
66
- --glatam-blocked-stripe: #2c2c2e;
67
- --glatam-blocked-text: #707074;
68
- --glatam-blocked-border: #38383a;
69
-
70
- /* Selection Colors */
71
- --glatam-selection-bg: rgba(94, 92, 230, 0.25);
72
- --glatam-selection-border: #5e5ce6;
73
-
74
- /* Today highlighting */
75
- --glatam-today-text: #7d7aff;
76
- --glatam-today-bg: rgba(94, 92, 230, 0.12);
77
- }
78
-
79
- :host([size="small"]) {
80
- --glatam-day-min-height: 48px;
81
- --glatam-slot-height: 36px;
82
- --glatam-time-col-width: 48px;
83
- --glatam-padding: 10px;
84
- font-size: 0.8rem;
85
- }
86
-
87
- :host([size="large"]) {
88
- --glatam-day-min-height: 96px;
89
- --glatam-slot-height: 60px;
90
- --glatam-time-col-width: 72px;
91
- --glatam-padding: 24px;
92
- font-size: 1.1rem;
93
- }
94
- `, P = E`
95
- :host {
96
- display: grid;
97
- min-width: 0;
98
- font-family: var(--glatam-font-family);
99
- color: var(--glatam-text);
100
- background-color: var(--glatam-bg);
101
- border-radius: var(--glatam-border-radius);
102
- padding: var(--glatam-padding);
103
- box-shadow: 0 4px 25px rgba(0, 0, 0, 0.05);
104
- border: 1px solid var(--glatam-border);
105
- box-sizing: border-box;
106
- width: 100%;
107
- max-width: 100%;
108
- overflow: hidden;
109
- transition: background-color var(--glatam-transition-normal), border-color var(--glatam-transition-normal);
110
- }
111
-
112
- *, *::before, *::after {
113
- box-sizing: border-box;
114
- }
115
-
116
- .calendar-header {
117
- display: flex;
118
- justify-content: space-between;
119
- align-items: center;
120
- margin-bottom: var(--glatam-padding);
121
- flex-wrap: wrap;
122
- gap: 12px;
123
- }
124
-
125
- .nav-group, .view-group {
126
- display: flex;
127
- align-items: center;
128
- gap: 8px;
129
- }
130
-
131
- .nav-title {
132
- font-size: 1.25rem;
133
- font-weight: 600;
134
- min-width: 140px;
135
- text-align: center;
136
- letter-spacing: -0.01em;
137
- }
138
-
139
- .btn {
140
- font-family: inherit;
141
- font-size: 0.875rem;
142
- font-weight: 500;
143
- padding: 8px 12px;
144
- border-radius: 8px;
145
- border: 1px solid var(--glatam-border);
146
- background-color: var(--glatam-bg);
147
- color: var(--glatam-text);
148
- cursor: pointer;
149
- transition: background-color var(--glatam-transition-fast), border-color var(--glatam-transition-fast), transform var(--glatam-transition-fast);
150
- display: inline-flex;
151
- align-items: center;
152
- justify-content: center;
153
- min-width: 36px;
154
- height: 36px;
155
- }
156
-
157
- .btn:hover:not(:disabled) {
158
- background-color: var(--glatam-surface);
159
- border-color: var(--glatam-text-secondary);
160
- }
161
-
162
- .btn:active:not(:disabled) {
163
- transform: scale(0.97);
164
- }
165
-
166
- .btn:disabled {
167
- opacity: 0.5;
168
- cursor: not-allowed;
169
- }
170
-
171
- .btn-primary {
172
- background-color: var(--glatam-primary);
173
- color: var(--glatam-text-light);
174
- border: none;
175
- }
176
-
177
- .btn-primary:hover:not(:disabled) {
178
- background-color: var(--glatam-primary-hover);
179
- }
180
-
181
- .btn-group {
182
- display: flex;
183
- border-radius: 8px;
184
- overflow: hidden;
185
- border: 1px solid var(--glatam-border);
186
- }
187
-
188
- .btn-group .btn {
189
- border-radius: 0;
190
- border: none;
191
- border-right: 1px solid var(--glatam-border);
192
- }
193
-
194
- .btn-group .btn:last-child {
195
- border-right: none;
196
- }
197
-
198
- .btn-group .btn.active {
199
- background-color: var(--glatam-primary-light);
200
- color: var(--glatam-primary);
201
- font-weight: 600;
202
- }
203
-
204
- /* Timezone Selector Styles */
205
- .timezone-badge {
206
- font-size: 0.75rem;
207
- padding: 4px 8px;
208
- background: var(--glatam-surface);
209
- border: 1px solid var(--glatam-border);
210
- border-radius: 20px;
211
- display: inline-flex;
212
- align-items: center;
213
- gap: 4px;
214
- color: var(--glatam-text-secondary);
215
- }
216
-
217
- .timezone-select {
218
- background: transparent;
219
- border: none;
220
- color: var(--glatam-text);
221
- font-family: inherit;
222
- font-size: 0.75rem;
223
- font-weight: 600;
224
- cursor: pointer;
225
- outline: none;
226
- padding-right: 4px;
227
- }
228
-
229
- /* Mini Popover Variant Styles */
230
- .dropdown-container {
231
- position: relative;
232
- display: inline-block;
233
- width: 100%;
234
- }
235
-
236
- .dropdown-toggle {
237
- width: 100%;
238
- justify-content: space-between;
239
- padding: 12px 16px;
240
- border-radius: 12px;
241
- font-weight: 600;
242
- height: 48px;
243
- }
244
-
245
- .dropdown-card {
246
- position: absolute;
247
- top: calc(100% + 8px);
248
- left: 0;
249
- width: 320px;
250
- background: var(--glatam-bg);
251
- border-radius: 16px;
252
- border: 1px solid var(--glatam-border);
253
- box-shadow: 0 12px 40px rgba(0, 0, 0, 0.1);
254
- z-index: 100;
255
- padding: 16px;
256
- display: flex;
257
- flex-direction: column;
258
- gap: 12px;
259
- animation: fadeInUp 0.3s cubic-bezier(0.16, 1, 0.3, 1) forwards;
260
- }
261
-
262
- .slot-list {
263
- display: flex;
264
- flex-direction: column;
265
- gap: 8px;
266
- max-height: 220px;
267
- overflow-y: auto;
268
- padding-right: 4px;
269
- }
270
-
271
- .slot-btn {
272
- width: 100%;
273
- padding: 10px;
274
- border-radius: 8px;
275
- border: 1px solid var(--glatam-border);
276
- background: var(--glatam-bg);
277
- color: var(--glatam-text);
278
- cursor: pointer;
279
- font-family: inherit;
280
- font-size: 0.85rem;
281
- font-weight: 500;
282
- text-align: center;
283
- transition: background-color var(--glatam-transition-fast);
284
- }
285
-
286
- .slot-btn:hover:not(.blocked) {
287
- background-color: var(--glatam-surface);
288
- border-color: var(--glatam-text-secondary);
289
- }
290
-
291
- .slot-btn.blocked {
292
- background-color: var(--glatam-surface);
293
- color: var(--glatam-blocked-text);
294
- text-decoration: line-through;
295
- cursor: not-allowed;
296
- border-color: var(--glatam-border);
297
- opacity: 0.6;
298
- }
299
-
300
- /* Smooth Apple Animation */
301
- .calendar-body {
302
- position: relative;
303
- width: 100%;
304
- overflow-x: auto;
305
- animation: fadeInUp 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;
306
- }
307
-
308
- @keyframes fadeInUp {
309
- from {
310
- opacity: 0;
311
- transform: translateY(8px) scale(0.995);
312
- }
313
- to {
314
- opacity: 1;
315
- transform: translateY(0) scale(1);
316
- }
317
- }
318
-
319
- @media (max-width: 600px) {
320
- :host {
321
- padding: 8px;
322
- }
323
- .calendar-header {
324
- flex-direction: column;
325
- align-items: stretch;
326
- gap: 10px;
327
- }
328
- .nav-group, .view-group {
329
- width: 100%;
330
- justify-content: space-between;
331
- flex-wrap: wrap;
332
- gap: 6px;
333
- }
334
- .nav-title {
335
- flex: 1;
336
- font-size: 1.1rem;
337
- min-width: unset;
338
- text-align: right;
339
- white-space: nowrap;
340
- overflow: hidden;
341
- text-overflow: ellipsis;
342
- }
343
- .btn {
344
- font-size: 0.8rem;
345
- padding: 6px 10px;
346
- height: 32px;
347
- min-width: 32px;
348
- }
349
- }
350
- `;
351
- function C(e, t, a) {
352
- if (t === a) return 0;
353
- const i = (r, l) => {
354
- const o = {
355
- year: "numeric",
356
- month: "numeric",
357
- day: "numeric",
358
- hour: "numeric",
359
- minute: "numeric",
360
- second: "numeric",
361
- hour12: !1
362
- };
363
- l !== "local" && (o.timeZone = l);
364
- const n = new Intl.DateTimeFormat("en-US", o).formatToParts(r), g = new Map(n.map((S) => [S.type, S.value])), u = Number(g.get("hour")), v = u === 24 ? 0 : u;
365
- return new Date(
366
- Number(g.get("year")),
367
- Number(g.get("month")) - 1,
368
- Number(g.get("day")),
369
- v,
370
- Number(g.get("minute")),
371
- Number(g.get("second"))
372
- );
373
- };
374
- try {
375
- const r = i(e, t);
376
- return (i(e, a).getTime() - r.getTime()) / (60 * 1e3);
377
- } catch {
378
- return 0;
379
- }
380
- }
381
- function W(e, t) {
382
- if (t === 0)
383
- return { start: e.start, end: e.end, dayShift: 0 };
384
- const a = (g) => {
385
- const [u, v] = g.split(":").map(Number);
386
- return u * 60 + v;
387
- }, i = (g) => {
388
- let u = g % 1440;
389
- u < 0 && (u += 1440);
390
- const v = String(Math.floor(u / 60)).padStart(2, "0"), S = String(u % 60).padStart(2, "0");
391
- return `${v}:${S}`;
392
- }, r = a(e.start), l = a(e.end), o = r + t, c = l + t;
393
- let n = 0;
394
- return o < 0 ? n = -1 : o >= 1440 && (n = 1), {
395
- start: i(o),
396
- end: i(c),
397
- dayShift: n
398
- };
399
- }
400
- var U = Object.defineProperty, L = Object.getOwnPropertyDescriptor, k = (e, t, a, i) => {
401
- for (var r = i > 1 ? void 0 : i ? L(t, a) : t, l = e.length - 1, o; l >= 0; l--)
402
- (o = e[l]) && (r = (i ? o(t, a, r) : o(r)) || r);
403
- return i && r && U(t, a, r), r;
404
- };
405
- let f = class extends O {
406
- constructor() {
407
- super(...arguments), this.days = [], this.locale = "es", this.startOfWeekDay = 0, this.selectedDates = [], this.role = "provider", this.size = "medium", this.minDate = "", this.maxDate = "", this.showNeighboringMonth = !0, this.tileClassName = null;
408
- }
409
- getWeekdayNames() {
410
- const e = [], t = new Date(2026, 6, 12 + this.startOfWeekDay), a = new Intl.DateTimeFormat(this.locale, { weekday: "short" });
411
- for (let i = 0; i < 7; i++)
412
- e.push(a.format(t)), t.setDate(t.getDate() + 1);
413
- return e;
414
- }
415
- handleDayClick(e) {
416
- this.role === "buyer" && e.isBlocked || this.dispatchEvent(new CustomEvent("day-select", {
417
- detail: { dateString: e.dateString, isBlocked: e.isBlocked },
418
- bubbles: !0,
419
- composed: !0
420
- }));
421
- }
422
- render() {
423
- const e = this.getWeekdayNames();
424
- return d`
425
- ${e.map((t) => d`<div class="weekday">${t}</div>`)}
426
-
427
- ${this.days.map((t) => {
428
- var c;
429
- if (!t.isCurrentMonth && !this.showNeighboringMonth)
430
- return d`<div class="day-cell empty"></div>`;
431
- const a = t.dateString === (/* @__PURE__ */ new Date()).toISOString().split("T")[0], i = this.selectedDates.includes(t.dateString), r = t.slots.filter((n) => n.isBlocked), l = this.minDate && t.dateString < this.minDate || this.maxDate && t.dateString > this.maxDate, o = this.tileClassName ? this.tileClassName({ date: t.date, dateString: t.dateString }) : "";
432
- return d`
433
- <div
434
- class=${I({
435
- "day-cell": !0,
436
- padding: !t.isCurrentMonth,
437
- blocked: t.isBlocked,
438
- today: a,
439
- selected: i,
440
- disabled: !!l,
441
- [o]: !!o
442
- })}
443
- part="day-cell ${o}"
444
- @click=${() => this.handleDayClick(t)}
445
- >
446
- <div class="day-number">${t.dayNumber}</div>
447
-
448
- <div class="slot-indicator">
449
- ${t.isBlocked ? d`<div class="badge blocked-day">${((c = t.rule) == null ? void 0 : c.description) || "Bloqueado"}</div>` : r.slice(0, 2).map((n) => {
450
- var g, u;
451
- return d`
452
- <div class="badge blocked-slot" title=${((g = n.rule) == null ? void 0 : g.description) || ""}>
453
- 🚫 ${((u = n.rule) == null ? void 0 : u.description) || n.start}
454
- </div>
455
- `;
456
- })}
457
- ${!t.isBlocked && r.length > 2 ? d`<div style="text-align: center; font-size: 0.65rem; color: var(--glatam-text-secondary);">+${r.length - 2} tareas</div>` : ""}
458
- </div>
459
- </div>
460
- `;
461
- })}
462
- `;
463
- }
464
- };
465
- f.styles = E`
466
- :host { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 6px; width: 100%; }
467
- .weekday { font-size: 0.75rem; font-weight: 600; color: var(--glatam-text-secondary); text-transform: uppercase; text-align: center; padding: 8px 0; letter-spacing: 0.05em; }
468
- .day-cell {
469
- min-height: var(--glatam-day-min-height); border: 1px solid var(--glatam-border); border-radius: var(--glatam-grid-border-radius);
470
- padding: 8px; display: flex; flex-direction: column; justify-content: space-between; cursor: pointer;
471
- transition: background-color var(--glatam-transition-fast), border-color var(--glatam-transition-fast); background-color: var(--glatam-bg); position: relative;
472
- }
473
- .day-cell:hover:not(.blocked):not(.disabled) { background-color: var(--glatam-surface); border-color: var(--glatam-text-secondary); }
474
- .day-cell.padding { opacity: 0.4; }
475
- .day-cell.blocked {
476
- background: repeating-linear-gradient(45deg, var(--glatam-blocked-bg), var(--glatam-blocked-bg) 10px, var(--glatam-blocked-stripe) 10px, var(--glatam-blocked-stripe) 20px);
477
- border-color: var(--glatam-blocked-border); color: var(--glatam-blocked-text); cursor: not-allowed;
478
- }
479
- .day-cell.today { background-color: var(--glatam-today-bg); border-color: var(--glatam-primary); }
480
- .day-cell.selected { background-color: var(--glatam-selection-bg); border-color: var(--glatam-selection-border); box-shadow: inset 0 0 0 1px var(--glatam-selection-border); }
481
- .day-cell.disabled { opacity: 0.2; cursor: not-allowed; background-color: var(--glatam-surface); border-color: var(--glatam-border); pointer-events: none; }
482
- .day-cell.empty { border: none; background: transparent; cursor: default; pointer-events: none; }
483
- .day-number { font-size: 0.875rem; font-weight: 500; margin-bottom: 4px; }
484
- .day-cell.today .day-number { color: var(--glatam-today-text); font-weight: 700; }
485
- .slot-indicator { display: flex; flex-direction: column; gap: 3px; font-size: 0.7rem; overflow: hidden; margin-top: 4px; }
486
- .badge { padding: 2px 6px; border-radius: 4px; font-weight: 500; text-align: center; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; }
487
- .badge.blocked-day { background-color: rgba(255, 69, 58, 0.12); color: #ff453a; font-weight: 600; }
488
- .badge.blocked-slot { background-color: var(--glatam-surface); border: 1px solid var(--glatam-border); color: var(--glatam-text-secondary); }
489
- :host([size="small"]) .day-cell { min-height: 38px; padding: 4px; justify-content: center; align-items: center; }
490
- :host([size="small"]) .slot-indicator { display: none; }
491
- :host([size="small"]) .day-number { margin-bottom: 0; font-size: 0.8rem; }
492
- @media (max-width: 600px) {
493
- .day-cell { min-height: 38px; padding: 4px; justify-content: center; align-items: center; }
494
- .slot-indicator { display: none; }
495
- .day-number { margin-bottom: 0; font-size: 0.8rem; }
496
- }
497
- `;
498
- k([
499
- s({ type: Array })
500
- ], f.prototype, "days", 2);
501
- k([
502
- s({ type: String })
503
- ], f.prototype, "locale", 2);
504
- k([
505
- s({ type: Number })
506
- ], f.prototype, "startOfWeekDay", 2);
507
- k([
508
- s({ type: Array })
509
- ], f.prototype, "selectedDates", 2);
510
- k([
511
- s({ type: String })
512
- ], f.prototype, "role", 2);
513
- k([
514
- s({ type: String, reflect: !0 })
515
- ], f.prototype, "size", 2);
516
- k([
517
- s({ type: String })
518
- ], f.prototype, "minDate", 2);
519
- k([
520
- s({ type: String })
521
- ], f.prototype, "maxDate", 2);
522
- k([
523
- s({ type: Boolean })
524
- ], f.prototype, "showNeighboringMonth", 2);
525
- k([
526
- s({ attribute: !1 })
527
- ], f.prototype, "tileClassName", 2);
528
- f = k([
529
- T("glatam-calendar-month-view")
530
- ], f);
531
- var F = Object.defineProperty, H = Object.getOwnPropertyDescriptor, R = (e, t, a, i) => {
532
- for (var r = i > 1 ? void 0 : i ? H(t, a) : t, l = e.length - 1, o; l >= 0; l--)
533
- (o = e[l]) && (r = (i ? o(t, a, r) : o(r)) || r);
534
- return i && r && F(t, a, r), r;
535
- };
536
- let w = class extends O {
537
- constructor() {
538
- super(...arguments), this.days = [], this.slots = [], this.locale = "es", this.selectedRange = null, this.role = "provider", this.isDragging = !1, this.dragDayIndex = null, this.dragStartSlotIndex = null, this.dragEndSlotIndex = null, this.handleMouseUp = () => {
539
- if (!this.isDragging || this.dragDayIndex === null || this.dragStartSlotIndex === null || this.dragEndSlotIndex === null) {
540
- this.isDragging = !1;
541
- return;
542
- }
543
- this.isDragging = !1;
544
- const e = Math.min(this.dragStartSlotIndex, this.dragEndSlotIndex), t = Math.max(this.dragStartSlotIndex, this.dragEndSlotIndex), a = this.days[this.dragDayIndex], i = a.slots.slice(e, t + 1);
545
- i.some((r) => r.isBlocked) || this.dispatchEvent(new CustomEvent("range-select", {
546
- detail: { dateString: a.dateString, start: i[0].start, end: i[i.length - 1].end },
547
- bubbles: !0,
548
- composed: !0
549
- })), this.dragDayIndex = null, this.dragStartSlotIndex = null, this.dragEndSlotIndex = null;
550
- };
551
- }
552
- connectedCallback() {
553
- super.connectedCallback(), window.addEventListener("mouseup", this.handleMouseUp);
554
- }
555
- disconnectedCallback() {
556
- window.removeEventListener("mouseup", this.handleMouseUp), super.disconnectedCallback();
557
- }
558
- handleMouseDown(e, t, a) {
559
- if (a) {
560
- if (this.role === "buyer") return;
561
- this.dispatchEvent(new CustomEvent("slot-click", {
562
- detail: { dateString: this.days[e].dateString, slot: this.days[e].slots[t], isBlocked: !0 },
563
- bubbles: !0,
564
- composed: !0
565
- }));
566
- return;
567
- }
568
- this.isDragging = !0, this.dragDayIndex = e, this.dragStartSlotIndex = t, this.dragEndSlotIndex = t;
569
- }
570
- handleMouseEnter(e, t, a) {
571
- this.isDragging && e === this.dragDayIndex && !a && (this.dragEndSlotIndex = t);
572
- }
573
- isSlotSelected(e, t) {
574
- return !this.selectedRange || this.selectedRange.dateString !== e ? !1 : t.start >= this.selectedRange.start && t.end <= this.selectedRange.end;
575
- }
576
- isSlotDragSelecting(e, t) {
577
- if (!this.isDragging || e !== this.dragDayIndex) return !1;
578
- const a = Math.min(this.dragStartSlotIndex, this.dragEndSlotIndex), i = Math.max(this.dragStartSlotIndex, this.dragEndSlotIndex);
579
- return t >= a && t <= i;
580
- }
581
- render() {
582
- const e = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
583
- return d`
584
- <div class="time-col">
585
- <div class="header-cell">Hora</div>
586
- ${this.slots.map((t) => d`<div class="slot-cell time-slot-label">${t.start}</div>`)}
587
- </div>
588
-
589
- ${this.days.map((t, a) => {
590
- const i = t.dateString === e, r = new Intl.DateTimeFormat(this.locale, { weekday: "short" }).format(t.date);
591
- return d`
592
- <div class="day-col">
593
- <div class="header-cell ${i ? "today" : ""}">
594
- <div>${r}</div>
595
- <div class="day-num">${t.dayNumber}</div>
596
- </div>
597
-
598
- ${t.slots.map((l, o) => {
599
- var u, v;
600
- const c = l.isBlocked, n = this.isSlotSelected(t.dateString, l), g = this.isSlotDragSelecting(a, o);
601
- return d`
602
- <div
603
- class=${I({
604
- "slot-cell": !0,
605
- available: !c,
606
- blocked: c,
607
- selected: n,
608
- "drag-selecting": g
609
- })}
610
- @mousedown=${() => this.handleMouseDown(a, o, c)}
611
- @mouseenter=${() => this.handleMouseEnter(a, o, c)}
612
- title=${c && ((u = l.rule) != null && u.description) ? l.rule.description : ""}
613
- >
614
- ${c ? ((v = l.rule) == null ? void 0 : v.description) || "Ocupado" : n ? "Reservado" : ""}
615
- </div>
616
- `;
617
- })}
618
- </div>
619
- `;
620
- })}
621
- `;
622
- }
623
- };
624
- w.styles = E`
625
- :host {
626
- display: grid; grid-template-columns: var(--glatam-time-col-width) repeat(7, 1fr); gap: 2px;
627
- width: 100%; background-color: var(--glatam-border); border: 1px solid var(--glatam-border);
628
- border-radius: var(--glatam-grid-border-radius); overflow: hidden; user-select: none;
629
- }
630
- @media (max-width: 600px) {
631
- :host {
632
- grid-template-columns: 40px repeat(7, 1fr);
633
- overflow-x: hidden;
634
- }
635
- .slot-cell {
636
- font-size: 0.65rem;
637
- }
638
- .slot-cell.blocked, .slot-cell.selected {
639
- font-size: 0;
640
- padding: 0;
641
- }
642
- .time-slot-label {
643
- font-size: 0.65rem;
644
- }
645
- .header-cell {
646
- font-size: 0.7rem;
647
- }
648
- .header-cell .day-num {
649
- font-size: 0.8rem;
650
- }
651
- }
652
- .time-col { background-color: var(--glatam-surface); display: flex; flex-direction: column; }
653
- .day-col { background-color: var(--glatam-bg); display: flex; flex-direction: column; }
654
- .header-cell {
655
- height: 60px; display: flex; flex-direction: column; align-items: center; justify-content: center;
656
- background-color: var(--glatam-surface); border-bottom: 2px solid var(--glatam-border);
657
- font-size: 0.8rem; font-weight: 500; text-transform: capitalize;
658
- }
659
- .header-cell.today { color: var(--glatam-primary); font-weight: 700; }
660
- .header-cell .day-num { font-size: 0.95rem; font-weight: 600; margin-top: 2px; }
661
- .slot-cell {
662
- height: var(--glatam-slot-height); border-bottom: 1px solid var(--glatam-border);
663
- display: flex; align-items: center; justify-content: center; font-size: 0.75rem;
664
- cursor: pointer; transition: background-color var(--glatam-transition-fast); position: relative;
665
- }
666
- .time-slot-label { font-size: 0.7rem; color: var(--glatam-text-secondary); }
667
- .slot-cell.available:hover { background-color: var(--glatam-surface); }
668
- .slot-cell.blocked {
669
- background-color: var(--glatam-blocked-bg);
670
- background-image: repeating-linear-gradient(45deg, transparent, transparent 5px, var(--glatam-blocked-stripe) 5px, var(--glatam-blocked-stripe) 10px);
671
- color: var(--glatam-blocked-text); cursor: not-allowed; font-weight: 600; padding: 0 4px;
672
- white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-align: center;
673
- }
674
- .slot-cell.selected { background-color: var(--glatam-selection-bg); border-left: 3px solid var(--glatam-selection-border); }
675
- .slot-cell.drag-selecting { background-color: var(--glatam-primary-light); }
676
- `;
677
- R([
678
- s({ type: Array })
679
- ], w.prototype, "days", 2);
680
- R([
681
- s({ type: Array })
682
- ], w.prototype, "slots", 2);
683
- R([
684
- s({ type: String })
685
- ], w.prototype, "locale", 2);
686
- R([
687
- s({ type: Object })
688
- ], w.prototype, "selectedRange", 2);
689
- R([
690
- s({ type: String })
691
- ], w.prototype, "role", 2);
692
- R([
693
- m()
694
- ], w.prototype, "isDragging", 2);
695
- R([
696
- m()
697
- ], w.prototype, "dragDayIndex", 2);
698
- R([
699
- m()
700
- ], w.prototype, "dragStartSlotIndex", 2);
701
- R([
702
- m()
703
- ], w.prototype, "dragEndSlotIndex", 2);
704
- w = R([
705
- T("glatam-calendar-week-view")
706
- ], w);
707
- var q = Object.defineProperty, G = Object.getOwnPropertyDescriptor, z = (e, t, a, i) => {
708
- for (var r = i > 1 ? void 0 : i ? G(t, a) : t, l = e.length - 1, o; l >= 0; l--)
709
- (o = e[l]) && (r = (i ? o(t, a, r) : o(r)) || r);
710
- return i && r && q(t, a, r), r;
711
- };
712
- let D = class extends O {
713
- constructor() {
714
- super(...arguments), this.day = null, this.slots = [], this.locale = "es", this.selectedRange = null, this.role = "provider", this.isDragging = !1, this.dragStartSlotIndex = null, this.dragEndSlotIndex = null, this.handleMouseUp = () => {
715
- if (!this.isDragging || !this.day || this.dragStartSlotIndex === null || this.dragEndSlotIndex === null) {
716
- this.isDragging = !1;
717
- return;
718
- }
719
- this.isDragging = !1;
720
- const e = Math.min(this.dragStartSlotIndex, this.dragEndSlotIndex), t = Math.max(this.dragStartSlotIndex, this.dragEndSlotIndex), a = this.day.slots.slice(e, t + 1);
721
- a.some((i) => i.isBlocked) || this.dispatchEvent(new CustomEvent("range-select", {
722
- detail: { dateString: this.day.dateString, start: a[0].start, end: a[a.length - 1].end },
723
- bubbles: !0,
724
- composed: !0
725
- })), this.dragStartSlotIndex = null, this.dragEndSlotIndex = null;
726
- };
727
- }
728
- connectedCallback() {
729
- super.connectedCallback(), window.addEventListener("mouseup", this.handleMouseUp);
730
- }
731
- disconnectedCallback() {
732
- window.removeEventListener("mouseup", this.handleMouseUp), super.disconnectedCallback();
733
- }
734
- handleMouseDown(e, t) {
735
- if (t && this.day) {
736
- if (this.role === "buyer") return;
737
- this.dispatchEvent(new CustomEvent("slot-click", {
738
- detail: { dateString: this.day.dateString, slot: this.day.slots[e], isBlocked: !0 },
739
- bubbles: !0,
740
- composed: !0
741
- }));
742
- return;
743
- }
744
- this.isDragging = !0, this.dragStartSlotIndex = e, this.dragEndSlotIndex = e;
745
- }
746
- handleMouseEnter(e, t) {
747
- this.isDragging && !t && (this.dragEndSlotIndex = e);
748
- }
749
- isSlotSelected(e) {
750
- return !this.day || !this.selectedRange || this.selectedRange.dateString !== this.day.dateString ? !1 : e.start >= this.selectedRange.start && e.end <= this.selectedRange.end;
751
- }
752
- isSlotDragSelecting(e) {
753
- if (!this.isDragging) return !1;
754
- const t = Math.min(this.dragStartSlotIndex, this.dragEndSlotIndex), a = Math.max(this.dragStartSlotIndex, this.dragEndSlotIndex);
755
- return e >= t && e <= a;
756
- }
757
- render() {
758
- if (!this.day) return d`<div>Cargando...</div>`;
759
- const e = this.day.dateString === (/* @__PURE__ */ new Date()).toISOString().split("T")[0], t = new Intl.DateTimeFormat(this.locale, { weekday: "long", day: "numeric", month: "long" }).format(this.day.date);
760
- return d`
761
- <div class="time-col">
762
- <div class="header-cell">Hora</div>
763
- ${this.slots.map((a) => d`<div class="slot-cell time-slot-label">${a.start}</div>`)}
764
- </div>
765
-
766
- <div class="day-col">
767
- <div class="header-cell ${e ? "today" : ""}">
768
- <div style="text-transform: capitalize;">${t}</div>
769
- </div>
770
-
771
- ${this.day.slots.map((a, i) => {
772
- var c, n;
773
- const r = a.isBlocked, l = this.isSlotSelected(a), o = this.isSlotDragSelecting(i);
774
- return d`
775
- <div
776
- class=${I({
777
- "slot-cell": !0,
778
- available: !r,
779
- blocked: r,
780
- selected: l,
781
- "drag-selecting": o
782
- })}
783
- @mousedown=${() => this.handleMouseDown(i, r)}
784
- @mouseenter=${() => this.handleMouseEnter(i, r)}
785
- title=${r && ((c = a.rule) != null && c.description) ? a.rule.description : ""}
786
- >
787
- ${r ? ((n = a.rule) == null ? void 0 : n.description) || "Ocupado" : l ? "Reservado" : ""}
788
- </div>
789
- `;
790
- })}
791
- </div>
792
- `;
793
- }
794
- };
795
- D.styles = E`
796
- :host {
797
- display: grid; grid-template-columns: var(--glatam-time-col-width) 1fr; gap: 2px;
798
- width: 100%; background-color: var(--glatam-border); border: 1px solid var(--glatam-border);
799
- border-radius: var(--glatam-grid-border-radius); overflow: hidden; user-select: none;
800
- }
801
- .time-col { background-color: var(--glatam-surface); display: flex; flex-direction: column; }
802
- .day-col { background-color: var(--glatam-bg); display: flex; flex-direction: column; }
803
- .header-cell {
804
- height: 60px; display: flex; flex-direction: column; align-items: center; justify-content: center;
805
- background-color: var(--glatam-surface); border-bottom: 2px solid var(--glatam-border);
806
- font-size: 0.875rem; font-weight: 500;
807
- }
808
- .header-cell.today { color: var(--glatam-primary); font-weight: 700; }
809
- .slot-cell {
810
- height: var(--glatam-slot-height); border-bottom: 1px solid var(--glatam-border);
811
- display: flex; align-items: center; justify-content: center; font-size: 0.75rem;
812
- cursor: pointer; transition: background-color var(--glatam-transition-fast); position: relative;
813
- }
814
- .time-slot-label { font-size: 0.7rem; color: var(--glatam-text-secondary); }
815
- .slot-cell.available:hover { background-color: var(--glatam-surface); }
816
- .slot-cell.blocked {
817
- background-color: var(--glatam-blocked-bg);
818
- background-image: repeating-linear-gradient(45deg, transparent, transparent 5px, var(--glatam-blocked-stripe) 5px, var(--glatam-blocked-stripe) 10px);
819
- color: var(--glatam-blocked-text); cursor: not-allowed; font-weight: 600; padding: 0 10px;
820
- white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
821
- }
822
- .slot-cell.selected { background-color: var(--glatam-selection-bg); border-left: 3px solid var(--glatam-selection-border); }
823
- .slot-cell.drag-selecting { background-color: var(--glatam-primary-light); }
824
- `;
825
- z([
826
- s({ type: Object })
827
- ], D.prototype, "day", 2);
828
- z([
829
- s({ type: Array })
830
- ], D.prototype, "slots", 2);
831
- z([
832
- s({ type: String })
833
- ], D.prototype, "locale", 2);
834
- z([
835
- s({ type: Object })
836
- ], D.prototype, "selectedRange", 2);
837
- z([
838
- s({ type: String })
839
- ], D.prototype, "role", 2);
840
- z([
841
- m()
842
- ], D.prototype, "isDragging", 2);
843
- z([
844
- m()
845
- ], D.prototype, "dragStartSlotIndex", 2);
846
- z([
847
- m()
848
- ], D.prototype, "dragEndSlotIndex", 2);
849
- D = z([
850
- T("glatam-calendar-day-view")
851
- ], D);
852
- var V = Object.defineProperty, Y = Object.getOwnPropertyDescriptor, $ = (e, t, a, i) => {
853
- for (var r = i > 1 ? void 0 : i ? Y(t, a) : t, l = e.length - 1, o; l >= 0; l--)
854
- (o = e[l]) && (r = (i ? o(t, a, r) : o(r)) || r);
855
- return i && r && V(t, a, r), r;
856
- };
857
- let x = class extends O {
858
- constructor() {
859
- super(...arguments), this.open = !1, this.dateString = "", this.startTime = "", this.endTime = "", this.isRange = !1, this.existingRule = null, this.description = "", this.blockAllDay = !0, this.isRecurring = !1, this.selectedDays = [];
860
- }
861
- willUpdate(e) {
862
- e.has("open") && this.open && (this.existingRule ? (this.description = "Bloqueo", this.blockAllDay = !this.existingRule.slots || this.existingRule.slots.length === 0, this.isRecurring = this.existingRule.type === "weekly", this.selectedDays = this.existingRule.daysOfWeek || []) : (this.description = "", this.blockAllDay = !this.isRange, this.isRecurring = !1, this.selectedDays = [(/* @__PURE__ */ new Date(this.dateString + "T00:00:00")).getDay()]));
863
- }
864
- toggleDay(e) {
865
- this.selectedDays.indexOf(e) > -1 ? this.selectedDays = this.selectedDays.filter((a) => a !== e) : this.selectedDays = [...this.selectedDays, e];
866
- }
867
- handleSave() {
868
- const e = {
869
- title: this.description || "Bloqueo",
870
- blockAllDay: this.blockAllDay,
871
- isRecurring: this.isRecurring,
872
- selectedDays: this.selectedDays,
873
- dateString: this.dateString,
874
- startTime: this.startTime,
875
- endTime: this.endTime
876
- };
877
- this.dispatchEvent(new CustomEvent("save-rule", { detail: e, bubbles: !0, composed: !0 }));
878
- }
879
- handleDelete() {
880
- this.existingRule && this.dispatchEvent(new CustomEvent("delete-rule", {
881
- detail: { id: this.existingRule.id },
882
- bubbles: !0,
883
- composed: !0
884
- }));
885
- }
886
- render() {
887
- const e = ["D", "L", "M", "M", "J", "V", "S"], t = this.isRange ? `${this.dateString} (${this.startTime} - ${this.endTime})` : this.dateString;
888
- return d`
889
- <div class=${I({ "modal-overlay": !0, open: this.open })}>
890
- <div class="modal-content">
891
- <h3>${this.existingRule ? "Gestionar Bloqueo" : "Crear Bloqueo"}</h3>
892
-
893
- <div style="font-size: 0.85rem; color: var(--glatam-text-secondary);">
894
- Selección: <strong>${t}</strong>
895
- </div>
896
-
897
- <div class="form-group">
898
- <label>Descripción / Nota</label>
899
- <input
900
- type="text"
901
- .value=${this.description}
902
- @input=${(a) => this.description = a.target.value}
903
- placeholder="Ej. Reunión de equipo, Vacaciones"
904
- />
905
- </div>
906
-
907
- <div class="switch-row">
908
- <label>Bloquear todo el día</label>
909
- <label class="switch">
910
- <input
911
- type="checkbox"
912
- .checked=${this.blockAllDay}
913
- @change=${(a) => this.blockAllDay = a.target.checked}
914
- />
915
- <span class="slider"></span>
916
- </label>
917
- </div>
918
-
919
- <div class="switch-row">
920
- <label>Repetir semanalmente</label>
921
- <label class="switch">
922
- <input
923
- type="checkbox"
924
- .checked=${this.isRecurring}
925
- @change=${(a) => this.isRecurring = a.target.checked}
926
- />
927
- <span class="slider"></span>
928
- </label>
929
- </div>
930
-
931
- ${this.isRecurring ? d`
932
- <div class="form-group">
933
- <label>Repetir los días</label>
934
- <div class="days-grid">
935
- ${[1, 2, 3, 4, 5, 6, 0].map((a) => d`
936
- <button
937
- class="day-btn ${this.selectedDays.includes(a) ? "selected" : ""}"
938
- @click=${() => this.toggleDay(a)}
939
- >
940
- ${e[a]}
941
- </button>
942
- `)}
943
- </div>
944
- </div>
945
- ` : ""}
946
-
947
- <div class="btn-actions">
948
- ${this.existingRule ? d`<button class="btn btn-danger" @click=${this.handleDelete}>Eliminar</button>` : ""}
949
- <button class="btn btn-cancel" @click=${() => this.dispatchEvent(new CustomEvent("close"))}>Cancelar</button>
950
- <button class="btn btn-save" @click=${this.handleSave}>Guardar</button>
951
- </div>
952
- </div>
953
- </div>
954
- `;
955
- }
956
- };
957
- x.styles = E`
958
- .modal-overlay {
959
- position: fixed;
960
- top: 0; left: 0; right: 0; bottom: 0;
961
- background: rgba(0, 0, 0, 0.35);
962
- backdrop-filter: blur(10px);
963
- display: flex;
964
- align-items: center;
965
- justify-content: center;
966
- z-index: 1000;
967
- opacity: 0; pointer-events: none;
968
- transition: opacity var(--glatam-transition-normal);
969
- }
970
- .modal-overlay.open {
971
- opacity: 1; pointer-events: auto;
972
- }
973
- .modal-content {
974
- background: var(--glatam-bg);
975
- color: var(--glatam-text);
976
- border-radius: 24px;
977
- padding: 28px;
978
- width: 90%;
979
- max-width: 400px;
980
- box-shadow: 0 20px 50px rgba(0, 0, 0, 0.12);
981
- border: 1px solid var(--glatam-border);
982
- transform: scale(0.92) translateY(10px);
983
- transition: transform var(--glatam-transition-normal), background-color var(--glatam-transition-normal);
984
- display: flex;
985
- flex-direction: column;
986
- gap: 18px;
987
- }
988
- .modal-overlay.open .modal-content {
989
- transform: scale(1) translateY(0);
990
- }
991
- h3 { margin: 0; font-size: 1.3rem; font-weight: 700; letter-spacing: -0.02em; }
992
- .form-group { display: flex; flex-direction: column; gap: 6px; }
993
- label { font-size: 0.8rem; color: var(--glatam-text-secondary); font-weight: 600; }
994
- input[type="text"] {
995
- background: var(--glatam-surface);
996
- border: 1px solid var(--glatam-border);
997
- border-radius: 10px;
998
- padding: 10px 14px;
999
- color: var(--glatam-text);
1000
- font-family: inherit;
1001
- font-size: 0.9rem;
1002
- outline: none;
1003
- transition: border-color var(--glatam-transition-fast);
1004
- }
1005
- input[type="text"]:focus {
1006
- border-color: var(--glatam-primary);
1007
- }
1008
- .switch-row {
1009
- display: flex;
1010
- justify-content: space-between;
1011
- align-items: center;
1012
- padding: 4px 0;
1013
- }
1014
-
1015
- /* Apple Switch Style */
1016
- .switch {
1017
- position: relative;
1018
- display: inline-block;
1019
- width: 46px;
1020
- height: 26px;
1021
- }
1022
- .switch input { opacity: 0; width: 0; height: 0; }
1023
- .slider {
1024
- position: absolute;
1025
- cursor: pointer;
1026
- top: 0; left: 0; right: 0; bottom: 0;
1027
- background-color: var(--glatam-border);
1028
- transition: .25s cubic-bezier(0.16, 1, 0.3, 1);
1029
- border-radius: 26px;
1030
- }
1031
- .slider:before {
1032
- position: absolute;
1033
- content: "";
1034
- height: 20px;
1035
- width: 20px;
1036
- left: 3px;
1037
- bottom: 3px;
1038
- background-color: white;
1039
- transition: .25s cubic-bezier(0.16, 1, 0.3, 1);
1040
- border-radius: 50%;
1041
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
1042
- }
1043
- input:checked + .slider {
1044
- background-color: var(--glatam-primary);
1045
- }
1046
- input:checked + .slider:before {
1047
- transform: translateX(20px);
1048
- }
1049
-
1050
- .days-grid {
1051
- display: grid;
1052
- grid-template-columns: repeat(7, 1fr);
1053
- gap: 6px;
1054
- margin-top: 4px;
1055
- }
1056
- .day-btn {
1057
- width: 36px;
1058
- height: 36px;
1059
- margin: 0 auto;
1060
- border-radius: 50%;
1061
- border: 1px solid var(--glatam-border);
1062
- background: var(--glatam-bg);
1063
- color: var(--glatam-text);
1064
- font-size: 0.8rem;
1065
- font-weight: 600;
1066
- cursor: pointer;
1067
- display: flex;
1068
- align-items: center;
1069
- justify-content: center;
1070
- transition: background-color var(--glatam-transition-fast), color var(--glatam-transition-fast), border-color var(--glatam-transition-fast);
1071
- }
1072
- .day-btn:hover {
1073
- background-color: var(--glatam-surface);
1074
- }
1075
- .day-btn.selected {
1076
- background: var(--glatam-primary);
1077
- color: var(--glatam-text-light);
1078
- border-color: var(--glatam-primary);
1079
- }
1080
- .btn-actions { display: flex; gap: 10px; margin-top: 10px; justify-content: flex-end; }
1081
- .btn {
1082
- padding: 10px 18px;
1083
- border-radius: 20px;
1084
- font-size: 0.875rem;
1085
- font-weight: 600;
1086
- cursor: pointer;
1087
- border: none;
1088
- transition: opacity var(--glatam-transition-fast), transform var(--glatam-transition-fast);
1089
- display: inline-flex;
1090
- align-items: center;
1091
- justify-content: center;
1092
- }
1093
- .btn:active { transform: scale(0.97); }
1094
- .btn-cancel { background: transparent; color: var(--glatam-text); border: 1px solid var(--glatam-border); }
1095
- .btn-cancel:hover { background-color: var(--glatam-surface); }
1096
- .btn-save { background: var(--glatam-primary); color: var(--glatam-text-light); }
1097
- .btn-save:hover { opacity: 0.95; }
1098
- .btn-danger {
1099
- background: rgba(255, 69, 58, 0.12);
1100
- color: #ff453a;
1101
- margin-right: auto;
1102
- }
1103
- .btn-danger:hover {
1104
- background: rgba(255, 69, 58, 0.18);
1105
- }
1106
- `;
1107
- $([
1108
- s({ type: Boolean })
1109
- ], x.prototype, "open", 2);
1110
- $([
1111
- s({ type: String })
1112
- ], x.prototype, "dateString", 2);
1113
- $([
1114
- s({ type: String })
1115
- ], x.prototype, "startTime", 2);
1116
- $([
1117
- s({ type: String })
1118
- ], x.prototype, "endTime", 2);
1119
- $([
1120
- s({ type: Boolean })
1121
- ], x.prototype, "isRange", 2);
1122
- $([
1123
- s({ type: Object })
1124
- ], x.prototype, "existingRule", 2);
1125
- $([
1126
- m()
1127
- ], x.prototype, "description", 2);
1128
- $([
1129
- m()
1130
- ], x.prototype, "blockAllDay", 2);
1131
- $([
1132
- m()
1133
- ], x.prototype, "isRecurring", 2);
1134
- $([
1135
- m()
1136
- ], x.prototype, "selectedDays", 2);
1137
- x = $([
1138
- T("glatam-calendar-modal")
1139
- ], x);
1140
- var Z = Object.defineProperty, J = Object.getOwnPropertyDescriptor, h = (e, t, a, i) => {
1141
- for (var r = i > 1 ? void 0 : i ? J(t, a) : t, l = e.length - 1, o; l >= 0; l--)
1142
- (o = e[l]) && (r = (i ? o(t, a, r) : o(r)) || r);
1143
- return i && r && Z(t, a, r), r;
1144
- };
1145
- const X = [
1146
- { start: "09:00", end: "10:00" },
1147
- { start: "10:00", end: "11:00" },
1148
- { start: "11:00", end: "12:00" },
1149
- { start: "12:00", end: "13:00" },
1150
- { start: "13:00", end: "14:00" },
1151
- { start: "14:00", end: "15:00" },
1152
- { start: "15:00", end: "16:00" },
1153
- { start: "16:00", end: "17:00" },
1154
- { start: "17:00", end: "18:00" }
1155
- ];
1156
- let p = class extends O {
1157
- constructor() {
1158
- super(...arguments), this.role = "provider", this.size = "medium", this.view = "month", this.locale = "es", this.startOfWeekDay = 0, this.rules = [], this.selectedDates = [], this.selectedRange = null, this.hostTimezone = "America/Bogota", this.activeTimezone = "local", this.slots = X, this.minDate = "", this.maxDate = "", this.showNeighboringMonth = !0, this.tileClassName = null, this.activeDate = /* @__PURE__ */ new Date(), this.localRules = [], this.darkMode = !1, this.modalOpen = !1, this.modalDateString = "", this.modalStartTime = "", this.modalEndTime = "", this.modalIsRange = !1, this.modalExistingRule = null;
1159
- }
1160
- firstUpdated() {
1161
- this.darkMode = window.matchMedia("(prefers-color-scheme: dark)").matches, this.localRules = [...this.rules];
1162
- }
1163
- willUpdate(e) {
1164
- e.has("rules") && this.rules.length > 0 && this.localRules.length === 0 && (this.localRules = [...this.rules]);
1165
- }
1166
- updated(e) {
1167
- e.has("darkMode") && this.classList.toggle("dark-mode", this.darkMode);
1168
- }
1169
- handlePrev() {
1170
- const e = new Date(this.activeDate);
1171
- this.view === "month" ? e.setMonth(e.getMonth() - 1) : this.view === "week" ? e.setDate(e.getDate() - 7) : e.setDate(e.getDate() - 1), this.activeDate = e;
1172
- }
1173
- handleNext() {
1174
- const e = new Date(this.activeDate);
1175
- this.view === "month" ? e.setMonth(e.getMonth() + 1) : this.view === "week" ? e.setDate(e.getDate() + 7) : e.setDate(e.getDate() + 1), this.activeDate = e;
1176
- }
1177
- getHeaderTitle() {
1178
- const e = this.view === "month" ? { month: "long", year: "numeric" } : this.view === "week" ? { month: "short", year: "numeric" } : { day: "numeric", month: "long", year: "numeric" };
1179
- return new Intl.DateTimeFormat(this.locale, e).format(this.activeDate);
1180
- }
1181
- handleDaySelect(e) {
1182
- const { dateString: t, isBlocked: a } = e.detail;
1183
- this.role === "buyer" && a || (this.activeDate = /* @__PURE__ */ new Date(t + "T00:00:00"), this.view = "day", this.dispatchEvent(new CustomEvent("date-selected", { detail: { dateString: t }, bubbles: !0, composed: !0 })));
1184
- }
1185
- handleRangeSelect(e) {
1186
- var u, v;
1187
- const { dateString: t, start: a, end: i } = e.detail, r = this.activeTimezone === "local" ? C(this.activeDate, this.hostTimezone, "local") : 0, l = this.getDisplaySlots(r), o = l.findIndex((S) => S.start === a), c = l.findIndex((S) => S.end === i), n = ((u = this.slots[o]) == null ? void 0 : u.start) || a, g = ((v = this.slots[c]) == null ? void 0 : v.end) || i;
1188
- if (this.role === "buyer") {
1189
- this.selectedRange = { dateString: t, start: a, end: i }, this.dispatchEvent(new CustomEvent("booking-selected", { detail: { dateString: t, start: a, end: i, hostStart: n, hostEnd: g }, bubbles: !0, composed: !0 }));
1190
- return;
1191
- }
1192
- this.openModal(t, n, g, !0, null);
1193
- }
1194
- handleSlotClick(e) {
1195
- const { dateString: t, slot: a } = e.detail, i = /* @__PURE__ */ new Date(t + "T00:00:00"), r = this.activeTimezone === "local" ? C(this.activeDate, this.hostTimezone, "local") : 0, l = this.getDisplaySlots(r), o = l.findIndex((g) => g.start === a.start), c = this.slots[o] || a;
1196
- if (this.role === "buyer") {
1197
- this.selectedRange = { dateString: t, start: a.start, end: a.end }, this.dispatchEvent(new CustomEvent("booking-selected", { detail: { dateString: t, start: a.start, end: a.end, hostStart: c.start, hostEnd: c.end }, bubbles: !0, composed: !0 }));
1198
- return;
1199
- }
1200
- const n = this.localRules.find((g) => M(i, c, [g]));
1201
- this.openModal(t, c.start, c.end, !0, n || null);
1202
- }
1203
- handleBlockDayAction() {
1204
- const e = N(this.activeDate), t = this.localRules.find((a) => M(this.activeDate, void 0, [a]));
1205
- this.openModal(e, "", "", !1, t || null);
1206
- }
1207
- openModal(e, t, a, i, r) {
1208
- this.modalDateString = e, this.modalStartTime = t, this.modalEndTime = a, this.modalIsRange = i, this.modalExistingRule = r, this.modalOpen = !0;
1209
- }
1210
- handleSaveRule(e) {
1211
- const t = e.detail, a = this.modalExistingRule ? this.modalExistingRule.id : `rule-${Date.now()}`, i = {
1212
- id: a,
1213
- type: t.isRecurring ? "weekly" : "date-range",
1214
- slots: t.blockAllDay ? void 0 : [{ start: t.startTime, end: t.endTime }],
1215
- daysOfWeek: t.isRecurring ? t.selectedDays : void 0,
1216
- startDate: t.isRecurring ? void 0 : t.dateString,
1217
- endDate: t.isRecurring ? void 0 : t.dateString,
1218
- description: t.title
1219
- };
1220
- this.localRules = this.modalExistingRule ? this.localRules.map((r) => r.id === a ? i : r) : [...this.localRules, i], this.modalOpen = !1, this.dispatchEvent(new CustomEvent("rules-changed", { detail: { rules: this.localRules }, bubbles: !0, composed: !0 }));
1221
- }
1222
- handleDeleteRule(e) {
1223
- this.localRules = this.localRules.filter((t) => t.id !== e.detail.id), this.modalOpen = !1, this.dispatchEvent(new CustomEvent("rules-changed", { detail: { rules: this.localRules }, bubbles: !0, composed: !0 }));
1224
- }
1225
- getDisplaySlots(e) {
1226
- return e === 0 ? this.slots : this.slots.map((t) => {
1227
- const a = W(t, e), i = a.dayShift > 0 ? " (+1d)" : a.dayShift < 0 ? " (-1d)" : "";
1228
- return { start: a.start + i, end: a.end + i };
1229
- });
1230
- }
1231
- render() {
1232
- var c;
1233
- const e = this.activeDate.getFullYear(), t = this.activeDate.getMonth(), a = M(this.activeDate, void 0, this.localRules), i = this.activeTimezone === "local" ? C(this.activeDate, this.hostTimezone, "local") : 0, r = this.getDisplaySlots(i), l = (n) => n.map((g) => ({ ...g, slots: g.slots.map((u, v) => {
1234
- var S, B;
1235
- return { ...u, start: ((S = r[v]) == null ? void 0 : S.start) || u.start, end: ((B = r[v]) == null ? void 0 : B.end) || u.end };
1236
- }) })), o = ((c = this.hostTimezone.split("/").pop()) == null ? void 0 : c.replace("_", " ")) || "Anfitrión";
1237
- return d`
1238
- <div class="calendar-header">
1239
- <div class="nav-group">
1240
- <button class="btn" @click=${() => this.activeDate = /* @__PURE__ */ new Date()}>Hoy</button>
1241
- <button class="btn" @click=${this.handlePrev}>&lt;</button>
1242
- <button class="btn" @click=${this.handleNext}>&gt;</button>
1243
- <span class="nav-title" style="text-transform: capitalize;">${this.getHeaderTitle()}</span>
1244
- </div>
1245
-
1246
- <div class="view-group">
1247
- ${this.role === "provider" ? d`
1248
- <div class="timezone-badge">
1249
- 🌐 Zona:
1250
- <select class="timezone-select" @change=${(n) => this.activeTimezone = n.target.value}>
1251
- <option value="local" ?selected=${this.activeTimezone === "local"}>Mi Hora</option>
1252
- <option value="host" ?selected=${this.activeTimezone === "host"}>Hora ${o}</option>
1253
- </select>
1254
- </div>
1255
- ` : ""}
1256
- ${this.role === "provider" && this.view === "day" ? d`<button class="btn btn-primary" @click=${this.handleBlockDayAction} style="margin-right: 8px;">${a ? "Liberar Día" : "Bloquear Día"}</button>` : ""}
1257
- <button class="btn" @click=${() => this.darkMode = !this.darkMode} style="margin-right: 8px;">${this.darkMode ? "☀️" : "🌙"}</button>
1258
- <div class="btn-group">
1259
- <button class="btn ${this.view === "month" ? "active" : ""}" @click=${() => this.view = "month"}>Mes</button>
1260
- <button class="btn ${this.view === "week" ? "active" : ""}" @click=${() => this.view = "week"}>Semana</button>
1261
- <button class="btn ${this.view === "day" ? "active" : ""}" @click=${() => this.view = "day"}>Día</button>
1262
- </div>
1263
- </div>
1264
- </div>
1265
-
1266
- <div class="calendar-body">
1267
- ${this.view === "month" ? d`<glatam-calendar-month-view .days=${j(e, t, this.localRules, this.slots, this.startOfWeekDay)} .locale=${this.locale} .startOfWeekDay=${this.startOfWeekDay} .role=${this.role} .size=${this.size} .minDate=${this.minDate} .maxDate=${this.maxDate} .showNeighboringMonth=${this.showNeighboringMonth} .tileClassName=${this.tileClassName} @day-select=${this.handleDaySelect}></glatam-calendar-month-view>` : this.view === "week" ? d`<glatam-calendar-week-view .days=${l(_(this.activeDate, this.localRules, this.slots, this.startOfWeekDay))} .slots=${r} .locale=${this.locale} .selectedRange=${this.selectedRange} .role=${this.role} @range-select=${this.handleRangeSelect} @slot-click=${this.handleSlotClick}></glatam-calendar-week-view>` : d`<glatam-calendar-day-view .day=${l(_(this.activeDate, this.localRules, this.slots, this.startOfWeekDay)).find((n) => n.dateString === N(this.activeDate)) || null} .slots=${r} .locale=${this.locale} .selectedRange=${this.selectedRange} .role=${this.role} @range-select=${this.handleRangeSelect} @slot-click=${this.handleSlotClick}></glatam-calendar-day-view>`}
1268
- </div>
1269
-
1270
- <glatam-calendar-modal
1271
- .open=${this.modalOpen} .dateString=${this.modalDateString} .startTime=${this.modalStartTime} .endTime=${this.modalEndTime}
1272
- .isRange=${this.modalIsRange} .existingRule=${this.modalExistingRule} @save-rule=${this.handleSaveRule}
1273
- @delete-rule=${this.handleDeleteRule} @close=${() => this.modalOpen = !1}
1274
- ></glatam-calendar-modal>
1275
- `;
1276
- }
1277
- };
1278
- p.styles = [A, P];
1279
- h([
1280
- s({ type: String })
1281
- ], p.prototype, "role", 2);
1282
- h([
1283
- s({ type: String, reflect: !0 })
1284
- ], p.prototype, "size", 2);
1285
- h([
1286
- s({ type: String })
1287
- ], p.prototype, "view", 2);
1288
- h([
1289
- s({ type: String })
1290
- ], p.prototype, "locale", 2);
1291
- h([
1292
- s({ type: Number })
1293
- ], p.prototype, "startOfWeekDay", 2);
1294
- h([
1295
- s({ type: Array })
1296
- ], p.prototype, "rules", 2);
1297
- h([
1298
- s({ type: Array })
1299
- ], p.prototype, "selectedDates", 2);
1300
- h([
1301
- s({ type: Object })
1302
- ], p.prototype, "selectedRange", 2);
1303
- h([
1304
- s({ type: String })
1305
- ], p.prototype, "hostTimezone", 2);
1306
- h([
1307
- s({ type: String })
1308
- ], p.prototype, "activeTimezone", 2);
1309
- h([
1310
- s({ type: Array })
1311
- ], p.prototype, "slots", 2);
1312
- h([
1313
- s({ type: String })
1314
- ], p.prototype, "minDate", 2);
1315
- h([
1316
- s({ type: String })
1317
- ], p.prototype, "maxDate", 2);
1318
- h([
1319
- s({ type: Boolean })
1320
- ], p.prototype, "showNeighboringMonth", 2);
1321
- h([
1322
- s({ attribute: !1 })
1323
- ], p.prototype, "tileClassName", 2);
1324
- h([
1325
- m()
1326
- ], p.prototype, "activeDate", 2);
1327
- h([
1328
- m()
1329
- ], p.prototype, "localRules", 2);
1330
- h([
1331
- m()
1332
- ], p.prototype, "darkMode", 2);
1333
- h([
1334
- m()
1335
- ], p.prototype, "modalOpen", 2);
1336
- h([
1337
- m()
1338
- ], p.prototype, "modalDateString", 2);
1339
- h([
1340
- m()
1341
- ], p.prototype, "modalStartTime", 2);
1342
- h([
1343
- m()
1344
- ], p.prototype, "modalEndTime", 2);
1345
- h([
1346
- m()
1347
- ], p.prototype, "modalIsRange", 2);
1348
- h([
1349
- m()
1350
- ], p.prototype, "modalExistingRule", 2);
1351
- p = h([
1352
- T("glatam-calendar")
1353
- ], p);
1354
- var K = Object.defineProperty, Q = Object.getOwnPropertyDescriptor, y = (e, t, a, i) => {
1355
- for (var r = i > 1 ? void 0 : i ? Q(t, a) : t, l = e.length - 1, o; l >= 0; l--)
1356
- (o = e[l]) && (r = (i ? o(t, a, r) : o(r)) || r);
1357
- return i && r && K(t, a, r), r;
1358
- };
1359
- let b = class extends O {
1360
- constructor() {
1361
- super(...arguments), this.role = "buyer", this.locale = "es", this.startOfWeekDay = 0, this.rules = [], this.selectedRange = null, this.size = "medium", this.hostTimezone = "America/Bogota", this.activeTimezone = "local", this.minDate = "", this.maxDate = "", this.showNeighboringMonth = !0, this.tileClassName = null, this.slots = [
1362
- { start: "09:00", end: "10:00" },
1363
- { start: "10:00", end: "11:00" },
1364
- { start: "11:00", end: "12:00" },
1365
- { start: "12:00", end: "13:00" },
1366
- { start: "13:00", end: "14:00" },
1367
- { start: "14:00", end: "15:00" },
1368
- { start: "15:00", end: "16:00" },
1369
- { start: "16:00", end: "17:00" },
1370
- { start: "17:00", end: "18:00" }
1371
- ], this.activeDate = /* @__PURE__ */ new Date(), this.dropdownOpen = !1, this.dropdownSelectedDateString = "";
1372
- }
1373
- handleDropdownDaySelect(e) {
1374
- this.dropdownSelectedDateString = e.detail.dateString;
1375
- }
1376
- selectDropdownSlot(e) {
1377
- const t = {
1378
- dateString: this.dropdownSelectedDateString,
1379
- start: e.displayStart,
1380
- end: e.displayEnd,
1381
- hostStart: e.start,
1382
- hostEnd: e.end
1383
- };
1384
- this.selectedRange = { dateString: this.dropdownSelectedDateString, start: e.displayStart, end: e.displayEnd }, this.dispatchEvent(new CustomEvent("booking-selected", { detail: t, bubbles: !0, composed: !0 })), this.dropdownOpen = !1, this.dropdownSelectedDateString = "";
1385
- }
1386
- render() {
1387
- const e = this.selectedRange ? `Reserva: ${this.selectedRange.dateString} (${this.selectedRange.start} - ${this.selectedRange.end})` : "Seleccionar Fecha y Hora", t = this.activeDate.getFullYear(), a = this.activeDate.getMonth(), i = this.dropdownSelectedDateString ? /* @__PURE__ */ new Date(this.dropdownSelectedDateString + "T00:00:00") : null, r = i && this.activeTimezone === "local" ? C(i, this.hostTimezone, "local") : 0, l = i ? this.slots.map((o) => {
1388
- const c = M(i, o, this.rules), n = W(o, r), g = n.dayShift > 0 ? " (+1d)" : n.dayShift < 0 ? " (-1d)" : "";
1389
- return {
1390
- ...o,
1391
- displayStart: n.start + g,
1392
- displayEnd: n.end + g,
1393
- isBlocked: c
1394
- };
1395
- }) : [];
1396
- return d`
1397
- <div class="dropdown-container">
1398
- <button class="btn btn-primary dropdown-toggle" @click=${() => this.dropdownOpen = !this.dropdownOpen}>
1399
- <span>${e}</span> <span>${this.dropdownOpen ? "▲" : "▼"}</span>
1400
- </button>
1401
-
1402
- ${this.dropdownOpen ? d`
1403
- <div class="dropdown-card" style="--glatam-day-min-height: 38px;">
1404
- ${this.dropdownSelectedDateString ? d`
1405
- <div style="display:flex; justify-content:space-between; align-items:center; border-bottom: 1px solid var(--glatam-border); padding-bottom:8px;">
1406
- <button class="btn" style="height:28px; padding:0 8px; font-size:0.75rem;" @click=${() => this.dropdownSelectedDateString = ""}>&lt; Volver</button>
1407
- <span style="font-size:0.8rem; font-weight:600; color: var(--glatam-text);">${this.dropdownSelectedDateString}</span>
1408
- </div>
1409
- <div class="slot-list">
1410
- ${l.map((o) => d`
1411
- <button
1412
- class="slot-btn ${o.isBlocked ? "blocked" : ""}"
1413
- ?disabled=${o.isBlocked}
1414
- @click=${() => this.selectDropdownSlot(o)}
1415
- >
1416
- ${o.displayStart} - ${o.displayEnd} ${o.isBlocked ? "(Ocupado)" : ""}
1417
- </button>
1418
- `)}
1419
- </div>
1420
- ` : d`
1421
- <div style="font-weight:600; font-size:0.9rem; text-align:center; color: var(--glatam-text);">Selecciona un Día</div>
1422
- <glatam-calendar-month-view
1423
- .days=${j(t, a, this.rules, this.slots, this.startOfWeekDay)}
1424
- .locale=${this.locale}
1425
- .startOfWeekDay=${this.startOfWeekDay}
1426
- .role=${this.role}
1427
- size="small"
1428
- .minDate=${this.minDate}
1429
- .maxDate=${this.maxDate}
1430
- .showNeighboringMonth=${this.showNeighboringMonth}
1431
- .tileClassName=${this.tileClassName}
1432
- @day-select=${this.handleDropdownDaySelect}
1433
- ></glatam-calendar-month-view>
1434
- `}
1435
- </div>
1436
- ` : ""}
1437
- </div>
1438
- `;
1439
- }
1440
- };
1441
- b.styles = [
1442
- A,
1443
- P,
1444
- E`
1445
- :host {
1446
- display: inline-block;
1447
- background: transparent;
1448
- border: none;
1449
- padding: 0;
1450
- box-shadow: none;
1451
- width: 100%;
1452
- }
1453
- `
1454
- ];
1455
- y([
1456
- s({ type: String })
1457
- ], b.prototype, "role", 2);
1458
- y([
1459
- s({ type: String })
1460
- ], b.prototype, "locale", 2);
1461
- y([
1462
- s({ type: Number })
1463
- ], b.prototype, "startOfWeekDay", 2);
1464
- y([
1465
- s({ type: Array })
1466
- ], b.prototype, "rules", 2);
1467
- y([
1468
- s({ type: Object })
1469
- ], b.prototype, "selectedRange", 2);
1470
- y([
1471
- s({ type: String, reflect: !0 })
1472
- ], b.prototype, "size", 2);
1473
- y([
1474
- s({ type: String })
1475
- ], b.prototype, "hostTimezone", 2);
1476
- y([
1477
- s({ type: String })
1478
- ], b.prototype, "activeTimezone", 2);
1479
- y([
1480
- s({ type: String })
1481
- ], b.prototype, "minDate", 2);
1482
- y([
1483
- s({ type: String })
1484
- ], b.prototype, "maxDate", 2);
1485
- y([
1486
- s({ type: Boolean })
1487
- ], b.prototype, "showNeighboringMonth", 2);
1488
- y([
1489
- s({ attribute: !1 })
1490
- ], b.prototype, "tileClassName", 2);
1491
- y([
1492
- s({ type: Array })
1493
- ], b.prototype, "slots", 2);
1494
- y([
1495
- m()
1496
- ], b.prototype, "activeDate", 2);
1497
- y([
1498
- m()
1499
- ], b.prototype, "dropdownOpen", 2);
1500
- y([
1501
- m()
1502
- ], b.prototype, "dropdownSelectedDateString", 2);
1503
- b = y([
1504
- T("glatam-calendar-mini")
1505
- ], b);
1506
- export {
1507
- p as GlatamCalendar,
1508
- D as GlatamCalendarDayView,
1509
- b as GlatamCalendarMini,
1510
- x as GlatamCalendarModal,
1511
- f as GlatamCalendarMonthView,
1512
- w as GlatamCalendarWeekView,
1513
- P as calendarStyles,
1514
- st as formatISODate,
1515
- lt as isTimeBlocked,
1516
- nt as parseISODate,
1517
- A as variablesStyles
1518
- };