feat(#29): use magic link to sign in

This commit is contained in:
OllyNicholass
2024-09-17 21:14:39 +01:00
parent 32a3feef64
commit 6e1d38ef58
7 changed files with 65 additions and 39 deletions
+19
View File
@@ -0,0 +1,19 @@
<script lang="ts">
import { Auth } from '@supabase/auth-ui-svelte'
import { ThemeSupa } from '@supabase/auth-ui-shared'
export let supabase: any;
export let url: string;
</script>
<div class="p-4">
<Auth
supabaseClient={supabase}
view="magic_link"
redirectTo={`${url}/auth/callback`}
showLinks={false}
appearance={{ theme: ThemeSupa, style: { input: 'color: #fff' } }}
additionalData={{}}
/>
</div>
+8 -8
View File
@@ -5,14 +5,14 @@
import { basket, type Basket, type Item } from '$lib/stores/basket.js'; import { basket, type Basket, type Item } from '$lib/stores/basket.js';
import { general } from '$lib/stores/generalStore.js'; import { general } from '$lib/stores/generalStore.js';
import { invalidate } from '$app/navigation'; import { invalidate } from '$app/navigation';
import SignIn from '$lib/components/SignIn.svelte';
import SignOut from '$lib/components/SignOut.svelte'; import SignOut from '$lib/components/SignOut.svelte';
import CookieConsent from '$lib/components/CookieConsent.svelte'; import CookieConsent from '$lib/components/CookieConsent.svelte';
import NavLinks from '$lib/components/NavLinks.svelte'; import NavLinks from '$lib/components/NavLinks.svelte';
import MagicLink from '$lib/components/MagicLink.svelte';
export let data; export let data;
let { supabase, session } = data; let { supabase, session, url } = data;
$: ({ supabase, session } = data); $: ({ supabase, session, url } = data);
let localBasket: Basket; let localBasket: Basket;
const unsubscribeToBasket = basket.subscribe((value) => { const unsubscribeToBasket = basket.subscribe((value) => {
@@ -113,8 +113,8 @@
<span class="badge badge-sm indicator-item">{localBasket.items.length}</span> <span class="badge badge-sm indicator-item">{localBasket.items.length}</span>
</div> </div>
</a> </a>
<div class="dropdown dropdown-end"> <details class="dropdown dropdown-end">
<div tabindex="0" role="button" class="btn btn-ghost btn-circle avatar"> <summary tabindex="0" role="button" class="btn btn-ghost btn-circle avatar">
<div class="w-10 rounded-full"> <div class="w-10 rounded-full">
{#if session?.user} {#if session?.user}
<div class="user-circle text-primary-content border-primary-content"> <div class="user-circle text-primary-content border-primary-content">
@@ -130,7 +130,7 @@
</svg> </svg>
{/if} {/if}
</div> </div>
</div> </summary>
{#if session?.user} {#if session?.user}
<ul <ul
@@ -147,10 +147,10 @@
<div <div
class="mt-3 z-[1] p-2 shadow menu menu-sm dropdown-content bg-base-100 text-base-content rounded-box min-w-[13rem] w-auto" class="mt-3 z-[1] p-2 shadow menu menu-sm dropdown-content bg-base-100 text-base-content rounded-box min-w-[13rem] w-auto"
> >
<SignIn {supabase} /> <MagicLink {supabase} {url} />
</div> </div>
{/if} {/if}
</div> </details>
</div> </div>
</nav> </nav>
</header> </header>
+2 -2
View File
@@ -2,7 +2,7 @@ import { createBrowserClient, createServerClient, isBrowser } from '@supabase/ss
import { PUBLIC_SUPABASE_ANON_KEY, PUBLIC_SUPABASE_URL } from '$env/static/public'; import { PUBLIC_SUPABASE_ANON_KEY, PUBLIC_SUPABASE_URL } from '$env/static/public';
import type { LayoutLoad } from './$types'; import type { LayoutLoad } from './$types';
export const load: LayoutLoad = async ({ fetch, data, depends }) => { export const load: LayoutLoad = async ({ fetch, data, depends, url }) => {
depends('supabase:auth'); depends('supabase:auth');
const supabase = isBrowser() const supabase = isBrowser()
@@ -31,5 +31,5 @@ export const load: LayoutLoad = async ({ fetch, data, depends }) => {
data: { session } data: { session }
} = await supabase.auth.getSession(); } = await supabase.auth.getSession();
return { supabase, session }; return { supabase, session, url: url.origin };
}; };
+4 -4
View File
@@ -1,9 +1,9 @@
<script lang="ts"> <script lang="ts">
import SignUp from '$lib/components/SignUp.svelte'; import MagicLink from '$lib/components/MagicLink.svelte';
export let data; export let data;
let { supabase, session } = data; let { supabase, session, url } = data;
$: ({ supabase, session } = data); $: ({ supabase, session, url } = data);
</script> </script>
{#if session !== null} {#if session !== null}
@@ -19,7 +19,7 @@
</h1> </h1>
</div> </div>
<div id="sign-up" class="card shrink-0 w-full max-w-sm shadow-2xl"> <div id="sign-up" class="card shrink-0 w-full max-w-sm shadow-2xl">
<SignUp {supabase} /> <MagicLink {supabase} {url} />
</div> </div>
</div> </div>
</div> </div>
+13 -15
View File
@@ -8,41 +8,39 @@ export const load: PageServerLoad = async ({ locals: { supabase, safeGetSession
redirect(303, '/'); redirect(303, '/');
} }
const { data: profile } = await supabase const { data: user } = await supabase
.from('profiles') .from('users')
.select(`username, full_name`) .select(`name`)
.eq('id', session.user.id) .eq('id', session.user.id)
.single(); .single();
return { session, profile }; return { session, user };
}; };
export const actions: Actions = { export const actions: Actions = {
update: async ({ request, locals: { supabase, safeGetSession } }) => { update: async ({ request, locals: { supabase, safeGetSession } }) => {
const formData = await request.formData(); const formData = await request.formData();
const fullName = formData.get('fullName') as string; const name = formData.get('name') as string;
const { session } = await safeGetSession(); const { session } = await safeGetSession();
const { error } = await supabase.from('profiles').upsert({ if (!session) {
id: session?.user.id, return fail(401, { name });
full_name: fullName, }
username: session?.user.email, const { error } = await supabase.from('users').update({
updated_at: new Date() name: name,
}); }).eq('id', session?.user.id);
console.error(error); console.error(error);
if (error) { if (error) {
return fail(500, { return fail(500, {
fullName, name,
username: session?.user.email
}); });
} }
return { return {
fullName, name,
username: session?.user.email
}; };
}, },
signout: async ({ locals: { supabase, safeGetSession } }) => { signout: async ({ locals: { supabase, safeGetSession } }) => {
+5 -10
View File
@@ -5,12 +5,12 @@
export let data; export let data;
export let form; export let form;
let { session, supabase, profile } = data; let { session, supabase, user } = data;
$: ({ session, supabase, profile } = data); $: ({ session, supabase, user } = data);
let profileForm: HTMLFormElement; let profileForm: HTMLFormElement;
let loading = false; let loading = false;
let fullName: string = profile?.full_name ?? ''; let name: string = user?.name ?? '';
const handleSubmit: SubmitFunction = () => { const handleSubmit: SubmitFunction = () => {
loading = true; loading = true;
@@ -37,13 +37,8 @@
bind:this={profileForm} bind:this={profileForm}
> >
<div> <div>
<label for="email">Username</label> <label for="name">Name</label>
<input id="email" type="text" value={session.user.email} disabled /> <input id="name" name="name" type="text" value={form?.name ?? name} />
</div>
<div>
<label for="fullName">Full Name</label>
<input id="fullName" name="fullName" type="text" value={form?.fullName ?? fullName} />
</div> </div>
<div> <div>
+14
View File
@@ -0,0 +1,14 @@
import { redirect, type RequestHandler } from '@sveltejs/kit'
export const GET: RequestHandler = async (event) => {
const { url, locals: { supabase } } = event;
const code = url.searchParams.get('code')
if (code) {
await supabase.auth.exchangeCodeForSession(code)
}
// TODO: Create stripe customer and sync with supabase user
throw redirect(303, '/account')
}