Skip to content
Open
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.

## Unreleased

- [#188](https://github.com/os2display/display-templates/pull/188)
- Fixed issues with calendar single booking layout.
- Added extra description for resourceAvailableText and hasDateAndTime fields.

## [2.5.1] - 2025-06-23

- [#178](https://github.com/os2display/display-templates/pull/178)
Expand Down
12 changes: 10 additions & 2 deletions build/calendar-admin.json
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@
"name": "resourceAvailableText",
"type": "text",
"label": "Tekst når resursen er ledig",
"helpText": "Her kan du skrive tekst, som vises når resursen er ledig.",
"helpText": "Her kan du skrive tekst, som vises når resursen er ledig. Dette gælder kun for \"Enkelt lokale\" layoutet",
"formGroupClasses": "col-md-6"
},
{
Expand Down Expand Up @@ -159,7 +159,7 @@
{
"key": "calendar-form-has-date-and-time",
"input": "checkbox",
"label": "Vis dato og tidspunkt",
"label": "Vis dato og tidspunkt. Gælder kun for \"Flere resurser\" layoutet",
"name": "hasDateAndTime",
"formGroupClasses": "col-md-6 mb-3"
},
Expand Down Expand Up @@ -210,5 +210,13 @@
"name": "headerOrder",
"formGroupClasses": "col-md-6 mb-3",
"helpText": "Dette er kun relevant hvis \"Flere resurser\" er valgt under \"layout\". Standard er \"Hvornår, hvad, hvor.\""
},
{
"key": "calendar-form-enable-instant-booking",
"input": "checkbox",
"label": "Aktivér straksbooking",
"helpText": "Aktivér mulighed for straksbooking. Dette kræver at resursen er godkendt til straksbooking.",
"name": "instantBookingEnabled",
"formGroupClasses": "mb-3"
}
]
6 changes: 3 additions & 3 deletions build/calendar-config-develop.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"id": "01FRJPF4XATRN8PBZ35XN84PS6",
"description": "Mulighed for at vise et kalenderfeed.",
"resources": {
"component": "https://raw.githubusercontent.com/os2display/display-templates/develop/build/calendar.js?ts=1744372285281",
"admin": "https://raw.githubusercontent.com/os2display/display-templates/develop/build/calendar-admin.json?ts=1744372285281",
"schema": "https://raw.githubusercontent.com/os2display/display-templates/develop/build/calendar-schema.json?ts=1744372285281",
"component": "https://raw.githubusercontent.com/os2display/display-templates/develop/build/calendar.js?ts=1756222633180",
"admin": "https://raw.githubusercontent.com/os2display/display-templates/develop/build/calendar-admin.json?ts=1756222633180",
"schema": "https://raw.githubusercontent.com/os2display/display-templates/develop/build/calendar-schema.json?ts=1756222633180",
"assets": [],
"options": {},
"content": {}
Expand Down
6 changes: 3 additions & 3 deletions build/calendar-config-main.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"id": "01FRJPF4XATRN8PBZ35XN84PS6",
"description": "Mulighed for at vise et kalenderfeed.",
"resources": {
"component": "https://raw.githubusercontent.com/os2display/display-templates/main/build/calendar.js?ts=1744372285281",
"admin": "https://raw.githubusercontent.com/os2display/display-templates/main/build/calendar-admin.json?ts=1744372285281",
"schema": "https://raw.githubusercontent.com/os2display/display-templates/main/build/calendar-schema.json?ts=1744372285281",
"component": "https://raw.githubusercontent.com/os2display/display-templates/main/build/calendar.js?ts=1756222633180",
"admin": "https://raw.githubusercontent.com/os2display/display-templates/main/build/calendar-admin.json?ts=1756222633180",
"schema": "https://raw.githubusercontent.com/os2display/display-templates/main/build/calendar-schema.json?ts=1756222633180",
"assets": [],
"options": {},
"content": {}
Expand Down
2 changes: 1 addition & 1 deletion build/calendar.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ services:
- "traefik.enable=true"
- "traefik.docker.network=frontend"
- "traefik.http.routers.${COMPOSE_PROJECT_NAME}.rule=Host(`${COMPOSE_DOMAIN}`)"
- "traefik.http.services.${COMPOSE_PROJECT_NAME}.loadbalancer.server.port=80"

node:
image: node:20
Expand Down
12 changes: 10 additions & 2 deletions src/calendar/calendar-admin.json
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@
"name": "resourceAvailableText",
"type": "text",
"label": "Tekst når resursen er ledig",
"helpText": "Her kan du skrive tekst, som vises når resursen er ledig.",
"helpText": "Her kan du skrive tekst, som vises når resursen er ledig. Dette gælder kun for \"Enkelt lokale\" layoutet",
"formGroupClasses": "col-md-6"
},
{
Expand Down Expand Up @@ -159,7 +159,7 @@
{
"key": "calendar-form-has-date-and-time",
"input": "checkbox",
"label": "Vis dato og tidspunkt",
"label": "Vis dato og tidspunkt. Gælder kun for \"Flere resurser\" layoutet",
"name": "hasDateAndTime",
"formGroupClasses": "col-md-6 mb-3"
},
Expand Down Expand Up @@ -210,5 +210,13 @@
"name": "headerOrder",
"formGroupClasses": "col-md-6 mb-3",
"helpText": "Dette er kun relevant hvis \"Flere resurser\" er valgt under \"layout\". Standard er \"Hvornår, hvad, hvor.\""
},
{
"key": "calendar-form-enable-instant-booking",
"input": "checkbox",
"label": "Aktivér straksbooking",
"helpText": "Aktivér mulighed for straksbooking. Dette kræver at resursen er godkendt til straksbooking.",
"name": "instantBookingEnabled",
"formGroupClasses": "mb-3"
}
]
83 changes: 62 additions & 21 deletions src/calendar/calendar-single-booking.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,12 @@ function CalendarSingleBooking({
slide,
run,
}) {
const { title = "", subTitle = null, mediaContain } = content;
const {
title = "",
subTitle = null,
mediaContain,
instantBookingEnabled = false,
} = content;

// Get values from client localstorage.
const token = localStorage.getItem("apiToken");
Expand All @@ -71,6 +76,10 @@ function CalendarSingleBooking({
const [bookingError, setBookingError] = useState(false);

const fetchBookingIntervals = () => {
if (!instantBookingEnabled) {
return;
}

if (!apiUrl || !slide || !token || !tenantKey) {
setFetchingIntervals(false);
return;
Expand Down Expand Up @@ -148,22 +157,31 @@ function CalendarSingleBooking({

const instantBooking = getInstantBookingFromLocalStorage(slide["@id"]);

let newBookingResult = null;

// Clean out old instantBookings.
if (instantBooking) {
if (dayjs(instantBooking.interval.to) < dayjs()) {
setInstantBookingFromLocalStorage(slide["@id"], null);
setBookingResult(null);
if (instantBooking !== null) {
const intervalFrom = instantBooking?.interval?.to;

if (intervalFrom !== null && dayjs(intervalFrom) > dayjs()) {
newBookingResult = instantBooking;
} else {
setBookingResult(instantBooking);
setInstantBookingFromLocalStorage(slide["@id"], null);
}
}

setBookingResult(newBookingResult);
};

const clickInterval = (interval) => {
if (!apiUrl || !slide || !token || !tenantKey) {
return;
}

if (!instantBookingEnabled) {
return;
}

setProcessingBooking(true);

fetch(`${apiUrl}${slide["@id"]}/action`, {
Expand Down Expand Up @@ -210,7 +228,9 @@ function CalendarSingleBooking({
}, []);

useEffect(() => {
fetchBookingIntervals();
if (instantBookingEnabled) {
fetchBookingIntervals();
}
}, [run]);

const currentEvents = calendarEvents.filter(
Expand All @@ -219,10 +239,13 @@ function CalendarSingleBooking({
);

const futureEvents = calendarEvents.filter(
(el) => !currentEvents.includes(el)
(el) =>
!currentEvents.includes(el) &&
el.endTime > dayjs().unix() &&
el.endTime <= dayjs().endOf("day").unix()
);

const roomInUse = currentEvents.length > 0;
const roomInUse = bookingResult !== null || currentEvents.length > 0;

const roomAvailableForInstantBooking =
!roomInUse && fetchingIntervals ? null : bookableIntervals?.length > 0;
Expand Down Expand Up @@ -278,18 +301,35 @@ function CalendarSingleBooking({
</DateTime>
</Header>
<Content className="content">
{roomInUse &&
currentEvents.map((event) => (
<ContentItem key={event.id} className="content-item">
<Meta>
{renderTimeOfDayFromUnixTimestamp(event.startTime)}
{" - "}
{renderTimeOfDayFromUnixTimestamp(event.endTime)}
</Meta>
<h1>{getTitle(event.title)}</h1>
</ContentItem>
))}
{!roomInUse && (
{roomInUse && (
<>
{bookingResult && (
<ContentItem className="content-item">
<p>
<FormattedMessage
id="instant_booked_until"
defaultMessage="Lokalet er straksbooket indtil"
/>{" "}
{dayjs(bookingResult.interval.to)
.locale(localeDa)
.format("HH:mm")}
</p>
</ContentItem>
)}
{!bookingResult &&
currentEvents.map((event) => (
<ContentItem key={event.id} className="content-item">
<Meta>
{renderTimeOfDayFromUnixTimestamp(event.startTime)}
{" - "}
{renderTimeOfDayFromUnixTimestamp(event.endTime)}
</Meta>
<h1>{getTitle(event.title)}</h1>
</ContentItem>
))}
</>
)}
{!roomInUse && instantBookingEnabled && (
<>
<ContentItem className="content-item">
{!processingBooking && !bookingResult && !bookingError && (
Expand Down Expand Up @@ -410,6 +450,7 @@ CalendarSingleBooking.propTypes = {
resourceAvailableText: PropTypes.string,
resourceUnavailableText: PropTypes.string,
mediaContain: PropTypes.bool,
instantBookingEnabled: PropTypes.bool,
}).isRequired,
getTitle: PropTypes.func.isRequired,
};
Expand Down
1 change: 1 addition & 0 deletions src/slides.js
Original file line number Diff line number Diff line change
Expand Up @@ -1401,6 +1401,7 @@ const slides = [
darkModeEnabled: false,
content: {
duration: 60000,
instantBookingEnabled: true,
layout: "singleBooking",
title: "M2.3",
subTitle: "Mødelokale",
Expand Down