diff --git a/server/src/routes/post.routes.ts b/server/src/routes/post.routes.ts index 4fd5c0c..ac7fbf7 100644 --- a/server/src/routes/post.routes.ts +++ b/server/src/routes/post.routes.ts @@ -1,16 +1,22 @@ import { Router } from 'express'; import { postController } from '../controllers/post.controller'; -import { authenticate } from '../middleware/auth'; +import { authenticate, optionalAuth } from '../middleware/auth'; import { uploadMedia } from '../middleware/upload'; + const router = Router(); -router.get('/trending', authenticate, postController.getTrending); -router.get('/', authenticate, postController.list); -router.get('/:id', authenticate, postController.getById); + +// Public / optional auth read endpoints +router.get('/trending', optionalAuth, postController.getTrending); +router.get('/', optionalAuth, postController.list); +router.get('/:id', optionalAuth, postController.getById); +router.get('/:id/comments', optionalAuth, postController.getComments); + +// Protected mutation endpoints router.post('/', authenticate, postController.create); router.post('/upload', authenticate, uploadMedia, postController.uploadMedia); router.post('/poll/vote', authenticate, postController.votePoll); router.delete('/:id', authenticate, postController.delete); router.post('/:id/like', authenticate, postController.like); -router.get('/:id/comments', authenticate, postController.getComments); router.post('/:id/comment', authenticate, postController.comment); + export default router; diff --git a/server/src/routes/tournament.routes.ts b/server/src/routes/tournament.routes.ts index 22cd894..1510785 100644 --- a/server/src/routes/tournament.routes.ts +++ b/server/src/routes/tournament.routes.ts @@ -1,6 +1,6 @@ import { Router } from 'express'; import { tournamentController } from '../controllers/tournament.controller'; -import { authenticate } from '../middleware/auth'; +import { authenticate, optionalAuth } from '../middleware/auth'; import { validate } from '../middleware/validate'; import { createTournamentValidation, @@ -16,13 +16,16 @@ import { } from '../validators/tournament'; const router = Router(); + +// Protected user-specific list router.get('/my', authenticate, tournamentController.myTournaments.bind(tournamentController)); -router.get('/', authenticate, tournamentController.list.bind(tournamentController)); -router.get('/:id', authenticate, tournamentIdParamValidation, validate, tournamentController.getById.bind(tournamentController)); -router.get('/:id/standings', authenticate, tournamentIdParamValidation, validate, tournamentController.getStandings.bind(tournamentController)); -router.get('/:id/announcements', authenticate, tournamentIdParamValidation, validate, tournamentController.getAnnouncements.bind(tournamentController)); -router.get('/:id/analytics', authenticate, tournamentIdParamValidation, validate, tournamentController.getAnalytics.bind(tournamentController)); +// Public / optional auth read endpoints +router.get('/', optionalAuth, tournamentController.list.bind(tournamentController)); +router.get('/:id', optionalAuth, tournamentIdParamValidation, validate, tournamentController.getById.bind(tournamentController)); +router.get('/:id/standings', optionalAuth, tournamentIdParamValidation, validate, tournamentController.getStandings.bind(tournamentController)); + +// Protected mutation endpoints router.post('/', authenticate, createTournamentValidation, validate, tournamentController.create.bind(tournamentController)); router.post('/:id/register', authenticate, registerTournamentValidation, validate, tournamentController.registerTeam.bind(tournamentController)); router.post('/:id/check-in', authenticate, tournamentIdParamValidation, validate, tournamentController.checkIn.bind(tournamentController)); diff --git a/web/src/app/auth/login/page.tsx b/web/src/app/auth/login/page.tsx index 4dac081..32d4b19 100644 --- a/web/src/app/auth/login/page.tsx +++ b/web/src/app/auth/login/page.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useState } from 'react'; -import { useRouter } from 'next/navigation'; +import { useState, Suspense } from 'react'; +import { useRouter, useSearchParams } from 'next/navigation'; import Link from 'next/link'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; @@ -14,8 +14,14 @@ import { useAuthStore } from '@/store/authStore'; import toast from 'react-hot-toast'; import { motion } from 'framer-motion'; -export default function LoginPage() { +function LoginForm() { const router = useRouter(); + const searchParams = useSearchParams(); + const rawRedirect = searchParams.get('redirect'); + const redirectTarget = (rawRedirect && rawRedirect.startsWith('/') && !rawRedirect.startsWith('//')) + ? rawRedirect + : '/feed'; + const { user, isAuthenticated, login } = useAuthStore(); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); @@ -27,8 +33,6 @@ export default function LoginPage() { return null; } - // Redirect to feed if already logged in - const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!email.trim() || !password) return; @@ -37,7 +41,7 @@ export default function LoginPage() { const { data } = await api.post('/auth/login', { email: email.trim(), password }); login(data.data.user, data.data.accessToken, data.data.refreshToken); toast.success(`Welcome back, ${data.data.user?.profile?.username || 'Gamer'}!`); - router.push('/feed'); + router.push(redirectTarget); } catch (err: any) { const msg = err.response?.data?.message || err.response?.data?.error || 'Invalid credentials'; toast.error(msg); @@ -49,8 +53,6 @@ export default function LoginPage() { const handleSocialLogin = async (provider: string) => { setSocialLoading(true); try { - // These are OAuth redirects to the external backend, not internal Next.js - // navigation — the browser must leave the app, so full navigation is required. if (provider === 'discord') { window.location.href = API_URL + '/auth/discord?action=login'; return; @@ -85,10 +87,11 @@ export default function LoginPage() { footer={ Don't have an account?{' '} - Sign up + Sign up } - >