🏠
@@ -214,6 +243,30 @@ export default function TeamPage({ params }) {
color: black;
}
+ .team-footer {
+ display: flex;
+ justify-content: space-around;
+ padding: 15px 0;
+ background-color: #c8b6a6;
+ }
+
+ .leave-button,
+ .start-hunt-button {
+ background-color: #e9c46a;
+ color: black;
+ padding: 10px 20px;
+ border: none;
+ border-radius: 5px;
+ font-weight: bold;
+ cursor: pointer;
+ }
+
+ .leave-button:disabled,
+ .start-hunt-button:disabled {
+ background-color: #ccc;
+ cursor: not-allowed;
+ }
+
.navbar {
display: flex;
justify-content: space-around;
diff --git a/app/api/auth/[...nextauth]/route.js b/app/api/auth/[...nextauth]/route.js
index 1d02ad8..26ea97b 100644
--- a/app/api/auth/[...nextauth]/route.js
+++ b/app/api/auth/[...nextauth]/route.js
@@ -1,33 +1,49 @@
+export const runtime = "nodejs";
import NextAuth from "next-auth";
-import CredentialsProvider from "next-auth/providers/credentials";
import { validateCredentials } from "@/actions/auth";
+// Ensure NEXTAUTH_SECRET is defined
+if (!process.env.NEXTAUTH_SECRET) {
+ console.error("Warning: NEXTAUTH_SECRET is not defined");
+}
+
+// Ensure NEXTAUTH_URL is defined
+if (!process.env.NEXTAUTH_URL) {
+ console.error("Warning: NEXTAUTH_URL is not defined");
+}
+
export const authOptions = {
debug: process.env.NODE_ENV === "development",
providers: [
- CredentialsProvider({
+ {
id: "credentials",
name: "Credentials",
+ type: "credentials",
credentials: {
username: { label: "Username", type: "text" },
password: { label: "Password", type: "password" },
},
async authorize(credentials) {
- if (!credentials?.username || !credentials?.password) return null;
- const user = await validateCredentials(
- credentials.username,
- credentials.password
- );
- return user
- ? {
- id: user.id,
- username: user.username,
- role: user.role,
- teamId: user.teamId,
- }
- : null;
+ try {
+ if (!credentials?.username || !credentials?.password) return null;
+ const user = await validateCredentials(
+ credentials.username,
+ credentials.password
+ );
+ return user
+ ? {
+ id: user.id,
+ username: user.username,
+ role: user.role,
+ teamId: user.teamId,
+ }
+ : null;
+ } catch (error) {
+ console.error("NextAuth authorize error:", error);
+ return null;
+ }
},
- }),
+ },
],
callbacks: {
async jwt({ token, user }) {
@@ -50,10 +66,11 @@ export const authOptions = {
return session;
},
},
- pages: { signIn: "/login" },
+ // no "pages" property
session: { strategy: "jwt", maxAge: 30 * 24 * 60 * 60 },
secret: process.env.NEXTAUTH_SECRET,
};
+// Creating the handler after exporting authOptions
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
diff --git a/app/api/hunt/route.js b/app/api/hunt/route.js
new file mode 100644
index 0000000..3b18de2
--- /dev/null
+++ b/app/api/hunt/route.js
@@ -0,0 +1,25 @@
+import { getServerSession } from "next-auth/next";
+import { authOptions } from "../auth/[...nextauth]/route";
+import { run } from "@/lib/db";
+
+export async function POST(request) {
+ const session = await getServerSession(authOptions);
+ if (!session || session.user.role !== "admin") {
+ return new Response(JSON.stringify({ error: "Unauthorized" }), {
+ status: 401,
+ });
+ }
+
+ try {
+ // Add a WHERE clause or provide an ID if you're updating a specific hunt record
+ await run("UPDATE hunts SET active = 1, start_time = NOW() WHERE id = ?", [1]);
+ // Or if you just have one hunt record: "UPDATE hunts SET active = 1, start_time = NOW()"
+
+ return new Response(JSON.stringify({ success: true }), { status: 200 });
+ } catch (err) {
+ console.error("Hunt start error:", err); // Add logging for better debugging
+ return new Response(JSON.stringify({ error: err.message }), {
+ status: 500,
+ });
+ }
+}
diff --git a/app/api/teams/[teamId]/route.js b/app/api/teams/[teamId]/route.js
index cab71cc..c891b6b 100644
--- a/app/api/teams/[teamId]/route.js
+++ b/app/api/teams/[teamId]/route.js
@@ -1,50 +1,43 @@
-import { queryOne, query } from "../../../../lib/db";
+import { query, queryOne } from "@/lib/db";
import { getServerSession } from "next-auth/next";
import { authOptions } from "../../auth/[...nextauth]/route";
-export async function GET({ params }) {
+export async function GET(request, context) {
const session = await getServerSession(authOptions);
if (!session) {
- return new Response(JSON.stringify({ error: "Unauthorized" }), {
- status: 401,
- });
+ return Response.json({ error: "Unauthorized" }, { status: 401 });
}
try {
- const teamId = parseInt(params.teamId, 10);
- if (isNaN(teamId)) {
- return new Response(JSON.stringify({ error: "Invalid team ID" }), {
- status: 400,
- });
+ const teamId = context.params.teamId;
+
+ // Validate teamId
+ if (!teamId || isNaN(parseInt(teamId, 10))) {
+ return Response.json({ error: "Invalid team ID" }, { status: 400 });
}
- const team = await queryOne(
- "SELECT id, name, code FROM teams WHERE id = ?",
- [teamId]
- );
+ const team = await queryOne("SELECT * FROM teams WHERE id = ?", [teamId]);
if (!team) {
- return new Response(JSON.stringify({ error: "Team not found" }), {
- status: 404,
- });
+ return Response.json({ error: "Team not found" }, { status: 404 });
}
const members = await query(
- "SELECT id, username FROM users WHERE team_id = ?",
+ "SELECT id, username FROM users WHERE team_id = ?",
[teamId]
);
- return new Response(JSON.stringify({ team, members }), {
- status: 200,
- headers: {
- "Content-Type": "application/json",
- },
- });
+ return Response.json({
+ 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" }),
+ return Response.json(
+ { error: "Failed to fetch team data" },
{ status: 500 }
);
}
diff --git a/database.sqlite b/database.sqlite
index 19ecf54..05bc2d1 100644
Binary files a/database.sqlite and b/database.sqlite differ
diff --git a/init-schema.sql b/init-schema.sql
index e433ac8..f2a7231 100644
--- a/init-schema.sql
+++ b/init-schema.sql
@@ -44,6 +44,22 @@ CREATE TABLE game_settings (
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
+-- Execute this in your database:
+CREATE TABLE IF NOT EXISTS hunts (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ active BOOLEAN DEFAULT FALSE,
+ start_time DATETIME DEFAULT NULL,
+ end_time DATETIME DEFAULT NULL,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
+);
+
+-- Insert a default hunt row if none exists:
+INSERT INTO hunts (active)
+SELECT FALSE
+WHERE NOT EXISTS (SELECT 1 FROM hunts LIMIT 1);
+
+
+
-- Insert initial admin user
INSERT INTO users (username, password, role)
VALUES ('admin', '$2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy', 'admin');
diff --git a/package-lock.json b/package-lock.json
index 53313e9..3390362 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -46,9 +46,9 @@
}
},
"node_modules/@babel/runtime": {
- "version": "7.26.9",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.9.tgz",
- "integrity": "sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==",
+ "version": "7.26.10",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.10.tgz",
+ "integrity": "sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==",
"license": "MIT",
"dependencies": {
"regenerator-runtime": "^0.14.0"
diff --git a/yarn.lock b/yarn.lock
index ef65a7d..7f51566 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8,9 +8,9 @@
integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==
"@babel/runtime@^7.20.13":
- version "7.26.9"
- resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.9.tgz"
- integrity sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==
+ version "7.26.10"
+ resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.10.tgz"
+ integrity sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==
dependencies:
regenerator-runtime "^0.14.0"