Skip to content

Commit

Permalink
feat(breaking): WIP supabase auth & db
Browse files Browse the repository at this point in the history
  • Loading branch information
jouwdan committed Jul 31, 2023
1 parent b7b7b0c commit 39dd644
Show file tree
Hide file tree
Showing 31 changed files with 801 additions and 153 deletions.
1 change: 0 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
"files.exclude": {
"**/*.js": { "when": "$(basename).ts" },
"**/*.js.map": true,
"**/*.d.ts": true,
"**/node_modules": true,
"**/.turbo": true,
"**/dist": true,
Expand Down
6 changes: 5 additions & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,9 @@
"typescript": "^5.1.6",
"vite": "^4.3.9"
},
"type": "module"
"type": "module",
"dependencies": {
"@supabase/auth-helpers-sveltekit": "0.10.1",
"@supabase/supabase-js": "2.31.0"
}
}
22 changes: 14 additions & 8 deletions apps/web/src/app.d.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
/// <reference types="@sveltejs/kit" />
import { SupabaseClient, Session } from '@supabase/supabase-js';
import { Database } from './DatabaseDefinitions';

// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
// and what to do when importing types
declare namespace App {
// interface Locals {}
// interface Platform {}
// interface Session {}
// interface Stuff {}
declare global {
namespace App {
interface Locals {
supabase: SupabaseClient<Database>;
getSession(): Promise<Session | null>;
}
interface PageData {
session: Session | null;
}
// interface Error {}
// interface Platform {}
}
}
28 changes: 28 additions & 0 deletions apps/web/src/hooks.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { createSupabaseServerClient } from '@supabase/auth-helpers-sveltekit';
import type { Handle } from '@sveltejs/kit';

export const handle: Handle = async ({ event, resolve }) => {
event.locals.supabase = createSupabaseServerClient({
supabaseUrl: import.meta.env.VITE_PUBLIC_SUPABASE_URL,
supabaseKey: import.meta.env.VITE_PUBLIC_SUPABASE_ANON_KEY,
event
});

/**
* a little helper that is written for convenience so that instead
* of calling `const { data: { session } } = await supabase.auth.getSession()`
* you just call this `await getSession()`
*/
event.locals.getSession = async () => {
const {
data: { session }
} = await event.locals.supabase.auth.getSession();
return session;
};

return resolve(event, {
filterSerializedResponseHeaders(name) {
return name === 'content-range';
}
});
};
26 changes: 26 additions & 0 deletions apps/web/src/lib/auth/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
export const handleSignIn = async () => {
await supabase.auth.signInWithPassword({
email,
password
});
};

export async function handleSignInWithGitHub() {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'github'
});
}

export const handleSignUp = async () => {
await supabase.auth.signUp({
email,
password,
options: {
emailRedirectTo: `${location.origin}/auth/callback`
}
});
};

export const handleSignOut = async () => {
await supabase.auth.signOut();
};
49 changes: 49 additions & 0 deletions apps/web/src/routes/(auth)/auth/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<script lang="ts">
import { Tab, TabGroup } from '@skeletonlabs/skeleton';
import Icon from '@iconify/svelte';
export let data;
let { supabase } = data;
$: ({ supabase } = data);
let email: any;
let password: any;
const handleSignUp = async () => {
await supabase.auth.signUp({
email,
password,
options: {
emailRedirectTo: `${location.origin}/auth/callback`
}
});
};
const handleSignIn = async () => {
await supabase.auth.signInWithPassword({
email,
password
});
};
async function handleSignInWithGitHub() {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'github'
});
}
const handleSignOut = async () => {
await supabase.auth.signOut();
};
let tabSet: number = 0;
</script>

<div class="card m-auto mt-16 max-w-md p-8">
<div class="py-4">
<button type="button" class="btn variant-filled w-full" on:click={handleSignInWithGitHub}>
<span><Icon icon="mdi:github" /></span>
<span>Sign in with GitHub</span>
</button>
</div>
</div>
11 changes: 11 additions & 0 deletions apps/web/src/routes/(auth)/auth/callback/+server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { redirect } from '@sveltejs/kit';

export const GET = async ({ url, locals: { supabase } }) => {
const code = url.searchParams.get('code');

if (code) {
await supabase.auth.exchangeCodeForSession(code);
}

throw redirect(303, '/');
};
16 changes: 16 additions & 0 deletions apps/web/src/routes/(auth)/dashboard/+page.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { redirect } from '@sveltejs/kit';

