This commit is contained in:
13
src/routes/account/+page.server.ts
Normal file
13
src/routes/account/+page.server.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { auth, authProviders } from '$lib/server/auth';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import type { PageServerLoad } from './$types';
|
||||
export const load: PageServerLoad = async ({ locals, request, url }) => {
|
||||
if (!locals.user) redirect(303, '/login?returnTo=/account');
|
||||
const accounts = await auth.api.listUserAccounts({ headers: request.headers });
|
||||
return {
|
||||
email: locals.user.email.endsWith('@osu.invalid') ? null : locals.user.email,
|
||||
providers: authProviders,
|
||||
linkedProviders: accounts.map((account) => account.providerId),
|
||||
oauthError: url.searchParams.has('error')
|
||||
};
|
||||
};
|
||||
72
src/routes/account/+page.svelte
Normal file
72
src/routes/account/+page.svelte
Normal file
@@ -0,0 +1,72 @@
|
||||
<script lang="ts">
|
||||
import { resolve } from '$app/paths';
|
||||
import { authClient } from '$lib/auth-client';
|
||||
import type { PageProps } from './$types';
|
||||
let { data }: PageProps = $props();
|
||||
let busy = $state(false);
|
||||
let message = $state('');
|
||||
async function link(provider: 'google' | 'osu') {
|
||||
busy = true;
|
||||
message = '';
|
||||
try {
|
||||
const result = await authClient.linkSocial({
|
||||
provider,
|
||||
callbackURL: '/account',
|
||||
errorCallbackURL: '/account'
|
||||
});
|
||||
if (result.error) {
|
||||
message = result.error.message || 'Could not link this account.';
|
||||
busy = false;
|
||||
}
|
||||
} catch {
|
||||
message = 'Could not connect. Please try again.';
|
||||
busy = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<section class="mx-auto max-w-xl p-6 space-y-6">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold">Your account</h1>
|
||||
<p class="mt-2">Signed in as {data.user?.name}{data.email ? ` (${data.email})` : ''}.</p>
|
||||
</div>
|
||||
<p class="text-sm text-gray-500">Account ID: <code>{data.user?.id}</code></p>
|
||||
|
||||
<div class="rounded border p-4 space-y-3">
|
||||
<h2 class="font-bold">Sign-in methods</h2>
|
||||
<p class="text-sm text-gray-600">
|
||||
Link a provider here to use it with this account and keep your saved progress together.
|
||||
</p>
|
||||
{#if message || data.oauthError}<p role="alert" class="text-red-700">
|
||||
{message ||
|
||||
'Linking failed or was cancelled. The provider may already belong to another account.'}
|
||||
</p>{/if}
|
||||
{#if data.linkedProviders.includes('credential')}<p>Email and password connected</p>{/if}
|
||||
{#each ['google', 'osu'] as provider (provider)}
|
||||
{@const label = provider === 'google' ? 'Google' : 'osu!'}
|
||||
{#if data.linkedProviders.includes(provider)}<p>{label} connected</p>
|
||||
{:else if data.providers[provider as 'google' | 'osu']}<button
|
||||
class="block rounded border px-4 py-2 disabled:opacity-50"
|
||||
disabled={busy}
|
||||
onclick={() => link(provider as 'google' | 'osu')}>Connect {label}</button
|
||||
>{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{#if data.isAdmin}
|
||||
<div class="rounded border p-4 space-y-3">
|
||||
<h2 class="font-bold">Administration</h2>
|
||||
<div class="flex flex-wrap gap-4">
|
||||
<a class="underline" href={resolve('/blog')}>Blog articles</a><a
|
||||
class="underline"
|
||||
href={resolve('/lists')}>Lists</a
|
||||
><a class="underline" href={resolve('/projects/animaldex/admin')}>Animaldex moderation</a><a
|
||||
class="underline"
|
||||
href={resolve('/projects/progress')}>Progress</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<form method="POST" action="/logout">
|
||||
<button class="rounded border px-4 py-2">Log out</button>
|
||||
</form>
|
||||
</section>
|
||||
Reference in New Issue
Block a user