diff --git a/src/App.svelte b/src/App.svelte index f9ed69b..3e960ef 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -10,21 +10,20 @@ import SearchPage from './lib/pages/SearchPage.svelte'; import SeriesPage from './lib/pages/SeriesPage.svelte'; import Sidebar from './lib/components/Sidebar/Sidebar.svelte'; - import { userStore } from './lib/stores/user.store'; import LoginPage from './lib/pages/LoginPage.svelte'; - import { reiverrApi } from './lib/apis/reiverr/reiverrApi'; + import { getReiverrApiClient } from './lib/apis/reiverr/reiverr-api'; + import { appState } from './lib/stores/app-state.store'; - reiverrApi - .getApi() + getReiverrApiClient() .GET('/user', {}) .then((res) => res.data) - .then((user) => userStore.set(user || null)) - .catch(() => userStore.set(null)); + .then((user) => appState.setUser(user || null)) + .catch(() => appState.setUser(null)); - {#if $userStore === undefined} + {#if $appState.user === undefined} @@ -32,7 +31,7 @@ Loading... - {:else if $userStore === null} + {:else if $appState.user === null} {:else} diff --git a/src/lib/apis/reiverr/reiverr-api.ts b/src/lib/apis/reiverr/reiverr-api.ts new file mode 100644 index 0000000..06ff9ec --- /dev/null +++ b/src/lib/apis/reiverr/reiverr-api.ts @@ -0,0 +1,25 @@ +import createClient from 'openapi-fetch'; +import type { paths } from './reiverr.generated'; +import { get } from 'svelte/store'; +import { appState } from '../../stores/app-state.store'; + +interface ApiInterface> { + getClient(): ReturnType>; +} +export class ReiverrApi implements ApiInterface { + getClient(basePath?: string) { + const token = get(appState).token; + + return createClient({ + baseUrl: (basePath || get(appState).serverBaseUrl) + '/api', + ...(token && { + headers: { + Authorization: 'Bearer ' + token + } + }) + }); + } +} + +export const reiverrApi = new ReiverrApi(); +export const getReiverrApiClient = reiverrApi.getClient; diff --git a/src/lib/apis/reiverr/reiverrApi.ts b/src/lib/apis/reiverr/reiverrApi.ts deleted file mode 100644 index 4ecfa47..0000000 --- a/src/lib/apis/reiverr/reiverrApi.ts +++ /dev/null @@ -1,29 +0,0 @@ -import createClient from 'openapi-fetch'; -import type { paths } from './reiverr.generated'; -import { Api } from '../api.interface'; -import { authenticationToken } from '../../stores/localstorage.store'; -import { get } from 'svelte/store'; - -class ReiverrApi> extends Api { - protected baseUrl: string; - protected client: ReturnType>; - protected isLoggedIn = false; - - constructor(baseUrl: string) { - super(); - this.baseUrl = baseUrl; - - const token = get(authenticationToken); - - this.client = createClient({ - baseUrl: this.baseUrl, - ...(token && { - headers: { - Authorization: 'Bearer ' + token - } - }) - }); - } -} - -export const reiverrApi = new ReiverrApi('http://localhost:3000/api'); diff --git a/src/lib/components/HeroShowcase/HeroShowcase.svelte b/src/lib/components/HeroShowcase/HeroShowcase.svelte index 3ae1e27..a56a810 100644 --- a/src/lib/components/HeroShowcase/HeroShowcase.svelte +++ b/src/lib/components/HeroShowcase/HeroShowcase.svelte @@ -13,7 +13,7 @@ export let items: Promise = Promise.resolve([]); - let showcaseIndex = 6; + let showcaseIndex = 0; let showcaseLength = 0; $: items.then((i) => (showcaseLength = i?.length || 0)); diff --git a/src/lib/pages/LoginPage.svelte b/src/lib/pages/LoginPage.svelte index 142efca..a8a7982 100644 --- a/src/lib/pages/LoginPage.svelte +++ b/src/lib/pages/LoginPage.svelte @@ -1,14 +1,18 @@ - + {#if error} {error} {/if} - Name: + Server: + input0?.focus()}> + appState.setBaseUrl(e?.target?.value)} + bind:this={input0} + /> + - Password: + Name: + input1?.focus()}> + + - Submit - + + + Password: + input2?.focus()}> + + + + Submit + diff --git a/src/lib/pages/ManagePage.svelte b/src/lib/pages/ManagePage.svelte index 40c7d39..d96bc01 100644 --- a/src/lib/pages/ManagePage.svelte +++ b/src/lib/pages/ManagePage.svelte @@ -1,5 +1,17 @@ - - -ManagePage + + + + Log Out + diff --git a/src/lib/selectable.ts b/src/lib/selectable.ts index e1263ed..bc39aef 100644 --- a/src/lib/selectable.ts +++ b/src/lib/selectable.ts @@ -84,20 +84,20 @@ export class Selectable { const focusIndex = get(this.focusIndex); if (this.children[focusIndex]?.isFocusable()) { - this.children[focusIndex].focus(); + this.children[focusIndex]?.focus(); } else { let i = focusIndex; while (i < this.children.length) { - if (this.children[i].isFocusable()) { - this.children[i].focus(); + if (this.children[i]?.isFocusable()) { + this.children[i]?.focus(); return; } i++; } i = focusIndex - 1; while (i >= 0) { - if (this.children[i].isFocusable()) { - this.children[i].focus(); + if (this.children[i]?.isFocusable()) { + this.children[i]?.focus(); return; } i--; @@ -163,7 +163,7 @@ export class Selectable { if (direction === 'up' || direction === 'left') { let index = focusIndex - 1; while (index >= 0) { - if (this.children[index].isFocusable()) { + if (this.children[index]?.isFocusable()) { return this.children[index]; } index--; @@ -171,7 +171,7 @@ export class Selectable { } else if (direction === 'down' || direction === 'right') { let index = focusIndex + 1; while (index < this.children.length) { - if (this.children[index].isFocusable()) { + if (this.children[index]?.isFocusable()) { return this.children[index]; } index++; diff --git a/src/lib/stores/app-state.store.ts b/src/lib/stores/app-state.store.ts new file mode 100644 index 0000000..fabe2cf --- /dev/null +++ b/src/lib/stores/app-state.store.ts @@ -0,0 +1,50 @@ +import { derived, writable } from 'svelte/store'; +import type { components } from '../apis/reiverr/reiverr.generated'; +import { createLocalStorageStore } from './localstorage.store'; + +export type User = components['schemas']['UserDto']; + +interface AuthenticationStoreData { + token?: string; + serverBaseUrl?: string; +} + +function createAppState() { + const userStore = writable(undefined); + const authenticationStore = createLocalStorageStore( + 'authentication-token', + { + token: undefined, + serverBaseUrl: window?.location?.origin + } + ); + const combinedStore = derived([userStore, authenticationStore], ([$user, $auth]) => { + return { + user: $user, + token: $auth.token, + serverBaseUrl: $auth.serverBaseUrl + }; + }); + + function setBaseUrl(serverBaseUrl: string | undefined = undefined) { + authenticationStore.update((p) => ({ ...p, serverBaseUrl })); + } + + function setToken(token: string | undefined = undefined) { + authenticationStore.update((p) => ({ ...p, token })); + } + + function setUser(user: User | null) { + userStore.set(user); + } + + return { + subscribe: combinedStore.subscribe, + setBaseUrl, + setToken, + setUser + }; +} + +export const appState = createAppState(); +export const appStateUser = derived(appState, ($state) => $state.user); diff --git a/src/lib/stores/localstorage.store.ts b/src/lib/stores/localstorage.store.ts index dc8a39c..5c2ea9f 100644 --- a/src/lib/stores/localstorage.store.ts +++ b/src/lib/stores/localstorage.store.ts @@ -1,4 +1,4 @@ -import { writable } from 'svelte/store'; +import { get, writable } from 'svelte/store'; export function createLocalStorageStore(key: string, defaultValue: T) { const store = writable(JSON.parse(localStorage.getItem(key) || 'null') || defaultValue); @@ -8,12 +8,17 @@ export function createLocalStorageStore(key: string, defaultValue: T) { set: (value: T) => { localStorage.setItem(key, JSON.stringify(value)); store.set(value); + }, + update: (updater: (value: T) => T) => { + const newValue = updater(get(store)); + localStorage.setItem(key, JSON.stringify(newValue)); + store.set(newValue); + }, + remove: () => { + localStorage.removeItem(key); + store.set(defaultValue); } }; } export const skippedVersion = createLocalStorageStore('skipped-version', null); -export const authenticationToken = createLocalStorageStore( - 'authentication-token', - null -); diff --git a/src/lib/stores/user.store.ts b/src/lib/stores/user.store.ts deleted file mode 100644 index ba7bb44..0000000 --- a/src/lib/stores/user.store.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { writable } from 'svelte/store'; -import type { components } from '../apis/reiverr/reiverr.generated'; - -export type User = components['schemas']['UserDto']; - -export const userStore = writable(undefined);