feat: Logging in multiple users, user selection
This commit is contained in:
@@ -15,6 +15,8 @@
|
|||||||
import { localSettings } from './lib/stores/localstorage.store';
|
import { localSettings } from './lib/stores/localstorage.store';
|
||||||
import { user } from './lib/stores/user.store';
|
import { user } from './lib/stores/user.store';
|
||||||
import { sessions } from './lib/stores/session.store';
|
import { sessions } from './lib/stores/session.store';
|
||||||
|
import SplashScreen from './lib/pages/SplashScreen.svelte';
|
||||||
|
import UsersPage from './lib/pages/UsersPage.svelte';
|
||||||
|
|
||||||
user.subscribe((s) => console.log('user', s));
|
user.subscribe((s) => console.log('user', s));
|
||||||
sessions.subscribe((s) => console.log('sessions', s));
|
sessions.subscribe((s) => console.log('sessions', s));
|
||||||
@@ -57,15 +59,9 @@
|
|||||||
<I18n />
|
<I18n />
|
||||||
<!--<Container class="w-full h-full overflow-auto text-white scrollbar-hide">-->
|
<!--<Container class="w-full h-full overflow-auto text-white scrollbar-hide">-->
|
||||||
{#if $user === undefined}
|
{#if $user === undefined}
|
||||||
<div class="h-full w-full flex flex-col items-center justify-center">
|
<SplashScreen />
|
||||||
<div class="flex items-center justify-center hover:text-inherit selectable rounded-sm mb-2">
|
|
||||||
<div class="rounded-full bg-amber-300 h-4 w-4 mr-2" />
|
|
||||||
<h1 class="font-display uppercase font-semibold tracking-wider text-xl">Reiverr</h1>
|
|
||||||
</div>
|
|
||||||
<div>Loading...</div>
|
|
||||||
</div>
|
|
||||||
{:else if $user === null}
|
{:else if $user === null}
|
||||||
<LoginPage />
|
<UsersPage />
|
||||||
{:else if $user.onboardingDone === false}
|
{:else if $user.onboardingDone === false}
|
||||||
<OnboardingPage />
|
<OnboardingPage />
|
||||||
{:else}
|
{:else}
|
||||||
@@ -92,10 +88,10 @@
|
|||||||
<StackRouter stack={stackRouter} />
|
<StackRouter stack={stackRouter} />
|
||||||
<!-- </Container>-->
|
<!-- </Container>-->
|
||||||
<!-- </Router>-->
|
<!-- </Router>-->
|
||||||
|
|
||||||
<ModalStack />
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
<ModalStack />
|
||||||
|
|
||||||
<NotificationStack />
|
<NotificationStack />
|
||||||
|
|
||||||
<NavigationDebugger />
|
<NavigationDebugger />
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ export class ReiverrApi implements Api<paths> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
isSetupDone = async (): Promise<boolean> =>
|
// isSetupDone = async (): Promise<boolean> =>
|
||||||
this.getClient()
|
// this.getClient()
|
||||||
?.GET('/user/isSetupDone')
|
// ?.GET('/user/isSetupDone')
|
||||||
.then((res) => res.data || false) || false;
|
// .then((res) => res.data || false) || false;
|
||||||
|
|
||||||
async getUser() {
|
async getUser() {
|
||||||
const res = await this.getClient()?.GET('/user', {});
|
const res = await this.getClient()?.GET('/user', {});
|
||||||
|
|||||||
9
src/lib/components/AddElementOverlay.svelte
Normal file
9
src/lib/components/AddElementOverlay.svelte
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { Plus } from 'radix-icons-svelte';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="absolute inset-0 bg-secondary-800/75 flex items-center justify-center">
|
||||||
|
<div class="rounded-full p-2.5 bg-secondary-800/75">
|
||||||
|
<Plus size={32} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
14
src/lib/components/Dialog/AddUserDialog.svelte
Normal file
14
src/lib/components/Dialog/AddUserDialog.svelte
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import Dialog from './Dialog.svelte';
|
||||||
|
import Login from '../Login.svelte';
|
||||||
|
import { navigate } from '../StackRouter/StackRouter.js';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Dialog let:close>
|
||||||
|
<Login
|
||||||
|
on:login={() => {
|
||||||
|
close();
|
||||||
|
navigate('/', { refresh: true });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Dialog>
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
$$restProps.class
|
$$restProps.class
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<slot />
|
<slot close={handleClose} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
64
src/lib/components/Login.svelte
Normal file
64
src/lib/components/Login.svelte
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import Container from '../../Container.svelte';
|
||||||
|
import TextField from '../components/TextField.svelte';
|
||||||
|
import Button from '../components/Button.svelte';
|
||||||
|
import { createLocalStorageStore } from '../stores/localstorage.store';
|
||||||
|
import { sessions } from '../stores/session.store';
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher<{ login: null }>();
|
||||||
|
|
||||||
|
const baseUrl = createLocalStorageStore('baseUrl', window.location.origin || '');
|
||||||
|
const name = createLocalStorageStore('username', '');
|
||||||
|
let password: string = '';
|
||||||
|
let error: string | undefined = undefined;
|
||||||
|
|
||||||
|
let loading = false;
|
||||||
|
|
||||||
|
function handleLogin() {
|
||||||
|
loading = true;
|
||||||
|
|
||||||
|
sessions
|
||||||
|
.addSession($baseUrl, $name, password)
|
||||||
|
.then((res) => {
|
||||||
|
console.log('res', res);
|
||||||
|
if (res?.request?.status === 401) {
|
||||||
|
error = 'Invalid credentials. Please try again.';
|
||||||
|
} else if (res?.request.status !== 200) {
|
||||||
|
error = 'Error occurred: ' + res.request.statusText;
|
||||||
|
} else {
|
||||||
|
dispatch('login');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err: Error) => {
|
||||||
|
error = err.name + ': ' + err.message;
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
loading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Container class="flex flex-col" focusOnMount>
|
||||||
|
<h1 class="header2 w-full mb-2">Login to Reiverr</h1>
|
||||||
|
<div class="header1 mb-4">
|
||||||
|
If this is your first time logging in, a new account will be created based on your credentials.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<TextField value={$baseUrl} on:change={(e) => baseUrl.set(e.detail)} class="mb-4 w-full">
|
||||||
|
Server
|
||||||
|
</TextField>
|
||||||
|
|
||||||
|
<TextField value={$name} on:change={({ detail }) => name.set(detail)} class="mb-4 w-full">
|
||||||
|
Name
|
||||||
|
</TextField>
|
||||||
|
<TextField bind:value={password} type="password" class="mb-8 w-full">Password</TextField>
|
||||||
|
|
||||||
|
<Button type="primary-dark" disabled={loading} on:clickOrSelect={handleLogin} class="mb-4 w-full"
|
||||||
|
>Submit</Button
|
||||||
|
>
|
||||||
|
|
||||||
|
{#if error}
|
||||||
|
<div class="text-red-300 text-center">{error}</div>
|
||||||
|
{/if}
|
||||||
|
</Container>
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { Plus, PlusCircled } from 'radix-icons-svelte';
|
import { Plus, PlusCircled } from 'radix-icons-svelte';
|
||||||
import { getCardDimensions } from '../../utils';
|
import { getCardDimensions } from '../../utils';
|
||||||
|
import AddElementOverlay from '../AddElementOverlay.svelte';
|
||||||
|
|
||||||
export let backdropUrl: string;
|
export let backdropUrl: string;
|
||||||
|
|
||||||
@@ -31,10 +32,6 @@
|
|||||||
class="bg-cover bg-center absolute inset-0"
|
class="bg-cover bg-center absolute inset-0"
|
||||||
style={`background-image: url('${backdropUrl}')`}
|
style={`background-image: url('${backdropUrl}')`}
|
||||||
/>
|
/>
|
||||||
<div class="absolute inset-0 bg-secondary-800/75 flex items-center justify-center">
|
<AddElementOverlay />
|
||||||
<div class="rounded-full p-2.5 bg-secondary-800/75">
|
|
||||||
<Plus size={32} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Container>
|
</Container>
|
||||||
</AnimateScale>
|
</AnimateScale>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { useTabs } from '../Tab/Tab';
|
import { useTabs } from '../Tab/Tab';
|
||||||
import { user } from '../../stores/user.store';
|
import { user } from '../../stores/user.store';
|
||||||
|
import { sessions } from '../../stores/session.store';
|
||||||
|
|
||||||
enum Tabs {
|
enum Tabs {
|
||||||
Users,
|
Users,
|
||||||
@@ -121,7 +122,7 @@
|
|||||||
|
|
||||||
<Container
|
<Container
|
||||||
class="w-full h-12 cursor-pointer"
|
class="w-full h-12 cursor-pointer"
|
||||||
on:clickOrSelect={selectIndex(Tabs.Users)}
|
on:clickOrSelect={() => sessions.setActiveSession()}
|
||||||
let:hasFocus
|
let:hasFocus
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -113,7 +113,14 @@ export function useStackRouter({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const navigate = (routeString: string, options: { replaceStack?: boolean } = {}) => {
|
const navigate = (
|
||||||
|
routeString: string,
|
||||||
|
options: { replaceStack?: boolean; refresh?: boolean } = {}
|
||||||
|
) => {
|
||||||
|
if (options.refresh) {
|
||||||
|
location.assign(routeString);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const page: Page = routeStringToRoute(routeString);
|
const page: Page = routeStringToRoute(routeString);
|
||||||
const replaceStack = page.route.root || options.replaceStack || false;
|
const replaceStack = page.route.root || options.replaceStack || false;
|
||||||
|
|
||||||
|
|||||||
@@ -1,65 +1,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Container from '../../Container.svelte';
|
import Login from '../components/Login.svelte';
|
||||||
import TextField from '../components/TextField.svelte';
|
|
||||||
import Button from '../components/Button.svelte';
|
|
||||||
import { createLocalStorageStore } from '../stores/localstorage.store';
|
|
||||||
|
|
||||||
import { sessions } from '../stores/session.store';
|
|
||||||
|
|
||||||
const baseUrl = createLocalStorageStore('baseUrl', window.location.origin || '');
|
|
||||||
const name = createLocalStorageStore('username', '');
|
|
||||||
let password: string = '';
|
|
||||||
let error: string | undefined = undefined;
|
|
||||||
|
|
||||||
let loading = false;
|
|
||||||
|
|
||||||
function handleLogin() {
|
|
||||||
loading = true;
|
|
||||||
|
|
||||||
sessions
|
|
||||||
.addSession($baseUrl, $name, password)
|
|
||||||
.then((res) => {
|
|
||||||
if (res.error?.statusCode === 401) {
|
|
||||||
error = 'Invalid credentials. Please try again.';
|
|
||||||
} else if (res.error) {
|
|
||||||
error = 'Error occurred: ' + res.error.message;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((err: Error) => {
|
|
||||||
error = err.name + ': ' + err.message;
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
loading = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="w-full h-full flex items-center justify-center">
|
<div class="w-full h-full flex items-center justify-center">
|
||||||
<Container class="flex flex-col bg-primary-800 rounded-2xl p-10 shadow-xl max-w-lg" focusOnMount>
|
<div class="bg-primary-800 rounded-2xl p-10 shadow-xl max-w-lg">
|
||||||
<h1 class="header2 w-full mb-2">Login to Reiverr</h1>
|
<Login />
|
||||||
<div class="header1 mb-4">
|
</div>
|
||||||
If this is your first time logging in, a new account will be created based on your
|
|
||||||
credentials.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<TextField value={$baseUrl} on:change={(e) => baseUrl.set(e.detail)} class="mb-4 w-full">
|
|
||||||
Server
|
|
||||||
</TextField>
|
|
||||||
|
|
||||||
<TextField value={$name} on:change={({ detail }) => name.set(detail)} class="mb-4 w-full">
|
|
||||||
Name
|
|
||||||
</TextField>
|
|
||||||
<TextField bind:value={password} type="password" class="mb-8 w-full">Password</TextField>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
type="primary-dark"
|
|
||||||
disabled={loading}
|
|
||||||
on:clickOrSelect={handleLogin}
|
|
||||||
class="mb-4 w-full">Submit</Button
|
|
||||||
>
|
|
||||||
|
|
||||||
{#if error}
|
|
||||||
<div class="text-red-300 text-center">{error}</div>
|
|
||||||
{/if}
|
|
||||||
</Container>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
7
src/lib/pages/SplashScreen.svelte
Normal file
7
src/lib/pages/SplashScreen.svelte
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<div class="h-full w-full flex flex-col items-center justify-center">
|
||||||
|
<div class="flex items-center justify-center hover:text-inherit selectable rounded-sm mb-2">
|
||||||
|
<div class="rounded-full bg-amber-300 h-4 w-4 mr-2" />
|
||||||
|
<h1 class="font-display uppercase font-semibold tracking-wider text-xl">Reiverr</h1>
|
||||||
|
</div>
|
||||||
|
<div>Loading...</div>
|
||||||
|
</div>
|
||||||
@@ -1,5 +1,93 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import DetachedPage from '../components/DetachedPage/DetachedPage.svelte';
|
import DetachedPage from '../components/DetachedPage/DetachedPage.svelte';
|
||||||
|
import { type Session, sessions } from '../stores/session.store.js';
|
||||||
|
import { reiverrApi } from '../apis/reiverr/reiverr-api';
|
||||||
|
import Container from '../../Container.svelte';
|
||||||
|
import Button from '../components/Button.svelte';
|
||||||
|
import { TMDB_PROFILE_LARGE } from '../constants';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import AnimateScale from '../components/AnimateScale.svelte';
|
||||||
|
import { navigate } from '../components/StackRouter/StackRouter';
|
||||||
|
import { createModal } from '../components/Modal/modal.store';
|
||||||
|
import AddUserDialog from '../components/Dialog/AddUserDialog.svelte';
|
||||||
|
import Login from '../components/Login.svelte';
|
||||||
|
import { Plus, Trash } from 'radix-icons-svelte';
|
||||||
|
import AddElementOverlay from '../components/AddElementOverlay.svelte';
|
||||||
|
|
||||||
|
$: users = getUsers($sessions.sessions);
|
||||||
|
|
||||||
|
async function getUsers(sessions: Session[]) {
|
||||||
|
return Promise.all(
|
||||||
|
sessions.map(async (session) =>
|
||||||
|
reiverrApi
|
||||||
|
.getClient(session.baseUrl, session.token)
|
||||||
|
.GET('/user')
|
||||||
|
.then((r) => ({ session, user: r.data }))
|
||||||
|
)
|
||||||
|
).then((us) => us.filter((u) => !!u.user));
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSwitchUser({ session, user }: Awaited<typeof users>[number]) {
|
||||||
|
sessions.setActiveSession(session);
|
||||||
|
navigate('/');
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<DetachedPage sidebar={false} class="px-32 py-16">Users Page</DetachedPage>
|
<DetachedPage sidebar={false} class="px-32 py-16 h-full flex flex-col items-center justify-center">
|
||||||
|
{#await users then users}
|
||||||
|
{#if users?.length}
|
||||||
|
<h1 class="header4 mb-16">Who is watching?</h1>
|
||||||
|
<Container direction="grid" gridCols={4} class="flex space-x-8 mb-16">
|
||||||
|
{#each users as item}
|
||||||
|
{@const user = item.user}
|
||||||
|
<Container let:hasFocus on:clickOrSelect={() => user && handleSwitchUser(item)}>
|
||||||
|
<AnimateScale {hasFocus}>
|
||||||
|
<div
|
||||||
|
class={classNames('w-40 h-40 bg-center bg-cover mb-4 rounded-xl', {
|
||||||
|
selected: hasFocus
|
||||||
|
})}
|
||||||
|
style={`background-image: url('${TMDB_PROFILE_LARGE}/wo2hJpn04vbtmh0B9utCFdsQhxM.jpg')`}
|
||||||
|
/>
|
||||||
|
<div class={classNames('text-center header1', { '!text-secondary-100': hasFocus })}>
|
||||||
|
{user?.name}
|
||||||
|
</div>
|
||||||
|
</AnimateScale>
|
||||||
|
</Container>
|
||||||
|
{/each}
|
||||||
|
<Container let:hasFocus on:clickOrSelect={() => createModal(AddUserDialog, {})}>
|
||||||
|
<AnimateScale {hasFocus}>
|
||||||
|
<div
|
||||||
|
class={classNames('relative overflow-hidden rounded-xl mb-4 w-40 h-40', {
|
||||||
|
selected: hasFocus
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class={`w-full h-full bg-center bg-cover`}
|
||||||
|
style={`background-image: url('${TMDB_PROFILE_LARGE}/wo2hJpn04vbtmh0B9utCFdsQhxM.jpg')`}
|
||||||
|
/>
|
||||||
|
<AddElementOverlay />
|
||||||
|
</div>
|
||||||
|
<!-- <div class={classNames('text-center header1', { '!text-secondary-100': hasFocus })}>-->
|
||||||
|
<!-- Add User-->
|
||||||
|
<!-- </div>-->
|
||||||
|
</AnimateScale>
|
||||||
|
</Container>
|
||||||
|
</Container>
|
||||||
|
<Container direction="horizontal" class="flex space-x-4">
|
||||||
|
<Button
|
||||||
|
on:clickOrSelect={() => {
|
||||||
|
sessions.removeSessions();
|
||||||
|
navigate('/');
|
||||||
|
}}
|
||||||
|
icon={Trash}
|
||||||
|
>
|
||||||
|
Remove all Accounts
|
||||||
|
</Button>
|
||||||
|
</Container>
|
||||||
|
{:else}
|
||||||
|
<div class="bg-primary-800 rounded-2xl p-10 shadow-xl max-w-lg">
|
||||||
|
<Login />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/await}
|
||||||
|
</DetachedPage>
|
||||||
|
|||||||
@@ -724,6 +724,8 @@ export class Selectable {
|
|||||||
this._addChildCount++;
|
this._addChildCount++;
|
||||||
// console.log('Incremented addChildCount to', this._addChildCount);
|
// console.log('Incremented addChildCount to', this._addChildCount);
|
||||||
if (focusIndex > 0) this.focusIndex.update((prev) => prev + 1); // TODO: Maybe needs fixing pt1
|
if (focusIndex > 0) this.focusIndex.update((prev) => prev + 1); // TODO: Maybe needs fixing pt1
|
||||||
|
} else if (this.children.length === 0 && get(this.hasFocus)) {
|
||||||
|
childToFocus = child;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._removedChildrenCount > 1) {
|
if (this._removedChildrenCount > 1) {
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import { createLocalStorageStore } from './localstorage.store';
|
import { createLocalStorageStore } from './localstorage.store';
|
||||||
import type { operations } from '../apis/reiverr/reiverr.generated';
|
import type { operations } from '../apis/reiverr/reiverr.generated';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import { get } from 'svelte/store';
|
||||||
|
|
||||||
export interface Session {
|
export interface Session {
|
||||||
|
id: string;
|
||||||
baseUrl: string;
|
baseUrl: string;
|
||||||
token: string;
|
token: string;
|
||||||
}
|
}
|
||||||
@@ -15,7 +17,7 @@ function useSessions() {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
function setActiveSession(session: Session) {
|
function setActiveSession(session?: Session) {
|
||||||
sessions.update((s) => ({ ...s, activeSession: session }));
|
sessions.update((s) => ({ ...s, activeSession: session }));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,12 +35,13 @@ function useSessions() {
|
|||||||
if (res.status !== 200) return res;
|
if (res.status !== 200) return res;
|
||||||
|
|
||||||
const session = {
|
const session = {
|
||||||
|
id: res.data.user.id,
|
||||||
baseUrl,
|
baseUrl,
|
||||||
token: res.data.accessToken
|
token: res.data.accessToken
|
||||||
};
|
};
|
||||||
|
|
||||||
sessions.update((s) => {
|
sessions.update((s) => {
|
||||||
const sessions = s.sessions.concat(session);
|
const sessions = s.sessions.filter((s) => s.id !== session.id).concat(session);
|
||||||
return {
|
return {
|
||||||
sessions,
|
sessions,
|
||||||
activeSession: activate ? session : s.activeSession
|
activeSession: activate ? session : s.activeSession
|
||||||
@@ -59,11 +62,16 @@ function useSessions() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function removeSessions() {
|
||||||
|
sessions.set({ sessions: [] });
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
subscribe: sessions.subscribe,
|
subscribe: sessions.subscribe,
|
||||||
setActiveSession,
|
setActiveSession,
|
||||||
addSession,
|
addSession,
|
||||||
removeSession
|
removeSession,
|
||||||
|
removeSessions
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ function useUser() {
|
|||||||
Authorization: 'Bearer ' + activeSession.token
|
Authorization: 'Bearer ' + activeSession.token
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then((r) => r.data);
|
.then((r) => r.data)
|
||||||
|
.catch(() => null);
|
||||||
|
|
||||||
if (lastActiveSession === activeSession) userStore.set(user);
|
if (lastActiveSession === activeSession) userStore.set(user);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user