Neueste Version

This commit is contained in:
Admin committed 2026-08-19 14:19:28 +00:00
1 parent 1410ceb441
commit 45730c4c57
15 files changed
+300 -92

No files matched your search

@@ -0,0 +1,5 @@
DELETE FROM `buchungen`
WHERE id =
{{ this.params.bookingId }}
AND gebucht_von =
{{ this.params.bookedBy }};
@@ -0,0 +1,35 @@
{
"gitSyncId": "6a6b5b477ebc9edeca96e2f8_766cb29a-c15e-4c36-a828-dda8c3fb28eb",
"id": "Sitzplätze_DeleteBooking",
"pluginId": "mysql-plugin",
"pluginType": "DB",
"unpublishedAction": {
"actionConfiguration": {
"body": "DELETE FROM `buchungen`\nWHERE id =\n {{ this.params.bookingId }}\n AND gebucht_von =\n {{ this.params.bookedBy }};",
"encodeParamsToggle": true,
"paginationType": "NONE",
"pluginSpecifiedTemplates": [
{
"value": true
}
],
"timeoutInMillisecond": 10000
},
"confirmBeforeExecute": false,
"datasource": {
"id": "MySQL Bürobuchungen",
"isAutoGenerated": false,
"name": "MySQL Bürobuchungen",
"pluginId": "mysql-plugin"
},
"dynamicBindingPathList": [
{
"key": "body"
}
],
"name": "DeleteBooking",
"pageId": "Sitzplätze",
"runBehaviour": "MANUAL",
"userSetOnLoad": false
}
}
@@ -1,6 +1,6 @@
{
"gitSyncId": "6a6b5b477ebc9edeca96e2f8_766cb29a-c15e-4c36-a828-dda8c3fb28eb",
"id": "Sitzplätze_Query1",
"gitSyncId": "6a6b5b477ebc9edeca96e2f8_cdc0389e-ec18-4013-bdb2-a8cefae53fda",
"id": "Sitzplätze_Query2",
"pluginId": "mysql-plugin",
"pluginType": "DB",
"unpublishedAction": {
@@ -22,7 +22,7 @@
"name": "MySQL Bürobuchungen",
"pluginId": "mysql-plugin"
},
"name": "Query1",
"name": "Query2",
"pageId": "Sitzplätze",
"runBehaviour": "MANUAL",
"userSetOnLoad": false
+1 -1
View File
@@ -55,7 +55,7 @@
"parentRowSpace": 10,
"renderMode": "CANVAS",
"rightColumn": 64,
"seatSelected": "{{\n showModal(\n \"SeatCalendar\"\n )\n}}",
"seatSelected": "{{\n storeValue(\n \"selectedSeatId\",\n Custom4.model.seatId ||\n Custom4.model.selectedSeat?.id ||\n \"\",\n false\n )\n .then(() =>\n storeValue(\n \"selectedSeatName\",\n Custom4.model.seatName ||\n Custom4.model.selectedSeat?.name ||\n \"\",\n false\n )\n )\n .then(() =>\n GetSeatBookings.run()\n )\n .then(() =>\n showModal(\n SeatCalendar.name\n )\n )\n}}",
"srcDoc": {
"css": "@charset \"UTF-8\";\nhtml,\nbody {\n margin: 0;\n width: 100%;\n height: 100%;\n overflow: auto;\n font-family: Arial, sans-serif;\n}\n\n/* Bild + Overlay */\n#imgHolder {\n position: relative;\n width: 100%;\n height: 700px; /* feste Höhe, damit sicher nicht 0 */\n overflow: hidden;\n border-radius: 6px;\n background: #f3f4f6;\n}\n\n#floorplanImage {\n position: absolute;\n inset: 0;\n z-index: 1;\n display: block;\n width: 100%;\n height: 100%;\n object-fit: contain;\n}\n\n#seatLayer {\n position: absolute;\n inset: 0;\n z-index: 2;\n width: 100%;\n height: 100%;\n pointer-events: none; /* Punkte bekommen später pointer-events:auto */\n}\n\n/* Sitzpunkte */\n.seat {\n position: absolute;\n z-index: 3;\n display: block;\n width: 18px;\n height: 18px;\n padding: 0;\n transform: translate(-50%, -50%);\n border: 2px solid #ffffff;\n border-radius: 50%;\n background: #22c55e;\n color: #22c55e;\n cursor: pointer;\n pointer-events: auto;\n appearance: none;\n box-sizing: border-box;\n box-shadow: 0 0 5px currentColor, 0 0 10px currentColor;\n transition: transform 0.15s ease, box-shadow 0.15s ease;\n}\n\n.seat:hover {\n z-index: 10;\n transform: translate(-50%, -50%) scale(1.45);\n box-shadow: 0 0 8px currentColor, 0 0 16px currentColor;\n}\n\n/* Farben nach Status */\n.seat.frei {\n background: #22c55e; /* Grün */\n color: #22c55e;\n}\n\n.seat.belegt {\n background: #ef4444; /* Rot */\n color: #ef4444;\n}\n\n.seat.selected {\n outline: 3px solid #2563eb;\n outline-offset: 3px;\n}\n\n/* Legende */\n#legend {\n display: flex;\n flex-wrap: wrap;\n gap: 14px;\n margin-top: 8px;\n color: #374151;\n font-size: 13px;\n}\n\n.legendItem {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n}\n\n.legendColor {\n display: inline-block;\n width: 14px;\n height: 14px;\n border-radius: 50%;\n}\n\n.legendColor.frei {\n background: #22c55e;\n}\n\n.legendColor.belegt {\n background: #ef4444;\n}",
"html": "<div id=\"seatPlan\">\n\n <div id=\"imgHolder\">\n <!-- Kein src hier, das Bild kommt über JavaScript -->\n <img id=\"floorplanImage\" alt=\"Büroplan\">\n\t\t<div id=\"seatLayer\"></div>\n\t\t\n\t\t\n </div>\n</div>",
@@ -0,0 +1,56 @@
{
"animateLoading": true,
"borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
"bottomRow": 24,
"boxShadow": "none",
"buttonColor": "{{appsmith.theme.colors.primaryColor}}",
"buttonStyle": "PRIMARY_BUTTON",
"buttonVariant": "PRIMARY",
"disabledWhenInvalid": false,
"dynamicBindingPathList": [
{
"key": "buttonColor"
},
{
"key": "borderRadius"
}
],
"dynamicPropertyPathList": [
{
"key": "onClick"
}
],
"dynamicTriggerPathList": [
{
"key": "onClick"
}
],
"isDefaultClickDisabled": true,
"isDisabled": false,
"isLoading": false,
"isVisible": true,
"key": "zb1cmuhe3l",
"leftColumn": 41,
"minWidth": 120,
"mobileBottomRow": 22,
"mobileLeftColumn": 47,
"mobileRightColumn": 63,
"mobileTopRow": 18,
"needsErrorInfo": false,
"onClick": "{{\n DeleteBooking\n .run({\n bookingId:\n appsmith.store.selectedBooking?.id,\n\n bookedBy:\n appsmith.user.email ||\n appsmith.user.username\n })\n .then((result) => {\n console.log(\n \"DeleteBooking Ergebnis:\",\n result\n );\n\n return GetSeatBookings.run();\n })\n .then(() => {\n return GetSeats.run();\n })\n .then(() => {\n return closeModal(\n MyBookingDetailsModal.name\n );\n })\n .then(() => {\n return showAlert(\n \"Die Buchung wurde gelöscht.\",\n \"success\"\n );\n })\n .catch((error) => {\n console.error(\n \"Löschen fehlgeschlagen:\",\n error\n );\n\n showAlert(\n \"Die Buchung konnte nicht gelöscht werden.\",\n \"error\"\n );\n });\n}}",
"originalBottomRow": 24,
"originalTopRow": 20,
"parentId": "7731jpp9wk",
"placement": "CENTER",
"recaptchaType": "V3",
"renderMode": "CANVAS",
"resetFormOnClick": false,
"responsiveBehavior": "hug",
"rightColumn": 63,
"text": "Buchung löschen",
"topRow": 20,
"type": "BUTTON_WIDGET",
"version": 1,
"widgetId": "zf6zh6z0sk",
"widgetName": "DeleteBookingButton"
}
@@ -0,0 +1,44 @@
{
"animateLoading": true,
"borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
"bottomRow": 4,
"boxShadow": "none",
"buttonColor": "{{appsmith.theme.colors.primaryColor}}",
"buttonVariant": "TERTIARY",
"dynamicBindingPathList": [
{
"key": "buttonColor"
},
{
"key": "borderRadius"
}
],
"dynamicTriggerPathList": [
{
"key": "onClick"
}
],
"iconName": "cross",
"iconSize": 24,
"isDisabled": false,
"isLoading": false,
"isVisible": true,
"key": "zaccq9na42",
"leftColumn": 58,
"minWidth": 50,
"mobileBottomRow": 4,
"mobileLeftColumn": 58,
"mobileRightColumn": 64,
"mobileTopRow": 0,
"needsErrorInfo": false,
"onClick": "{{closeModal(MyBookingDetailsModal.name);}}",
"parentId": "7731jpp9wk",
"renderMode": "CANVAS",
"responsiveBehavior": "hug",
"rightColumn": 64,
"topRow": 0,
"type": "ICON_BUTTON_WIDGET",
"version": 1,
"widgetId": "pcmtvkn5jw",
"widgetName": "IconButton2"
}
@@ -0,0 +1,85 @@
{
"animateLoading": true,
"borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
"bottomRow": 289,
"boxShadow": "none",
"canEscapeKeyClose": true,
"canOutsideClickClose": true,
"children": [
{
"borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
"bottomRow": 260,
"boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}",
"canExtend": true,
"detachFromLayout": true,
"dynamicBindingPathList": [
{
"key": "borderRadius"
},
{
"key": "boxShadow"
}
],
"dynamicHeight": "AUTO_HEIGHT",
"flexLayers": [],
"isDisabled": false,
"isLoading": false,
"isVisible": true,
"key": "iy86p0btqs",
"leftColumn": 0,
"maxDynamicHeight": 9000,
"minDynamicHeight": 4,
"minHeight": 260,
"minWidth": 450,
"mobileBottomRow": 240,
"mobileLeftColumn": 0,
"mobileRightColumn": 435.75,
"mobileTopRow": 0,
"needsErrorInfo": false,
"parentColumnSpace": 1,
"parentId": "m9c4kqrhxt",
"parentRowSpace": 1,
"renderMode": "CANVAS",
"responsiveBehavior": "fill",
"rightColumn": 435.75,
"shouldScrollContents": false,
"topRow": 0,
"type": "CANVAS_WIDGET",
"version": 1,
"widgetId": "7731jpp9wk",
"widgetName": "Canvas9"
}
],
"detachFromLayout": true,
"dynamicBindingPathList": [
{
"key": "borderRadius"
}
],
"dynamicHeight": "AUTO_HEIGHT",
"height": 260,
"isCanvas": true,
"isLoading": false,
"key": "jc8yhgzuwd",
"leftColumn": 20,
"maxDynamicHeight": 9000,
"minDynamicHeight": 24,
"minHeight": 260,
"mobileBottomRow": 53,
"mobileLeftColumn": 20,
"mobileRightColumn": 44,
"mobileTopRow": 29,
"needsErrorInfo": false,
"parentColumnSpace": 18.15625,
"parentId": "0",
"parentRowSpace": 10,
"renderMode": "CANVAS",
"rightColumn": 44,
"shouldScrollContents": true,
"topRow": 29,
"type": "MODAL_WIDGET",
"version": 2,
"widgetId": "m9c4kqrhxt",
"widgetName": "MyBookingDetailsModal",
"width": 732
}
@@ -1,7 +1,7 @@
{
"animateLoading": true,
"borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
"bottomRow": 92,
"bottomRow": 24,
"dynamicBindingPathList": [
{
"key": "truncateButtonColor"
@@ -19,37 +19,35 @@
"dynamicHeight": "AUTO_HEIGHT",
"dynamicTriggerPathList": [],
"fontFamily": "{{appsmith.theme.fontFamily.appFont}}",
"fontSize": "1rem",
"fontSize": "1.25rem",
"fontStyle": "BOLD",
"isLoading": false,
"isVisible": true,
"key": "wb75ugacfs",
"leftColumn": 39,
"key": "wnu3ozrv06",
"leftColumn": 1,
"maxDynamicHeight": 9000,
"minDynamicHeight": 4,
"minWidth": 450,
"mobileBottomRow": 56,
"mobileLeftColumn": 43,
"mobileRightColumn": 59,
"mobileTopRow": 52,
"mobileBottomRow": 5,
"mobileLeftColumn": 1,
"mobileRightColumn": 41,
"mobileTopRow": 1,
"needsErrorInfo": false,
"originalBottomRow": 92,
"originalTopRow": 43,
"originalBottomRow": 24,
"originalTopRow": 1,
"overflow": "NONE",
"parentColumnSpace": 18.56015625,
"parentId": "q44lz1f0e4",
"parentRowSpace": 10,
"parentId": "7731jpp9wk",
"renderMode": "CANVAS",
"responsiveBehavior": "fill",
"rightColumn": 48,
"rightColumn": 41,
"shouldTruncate": false,
"text": "{{\n JSON.stringify(\n appsmith.store.bookingFormData || {},\n null,\n 2\n )\n}}",
"text": "{{\n JSON.stringify(\n appsmith.store.selectedBooking || {},\n null,\n 2\n )\n}}",
"textAlign": "LEFT",
"textColor": "#231F20",
"topRow": 43,
"topRow": 1,
"truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}",
"type": "TEXT_WIDGET",
"version": 1,
"widgetId": "y723ubcx1i",
"widgetName": "Text4"
"widgetId": "uby200a2fb",
"widgetName": "Text6"
}
@@ -7,17 +7,32 @@
"closeOnSelection": true,
"dateFormat": "D MMMM, YYYY",
"datePickerType": "DATE_PICKER",
"defaultDate": "2026-08-17T09:59:18.715Z",
"defaultDate": "{{\n appsmith.store.bookingFormData?.endDate ||\n appsmith.store.bookingFormData?.startDate ||\n appsmith.store.calendarSelection?.start?.slice(0, 10) ||\n \"\"\n}}",
"dynamicBindingPathList": [
{
"key": "accentColor"
},
{
"key": "borderRadius"
},
{
"key": "defaultDate"
}
],
"dynamicHeight": "FIXED",
"dynamicTriggerPathList": [],
"dynamicPropertyPathList": [
{
"key": "defaultDate"
},
{
"key": "onDateSelected"
}
],
"dynamicTriggerPathList": [
{
"key": "onDateSelected"
}
],
"firstDayOfWeek": 0,
"isDisabled": false,
"isLoading": false,
@@ -40,6 +55,7 @@
"mobileRightColumn": 21,
"mobileTopRow": 11,
"needsErrorInfo": false,
"onDateSelected": "{{\n storeValue(\n \"bookingFormData\",\n {\n ...(appsmith.store.bookingFormData || {}),\n\n endDate:\n BookingEndDate.selectedDate\n },\n false\n )\n}}",
"parentColumnSpace": 8.875,
"parentId": "q44lz1f0e4",
"parentRowSpace": 10,
@@ -7,17 +7,32 @@
"closeOnSelection": true,
"dateFormat": "D MMMM, YYYY",
"datePickerType": "DATE_PICKER",
"defaultDate": "2026-08-17T09:59:18.715Z",
"defaultDate": "{{\n appsmith.store.bookingFormData?.startDate ||\n appsmith.store.calendarSelection?.start?.slice(0, 10) ||\n \"\"\n}}",
"dynamicBindingPathList": [
{
"key": "accentColor"
},
{
"key": "borderRadius"
},
{
"key": "defaultDate"
}
],
"dynamicHeight": "FIXED",
"dynamicTriggerPathList": [],
"dynamicPropertyPathList": [
{
"key": "defaultDate"
},
{
"key": "onDateSelected"
}
],
"dynamicTriggerPathList": [
{
"key": "onDateSelected"
}
],
"firstDayOfWeek": 0,
"isDisabled": false,
"isLoading": false,
@@ -40,6 +55,7 @@
"mobileRightColumn": 21,
"mobileTopRow": 11,
"needsErrorInfo": false,
"onDateSelected": "{{\n storeValue(\n \"bookingFormData\",\n {\n ...(appsmith.store.bookingFormData || {}),\n\n startDate:\n BookingStartDate.selectedDate,\n\n endDate:\n BookingStartDate.selectedDate\n },\n false\n )\n}}",
"parentColumnSpace": 8.875,
"parentId": "q44lz1f0e4",
"parentRowSpace": 10,
@@ -1,7 +1,7 @@
{
"animateLoading": true,
"borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
"bottomRow": 79,
"bottomRow": 64,
"boxShadow": "none",
"buttonColor": "{{appsmith.theme.colors.primaryColor}}",
"buttonStyle": "PRIMARY_BUTTON",
@@ -34,8 +34,8 @@
"mobileTopRow": 18,
"needsErrorInfo": false,
"onClick": "{{RecurringBooking.prepareRecurringBooking();}}",
"originalBottomRow": 78,
"originalTopRow": 74,
"originalBottomRow": 79,
"originalTopRow": 75,
"parentId": "q44lz1f0e4",
"placement": "CENTER",
"recaptchaType": "V3",
@@ -44,7 +44,7 @@
"responsiveBehavior": "hug",
"rightColumn": 62,
"text": "Buchen",
"topRow": 75,
"topRow": 60,
"type": "BUTTON_WIDGET",
"version": 1,
"widgetId": "iutdgcd629",
@@ -1,14 +1,14 @@
{
"animateLoading": true,
"borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
"bottomRow": 94,
"bottomRow": 66,
"boxShadow": "none",
"canEscapeKeyClose": true,
"canOutsideClickClose": true,
"children": [
{
"borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
"bottomRow": 940,
"bottomRow": 660,
"boxShadow": "{{appsmith.theme.boxShadow.appBoxShadow}}",
"canExtend": true,
"detachFromLayout": true,
@@ -58,14 +58,14 @@
],
"dynamicHeight": "AUTO_HEIGHT",
"dynamicTriggerPathList": [],
"height": 940,
"height": 660,
"isCanvas": true,
"isLoading": false,
"key": "tfld9k9m85",
"leftColumn": 19,
"maxDynamicHeight": 9000,
"minDynamicHeight": 10,
"minHeight": 940,
"minHeight": 660,
"mobileBottomRow": 39,
"mobileLeftColumn": 19,
"mobileRightColumn": 43,
@@ -1,55 +0,0 @@
{
"animateLoading": true,
"borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
"bottomRow": 48,
"dynamicBindingPathList": [
{
"key": "truncateButtonColor"
},
{
"key": "fontFamily"
},
{
"key": "borderRadius"
},
{
"key": "text"
}
],
"dynamicHeight": "AUTO_HEIGHT",
"dynamicTriggerPathList": [],
"fontFamily": "{{appsmith.theme.fontFamily.appFont}}",
"fontSize": "1rem",
"fontStyle": "BOLD",
"isLoading": false,
"isVisible": true,
"key": "wb75ugacfs",
"leftColumn": 48,
"maxDynamicHeight": 9000,
"minDynamicHeight": 4,
"minWidth": 450,
"mobileBottomRow": 47,
"mobileLeftColumn": 48,
"mobileRightColumn": 64,
"mobileTopRow": 43,
"needsErrorInfo": false,
"originalBottomRow": 47,
"originalTopRow": 43,
"overflow": "NONE",
"parentColumnSpace": 18.56015625,
"parentId": "q44lz1f0e4",
"parentRowSpace": 10,
"renderMode": "CANVAS",
"responsiveBehavior": "fill",
"rightColumn": 64,
"shouldTruncate": false,
"text": "{{\n \"Start: \" +\n appsmith.store.bookingFormData?.startDate +\n \" | Ende: \" +\n appsmith.store.bookingFormData?.endDate\n}}",
"textAlign": "LEFT",
"textColor": "#231F20",
"topRow": 43,
"truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}",
"type": "TEXT_WIDGET",
"version": 1,
"widgetId": "8r5ranska0",
"widgetName": "Text5"
}
@@ -1,5 +1,6 @@
{
"backgroundColor": "#FFFFFF",
"bookingClicked": "{{\n storeValue(\n \"selectedBooking\",\n Custom5.model.selectedBooking,\n false\n )\n .then(() =>\n showModal(\n MyBookingDetailsModal.name\n )\n )\n}}",
"bookingSelected": "{{ BookingSelect.openBookingWidget() }}",
"borderColor": "#E0DEDE",
"borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
@@ -28,6 +29,9 @@
},
{
"key": "bookingSelected"
},
{
"key": "bookingClicked"
}
],
"dynamicTriggerPathList": [
@@ -39,12 +43,16 @@
},
{
"key": "timeSelected"
},
{
"key": "bookingClicked"
}
],
"events": [
"seatSelected",
"bookingSelected",
"timeSelected"
"timeSelected",
"bookingClicked"
],
"isCanvas": false,
"isLoading": false,
@@ -68,7 +76,7 @@
"srcDoc": {
"css": "@charset \"UTF-8\";\nhtml,\nbody {\n margin: 0;\n padding: 0;\n width: 100%;\n min-height: 100%;\n font-family: Arial, sans-serif;\n overflow: hidden;\n}\n\n/* Äußerer Custom-Widget-Bereich */\n#calendarWrapper {\n width: 100%;\n min-height: 0;\n box-sizing: border-box;\n padding: 10px;\n background: #ffffff;\n overflow: visible;\n}\n\n/* Kopfbereich */\n#calendarHeader {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 10px;\n padding: 8px 10px;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n background: #f9fafb;\n}\n\n#calendarSeatTitle {\n font-size: 15px;\n font-weight: 600;\n color: #374151;\n}\n\n/* Kalender */\n#calendar {\n width: 100%;\n min-height: 0;\n box-sizing: border-box;\n --calendar-selection-color: rgba(\n 11,\n 116,\n 222,\n 0.12\n );\n --fc-highlight-color: rgba(\n 11,\n 116,\n 222,\n 0.12\n );\n --fc-today-bg-color: transparent;\n}\n\n/* Auswahltext */\n#calendarSelection {\n margin-top: 10px;\n padding: 8px 10px;\n border: 1px solid #d1d5db;\n border-radius: 5px;\n background: #f9fafb;\n color: #374151;\n font-size: 13px;\n}\n\n/* FullCalendar-Grundformatierung */\n#calendar .fc {\n width: 100%;\n font-size: 13px;\n --fc-highlight-color: rgba(\n 11,\n 116,\n 222,\n 0.12\n );\n --fc-today-bg-color: transparent;\n}\n\n#calendar .fc .fc-button {\n background: #374151;\n border-color: #374151;\n}\n\n#calendar .fc .fc-button:hover,\n#calendar .fc .fc-button-active {\n background: #111827;\n border-color: #111827;\n}\n\n#calendar .fc .fc-event {\n cursor: pointer;\n}\n\n/*\n * EINHEITLICHE AUSWAHLFARBE\n *\n * Gilt für:\n * - einen Tag\n * - mehrere Tage\n * - einen Timeslot\n *\n * Wichtig: FullCalendar verwendet background.\n */\n#calendar .fc .fc-highlight,\n#calendar .fc .fc-highlight-skeleton,\n#calendar .fc .fc-highlight-skeleton td,\n#calendar .fc .fc-highlight-container,\n#calendar .fc .fc-highlight-container td {\n background: var(--calendar-selection-color) !important;\n background-color: var(--calendar-selection-color) !important;\n opacity: 1 !important;\n border: 0 !important;\n box-shadow: none !important;\n}\n\n/*\n * Tagesansicht:\n * mögliche Auswahlcontainer ebenfalls\n * auf dieselbe Farbe setzen.\n */\n#calendar .fc-timegrid .fc-timegrid-col-bg,\n#calendar .fc-timegrid .fc-timegrid-col-bg-container,\n#calendar .fc-timegrid .fc-timegrid-col-bg-container table,\n#calendar .fc-timegrid .fc-timegrid-col-bg-container td,\n#calendar .fc-timegrid .fc-highlight-skeleton,\n#calendar .fc-timegrid .fc-highlight-container {\n background: transparent !important;\n background-color: transparent !important;\n}\n\n/*\n * Die tatsächliche Auswahlfläche\n * in der Tagesansicht.\n */\n#calendar .fc-timegrid .fc-highlight,\n#calendar .fc-timegrid .fc-highlight-skeleton td,\n#calendar .fc-timegrid .fc-highlight-container td {\n background: var(--calendar-selection-color) !important;\n background-color: var(--calendar-selection-color) !important;\n opacity: 1 !important;\n border: 0 !important;\n box-shadow: none !important;\n}\n\n/*\n * Aktueller Tag in der Monatsansicht:\n * transparenter Hintergrund,\n * nur schmaler roter Rahmen.\n */\n#calendar .fc-daygrid-day.fc-day-today {\n background: transparent !important;\n background-color: transparent !important;\n box-shadow: inset 0 0 0 1px #dc2626 !important;\n}\n\n#calendar .fc-daygrid-day.fc-day-today .fc-daygrid-day-frame {\n background: transparent !important;\n background-color: transparent !important;\n box-shadow: none !important;\n}\n\n/*\n * Kopfzelle des aktuellen Tages\n * ohne Hintergrund und ohne Rahmen.\n */\n#calendar .fc-col-header-cell.fc-day-today {\n background: transparent !important;\n background-color: transparent !important;\n box-shadow: none !important;\n}\n\n/*\n * Tagesansicht:\n * aktueller Tag ohne Hintergrund\n * und ohne roten Rahmen.\n */\n#calendar .fc-timegrid-col.fc-day-today {\n background: transparent !important;\n background-color: transparent !important;\n box-shadow: none !important;\n border: none !important;\n}\n\n#calendar .fc-timegrid-col.fc-day-today .fc-timegrid-col-frame {\n background: transparent !important;\n background-color: transparent !important;\n box-shadow: none !important;\n border: none !important;\n}\n\n/* Wochenenden grau */\n#calendar td.fc-day-sat,\n#calendar td.fc-day-sun,\n#calendar .fc-timegrid-col.fc-day-sat,\n#calendar .fc-timegrid-col.fc-day-sun {\n background-color: #eeeeee !important;\n}\n\n/* Wochenend-Kopfzellen */\n#calendar .fc-col-header-cell.fc-day-sat,\n#calendar .fc-col-header-cell.fc-day-sun {\n background-color: #d6d6d6 !important;\n}\n\n/*\n * Monatsansicht:\n * kein Scrollen innerhalb des Monats.\n */\n#calendar .fc-daygrid .fc-scroller {\n height: auto !important;\n max-height: none !important;\n overflow-y: visible !important;\n overflow-x: visible !important;\n}\nLine truncated
"html": "<div id=\"calendarWrapper\">\n <div id=\"calendarHeader\">\n <div id=\"calendarSeatTitle\">\n Kalender\n </div>\n </div>\n\n <div id=\"calendar\"></div>\n\n <div id=\"calendarSelection\">\n Keine Auswahl\n </div>\n</div>\n\n<link\n rel=\"stylesheet\"\n href=\"https://cdn.jsdelivr.net/npm/[email protected]/index.global.min.css\"\n>\n\n<script\n src=\"https://cdn.jsdelivr.net/npm/[email protected]/index.global.min.js\">\n</script>",
"js": "let calendar = null;\nlet resizeTimer = null;\nlet modelChangeRegistered = false;\nlet resizeRegistered = false;\nconst MONTH_HEIGHT = 620;\nconst MONTH_CONTENT_HEIGHT = 550;\nconst DAY_HEIGHT = 600;\nconst DAY_CONTENT_HEIGHT = 480;\nconst BUSINESS_START_MINUTES = 7 * 60;\nconst BUSINESS_END_MINUTES = 18 * 60;\nconst SLOT_MINUTES = 30;\nfunction getModel() {\n const model = appsmith.model || {};\n if (typeof model === \"string\") {\n try {\n return JSON.parse(model);\n } catch (error) {\n return {};\n }\n }\n return model;\n}\nfunction getEvents() {\n const model = getModel();\n return Array.isArray(model.events) ? model.events : [];\n}\nfunction getSeatName() {\n const model = getModel();\n return model.seatName || model.seatId || \"Kein Platz ausgewählt\";\n}\nfunction updateSeatTitle() {\n const element = document.getElementById(\"calendarSeatTitle\");\n if (!element) {\n return;\n }\n element.textContent = `Kalender für ${getSeatName()}`;\n}\nfunction isDayView() {\n return Boolean(calendar && calendar.view && calendar.view.type === \"timeGridDay\");\n}\nfunction updateSelectionText(text) {\n const element = document.getElementById(\"calendarSelection\");\n if (!element) {\n return;\n }\n if (isDayView()) {\n element.textContent = \"\";\n element.style.display = \"none\";\n return;\n }\n element.style.display = \"block\";\n element.textContent = text;\n}\nfunction updateCalendarViewSettings(viewType) {\n if (!calendar) {\n return;\n }\n const dayView = viewType === \"timeGridDay\";\n calendar.setOption(\"height\", dayView ? DAY_HEIGHT : MONTH_HEIGHT);\n calendar.setOption(\"contentHeight\", dayView ? DAY_CONTENT_HEIGHT : MONTH_CONTENT_HEIGHT);\n calendar.setOption(\"expandRows\", !dayView);\n if (typeof calendar.updateSize === \"function\") {\n calendar.updateSize();\n }\n}\nfunction scheduleResize() {\n window.clearTimeout(resizeTimer);\n resizeTimer = window.setTimeout(() => {\n if (calendar) {\n calendar.updateSize();\n }\n }, 250);\n}\nfunction isWeekend(date) {\n const day = date.getDay();\n return day === 0 || day === 6;\n}\nfunction isBusinessDay(date) {\n const day = date.getDay();\n return day >= 1 && day <= 5;\n}\nfunction getMinutesOfDay(date) {\n return date.getHours() * 60 + date.getMinutes();\n}\nfunction isBusinessTimeRange(start, end) {\n if (!start || !end) {\n return false;\n }\n if (!isBusinessDay(start)) {\n return false;\n }\n if (start.toDateString() !== end.toDateString()) {\n return false;\n }\n const startMinutes = getMinutesOfDay(start);\n const endMinutes = getMinutesOfDay(end);\n return startMinutes >= BUSINESS_START_MINUTES && endMinutes <= BUSINESS_END_MINUTES && endMinutes > startMinutes;\n}\nfunction isBusinessDayRange(start, end) {\n if (!start || !end || end <= start) {\n return false;\n }\n const lastSelectedDay = new Date(end.getTime() - 1);\n const current = new Date(start);\n current.setHours(12, 0, 0, 0);\n lastSelectedDay.setHours(12, 0, 0, 0);\n while (current <= lastSelectedDay) {\n if (!isBusinessDay(current)) {\n return false;\n }\n current.setDate(current.getDate() + 1);\n }\n return true;\n}\nfunction showWeekendMessage() {\n updateSelectionText(\"Samstag und Sonntag sind nicht buchbar.\");\n}\nfunction showBusinessHoursMessage() {\n updateSelectionText(\"Reservierungen sind Montag bis Freitag von 07:00 bis 18:00 Uhr möglich.\");\n}\nfunction openDayView(date) {\n if (!calendar) {\n return;\n }\n if (isWeekend(date)) {\n showWeekendMessage();\n return;\n }\n calendar.changeView(\"timeGridDay\", date);\n}\nfunction isDayNumberClick(info) {\n const target = info.jsEvent && info.jsEvent.target;\n if (!target || typeof target.closest !== \"function\") {\n return false;\n }\n return Boolean(target.closest(\".fc-daygrid-day-number\"));\n}\nfunction roundToHalfHour(date) {\n const result = new Date(date);\n const minutes = result.getMinutes();\n result.setSeconds(0, 0);\n result.setMinutes(minutes < 30 ? 0 : 30);\n return result;\n}\nfunction pad(value) {\n return String(value).padStart(2, \"0\");\n}\nfunction formatLocalDate(date) {\n return [date.getFullYear(), pad(date.getMonth() + 1), pad(date.getDate())].join(\"-\");\n}\nfunction formatLocalTime(date) {\n return [pad(date.getHours()), pad(date.getMinutes()), pad(date.getSeconds())].join(\":\");\n}\nfunction formatLocalDateTime(date) {\n return `${formatLocalDate(date)}T${formatLocalTime(date)}`;\n}\nfunction formatDateTime(date) {\n if (!date) {\n return \"\";\n }\n return new Intl.DateTimeFormat(\"de-DE\", {\n dateStyle: \"short\",\n timeStyle: \"short\"\n }).format(date);\n}\nfunction triggerAppsmithEvent(eventName) {\n try {\n appsmith.triggerEvent(eventName);\n } catch (error) {\n console.warn(`Event ${eventName} ist nicht konfiguriert.`, error);\n }\n}\nfunction saveCalendarSelection(type, start, end) {\n ifLine truncated
"js": "let calendar = null;\nlet resizeTimer = null;\nlet modelChangeRegistered = false;\nlet resizeRegistered = false;\nconst MONTH_HEIGHT = 620;\nconst MONTH_CONTENT_HEIGHT = 550;\nconst DAY_HEIGHT = 600;\nconst DAY_CONTENT_HEIGHT = 480;\nconst BUSINESS_START_MINUTES = 7 * 60;\nconst BUSINESS_END_MINUTES = 18 * 60;\nconst SLOT_MINUTES = 30;\nfunction getModel() {\n const model = appsmith.model || {};\n if (typeof model === \"string\") {\n try {\n return JSON.parse(model);\n } catch (error) {\n return {};\n }\n }\n return model;\n}\nfunction getEvents() {\n const model = getModel();\n return Array.isArray(model.events) ? model.events : [];\n}\nfunction getSeatName() {\n const model = getModel();\n return model.seatName || model.seatId || \"Kein Platz ausgewählt\";\n}\nfunction getCurrentUser() {\n const model = getModel();\n return String(model.currentUser || \"\").trim().toLowerCase();\n}\nfunction updateSeatTitle() {\n const element = document.getElementById(\"calendarSeatTitle\");\n if (!element) return;\n element.textContent = `Kalender für ${getSeatName()}`;\n}\nfunction isDayView() {\n return Boolean(calendar && calendar.view && calendar.view.type === \"timeGridDay\");\n}\nfunction updateSelectionText(text) {\n const element = document.getElementById(\"calendarSelection\");\n if (!element) return;\n if (isDayView()) {\n element.textContent = \"\";\n element.style.display = \"none\";\n return;\n }\n element.style.display = \"block\";\n element.textContent = text;\n}\nfunction updateCalendarViewSettings(viewType) {\n if (!calendar) return;\n const dayView = viewType === \"timeGridDay\";\n calendar.setOption(\"height\", dayView ? DAY_HEIGHT : MONTH_HEIGHT);\n calendar.setOption(\"contentHeight\", dayView ? DAY_CONTENT_HEIGHT : MONTH_CONTENT_HEIGHT);\n calendar.setOption(\"expandRows\", !dayView);\n if (typeof calendar.updateSize === \"function\") {\n calendar.updateSize();\n }\n}\nfunction scheduleResize() {\n window.clearTimeout(resizeTimer);\n resizeTimer = window.setTimeout(() => {\n if (calendar) calendar.updateSize();\n }, 250);\n}\nfunction isWeekend(date) {\n const day = date.getDay();\n return day === 0 || day === 6;\n}\nfunction isBusinessDay(date) {\n const day = date.getDay();\n return day >= 1 && day <= 5;\n}\nfunction getMinutesOfDay(date) {\n return date.getHours() * 60 + date.getMinutes();\n}\nfunction isBusinessTimeRange(start, end) {\n if (!start || !end) return false;\n if (!isBusinessDay(start)) return false;\n if (start.toDateString() !== end.toDateString()) return false;\n const startMinutes = getMinutesOfDay(start);\n const endMinutes = getMinutesOfDay(end);\n return startMinutes >= BUSINESS_START_MINUTES && endMinutes <= BUSINESS_END_MINUTES && endMinutes > startMinutes;\n}\nfunction isBusinessDayRange(start, end) {\n if (!start || !end || end <= start) return false;\n const lastSelectedDay = new Date(end.getTime() - 1);\n const current = new Date(start);\n current.setHours(12, 0, 0, 0);\n lastSelectedDay.setHours(12, 0, 0, 0);\n while (current <= lastSelectedDay) {\n if (!isBusinessDay(current)) return false;\n current.setDate(current.getDate() + 1);\n }\n return true;\n}\nfunction showWeekendMessage() {\n updateSelectionText(\"Samstag und Sonntag sind nicht buchbar.\");\n}\nfunction showBusinessHoursMessage() {\n updateSelectionText(\"Reservierungen sind Montag bis Freitag von 07:00 bis 18:00 Uhr möglich.\");\n}\nfunction openDayView(date) {\n if (!calendar) return;\n if (isWeekend(date)) {\n showWeekendMessage();\n return;\n }\n calendar.changeView(\"timeGridDay\", date);\n}\nfunction isDayNumberClick(info) {\n const target = info.jsEvent && info.jsEvent.target;\n if (!target || typeof target.closest !== \"function\") {\n return false;\n }\n return Boolean(target.closest(\".fc-daygrid-day-number\"));\n}\nfunction roundToHalfHour(date) {\n const result = new Date(date);\n const minutes = result.getMinutes();\n result.setSeconds(0, 0);\n result.setMinutes(minutes < 30 ? 0 : 30);\n return result;\n}\nfunction pad(value) {\n return String(value).padStart(2, \"0\");\n}\nfunction formatLocalDate(date) {\n return [date.getFullYear(), pad(date.getMonth() + 1), pad(date.getDate())].join(\"-\");\n}\nfunction formatLocalTime(date) {\n return [pad(date.getHours()), pad(date.getMinutes()), pad(date.getSeconds())].join(\":\");\n}\nfunction formatLocalDateTime(date) {\n return `${formatLocalDate(date)}T${formatLocalTime(date)}`;\n}\nfunction formatDateTime(date) {\n if (!date) return \"\";\n return new Intl.DateTimeFormat(\"de-DE\", {\n dateStyle: \"short\",\n timeStyle: \"short\"\n }).format(date);\n}\nfunction triggerAppsmithEvent(eventName) {\n try {\n appsmith.triggerEvent(eventName);\n } catch (error) {\n console.warn(`Event ${eventName} ist nicht konfiguriert.`, error);\n }\n}\nfunction normalizeBookingEvent(event) {\n const extended = event.extLine truncated
},
"theme": "{{appsmith.theme}}",
"timeSelected": "{{showModal(Platzbuchung.name);}}",
@@ -77,7 +85,7 @@
"uncompiledSrcDoc": {
"css": "html,\nbody {\n margin: 0;\n padding: 0;\n width: 100%;\n min-height: 100%;\n font-family: Arial, sans-serif;\n overflow: hidden;\n}\n\n/* Äußerer Custom-Widget-Bereich */\n\n#calendarWrapper {\n width: 100%;\n min-height: 0;\n box-sizing: border-box;\n padding: 10px;\n background: #ffffff;\n overflow: visible;\n}\n\n/* Kopfbereich */\n\n#calendarHeader {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 10px;\n padding: 8px 10px;\n border: 1px solid #d1d5db;\n border-radius: 6px;\n background: #f9fafb;\n}\n\n#calendarSeatTitle {\n font-size: 15px;\n font-weight: 600;\n color: #374151;\n}\n\n/* Kalender */\n\n#calendar {\n width: 100%;\n min-height: 0;\n box-sizing: border-box;\n\n --calendar-selection-color: rgba(\n 11,\n 116,\n 222,\n 0.12\n );\n\n --fc-highlight-color: rgba(\n 11,\n 116,\n 222,\n 0.12\n );\n\n --fc-today-bg-color: transparent;\n}\n\n/* Auswahltext */\n\n#calendarSelection {\n margin-top: 10px;\n padding: 8px 10px;\n border: 1px solid #d1d5db;\n border-radius: 5px;\n background: #f9fafb;\n color: #374151;\n font-size: 13px;\n}\n\n/* FullCalendar-Grundformatierung */\n\n#calendar .fc {\n width: 100%;\n font-size: 13px;\n\n --fc-highlight-color: rgba(\n 11,\n 116,\n 222,\n 0.12\n );\n\n --fc-today-bg-color: transparent;\n}\n\n#calendar .fc .fc-button {\n background: #374151;\n border-color: #374151;\n}\n\n#calendar .fc .fc-button:hover,\n#calendar .fc .fc-button-active {\n background: #111827;\n border-color: #111827;\n}\n\n#calendar .fc .fc-event {\n cursor: pointer;\n}\n\n/*\n * EINHEITLICHE AUSWAHLFARBE\n *\n * Gilt für:\n * - einen Tag\n * - mehrere Tage\n * - einen Timeslot\n *\n * Wichtig: FullCalendar verwendet background.\n */\n#calendar .fc .fc-highlight,\n#calendar .fc .fc-highlight-skeleton,\n#calendar .fc .fc-highlight-skeleton td,\n#calendar .fc .fc-highlight-container,\n#calendar .fc .fc-highlight-container td {\n background: var(\n --calendar-selection-color\n ) !important;\n\n background-color: var(\n --calendar-selection-color\n ) !important;\n\n opacity: 1 !important;\n border: 0 !important;\n box-shadow: none !important;\n}\n\n/*\n * Tagesansicht:\n * mögliche Auswahlcontainer ebenfalls\n * auf dieselbe Farbe setzen.\n */\n#calendar .fc-timegrid .fc-timegrid-col-bg,\n#calendar .fc-timegrid .fc-timegrid-col-bg-container,\n#calendar .fc-timegrid .fc-timegrid-col-bg-container table,\n#calendar .fc-timegrid .fc-timegrid-col-bg-container td,\n#calendar .fc-timegrid .fc-highlight-skeleton,\n#calendar .fc-timegrid .fc-highlight-container {\n background: transparent !important;\n background-color: transparent !important;\n}\n\n/*\n * Die tatsächliche Auswahlfläche\n * in der Tagesansicht.\n */\n#calendar .fc-timegrid .fc-highlight,\n#calendar .fc-timegrid .fc-highlight-skeleton td,\n#calendar .fc-timegrid .fc-highlight-container td {\n background: var(\n --calendar-selection-color\n ) !important;\n\n background-color: var(\n --calendar-selection-color\n ) !important;\n\n opacity: 1 !important;\n border: 0 !important;\n box-shadow: none !important;\n}\n\n/*\n * Aktueller Tag in der Monatsansicht:\n * transparenter Hintergrund,\n * nur schmaler roter Rahmen.\n */\n#calendar .fc-daygrid-day.fc-day-today {\n background: transparent !important;\n background-color: transparent !important;\n box-shadow: inset 0 0 0 1px #dc2626 !important;\n}\n\n#calendar\n .fc-daygrid-day.fc-day-today\n .fc-daygrid-day-frame {\n background: transparent !important;\n background-color: transparent !important;\n box-shadow: none !important;\n}\n\n/*\n * Kopfzelle des aktuellen Tages\n * ohne Hintergrund und ohne Rahmen.\n */\n#calendar .fc-col-header-cell.fc-day-today {\n background: transparent !important;\n background-color: transparent !important;\n box-shadow: none !important;\n}\n\n/*\n * Tagesansicht:\n * aktueller Tag ohne Hintergrund\n * und ohne roten Rahmen.\n */\n#calendar .fc-timegrid-col.fc-day-today {\n background: transparent !important;\n background-color: transparent !important;\n box-shadow: none !important;\n border: none !important;\n}\n\n#calendar\n .fc-timegrid-col.fc-day-today\n .fc-timegrid-col-frame {\n background: transparent !important;\n background-color: transparent !important;\n box-shadow: none !important;\n border: none !important;\n}\n\n/* Wochenenden grau */\n\n#calendar td.fc-day-sat,\n#calendar td.fc-day-sun,\n#calendar .fc-timegrid-col.fc-day-sat,\n#calendar .fc-timegrid-col.fc-day-sun {\n background-color: #eeeeee !important;\n}\n\n/* Wochenend-Kopfzellen */\n\n#calendar .fc-col-header-cell.fc-day-sat,\n#calendar .fc-col-header-cell.fc-day-sun {\n background-color: #d6d6d6 !important;\n}\n\n/*\n * Monatsansicht:\n * kein Scrollen innerhalb des Monats.\n */\n#calendar .fc-daygrid .fc-scroller {\n height: auto !important;\n max-height: none !important;\n overflowLine truncated
"html": "<div id=\"calendarWrapper\">\n <div id=\"calendarHeader\">\n <div id=\"calendarSeatTitle\">\n Kalender\n </div>\n </div>\n\n <div id=\"calendar\"></div>\n\n <div id=\"calendarSelection\">\n Keine Auswahl\n </div>\n</div>\n\n<link\n rel=\"stylesheet\"\n href=\"https://cdn.jsdelivr.net/npm/[email protected]/index.global.min.css\"\n>\n\n<script\n src=\"https://cdn.jsdelivr.net/npm/[email protected]/index.global.min.js\">\n</script>",
"js": "let calendar = null;\nlet resizeTimer = null;\nlet modelChangeRegistered = false;\nlet resizeRegistered = false;\n\nconst MONTH_HEIGHT = 620;\nconst MONTH_CONTENT_HEIGHT = 550;\n\nconst DAY_HEIGHT = 600;\nconst DAY_CONTENT_HEIGHT = 480;\n\nconst BUSINESS_START_MINUTES = 7 * 60;\nconst BUSINESS_END_MINUTES = 18 * 60;\nconst SLOT_MINUTES = 30;\n\nfunction getModel() {\n const model = appsmith.model || {};\n\n if (typeof model === \"string\") {\n try {\n return JSON.parse(model);\n } catch (error) {\n return {};\n }\n }\n\n return model;\n}\n\nfunction getEvents() {\n const model = getModel();\n return Array.isArray(model.events) ? model.events : [];\n}\n\nfunction getSeatName() {\n const model = getModel();\n return model.seatName || model.seatId || \"Kein Platz ausgewählt\";\n}\n\nfunction updateSeatTitle() {\n const element = document.getElementById(\"calendarSeatTitle\");\n\n if (!element) {\n return;\n }\n\n element.textContent = `Kalender für ${getSeatName()}`;\n}\n\nfunction isDayView() {\n return Boolean(\n calendar &&\n calendar.view &&\n calendar.view.type === \"timeGridDay\"\n );\n}\n\nfunction updateSelectionText(text) {\n const element = document.getElementById(\"calendarSelection\");\n\n if (!element) {\n return;\n }\n\n if (isDayView()) {\n element.textContent = \"\";\n element.style.display = \"none\";\n return;\n }\n\n element.style.display = \"block\";\n element.textContent = text;\n}\n\nfunction updateCalendarViewSettings(viewType) {\n if (!calendar) {\n return;\n }\n\n const dayView = viewType === \"timeGridDay\";\n\n calendar.setOption(\"height\", dayView ? DAY_HEIGHT : MONTH_HEIGHT);\n calendar.setOption(\n \"contentHeight\",\n dayView ? DAY_CONTENT_HEIGHT : MONTH_CONTENT_HEIGHT\n );\n calendar.setOption(\"expandRows\", !dayView);\n\n if (typeof calendar.updateSize === \"function\") {\n calendar.updateSize();\n }\n}\n\nfunction scheduleResize() {\n window.clearTimeout(resizeTimer);\n\n resizeTimer = window.setTimeout(() => {\n if (calendar) {\n calendar.updateSize();\n }\n }, 250);\n}\n\nfunction isWeekend(date) {\n const day = date.getDay();\n return day === 0 || day === 6;\n}\n\nfunction isBusinessDay(date) {\n const day = date.getDay();\n return day >= 1 && day <= 5;\n}\n\nfunction getMinutesOfDay(date) {\n return date.getHours() * 60 + date.getMinutes();\n}\n\nfunction isBusinessTimeRange(start, end) {\n if (!start || !end) {\n return false;\n }\n\n if (!isBusinessDay(start)) {\n return false;\n }\n\n if (start.toDateString() !== end.toDateString()) {\n return false;\n }\n\n const startMinutes = getMinutesOfDay(start);\n const endMinutes = getMinutesOfDay(end);\n\n return (\n startMinutes >= BUSINESS_START_MINUTES &&\n endMinutes <= BUSINESS_END_MINUTES &&\n endMinutes > startMinutes\n );\n}\n\nfunction isBusinessDayRange(start, end) {\n if (!start || !end || end <= start) {\n return false;\n }\n\n const lastSelectedDay = new Date(end.getTime() - 1);\n const current = new Date(start);\n\n current.setHours(12, 0, 0, 0);\n lastSelectedDay.setHours(12, 0, 0, 0);\n\n while (current <= lastSelectedDay) {\n if (!isBusinessDay(current)) {\n return false;\n }\n\n current.setDate(current.getDate() + 1);\n }\n\n return true;\n}\n\nfunction showWeekendMessage() {\n updateSelectionText(\"Samstag und Sonntag sind nicht buchbar.\");\n}\n\nfunction showBusinessHoursMessage() {\n updateSelectionText(\n \"Reservierungen sind Montag bis Freitag von 07:00 bis 18:00 Uhr möglich.\"\n );\n}\n\nfunction openDayView(date) {\n if (!calendar) {\n return;\n }\n\n if (isWeekend(date)) {\n showWeekendMessage();\n return;\n }\n\n calendar.changeView(\"timeGridDay\", date);\n}\n\nfunction isDayNumberClick(info) {\n const target = info.jsEvent && info.jsEvent.target;\n\n if (!target || typeof target.closest !== \"function\") {\n return false;\n }\n\n return Boolean(target.closest(\".fc-daygrid-day-number\"));\n}\n\nfunction roundToHalfHour(date) {\n const result = new Date(date);\n const minutes = result.getMinutes();\n\n result.setSeconds(0, 0);\n result.setMinutes(minutes < 30 ? 0 : 30);\n\n return result;\n}\n\nfunction pad(value) {\n return String(value).padStart(2, \"0\");\n}\n\nfunction formatLocalDate(date) {\n return [\n date.getFullYear(),\n pad(date.getMonth() + 1),\n pad(date.getDate())\n ].join(\"-\");\n}\n\nfunction formatLocalTime(date) {\n return [\n pad(date.getHours()),\n pad(date.getMinutes()),\n pad(date.getSeconds())\n ].join(\":\");\n}\n\nfunction formatLocalDateTime(date) {\n return `${formatLocalDate(date)}T${formatLocalTime(date)}`;\n}\n\nfunction formatDateTime(date) {\n if (!date) {\n return \"\";\n }\n\n return new Intl.DateTimeFormat(\"de-DE\", {\n dateStyle: \"short\",\n timeStyle: \"short\"\n }).format(date);\n}\n\nfunction triggerAppsmithEvent(evenLine truncated
"js": "let calendar = null;\nlet resizeTimer = null;\nlet modelChangeRegistered = false;\nlet resizeRegistered = false;\n\nconst MONTH_HEIGHT = 620;\nconst MONTH_CONTENT_HEIGHT = 550;\nconst DAY_HEIGHT = 600;\nconst DAY_CONTENT_HEIGHT = 480;\nconst BUSINESS_START_MINUTES = 7 * 60;\nconst BUSINESS_END_MINUTES = 18 * 60;\nconst SLOT_MINUTES = 30;\n\nfunction getModel() {\n const model = appsmith.model || {};\n\n if (typeof model === \"string\") {\n try {\n return JSON.parse(model);\n } catch (error) {\n return {};\n }\n }\n\n return model;\n}\n\nfunction getEvents() {\n const model = getModel();\n return Array.isArray(model.events)\n ? model.events\n : [];\n}\n\nfunction getSeatName() {\n const model = getModel();\n return model.seatName || model.seatId || \"Kein Platz ausgewählt\";\n}\n\nfunction getCurrentUser() {\n const model = getModel();\n return String(model.currentUser || \"\")\n .trim()\n .toLowerCase();\n}\n\nfunction updateSeatTitle() {\n const element = document.getElementById(\"calendarSeatTitle\");\n\n if (!element) return;\n\n element.textContent = `Kalender für ${getSeatName()}`;\n}\n\nfunction isDayView() {\n return Boolean(\n calendar &&\n calendar.view &&\n calendar.view.type === \"timeGridDay\"\n );\n}\n\nfunction updateSelectionText(text) {\n const element = document.getElementById(\"calendarSelection\");\n\n if (!element) return;\n\n if (isDayView()) {\n element.textContent = \"\";\n element.style.display = \"none\";\n return;\n }\n\n element.style.display = \"block\";\n element.textContent = text;\n}\n\nfunction updateCalendarViewSettings(viewType) {\n if (!calendar) return;\n\n const dayView = viewType === \"timeGridDay\";\n\n calendar.setOption(\n \"height\",\n dayView ? DAY_HEIGHT : MONTH_HEIGHT\n );\n\n calendar.setOption(\n \"contentHeight\",\n dayView ? DAY_CONTENT_HEIGHT : MONTH_CONTENT_HEIGHT\n );\n\n calendar.setOption(\n \"expandRows\",\n !dayView\n );\n\n if (typeof calendar.updateSize === \"function\") {\n calendar.updateSize();\n }\n}\n\nfunction scheduleResize() {\n window.clearTimeout(resizeTimer);\n\n resizeTimer = window.setTimeout(() => {\n if (calendar) calendar.updateSize();\n }, 250);\n}\n\nfunction isWeekend(date) {\n const day = date.getDay();\n return day === 0 || day === 6;\n}\n\nfunction isBusinessDay(date) {\n const day = date.getDay();\n return day >= 1 && day <= 5;\n}\n\nfunction getMinutesOfDay(date) {\n return date.getHours() * 60 + date.getMinutes();\n}\n\nfunction isBusinessTimeRange(start, end) {\n if (!start || !end) return false;\n if (!isBusinessDay(start)) return false;\n if (start.toDateString() !== end.toDateString()) return false;\n\n const startMinutes = getMinutesOfDay(start);\n const endMinutes = getMinutesOfDay(end);\n\n return (\n startMinutes >= BUSINESS_START_MINUTES &&\n endMinutes <= BUSINESS_END_MINUTES &&\n endMinutes > startMinutes\n );\n}\n\nfunction isBusinessDayRange(start, end) {\n if (!start || !end || end <= start) return false;\n\n const lastSelectedDay = new Date(\n end.getTime() - 1\n );\n\n const current = new Date(start);\n current.setHours(12, 0, 0, 0);\n lastSelectedDay.setHours(12, 0, 0, 0);\n\n while (current <= lastSelectedDay) {\n if (!isBusinessDay(current)) return false;\n current.setDate(current.getDate() + 1);\n }\n\n return true;\n}\n\nfunction showWeekendMessage() {\n updateSelectionText(\n \"Samstag und Sonntag sind nicht buchbar.\"\n );\n}\n\nfunction showBusinessHoursMessage() {\n updateSelectionText(\n \"Reservierungen sind Montag bis Freitag von 07:00 bis 18:00 Uhr möglich.\"\n );\n}\n\nfunction openDayView(date) {\n if (!calendar) return;\n\n if (isWeekend(date)) {\n showWeekendMessage();\n return;\n }\n\n calendar.changeView(\"timeGridDay\", date);\n}\n\nfunction isDayNumberClick(info) {\n const target = info.jsEvent && info.jsEvent.target;\n\n if (!target || typeof target.closest !== \"function\") {\n return false;\n }\n\n return Boolean(\n target.closest(\".fc-daygrid-day-number\")\n );\n}\n\nfunction roundToHalfHour(date) {\n const result = new Date(date);\n const minutes = result.getMinutes();\n\n result.setSeconds(0, 0);\n result.setMinutes(minutes < 30 ? 0 : 30);\n\n return result;\n}\n\nfunction pad(value) {\n return String(value).padStart(2, \"0\");\n}\n\nfunction formatLocalDate(date) {\n return [\n date.getFullYear(),\n pad(date.getMonth() + 1),\n pad(date.getDate())\n ].join(\"-\");\n}\n\nfunction formatLocalTime(date) {\n return [\n pad(date.getHours()),\n pad(date.getMinutes()),\n pad(date.getSeconds())\n ].join(\":\");\n}\n\nfunction formatLocalDateTime(date) {\n return `${formatLocalDate(date)}T${formatLocalTime(date)}`;\n}\n\nfunction formatDateTime(date) {\n if (!date) return \"\";\n\n return new Intl.DateTimeFormat(\n \"de-DE\",\n {\n dateStyle: \"short\",\n tLine truncated
},
"version": 1,
"widgetId": "ad7fob2vs9",