Sixtens hemsida Uppgifter Blogg Om

VED House bokningssystem

Gå till sida

Källkod

api/

database.php

api.php

ved/

monthBookingData.php

openingHoursException.php

bookingData.php

dayTimeframes.php

bookings.php

admin/

revokeToken.php

authorization.php

login.php

modules/

vedDatabase.php

utility.php

gyar/

log.php

auth/

revokeToken.php

authorization.php

login.php

station/

settings.php

log.php

modules/

gyarDatabase.php

databaseConnection.php

database.php

utility.php

credentials.json

weather/

latest.php

old.php

admin/

index.html

changeTimetable.html

login.html

js/

login.js

modules.js

admin.js

header.js

changeTimetable.js

cron/

vedClearExpiredTokens.php

weuweb01/ved/admin/js/changeTimetable.js

1 lines
import { vedAPI as api, getAuthHeader, httpErrorMessage } from "./modules.js";

var auth = getAuthHeader();
var bookingData;

const appendAlert = (wrapper, message, type = "danger") => {
    wrapper.innerHTML = "";
    const alertBox = document.createElement("div")
    alertBox.innerHTML = [
        `<div class="alert alert-${type} alert-dismissible" role="alert">`,
        `   <div>${message}</div>`,
        '   <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>',
        '</div>'
    ].join('')

    wrapper.append(alertBox);
}

function wrapApiResponse(wrapper, response, successMessage) {
    if (!response.ok) {
        appendAlert(wrapper, httpErrorMessage(response.status));
        return;
    }
    if (successMessage)
        appendAlert(wrapper, successMessage, "success");
}

// Schemed opening hours

var timetableForm = document.getElementById("timetable-form");
var timetableFormError = document.getElementById("timetable-form-error");
var bookingIntervalInput = document.querySelector("[name=bookingInterval]");
var bookingLengthInput = document.querySelector("[name=bookingLength]");
var seatCountInput = document.querySelector("[name=seatCount]");

const weekdays = ["Måndag", "Tisdag", "Onsdag", "Torsdag", "Fredag", "Lördag", "Söndag"];

function registerTimeSelector(timeSelector) {
    let isOpenSwitch = timeSelector.querySelector(".day-is-open");
    let openingInput = timeSelector.querySelector(".day-opening");
    let closingInput = timeSelector.querySelector(".day-closing");

    let enable = () => isOpenSwitch.checked = true;
    openingInput.addEventListener("change", enable);
    closingInput.addEventListener("change", enable);
    isOpenSwitch.addEventListener("change", () => {
        if (isOpenSwitch.checked) return;
        openingInput.value = "";
        closingInput.value = "";
    });

    return {
        switch: isOpenSwitch,
        opening: openingInput,
        closing: closingInput
    };
}

var dayTimes = document.getElementById("dayTimes");
var weekdayTimeSelectors = [];
for (let i = 0; i < weekdays.length; i++) {
    let timeSelector = document.createElement("div")
    timeSelector.classList.add("row");
    timeSelector.innerHTML = `<label for="opening-hours-day${i}-1" class="col pt-1">
            ${weekdays[i]}:
        </label>
        <div class="col">
            <div class="form-check form-switch pt-2 pd-2 float-end">
                <input class="form-check-input day-is-open" type="checkbox" role="switch"
                    id="switchCheckDefault" name="isOpen{$i}">
            </div>
        </div>
        <div class="col">
            <div class="input-group mb-3" style="width: 7rem">
                <input id="opening-hours-day${i}-1" type="time" class="form-control day-opening" name="opening{$i}">
            </div>
        </div>
        <div class="col">
            <div class="input-group mb-3" style="width: 7rem">
                <input id="opening-hours-day${i}-2" type="time" class="form-control day-closing" name="closing{$i}">
            </div>
        </div>`;
    dayTimes.append(timeSelector);

    let object = registerTimeSelector(timeSelector);
    weekdayTimeSelectors.push(object);
}

