diff --git a/src/app.d.ts b/src/app.d.ts index da08e6d..bce918f 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -1,13 +1,16 @@ -// See https://svelte.dev/docs/kit/types#app.d.ts -// for information about these interfaces +// src/app.d.ts +import { SupabaseClient, Session } from '@supabase/supabase-js' declare global { - namespace App { - // interface Error {} - // interface Locals {} - // interface PageData {} - // interface PageState {} - // interface Platform {} - } -} - -export {}; + namespace App { + interface Locals { + supabase: SupabaseClient + safeGetSession(): Promise<{ session: Session | null; user: User | null }> + } + interface PageData { + session: Session | null + user: User | null + } + // interface Error {} + // interface Platform {} + } +} \ No newline at end of file diff --git a/src/hooks.server.ts b/src/hooks.server.ts new file mode 100644 index 0000000..9a89766 --- /dev/null +++ b/src/hooks.server.ts @@ -0,0 +1,53 @@ +// src/hooks.server.ts +import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public' +import { createServerClient } from '@supabase/ssr' +import type { Handle } from '@sveltejs/kit' + +export const handle: Handle = async ({ event, resolve }) => { + event.locals.supabase = createServerClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY, { + cookies: { + getAll: () => event.cookies.getAll(), + /** + * SvelteKit's cookies API requires `path` to be explicitly set in + * the cookie options. Setting `path` to `/` replicates previous/ + * standard behavior. + */ + setAll: (cookiesToSet) => { + cookiesToSet.forEach(({ name, value, options }) => { + event.cookies.set(name, value, { ...options, path: '/' }) + }) + }, + }, + }) + + /** + * Unlike `supabase.auth.getSession()`, which returns the session _without_ + * validating the JWT, this function also calls `getUser()` to validate the + * JWT before returning the session. + */ + event.locals.safeGetSession = async () => { + const { + data: { session }, + } = await event.locals.supabase.auth.getSession() + if (!session) { + return { session: null, user: null } + } + + const { + data: { user }, + error, + } = await event.locals.supabase.auth.getUser() + if (error) { + // JWT validation has failed + return { session: null, user: null } + } + + return { session, user } + } + + return resolve(event, { + filterSerializedResponseHeaders(name) { + return name === 'content-range' || name === 'x-supabase-api-version' + }, + }) +} \ No newline at end of file diff --git a/src/lib/types.ts b/src/lib/types.ts new file mode 100644 index 0000000..e9558fb --- /dev/null +++ b/src/lib/types.ts @@ -0,0 +1,31 @@ +export enum ScanState { + scanning, + scan_successful, + scan_failed +} + +export type TicketData = { + id: string; + name: string; + surname: string; + email: string; + event: string; + created_at: string; + created_by: string | null; + scanned: boolean; + scanned_at: string | null; + scanned_by: string | null; +}; + +export const defaultTicketData: TicketData = { + id: '', + name: '', + surname: '', + email: '', + event: '', + created_at: new Date().toISOString(), + created_by: null, + scanned: false, + scanned_at: null, + scanned_by: null, +}; \ No newline at end of file diff --git a/src/routes/+layout.server.ts b/src/routes/+layout.server.ts new file mode 100644 index 0000000..55e62fe --- /dev/null +++ b/src/routes/+layout.server.ts @@ -0,0 +1,10 @@ +// src/routes/+layout.server.ts +import type { LayoutServerLoad } from './$types' +export const load: LayoutServerLoad = async ({ locals: { safeGetSession }, cookies }) => { + const { session, user } = await safeGetSession() + return { + session, + user, + cookies: cookies.getAll(), + } +} \ No newline at end of file diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index b93e9ba..b8a1c4d 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -2,6 +2,7 @@ import '../app.css'; let { children } = $props(); + {@render children()} diff --git a/src/routes/+layout.ts b/src/routes/+layout.ts index c173c2e..768b716 100644 --- a/src/routes/+layout.ts +++ b/src/routes/+layout.ts @@ -8,7 +8,7 @@ export const load: LayoutLoad = async ({ fetch, data, depends }) => { ? createBrowserClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY, { global: { fetch, - }, + } }) : createServerClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY, { global: { @@ -16,7 +16,7 @@ export const load: LayoutLoad = async ({ fetch, data, depends }) => { }, cookies: { getAll() { - return data?.cookies ?? [] + return data.cookies ?? [] }, }, }) diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 7642608..f229fc2 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,15 +1,5 @@ diff --git a/src/routes/login/+page.svelte b/src/routes/login/+page.svelte new file mode 100644 index 0000000..e69de29 diff --git a/src/routes/private/scanner/+page.svelte b/src/routes/private/scanner/+page.svelte new file mode 100644 index 0000000..a3843f9 --- /dev/null +++ b/src/routes/private/scanner/+page.svelte @@ -0,0 +1,42 @@ + + + + +{#if scan_state === ScanState.scan_successful} + +{/if} + +{#if scan_state === ScanState.scan_failed} +

Scan failed. Please try again.

+{/if} + +{#if scan_state === ScanState.scanning} +

Fetching data...

+{/if} diff --git a/src/routes/scanner/QRScanner.svelte b/src/routes/private/scanner/QRScanner.svelte similarity index 100% rename from src/routes/scanner/QRScanner.svelte rename to src/routes/private/scanner/QRScanner.svelte diff --git a/src/routes/private/scanner/TicketDisplay.svelte b/src/routes/private/scanner/TicketDisplay.svelte new file mode 100644 index 0000000..6e76511 --- /dev/null +++ b/src/routes/private/scanner/TicketDisplay.svelte @@ -0,0 +1,8 @@ + + +

{ticket_data.name}

+

{ticket_data.surname}

diff --git a/src/routes/scanner/+page.svelte b/src/routes/scanner/+page.svelte deleted file mode 100644 index 4d9a80f..0000000 --- a/src/routes/scanner/+page.svelte +++ /dev/null @@ -1,68 +0,0 @@ - - - - -

CODE: {scanned_id}

- -

Name: {scan_data.name} {scan_data.surname}

-

State: {ticket_state}

-

Event: {scan_data.event_name}