advent22/ui/src/lib/store.ts

158 lines
4.2 KiB
TypeScript
Raw Normal View History

import { acceptHMRUpdate, defineStore } from "pinia";
2024-08-23 16:38:04 +00:00
import { API } from "./api";
import { Credentials, DoorSaved, SiteConfigModel } from "./model";
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 = {
on_initialized: (() => void)[];
2023-11-09 23:08:35 +00:00
is_touch_device: boolean;
is_admin: boolean;
site_config: SiteConfigModel;
calendar_background_image: string | undefined;
2023-11-09 23:08:35 +00:00
calendar_aspect_ratio: number;
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,
site_config: {
title: document.title,
subtitle: "",
2023-11-03 14:40:44 +00:00
content: "",
footer: "",
2023-11-09 23:08:35 +00:00
},
calendar_background_image: undefined,
2023-11-05 22:36:58 +00:00
calendar_aspect_ratio: 1,
2023-11-09 23:08:35 +00:00
user_doors: [],
next_door_target: null,
2023-11-03 14:40:44 +00:00
}),
actions: {
2023-11-09 23:08:35 +00:00
init(): void {
2024-08-23 16:38:04 +00:00
this.update().then(() => this.on_initialized.forEach((fn) => fn()));
2023-11-03 14:40:44 +00:00
},
2023-11-24 11:57:33 +00:00
update(): Promise<void> {
return new Promise((resolve, reject) => {
2024-08-23 16:38:04 +00:00
API.request("user/favicon");
2023-11-24 11:57:33 +00:00
this.advent22
.api_get_blob("user/favicon")
.then((favicon_src) => {
const link: HTMLLinkElement =
document.querySelector("link[rel*='icon']") ||
document.createElement("link");
link.rel = "shortcut icon";
link.type = "image/x-icon";
link.href = favicon_src;
if (link.parentElement === null)
document.getElementsByTagName("head")[0].appendChild(link);
})
.catch(() => {});
Promise.all([
this.update_is_admin(),
this.advent22.api_get<SiteConfigModel>("user/site_config"),
this.advent22.api_get_blob("user/background_image"),
this.advent22.api_get<DoorSaved[]>("user/doors"),
this.advent22.api_get<number | null>("user/next_door"),
])
.then(
([
is_admin,
site_config,
background_image,
user_doors,
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.calendar_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;
resolve();
},
)
.catch(reject);
});
},
when_initialized(callback: () => void): void {
if (this.is_initialized) {
callback();
} else {
this.on_initialized.push(callback);
}
},
update_is_admin(): Promise<boolean> {
2023-11-09 23:08:35 +00:00
return new Promise((resolve, reject) => {
2023-11-04 15:58:31 +00:00
this.advent22
.api_get<boolean>("admin/is_admin")
2023-11-02 00:37:00 +00:00
.then((is_admin) => {
this.is_admin = is_admin;
resolve(is_admin);
})
.catch(reject);
});
},
login(creds: Credentials): Promise<boolean> {
2024-08-23 16:38:04 +00:00
API.creds = { username: creds[0], password: creds[1] };
return this.update_is_admin();
},
2023-11-02 00:37:00 +00:00
logout(): Promise<boolean> {
2023-11-05 21:57:50 +00:00
return this.login(["", ""]);
},
toggle_touch_device(): void {
this.is_touch_device = !this.is_touch_device;
},
2023-11-05 22:36:58 +00:00
set_calendar_aspect_ratio(rect: DOMRectReadOnly): void {
const result = rect.width / rect.height;
// filter suspicious results
if (result !== 0 && isFinite(result) && !isNaN(result))
this.calendar_aspect_ratio = result;
},
},
});
if (import.meta.webpackHot) {
import.meta.webpackHot.accept(
acceptHMRUpdate(advent22Store, import.meta.webpackHot),
);
}