@dialiq/calendar-component 1.0.4 → 1.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.js CHANGED
@@ -7531,7 +7531,426 @@ const CreateBookingModal = ({ businessId, apiBaseUrl, initialDate, participants:
7531
7531
  React.createElement("button", { type: "submit", className: "modal-btn modal-btn-primary", disabled: loading }, loading ? 'Creating...' : 'Create Booking'))))));
7532
7532
  };
7533
7533
 
7534
- var css_248z = ".calendar-container {\n width: 100%;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n background: #ffffff;\n border-radius: 8px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n overflow: hidden;\n}\n\n.calendar-header {\n background: #f8f9fa;\n padding: 20px;\n border-bottom: 1px solid #e9ecef;\n}\n\n.calendar-title-section {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 16px;\n gap: 16px;\n flex-wrap: wrap;\n}\n\n.calendar-title {\n margin: 0;\n font-size: 24px;\n font-weight: 600;\n color: #212529;\n}\n\n.calendar-view-toggle {\n display: flex;\n gap: 4px;\n background: #e9ecef;\n padding: 4px;\n border-radius: 6px;\n}\n\n.calendar-btn-view {\n padding: 6px 14px;\n border: none;\n background: transparent;\n font-size: 13px;\n}\n\n.calendar-btn-view.active {\n background: #ffffff;\n color: #0d6efd;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n.calendar-btn-view:hover {\n background: #ffffff;\n border-color: transparent;\n}\n\n.calendar-navigation {\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.calendar-current-month {\n font-size: 18px;\n font-weight: 500;\n color: #495057;\n margin-left: 12px;\n}\n\n.calendar-btn {\n padding: 8px 16px;\n border: 1px solid #dee2e6;\n background: #ffffff;\n border-radius: 4px;\n cursor: pointer;\n font-size: 14px;\n font-weight: 500;\n color: #495057;\n transition: all 0.2s;\n}\n\n.calendar-btn:hover {\n background: #e9ecef;\n border-color: #adb5bd;\n}\n\n.calendar-btn-create {\n background: #0d6efd;\n color: #ffffff;\n border-color: #0d6efd;\n}\n\n.calendar-btn-create:hover {\n background: #0b5ed7;\n border-color: #0a58ca;\n}\n\n.calendar-days-row {\n display: grid;\n grid-template-columns: repeat(7, 1fr);\n background: #f8f9fa;\n border-bottom: 2px solid #dee2e6;\n}\n\n.calendar-day-header {\n padding: 12px;\n text-align: center;\n font-weight: 600;\n font-size: 14px;\n color: #6c757d;\n text-transform: uppercase;\n}\n\n.calendar-body {\n background: #ffffff;\n}\n\n.calendar-row {\n display: grid;\n grid-template-columns: repeat(7, 1fr);\n border-bottom: 1px solid #e9ecef;\n}\n\n.calendar-row:last-child {\n border-bottom: none;\n}\n\n.calendar-cell {\n min-height: 120px;\n padding: 8px;\n border-right: 1px solid #e9ecef;\n cursor: pointer;\n transition: background-color 0.2s;\n position: relative;\n}\n\n.calendar-cell:last-child {\n border-right: none;\n}\n\n.calendar-cell:hover {\n background: #f8f9fa;\n}\n\n.calendar-cell-disabled {\n background: #f8f9fa;\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.calendar-cell-disabled:hover {\n background: #f8f9fa;\n}\n\n.calendar-cell-today {\n background: #e7f5ff;\n}\n\n.calendar-cell-today .calendar-cell-number {\n background: #0d6efd;\n color: #ffffff;\n}\n\n.calendar-cell-number {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border-radius: 50%;\n font-weight: 600;\n font-size: 14px;\n color: #212529;\n margin-bottom: 4px;\n}\n\n.calendar-cell-bookings {\n margin-top: 4px;\n}\n\n.calendar-booking {\n background: #0d6efd;\n color: #ffffff;\n padding: 4px 8px;\n margin-bottom: 4px;\n border-radius: 4px;\n font-size: 12px;\n cursor: pointer;\n transition: background-color 0.2s;\n display: flex;\n gap: 4px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.calendar-booking:hover {\n background: #0b5ed7;\n}\n\n.calendar-booking-time {\n font-weight: 600;\n}\n\n.calendar-booking-title {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.calendar-booking-more {\n color: #6c757d;\n font-size: 11px;\n padding: 2px 4px;\n font-weight: 500;\n}\n\n.calendar-error {\n background: #f8d7da;\n color: #842029;\n padding: 12px 20px;\n border-bottom: 1px solid #f5c2c7;\n}\n\n.calendar-loading {\n background: #cff4fc;\n color: #055160;\n padding: 12px 20px;\n border-bottom: 1px solid #b6effb;\n text-align: center;\n}\n\n.calendar-week-view {\n display: grid;\n grid-template-columns: repeat(7, 1fr);\n gap: 1px;\n background: #e9ecef;\n padding: 1px;\n}\n\n.calendar-week-day {\n background: #ffffff;\n min-height: 400px;\n cursor: pointer;\n transition: background-color 0.2s;\n display: flex;\n flex-direction: column;\n}\n\n.calendar-week-day:hover {\n background: #f8f9fa;\n}\n\n.calendar-week-day-header {\n padding: 12px;\n border-bottom: 2px solid #e9ecef;\n text-align: center;\n background: #f8f9fa;\n}\n\n.calendar-week-day-name {\n font-size: 12px;\n font-weight: 600;\n color: #6c757d;\n text-transform: uppercase;\n margin-bottom: 4px;\n}\n\n.calendar-week-day-number {\n font-size: 20px;\n font-weight: 600;\n color: #212529;\n}\n\n.calendar-week-day.calendar-cell-today .calendar-week-day-header {\n background: #e7f5ff;\n}\n\n.calendar-week-day.calendar-cell-today .calendar-week-day-number {\n color: #0d6efd;\n}\n\n.calendar-week-day-bookings {\n padding: 8px;\n flex: 1;\n overflow-y: auto;\n}\n\n.calendar-week-booking {\n margin-bottom: 6px;\n display: block;\n}\n\n.calendar-day-view {\n padding: 20px;\n background: #ffffff;\n}\n\n.calendar-day-container {\n max-width: 800px;\n margin: 0 auto;\n background: #ffffff;\n border: 1px solid #e9ecef;\n border-radius: 8px;\n overflow: hidden;\n}\n\n.calendar-day-container.calendar-cell-today {\n border-color: #0d6efd;\n box-shadow: 0 0 0 2px rgba(13, 110, 253, 0.1);\n}\n\n.calendar-day-header {\n background: #f8f9fa;\n padding: 20px;\n border-bottom: 2px solid #e9ecef;\n text-align: center;\n}\n\n.calendar-day-name {\n font-size: 16px;\n font-weight: 600;\n color: #6c757d;\n text-transform: uppercase;\n margin-bottom: 8px;\n}\n\n.calendar-day-date {\n font-size: 24px;\n font-weight: 700;\n color: #212529;\n}\n\n.calendar-day-bookings {\n padding: 20px;\n min-height: 300px;\n}\n\n.calendar-no-bookings {\n text-align: center;\n color: #6c757d;\n padding: 60px 20px;\n font-size: 16px;\n}\n\n.calendar-day-booking {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 16px;\n margin-bottom: 12px;\n border-left: 4px solid #0d6efd;\n}\n\n.calendar-day-booking .calendar-booking-time {\n font-size: 14px;\n}\n\n.calendar-day-booking .calendar-booking-title {\n font-size: 16px;\n font-weight: 600;\n color: #212529;\n}\n\n.calendar-booking-description {\n font-size: 14px;\n color: #6c757d;\n line-height: 1.5;\n}\n\n.calendar-day-add-btn {\n margin: 20px;\n width: calc(100% - 40px);\n background: #0d6efd;\n color: #ffffff;\n border-color: #0d6efd;\n padding: 12px;\n font-size: 15px;\n}\n\n.calendar-day-add-btn:hover {\n background: #0b5ed7;\n border-color: #0a58ca;\n}\n\n@media (max-width: 768px) {\n .calendar-title-section {\n flex-direction: column;\n align-items: flex-start;\n gap: 12px;\n }\n\n .calendar-cell {\n min-height: 80px;\n padding: 4px;\n }\n\n .calendar-cell-number {\n width: 24px;\n height: 24px;\n font-size: 12px;\n }\n\n .calendar-booking {\n font-size: 10px;\n padding: 2px 4px;\n }\n\n .calendar-week-view {\n grid-template-columns: 1fr;\n }\n\n .calendar-week-day {\n min-height: 200px;\n }\n\n .calendar-day-view {\n padding: 12px;\n }\n\n .calendar-day-container {\n border-radius: 4px;\n }\n\n .calendar-day-header {\n padding: 16px;\n }\n\n .calendar-day-date {\n font-size: 20px;\n }\n\n .calendar-day-bookings {\n padding: 12px;\n }\n}\n";
7534
+ const getWeekDays = (currentDate, view, businessHours) => {
7535
+ const startOfWeek = currentDate.clone().startOf('week');
7536
+ const days = [];
7537
+ // Generate all 7 days of the week first
7538
+ for (let i = 0; i < 7; i++) {
7539
+ days.push(startOfWeek.clone().add(i, 'days'));
7540
+ }
7541
+ if (view === 'workWeek') {
7542
+ if (businessHours) {
7543
+ // Filter based on business hours
7544
+ return days.filter(day => {
7545
+ var _a;
7546
+ const dayName = day.format('dddd');
7547
+ return !((_a = businessHours[dayName]) === null || _a === void 0 ? void 0 : _a.isClosed);
7548
+ });
7549
+ }
7550
+ else {
7551
+ // Default to 7 days (24/7) if no business hours provided
7552
+ return days;
7553
+ }
7554
+ }
7555
+ return days;
7556
+ };
7557
+ const calculateEventPositions = (bookings, timezone) => {
7558
+ const positions = new Map();
7559
+ // Sort bookings by start time
7560
+ const sortedBookings = [...bookings].sort((a, b) => {
7561
+ const startA = moment$1(a.start).tz(timezone);
7562
+ const startB = moment$1(b.start).tz(timezone);
7563
+ return startA.diff(startB);
7564
+ });
7565
+ // Group overlapping events
7566
+ const columns = [];
7567
+ sortedBookings.forEach(booking => {
7568
+ const start = moment$1(booking.start).tz(timezone);
7569
+ const end = moment$1(booking.end).tz(timezone);
7570
+ // Simple vertical position calculation (0-24 hours mapped to 0-100%)
7571
+ const startMinutes = start.hours() * 60 + start.minutes();
7572
+ const durationMinutes = end.diff(start, 'minutes');
7573
+ const top = (startMinutes / 1440) * 100;
7574
+ const height = (durationMinutes / 1440) * 100;
7575
+ // Overlap logic: Find a column where this event fits
7576
+ let placed = false;
7577
+ for (let i = 0; i < columns.length; i++) {
7578
+ const column = columns[i];
7579
+ const lastInColumn = column[column.length - 1];
7580
+ const lastInColumnEnd = moment$1(lastInColumn.end).tz(timezone);
7581
+ if (start.isSameOrAfter(lastInColumnEnd)) {
7582
+ column.push(booking);
7583
+ placed = true;
7584
+ break;
7585
+ }
7586
+ }
7587
+ if (!placed) {
7588
+ columns.push([booking]);
7589
+ }
7590
+ // Store temporary data to be refined
7591
+ positions.set(booking.meeting_id, { top, height, left: 0, width: 0 }); // Placeholder
7592
+ });
7593
+ // Refine positions based on columns
7594
+ // Let's try a standard "expand to fill" algorithm
7595
+ // Iterate through sorted bookings again to find "clusters"
7596
+ let cluster = [];
7597
+ let clusterEnd = null;
7598
+ for (let i = 0; i < sortedBookings.length; i++) {
7599
+ const booking = sortedBookings[i];
7600
+ const start = moment$1(booking.start).tz(timezone);
7601
+ const end = moment$1(booking.end).tz(timezone);
7602
+ if (clusterEnd === null || start.isBefore(clusterEnd)) {
7603
+ cluster.push(booking);
7604
+ if (clusterEnd === null || end.isAfter(clusterEnd)) {
7605
+ clusterEnd = end;
7606
+ }
7607
+ }
7608
+ else {
7609
+ // Process completed cluster
7610
+ processCluster(cluster, positions, timezone);
7611
+ cluster = [booking];
7612
+ clusterEnd = end;
7613
+ }
7614
+ }
7615
+ // Process last cluster
7616
+ if (cluster.length > 0) {
7617
+ processCluster(cluster, positions, timezone);
7618
+ }
7619
+ return positions;
7620
+ };
7621
+ const processCluster = (cluster, positions, timezone) => {
7622
+ // This is a simplified layout algorithm.
7623
+ // We will use a "columns" approach where we pack events into columns.
7624
+ const columns = [];
7625
+ cluster.forEach(booking => {
7626
+ const start = moment$1(booking.start).tz(timezone);
7627
+ let placed = false;
7628
+ for (let i = 0; i < columns.length; i++) {
7629
+ const lastInCol = columns[i][columns[i].length - 1];
7630
+ const lastEnd = moment$1(lastInCol.end).tz(timezone);
7631
+ if (start.isSameOrAfter(lastEnd)) {
7632
+ columns[i].push(booking);
7633
+ placed = true;
7634
+ break;
7635
+ }
7636
+ }
7637
+ if (!placed) {
7638
+ columns.push([booking]);
7639
+ }
7640
+ });
7641
+ const numColumns = columns.length;
7642
+ const width = 100 / numColumns;
7643
+ columns.forEach((col, colIndex) => {
7644
+ col.forEach(booking => {
7645
+ const pos = positions.get(booking.meeting_id);
7646
+ if (pos) {
7647
+ pos.left = colIndex * width;
7648
+ pos.width = width;
7649
+ positions.set(booking.meeting_id, pos);
7650
+ }
7651
+ });
7652
+ });
7653
+ };
7654
+ const isMobile = () => {
7655
+ if (typeof window !== 'undefined') {
7656
+ return window.innerWidth < 768;
7657
+ }
7658
+ return false;
7659
+ };
7660
+
7661
+ const CalendarHeader = ({ title, currentView, onViewChange, onNext, onPrevious, onToday, onCreateClick, dateRangeText, }) => {
7662
+ const mobile = isMobile();
7663
+ return (React.createElement("div", { className: "calendar-header" },
7664
+ React.createElement("div", { className: "calendar-title-section" },
7665
+ React.createElement("h2", { className: "calendar-title" }, title),
7666
+ React.createElement("div", { className: "calendar-view-toggle" },
7667
+ React.createElement("button", { className: `calendar-btn calendar-btn-view ${currentView === 'month' ? 'active' : ''}`, onClick: () => onViewChange('month'), disabled: mobile, style: mobile ? { display: 'none' } : {} }, "Month"),
7668
+ React.createElement("button", { className: `calendar-btn calendar-btn-view ${currentView === 'week' ? 'active' : ''}`, onClick: () => onViewChange('week'), disabled: mobile, style: mobile ? { display: 'none' } : {} }, "Week"),
7669
+ React.createElement("button", { className: `calendar-btn calendar-btn-view ${currentView === 'workWeek' ? 'active' : ''}`, onClick: () => onViewChange('workWeek'), disabled: mobile, style: mobile ? { display: 'none' } : {} }, "Work Week"),
7670
+ React.createElement("button", { className: `calendar-btn calendar-btn-view ${currentView === 'day' ? 'active' : ''}`, onClick: () => onViewChange('day') }, "Day")),
7671
+ React.createElement("button", { className: "calendar-btn calendar-btn-create", onClick: onCreateClick }, "+ Create Booking")),
7672
+ React.createElement("div", { className: "calendar-navigation" },
7673
+ React.createElement("button", { className: "calendar-btn", onClick: onPrevious }, "\u2039"),
7674
+ React.createElement("button", { className: "calendar-btn", onClick: onToday }, "Today"),
7675
+ React.createElement("button", { className: "calendar-btn", onClick: onNext }, "\u203A"),
7676
+ React.createElement("span", { className: "calendar-current-month" }, dateRangeText))));
7677
+ };
7678
+
7679
+ const TimeGrid = ({ currentDate, view, bookings, timezone, onBookingClick, onTimeSlotClick, businessHours, }) => {
7680
+ const days = React.useMemo(() => {
7681
+ if (view === 'day') {
7682
+ return [moment$1(currentDate).tz(timezone)];
7683
+ }
7684
+ return getWeekDays(moment$1(currentDate).tz(timezone), view, businessHours);
7685
+ }, [currentDate, view, timezone, businessHours]);
7686
+ const { displayStart, displayEnd, timeLabels } = React.useMemo(() => {
7687
+ if (!businessHours) {
7688
+ return {
7689
+ displayStart: 0,
7690
+ displayEnd: 1440,
7691
+ timeLabels: Array.from({ length: 24 }, (_, i) => i * 60)
7692
+ };
7693
+ }
7694
+ let longestDayOpen = 0;
7695
+ let longestDayClose = 0;
7696
+ let maxDuration = 0;
7697
+ days.forEach(day => {
7698
+ const dayName = day.format('dddd');
7699
+ const dayHours = businessHours[dayName];
7700
+ console.log('Day:', dayName, 'Hours:', dayHours);
7701
+ if (!(dayHours === null || dayHours === void 0 ? void 0 : dayHours.isClosed) && (dayHours === null || dayHours === void 0 ? void 0 : dayHours.openTime) && (dayHours === null || dayHours === void 0 ? void 0 : dayHours.closeTime)) {
7702
+ const openTime = moment$1(dayHours.openTime, ['h:mm A', 'hh:mm A'], true);
7703
+ const closeTime = moment$1(dayHours.closeTime, ['h:mm A', 'hh:mm A'], true);
7704
+ if (!openTime.isValid() || !closeTime.isValid()) {
7705
+ console.warn('Invalid time format:', dayHours.openTime, dayHours.closeTime);
7706
+ return;
7707
+ }
7708
+ const openMinutes = openTime.hours() * 60 + openTime.minutes();
7709
+ const closeMinutes = closeTime.hours() * 60 + closeTime.minutes();
7710
+ const duration = closeMinutes - openMinutes;
7711
+ console.log(' Open:', dayHours.openTime, '->', openMinutes, '| Close:', dayHours.closeTime, '->', closeMinutes, '| Duration:', duration);
7712
+ if (openMinutes < closeMinutes && duration > maxDuration) {
7713
+ maxDuration = duration;
7714
+ longestDayOpen = openMinutes;
7715
+ longestDayClose = closeMinutes;
7716
+ }
7717
+ }
7718
+ });
7719
+ console.log('Longest: open =', longestDayOpen, 'close =', longestDayClose);
7720
+ if (maxDuration === 0) {
7721
+ return {
7722
+ displayStart: 0,
7723
+ displayEnd: 1440,
7724
+ timeLabels: Array.from({ length: 24 }, (_, i) => i * 60)
7725
+ };
7726
+ }
7727
+ const displayStart = Math.max(0, longestDayOpen - 60);
7728
+ const displayEnd = Math.min(1440, longestDayClose + 60);
7729
+ const labels = [];
7730
+ const startHour = Math.floor(displayStart / 60);
7731
+ const endHour = Math.floor(displayEnd / 60);
7732
+ for (let h = startHour; h <= endHour; h++) {
7733
+ const hourInMinutes = h * 60;
7734
+ if (hourInMinutes < displayEnd && hourInMinutes >= displayStart) {
7735
+ labels.push(hourInMinutes);
7736
+ }
7737
+ }
7738
+ return { displayStart, displayEnd, timeLabels: labels };
7739
+ }, [days, businessHours]);
7740
+ const visibleBookings = React.useMemo(() => {
7741
+ if (days.length === 0)
7742
+ return [];
7743
+ const start = days[0].clone().startOf('day');
7744
+ const end = days[days.length - 1].clone().endOf('day');
7745
+ return bookings.filter(b => {
7746
+ const bStart = moment$1(b.start).tz(timezone);
7747
+ const bEnd = moment$1(b.end).tz(timezone);
7748
+ return bStart.isBefore(end) && bEnd.isAfter(start);
7749
+ });
7750
+ }, [bookings, days, timezone]);
7751
+ const dayPositions = React.useMemo(() => {
7752
+ const positions = new Map();
7753
+ const totalMinutes = displayEnd - displayStart;
7754
+ days.forEach(day => {
7755
+ const dayBookings = visibleBookings.filter(b => moment$1(b.start).tz(timezone).isSame(day, 'day'));
7756
+ const dayPos = calculateEventPositions(dayBookings, timezone);
7757
+ dayPos.forEach((pos, id) => {
7758
+ const startMinutes = (pos.top / 100) * 1440;
7759
+ const durationMinutes = (pos.height / 100) * 1440;
7760
+ const newTop = ((startMinutes - displayStart) / totalMinutes) * 100;
7761
+ const newHeight = (durationMinutes / totalMinutes) * 100;
7762
+ positions.set(id, Object.assign(Object.assign({}, pos), { top: Math.max(0, newTop), height: newHeight }));
7763
+ });
7764
+ });
7765
+ return positions;
7766
+ }, [visibleBookings, days, timezone, displayStart, displayEnd]);
7767
+ return (React.createElement("div", { className: "time-grid-container" },
7768
+ React.createElement("div", { className: "time-grid-header" },
7769
+ React.createElement("div", { className: "time-column-header", style: { width: '60px', minWidth: '60px' } }),
7770
+ days.map(day => {
7771
+ var _a;
7772
+ const dayName = day.format('dddd');
7773
+ const isClosed = (_a = businessHours === null || businessHours === void 0 ? void 0 : businessHours[dayName]) === null || _a === void 0 ? void 0 : _a.isClosed;
7774
+ const isToday = day.isSame(moment$1().tz(timezone), 'day');
7775
+ return (React.createElement("div", { key: day.toString(), className: `day-column-header ${isToday ? 'today' : ''} ${isClosed ? 'closed' : ''}` },
7776
+ React.createElement("div", { className: "day-name" }, day.format('ddd')),
7777
+ React.createElement("div", { className: "day-number" }, day.format('D')),
7778
+ isClosed && React.createElement("span", { className: "closed-label" }, "Closed")));
7779
+ })),
7780
+ React.createElement("div", { className: "time-grid-body" },
7781
+ React.createElement("div", { className: "time-labels-column" }, timeLabels.map(minutes => (React.createElement("div", { key: minutes, className: "time-label" }, moment$1().startOf('day').add(minutes, 'minutes').format('h A'))))),
7782
+ React.createElement("div", { className: "days-grid", style: { height: `${(displayEnd - displayStart)}px` } },
7783
+ React.createElement("div", { className: "grid-lines" }, timeLabels.map(minutes => (React.createElement("div", { key: minutes, className: "grid-hour-row" })))),
7784
+ days.map(day => {
7785
+ const dayName = day.format('dddd');
7786
+ const businessDay = businessHours === null || businessHours === void 0 ? void 0 : businessHours[dayName];
7787
+ const isClosed = businessDay === null || businessDay === void 0 ? void 0 : businessDay.isClosed;
7788
+ let closedBlocks = [];
7789
+ if (!isClosed && businessDay && businessDay.openTime && businessDay.closeTime) {
7790
+ const openTime = moment$1(businessDay.openTime, ['h:mm A', 'hh:mm A'], true);
7791
+ const closeTime = moment$1(businessDay.closeTime, ['h:mm A', 'hh:mm A'], true);
7792
+ const openMinutes = openTime.hours() * 60 + openTime.minutes();
7793
+ const closeMinutes = closeTime.hours() * 60 + closeTime.minutes();
7794
+ const totalMinutes = displayEnd - displayStart;
7795
+ if (openMinutes < closeMinutes) {
7796
+ const preOpenEnd = openMinutes - 60;
7797
+ if (preOpenEnd > displayStart) {
7798
+ const height = ((preOpenEnd - displayStart) / totalMinutes) * 100;
7799
+ closedBlocks.push(React.createElement("div", { key: "pre-open", className: "calendar-closed-block", style: { top: '0%', height: `${height}%` } },
7800
+ React.createElement("span", { className: "closed-block-label" }, "Closed")));
7801
+ }
7802
+ const bufferStart = Math.max(displayStart, openMinutes - 60);
7803
+ const bufferEnd = openMinutes;
7804
+ if (bufferStart < bufferEnd) {
7805
+ const top = ((bufferStart - displayStart) / totalMinutes) * 100;
7806
+ const height = ((bufferEnd - bufferStart) / totalMinutes) * 100;
7807
+ closedBlocks.push(React.createElement("div", { key: "morning", className: "calendar-closed-block", style: { top: `${top}%`, height: `${height}%` } },
7808
+ React.createElement("span", { className: "closed-block-label" }, "Closed")));
7809
+ }
7810
+ const bufferCloseStart = closeMinutes;
7811
+ const bufferCloseEnd = Math.min(displayEnd, closeMinutes + 60);
7812
+ if (bufferCloseStart < bufferCloseEnd) {
7813
+ const top = ((bufferCloseStart - displayStart) / totalMinutes) * 100;
7814
+ const height = ((bufferCloseEnd - bufferCloseStart) / totalMinutes) * 100;
7815
+ closedBlocks.push(React.createElement("div", { key: "evening", className: "calendar-closed-block", style: { top: `${top}%`, height: `${height}%` } },
7816
+ React.createElement("span", { className: "closed-block-label" }, "Closed")));
7817
+ }
7818
+ const postCloseStart = closeMinutes + 60;
7819
+ if (postCloseStart < displayEnd) {
7820
+ const top = ((postCloseStart - displayStart) / totalMinutes) * 100;
7821
+ const height = ((displayEnd - postCloseStart) / totalMinutes) * 100;
7822
+ closedBlocks.push(React.createElement("div", { key: "post-close", className: "calendar-closed-block", style: { top: `${top}%`, height: `${height}%` } },
7823
+ React.createElement("span", { className: "closed-block-label" }, "Closed")));
7824
+ }
7825
+ }
7826
+ }
7827
+ return (React.createElement("div", { key: day.toString(), className: `day-column ${isClosed ? 'closed-column' : ''}`, onClick: (e) => {
7828
+ const rect = e.currentTarget.getBoundingClientRect();
7829
+ const y = e.clientY - rect.top;
7830
+ const height = rect.height;
7831
+ const percentage = y / height;
7832
+ const totalMinutes = displayEnd - displayStart;
7833
+ const minutesFromDisplayStart = percentage * totalMinutes;
7834
+ const minutesFromMidnight = displayStart + minutesFromDisplayStart;
7835
+ const clickedTime = day.clone().startOf('day').add(minutesFromMidnight, 'minutes');
7836
+ if (!isClosed && businessDay && businessDay.openTime && businessDay.closeTime) {
7837
+ const openTime = moment$1(businessDay.openTime, ['h:mm A', 'hh:mm A'], true);
7838
+ const closeTime = moment$1(businessDay.closeTime, ['h:mm A', 'hh:mm A'], true);
7839
+ const clickedMinutes = clickedTime.hours() * 60 + clickedTime.minutes();
7840
+ const openMinutes = openTime.hours() * 60 + openTime.minutes();
7841
+ const closeMinutes = closeTime.hours() * 60 + closeTime.minutes();
7842
+ if (clickedMinutes < openMinutes || clickedMinutes > closeMinutes) {
7843
+ return;
7844
+ }
7845
+ }
7846
+ if (!isClosed)
7847
+ onTimeSlotClick(clickedTime);
7848
+ } },
7849
+ closedBlocks,
7850
+ visibleBookings
7851
+ .filter(b => moment$1(b.start).tz(timezone).isSame(day, 'day'))
7852
+ .map(booking => {
7853
+ var _a, _b, _c, _d, _e, _f;
7854
+ const pos = dayPositions.get(booking.meeting_id);
7855
+ if (!pos)
7856
+ return null;
7857
+ return (React.createElement("div", { key: booking.meeting_id, className: `calendar-event ${booking.className || ''}`, style: {
7858
+ top: `${pos.top}%`,
7859
+ height: `${pos.height}%`,
7860
+ left: `${pos.left}%`,
7861
+ width: `${pos.width}%`,
7862
+ position: 'absolute'
7863
+ }, onClick: (e) => {
7864
+ e.stopPropagation();
7865
+ if (onBookingClick)
7866
+ onBookingClick(booking);
7867
+ } },
7868
+ React.createElement("div", { className: "event-content" },
7869
+ React.createElement("div", { className: "event-title" }, ((_a = booking.metadata) === null || _a === void 0 ? void 0 : _a.title) || 'Untitled'),
7870
+ React.createElement("div", { className: "event-time" },
7871
+ moment$1(booking.start).tz(timezone).format('h:mm A'),
7872
+ " - ",
7873
+ moment$1(booking.end).tz(timezone).format('h:mm A'))),
7874
+ React.createElement("div", { className: "event-tooltip" },
7875
+ React.createElement("div", { className: "tooltip-title" }, ((_b = booking.metadata) === null || _b === void 0 ? void 0 : _b.title) || 'Untitled'),
7876
+ React.createElement("div", { className: "tooltip-row" },
7877
+ React.createElement("span", { className: "tooltip-label" }, "Time:"),
7878
+ React.createElement("span", { className: "tooltip-value" },
7879
+ moment$1(booking.start).tz(timezone).format('h:mm A'),
7880
+ " - ",
7881
+ moment$1(booking.end).tz(timezone).format('h:mm A'))),
7882
+ (booking.staff || ((_c = booking.metadata) === null || _c === void 0 ? void 0 : _c.staff)) && (React.createElement("div", { className: "tooltip-row" },
7883
+ React.createElement("span", { className: "tooltip-label" }, "Staff:"),
7884
+ React.createElement("span", { className: "tooltip-value" }, booking.staff || ((_d = booking.metadata) === null || _d === void 0 ? void 0 : _d.staff)))),
7885
+ (booking.room || ((_e = booking.metadata) === null || _e === void 0 ? void 0 : _e.room)) && (React.createElement("div", { className: "tooltip-row" },
7886
+ React.createElement("span", { className: "tooltip-label" }, "Room:"),
7887
+ React.createElement("span", { className: "tooltip-value" }, booking.room || ((_f = booking.metadata) === null || _f === void 0 ? void 0 : _f.room)))))));
7888
+ })));
7889
+ })))));
7890
+ };
7891
+
7892
+ const MonthView = ({ currentDate, bookings, timezone, onBookingClick, onDateClick, businessHours, }) => {
7893
+ var _a;
7894
+ const startOfMonth = moment$1(currentDate).tz(timezone).startOf('month');
7895
+ const endOfMonth = moment$1(currentDate).tz(timezone).endOf('month');
7896
+ const startDate = startOfMonth.clone().startOf('week');
7897
+ const endDate = endOfMonth.clone().endOf('week');
7898
+ const rows = [];
7899
+ let days = [];
7900
+ let day = startDate.clone();
7901
+ while (day.isSameOrBefore(endDate, 'day')) {
7902
+ for (let i = 0; i < 7; i++) {
7903
+ const currentDay = day.clone();
7904
+ const dayBookings = bookings.filter(b => moment$1(b.start).tz(timezone).isSame(currentDay, 'day'));
7905
+ const isCurrentMonth = currentDay.isSame(startOfMonth, 'month');
7906
+ const isToday = currentDay.isSame(moment$1().tz(timezone), 'day');
7907
+ const dayName = currentDay.format('dddd');
7908
+ const isClosed = (_a = businessHours === null || businessHours === void 0 ? void 0 : businessHours[dayName]) === null || _a === void 0 ? void 0 : _a.isClosed;
7909
+ days.push(React.createElement("div", { key: day.toString(), className: `calendar-cell ${!isCurrentMonth ? 'calendar-cell-disabled' : ''} ${isToday ? 'calendar-cell-today' : ''} ${isClosed ? 'calendar-cell-closed' : ''}`, onClick: () => isCurrentMonth && !isClosed && onDateClick(currentDay) },
7910
+ React.createElement("div", { className: "calendar-cell-header" },
7911
+ React.createElement("span", { className: "calendar-cell-number" }, currentDay.format('D')),
7912
+ isClosed && React.createElement("span", { className: "calendar-closed-label-small" }, "Closed")),
7913
+ React.createElement("div", { className: "calendar-cell-bookings" },
7914
+ dayBookings.slice(0, 3).map((booking) => {
7915
+ var _a, _b, _c, _d, _e, _f;
7916
+ return (React.createElement("div", { key: booking.meeting_id, className: `calendar-booking ${booking.className || ''}`, onClick: (e) => {
7917
+ e.stopPropagation();
7918
+ if (onBookingClick) {
7919
+ onBookingClick(booking);
7920
+ }
7921
+ } },
7922
+ React.createElement("span", { className: "calendar-booking-time" }, moment$1(booking.start).tz(timezone).format('HH:mm')),
7923
+ React.createElement("span", { className: "calendar-booking-title" }, ((_a = booking.metadata) === null || _a === void 0 ? void 0 : _a.title) || 'Untitled'),
7924
+ React.createElement("div", { className: "event-tooltip" },
7925
+ React.createElement("div", { className: "tooltip-title" }, ((_b = booking.metadata) === null || _b === void 0 ? void 0 : _b.title) || 'Untitled'),
7926
+ React.createElement("div", { className: "tooltip-row" },
7927
+ React.createElement("span", { className: "tooltip-label" }, "Time:"),
7928
+ React.createElement("span", { className: "tooltip-value" },
7929
+ moment$1(booking.start).tz(timezone).format('h:mm A'),
7930
+ " - ",
7931
+ moment$1(booking.end).tz(timezone).format('h:mm A'))),
7932
+ (booking.staff || ((_c = booking.metadata) === null || _c === void 0 ? void 0 : _c.staff)) && (React.createElement("div", { className: "tooltip-row" },
7933
+ React.createElement("span", { className: "tooltip-label" }, "Staff:"),
7934
+ React.createElement("span", { className: "tooltip-value" }, booking.staff || ((_d = booking.metadata) === null || _d === void 0 ? void 0 : _d.staff)))),
7935
+ (booking.room || ((_e = booking.metadata) === null || _e === void 0 ? void 0 : _e.room)) && (React.createElement("div", { className: "tooltip-row" },
7936
+ React.createElement("span", { className: "tooltip-label" }, "Room:"),
7937
+ React.createElement("span", { className: "tooltip-value" }, booking.room || ((_f = booking.metadata) === null || _f === void 0 ? void 0 : _f.room)))))));
7938
+ }),
7939
+ dayBookings.length > 3 && (React.createElement("div", { className: "calendar-booking-more" },
7940
+ "+",
7941
+ dayBookings.length - 3,
7942
+ " more")))));
7943
+ day.add(1, 'days');
7944
+ }
7945
+ rows.push(React.createElement("div", { key: day.toString(), className: "calendar-row" }, days));
7946
+ days = [];
7947
+ }
7948
+ return (React.createElement("div", { className: "month-view-container" },
7949
+ React.createElement("div", { className: "calendar-days-row" }, ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map(d => (React.createElement("div", { key: d, className: "calendar-day-header" }, d)))),
7950
+ React.createElement("div", { className: "calendar-body" }, rows)));
7951
+ };
7952
+
7953
+ var css_248z = ".calendar-container {\n font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n border: 1px solid #e0e0e0;\n border-radius: 8px;\n background-color: #fff;\n display: flex;\n flex-direction: column;\n height: 100%;\n /* Use 100% height of parent */\n max-height: 100vh;\n /* Ensure it doesn't exceed viewport */\n min-height: 600px;\n /* Minimum height fallback */\n /* Minimum height fallback */\n overflow: hidden;\n}\n\n/* Header */\n.calendar-header {\n padding: 16px;\n border-bottom: 1px solid #e0e0e0;\n background-color: #fff;\n}\n\n.calendar-title-section {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 16px;\n flex-wrap: wrap;\n gap: 10px;\n}\n\n.calendar-title {\n margin: 0;\n font-size: 1.5rem;\n color: #333;\n}\n\n.calendar-view-toggle {\n display: flex;\n background-color: #f5f5f5;\n border-radius: 6px;\n padding: 2px;\n}\n\n.calendar-btn {\n padding: 8px 16px;\n border: 1px solid #e0e0e0;\n background-color: #fff;\n cursor: pointer;\n border-radius: 4px;\n font-size: 14px;\n transition: all 0.2s;\n}\n\n.calendar-btn:hover {\n background-color: #f5f5f5;\n}\n\n.calendar-btn-view {\n border: none;\n background: transparent;\n border-radius: 4px;\n padding: 6px 12px;\n}\n\n.calendar-btn-view.active {\n background-color: #fff;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n font-weight: 600;\n}\n\n.calendar-btn-create {\n background-color: #0078d4;\n color: white;\n border: none;\n}\n\n.calendar-btn-create:hover {\n background-color: #106ebe;\n}\n\n.calendar-navigation {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.calendar-current-month {\n font-size: 1.1rem;\n font-weight: 600;\n margin-left: 16px;\n color: #333;\n}\n\n/* Content Area */\n.calendar-content {\n flex: 1;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n}\n\n/* Month View */\n.month-view-container {\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n /* Prevent container scrolling, let body scroll */\n}\n\n.calendar-days-row {\n display: grid;\n grid-template-columns: repeat(7, 1fr);\n /* Ensure equal columns */\n border-bottom: 1px solid #e0e0e0;\n background-color: #f9f9f9;\n}\n\n.calendar-day-header {\n padding: 10px;\n text-align: center;\n font-weight: 600;\n color: #666;\n font-size: 0.9rem;\n overflow: hidden;\n /* Prevent overflow */\n text-overflow: ellipsis;\n}\n\n.calendar-body {\n display: flex;\n flex-direction: column;\n flex: 1;\n overflow-y: auto;\n /* Scrollable body */\n}\n\n.calendar-row {\n display: grid;\n grid-template-columns: repeat(7, 1fr);\n /* Ensure equal columns */\n flex: 1;\n min-height: 100px;\n /* Minimum row height */\n border-bottom: 1px solid #e0e0e0;\n}\n\n.calendar-cell {\n border-right: 1px solid #e0e0e0;\n padding: 8px;\n position: relative;\n cursor: pointer;\n transition: background-color 0.2s;\n overflow: hidden;\n /* Prevent cell expansion */\n min-width: 0;\n /* Allow shrinking below content size */\n}\n\n.calendar-cell:hover {\n background-color: #fcfcfc;\n}\n\n.calendar-cell-disabled {\n background-color: #f9f9f9;\n color: #999;\n}\n\n.calendar-cell-today {\n background-color: #e6f2ff;\n}\n\n.calendar-cell-closed {\n background-color: #f5f5f5;\n cursor: not-allowed;\n}\n\n.calendar-cell-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 4px;\n}\n\n.calendar-cell-number {\n font-weight: 600;\n font-size: 0.9rem;\n}\n\n.calendar-closed-label-small {\n font-size: 0.7rem;\n color: #d13438;\n background: #fde7e9;\n padding: 2px 4px;\n border-radius: 3px;\n}\n\n.calendar-cell-bookings {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.calendar-booking {\n background-color: #e1dfdd;\n /* Default neutral color */\n border-left: 3px solid #0078d4;\n padding: 4px 6px;\n border-radius: 2px;\n font-size: 0.8rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n cursor: pointer;\n position: relative;\n /* For tooltip positioning */\n}\n\n.calendar-booking:hover {\n background-color: #d0d0d0;\n}\n\n.calendar-booking-time {\n font-weight: 600;\n margin-right: 4px;\n}\n\n.calendar-booking-more {\n font-size: 0.8rem;\n color: #666;\n padding: 2px 4px;\n}\n\n/* Time Grid (Day/Week/WorkWeek) */\n.time-grid-container {\n display: flex;\n flex-direction: column;\n flex: 1;\n overflow: hidden;\n}\n\n.time-grid-header {\n display: flex;\n border-bottom: 1px solid #e0e0e0;\n padding-right: 17px;\n /* Adjust for scrollbar */\n}\n\n.time-column-header {\n width: 60px;\n /* Width of time labels column */\n flex-shrink: 0;\n border-right: 1px solid #e0e0e0;\n}\n\n.day-column-header {\n flex: 1;\n text-align: center;\n padding: 8px;\n border-right: 1px solid #e0e0e0;\n background-color: #f9f9f9;\n min-width: 0;\n /* Prevent expansion */\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.day-column-header.today {\n background-color: #e6f2ff;\n color: #0078d4;\n}\n\n.day-column-header.closed {\n background-color: #f0f0f0;\n color: #999;\n}\n\n.day-name {\n font-size: 0.8rem;\n text-transform: uppercase;\n color: #666;\n}\n\n.day-number {\n font-size: 1.2rem;\n font-weight: 600;\n}\n\n.time-grid-body {\n display: flex;\n flex: 1;\n overflow-y: auto;\n position: relative;\n}\n\n.time-labels-column {\n width: 60px;\n flex-shrink: 0;\n border-right: 1px solid #e0e0e0;\n background-color: #fff;\n}\n\n.time-label {\n height: 60px;\n /* 1 hour height */\n text-align: right;\n padding-right: 8px;\n font-size: 0.75rem;\n color: #666;\n justify-content: center;\n}\n\n.days-grid {\n flex: 1;\n display: flex;\n position: relative;\n /* 24 hours * 60px/hour = 1440px total height */\n height: 1440px;\n}\n\n.grid-lines {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n pointer-events: none;\n z-index: 0;\n}\n\n.grid-hour-row {\n height: 60px;\n border-bottom: 1px solid #e0e0e0;\n box-sizing: border-box;\n}\n\n.grid-hour-row:last-child {\n border-bottom: none;\n}\n\n.day-column {\n flex: 1;\n border-right: 1px solid #e0e0e0;\n position: relative;\n height: 100%;\n min-width: 0;\n /* Critical for flex containers to not expand based on content */\n}\n\n.day-column.closed-column {\n background-color: repeating-linear-gradient(45deg,\n #fbfbfb,\n #fbfbfb 10px,\n #f5f5f5 10px,\n #f5f5f5 20px);\n}\n\n.calendar-event {\n background-color: #e1dfdd;\n border-left: 4px solid #0078d4;\n border-radius: 3px;\n padding: 2px 4px;\n font-size: 0.75rem;\n overflow: hidden;\n cursor: pointer;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n z-index: 1;\n transition: transform 0.1s, z-index 0.1s;\n}\n\n.calendar-event:hover {\n z-index: 10;\n /* Bring to front on hover */\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);\n}\n\n.event-content {\n height: 100%;\n overflow: hidden;\n}\n\n.event-title {\n font-weight: 600;\n margin-bottom: 2px;\n}\n\n.event-time {\n font-size: 0.7rem;\n color: #555;\n}\n\n/* Tooltip Styles */\n.event-tooltip {\n display: none;\n position: absolute;\n left: 100%;\n top: 0;\n background: white;\n border: 1px solid #ccc;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n padding: 10px;\n border-radius: 4px;\n width: 200px;\n z-index: 100;\n pointer-events: none;\n}\n\n/* Show tooltip on hover */\n.calendar-booking:hover .event-tooltip,\n.calendar-event:hover .event-tooltip {\n display: block;\n}\n\n/* Adjust tooltip position if it goes offscreen (simple right-side check) */\n/* Note: A real production app would use a library like Popper.js */\n.day-column:last-child .event-tooltip,\n.day-column:nth-last-child(2) .event-tooltip {\n left: auto;\n right: 100%;\n}\n\n.tooltip-title {\n font-weight: bold;\n margin-bottom: 8px;\n border-bottom: 1px solid #eee;\n padding-bottom: 4px;\n}\n\n.tooltip-row {\n display: flex;\n justify-content: space-between;\n margin-bottom: 4px;\n font-size: 0.85rem;\n}\n\n.tooltip-label {\n color: #666;\n margin-right: 8px;\n}\n\n.tooltip-value {\n font-weight: 500;\n text-align: right;\n}\n\n/* Loading & Error */\n.calendar-loading,\n.calendar-error {\n padding: 20px;\n text-align: center;\n color: #666;\n}\n\n.calendar-error {\n color: #d13438;\n}\n\n/* Closed Block Styles */\n.calendar-closed-block {\n position: absolute;\n left: 0;\n right: 0;\n background-color: #f0f0f0;\n background-image: repeating-linear-gradient(45deg,\n #f0f0f0,\n #f0f0f0 10px,\n #e8e8e8 10px,\n #e8e8e8 20px);\n display: flex;\n justify-content: center;\n align-items: center;\n z-index: 5;\n /* Below events but above grid lines */\n pointer-events: none;\n /* Allow clicks to pass through if needed, though we block clicks in JS */\n border-bottom: 1px solid #ddd;\n border-top: 1px solid #ddd;\n}\n\n.closed-block-label {\n background-color: rgba(255, 255, 255, 0.8);\n padding: 4px 8px;\n border-radius: 4px;\n font-size: 0.8rem;\n color: #888;\n font-weight: 500;\n}";
7535
7954
  styleInject(css_248z);
