POL-124: Migrate frontend from React Native to Next.js web app
- Replace mobile/ (Expo) with web/ (Next.js 16 + Tailwind + shadcn/ui) - Pages: login, register, pending, championships, championship detail, registrations, profile, admin - Logic/view separated: hooks/ for data, components/ for UI, pages compose both - Types in src/types/ (one interface per file) - Auth: Zustand store + localStorage tokens + cookie presence flag for proxy - API layer: axios client with JWT auto-refresh Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
60
web/src/lib/tokenStorage.ts
Normal file
60
web/src/lib/tokenStorage.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
const ACCESS_KEY = "access_token";
|
||||
const REFRESH_KEY = "refresh_token";
|
||||
|
||||
let _accessToken: string | null = null;
|
||||
let _refreshToken: string | null = null;
|
||||
|
||||
function setCookie(name: string, days: number) {
|
||||
const expires = new Date(Date.now() + days * 864e5).toUTCString();
|
||||
document.cookie = `${name}=1; expires=${expires}; path=/; SameSite=Lax`;
|
||||
}
|
||||
|
||||
function deleteCookie(name: string) {
|
||||
document.cookie = `${name}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;
|
||||
}
|
||||
|
||||
export function saveTokens(access: string, refresh: string) {
|
||||
_accessToken = access;
|
||||
_refreshToken = refresh;
|
||||
if (typeof window !== "undefined") {
|
||||
localStorage.setItem(ACCESS_KEY, access);
|
||||
localStorage.setItem(REFRESH_KEY, refresh);
|
||||
// Presence-only cookies so Next.js middleware can check auth on the edge
|
||||
setCookie(ACCESS_KEY, 1);
|
||||
setCookie(REFRESH_KEY, 7);
|
||||
}
|
||||
}
|
||||
|
||||
export function getAccessToken(): string | null {
|
||||
if (_accessToken) return _accessToken;
|
||||
if (typeof window !== "undefined") {
|
||||
_accessToken = localStorage.getItem(ACCESS_KEY);
|
||||
}
|
||||
return _accessToken;
|
||||
}
|
||||
|
||||
export function getRefreshToken(): string | null {
|
||||
if (_refreshToken) return _refreshToken;
|
||||
if (typeof window !== "undefined") {
|
||||
_refreshToken = localStorage.getItem(REFRESH_KEY);
|
||||
}
|
||||
return _refreshToken;
|
||||
}
|
||||
|
||||
export function clearTokens() {
|
||||
_accessToken = null;
|
||||
_refreshToken = null;
|
||||
if (typeof window !== "undefined") {
|
||||
localStorage.removeItem(ACCESS_KEY);
|
||||
localStorage.removeItem(REFRESH_KEY);
|
||||
deleteCookie(ACCESS_KEY);
|
||||
deleteCookie(REFRESH_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
export function loadFromStorage() {
|
||||
if (typeof window !== "undefined") {
|
||||
_accessToken = localStorage.getItem(ACCESS_KEY);
|
||||
_refreshToken = localStorage.getItem(REFRESH_KEY);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user