133 lines
3.6 KiB
TypeScript
133 lines
3.6 KiB
TypeScript
import { acceptHMRUpdate, defineStore } from "pinia";
|
||
import { API } from "./api";
|
||
import { Loading } from "./helpers";
|
||
import { Credentials, DoorSaved, ImageData, SiteConfigModel } from "./model";
|
||
import { Door } from "./rects/door";
|
||
|
||
declare global {
|
||
interface Navigator {
|
||
readonly msMaxTouchPoints: number;
|
||
}
|
||
}
|
||
|
||
type State = {
|
||
on_initialized: (() => void)[] | null;
|
||
is_touch_device: boolean;
|
||
is_admin: boolean;
|
||
site_config: SiteConfigModel;
|
||
background_image: Loading<ImageData>;
|
||
user_doors: Door[];
|
||
next_door_target: number | null;
|
||
};
|
||
|
||
export const advent22Store = defineStore({
|
||
id: "advent22",
|
||
|
||
state: (): State => ({
|
||
on_initialized: [],
|
||
is_touch_device:
|
||
window.matchMedia("(any-hover: none)").matches ||
|
||
"ontouchstart" in window ||
|
||
navigator.maxTouchPoints > 0 ||
|
||
navigator.msMaxTouchPoints > 0,
|
||
is_admin: false,
|
||
site_config: {
|
||
title: document.title,
|
||
subtitle: "",
|
||
content: "",
|
||
footer: "",
|
||
},
|
||
background_image: "loading",
|
||
user_doors: [],
|
||
next_door_target: null,
|
||
}),
|
||
|
||
actions: {
|
||
async init(): Promise<void> {
|
||
await this.update();
|
||
|
||
if (this.on_initialized !== null) {
|
||
for (const callback of this.on_initialized) callback();
|
||
}
|
||
this.on_initialized = null;
|
||
},
|
||
|
||
async update(): Promise<void> {
|
||
try {
|
||
const favicon = await API.request<ImageData>("user/favicon");
|
||
|
||
const link: HTMLLinkElement =
|
||
document.querySelector("link[rel*='icon']") ||
|
||
document.createElement("link");
|
||
link.rel = "shortcut icon";
|
||
link.type = "image/x-icon";
|
||
link.href = favicon.data_url;
|
||
|
||
if (link.parentElement === null)
|
||
document.getElementsByTagName("head")[0].appendChild(link);
|
||
} catch {}
|
||
|
||
try {
|
||
const [is_admin, site_config, background_image, user_doors, next_door] =
|
||
await Promise.all([
|
||
this.update_is_admin(),
|
||
API.request<SiteConfigModel>("user/site_config"),
|
||
API.request<ImageData>("user/background_image"),
|
||
API.request<DoorSaved[]>("user/doors"),
|
||
API.request<number | null>("user/next_door"),
|
||
]);
|
||
void is_admin; // discard value
|
||
|
||
document.title = site_config.title;
|
||
|
||
if (site_config.subtitle !== "")
|
||
document.title += " – " + site_config.subtitle;
|
||
|
||
this.site_config = site_config;
|
||
this.background_image = background_image;
|
||
|
||
this.user_doors.length = 0;
|
||
for (const door_saved of user_doors) {
|
||
this.user_doors.push(Door.load(door_saved));
|
||
}
|
||
|
||
if (next_door !== null) this.next_door_target = Date.now() + next_door;
|
||
} catch {
|
||
this.background_image = "error";
|
||
}
|
||
},
|
||
|
||
when_initialized(callback: () => void): void {
|
||
if (this.on_initialized === null) {
|
||
callback();
|
||
} else {
|
||
this.on_initialized.push(callback);
|
||
}
|
||
},
|
||
|
||
async update_is_admin(): Promise<boolean> {
|
||
this.is_admin = await API.request<boolean>("admin/is_admin");
|
||
return this.is_admin;
|
||
},
|
||
|
||
async login(creds: Credentials): Promise<boolean> {
|
||
API.creds = { username: creds[0], password: creds[1] };
|
||
return await this.update_is_admin();
|
||
},
|
||
|
||
logout() {
|
||
API.creds = { username: "", password: "" };
|
||
this.is_admin = false;
|
||
},
|
||
|
||
toggle_touch_device(): void {
|
||
this.is_touch_device = !this.is_touch_device;
|
||
},
|
||
},
|
||
});
|
||
|
||
if (import.meta.webpackHot) {
|
||
import.meta.webpackHot.accept(
|
||
acceptHMRUpdate(advent22Store, import.meta.webpackHot),
|
||
);
|
||
}
|