digitalfabrik/integreat-cms

View on GitHub
integreat_cms/static/src/js/poi_box.ts

Summary

Maintainability
A
0 mins
Test Coverage
import { createIconsAt } from "./utils/create-icons";
import { getCsrfToken } from "./utils/csrf-token";

const toggleContactInfo = (infoType: string, info: string) => {
    document.getElementById(infoType).textContent = `${info}`;
    const infoNotGivenMessage = document.getElementById(`no-${infoType}`);
    if (info) {
        infoNotGivenMessage.classList.add("hidden");
    } else {
        infoNotGivenMessage.classList.remove("hidden");
    }
};

const toggleContactFieldBox = (show: boolean) => {
    const contactFieldsBox = document.getElementById("contact_fields");
    contactFieldsBox?.classList.toggle("hidden", !show);
    const contactUsageBox = document.getElementById("contact_usage");
    contactUsageBox?.classList.toggle("hidden", !show);
};

const renderPoiData = (
    queryPlaceholder: string,
    id: string,
    address: string,
    postcode: string,
    city: string,
    country: string,
    email: string,
    phoneNumber: string,
    website: string
) => {
    document.getElementById("poi-query-input").setAttribute("placeholder", queryPlaceholder);
    document.getElementById("id_location")?.setAttribute("value", id);
    const poiAddress = document.getElementById("poi-address");
    if (poiAddress) {
        poiAddress.textContent = `${address}\n${postcode} ${city}\n${country}`;
    }
    if (document.getElementById("poi-contact-information")) {
        toggleContactInfo("email", email);
        toggleContactInfo("phone_number", phoneNumber);
        toggleContactInfo("website", website);
    }

    document
        .getElementById("poi-google-maps-link")
        ?.setAttribute(
            "href",
            `https://www.google.com/maps/search/?api=1&query=${address}, ${postcode} ${city}, ${country}`
        );
    document.getElementById("poi-query-result").classList.add("hidden");
    (document.getElementById("poi-query-input") as HTMLInputElement).value = "";
    toggleContactFieldBox(true);
};

const hidePoiFormWidget = () => {
    const widget = document.getElementById("poi-form-widget") as HTMLElement;
    if (widget) {
        widget.textContent = "";
    }
};

const setPoi = ({ target }: Event) => {
    const option = (target as HTMLElement).closest(".option-existing-poi");
    renderPoiData(
        option.getAttribute("data-poi-title"),
        option.getAttribute("data-poi-id"),
        option.getAttribute("data-poi-address"),
        option.getAttribute("data-poi-postcode"),
        option.getAttribute("data-poi-city"),
        option.getAttribute("data-poi-country"),
        option.getAttribute("data-poi-email"),
        option.getAttribute("data-poi-phone_number"),
        option.getAttribute("data-poi-website")
    );
    // Show the address container
    document.getElementById("poi-address-container")?.classList.remove("hidden");
    console.debug("Rendered POI data");
};

const showMessage = (response: any) => {
    const timeoutDuration = 10000;
    if (response.success) {
        hidePoiFormWidget();
        const successMessageField = document.getElementById("poi-ajax-success-message");
        successMessageField.classList.remove("hidden");
        setTimeout(() => {
            successMessageField.classList.add("hidden");
        }, timeoutDuration);
    } else {
        const errorMessageField = document.getElementById("poi-ajax-error-message");
        errorMessageField.classList.remove("hidden");
        setTimeout(() => {
            errorMessageField.classList.add("hidden");
        }, timeoutDuration);
    }
};

