From 63e99885a45f1eb4a7ee234bde7a666c664f41b7 Mon Sep 17 00:00:00 2001 From: kritzl Date: Thu, 14 May 2026 15:58:12 +0200 Subject: [PATCH] update api, add loading states --- app/src/api/README.md | 2 +- app/src/api/schema.ts | 10 +++----- app/src/assets/main.ts | 55 ++++++++++++++++++++++++++++++++---------- app/src/i18n/ui.ts | 6 ++++- 4 files changed, 52 insertions(+), 21 deletions(-) diff --git a/app/src/api/README.md b/app/src/api/README.md index 7a882e1..256986b 100644 --- a/app/src/api/README.md +++ b/app/src/api/README.md @@ -1,3 +1,3 @@ # Update schema -`pnpm dlx openapi-typescript http://localhost:8000/openapi.json -o ./schema.d.ts` +`pnpm dlx openapi-typescript http://localhost:8000/openapi.json -o ./schema.ts` diff --git a/app/src/api/schema.ts b/app/src/api/schema.ts index a69f8d7..87104a6 100644 --- a/app/src/api/schema.ts +++ b/app/src/api/schema.ts @@ -132,18 +132,16 @@ export interface components { */ activity_state: "unknown" | "locking" | "unlocking" | "stable"; }; - /** UserInfo */ - UserInfo: { - /** Username */ - username: string; - }; /** UserStatus */ UserStatus: { /** Is Logged In */ is_logged_in: boolean; + /** Is Authorized */ + is_authorized: boolean; /** Guaranteed Session Until */ guaranteed_session_until: string | null; - user_info: components["schemas"]["UserInfo"] | null; + /** Username */ + username: string | null; }; /** ValidationError */ ValidationError: { diff --git a/app/src/assets/main.ts b/app/src/assets/main.ts index d107178..48bcd57 100644 --- a/app/src/assets/main.ts +++ b/app/src/assets/main.ts @@ -32,33 +32,45 @@ const auth: AuthType = { } const apiError: { - current: "serverError" | null; + current: "serverError" | "networkError" | null; } = { current: null, } +const loading: { + doors: boolean; + auth: boolean; +} = { + doors: false, + auth: false, +} + + const doors: Array = [] function loadAuthFromLocalStorage() { - const localAuth = JSON.parse(localStorage.getItem("auth") ?? "") - auth.recentLogout = localAuth.recentLogout // set recentLogout true, if user was logged in before - auth.authenticated = localAuth.authenticated - auth.authorized = localAuth.authorized - auth.until = localAuth.until ? new Date(localAuth.until) : null - auth.username = localAuth.username + if (localStorage.getItem("auth")) { + const localAuth = JSON.parse(localStorage.getItem("auth")!) + auth.recentLogout = localAuth.recentLogout // set recentLogout true, if user was logged in before + auth.authenticated = localAuth.authenticated + auth.authorized = localAuth.authorized + auth.until = localAuth.until ? new Date(localAuth.until) : null + auth.username = localAuth.username + } } async function checkUser() { + loading.auth = true const getUserInfo = fetcher.path("/api/user-info/").method("get").create() try { - const {status, data: userInfo} = await getUserInfo({}) + const {data: userInfo} = await getUserInfo({}) apiError.current = null auth.authenticated = userInfo.is_logged_in - auth.authorized = true + auth.authorized = userInfo.is_authorized auth.until = userInfo.guaranteed_session_until ? new Date(userInfo.guaranteed_session_until) : null - auth.username = userInfo.user_info?.username ?? "" + auth.username = userInfo.username ?? "" auth.recentLogout = false } catch (e) { // check which operation threw the exception @@ -80,15 +92,18 @@ async function checkUser() { } } finally { localStorage.setItem("auth", JSON.stringify(auth)) + loading.auth = false refresh() } } async function fetchDoors() { + loading.doors = true + refresh() const getDoors = fetcher.path("/api/locks/").method("get").create() try { - const {status, data: doorInfo} = await getDoors({}) + const {data: doorInfo} = await getDoors({}) apiError.current = null while (doors.length) { @@ -129,7 +144,15 @@ async function fetchDoors() { console.error("unknown error:", error) } } + + if (e instanceof Error) { + switch (e.name) { + case "TypeError": + apiError.current = "networkError" + } + } } finally { + loading.doors = false refresh() } } @@ -190,21 +213,27 @@ function refresh() { const alertUnauthorized: HTMLDivElement = document.querySelector("#alert-unauthorized")! const alertLoggedout: HTMLDivElement = document.querySelector("#alert-loggedout")! const alertServerError: HTMLDivElement = document.querySelector("#alert-serverError")! + const alertNetworkError: HTMLDivElement = document.querySelector("#alert-networkError")! const alertDivider: HTMLDivElement = document.querySelector("#alert-divider")! const badgeUsername: HTMLDivElement = document.querySelector("#badge-username")! const buttonLogin: HTMLDivElement = document.querySelector("#button-login")! const usernameElement: HTMLSpanElement = badgeUsername.querySelector("#username")! + const loadingDoors: HTMLDivElement = document.querySelector("#loading-doors")! - alertUnauthenticated.classList.toggle("hidden", auth.authenticated) + alertUnauthenticated.classList.toggle("hidden", auth.authenticated || auth.recentLogout) alertUnauthorized.classList.toggle("hidden", !auth.authenticated || auth.authorized) alertLoggedout.classList.toggle("hidden", !auth.recentLogout) alertServerError.classList.toggle("hidden", apiError.current !== "serverError") - alertDivider.classList.toggle("hidden", auth.authenticated && auth.authorized && !auth.recentLogout && apiError.current === null) + alertNetworkError.classList.toggle("hidden", apiError.current !== "networkError") + alertDivider.classList.toggle("hidden", auth.authenticated && auth.authorized && !auth.recentLogout && apiError.current === null || doors.length === 0) badgeUsername.classList.toggle("hidden", !auth.authenticated) usernameElement.innerHTML = auth.username buttonLogin.classList.toggle("hidden", auth.authenticated) + loadingDoors.classList.toggle("hidden", !loading.doors) } + + loadAuthFromLocalStorage() fetchDoors() checkUser() diff --git a/app/src/i18n/ui.ts b/app/src/i18n/ui.ts index a36c612..c6be0f4 100644 --- a/app/src/i18n/ui.ts +++ b/app/src/i18n/ui.ts @@ -28,8 +28,10 @@ export const ui = { "loggedOut.title": "Signed out", "loggedOut.description": `Your session has expired and you have been logged out.
Please log in again.`, - "serverError.title": "Server Error", + "serverError.title": "Server error", "serverError.description": `Please try again later.`, + "networkError.title": "Network error", + "networkError.description": `Please check your network connection.`, }, de: { "dooris": "TüRIS (DOORIS)", @@ -55,5 +57,7 @@ export const ui = { Melde dich erneut an.`, "serverError.title": "Serverfehler", "serverError.description": `Bitte versuche es später erneut.`, + "networkError.title": "Netzwerkfehler", + "networkError.description": `Bitte überprüfe deine Internetverbindung.`, }, } as const \ No newline at end of file