async function processTimetableForm(e) {
    if (e.preventDefault) e.preventDefault();
    timetableFormError.innerHTML = "";

    let bookingInterval = Number(bookingIntervalInput.value);
    let bookingLength = Number(bookingLengthInput.value);
    if (bookingLength % bookingInterval != 0) {
        appendAlert(timetableFormError, "Bokningsintervall måste passa in i bokningslängd!");
        return;
    }

    let data = {
        "seatCount": Number(seatCountInput.value),
        "bookingInterval": bookingInterval,
        "bookingLength": bookingLength,
        "openingHours": []
    };

    for (let i = 0; i < weekdayTimeSelectors.length; i++) {
        let timeSelector = weekdayTimeSelectors[i];
        if (!timeSelector.switch.checked) {
            data.openingHours.push({ "openingTime": null, "closingTime": null });
            continue;
        }
        if (timeSelector.opening.value == "" || timeSelector.closing.value == "") {
            appendAlert(timetableFormError, `Ogiltig tid för ${weekdays[i].toLowerCase()}!`);
            return;
        }
        data.openingHours.push({ "openingTime": timeSelector.opening.value, "closingTime": timeSelector.closing.value });

        let [openHours, openMins] = timeSelector.opening.value.split(":");
        let [closeHours, closeMins] = timeSelector.closing.value.split(":");
        let dayLength = closeHours * 60 + Number(closeMins) - (openHours * 60 + Number(openMins));
        if (!dayLength || dayLength < bookingLength) {
            appendAlert(timetableFormError, `Ogiltig tid för ${weekdays[i].toLowerCase()}!`);
            return;
        }

        if (dayLength % bookingInterval != 0) {
            appendAlert(timetableFormError, `Bokningsintervall måste passa in i ${weekdays[i].toLowerCase()}!`);
            return;
        }
    }

    let res = await api.fetch("bookingData", "PUT", { "body": JSON.stringify(data), "headers": { "Authorization": auth } });
    wrapApiResponse(timetableFormError, res, "Uppdaterat!");
    if (!res.ok)
        return;
    bookingData = data;
}

if (timetableForm.attachEvent) {
    timetableForm.attachEvent("submit", processTimetableForm);
} else {
    timetableForm.addEventListener("submit", processTimetableForm);
}

async function loadBookingData() {
    let res = await api.fetch("bookingData");
    wrapApiResponse(timetableFormError, res);
    if (!res.ok)
        return;

    let data = await res.json();
    bookingData = data;
    seatCountInput.value = data.seatCount;
    bookingIntervalInput.value = data.bookingInterval;
    bookingLengthInput.value = data.bookingLength;
    for (let i = 0; i < data.openingHours.length; i++) {
        let openingHours = data.openingHours[i];
        if (!openingHours.openingTime || !openingHours.openingTime)
            continue;
        let group = weekdayTimeSelectors[i];
        group.opening.value = openingHours.openingTime;
        group.closing.value = openingHours.closingTime;
        group.switch.checked = true;
    }
}

loadBookingData();

// Opening hours exceptions adder

var exceptionForm = document.getElementById("exception-form");
var exceptionFormError = document.getElementById("exception-form-error");
var exceptionDay1Input = document.getElementById("exception-day1");
var exceptionDay2Input = document.getElementById("exception-day2");

var exceptionTimeSelector = registerTimeSelector(document.getElementById("exception-time"));
var multiDayCheck = document.getElementById("multi-day");
multiDayCheck.checked = false;
multiDayCheck.addEventListener("change", () => {
    document.querySelector("#exception-single-day label").innerText = multiDayCheck.checked ? "Från:" : "Datum:";
    let mdd = document.getElementById("exception-multi-day");
    let ed2 = document.getElementById("exception-day2");
    if (multiDayCheck.checked) {
        mdd.removeAttribute("hidden");
        ed2.setAttribute("required", "");
    }
    else {
        mdd.setAttribute("hidden", "");
        ed2.removeAttribute("required");
    }
});

