87 lines
2.3 KiB
TypeScript
87 lines
2.3 KiB
TypeScript
import * as Y from "yjs";
|
|
import { getDeadline } from "../state";
|
|
|
|
const DEADLINE_DURATION_MS = 2 * 60 * 1000; // 2 minutes
|
|
|
|
export function DeadlineTimer(
|
|
deadlineMap: Y.Map<unknown>,
|
|
onStartDeadline: (durationMs: number) => void,
|
|
onClearDeadline: () => void,
|
|
): HTMLElement {
|
|
const wrapper = document.createElement("div");
|
|
wrapper.className = "deadline-wrapper";
|
|
|
|
const timerEl = document.createElement("span");
|
|
timerEl.className = "deadline-timer";
|
|
|
|
const startBtn = document.createElement("button");
|
|
startBtn.className = "deadline-btn";
|
|
startBtn.textContent = "Start 2-min vote";
|
|
startBtn.setAttribute("aria-label", "Start a 2-minute voting deadline");
|
|
|
|
const clearBtn = document.createElement("button");
|
|
clearBtn.className = "deadline-btn deadline-btn--clear";
|
|
clearBtn.textContent = "Clear";
|
|
clearBtn.setAttribute("aria-label", "Remove voting deadline");
|
|
|
|
wrapper.append(timerEl, startBtn, clearBtn);
|
|
|
|
let interval: ReturnType<typeof setInterval> | undefined;
|
|
|
|
function render() {
|
|
const deadline = getDeadline(deadlineMap);
|
|
const now = Date.now();
|
|
|
|
if (deadline === null) {
|
|
// No deadline set
|
|
timerEl.textContent = "";
|
|
timerEl.className = "deadline-timer";
|
|
startBtn.hidden = false;
|
|
clearBtn.hidden = true;
|
|
if (interval) {
|
|
clearInterval(interval);
|
|
interval = undefined;
|
|
}
|
|
return;
|
|
}
|
|
|
|
startBtn.hidden = true;
|
|
clearBtn.hidden = false;
|
|
|
|
if (now >= deadline) {
|
|
// Voting closed
|
|
timerEl.textContent = "Voting closed";
|
|
timerEl.className = "deadline-timer deadline-timer--closed";
|
|
if (interval) {
|
|
clearInterval(interval);
|
|
interval = undefined;
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Counting down
|
|
const remaining = Math.ceil((deadline - now) / 1000);
|
|
const mins = Math.floor(remaining / 60);
|
|
const secs = remaining % 60;
|
|
timerEl.textContent = `Voting closes in ${mins}:${secs.toString().padStart(2, "0")}`;
|
|
timerEl.className = "deadline-timer deadline-timer--active";
|
|
|
|
if (!interval) {
|
|
interval = setInterval(() => render(), 1000);
|
|
}
|
|
}
|
|
|
|
startBtn.addEventListener("click", () => {
|
|
onStartDeadline(DEADLINE_DURATION_MS);
|
|
});
|
|
|
|
clearBtn.addEventListener("click", () => {
|
|
onClearDeadline();
|
|
});
|
|
|
|
deadlineMap.observe(() => render());
|
|
render();
|
|
|
|
return wrapper;
|
|
}
|