Skip to content
Snippets Groups Projects
timer.js 8.44 KiB
import $ from "jquery"
import Timer from "easytimer.js"

import alertify from "alertifyjs";
import "alertifyjs/build/css/alertify.css";

const disableInputs = () => {
    $("#pause_play,#minutes,#seconds,#update_time,#reset_time").prop("disabled", true)
}

const enableInputs = () => {
    $("#pause_play,#minutes,#seconds,#update_time,#reset_time").prop("disabled", false)
}

const updateTimeText = () => {
    const timeValues = window.timer.getTimeValues()

    const hours = String(timeValues.minutes + timeValues.hours * 60 + timeValues.days * 1440).padStart(2, '0')
    const seconds = String(timeValues.seconds).padStart(2, '0')

    $('#timer .timer-values').html(`${hours}:${seconds}`)
}

const assignEventListeners = () => {
    window.timer.addEventListener(
        'secondsUpdated',
        (event) => {
            updateTimeText()
        }
    )

    window.timer.addEventListener(
        'targetAchieved',
        (event) => {
            $("#is_counting").prop("checked", false)
            $('#timer .timer-values').html("Konec")
        }
    )

    updateTimeText()
}

const updateTimer = (data, options) => {
    const timerValues = timer.getTimeValues()
    const minutes = data["sync_time"]["minutes"]
    const seconds = data["sync_time"]["seconds"]

    if (window.timerIsRunning && (minutes === 0 && seconds <= 5)) {
        // Don't update the time if we're running in the final 5 seconds.
        return
    }

    if (options.minuteTolerance !== undefined && options.secondTolerance !== undefined) {
        if (
            (Math.abs(timerValues.minutes - minutes) < options.minuteTolerance)
            && (Math.abs(timerValues.seconds - seconds) < options.secondTolerance)
        ) {
            // Don't annoy the user with time changes when there is only a 1-2 second difference.
            return
        } else {
            console.warn("Timer out of sync!")
        }
    }

    if (minutes === 0 && seconds === 0) {
        // Let an event listener handle the timer ending.
        return
    }

    console.info(`Updating timer: ${minutes}:${seconds}, used to be ${timerValues.minutes}:${timerValues.seconds}`)

    window.startingTime = {
        minutes: minutes,
        seconds: seconds
    }

    window.timer.removeAllEventListeners()

    window.timer = new Timer({
        countdown: true,
        startValues: {
            minutes: window.startingTime.minutes,
            seconds: window.startingTime.seconds,
        }
    })

    assignEventListeners()

    if (window.timerIsRunning) {
        window.timer.start()
    }
}

const syncTime = (timerSocket) => {
    timerSocket.send(JSON.stringify({
        "sync": window.timer.getTimeValues()
    }))
}

$(window).ready(
    () => {
        disableInputs()

        // --- BEGIN Timer ---

        window.timerIsRunning = false
        window.timer = new Timer({
            countdown: true,
            startValues: {
                minutes: window.startingTime.minutes,
                seconds: window.startingTime.seconds,
            }
        })

        let timerSocket = null
        let isInitialConnect = true

        const connectToSocket = () => {
            timerSocket = new WebSocket(
                (
                    (window.location.protocol === "https:") ?
                    "wss://" : "ws://"
                )
                + window.location.host
                + "/ws/timer/"
                + window.timerId
                + "/"
            )

            if (!isInitialConnect) {
                alertify.success("Obnovování spojení.")
            }

            isInitialConnect = false

            timerSocket.onmessage = (event) => {
                enableInputs()

                console.info("Received timer message:", event.data)
                const data = JSON.parse(event.data)

                if ("sync_time" in data) {
                   updateTimer(
                        data,
                        {
                            minuteTolerance: 1,
                            secondTolerance: 2
                        }
                    )
                }

                if ("is_running" in data) {
                    if (data["is_running"]) {
                        // Reset if we are playing again.
                        const remainingTime = window.timer.getTimeValues()

                        if (remainingTime.seconds === 0 && remainingTime.minutes === 0) {
                            window.timer = new Timer({
                                countdown: true,
                                startValues: {
                                    minutes: window.startingTime.minutes,
                                    seconds: window.startingTime.seconds,
                                }
                            })

                            assignEventListeners()
                        }

                        window.timer.start()

                        $("#is_counting").prop("checked", true)
                        $("#pause_play > .btn__body").html("⏸︎")
                        window.timerIsRunning = true
                    } else {
                        window.timer.pause()

                        $("#is_counting").prop("checked", false)
                        $("#pause_play > .btn__body").html("⏵︎")
                        window.timerIsRunning = false
                    }
                }
            }

            let interval = null

            timerSocket.onopen = () => {
                syncTime(timerSocket)

                interval = setInterval(syncTime, 1000, timerSocket)

                // --- BEGIN Controls ---

                $("#pause_play").on(
                    "click",
                    (event) => {
                        const timeValues = window.timer.getTimeValues()

                        if (timeValues.minutes == 0 && timeValues.seconds == 0) {
                            alertify.error("Prosím, nastav čas.")

                            return
                        }

                        $("#is_counting").click()
                    }
                )

                $("#is_counting").on(
                    "change",
                    (event) => {
                        disableInputs()

                        if (event.target.checked) {
                            console.info("Starting timer")

                            $("#pause_play > .btn__body").html("⏸︎")
                            timerSocket.send(JSON.stringify({
                                "is_running": true
                            }))
                        } else {
                            console.info("Stopping timer")

                            $("#pause_play > .btn__body").html("⏵︎")
                            timerSocket.send(JSON.stringify({
                                "is_running": false
                            }))
                        }
                    }
                )

                $("#update_time").on(
                    "click",
                    (event) => {
                        disableInputs()

                        window.timer.pause()

                        let minutes = Number($("#minutes").val())
                        let seconds = Number($("#seconds").val())

                        timerSocket.send(JSON.stringify({
                            "time": {
                                "minutes": minutes,
                                "seconds": seconds
                            },
                            "is_running": false
                        }))

                        $("#is_counting").prop("checked", false)
                    }
                )

                $("#reset_time").on(
                    "click",
                    (event) => {
                        disableInputs()

                        window.timer.pause()

                        timerSocket.send(JSON.stringify({
                            "reset": true,
                            "is_running": false
                        }))
                    }
                )

                // --- END Controls ---
            }

            timerSocket.onclose = (event) => {
                disableInputs()

                alertify.error("Ztráta spojení, pokoušíme se o zpětné připojení.")

                setTimeout(connectToSocket, 1000)
                clearInterval(interval)
                $("#is_counting,#pause_play,#update_time").unbind("click")
            }
        }

        connectToSocket()
        assignEventListeners()

        // --- END Timer ---
    }
)