@dialiq/calendar-component 1.1.2 → 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 +3 -0
- 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/api.d.ts +3 -0
- package/dist/api.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 +123 -26
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +122 -25
- 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
package/dist/index.js
CHANGED
|
@@ -7400,6 +7400,17 @@ const getMeetingDetails = (businessId, meetingId, timezone, apiBaseUrl) => __awa
|
|
|
7400
7400
|
}
|
|
7401
7401
|
return response.json();
|
|
7402
7402
|
});
|
|
7403
|
+
const deleteMeeting = (businessId, meetingId, apiBaseUrl) => __awaiter(void 0, void 0, void 0, function* () {
|
|
7404
|
+
const baseUrl = apiBaseUrl || getBaseUrl();
|
|
7405
|
+
const response = yield fetch(`${baseUrl}/businesses/${businessId}/meetings/${meetingId}`, {
|
|
7406
|
+
method: 'DELETE',
|
|
7407
|
+
});
|
|
7408
|
+
if (!response.ok) {
|
|
7409
|
+
const error = yield response.json();
|
|
7410
|
+
throw new Error(error.error || 'Failed to delete meeting');
|
|
7411
|
+
}
|
|
7412
|
+
return response.json();
|
|
7413
|
+
});
|
|
7403
7414
|
|
|
7404
7415
|
function styleInject(css, ref) {
|
|
7405
7416
|
if ( ref === void 0 ) ref = {};
|
|
@@ -7428,19 +7439,45 @@ function styleInject(css, ref) {
|
|
|
7428
7439
|
}
|
|
7429
7440
|
}
|
|
7430
7441
|
|
|
7431
|
-
var css_248z$2 = ".modal-overlay {\
|
|
7442
|
+
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";
|
|
7432
7443
|
styleInject(css_248z$2);
|
|
7433
7444
|
|
|
7434
|
-
const
|
|
7445
|
+
const generateConfirmationNumber = () => {
|
|
7446
|
+
return Math.floor(100000 + Math.random() * 900000).toString();
|
|
7447
|
+
};
|
|
7448
|
+
const CreateBookingModal = ({ businessId, apiBaseUrl, initialDate, participants: defaultParticipants, onClose, onBookingCreated, timezone = moment$1.tz.guess(), businessHours, employees = [], rooms = [], }) => {
|
|
7449
|
+
React.useEffect(() => {
|
|
7450
|
+
const handleKeyDown = (e) => {
|
|
7451
|
+
if (e.key === 'Escape') {
|
|
7452
|
+
onClose();
|
|
7453
|
+
}
|
|
7454
|
+
};
|
|
7455
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
7456
|
+
return () => document.removeEventListener('keydown', handleKeyDown);
|
|
7457
|
+
}, [onClose]);
|
|
7435
7458
|
const [title, setTitle] = React.useState('');
|
|
7436
|
-
const [
|
|
7437
|
-
// Initialize date/time using the target timezone
|
|
7459
|
+
const [meetingPurpose, setMeetingPurpose] = React.useState('');
|
|
7438
7460
|
const [startDate, setStartDate] = React.useState(moment$1(initialDate).tz(timezone).format("YYYY-MM-DD"));
|
|
7439
7461
|
const [startTime, setStartTime] = React.useState('09:00');
|
|
7440
7462
|
const [endTime, setEndTime] = React.useState('10:00');
|
|
7441
|
-
const [
|
|
7463
|
+
const [selectedEmployees, setSelectedEmployees] = React.useState([]);
|
|
7464
|
+
const [selectedRoom, setSelectedRoom] = React.useState(null);
|
|
7442
7465
|
const [loading, setLoading] = React.useState(false);
|
|
7443
7466
|
const [error, setError] = React.useState(null);
|
|
7467
|
+
const handleAddEmployee = (employeeId) => {
|
|
7468
|
+
const employee = employees.find(e => e.id === employeeId);
|
|
7469
|
+
if (employee && !selectedEmployees.find(e => e.id === employeeId)) {
|
|
7470
|
+
setSelectedEmployees([...selectedEmployees, employee]);
|
|
7471
|
+
}
|
|
7472
|
+
};
|
|
7473
|
+
const handleRemoveEmployee = (employeeId) => {
|
|
7474
|
+
setSelectedEmployees(selectedEmployees.filter(e => e.id !== employeeId));
|
|
7475
|
+
};
|
|
7476
|
+
const handleRoomChange = (roomId) => {
|
|
7477
|
+
const room = rooms.find(r => r.id === roomId);
|
|
7478
|
+
setSelectedRoom(room || null);
|
|
7479
|
+
};
|
|
7480
|
+
const availableEmployees = employees.filter(e => !selectedEmployees.find(se => se.id === e.id));
|
|
7444
7481
|
const validateBusinessHours = (start, end) => {
|
|
7445
7482
|
if (!businessHours)
|
|
7446
7483
|
return;
|
|
@@ -7467,14 +7504,16 @@ const CreateBookingModal = ({ businessId, apiBaseUrl, initialDate, participants:
|
|
|
7467
7504
|
setLoading(true);
|
|
7468
7505
|
setError(null);
|
|
7469
7506
|
try {
|
|
7470
|
-
|
|
7471
|
-
|
|
7472
|
-
.map((p) => p.trim())
|
|
7473
|
-
.filter((p) => p.length > 0);
|
|
7474
|
-
if (participantList.length === 0) {
|
|
7475
|
-
throw new Error('At least one participant is required');
|
|
7507
|
+
if (selectedEmployees.length === 0) {
|
|
7508
|
+
throw new Error('At least one employee is required');
|
|
7476
7509
|
}
|
|
7477
|
-
|
|
7510
|
+
if (!selectedRoom) {
|
|
7511
|
+
throw new Error('A room is required');
|
|
7512
|
+
}
|
|
7513
|
+
const participantList = [
|
|
7514
|
+
selectedRoom.id,
|
|
7515
|
+
...selectedEmployees.map(e => e.id)
|
|
7516
|
+
];
|
|
7478
7517
|
const startDateTime = moment$1.tz(`${startDate}T${startTime}`, "YYYY-MM-DDTHH:mm", timezone);
|
|
7479
7518
|
const endDateTime = moment$1.tz(`${startDate}T${endTime}`, "YYYY-MM-DDTHH:mm", timezone);
|
|
7480
7519
|
if (!startDateTime.isValid() || !endDateTime.isValid()) {
|
|
@@ -7483,15 +7522,18 @@ const CreateBookingModal = ({ businessId, apiBaseUrl, initialDate, participants:
|
|
|
7483
7522
|
if (endDateTime.isSameOrBefore(startDateTime)) {
|
|
7484
7523
|
throw new Error('End time must be after start time');
|
|
7485
7524
|
}
|
|
7486
|
-
// Validate Business Hours
|
|
7487
7525
|
validateBusinessHours(startDateTime, endDateTime);
|
|
7526
|
+
const confirmationNumber = generateConfirmationNumber();
|
|
7488
7527
|
const booking = yield createBooking(businessId, {
|
|
7489
7528
|
participants: participantList,
|
|
7490
7529
|
start: startDateTime.format(),
|
|
7491
7530
|
end: endDateTime.format(),
|
|
7492
7531
|
metadata: {
|
|
7532
|
+
description: meetingPurpose,
|
|
7493
7533
|
title: title || 'Untitled Meeting',
|
|
7494
|
-
|
|
7534
|
+
staff: selectedEmployees.map(e => e.name).join(', '),
|
|
7535
|
+
room: selectedRoom.name,
|
|
7536
|
+
confirmation: confirmationNumber,
|
|
7495
7537
|
},
|
|
7496
7538
|
}, apiBaseUrl);
|
|
7497
7539
|
onBookingCreated(booking);
|
|
@@ -7515,12 +7557,27 @@ const CreateBookingModal = ({ businessId, apiBaseUrl, initialDate, participants:
|
|
|
7515
7557
|
React.createElement("label", { htmlFor: "title" }, "Title"),
|
|
7516
7558
|
React.createElement("input", { id: "title", type: "text", value: title, onChange: (e) => setTitle(e.target.value), placeholder: "Meeting title", required: true })),
|
|
7517
7559
|
React.createElement("div", { className: "form-group" },
|
|
7518
|
-
React.createElement("label", { htmlFor: "
|
|
7519
|
-
React.createElement("textarea", { id: "
|
|
7560
|
+
React.createElement("label", { htmlFor: "meetingPurpose" }, "What is this meeting for?"),
|
|
7561
|
+
React.createElement("textarea", { id: "meetingPurpose", value: meetingPurpose, onChange: (e) => setMeetingPurpose(e.target.value), placeholder: "Enter the purpose of this meeting", rows: 3 })),
|
|
7562
|
+
React.createElement("div", { className: "form-group" },
|
|
7563
|
+
React.createElement("label", { htmlFor: "room" }, "Room *"),
|
|
7564
|
+
React.createElement("select", { id: "room", value: (selectedRoom === null || selectedRoom === void 0 ? void 0 : selectedRoom.id) || '', onChange: (e) => handleRoomChange(e.target.value), required: true },
|
|
7565
|
+
React.createElement("option", { value: "" }, "Select a room"),
|
|
7566
|
+
rooms.map((room) => (React.createElement("option", { key: room.id, value: room.id }, room.name))))),
|
|
7520
7567
|
React.createElement("div", { className: "form-group" },
|
|
7521
|
-
React.createElement("label", { htmlFor: "
|
|
7522
|
-
React.createElement("
|
|
7523
|
-
|
|
7568
|
+
React.createElement("label", { htmlFor: "employees" }, "Employees *"),
|
|
7569
|
+
React.createElement("select", { id: "employees", value: "", onChange: (e) => {
|
|
7570
|
+
if (e.target.value) {
|
|
7571
|
+
handleAddEmployee(e.target.value);
|
|
7572
|
+
e.target.value = '';
|
|
7573
|
+
}
|
|
7574
|
+
} },
|
|
7575
|
+
React.createElement("option", { value: "" }, "Add an employee"),
|
|
7576
|
+
availableEmployees.map((employee) => (React.createElement("option", { key: employee.id, value: employee.id }, employee.name)))),
|
|
7577
|
+
selectedEmployees.length > 0 && (React.createElement("div", { className: "selected-items" }, selectedEmployees.map((employee) => (React.createElement("span", { key: employee.id, className: "selected-item" },
|
|
7578
|
+
employee.name,
|
|
7579
|
+
React.createElement("button", { type: "button", className: "remove-item-btn", onClick: () => handleRemoveEmployee(employee.id) }, "\u00D7")))))),
|
|
7580
|
+
React.createElement("small", null, "At least one employee is required")),
|
|
7524
7581
|
React.createElement("div", { className: "form-row" },
|
|
7525
7582
|
React.createElement("div", { className: "form-group" },
|
|
7526
7583
|
React.createElement("label", { htmlFor: "date" }, "Date"),
|
|
@@ -7541,20 +7598,57 @@ const CreateBookingModal = ({ businessId, apiBaseUrl, initialDate, participants:
|
|
|
7541
7598
|
React.createElement("button", { type: "submit", className: "modal-btn modal-btn-primary", disabled: loading }, loading ? 'Creating...' : 'Create Booking'))))));
|
|
7542
7599
|
};
|
|
7543
7600
|
|
|
7544
|
-
var css_248z$1 = "/* BookingDetailsModal - extends base modal styles from CreateBookingModal.css */\
|
|
7601
|
+
var css_248z$1 = "/* BookingDetailsModal - extends base modal styles from CreateBookingModal.css */\n\n.booking-details-modal {\n max-width: 500px;\n}\n\n.detail-section {\n padding: 12px 0;\n border-bottom: 1px solid #e9ecef;\n}\n\n.detail-section:last-child {\n border-bottom: none;\n}\n\n.detail-row {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n margin-bottom: 8px;\n}\n\n.detail-row:last-child {\n margin-bottom: 0;\n}\n\n.detail-row.full-width {\n flex-direction: column;\n}\n\n.detail-label {\n font-weight: 500;\n color: #6c757d;\n font-size: 14px;\n min-width: 100px;\n}\n\n.detail-label-muted {\n color: #adb5bd;\n font-size: 12px;\n}\n\n.detail-value {\n font-weight: 500;\n color: #212529;\n font-size: 14px;\n text-align: right;\n}\n\n.detail-value-muted {\n color: #adb5bd;\n font-size: 12px;\n font-family: monospace;\n}\n\n.detail-description {\n margin: 8px 0 0 0;\n color: #495057;\n font-size: 14px;\n line-height: 1.5;\n white-space: pre-wrap;\n}\n\n.participants-list {\n margin: 8px 0 0 0;\n padding-left: 20px;\n list-style-type: disc;\n}\n\n.participant-item {\n color: #495057;\n font-size: 14px;\n margin-bottom: 4px;\n}\n\n.modal-header-actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.modal-delete-btn {\n background: none;\n border: none;\n color: #dc3545;\n cursor: pointer;\n padding: 6px;\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-delete-btn:hover:not(:disabled) {\n background: #f8d7da;\n}\n\n.modal-delete-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.delete-confirm-box {\n background: #fff3cd;\n border: 1px solid #ffc107;\n border-radius: 4px;\n padding: 16px;\n margin-bottom: 16px;\n}\n\n.delete-confirm-box p {\n margin: 0 0 12px 0;\n font-size: 14px;\n color: #856404;\n}\n\n.delete-confirm-actions {\n display: flex;\n gap: 8px;\n justify-content: flex-end;\n}\n\n.modal-btn-danger {\n background: #dc3545;\n color: #ffffff;\n}\n\n.modal-btn-danger:hover:not(:disabled) {\n background: #bb2d3b;\n}\n\n@media (max-width: 576px) {\n .booking-details-modal {\n max-width: 100%;\n }\n\n .detail-row {\n flex-direction: column;\n gap: 4px;\n }\n\n .detail-value {\n text-align: left;\n }\n}\n";
|
|
7545
7602
|
styleInject(css_248z$1);
|
|
7546
7603
|
|
|
7547
|
-
const BookingDetailsModal = ({ booking, timezone, onClose, }) => {
|
|
7604
|
+
const BookingDetailsModal = ({ booking, timezone, businessId, apiBaseUrl, onClose, onBookingDeleted, }) => {
|
|
7548
7605
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
7606
|
+
React.useEffect(() => {
|
|
7607
|
+
const handleKeyDown = (e) => {
|
|
7608
|
+
if (e.key === 'Escape') {
|
|
7609
|
+
onClose();
|
|
7610
|
+
}
|
|
7611
|
+
};
|
|
7612
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
7613
|
+
return () => document.removeEventListener('keydown', handleKeyDown);
|
|
7614
|
+
}, [onClose]);
|
|
7615
|
+
const [showConfirm, setShowConfirm] = React.useState(false);
|
|
7616
|
+
const [deleting, setDeleting] = React.useState(false);
|
|
7617
|
+
const [error, setError] = React.useState(null);
|
|
7549
7618
|
const startMoment = moment$1(booking.start).tz(timezone);
|
|
7550
7619
|
const endMoment = moment$1(booking.end).tz(timezone);
|
|
7551
7620
|
const durationMinutes = endMoment.diff(startMoment, 'minutes');
|
|
7621
|
+
const handleDelete = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
7622
|
+
setDeleting(true);
|
|
7623
|
+
setError(null);
|
|
7624
|
+
try {
|
|
7625
|
+
yield deleteMeeting(businessId, booking.meeting_id, apiBaseUrl);
|
|
7626
|
+
onBookingDeleted();
|
|
7627
|
+
}
|
|
7628
|
+
catch (err) {
|
|
7629
|
+
setError(err instanceof Error ? err.message : 'Failed to delete meeting');
|
|
7630
|
+
setDeleting(false);
|
|
7631
|
+
}
|
|
7632
|
+
});
|
|
7552
7633
|
return (React.createElement("div", { className: "modal-overlay", onClick: onClose },
|
|
7553
7634
|
React.createElement("div", { className: "modal-content booking-details-modal", onClick: (e) => e.stopPropagation() },
|
|
7554
7635
|
React.createElement("div", { className: "modal-header" },
|
|
7555
7636
|
React.createElement("h3", null, ((_a = booking.metadata) === null || _a === void 0 ? void 0 : _a.title) || 'Untitled Booking'),
|
|
7556
|
-
React.createElement("
|
|
7637
|
+
React.createElement("div", { className: "modal-header-actions" },
|
|
7638
|
+
React.createElement("button", { className: "modal-delete-btn", onClick: () => setShowConfirm(true), title: "Delete meeting", disabled: deleting },
|
|
7639
|
+
React.createElement("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" },
|
|
7640
|
+
React.createElement("polyline", { points: "3 6 5 6 21 6" }),
|
|
7641
|
+
React.createElement("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" }),
|
|
7642
|
+
React.createElement("line", { x1: "10", y1: "11", x2: "10", y2: "17" }),
|
|
7643
|
+
React.createElement("line", { x1: "14", y1: "11", x2: "14", y2: "17" }))),
|
|
7644
|
+
React.createElement("button", { className: "modal-close-btn", onClick: onClose }, "\u00D7"))),
|
|
7557
7645
|
React.createElement("div", { className: "modal-body" },
|
|
7646
|
+
error && React.createElement("div", { className: "modal-error" }, error),
|
|
7647
|
+
showConfirm && (React.createElement("div", { className: "delete-confirm-box" },
|
|
7648
|
+
React.createElement("p", null, "Are you sure you want to delete this meeting?"),
|
|
7649
|
+
React.createElement("div", { className: "delete-confirm-actions" },
|
|
7650
|
+
React.createElement("button", { className: "modal-btn modal-btn-secondary", onClick: () => setShowConfirm(false), disabled: deleting }, "Cancel"),
|
|
7651
|
+
React.createElement("button", { className: "modal-btn modal-btn-danger", onClick: handleDelete, disabled: deleting }, deleting ? 'Deleting...' : 'Delete')))),
|
|
7558
7652
|
React.createElement("div", { className: "detail-section" },
|
|
7559
7653
|
React.createElement("div", { className: "detail-row" },
|
|
7560
7654
|
React.createElement("span", { className: "detail-label" }, "Date:"),
|
|
@@ -7979,7 +8073,7 @@ const MonthView = ({ currentDate, bookings, timezone, onBookingClick, onDateClic
|
|
|
7979
8073
|
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}";
|
|
7980
8074
|
styleInject(css_248z);
|
|
7981
8075
|
|
|
7982
|
-
const Calendar = ({ businessId, resourceId, title = 'Calendar', apiBaseUrl, defaultView = 'month', onBookingCreate, onBookingClick, participants = [], timezone = moment$1.tz.guess(), businessHours, }) => {
|
|
8076
|
+
const Calendar = ({ businessId, resourceId, title = 'Calendar', apiBaseUrl, defaultView = 'month', onBookingCreate, onBookingClick, participants = [], timezone = moment$1.tz.guess(), businessHours, employees = [], rooms = [], }) => {
|
|
7983
8077
|
const [currentDate, setCurrentDate] = React.useState(moment$1().tz(timezone));
|
|
7984
8078
|
const [currentView, setCurrentView] = React.useState(defaultView);
|
|
7985
8079
|
const [bookings, setBookings] = React.useState([]);
|
|
@@ -8115,8 +8209,11 @@ const Calendar = ({ businessId, resourceId, title = 'Calendar', apiBaseUrl, defa
|
|
|
8115
8209
|
error && React.createElement("div", { className: "calendar-error" }, error),
|
|
8116
8210
|
loading && React.createElement("div", { className: "calendar-loading" }, "Loading..."),
|
|
8117
8211
|
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 }))),
|
|
8118
|
-
showCreateModal && selectedDate && (React.createElement(CreateBookingModal, { businessId: businessId, apiBaseUrl: apiBaseUrl, initialDate: selectedDate, participants: participants, onClose: () => setShowCreateModal(false), onBookingCreated: handleBookingCreated, timezone: timezone, businessHours: businessHours })),
|
|
8119
|
-
selectedBooking && (React.createElement(BookingDetailsModal, { booking: selectedBooking, timezone: timezone, onClose: () => setSelectedBooking(null)
|
|
8212
|
+
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 })),
|
|
8213
|
+
selectedBooking && (React.createElement(BookingDetailsModal, { booking: selectedBooking, timezone: timezone, businessId: businessId, apiBaseUrl: apiBaseUrl, onClose: () => setSelectedBooking(null), onBookingDeleted: () => __awaiter(void 0, void 0, void 0, function* () {
|
|
8214
|
+
setSelectedBooking(null);
|
|
8215
|
+
yield fetchBookings();
|
|
8216
|
+
}) }))));
|
|
8120
8217
|
};
|
|
8121
8218
|
|
|
8122
8219
|
exports.Calendar = Calendar;
|