import { acceptHMRUpdate, defineStore } from "pinia"; import { API } from "./api"; import { Credentials, DoorSaved, SiteConfigModel } from "./model"; import { Door } from "./rects/door"; declare global { interface Navigator { readonly msMaxTouchPoints: number; } } type State = { on_initialized: (() => void)[]; is_touch_device: boolean; is_admin: boolean; site_config: SiteConfigModel; calendar_background_image: string | undefined; calendar_aspect_ratio: number; 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: "", }, calendar_background_image: undefined, calendar_aspect_ratio: 1, user_doors: [], next_door_target: null, }), actions: { init(): void { this.update().then(() => this.on_initialized.forEach((fn) => fn())); }, update(): Promise { return new Promise((resolve, reject) => { API.request("user/favicon"); 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("user/site_config"), this.advent22.api_get_blob("user/background_image"), this.advent22.api_get("user/doors"), this.advent22.api_get("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 { return new Promise((resolve, reject) => { this.advent22 .api_get("admin/is_admin") .then((is_admin) => { this.is_admin = is_admin; resolve(is_admin); }) .catch(reject); }); }, login(creds: Credentials): Promise { API.creds = { username: creds[0], password: creds[1] }; return this.update_is_admin(); }, logout(): Promise { return this.login(["", ""]); }, toggle_touch_device(): void { this.is_touch_device = !this.is_touch_device; }, 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), ); }