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 }) {
Add Users
- {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