7536
7955
 
7537
7956
  const Calendar = ({ businessId, resourceId, title = 'Calendar', apiBaseUrl, defaultView = 'month', onBookingCreate, onBookingClick, participants = [], timezone = moment$1.tz.guess(), businessHours, }) => {
@@ -7542,6 +7961,18 @@ const Calendar = ({ businessId, resourceId, title = 'Calendar', apiBaseUrl, defa
7542
7961
  const [error, setError] = React.useState(null);
7543
7962
  const [showCreateModal, setShowCreateModal] = React.useState(false);
7544
7963
  const [selectedDate, setSelectedDate] = React.useState(null);
7964
+ // Mobile responsiveness logic
7965
+ React.useEffect(() => {
7966
+ const handleResize = () => {
7967
+ if (isMobile()) {
7968
+ setCurrentView('day');
7969
+ }
7970
+ };
7971
+ // Initial check
7972
+ handleResize();
7973
+ window.addEventListener('resize', handleResize);
7974
+ return () => window.removeEventListener('resize', handleResize);
7975
+ }, []);
7545
7976
  // Update currentDate when timezone changes
7546
7977
  React.useEffect(() => {
7547
7978
  setCurrentDate((prev) => moment$1(prev).tz(timezone));
@@ -7563,6 +7994,10 @@ const Calendar = ({ businessId, resourceId, title = 'Calendar', apiBaseUrl, defa
7563
7994
  startDate = current.clone().startOf('week');
7564
7995
  endDate = current.clone().endOf('week');
7565
7996
  }
7997
+ else if (currentView === 'workWeek') {
7998
+ startDate = current.clone().startOf('week'); // Fetch full week to be safe
7999
+ endDate = current.clone().endOf('week');
8000
+ }
7566
8001
  else {
7567
8002
  startDate = current.clone().startOf('day');
7568
8003
  endDate = current.clone().endOf('day');
@@ -7591,7 +8026,7 @@ const Calendar = ({ businessId, resourceId, title = 'Calendar', apiBaseUrl, defa
7591
8026
  if (currentView === 'month') {
7592
8027
  newDate.subtract(1, 'months');
7593
8028
  }
7594
- else if (currentView === 'week') {
8029
+ else if (currentView === 'week' || currentView === 'workWeek') {
7595
8030
  newDate.subtract(1, 'weeks');
7596
8031
  }
7597
8032
  else {
@@ -7604,7 +8039,7 @@ const Calendar = ({ businessId, resourceId, title = 'Calendar', apiBaseUrl, defa
7604
8039
  if (currentView === 'month') {
7605
8040
  newDate.add(1, 'months');
7606
8041
  }
7607
- else if (currentView === 'week') {
8042
+ else if (currentView === 'week' || currentView === 'workWeek') {
7608
8043
  newDate.add(1, 'weeks');
7609
8044
  }
7610
8045
  else {
@@ -7627,18 +8062,12 @@ const Calendar = ({ businessId, resourceId, title = 'Calendar', apiBaseUrl, defa
7627
8062
  onBookingCreate(booking);
7628
8063
  }
7629
8064
  });
7630
- const getBookingsForDay = (day) => {
7631
- return bookings.filter((booking) => {
7632
- const bookingStart = moment$1(booking.start).tz(timezone);
7633
- return bookingStart.isSame(day, 'day');
7634
- });
7635
- };
7636
8065
  const getHeaderDateFormat = () => {
7637
8066
  const current = moment$1(currentDate).tz(timezone);
7638
8067
  if (currentView === 'month') {
7639
8068
  return current.format('MMMM YYYY');
7640
8069
  }
7641
- else if (currentView === 'week') {
8070
+ else if (currentView === 'week' || currentView === 'workWeek') {
7642
8071
  const weekStart = current.clone().startOf('week');
7643
8072
  const weekEnd = current.clone().endOf('week');
7644
8073
  return `${weekStart.format('MMM D')} - ${weekEnd.format('MMM D, YYYY')}`;
@@ -7647,142 +8076,14 @@ const Calendar = ({ businessId, resourceId, title = 'Calendar', apiBaseUrl, defa
7647
8076
  return current.format('MMMM D, YYYY');
7648
8077
  }
7649
8078
  };
7650
- const renderHeader = () => {
7651
- return (React.createElement("div", { className: "calendar-header" },
7652
- React.createElement("div", { className: "calendar-title-section" },
7653
- React.createElement("h2", { className: "calendar-title" }, title),
7654
- React.createElement("div", { className: "calendar-view-toggle" },
7655
- React.createElement("button", { className: `calendar-btn calendar-btn-view ${currentView === 'month' ? 'active' : ''}`, onClick: () => setCurrentView('month') }, "Month"),
7656
- React.createElement("button", { className: `calendar-btn calendar-btn-view ${currentView === 'week' ? 'active' : ''}`, onClick: () => setCurrentView('week') }, "Week"),
7657
- React.createElement("button", { className: `calendar-btn calendar-btn-view ${currentView === 'day' ? 'active' : ''}`, onClick: () => setCurrentView('day') }, "Day")),
7658
- React.createElement("button", { className: "calendar-btn calendar-btn-create", onClick: () => setShowCreateModal(true) }, "+ Create Booking")),
7659
- React.createElement("div", { className: "calendar-navigation" },
7660
- React.createElement("button", { className: "calendar-btn", onClick: handlePrevious }, "\u2039"),
7661
- React.createElement("button", { className: "calendar-btn", onClick: handleToday }, "Today"),
7662
- React.createElement("button", { className: "calendar-btn", onClick: handleNext }, "\u203A"),
7663
- React.createElement("span", { className: "calendar-current-month" }, getHeaderDateFormat()))));
7664
- };
7665
- const renderDaysOfWeek = () => {
7666
- const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
7667
- return (React.createElement("div", { className: "calendar-days-row" }, days.map((day) => (React.createElement("div", { key: day, className: "calendar-day-header" }, day)))));
7668
- };
7669
- const renderMonthView = () => {
7670
- var _a;
7671
- const current = moment$1(currentDate).tz(timezone);
7672
- const monthStart = current.clone().startOf('month');
7673
- const monthEnd = current.clone().endOf('month');
7674
- const startDate = monthStart.clone().startOf('week');
7675
- const endDate = monthEnd.clone().endOf('week');
7676
- const rows = [];
7677
- let days = [];
7678
- let day = startDate.clone();
7679
- while (day.isSameOrBefore(endDate, 'day')) {
7680
- for (let i = 0; i < 7; i++) {
7681
- const currentDay = day.clone();
7682
- const dayBookings = getBookingsForDay(currentDay);
7683
- const isCurrentMonth = currentDay.isSame(monthStart, 'month');
7684
- const isToday = currentDay.isSame(moment$1().tz(timezone), 'day');
7685
- // Check business hours
7686
- const dayName = currentDay.format('dddd');
7687
- const isClosed = (_a = businessHours === null || businessHours === void 0 ? void 0 : businessHours[dayName]) === null || _a === void 0 ? void 0 : _a.isClosed;
7688
- days.push(React.createElement("div", { key: day.toString(), className: `calendar-cell ${!isCurrentMonth ? 'calendar-cell-disabled' : ''} ${isToday ? 'calendar-cell-today' : ''} ${isClosed ? 'calendar-cell-closed' : ''}`, onClick: () => isCurrentMonth && !isClosed && handleDateClick(currentDay), style: isClosed ? { backgroundColor: '#f5f5f5', cursor: 'not-allowed' } : {} },
7689
- React.createElement("div", { className: "calendar-cell-number" }, currentDay.format('D')),
7690
- isClosed && React.createElement("div", { className: "calendar-closed-label" }, "Closed"),
7691
- React.createElement("div", { className: "calendar-cell-bookings" },
7692
- dayBookings.slice(0, 3).map((booking) => {
7693
- var _a, _b;
7694
- return (React.createElement("div", { key: booking.meeting_id, className: "calendar-booking", onClick: (e) => {
7695
- e.stopPropagation();
7696
- if (onBookingClick) {
7697
- onBookingClick(booking);
7698
- }
7699
- }, title: ((_a = booking.metadata) === null || _a === void 0 ? void 0 : _a.title) || 'Untitled' },
7700
- React.createElement("span", { className: "calendar-booking-time" }, moment$1(booking.start).tz(timezone).format('HH:mm')),
7701
- React.createElement("span", { className: "calendar-booking-title" }, ((_b = booking.metadata) === null || _b === void 0 ? void 0 : _b.title) || 'Untitled')));
7702
- }),
7703
- dayBookings.length > 3 && (React.createElement("div", { className: "calendar-booking-more" },
7704
- "+",
7705
- dayBookings.length - 3,
7706
- " more")))));
7707
- day.add(1, 'days');
7708
- }
7709
- rows.push(React.createElement("div", { key: day.toString(), className: "calendar-row" }, days));
7710
- days = [];
7711
- }
7712
- return React.createElement("div", { className: "calendar-body" }, rows);
7713
- };
7714
- const renderWeekView = () => {
7715
- var _a;
7716
- const current = moment$1(currentDate).tz(timezone);
7717
- const weekStart = current.clone().startOf('week');
7718
- const days = [];
7719
- for (let i = 0; i < 7; i++) {
7720
- const day = weekStart.clone().add(i, 'days');
7721
- const dayBookings = getBookingsForDay(day);
7722
- const isToday = day.isSame(moment$1().tz(timezone), 'day');
7723
- const dayName = day.format('dddd');
7724
- const isClosed = (_a = businessHours === null || businessHours === void 0 ? void 0 : businessHours[dayName]) === null || _a === void 0 ? void 0 : _a.isClosed;
7725
- days.push(React.createElement("div", { key: day.toString(), className: `calendar-week-day ${isToday ? 'calendar-cell-today' : ''}`, onClick: () => !isClosed && handleDateClick(day), style: isClosed ? { backgroundColor: '#f5f5f5' } : {} },
7726
- React.createElement("div", { className: "calendar-week-day-header" },
7727
- React.createElement("div", { className: "calendar-week-day-name" }, day.format('EEE')),
7728
- React.createElement("div", { className: "calendar-week-day-number" }, day.format('D')),
7729
- isClosed && React.createElement("div", { className: "calendar-closed-label-small" }, "Closed")),
7730
- React.createElement("div", { className: "calendar-week-day-bookings" }, dayBookings.map((booking) => {
7731
- var _a, _b;
7732
- return (React.createElement("div", { key: booking.meeting_id, className: "calendar-booking calendar-week-booking", onClick: (e) => {
7733
- e.stopPropagation();
7734
- if (onBookingClick) {
7735
- onBookingClick(booking);
7736
- }
7737
- }, title: ((_a = booking.metadata) === null || _a === void 0 ? void 0 : _a.title) || 'Untitled' },
7738
- React.createElement("span", { className: "calendar-booking-time" }, moment$1(booking.start).tz(timezone).format('HH:mm')),
7739
- React.createElement("span", { className: "calendar-booking-title" }, ((_b = booking.metadata) === null || _b === void 0 ? void 0 : _b.title) || 'Untitled')));
7740
- }))));
7741
- }
7742
- return React.createElement("div", { className: "calendar-week-view" }, days);
7743
- };
7744
- const renderDayView = () => {
7745
- const current = moment$1(currentDate).tz(timezone);
7746
- const dayBookings = getBookingsForDay(current);
7747
- const isToday = current.isSame(moment$1().tz(timezone), 'day');
7748
- const dayName = current.format('dddd');
7749
- const businessDay = businessHours === null || businessHours === void 0 ? void 0 : businessHours[dayName];
7750
- const isClosed = businessDay === null || businessDay === void 0 ? void 0 : businessDay.isClosed;
7751
- return (React.createElement("div", { className: "calendar-day-view" },
7752
- React.createElement("div", { className: `calendar-day-container ${isToday ? 'calendar-cell-today' : ''}` },
7753
- React.createElement("div", { className: "calendar-day-header" },
7754
- React.createElement("div", { className: "calendar-day-name" }, current.format('dddd')),
7755
- React.createElement("div", { className: "calendar-day-date" }, current.format('MMMM D, YYYY')),
7756
- isClosed ? (React.createElement("div", { className: "calendar-status-closed" }, "Closed")) : businessDay ? (React.createElement("div", { className: "calendar-status-open" },
7757
- "Open: ",
7758
- businessDay.openTime,
7759
- " - ",
7760
- businessDay.closeTime)) : null),
7761
- React.createElement("div", { className: "calendar-day-bookings" }, dayBookings.length === 0 ? (React.createElement("div", { className: "calendar-no-bookings" }, "No bookings for this day")) : (dayBookings.map((booking) => {
7762
- var _a, _b, _c;
7763
- return (React.createElement("div", { key: booking.meeting_id, className: "calendar-booking calendar-day-booking", onClick: () => {
7764
- if (onBookingClick) {
7765
- onBookingClick(booking);
7766
- }
7767
- }, title: ((_a = booking.metadata) === null || _a === void 0 ? void 0 : _a.title) || 'Untitled' },
7768
- React.createElement("span", { className: "calendar-booking-time" },
7769
- moment$1(booking.start).tz(timezone).format('HH:mm'),
7770
- " - ",
7771
- moment$1(booking.end).tz(timezone).format('HH:mm')),
7772
- React.createElement("span", { className: "calendar-booking-title" }, ((_b = booking.metadata) === null || _b === void 0 ? void 0 : _b.title) || 'Untitled'),
7773
- ((_c = booking.metadata) === null || _c === void 0 ? void 0 : _c.description) && (React.createElement("span", { className: "calendar-booking-description" }, booking.metadata.description))));
7774
- }))),
7775
- !isClosed && (React.createElement("button", { className: "calendar-btn calendar-day-add-btn", onClick: () => handleDateClick(current) }, "+ Add Booking")))));
7776
- };
7777
8079
  return (React.createElement("div", { className: "calendar-container" },
7778
- renderHeader(),
8080
+ React.createElement(CalendarHeader, { title: title, currentView: currentView, onViewChange: setCurrentView, onNext: handleNext, onPrevious: handlePrevious, onToday: handleToday, onCreateClick: () => {
8081
+ setSelectedDate(moment$1().tz(timezone).toDate());
8082
+ setShowCreateModal(true);
8083
+ }, dateRangeText: getHeaderDateFormat() }),
7779
8084
  error && React.createElement("div", { className: "calendar-error" }, error),
7780
8085
  loading && React.createElement("div", { className: "calendar-loading" }, "Loading..."),
7781
- currentView === 'month' && (React.createElement(React.Fragment, null,
7782
- renderDaysOfWeek(),
7783
- renderMonthView())),
7784
- currentView === 'week' && renderWeekView(),
7785
- currentView === 'day' && renderDayView(),
8086
+ React.createElement("div", { className: "calendar-content" }, currentView === 'month' ? (React.createElement(MonthView, { currentDate: currentDate, bookings: bookings, timezone: timezone, onBookingClick: onBookingClick, onDateClick: handleDateClick, businessHours: businessHours })) : (React.createElement(TimeGrid, { currentDate: currentDate, view: currentView, bookings: bookings, timezone: timezone, onBookingClick: onBookingClick, onTimeSlotClick: handleDateClick, businessHours: businessHours }))),
7786
8087
  showCreateModal && selectedDate && (React.createElement(CreateBookingModal, { businessId: businessId, apiBaseUrl: apiBaseUrl, initialDate: selectedDate, participants: participants, onClose: () => setShowCreateModal(false), onBookingCreated: handleBookingCreated, timezone: timezone, businessHours: businessHours }))));
7787
8088
  };
7788
8089