export const load = async ({ locals: { supabase, getSession } }) => {
const session = await getSession();

if (!session) {
throw redirect(303, '/auth');
}

const { data: courses } = await supabase
.from('accessed_courses')
.select(`course_list`)
.eq('id', session.user.id);

return { session, courses };
};
32 changes: 32 additions & 0 deletions apps/web/src/routes/(auth)/dashboard/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<script lang="ts">
import { Table } from '@skeletonlabs/skeleton';
export let data;
</script>

<div class="container mx-auto">
<div class="card m-8 p-8">
<div class="table-container">
<table class="table table-hover">
<thead>
<tr>
<th>Course Name</th>
<th>Last Accessed</th>
<th>No Of Visits</th>
<th />
</tr>
</thead>
<tbody>
{#each data.courses[0].course_list.courses as course}
<tr>
<td>{course.name}</td>
<td>{course.last_accessed}</td>
<td>{course.visits}</td>
<td />
</tr>
{/each}
</tbody>
</table>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,20 @@
import { onMount } from 'svelte';
import { clearLocalStorage, logout } from '$lib/utils/auth';
import { currentCourse, currentUser } from '$lib/stores';
export let data;
let { supabase } = data;
$: ({ supabase } = data);
const handleSignOut = async () => {
await supabase.auth.signOut();
};
onMount(() => {
currentUser.set(null);
currentCourse.set(null);
clearLocalStorage();
handleSignOut();
logout();
});
</script>
Expand Down
Empty file.
5 changes: 5 additions & 0 deletions apps/web/src/routes/+layout.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const load = async ({ locals: { getSession } }) => {
return {
session: await getSession()
};
};
55 changes: 54 additions & 1 deletion apps/web/src/routes/+layout.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,60 @@
<script>
<script lang="ts">
import 'tutors-ui/lib/themes/tutors.css';
import '@skeletonlabs/skeleton/styles/all.css';
import './app.postcss';
import { invalidate } from '$app/navigation';
import { onMount } from 'svelte';
import { AppBar, Avatar, LightSwitch } from '@skeletonlabs/skeleton';
export let data: any;
let { supabase, session } = data;
$: ({ supabase, session } = data);
onMount(() => {
const {
data: { subscription }
} = supabase.auth.onAuthStateChange((event: any, _session: any) => {
if (_session?.expires_at !== session?.expires_at) {
invalidate('supabase:auth');
}
});
return () => subscription.unsubscribe();
});
</script>

<AppBar background="bg-surface-100-800-token" shadow="none" class="h-20 justify-center">
<svelte:fragment slot="lead">
<div class="flex space-x-4">
<img src="logo.svg" alt="tutors logo" />
<span class="text-2xl font-bold">Tutors</span>
</div>
</svelte:fragment>

<svelte:fragment slot="trail">
{#if data.session}
<Avatar
src={data.session.user.user_metadata.avatar_url}
alt={data.session.user.user_metadata.name}
width="w-12"
/>
<p>Welcome, {data.session.user.user_metadata.name}</p>
<a class="btn btn-sm" href="/dashboard">
<span class="hidden text-sm font-bold lg:block">Dashboard</span>
</a>
<a class="btn btn-sm" href="/logout">
<span class="hidden text-sm font-bold lg:block">Log Out</span>
</a>
{:else}
<a class="btn btn-sm" href="/auth">
<span class="hidden text-sm font-bold lg:block">Login / Register</span>
</a>
{/if}
<span class="divider-vertical h-10 hidden lg:block" />

<LightSwitch />
</svelte:fragment>
</AppBar>
<slot />
19 changes: 19 additions & 0 deletions apps/web/src/routes/+layout.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { createSupabaseLoadClient } from '@supabase/auth-helpers-sveltekit';
import type { Database } from '../DatabaseDefinitions';

export const load = async ({ fetch, data, depends }) => {
depends('supabase:auth');

const supabase = createSupabaseLoadClient<Database>({
supabaseUrl: import.meta.env.VITE_PUBLIC_SUPABASE_URL,
supabaseKey: import.meta.env.VITE_PUBLIC_SUPABASE_ANON_KEY,
event: { fetch },
serverSession: data.session
});

const {
data: { session }
} = await supabase.auth.getSession();

return { supabase, session };
};
Loading

0 comments on commit 39dd644

Please sign in to comment.