advent22/ui/src/lib/store.ts

133 lines
3.5 KiB
TypeScript
Raw Normal View History

import { acceptHMRUpdate, defineStore } from "pinia";
2024-08-23 16:38:04 +00:00
import { API } from "./api";
2024-08-23 18:59:11 +00:00
import { Loading } from "./helpers";
2024-08-23 18:21:32 +00:00
import { Credentials, DoorSaved, ImageData, SiteConfigModel } from "./model";
2024-08-23 16:38:04 +00:00
import { Door } from "./rects/door";
2023-11-05 21:57:50 +00:00
declare global {
interface Navigator {
readonly msMaxTouchPoints: number;
}
}
2023-11-09 23:08:35 +00:00
type State = {
2024-08-23 18:59:11 +00:00
on_initialized: (() => void)[] | null;
2023-11-09 23:08:35 +00:00
is_touch_device: boolean;
is_admin: boolean;
2024-08-23 18:59:11 +00:00
site_config: SiteConfigModel;
2024-08-23 18:21:32 +00:00
background_image: Loading<ImageData>;
2023-11-09 23:14:19 +00:00
user_doors: Door[];
2023-11-09 23:08:35 +00:00
next_door_target: number | null;
};
export const advent22Store = defineStore({
id: "advent22",
2023-11-09 23:08:35 +00:00
state: (): State => ({
on_initialized: [],
2023-11-05 21:57:50 +00:00
is_touch_device:
window.matchMedia("(any-hover: none)").matches ||
"ontouchstart" in window ||
navigator.maxTouchPoints > 0 ||
navigator.msMaxTouchPoints > 0,
2023-11-03 14:40:44 +00:00
is_admin: false,
2024-08-23 18:59:11 +00:00
site_config: {
title: document.title,
subtitle: "",
content: "",
footer: "",
},
2024-08-23 18:21:32 +00:00
background_image: "loading",
2023-11-09 23:08:35 +00:00
user_doors: [],
next_door_target: null,
2023-11-03 14:40:44 +00:00
}),
actions: {
2024-08-23 18:59:11 +00:00
async init(): Promise<void> {
await this.update();
if (this.on_initialized !== null) {
for (const callback of this.on_initialized) callback();
}
this.on_initialized = null;
2023-11-03 14:40:44 +00:00
},
2024-08-23 18:21:32 +00:00
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 {}
2024-08-26 19:13:08 +00:00
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"),
]);
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";
2024-08-23 18:21:32 +00:00
}
2023-11-24 11:57:33 +00:00
},
when_initialized(callback: () => void): void {
2024-08-23 18:59:11 +00:00
if (this.on_initialized === null) {
callback();
} else {
this.on_initialized.push(callback);
}
},
2024-08-23 18:21:32 +00:00
async update_is_admin(): Promise<boolean> {
this.is_admin = await API.request<boolean>("admin/is_admin");
return this.is_admin;
2023-11-02 00:37:00 +00:00
},
2025-12-28 16:35:10 +00:00
async login(creds: Credentials): Promise<boolean> {
2024-08-23 16:38:04 +00:00
API.creds = { username: creds[0], password: creds[1] };
2025-12-28 16:35:10 +00:00
return await this.update_is_admin();
},
2025-12-28 16:35:10 +00:00
logout() {
2023-11-05 21:57:50 +00:00
return this.login(["", ""]);
},
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),
);
}