+ const handleJoinTeam = async (e) => {
+ e.preventDefault();
+ setIsLoading(true);
+ setError("");
-
+ try {
+ const result = await joinTeam(session.user.id, teamCode);
-
-
-
-
-
+ if (result.success) {
+ router.push(`/team/${result.teamId}`);
+ } else {
+ setError(result.error || "Team not found");
+ }
+ } catch (err) {
+ setError("An unexpected error occurred");
+ console.error(err);
+ } finally {
+ setIsLoading(false);
+ }
+ };
+
+ if (status === "loading") {
+ return
Loading...
;
+ }
+
+ // Don't render anything if redirecting
+ if (
+ status === "unauthenticated" ||
+ (status === "authenticated" && session?.user?.role === "admin")
+ ) {
+ return null;
+ }
+
+ return (
+
+
+
+
+
+
Team Selection
+
+ {error &&
{error}
}
+
+
+
+
+
- );
-}
\ No newline at end of file
+
+
+
+
+
+
+ );
+}
diff --git a/app/(main)/team/[teamId]/members/route.js b/app/(main)/team/[teamId]/members/route.js
index eaae3c9..74675d9 100644
--- a/app/(main)/team/[teamId]/members/route.js
+++ b/app/(main)/team/[teamId]/members/route.js
@@ -1,35 +1,51 @@
-// app/api/teams/[teamId]/members/route.js
-import { query } from '../../../../../lib/db';
-import { getServerSession } from 'next-auth/next';
-import { authOptions } from '../../../api/auth/[...nextauth]/route';
+import { query } from "../../../../lib/db";
+import { getServerSession } from "next-auth/next";
+import { authOptions } from "../../auth/[...nextauth]/route";
-export async function GET(request, { params }) {
- const session = await getServerSession(authOptions);
+export async function GET(request, context) {
+ const session = await getServerSession(authOptions);
- if (!session) {
- return Response.json({ error: 'Unauthorised' }, { status: 401 });
+ if (!session) {
+ return Response.json({ error: "Unauthorised" }, { status: 401 });
+ }
+
+ try {
+ const { teamId } = context.params;
+
+ // Convert teamId to number for proper comparison
+ const requestedTeamId = parseInt(teamId, 10);
+ const userTeamId = parseInt(session.user.teamId, 10);
+
+ // Log for debugging
+ console.log("Requested team:", requestedTeamId);
+ console.log("User team:", userTeamId);
+ console.log("User role:", session.user.role);
+
+ // Ensure the user is requesting their own team or is an admin
+ if (userTeamId !== requestedTeamId && session.user.role !== "admin") {
+ return Response.json(
+ { error: "Not authorized to view this team" },
+ { status: 403 }
+ );
}
- try {
- const { teamId } = params;
+ const teamMembers = await query("SELECT * FROM users WHERE team_id = ?", [
+ requestedTeamId,
+ ]);
- // Convert teamId to number for proper comparison
- const requestedTeamId = parseInt(teamId, 10);
- const userTeamId = parseInt(session.user.teamId, 10);
-
- // Ensure the user is requesting their own team or is an admin
- if (userTeamId !== requestedTeamId && session.user.role !== 'admin') {
- return Response.json({ error: 'Not authorized to view this team' }, { status: 403 });
- }
-
- const members = await query(
- 'SELECT id, username FROM users WHERE team_id = ?',
- [requestedTeamId]
- );
-
- return Response.json(members);
- } catch (error) {
- console.error('Team members fetch error:', error);
- return Response.json({ error: 'Failed to fetch team members' }, { status: 500 });
+ if (!teamMembers) {
+ return Response.json(
+ { error: "Team members not found" },
+ { status: 404 }
+ );
}
-}
\ No newline at end of file
+
+ return Response.json(teamMembers);
+ } catch (error) {
+ console.error("Team members fetch error:", error);
+ return Response.json(
+ { error: "Failed to fetch team members" },
+ { status: 500 }
+ );
+ }
+}
diff --git a/app/(main)/team/[teamId]/page.js b/app/(main)/team/[teamId]/page.js
index 44a2bfd..2580a1f 100644
--- a/app/(main)/team/[teamId]/page.js
+++ b/app/(main)/team/[teamId]/page.js
@@ -1,129 +1,139 @@
-'use client'; // Mark as a Client Component
-import { useState, useEffect } from 'react';
-import { useSession } from 'next-auth/react';
-import { useRouter } from 'next/navigation';
-import Link from 'next/link';
+"use client"; // Mark as a Client Component
+import { useState, useEffect } from "react";
+import { useSession } from "next-auth/react";
+import { useRouter } from "next/navigation";
+import Link from "next/link";
export default function TeamPage({ params }) {
- const { data: session, status } = useSession();
- const [team, setTeam] = useState(null);
- const [teamMembers, setTeamMembers] = useState([]);
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState('');
- const router = useRouter();
- const { teamId } = params;
+ const { data: session, status } = useSession();
+ const [team, setTeam] = useState(null);
+ const [teamMembers, setTeamMembers] = useState([]);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState("");
+ const [huntActive, setHuntActive] = useState(false);
+ const router = useRouter();
+ const { teamId } = params;
- // Fetch team data
- useEffect(() => {
- async function fetchTeamData() {
- try {
- if (!teamId) {
- throw new Error('No team ID provided');
- }
-
- // Fetch team details
- const teamResponse = await fetch(`/api/teams/${teamId}`);
- if (!teamResponse.ok) {
- const errorData = await teamResponse.json();
- throw new Error(errorData.error || 'Failed to fetch team data');
- }
- const teamData = await teamResponse.json();
- setTeam(teamData);
-
- // Fetch team members
- const membersResponse = await fetch(`/api/teams/${teamId}/members`);
- if (!membersResponse.ok) {
- // Don't throw here, just log the error
- console.error('Failed to fetch team members');
- } else {
- const membersData = await membersResponse.json();
- setTeamMembers(membersData);
- }
- } catch (err) {
- console.error('Team page error:', err);
- setError(err.message);
- } finally {
- setLoading(false);
- }
+ // Fetch team data
+ useEffect(() => {
+ async function fetchTeamData() {
+ try {
+ if (!teamId) {
+ throw new Error("No team ID provided");
}
- if (status === 'authenticated' && teamId) {
- fetchTeamData();
+ // Fetch team details
+ const teamResponse = await fetch(`/api/teams/${teamId}`);
+ if (!teamResponse.ok) {
+ const errorData = await teamResponse.json();
+ throw new Error(errorData.error || "Failed to fetch team data");
}
- }, [teamId, status]);
+ const teamData = await teamResponse.json();
+ setTeam(teamData);
- // Handle authentication
- useEffect(() => {
- if (status === 'unauthenticated') {
- router.push('/login');
+ // Fetch team members
+ const membersResponse = await fetch(`/api/teams/${teamId}/members`);
+ if (!membersResponse.ok) {
+ // Don't throw here, just log the error
+ console.error("Failed to fetch team members");
+ } else {
+ const membersData = await membersResponse.json();
+ setTeamMembers(membersData);
}
- }, [status, router]);
- if (status === 'loading' || loading) {
- return
Loading...
;
+ // Fetch hunt status
+ const huntStatusResponse = await fetch("/api/hunt-status");
+ if (huntStatusResponse.ok) {
+ const huntStatusData = await huntStatusResponse.json();
+ setHuntActive(huntStatusData.active);
+ }
+ } catch (err) {
+ console.error("Team page error:", err);
+ setError(err.message);
+ } finally {
+ setLoading(false);
+ }
}
- if (error) {
- return
Error: {error}
;
+ if (status === "authenticated" && teamId) {
+ fetchTeamData();
}
+ }, [teamId, status]);
- if (!team) {
- return
Team not found
;
+ // Handle authentication
+ useEffect(() => {
+ if (status === "unauthenticated") {
+ router.push("/login");
}
+ }, [status, router]);
- return (
-
-
+ if (status === "loading" || loading) {
+ return
Loading...
;
+ }
-
-
{team.name}
+ if (error) {
+ return
Error: {error}
;
+ }
-
-
Team Code
-
{team.code}
-
Share this code with others to join your team
-
+ if (!team) {
+ return
Team not found
;
+ }
-
-
Team Members
- {teamMembers.length === 0 ? (
-
No members have joined yet
- ) : (
-
- {teamMembers.map(member => (
- -
- {member.username}
-
- ))}
-
- )}
-
+ return (
+
+
+
+ ←
+
+
Team Details
+
+
-
-
- Start Hunt
-
-
-
+
+
{team.name}
-
+
+
Team Code
+
{team.code}
+
Share this code with others to join your team
- );
-}
\ No newline at end of file
+
+
+
Team Members
+ {teamMembers.length === 0 ? (
+
No members have joined yet
+ ) : (
+
+ {teamMembers.map((member) => (
+ -
+ {member.username}
+
+ ))}
+
+ )}
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/app/(main)/team/[teamId]/route.js b/app/(main)/team/[teamId]/route.js
index 59ac8b2..ff4e36a 100644
--- a/app/(main)/team/[teamId]/route.js
+++ b/app/(main)/team/[teamId]/route.js
@@ -1,41 +1,101 @@
// app/api/teams/[teamId]/route.js
-import { queryOne } from '../../../../lib/db';
-import { getServerSession } from 'next-auth/next';
-import { authOptions } from '../../../api/auth/[...nextauth]/route';
+import { queryOne } from "../../../../lib/db";
+import { getServerSession } from "next-auth/next";
+import { authOptions } from "../../../api/auth/[...nextauth]/route";
-export async function GET(request, { params }) {
- const session = await getServerSession(authOptions);
+export async function GET(request, context) {
+ const session = await getServerSession(authOptions);
- if (!session) {
- return Response.json({ error: 'Unauthorised' }, { status: 401 });
+ if (!session) {
+ return new Response(JSON.stringify({ error: "Unauthorised" }), {
+ status: 401,
+ });
+ }
+
+ try {
+ const { teamId } = await context.params; // Await the params
+
+ // Convert teamId to number for proper comparison
+ const requestedTeamId = parseInt(teamId, 10);
+ const userTeamId = parseInt(session.user.teamId, 10);
+
+ // Log for debugging
+ console.log("Requested team:", requestedTeamId);
+ console.log("User team:", userTeamId);
+ console.log("User role:", session.user.role);
+
+ // Ensure the user is requesting their own team or is an admin
+ if (userTeamId !== requestedTeamId && session.user.role !== "admin") {
+ return new Response(
+ JSON.stringify({ error: "Not authorized to view this team" }),
+ { status: 403 }
+ );
}
- try {
- const { teamId } = params;
+ const team = await queryOne("SELECT * FROM teams WHERE id = ?", [
+ requestedTeamId,
+ ]);
- // Convert teamId to number for proper comparison
- const requestedTeamId = parseInt(teamId, 10);
- const userTeamId = parseInt(session.user.teamId, 10);
-
- // Log for debugging
- console.log('Requested team:', requestedTeamId);
- console.log('User team:', userTeamId);
- console.log('User role:', session.user.role);
-
- // Ensure the user is requesting their own team or is an admin
- if (userTeamId !== requestedTeamId && session.user.role !== 'admin') {
- return Response.json({ error: 'Not authorized to view this team' }, { status: 403 });
- }
-
- const team = await queryOne('SELECT * FROM teams WHERE id = ?', [requestedTeamId]);
-
- if (!team) {
- return Response.json({ error: 'Team not found' }, { status: 404 });
- }
-
- return Response.json(team);
- } catch (error) {
- console.error('Team fetch error:', error);
- return Response.json({ error: 'Failed to fetch team details' }, { status: 500 });
+ if (!team) {
+ return new Response(JSON.stringify({ error: "Team not found" }), {
+ status: 404,
+ });
}
-}
\ No newline at end of file
+
+ return new Response(JSON.stringify(team), { status: 200 });
+ } catch (error) {
+ console.error("Team fetch error:", error);
+ return new Response(
+ JSON.stringify({ error: "Failed to fetch team details" }),
+ { status: 500 }
+ );
+ }
+}
+
+export async function PATCH(request, context) {
+ const session = await getServerSession(authOptions);
+
+ if (!session) {
+ return new Response(JSON.stringify({ error: "Unauthorised" }), {
+ status: 401,
+ });
+ }
+
+ try {
+ const { teamId } = await context.params; // Await the params
+ const requestedTeamId = parseInt(teamId, 10);
+ const { userId } = await request.json(); // Parse the request body
+
+ // Log for debugging
+ console.log("Requested team:", requestedTeamId);
+ console.log("User role:", session.user.role);
+
+ // Ensure the user is an admin or the user themselves
+ if (session.user.role !== "admin" && session.user.id !== userId) {
+ return new Response(
+ JSON.stringify({ error: "Not authorized to change this team" }),
+ { status: 403 }
+ );
+ }
+
+ // Update the user's team
+ await queryOne("UPDATE users SET teamId = ? WHERE id = ?", [
+ requestedTeamId,
+ userId,
+ ]);
+
+ // Update the session with the new teamId
+ session.user.teamId = requestedTeamId;
+
+ return new Response(
+ JSON.stringify({ success: "Team updated successfully" }),
+ { status: 200 }
+ );
+ } catch (error) {
+ console.error("Team update error:", error);
+ return new Response(
+ JSON.stringify({ error: "Failed to update team" }),
+ { status: 500 }
+ );
+ }
+}
diff --git a/app/api/teams/[teamId]/route.js b/app/api/teams/[teamId]/route.js
index eb7bbf4..e768564 100644
--- a/app/api/teams/[teamId]/route.js
+++ b/app/api/teams/[teamId]/route.js
@@ -1,31 +1,38 @@
-import { queryOne } from '../../../../lib/db';
-import { getServerSession } from 'next-auth/next';
-import { authOptions } from '../../auth/[...nextauth]/route';
+import { queryOne } from "../../../../lib/db";
+import { getServerSession } from "next-auth/next";
+import { authOptions } from "../../auth/[...nextauth]/route";
export async function GET(request, { params }) {
- const session = await getServerSession(authOptions);
+ const session = await getServerSession(authOptions);
- if (!session) {
- return Response.json({ error: 'Unauthorised' }, { status: 401 });
+ if (!session) {
+ return Response.json({ error: "Unauthorised" }, { status: 401 });
+ }
+
+ try {
+ const { teamId } = params;
+
+ // Single query to get team data with authorization check
+ const team = await queryOne(
+ `SELECT t.* FROM teams t
+ LEFT JOIN users u ON u.id = ?
+ WHERE t.id = ? AND (u.team_id = t.id OR ? = 'admin')`,
+ [session.user.id, teamId, session.user.role]
+ );
+
+ if (!team) {
+ return Response.json(
+ { error: "Team not found or unauthorized" },
+ { status: 404 }
+ );
}
- try {
- const { teamId } = params;
-
- // Ensure the user is requesting their own team or is an admin
- if (session.user.teamId != teamId && session.user.role !== 'admin') {
- return Response.json({ error: 'Not authorized to view this team' }, { status: 403 });
- }
-
- const team = await queryOne('SELECT * FROM teams WHERE id = ?', [teamId]);
-
- if (!team) {
- return Response.json({ error: 'Team not found' }, { status: 404 });
- }
-
- return Response.json(team);
- } catch (error) {
- console.error('Team fetch error:', error);
- return Response.json({ error: 'Failed to fetch team details' }, { status: 500 });
- }
-}
\ No newline at end of file
+ return Response.json(team);
+ } catch (error) {
+ console.error("Team fetch error:", error);
+ return Response.json(
+ { error: "Failed to fetch team details" },
+ { status: 500 }
+ );
+ }
+}