async function processExceptionForm(e) {
    if (e.preventDefault) e.preventDefault();
    exceptionFormError.innerHTML = "";


    if (exceptionTimeSelector.switch.checked) {
        let [openHours, openMins] = exceptionTimeSelector.opening.value.split(":");
        let [closeHours, closeMins] = exceptionTimeSelector.closing.value.split(":");
        let dayLength = closeHours * 60 + Number(closeMins) - (openHours * 60 + Number(openMins));
        if (!dayLength || dayLength < bookingData["bookingLength"]) {
            appendAlert(exceptionFormError, "Ogiltig tid!");
            return;
        }
        if (dayLength % bookingData["bookingInterval"] != 0) {
            appendAlert(exceptionFormError, "Bokningsintervall måste passa in i tiderna!");
            return;
        }
    }

    let data = {
        "openingTime": exceptionTimeSelector.opening.value,
        "closingTime": exceptionTimeSelector.closing.value,
        "date": exceptionDay1Input.value,
    }
    if (multiDayCheck.checked)
        data["date2"] = exceptionDay2Input.value;
    if (exceptionDay2Input.value) {
        let date1 = new Date(exceptionDay1Input.value);
        let date2 = new Date(exceptionDay2Input.value);

        if (date1.getTime() >= date2.getTime()) {
            appendAlert(exceptionFormError, "Ogiltiga datum!");
            return;
        }
    }

    for (let key in data)
        if (data[key] == "") data[key] = null;
    let res = await api.fetch("openingHoursException", "POST", { "body": JSON.stringify(data), "headers": { "Authorization": auth } });
    wrapApiResponse(exceptionFormError, res, "Tillagt!");

    if (res.ok)
        updateExceptionsList();
}

if (exceptionForm.attachEvent) {
    exceptionForm.attachEvent("submit", processExceptionForm);
} else {
    exceptionForm.addEventListener("submit", processExceptionForm);
}

// Opening hours exceptions list
var exceptionListError = document.getElementById("exception-list-error");
var exceptionListEmpty = document.getElementById("exception-list-empty");
var exceptionListContainer = document.getElementById("exception-list-container");

async function updateExceptionsList() {
    let res = await api.fetch("openingHoursException", "GET", { "headers": { "Authorization": auth } });
    wrapApiResponse(exceptionListError, res);
    if (!res.ok)
        return;
    let data = await res.json();

    if (data.length == 0)
        exceptionListEmpty.removeAttribute("hidden");
    else
        exceptionListEmpty.setAttribute("hidden", "");

    exceptionListContainer.innerHTML = "";
    for (let i = 0; i < data.length; i++) {
        let exceptionData = data[i];
        let dateText = exceptionData["date2"] ? `${exceptionData["date1"]} — ${exceptionData["date2"]}` : exceptionData["date1"];
        let timeText = (exceptionData["openingTime"] && exceptionData["closingTime"]) ? `${exceptionData["openingTime"]} — ${exceptionData["closingTime"]}` : "Stängt";

        const box = document.createElement("div");
        box.classList.add("card");
        box.classList.add("m-1");
        box.innerHTML = `<div class="card-body">
                <button class="btn btn-danger float-end mt-1">Ta bort</button>
                <span>Datum: ${dateText}</span>
                <br>
                    <span>Tider: ${timeText}</span>
            </div>`;
        box.querySelector("button").addEventListener("click", async () => {
            let res = await api.fetch("openingHoursException", "DELETE", { "body": JSON.stringify({ "exceptionId": exceptionData["exceptionId"] }), "headers": { "Authorization": auth } });
            wrapApiResponse(exceptionListError, res);
            if (!res.ok) return;

            exceptionListContainer.removeChild(box);
            if (exceptionListContainer.children.length == 0)
                exceptionListEmpty.removeAttribute("hidden");

        });
        exceptionListContainer.append(box);
    }

}
updateExceptionsList();