@dialiq/calendar-component 1.1.3 → 1.1.4
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/BookingDetailsModal.d.ts.map +1 -1
- package/dist/Calendar.d.ts.map +1 -1
- package/dist/CreateBookingModal.d.ts +3 -1
- package/dist/CreateBookingModal.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +77 -22
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +76 -21
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +10 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BookingDetailsModal.d.ts","sourceRoot":"","sources":["../src/BookingDetailsModal.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"BookingDetailsModal.d.ts","sourceRoot":"","sources":["../src/BookingDetailsModal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAEnD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,OAAO,2BAA2B,CAAC;AAEnC,UAAU,wBAAwB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,gBAAgB,EAAE,MAAM,IAAI,CAAC;CAC9B;AAED,QAAA,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CA4J3D,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
|
package/dist/Calendar.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Calendar.d.ts","sourceRoot":"","sources":["../src/Calendar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2C,MAAM,OAAO,CAAC;AAEhE,OAAO,EAAE,aAAa,EAAW,MAAM,SAAS,CAAC;AAQjD,OAAO,gBAAgB,CAAC;AAIxB,QAAA,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,
|
|
1
|
+
{"version":3,"file":"Calendar.d.ts","sourceRoot":"","sources":["../src/Calendar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA2C,MAAM,OAAO,CAAC;AAEhE,OAAO,EAAE,aAAa,EAAW,MAAM,SAAS,CAAC;AAQjD,OAAO,gBAAgB,CAAC;AAIxB,QAAA,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAyOrC,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { Booking, WeeklyBusinessHours } from './types';
|
|
2
|
+
import { Booking, WeeklyBusinessHours, Employee, Room } from './types';
|
|
3
3
|
import './CreateBookingModal.css';
|
|
4
4
|
interface CreateBookingModalProps {
|
|
5
5
|
businessId: string;
|
|
@@ -10,6 +10,8 @@ interface CreateBookingModalProps {
|
|
|
10
10
|
onBookingCreated: (booking: Booking) => void;
|
|
11
11
|
timezone?: string;
|
|
12
12
|
businessHours?: WeeklyBusinessHours;
|
|
13
|
+
employees?: Employee[];
|
|
14
|
+
rooms?: Room[];
|
|
13
15
|
}
|
|
14
16
|
declare const CreateBookingModal: React.FC<CreateBookingModalProps>;
|
|
15
17
|
export default CreateBookingModal;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateBookingModal.d.ts","sourceRoot":"","sources":["../src/CreateBookingModal.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"CreateBookingModal.d.ts","sourceRoot":"","sources":["../src/CreateBookingModal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA8B,MAAM,OAAO,CAAC;AAGnD,OAAO,EAAE,OAAO,EAAE,mBAAmB,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACvE,OAAO,0BAA0B,CAAC;AAElC,UAAU,uBAAuB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,IAAI,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,gBAAgB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;CAChB;AAMD,QAAA,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAqSzD,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { default as Calendar } from './Calendar';
|
|
2
|
-
export type { CalendarProps, Booking, CreateBookingRequest } from './types';
|
|
2
|
+
export type { CalendarProps, Booking, CreateBookingRequest, Employee, Room } from './types';
|
|
3
3
|
export { createBooking, getResourceSchedule, getAllBookings, getMeetingDetails } from './api';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC;AACjD,YAAY,EAAE,aAAa,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC;AACjD,YAAY,EAAE,aAAa,EAAE,OAAO,EAAE,oBAAoB,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5F,OAAO,EAAE,aAAa,EAAE,mBAAmB,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC"}
|
package/dist/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState, useMemo,
|
|
1
|
+
import React, { useEffect, useState, useMemo, useCallback } from 'react';
|
|
2
2
|
|
|
3
3
|
/******************************************************************************
|
|
4
4
|
Copyright (c) Microsoft Corporation.
|
|
@@ -7437,19 +7437,45 @@ function styleInject(css, ref) {
|
|
|
7437
7437
|
}
|
|
7438
7438
|
}
|
|
7439
7439
|
|
|
7440
|
-
var css_248z$2 = ".modal-overlay {\
|
|
7440
|
+
var css_248z$2 = ".modal-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 1000;\n padding: 20px;\n}\n\n.modal-content {\n background: #ffffff;\n border-radius: 8px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);\n width: 100%;\n max-width: 500px;\n max-height: 90vh;\n overflow-y: auto;\n}\n\n.modal-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 20px;\n border-bottom: 1px solid #e9ecef;\n}\n\n.modal-header h3 {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n color: #212529;\n}\n\n.modal-close-btn {\n background: none;\n border: none;\n font-size: 32px;\n line-height: 1;\n color: #6c757d;\n cursor: pointer;\n padding: 0;\n width: 32px;\n height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n transition: background-color 0.2s;\n}\n\n.modal-close-btn:hover {\n background: #e9ecef;\n color: #212529;\n}\n\n.modal-body {\n padding: 20px;\n}\n\n.modal-footer {\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n padding: 20px;\n border-top: 1px solid #e9ecef;\n}\n\n.modal-error {\n background: #f8d7da;\n color: #842029;\n padding: 12px;\n border-radius: 4px;\n margin-bottom: 16px;\n font-size: 14px;\n}\n\n.form-group {\n margin-bottom: 16px;\n}\n\n.form-group label {\n display: block;\n font-weight: 500;\n font-size: 14px;\n color: #212529;\n margin-bottom: 6px;\n}\n\n.form-group input,\n.form-group textarea {\n width: 100%;\n padding: 10px 12px;\n border: 1px solid #ced4da;\n border-radius: 4px;\n font-size: 14px;\n font-family: inherit;\n color: #212529;\n transition: border-color 0.2s;\n box-sizing: border-box;\n}\n\n.form-group input:focus,\n.form-group textarea:focus {\n outline: none;\n border-color: #0d6efd;\n box-shadow: 0 0 0 3px rgba(13, 110, 253, 0.1);\n}\n\n.form-group textarea {\n resize: vertical;\n}\n\n.form-group small {\n display: block;\n margin-top: 4px;\n font-size: 12px;\n color: #6c757d;\n}\n\n.form-group select {\n width: 100%;\n padding: 10px 12px;\n border: 1px solid #ced4da;\n border-radius: 4px;\n font-size: 14px;\n font-family: inherit;\n color: #212529;\n background: #ffffff;\n cursor: pointer;\n transition: border-color 0.2s;\n box-sizing: border-box;\n}\n\n.form-group select:focus {\n outline: none;\n border-color: #0d6efd;\n box-shadow: 0 0 0 3px rgba(13, 110, 253, 0.1);\n}\n\n.selected-items {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n margin-top: 8px;\n}\n\n.selected-item {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 8px;\n background: #e7f1ff;\n border: 1px solid #b6d4fe;\n border-radius: 4px;\n font-size: 13px;\n color: #0d6efd;\n}\n\n.remove-item-btn {\n background: none;\n border: none;\n padding: 0;\n width: 18px;\n height: 18px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n color: #0d6efd;\n cursor: pointer;\n border-radius: 50%;\n transition: background-color 0.2s;\n}\n\n.remove-item-btn:hover {\n background: #b6d4fe;\n color: #084298;\n}\n\n.form-row {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 12px;\n}\n\n.modal-btn {\n padding: 10px 20px;\n border: none;\n border-radius: 4px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.2s;\n}\n\n.modal-btn:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n.modal-btn-primary {\n background: #0d6efd;\n color: #ffffff;\n}\n\n.modal-btn-primary:hover:not(:disabled) {\n background: #0b5ed7;\n}\n\n.modal-btn-secondary {\n background: #6c757d;\n color: #ffffff;\n}\n\n.modal-btn-secondary:hover:not(:disabled) {\n background: #5c636a;\n}\n\n@media (max-width: 576px) {\n .modal-content {\n max-width: 100%;\n }\n\n .form-row {\n grid-template-columns: 1fr;\n }\n}\n";
|
|
7441
7441
|
styleInject(css_248z$2);
|
|
7442
7442
|
|
|
7443
|
-
const
|
|
7443
|
+
const generateConfirmationNumber = () => {
|
|
7444
|
+
return Math.floor(100000 + Math.random() * 900000).toString();
|
|
7445
|
+
};
|
|
7446
|
+
const CreateBookingModal = ({ businessId, apiBaseUrl, initialDate, participants: defaultParticipants, onClose, onBookingCreated, timezone = moment$1.tz.guess(), businessHours, employees = [], rooms = [], }) => {
|
|
7447
|
+
useEffect(() => {
|
|
7448
|
+
const handleKeyDown = (e) => {
|
|
7449
|
+
if (e.key === 'Escape') {
|
|
7450
|
+
onClose();
|
|
7451
|
+
}
|
|
7452
|
+
};
|
|
7453
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
7454
|
+
return () => document.removeEventListener('keydown', handleKeyDown);
|
|
7455
|
+
}, [onClose]);
|
|
7444
7456
|
const [title, setTitle] = useState('');
|
|
7445
|
-
const [
|
|
7446
|
-
// Initialize date/time using the target timezone
|
|
7457
|
+
const [meetingPurpose, setMeetingPurpose] = useState('');
|
|
7447
7458
|
const [startDate, setStartDate] = useState(moment$1(initialDate).tz(timezone).format("YYYY-MM-DD"));
|
|
7448
7459
|
const [startTime, setStartTime] = useState('09:00');
|
|
7449
7460
|
const [endTime, setEndTime] = useState('10:00');
|
|
7450
|
-
const [
|
|
7461
|
+
const [selectedEmployees, setSelectedEmployees] = useState([]);
|
|
7462
|
+
const [selectedRoom, setSelectedRoom] = useState(null);
|
|
7451
7463
|
const [loading, setLoading] = useState(false);
|
|
7452
7464
|
const [error, setError] = useState(null);
|
|
7465
|
+
const handleAddEmployee = (employeeId) => {
|
|
7466
|
+
const employee = employees.find(e => e.id === employeeId);
|
|
7467
|
+
if (employee && !selectedEmployees.find(e => e.id === employeeId)) {
|
|
7468
|
+
setSelectedEmployees([...selectedEmployees, employee]);
|
|
7469
|
+
}
|
|
7470
|
+
};
|
|
7471
|
+
const handleRemoveEmployee = (employeeId) => {
|
|
7472
|
+
setSelectedEmployees(selectedEmployees.filter(e => e.id !== employeeId));
|
|
7473
|
+
};
|
|
7474
|
+
const handleRoomChange = (roomId) => {
|
|
7475
|
+
const room = rooms.find(r => r.id === roomId);
|
|
7476
|
+
setSelectedRoom(room || null);
|
|
7477
|
+
};
|
|
7478
|
+
const availableEmployees = employees.filter(e => !selectedEmployees.find(se => se.id === e.id));
|
|
7453
7479
|
const validateBusinessHours = (start, end) => {
|
|
7454
7480
|
if (!businessHours)
|
|
7455
7481
|
return;
|
|
@@ -7476,14 +7502,16 @@ const CreateBookingModal = ({ businessId, apiBaseUrl, initialDate, participants:
|
|
|
7476
7502
|
setLoading(true);
|
|
7477
7503
|
setError(null);
|
|
7478
7504
|
try {
|
|
7479
|
-
|
|
7480
|
-
|
|
7481
|
-
.map((p) => p.trim())
|
|
7482
|
-
.filter((p) => p.length > 0);
|
|
7483
|
-
if (participantList.length === 0) {
|
|
7484
|
-
throw new Error('At least one participant is required');
|
|
7505
|
+
if (selectedEmployees.length === 0) {
|
|
7506
|
+
throw new Error('At least one employee is required');
|
|
7485
7507
|
}
|
|
7486
|
-
|
|
7508
|
+
if (!selectedRoom) {
|
|
7509
|
+
throw new Error('A room is required');
|
|
7510
|
+
}
|
|
7511
|
+
const participantList = [
|
|
7512
|
+
selectedRoom.id,
|
|
7513
|
+
...selectedEmployees.map(e => e.id)
|
|
7514
|
+
];
|
|
7487
7515
|
const startDateTime = moment$1.tz(`${startDate}T${startTime}`, "YYYY-MM-DDTHH:mm", timezone);
|
|
7488
7516
|
const endDateTime = moment$1.tz(`${startDate}T${endTime}`, "YYYY-MM-DDTHH:mm", timezone);
|
|
7489
7517
|
if (!startDateTime.isValid() || !endDateTime.isValid()) {
|
|
@@ -7492,15 +7520,18 @@ const CreateBookingModal = ({ businessId, apiBaseUrl, initialDate, participants:
|
|
|
7492
7520
|
if (endDateTime.isSameOrBefore(startDateTime)) {
|
|
7493
7521
|
throw new Error('End time must be after start time');
|
|
7494
7522
|
}
|
|
7495
|
-
// Validate Business Hours
|
|
7496
7523
|
validateBusinessHours(startDateTime, endDateTime);
|
|
7524
|
+
const confirmationNumber = generateConfirmationNumber();
|
|
7497
7525
|
const booking = yield createBooking(businessId, {
|
|
7498
7526
|
participants: participantList,
|
|
7499
7527
|
start: startDateTime.format(),
|
|
7500
7528
|
end: endDateTime.format(),
|
|
7501
7529
|
metadata: {
|
|
7530
|
+
description: meetingPurpose,
|
|
7502
7531
|
title: title || 'Untitled Meeting',
|
|
7503
|
-
|
|
7532
|
+
staff: selectedEmployees.map(e => e.name).join(', '),
|
|
7533
|
+
room: selectedRoom.name,
|
|
7534
|
+
confirmation: confirmationNumber,
|
|
7504
7535
|
},
|
|
7505
7536
|
}, apiBaseUrl);
|
|
7506
7537
|
onBookingCreated(booking);
|
|
@@ -7524,12 +7555,27 @@ const CreateBookingModal = ({ businessId, apiBaseUrl, initialDate, participants:
|
|
|
7524
7555
|
React.createElement("label", { htmlFor: "title" }, "Title"),
|
|
7525
7556
|
React.createElement("input", { id: "title", type: "text", value: title, onChange: (e) => setTitle(e.target.value), placeholder: "Meeting title", required: true })),
|
|
7526
7557
|
React.createElement("div", { className: "form-group" },
|
|
7527
|
-
React.createElement("label", { htmlFor: "
|
|
7528
|
-
React.createElement("textarea", { id: "
|
|
7558
|
+
React.createElement("label", { htmlFor: "meetingPurpose" }, "What is this meeting for?"),
|
|
7559
|
+
React.createElement("textarea", { id: "meetingPurpose", value: meetingPurpose, onChange: (e) => setMeetingPurpose(e.target.value), placeholder: "Enter the purpose of this meeting", rows: 3 })),
|
|
7560
|
+
React.createElement("div", { className: "form-group" },
|
|
7561
|
+
React.createElement("label", { htmlFor: "room" }, "Room *"),
|
|
7562
|
+
React.createElement("select", { id: "room", value: (selectedRoom === null || selectedRoom === void 0 ? void 0 : selectedRoom.id) || '', onChange: (e) => handleRoomChange(e.target.value), required: true },
|
|
7563
|
+
React.createElement("option", { value: "" }, "Select a room"),
|
|
7564
|
+
rooms.map((room) => (React.createElement("option", { key: room.id, value: room.id }, room.name))))),
|
|
7529
7565
|
React.createElement("div", { className: "form-group" },
|
|
7530
|
-
React.createElement("label", { htmlFor: "
|
|
7531
|
-
React.createElement("
|
|
7532
|
-
|
|
7566
|
+
React.createElement("label", { htmlFor: "employees" }, "Employees *"),
|
|
7567
|
+
React.createElement("select", { id: "employees", value: "", onChange: (e) => {
|
|
7568
|
+
if (e.target.value) {
|
|
7569
|
+
handleAddEmployee(e.target.value);
|
|
7570
|
+
e.target.value = '';
|
|
7571
|
+
}
|
|
7572
|
+
} },
|
|
7573
|
+
React.createElement("option", { value: "" }, "Add an employee"),
|
|
7574
|
+
availableEmployees.map((employee) => (React.createElement("option", { key: employee.id, value: employee.id }, employee.name)))),
|
|
7575
|
+
selectedEmployees.length > 0 && (React.createElement("div", { className: "selected-items" }, selectedEmployees.map((employee) => (React.createElement("span", { key: employee.id, className: "selected-item" },
|
|
7576
|
+
employee.name,
|
|
7577
|
+
React.createElement("button", { type: "button", className: "remove-item-btn", onClick: () => handleRemoveEmployee(employee.id) }, "\u00D7")))))),
|
|
7578
|
+
React.createElement("small", null, "At least one employee is required")),
|
|
7533
7579
|
React.createElement("div", { className: "form-row" },
|
|
7534
7580
|
React.createElement("div", { className: "form-group" },
|
|
7535
7581
|
React.createElement("label", { htmlFor: "date" }, "Date"),
|
|
@@ -7555,6 +7601,15 @@ styleInject(css_248z$1);
|
|
|
7555
7601
|
|
|
7556
7602
|
const BookingDetailsModal = ({ booking, timezone, businessId, apiBaseUrl, onClose, onBookingDeleted, }) => {
|
|
7557
7603
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
7604
|
+
useEffect(() => {
|
|
7605
|
+
const handleKeyDown = (e) => {
|
|
7606
|
+
if (e.key === 'Escape') {
|
|
7607
|
+
onClose();
|
|
7608
|
+
}
|
|
7609
|
+
};
|
|
7610
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
7611
|
+
return () => document.removeEventListener('keydown', handleKeyDown);
|
|
7612
|
+
}, [onClose]);
|
|
7558
7613
|
const [showConfirm, setShowConfirm] = useState(false);
|
|
7559
7614
|
const [deleting, setDeleting] = useState(false);
|
|
7560
7615
|
const [error, setError] = useState(null);
|
|
@@ -8016,7 +8071,7 @@ const MonthView = ({ currentDate, bookings, timezone, onBookingClick, onDateClic
|
|
|
8016
8071
|
var css_248z = ".calendar-container {\r\n font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\r\n border: 1px solid #e0e0e0;\r\n border-radius: 8px;\r\n display: flex;\r\n flex-direction: column;\r\n height: 100%;\r\n /* Use 100% height of parent */\r\n max-height: 100vh;\r\n overflow: hidden;\r\n}\r\n\r\n/* Header */\r\n.calendar-header {\r\n padding: 16px;\r\n border-bottom: 1px solid #e0e0e0;\r\n background-color: #fff;\r\n}\r\n\r\n.calendar-title-section {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n margin-bottom: 16px;\r\n flex-wrap: wrap;\r\n gap: 10px;\r\n}\r\n\r\n.calendar-title {\r\n margin: 0;\r\n font-size: 1.5rem;\r\n color: #333;\r\n}\r\n\r\n.calendar-view-toggle {\r\n display: flex;\r\n background-color: #f5f5f5;\r\n border-radius: 6px;\r\n padding: 2px;\r\n}\r\n\r\n.calendar-btn {\r\n padding: 8px 16px;\r\n border: 1px solid #e0e0e0;\r\n background-color: #fff;\r\n cursor: pointer;\r\n border-radius: 4px;\r\n font-size: 14px;\r\n transition: all 0.2s;\r\n}\r\n\r\n.calendar-btn:hover {\r\n background-color: #f5f5f5;\r\n}\r\n\r\n.calendar-btn-view {\r\n border: none;\r\n background: transparent;\r\n border-radius: 4px;\r\n padding: 6px 12px;\r\n}\r\n\r\n.calendar-btn-view.active {\r\n background-color: #fff;\r\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\r\n font-weight: 600;\r\n}\r\n\r\n.calendar-btn-create {\r\n background-color: #0078d4;\r\n color: white;\r\n border: none;\r\n}\r\n\r\n.calendar-btn-create:hover {\r\n background-color: #106ebe;\r\n}\r\n\r\n.calendar-navigation {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n}\r\n\r\n.calendar-current-month {\r\n font-size: 1.1rem;\r\n font-weight: 600;\r\n margin-left: 16px;\r\n color: #333;\r\n}\r\n\r\n/* Content Area */\r\n.calendar-content {\r\n flex: 1;\r\n overflow: hidden;\r\n display: flex;\r\n flex-direction: column;\r\n}\r\n\r\n/* Month View */\r\n.month-view-container {\r\n flex: 1;\r\n display: flex;\r\n flex-direction: column;\r\n overflow: hidden;\r\n /* Prevent container scrolling, let body scroll */\r\n}\r\n\r\n.calendar-days-row {\r\n display: grid;\r\n grid-template-columns: repeat(7, 1fr);\r\n /* Ensure equal columns */\r\n border-bottom: 1px solid #e0e0e0;\r\n background-color: #f9f9f9;\r\n}\r\n\r\n.calendar-day-header {\r\n padding: 10px;\r\n text-align: center;\r\n font-weight: 600;\r\n color: #666;\r\n font-size: 0.9rem;\r\n overflow: hidden;\r\n /* Prevent overflow */\r\n text-overflow: ellipsis;\r\n}\r\n\r\n.calendar-body {\r\n display: flex;\r\n flex-direction: column;\r\n flex: 1;\r\n overflow-y: auto;\r\n /* Scrollable body */\r\n}\r\n\r\n.calendar-row {\r\n display: grid;\r\n grid-template-columns: repeat(7, 1fr);\r\n /* Ensure equal columns */\r\n flex: 1;\r\n min-height: 100px;\r\n /* Minimum row height */\r\n border-bottom: 1px solid #e0e0e0;\r\n}\r\n\r\n.calendar-cell {\r\n border-right: 1px solid #e0e0e0;\r\n padding: 8px;\r\n position: relative;\r\n cursor: pointer;\r\n transition: background-color 0.2s;\r\n overflow: hidden;\r\n /* Prevent cell expansion */\r\n min-width: 0;\r\n /* Allow shrinking below content size */\r\n}\r\n\r\n.calendar-cell:hover {\r\n background-color: #fcfcfc;\r\n}\r\n\r\n.calendar-cell-disabled {\r\n background-color: #f9f9f9;\r\n color: #999;\r\n}\r\n\r\n.calendar-cell-today {\r\n background-color: #e6f2ff;\r\n}\r\n\r\n.calendar-cell-closed {\r\n background-color: #f5f5f5;\r\n cursor: not-allowed;\r\n}\r\n\r\n.calendar-cell-header {\r\n display: flex;\r\n justify-content: space-between;\r\n align-items: center;\r\n margin-bottom: 4px;\r\n}\r\n\r\n.calendar-cell-number {\r\n font-weight: 600;\r\n font-size: 0.9rem;\r\n}\r\n\r\n.calendar-closed-label-small {\r\n font-size: 0.7rem;\r\n color: #d13438;\r\n background: #fde7e9;\r\n padding: 2px 4px;\r\n border-radius: 3px;\r\n}\r\n\r\n.calendar-cell-bookings {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 4px;\r\n}\r\n\r\n.calendar-booking {\r\n background-color: #e1dfdd;\r\n /* Default neutral color */\r\n border-left: 3px solid #0078d4;\r\n padding: 4px 6px;\r\n border-radius: 2px;\r\n font-size: 0.8rem;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n cursor: pointer;\r\n position: relative;\r\n /* For tooltip positioning */\r\n}\r\n\r\n.calendar-booking:hover {\r\n background-color: #d0d0d0;\r\n}\r\n\r\n.calendar-booking-time {\r\n font-weight: 600;\r\n margin-right: 4px;\r\n}\r\n\r\n.calendar-booking-more {\r\n font-size: 0.8rem;\r\n color: #666;\r\n padding: 2px 4px;\r\n}\r\n\r\n/* Time Grid (Day/Week/WorkWeek) */\r\n.time-grid-container {\r\n display: flex;\r\n flex-direction: column;\r\n flex: 1;\r\n overflow: hidden;\r\n}\r\n\r\n.time-grid-header {\r\n display: flex;\r\n border-bottom: 1px solid #e0e0e0;\r\n padding-right: 17px;\r\n /* Adjust for scrollbar */\r\n}\r\n\r\n.time-column-header {\r\n width: 60px;\r\n /* Width of time labels column */\r\n flex-shrink: 0;\r\n border-right: 1px solid #e0e0e0;\r\n}\r\n\r\n.day-column-header {\r\n flex: 1;\r\n text-align: center;\r\n padding: 8px;\r\n border-right: 1px solid #e0e0e0;\r\n background-color: #f9f9f9;\r\n min-width: 0;\r\n /* Prevent expansion */\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n}\r\n\r\n.day-column-header.today {\r\n background-color: #e6f2ff;\r\n color: #0078d4;\r\n}\r\n\r\n.day-column-header.closed {\r\n background-color: #f0f0f0;\r\n color: #999;\r\n}\r\n\r\n.day-name {\r\n font-size: 0.8rem;\r\n text-transform: uppercase;\r\n color: #666;\r\n}\r\n\r\n.day-number {\r\n font-size: 1.2rem;\r\n font-weight: 600;\r\n}\r\n\r\n.time-grid-body {\r\n display: flex;\r\n flex: 1;\r\n overflow-y: auto;\r\n position: relative;\r\n}\r\n\r\n.time-labels-column {\r\n width: 60px;\r\n flex-shrink: 0;\r\n border-right: 1px solid #e0e0e0;\r\n background-color: #fff;\r\n}\r\n\r\n.time-label {\r\n height: 60px;\r\n /* 1 hour height */\r\n text-align: right;\r\n padding-right: 8px;\r\n font-size: 0.75rem;\r\n color: #666;\r\n justify-content: center;\r\n}\r\n\r\n.days-grid {\r\n flex: 1;\r\n display: flex;\r\n position: relative;\r\n /* 24 hours * 60px/hour = 1440px total height */\r\n height: 1440px;\r\n}\r\n\r\n.grid-lines {\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n right: 0;\r\n bottom: 0;\r\n pointer-events: none;\r\n z-index: 0;\r\n}\r\n\r\n.grid-hour-row {\r\n height: 60px;\r\n border-bottom: 1px solid #e0e0e0;\r\n box-sizing: border-box;\r\n}\r\n\r\n.grid-hour-row:last-child {\r\n border-bottom: none;\r\n}\r\n\r\n.day-column {\r\n flex: 1;\r\n border-right: 1px solid #e0e0e0;\r\n position: relative;\r\n height: 100%;\r\n min-width: 0;\r\n /* Critical for flex containers to not expand based on content */\r\n}\r\n\r\n.day-column.closed-column {\r\n background-color: repeating-linear-gradient(45deg,\r\n #fbfbfb,\r\n #fbfbfb 10px,\r\n #f5f5f5 10px,\r\n #f5f5f5 20px);\r\n}\r\n\r\n.calendar-event {\r\n background-color: #e1dfdd;\r\n border-left: 4px solid #0078d4;\r\n border-radius: 3px;\r\n padding: 2px 4px;\r\n font-size: 0.75rem;\r\n overflow: hidden;\r\n cursor: pointer;\r\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\r\n z-index: 1;\r\n transition: transform 0.1s, z-index 0.1s;\r\n}\r\n\r\n.calendar-event:hover {\r\n z-index: 10;\r\n /* Bring to front on hover */\r\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);\r\n}\r\n\r\n.event-content {\r\n height: 100%;\r\n overflow: hidden;\r\n}\r\n\r\n.event-title {\r\n font-weight: 600;\r\n margin-bottom: 2px;\r\n}\r\n\r\n.event-time {\r\n font-size: 0.7rem;\r\n color: #555;\r\n}\r\n\r\n/* Tooltip Styles */\r\n.event-tooltip {\r\n display: none;\r\n position: absolute;\r\n left: 100%;\r\n top: 0;\r\n background: white;\r\n border: 1px solid #ccc;\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\r\n padding: 10px;\r\n border-radius: 4px;\r\n width: 200px;\r\n z-index: 100;\r\n pointer-events: none;\r\n}\r\n\r\n/* Show tooltip on hover */\r\n.calendar-booking:hover .event-tooltip,\r\n.calendar-event:hover .event-tooltip {\r\n display: block;\r\n}\r\n\r\n/* Adjust tooltip position if it goes offscreen (simple right-side check) */\r\n/* Note: A real production app would use a library like Popper.js */\r\n.day-column:last-child .event-tooltip,\r\n.day-column:nth-last-child(2) .event-tooltip {\r\n left: auto;\r\n right: 100%;\r\n}\r\n\r\n.tooltip-title {\r\n font-weight: bold;\r\n margin-bottom: 8px;\r\n border-bottom: 1px solid #eee;\r\n padding-bottom: 4px;\r\n}\r\n\r\n.tooltip-row {\r\n display: flex;\r\n justify-content: space-between;\r\n margin-bottom: 4px;\r\n font-size: 0.85rem;\r\n}\r\n\r\n.tooltip-label {\r\n color: #666;\r\n margin-right: 8px;\r\n}\r\n\r\n.tooltip-value {\r\n font-weight: 500;\r\n text-align: right;\r\n}\r\n\r\n/* Loading & Error */\r\n.calendar-loading,\r\n.calendar-error {\r\n padding: 20px;\r\n text-align: center;\r\n color: #666;\r\n}\r\n\r\n.calendar-error {\r\n color: #d13438;\r\n}\r\n\r\n/* Closed Block Styles */\r\n.calendar-closed-block {\r\n position: absolute;\r\n left: 0;\r\n right: 0;\r\n background-color: #f0f0f0;\r\n background-image: repeating-linear-gradient(45deg,\r\n #f0f0f0,\r\n #f0f0f0 10px,\r\n #e8e8e8 10px,\r\n #e8e8e8 20px);\r\n display: flex;\r\n justify-content: center;\r\n align-items: center;\r\n z-index: 5;\r\n /* Below events but above grid lines */\r\n pointer-events: none;\r\n /* Allow clicks to pass through if needed, though we block clicks in JS */\r\n border-bottom: 1px solid #ddd;\r\n border-top: 1px solid #ddd;\r\n}\r\n\r\n.closed-block-label {\r\n background-color: rgba(255, 255, 255, 0.8);\r\n padding: 4px 8px;\r\n border-radius: 4px;\r\n font-size: 0.8rem;\r\n color: #888;\r\n font-weight: 500;\r\n}";
|
|
8017
8072
|
styleInject(css_248z);
|
|
8018
8073
|
|
|
8019
|
-
const Calendar = ({ businessId, resourceId, title = 'Calendar', apiBaseUrl, defaultView = 'month', onBookingCreate, onBookingClick, participants = [], timezone = moment$1.tz.guess(), businessHours, }) => {
|
|
8074
|
+
const Calendar = ({ businessId, resourceId, title = 'Calendar', apiBaseUrl, defaultView = 'month', onBookingCreate, onBookingClick, participants = [], timezone = moment$1.tz.guess(), businessHours, employees = [], rooms = [], }) => {
|
|
8020
8075
|
const [currentDate, setCurrentDate] = useState(moment$1().tz(timezone));
|
|
8021
8076
|
const [currentView, setCurrentView] = useState(defaultView);
|
|
8022
8077
|
const [bookings, setBookings] = useState([]);
|
|
@@ -8152,7 +8207,7 @@ const Calendar = ({ businessId, resourceId, title = 'Calendar', apiBaseUrl, defa
|
|
|
8152
8207
|
error && React.createElement("div", { className: "calendar-error" }, error),
|
|
8153
8208
|
loading && React.createElement("div", { className: "calendar-loading" }, "Loading..."),
|
|
8154
8209
|
React.createElement("div", { className: "calendar-content" }, currentView === 'month' ? (React.createElement(MonthView, { currentDate: currentDate, bookings: bookings, timezone: timezone, onBookingClick: handleInternalBookingClick, onDateClick: handleDateClick, businessHours: businessHours })) : (React.createElement(TimeGrid, { currentDate: currentDate, view: currentView, bookings: bookings, timezone: timezone, onBookingClick: handleInternalBookingClick, onTimeSlotClick: handleDateClick, businessHours: businessHours }))),
|
|
8155
|
-
showCreateModal && selectedDate && (React.createElement(CreateBookingModal, { businessId: businessId, apiBaseUrl: apiBaseUrl, initialDate: selectedDate, participants: participants, onClose: () => setShowCreateModal(false), onBookingCreated: handleBookingCreated, timezone: timezone, businessHours: businessHours })),
|
|
8210
|
+
showCreateModal && selectedDate && (React.createElement(CreateBookingModal, { businessId: businessId, apiBaseUrl: apiBaseUrl, initialDate: selectedDate, participants: participants, onClose: () => setShowCreateModal(false), onBookingCreated: handleBookingCreated, timezone: timezone, businessHours: businessHours, employees: employees, rooms: rooms })),
|
|
8156
8211
|
selectedBooking && (React.createElement(BookingDetailsModal, { booking: selectedBooking, timezone: timezone, businessId: businessId, apiBaseUrl: apiBaseUrl, onClose: () => setSelectedBooking(null), onBookingDeleted: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
8157
8212
|
setSelectedBooking(null);
|
|
8158
8213
|
yield fetchBookings();
|