const showPoiFormWidget = async ({ target }: Event) => {
    const option = (target as HTMLElement).closest(".option-new-poi");
    const response = await fetch(document.getElementById("show-poi-form-button").getAttribute("data-url"));

    document.getElementById("poi-form-widget").innerHTML = await response.text();
    document.querySelector("[data-poi-title]").setAttribute("value", option.getAttribute("data-poi-title"));
    document.getElementById("show-poi-form-button").classList.add("hidden");

    // Add listeners for save and draft-save buttons
    document.querySelectorAll("[data-btn-save-poi-form]").forEach((el) => {
        el.addEventListener("click", async (event) => {
            event.preventDefault();
            const btn = event.target as HTMLInputElement;
            const form = btn.form as HTMLFormElement;
            const formData: FormData = new FormData(form);
            formData.append(btn.name, btn.value);
            if (!form.reportValidity()) {
                return;
            }
            const response = await fetch(btn.getAttribute("data-url"), {
                method: "POST",
                headers: {
                    "X-CSRFToken": getCsrfToken(),
                },
                body: formData,
            });
            // Handle messages
            const messages = await response.json();
            console.debug(messages);
            showMessage(messages);
            // If POI was created successful, show it as selected option
            if (messages.success) {
                console.debug(messages);
                renderPoiData(
                    formData.get("title").toString(),
                    messages.id,
                    formData.get("address").toString(),
                    formData.get("postcode").toString(),
                    formData.get("city").toString(),
                    formData.get("country").toString(),
                    formData.get("email").toString(),
                    formData.get("phone_number").toString(),
                    formData.get("website").toString()
                );
                document.getElementById("poi-address-container")?.classList.remove("hidden");
                // Add the POI to the actual django form field
                (document.getElementById("id_location") as HTMLInputElement).value = messages.id.toString();
            }
            hidePoiFormWidget();
        });
    });
};

const queryPois = async (url: string, queryString: string, regionSlug: string, createPoiOption: boolean) => {
    const response = await fetch(url, {
        method: "POST",
        headers: {
            "X-CSRFToken": getCsrfToken(),
        },
        body: JSON.stringify({
            query_string: queryString,
            region_slug: regionSlug,
            create_poi_option: createPoiOption,
        }),
    });

    const HTTP_STATUS_OK = 200;
    if (response.status !== HTTP_STATUS_OK) {
        // Invalid status => return empty result
        return "";
    }

    const data = await response.text();

    if (data) {
        // Set and display new data
        const queryResult = document.getElementById("poi-query-result");
        queryResult.classList.remove("hidden");
        queryResult.innerHTML = data;
        createIconsAt(queryResult);
    }

    document.querySelectorAll(".option-new-poi").forEach((node) => {
        node.addEventListener("click", (event) => {
            event.preventDefault();
            showPoiFormWidget(event);
        });
    });

    document.querySelectorAll(".option-existing-poi").forEach((node) => {
        console.debug("Set event listener for existing POI:", node);
        node.addEventListener("click", (event) => {
            event.preventDefault();
            setPoi(event);
        });
    });

    return "";
};

const removePoi = () => {
    renderPoiData(
        document.getElementById("poi-query-input").getAttribute("data-default-placeholder"),
        "-1",
        "",
        "",
        "",
        "",
        "",
        "",
        ""
    );
    // Hide the address container
    document.getElementById("poi-address-container")?.classList.add("hidden");
    // Clear the poi form
    hidePoiFormWidget();
    toggleContactFieldBox(false);
    console.debug("Removed POI data");
};

let scheduledFunction: number | null = null;
const setPoiQueryEventListeners = () => {
    // AJAX search
    document.getElementById("poi-query-input").addEventListener("keyup", (event) => {
        hidePoiFormWidget();
        event.preventDefault();
        const inputField = (event.target as HTMLElement).closest("input");

        // Reschedule function execution on new input
        if (scheduledFunction) {
            clearTimeout(scheduledFunction);
        }
        // Schedule function execution
        const timeoutDuration = 300;
        scheduledFunction = window.setTimeout(
            queryPois,
            timeoutDuration,
            inputField.getAttribute("data-url"),
            inputField.value,
            inputField.getAttribute("data-region-slug"),
            !inputField.classList.contains("no-new-poi") // Allow suppressing the option to create a new POI
        );
    });

    // Hide AJAX search results
    document.addEventListener("click", ({ target }) => {
        if (
            !(target as HTMLElement).closest("#poi-query-input") &&
            !(target as HTMLElement).closest("#poi-query-result")
        ) {
            // Neither clicking on input field nor on result to select it
            document.getElementById("poi-query-result").innerHTML = "";
            (document.getElementById("poi-query-input") as HTMLInputElement).value = "";
        }
    });

    // Remove POI
    document.getElementById("poi-remove").addEventListener("click", (event) => {
        event.preventDefault();
        removePoi();
    });
};

window.addEventListener("load", () => {
    if (document.getElementById("poi-query-input") && !document.querySelector("[data-disable-poi-query]")) {
        setPoiQueryEventListeners();
        // event handler to reset filter form
        document.getElementById("filter-reset")?.addEventListener("click", removePoi);
    }
});