Files
tranquil-pds/frontend/src/App.svelte
T

214 lines
6.0 KiB
Svelte

<script lang="ts">
import { getCurrentPath, navigate } from './lib/router.svelte'
import { initAuth, getAuthState } from './lib/auth.svelte'
import { initServerConfig } from './lib/serverConfig.svelte'
import { initI18n } from './lib/i18n'
import { isLoading as i18nLoading } from 'svelte-i18n'
import Toast from './components/Toast.svelte'
import Login from './routes/Login.svelte'
import RegisterSso from './routes/RegisterSso.svelte'
import Verify from './routes/Verify.svelte'
import ResetPassword from './routes/ResetPassword.svelte'
import RecoverPasskey from './routes/RecoverPasskey.svelte'
import RequestPasskeyRecovery from './routes/RequestPasskeyRecovery.svelte'
import Dashboard from './routes/Dashboard.svelte'
import AppPasswords from './routes/AppPasswords.svelte'
import InviteCodes from './routes/InviteCodes.svelte'
import Settings from './routes/Settings.svelte'
import Sessions from './routes/Sessions.svelte'
import Comms from './routes/Comms.svelte'
import RepoExplorer from './routes/RepoExplorer.svelte'
import Admin from './routes/Admin.svelte'
import OAuthConsent from './routes/OAuthConsent.svelte'
import OAuthLogin from './routes/OAuthLogin.svelte'
import OAuthAccounts from './routes/OAuthAccounts.svelte'
import OAuth2FA from './routes/OAuth2FA.svelte'
import OAuthTotp from './routes/OAuthTotp.svelte'
import OAuthPasskey from './routes/OAuthPasskey.svelte'
import OAuthDelegation from './routes/OAuthDelegation.svelte'
import OAuthError from './routes/OAuthError.svelte'
import SsoRegisterComplete from './routes/SsoRegisterComplete.svelte'
import Register from './routes/Register.svelte'
import RegisterPassword from './routes/RegisterPassword.svelte'
import Security from './routes/Security.svelte'
import TrustedDevices from './routes/TrustedDevices.svelte'
import Controllers from './routes/Controllers.svelte'
import DelegationAudit from './routes/DelegationAudit.svelte'
import ActAs from './routes/ActAs.svelte'
import Migration from './routes/Migration.svelte'
import DidDocumentEditor from './routes/DidDocumentEditor.svelte'
import { _ } from './lib/i18n'
initI18n()
const auth = $derived(getAuthState())
let oauthCallbackPending = $state(hasOAuthCallback())
let showSpinner = $state(false)
let loadingTimer: ReturnType<typeof setTimeout> | null = null
function hasOAuthCallback(): boolean {
if (window.location.pathname === '/app/migrate') {
return false
}
const params = new URLSearchParams(window.location.search)
return !!(params.get('code') && params.get('state'))
}
$effect(() => {
loadingTimer = setTimeout(() => {
showSpinner = true
}, 5000)
initServerConfig()
initAuth().then(({ oauthLoginCompleted }) => {
if (oauthLoginCompleted) {
navigate('/dashboard', { replace: true })
}
oauthCallbackPending = false
if (loadingTimer) {
clearTimeout(loadingTimer)
loadingTimer = null
}
})
return () => {
if (loadingTimer) {
clearTimeout(loadingTimer)
}
}
})
const isLoading = $derived(
auth.kind === 'loading' || $i18nLoading || oauthCallbackPending
)
$effect(() => {
if (auth.kind === 'loading') return
const path = getCurrentPath()
if (path === '/') {
if (auth.kind === 'authenticated') {
navigate('/dashboard', { replace: true })
} else {
navigate('/login', { replace: true })
}
}
})
function getComponent(path: string) {
switch (path) {
case '/login':
return Login
case '/verify':
return Verify
case '/reset-password':
return ResetPassword
case '/recover-passkey':
return RecoverPasskey
case '/request-passkey-recovery':
return RequestPasskeyRecovery
case '/dashboard':
return Dashboard
case '/app-passwords':
return AppPasswords
case '/invite-codes':
return InviteCodes
case '/settings':
return Settings
case '/sessions':
return Sessions
case '/comms':
return Comms
case '/repo':
return RepoExplorer
case '/admin':
return Admin
case '/oauth/consent':
return OAuthConsent
case '/oauth/login':
return OAuthLogin
case '/oauth/accounts':
return OAuthAccounts
case '/oauth/2fa':
return OAuth2FA
case '/oauth/totp':
return OAuthTotp
case '/oauth/passkey':
return OAuthPasskey
case '/oauth/delegation':
return OAuthDelegation
case '/oauth/error':
return OAuthError
case '/oauth/sso-register':
return SsoRegisterComplete
case '/register':
case '/oauth/register':
return Register
case '/oauth/register-sso':
return RegisterSso
case '/oauth/register-password':
return RegisterPassword
case '/security':
return Security
case '/trusted-devices':
return TrustedDevices
case '/controllers':
return Controllers
case '/delegation-audit':
return DelegationAudit
case '/act-as':
return ActAs
case '/migrate':
return Migration
case '/did-document':
return DidDocumentEditor
default:
return Login
}
}
let currentPath = $derived(getCurrentPath())
let CurrentComponent = $derived(getComponent(currentPath))
</script>
<main>
{#if isLoading}
<div class="loading">
{#if showSpinner}
<div class="loading-content">
<div class="spinner"></div>
<p>{$_('common.loading')}</p>
</div>
{/if}
</div>
{:else}
<CurrentComponent />
{/if}
</main>
<Toast />
<style>
main {
min-height: 100vh;
}
.loading {
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.loading-content {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--space-4);
}
.loading-content p {
margin: 0;
color: var(--text-secondary);
}
</style>