Files
Anitrack/frontend/src/helperComponents/Header.svelte
T
john-okeefe a16c804692 feat(ui): show per-service login status while accounts are being checked
When the app starts it verifies all three services sequentially, which
could leave the other two login controls looking idle or trigger login
actions before their real state is known. Track which service is
currently being checked and reflect it in the header:

- Add a serviceLoggingIn store (plus setServiceLoggingIn and
  isServiceLoggingIn helpers) to GlobalVariablesAndHelperFunctions.
- Have the loginTo* functions and the startup CheckIf* functions toggle
  their service in the store (seed all three at startup, clear each as
  it resolves).
- In Header, the login buttons show a spinner with 'Checking AniList' /
  'Checking MAL' / 'Checking Simkl' and are disabled while that service
  is being checked, reverting to the normal 'AniList Login' style label
  once its state is known.
- In the avatar menu, the 'Login to X' row shows a spinner with the
  matching 'Checking X' text while that service is logging in.
2026-08-29 13:13:42 -04:00

134 lines
5.5 KiB
Svelte

<script lang="ts">
import Search from "./Search.svelte";
import {
aniListLoggedIn,
loginToAniList,
loginToMAL,
loginToSimkl,
malLoggedIn,
simklLoggedIn,
serviceLoggingIn,
} from "../helperModules/GlobalVariablesAndHelperFunctions.svelte";
import AvatarMenu from "./AvatarMenu.svelte";
import logo from "../assets/images/AniTrackLogo.svg";
import { link } from "svelte-spa-router";
let isAniListLoggedIn: boolean;
let isSimklLoggedIn: boolean;
let isMALLoggedIn: boolean;
let loggingIn: string[] = [];
aniListLoggedIn.subscribe((value) => (isAniListLoggedIn = value));
simklLoggedIn.subscribe((value) => (isSimklLoggedIn = value));
malLoggedIn.subscribe((value) => (isMALLoggedIn = value));
serviceLoggingIn.subscribe((value) => (loggingIn = value));
</script>
<nav class="border-gray-200 bg-gray-900">
<div
class="max-w-screen-xl flex flex-wrap items-center justify-between mx-auto p-4"
>
<div class="flex items-center space-x-3 rtl:space-x-reverse">
<a href="/" use:link
><img src={logo} class="h-8" alt="AniTrack Logo" /></a
>
</div>
<div
class="flex items-center min-[950px]:order-2 space-x-3 min-[950px]:space-x-0 rtl:space-x-reverse"
>
<div class="min-[950px]:block min-[950px]:mr-4">
<Search />
</div>
<AvatarMenu />
<button
on:click={() => {
let menu = document.querySelector("#navbar-user");
menu.classList.toggle("hidden");
}}
type="button"
class="inline-flex items-center p-2 w-10 h-10 justify-center text-sm rounded-lg min-[950px]:hidden focus:outline-none focus:ring-2 text-gray-400 hover:bg-gray-700 focus:ring-gray-600"
aria-controls="navbar-user"
aria-expanded="false"
>
<span class="sr-only">Open main menu</span>
<svg
class="w-5 h-5"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 17 14"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M1 1h15M1 7h15M1 13h15"
/>
</svg>
</button>
</div>
<div
class="hidden items-center justify-between w-full pb-4 min-[950px]:pb-0 min-[950px]:flex min-[950px]:w-auto min-[950px]:order-1 border border-gray-700 min-[950px]:border-0 bg-gray-800 min-[950px]:bg-transparent rounded-lg"
id="navbar-user"
>
<ul
class="flex flex-col font-medium pb-6 min-[950px]:p-0 mt-4 min-[950px]:space-x-8 rtl:space-x-reverse min-[950px]:flex-row min-[950px]:mt-0"
>
<li>
{#if !isAniListLoggedIn}
<button
disabled={loggingIn.includes("anilist")}
on:click={loginToAniList}
>
{#if loggingIn.includes("anilist")}
<span
class="inline-block w-4 h-4 mr-2 border-2 border-gray-300 border-t-transparent rounded-full animate-spin align-middle"
></span
>Checking AniList
{:else}
AniList Login
{/if}
</button>
{/if}
{#if !isMALLoggedIn}
<button
disabled={loggingIn.includes("mal")}
on:click={loginToMAL}
>
{#if loggingIn.includes("mal")}
<span
class="inline-block w-4 h-4 mr-2 border-2 border-gray-300 border-t-transparent rounded-full animate-spin align-middle"
></span
>Checking MAL
{:else}
MyAnimeList Login
{/if}
</button>
{/if}
</li>
<li>
{#if !isSimklLoggedIn}
<button
disabled={loggingIn.includes("simkl")}
on:click={loginToSimkl}
>
{#if loggingIn.includes("simkl")}
<span
class="inline-block w-4 h-4 mr-2 border-2 border-gray-300 border-t-transparent rounded-full animate-spin align-middle"
></span
>Checking Simkl
{:else}
Simkl Login
{/if}
</button>
{/if}
</li>
</ul>
<div class="flex justify-center min-[950px]:hidden">
<Search />
</div>
</div>
</div>
</nav>