diff --git a/app/(main)/team/[teamId]/page.js b/app/(main)/team/[teamId]/page.js
index a313431..194efa1 100644
--- a/app/(main)/team/[teamId]/page.js
+++ b/app/(main)/team/[teamId]/page.js
@@ -5,7 +5,7 @@ import { useRouter } from "next/navigation";
import Link from "next/link";
export default function TeamPage({ params }) {
- const { data: session, status } = useSession();
+ const { status } = useSession();
const [team, setTeam] = useState(null);
const [teamMembers, setTeamMembers] = useState([]);
const [loading, setLoading] = useState(true);
@@ -88,9 +88,9 @@ export default function TeamPage({ params }) {
- {teamMembers.map((member, index) => (
+ {teamMembers.map((member) => (
- User #{index + 1}
+ {member.username}
))}
diff --git a/app/(main)/team/[teamId]/route.js b/app/(main)/team/[teamId]/route.js
index 956fae0..89ac0a3 100644
--- a/app/(main)/team/[teamId]/route.js
+++ b/app/(main)/team/[teamId]/route.js
@@ -1,29 +1,40 @@
-// app/(main)/team/[teamId]/route.js
-import { queryOne, query } from "../../../../lib/db";
-import { getServerSession } from "next-auth/next";
-import { authOptions } from "../../../api/auth/[...nextauth]/route";
import { redirect } from "next/navigation";
+import { getServerSession } from "next-auth/next";
+import { authOptions } from "@/app/api/auth/[...nextauth]/route";
+import { queryOne, query } from "@/lib/db";
-export async function GET(request, context) {
+export async function GET(_, context) {
const session = await getServerSession(authOptions);
if (!session) {
- // Redirect to login page instead of returning JSON
return redirect("/login");
}
try {
- const { teamId } = context.params;
+ const params = await context.params;
+ const teamId = params.teamId;
- // Instead of returning JSON, we should let the page component handle rendering
- // This route.js file should only be used for API endpoints, not page rendering
+ const team = await queryOne("SELECT * FROM teams WHERE id = ?", [teamId]);
- // Redirect to the page component
- return redirect(`/team/${teamId}`);
+ if (!team) {
+ return new Response(
+ JSON.stringify({ success: false, error: "Team not found" }),
+ { status: 404 }
+ );
+ }
+
+ const members = await query(
+ "SELECT id, username FROM users WHERE team_id = ?",
+ [teamId]
+ );
+
+ return new Response(JSON.stringify({ success: true, team, members }), {
+ status: 200,
+ });
} catch (error) {
console.error("Team fetch error:", error);
return new Response(
- JSON.stringify({ error: "Failed to fetch team details" }),
+ JSON.stringify({ success: false, error: "Failed to fetch team" }),
{ status: 500 }
);
}
diff --git a/app/api/auth/[...nextauth]/route.js b/app/api/auth/[...nextauth]/route.js
index 4b529da..aaeb3c0 100644
--- a/app/api/auth/[...nextauth]/route.js
+++ b/app/api/auth/[...nextauth]/route.js
@@ -1,58 +1,64 @@
-// app/api/auth/[...nextauth]/route.js
-import NextAuth from 'next-auth';
-import CredentialsProvider from 'next-auth/providers/credentials';
-import { validateCredentials } from '../../../actions/auth';
+import NextAuth from "next-auth";
+import CredentialsProvider from "next-auth/providers/credentials";
+import { validateCredentials } from "@/actions/auth";
export const authOptions = {
- providers: [
- CredentialsProvider({
- name: 'Credentials',
- credentials: {
- username: { label: "Username", type: "text" },
- password: { label: "Password", type: "password" }
- },
- async authorize(credentials) {
- if (!credentials?.username || !credentials?.password) {
- return null;
- }
+ providers: [
+ CredentialsProvider({
+ id: "credentials",
+ name: "Credentials",
+ credentials: {
+ username: { label: "Username", type: "text" },
+ password: { label: "Password", type: "password" },
+ },
+ async authorize(credentials) {
+ try {
+ if (!credentials?.username || !credentials?.password) {
+ return null;
+ }
- const user = await validateCredentials(
- credentials.username,
- credentials.password
- );
+ const user = await validateCredentials(
+ credentials.username,
+ credentials.password
+ );
- return user;
- }
- })
- ],
- callbacks: {
- async jwt({ token, user }) {
- if (user) {
- token.id = user.id;
- token.role = user.role;
- token.username = user.username;
- token.teamId = user.teamId;
- }
- return token;
- },
- async session({ session, token }) {
- if (token) {
- session.user = session.user || {};
- session.user.id = token.id;
- session.user.role = token.role;
- session.user.username = token.username;
- session.user.teamId = token.teamId;
- }
- return session;
+ return user;
+ } catch (error) {
+ console.error("Auth error:", error);
+ return null;
}
+ },
+ }),
+ ],
+ callbacks: {
+ async jwt({ token, user }) {
+ if (user) {
+ token.id = user.id;
+ token.role = user.role;
+ token.username = user.username;
+ token.teamId = user.teamId;
+ }
+ return token;
},
- pages: {
- signIn: '/login',
+ async session({ session, token }) {
+ if (token) {
+ session.user = session.user || {};
+ session.user.id = token.id;
+ session.user.role = token.role;
+ session.user.username = token.username;
+ session.user.teamId = token.teamId;
+ }
+ return session;
},
- session: {
- strategy: "jwt",
- }
+ },
+ pages: {
+ signIn: "/login",
+ },
+ session: {
+ strategy: "jwt",
+ },
+ secret: process.env.NEXTAUTH_SECRET,
};
const handler = NextAuth(authOptions);
-export { handler as GET, handler as POST };
\ No newline at end of file
+export { handler as GET, handler as POST };
diff --git a/app/api/teams/[teamId]/route.js b/app/api/teams/[teamId]/route.js
index e26b6a5..cab71cc 100644
--- a/app/api/teams/[teamId]/route.js
+++ b/app/api/teams/[teamId]/route.js
@@ -1,9 +1,8 @@
-// app/api/teams/[teamId]/route.js
import { queryOne, query } from "../../../../lib/db";
import { getServerSession } from "next-auth/next";
import { authOptions } from "../../auth/[...nextauth]/route";
-export async function GET(request, { params }) {
+export async function GET({ params }) {
const session = await getServerSession(authOptions);
if (!session) {
diff --git a/app/api/teams/create/route.js b/app/api/teams/create/route.js
index 569056c..023fcbd 100644
--- a/app/api/teams/create/route.js
+++ b/app/api/teams/create/route.js
@@ -1,4 +1,4 @@
-import { queryOne, run } from "../../../../lib/db";
+import { queryOne, run } from "@/lib/db";
import { getServerSession } from "next-auth/next";
import { authOptions } from "../../auth/[...nextauth]/route";
import { nanoid } from "nanoid";
@@ -7,9 +7,6 @@ export async function POST(request) {
try {
const session = await getServerSession(authOptions);
- // Debugging: Log the session
- console.log("Session:", session);
-
if (!session) {
return new Response(
JSON.stringify({ success: false, error: "Unauthorised" }),
@@ -17,7 +14,6 @@ export async function POST(request) {
);
}
- // Ensure the user is not an admin
if (session.user.role === "admin") {
return new Response(
JSON.stringify({ success: false, error: "Admins cannot create teams" }),
@@ -34,27 +30,19 @@ export async function POST(request) {
);
}
- // Generate a unique team code (6 characters)
const teamCode = nanoid(6).toUpperCase();
- // Insert the new team
- const result = await run("INSERT INTO teams (name, code) VALUES (?, ?)", [
- name,
- teamCode,
- ]);
+ await run("INSERT INTO teams (name, code) VALUES (?, ?)", [name, teamCode]);
- // Fetch the newly created team ID
const newTeam = await queryOne("SELECT id FROM teams WHERE code = ?", [
teamCode,
]);
- // Update the user's team_id
await run("UPDATE users SET team_id = ? WHERE id = ?", [
newTeam.id,
userId,
]);
- // Update the session with the new teamId
session.user.teamId = newTeam.id;
return new Response(JSON.stringify({ success: true, teamId: newTeam.id }), {
diff --git a/app/api/teams/route.js b/app/api/teams/route.js
index f1de0cc..45e27e5 100644
--- a/app/api/teams/route.js
+++ b/app/api/teams/route.js
@@ -1,6 +1,6 @@
-import { queryOne, query } from "../../../../lib/db";
+import { queryOne } from "@/lib/db";
import { getServerSession } from "next-auth/next";
-import { authOptions } from "../../auth/[...nextauth]/route";
+import { authOptions } from "@/app/api/auth/[...nextauth]/route";
export async function POST(request) {
const session = await getServerSession(authOptions);
diff --git a/app/layout.js b/app/layout.js
index b7c43e5..7eecd5b 100644
--- a/app/layout.js
+++ b/app/layout.js
@@ -1,12 +1,12 @@
-import './globals.css';
-import { NextAuthProvider } from './providers';
+import "./globals.css";
+import { NextAuthProvider } from "./providers";
export default function RootLayout({ children }) {
- return (
-
-
+ return (
+
+
{children}
-
-
- );
-}
\ No newline at end of file
+
+
+ );
+}
diff --git a/lib/db.js b/lib/db.js
index 08a720b..c2f3006 100644
--- a/lib/db.js
+++ b/lib/db.js
@@ -1,69 +1,52 @@
-// lib/db.js
-let sqlite3;
+import sqlite3 from "sqlite3";
-// Only import sqlite3 on server-side
-if (typeof window === 'undefined') {
- sqlite3 = require('sqlite3').verbose();
-}
+let db = null;
-// Initialize the database connection
-function getDb() {
- if (!sqlite3) {
- console.error('Cannot access SQLite on the client side');
- return null;
- }
-
- return new sqlite3.Database('./sqlite.db', (err) => {
- if (err) {
- console.error('Error opening database:', err.message);
- } else {
- console.log('Connected to the SQLite database.');
- }
+export function getDb() {
+ if (!db) {
+ db = new sqlite3.Database("./database.sqlite", (err) => {
+ if (err) {
+ console.error("Error connecting to database:", err);
+ } else {
+ console.log("Connected to the SQLite database.");
+ }
});
+ }
+ return db;
}
-// Helper function to run queries with results
-async function query(sql, params = []) {
- if (typeof window !== 'undefined') {
- throw new Error('Database queries cannot be executed on the client side');
- }
-
- const db = getDb();
- return new Promise((resolve, reject) => {
- db.all(sql, params, (err, rows) => {
- if (err) {
- reject(err);
- } else {
- resolve(rows);
- }
- db.close(); // Close the database connection
- });
+export function queryOne(sql, params = []) {
+ return new Promise((resolve, reject) => {
+ getDb().get(sql, params, (err, row) => {
+ if (err) {
+ reject(err);
+ } else {
+ resolve(row);
+ }
});
+ });
}
-// Helper for single row queries
-async function queryOne(sql, params = []) {
- const rows = await query(sql, params);
- return rows && rows.length > 0 ? rows[0] : null;
-}
-
-// Helper for insert/update/delete operations
-async function run(sql, params = []) {
- if (typeof window !== 'undefined') {
- throw new Error('Database operations cannot be executed on the client side');
- }
-
- const db = getDb();
- return new Promise((resolve, reject) => {
- db.run(sql, params, function(err) {
- if (err) {
- reject(err);
- } else {
- resolve({ lastID: this.lastID, changes: this.changes });
- }
- db.close(); // Close the database connection
- });
+export function query(sql, params = []) {
+ return new Promise((resolve, reject) => {
+ getDb().all(sql, params, (err, rows) => {
+ if (err) {
+ reject(err);
+ } else {
+ resolve(rows);
+ }
});
+ });
}
-module.exports = { query, queryOne, run };
\ No newline at end of file
+export function run(sql, params = []) {
+ return new Promise((resolve, reject) => {
+ getDb().run(sql, params, function (err) {
+ if (err) {
+ reject(err);
+ } else {
+ resolve({ lastID: this.lastID, changes: this.changes });
+ }
+ });
+ });
+}
diff --git a/package.json b/package.json
index 774fbf3..b2d80b8 100644
--- a/package.json
+++ b/package.json
@@ -2,11 +2,13 @@
"name": "clue-hunt-app",
"version": "0.1.0",
"private": true,
+ "type": "module",
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
- "lint": "next lint"
+ "lint": "next lint",
+ "init-db": "node lib/init-db.js"
},
"dependencies": {
"bcryptjs": "^3.0.2",
diff --git a/sqlite.db b/sqlite.db
index 75eb57d..62f33d6 100644
Binary files a/sqlite.db and b/sqlite.db differ