Skip to content

Commit cd79350

Browse files
authored
Merge pull request #39 from Tiyas04/main
feat: add session restore, admin dashboard, and innovision components…
2 parents a84ece6 + 0e222f1 commit cd79350

6 files changed

Lines changed: 25 additions & 23 deletions

File tree

‎src/app/api/auth/session/route.ts‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,6 @@ export async function GET(req: NextRequest) {
7373
const res = NextResponse.json({
7474
success: true,
7575
user: profile || null,
76-
tokens: {
77-
access_token: currentAccessToken,
78-
refresh_token: currentRefreshToken,
79-
},
8076
});
8177

8278
if (currentAccessToken) {

‎src/components/entry/EntryScanner.tsx‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use client';
22

33
import { useCallback, useEffect, useRef, useState, useSyncExternalStore } from 'react';
4-
import { fetchSessionFromDatabase, getSupabase } from '@/lib/supabase';
4+
import { fetchSessionFromDatabase, getCookie, getSupabase } from '@/lib/supabase';
55
import { DESK_RE, REJECT_REASONS, REJECT_REASON_LABELS, type RejectReason } from '@/lib/entry-shared';
66
import styles from './EntryScanner.module.css';
77

@@ -89,7 +89,8 @@ async function currentToken(): Promise<string | null> {
8989
const { data } = await getSupabase().auth.getSession();
9090
if (data.session?.access_token) return data.session.access_token;
9191
} catch {}
92-
return (await fetchSessionFromDatabase()).tokens?.access_token ?? null;
92+
await fetchSessionFromDatabase();
93+
return getCookie('inn_access_token');
9394
}
9495

9596
/** After a 401: force a refresh (the auto-refresh timer is throttled on phones), else the server-side refresh. */
@@ -98,7 +99,8 @@ async function refreshedToken(): Promise<string | null> {
9899
const { data, error } = await getSupabase().auth.refreshSession();
99100
if (!error && data.session?.access_token) return data.session.access_token;
100101
} catch {}
101-
return (await fetchSessionFromDatabase()).tokens?.access_token ?? null;
102+
await fetchSessionFromDatabase();
103+
return getCookie('inn_access_token');
102104
}
103105

104106
const offline = () => typeof navigator !== 'undefined' && navigator.onLine === false;

‎src/components/entry/SessionRestore.tsx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use client';
22

33
import { useEffect } from 'react';
4-
import { fetchSessionFromDatabase } from '@/lib/supabase';
4+
import { fetchSessionFromDatabase, getCookie } from '@/lib/supabase';
55
import styles from './EntryScanner.module.css';
66

77
const LOGIN_URL = '/?auth=login&required=scan'; // the home page returns to /admin/scan after login
@@ -25,7 +25,7 @@ export default function SessionRestore() {
2525
}
2626
fetchSessionFromDatabase()
2727
.then((s) => {
28-
if (s.tokens?.access_token) window.location.reload();
28+
if (s.user || getCookie('inn_access_token')) window.location.reload();
2929
else window.location.replace(LOGIN_URL);
3030
})
3131
.catch(() => window.location.replace(LOGIN_URL));

‎src/components/innovision/AdminDashboard.tsx‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import React, { useState, useEffect, useCallback } from 'react';
44
import type { UserProfile, Registration } from '@/lib/supabase';
5-
import { getSupabase, fetchSessionFromDatabase } from '@/lib/supabase';
5+
import { getSupabase, fetchSessionFromDatabase, getCookie } from '@/lib/supabase';
66
import { csvCell, GENDER_OPTIONS, safeHttpUrl } from '@/lib/validation';
77

88
const genderLabel = (value: string) => GENDER_OPTIONS.find((g) => g.value === value)?.label ?? value;
@@ -97,10 +97,11 @@ export default function AdminDashboard({
9797
}
9898
}
9999

100-
// Fallback 3: Query server session (auto-refreshes tokens if expired)
100+
// Fallback 3: Query server session (auto-refreshes tokens in cookies if expired)
101101
const dbAuth = await fetchSessionFromDatabase();
102-
if (dbAuth.tokens?.access_token) {
103-
return dbAuth.tokens.access_token;
102+
if (dbAuth.user) {
103+
const cookieToken = getCookie('inn_access_token');
104+
if (cookieToken) return cookieToken;
104105
}
105106
} catch (e) {
106107
console.warn('getAuthToken error:', e);

‎src/components/innovision/Innovision.tsx‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import {
4343
cleanAuthUrl,
4444
saveSessionToDatabase,
4545
fetchSessionFromDatabase,
46+
getCookie,
4647
purgeLocalStorageTokens,
4748
type UserProfile,
4849
type Registration,
@@ -1666,11 +1667,13 @@ export class Innovision extends Component<Props, State> {
16661667
// 3. Fall back to Server/Database session via cookies (ZERO localStorage)
16671668
const dbAuth = await fetchSessionFromDatabase();
16681669
if (dbAuth.user) {
1669-
if (dbAuth.tokens?.access_token) {
1670+
const cookieAccessToken = getCookie('inn_access_token');
1671+
const cookieRefreshToken = getCookie('inn_refresh_token');
1672+
if (cookieAccessToken) {
16701673
try {
16711674
await supabase.auth.setSession({
1672-
access_token: dbAuth.tokens.access_token,
1673-
refresh_token: dbAuth.tokens.refresh_token || '',
1675+
access_token: cookieAccessToken,
1676+
refresh_token: cookieRefreshToken || '',
16741677
});
16751678
} catch (e) {
16761679
console.warn('setSession failed:', e);

‎src/lib/supabase.ts‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export interface GalleryPhoto {
7474
export type GalleryItem = GalleryPhoto;
7575

7676
// Cookie-based storage adapter for Supabase Client: ZERO tokens or keys ever touch browser localStorage
77-
function getCookie(name: string): string | null {
77+
export function getCookie(name: string): string | null {
7878
if (typeof document === 'undefined') return null;
7979
const nameEQ = encodeURIComponent(name) + '=';
8080
const ca = document.cookie.split(';');
@@ -382,23 +382,23 @@ export async function saveSessionToDatabase(session: Session | null): Promise<bo
382382
}
383383

384384
/**
385-
* Fetches the user session directly from the database using the HttpOnly cookie.
385+
* Fetches the user session directly from the database using cookies.
386+
* Tokens are kept strictly in cookies and never returned in the API response payload.
386387
*/
387388
export async function fetchSessionFromDatabase(): Promise<{
388389
user: UserProfile | null;
389-
tokens: { access_token: string; refresh_token?: string } | null;
390390
}> {
391391
try {
392392
const res = await fetch('/api/auth/session');
393-
if (!res.ok) return { user: null, tokens: null };
393+
if (!res.ok) return { user: null };
394394
const data = await res.json();
395395
if (data.success && data.user) {
396-
return { user: data.user, tokens: data.tokens || null };
396+
return { user: data.user };
397397
}
398-
return { user: null, tokens: null };
398+
return { user: null };
399399
} catch (err) {
400400
console.warn('fetchSessionFromDatabase error:', err);
401-
return { user: null, tokens: null };
401+
return { user: null };
402402
}
403403
}
404404

0 commit comments

Comments
 (0)