-
+
+
+
Team Name: {team.name}
+
Team Join Code: {team.code}
-
-
-
-
-
+
+ {teamMembers.map((member) => (
+
+ {member.username}
+
+ ))}
+
+
);
}
diff --git a/app/(main)/team/[teamId]/route.js b/app/(main)/team/[teamId]/route.js
index a21f4a2..bc57b7c 100644
--- a/app/(main)/team/[teamId]/route.js
+++ b/app/(main)/team/[teamId]/route.js
@@ -1,5 +1,5 @@
// app/api/teams/[teamId]/route.js
-import { queryOne } from "../../../../lib/db";
+import { queryOne, query } from "../../../../lib/db";
import { getServerSession } from "next-auth/next";
import { authOptions } from "../../../api/auth/[...nextauth]/route";
@@ -32,9 +32,10 @@ export async function GET(request, context) {
);
}
- const team = await queryOne("SELECT * FROM teams WHERE id = ?", [
- requestedTeamId,
- ]);
+ const team = await queryOne(
+ "SELECT id, name, code FROM teams WHERE id = ?",
+ [requestedTeamId]
+ );
if (!team) {
return new Response(JSON.stringify({ error: "Team not found" }), {
@@ -42,9 +43,13 @@ export async function GET(request, context) {
});
}
- return new Response(JSON.stringify(team), { status: 200 });
+ const members = await query(
+ "SELECT id, username FROM users WHERE team_id = ?",
+ [requestedTeamId]
+ );
+
+ return new Response(JSON.stringify({ team, members }), { status: 200 });
} catch (error) {
- console.error("Team fetch error:", error);
return new Response(
JSON.stringify({ error: "Failed to fetch team details" }),
{ status: 500 }
diff --git a/app/api/join-team/route.js b/app/api/join-team/route.js
new file mode 100644
index 0000000..d414251
--- /dev/null
+++ b/app/api/join-team/route.js
@@ -0,0 +1,46 @@
+import { queryOne } from "../../../../lib/db";
+import { getServerSession } from "next-auth/next";
+import { authOptions } from "../../auth/[...nextauth]/route";
+
+export async function POST(request) {
+ const session = await getServerSession(authOptions);
+
+ if (!session) {
+ return new Response(JSON.stringify({ error: "Unauthorized" }), {
+ status: 401,
+ });
+ }
+
+ try {
+ const { teamCode } = await request.json();
+ if (!teamCode) {
+ return new Response(JSON.stringify({ error: "Team code is required" }), {
+ status: 400,
+ });
+ }
+
+ const team = await queryOne("SELECT id FROM teams WHERE code = ?", [
+ teamCode,
+ ]);
+
+ if (!team) {
+ return new Response(JSON.stringify({ error: "Invalid team code" }), {
+ status: 404,
+ });
+ }
+
+ await queryOne("UPDATE users SET team_id = ? WHERE id = ?", [
+ team.id,
+ session.user.id,
+ ]);
+
+ return new Response(JSON.stringify({ teamId: team.id }), {
+ status: 200,
+ });
+ } catch (error) {
+ console.error("Join team error:", error);
+ return new Response(JSON.stringify({ error: "Failed to join team" }), {
+ status: 500,
+ });
+ }
+}
diff --git a/app/api/register/route.js b/app/api/register/route.js
new file mode 100644
index 0000000..445b1bc
--- /dev/null
+++ b/app/api/register/route.js
@@ -0,0 +1,45 @@
+import { queryOne, run } from "../../../lib/db";
+const bcrypt = require("bcryptjs");
+
+export async function POST(request) {
+ try {
+ const { username, password } = await request.json();
+
+ // Validate input
+ if (!username || !password) {
+ return new Response(
+ JSON.stringify({ error: "Username and password are required" }),
+ { status: 400 }
+ );
+ }
+
+ // Check if username exists
+ const existingUser = await queryOne(
+ "SELECT id FROM users WHERE username = ?",
+ [username]
+ );
+
+ if (existingUser) {
+ return new Response(
+ JSON.stringify({ error: "Username already exists" }),
+ { status: 400 }
+ );
+ }
+
+ // Hash password
+ const hashedPassword = await bcrypt.hash(password, 10);
+
+ // Insert user
+ await run(
+ "INSERT INTO users (username, password, role) VALUES (?, ?, 'user')",
+ [username, hashedPassword]
+ );
+
+ return new Response(JSON.stringify({ success: true }), { status: 201 });
+ } catch (error) {
+ console.error("Registration error:", error);
+ return new Response(JSON.stringify({ error: "Failed to register user" }), {
+ status: 500,
+ });
+ }
+}
diff --git a/app/api/teams/[teamId]/route.js b/app/api/teams/[teamId]/route.js
index e768564..d317871 100644
--- a/app/api/teams/[teamId]/route.js
+++ b/app/api/teams/[teamId]/route.js
@@ -1,4 +1,4 @@
-import { queryOne } from "../../../../lib/db";
+import { queryOne, query } from "../../../../lib/db";
import { getServerSession } from "next-auth/next";
import { authOptions } from "../../auth/[...nextauth]/route";
@@ -6,32 +6,40 @@ export async function GET(request, { params }) {
const session = await getServerSession(authOptions);
if (!session) {
- return Response.json({ error: "Unauthorised" }, { status: 401 });
+ return new Response(JSON.stringify({ error: "Unauthorized" }), {
+ status: 401,
+ });
}
try {
- const { teamId } = params;
+ const teamId = parseInt(params.teamId, 10);
+ if (isNaN(teamId)) {
+ return new Response(JSON.stringify({ error: "Invalid team ID" }), {
+ status: 400,
+ });
+ }
- // 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]
+ "SELECT id, name, code FROM teams WHERE id = ?",
+ [teamId]
);
if (!team) {
- return Response.json(
- { error: "Team not found or unauthorized" },
- { status: 404 }
- );
+ return new Response(JSON.stringify({ error: "Team not found" }), {
+ status: 404,
+ });
}
- return Response.json(team);
+ const members = await query(
+ "SELECT id, username FROM users WHERE team_id = ?",
+ [teamId]
+ );
+
+ return new Response(JSON.stringify({ team, members }), { status: 200 });
} catch (error) {
console.error("Team fetch error:", error);
- return Response.json(
- { error: "Failed to fetch team details" },
+ return new Response(
+ JSON.stringify({ error: "Failed to fetch team details" }),
{ status: 500 }
);
}
diff --git a/app/api/teams/route.js b/app/api/teams/route.js
new file mode 100644
index 0000000..f1de0cc
--- /dev/null
+++ b/app/api/teams/route.js
@@ -0,0 +1,49 @@
+import { queryOne, query } from "../../../../lib/db";
+import { getServerSession } from "next-auth/next";
+import { authOptions } from "../../auth/[...nextauth]/route";
+
+export async function POST(request) {
+ const session = await getServerSession(authOptions);
+
+ if (!session) {
+ return new Response(JSON.stringify({ error: "Unauthorized" }), {
+ status: 401,
+ });
+ }
+
+ try {
+ const { name } = await request.json();
+ if (!name) {
+ return new Response(JSON.stringify({ error: "Team name is required" }), {
+ status: 400,
+ });
+ }
+
+ const result = await queryOne(
+ "INSERT INTO teams (name, code) VALUES (?, ?)",
+ [name, generateTeamCode()]
+ );
+
+ if (!result.insertId) {
+ throw new Error("Failed to create team");
+ }
+
+ await queryOne("UPDATE users SET team_id = ? WHERE id = ?", [
+ result.insertId,
+ session.user.id,
+ ]);
+
+ return new Response(JSON.stringify({ teamId: result.insertId }), {
+ status: 201,
+ });
+ } catch (error) {
+ console.error("Team creation error:", error);
+ return new Response(JSON.stringify({ error: "Failed to create team" }), {
+ status: 500,
+ });
+ }
+}
+
+function generateTeamCode() {
+ return Math.random().toString(36).substring(2, 8).toUpperCase();
+}
diff --git a/sqlite.db b/sqlite.db
index f7af11a..75eb57d 100644
Binary files a/sqlite.db and b/sqlite.db differ