Team Name: {team.name}
@@ -235,45 +251,12 @@ export default function TeamPage({ params }) {
{/* New Start Hunt button with conditional behavior */}
- {session?.user?.role !== "admin" && (
-
- )}
+
{/* Replace the outdated navbar with the correct one */}
diff --git a/app/(main)/[teamId]/teamId.module.css b/app/(main)/[teamId]/teamId.module.css
new file mode 100644
index 0000000..ea5320a
--- /dev/null
+++ b/app/(main)/[teamId]/teamId.module.css
@@ -0,0 +1,14 @@
+.container {
+ display: flex;
+ flex-direction: column;
+ min-height: 100vh;
+ background-color: #f4f4f4;
+ font-family: Arial, sans-serif;
+ position: relative;
+ overflow-x: hidden;
+ width: 100%;
+ padding-bottom: 70px;
+}
+
+/* Note: Most styles are defined inline in the component,
+ but we're creating this file to fix the build error */
diff --git a/app/(main)/map/page.js b/app/(main)/map/page.js
index a83d252..96b428e 100644
--- a/app/(main)/map/page.js
+++ b/app/(main)/map/page.js
@@ -375,11 +375,11 @@ export default function MapPage() {
)
}
style={{
- left: "230px", // Moved from 150px to 160px (10px right)
- top: "212px", // Moved from 200px to 203px (3px down)
+ left: "230px",
+ top: "212px",
}}
>
- Clue {firstClue.id}
+ {/* Clue {firstClue.id} */}
)}
@@ -394,11 +394,12 @@ export default function MapPage() {
)
}
style={{
- left: "320px", // 168px + 50px = 218px
- top: "290px", // 208px + 30px = 238px
+ left: "320px",
+ top: "285px",
}}
>
- Clue {clues[1].id}
+ {/* Clue {clues[1].id} */}
+ {/* If clues are to be named uncomment the line above */}
)}
@@ -413,11 +414,11 @@ export default function MapPage() {
)
}
style={{
- left: "265px", // 168px + 50px = 218px
- top: "400px", // 208px + 30px = 238px
+ left: "265px",
+ top: "400px",
}}
>
- Clue {clues[2].id}
+ {/* Clue {clues[2].id} */}
)}
diff --git a/app/(main)/team-selection/page.js b/app/(main)/team-selection/page.js
index 6768f41..dece12b 100644
--- a/app/(main)/team-selection/page.js
+++ b/app/(main)/team-selection/page.js
@@ -1,11 +1,11 @@
"use client";
import { useState, useEffect } from "react";
-import { useSession } from "next-auth/react";
+import { useSession, signOut } from "next-auth/react";
import { useRouter } from "next/navigation";
import Link from "next/link";
export default function TeamSelection() {
- const { data: session, status } = useSession();
+ const { data: session, status, update: updateSession } = useSession();
const [teamCode, setTeamCode] = useState("");
const [error, setError] = useState("");
const [isLoading, setIsLoading] = useState(true);
@@ -53,28 +53,110 @@ export default function TeamSelection() {
setIsLoading(true);
setError("");
+ // Validate team code before submitting
+ if (!teamCode || teamCode.trim() === "") {
+ setError("Please enter a team code");
+ setIsLoading(false);
+ return;
+ }
+
+ // Clean the team code of any whitespace
+ const cleanedTeamCode = teamCode.trim().toUpperCase();
+ console.log("Joining team with code:", cleanedTeamCode);
+
try {
- const response = await fetch("/api/join-team", {
+ // First check if we have a valid session
+ if (status !== "authenticated" || !session?.user) {
+ console.log("Session not authenticated, refreshing session...");
+ await updateSession();
+
+ // If still not authenticated after refresh, redirect to login
+ if (status !== "authenticated") {
+ throw new Error(
+ "Your session appears to be invalid. Please log in again."
+ );
+ }
+ }
+
+ // Now attempt to join the team
+ const response = await fetch("/api/teams/join", {
method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify({ teamCode }),
+ headers: {
+ "Content-Type": "application/json",
+ "Cache-Control": "no-cache, no-store, must-revalidate",
+ },
+ body: JSON.stringify({ teamCode: cleanedTeamCode }),
+ credentials: "include",
});
- const data = await response.json();
+ // Improved error handling for response
+ let data;
+ try {
+ // First try to parse as JSON
+ const contentType = response.headers.get("content-type");
+ if (contentType && contentType.includes("application/json")) {
+ data = await response.json();
+ } else {
+ // If not JSON, get as text
+ const text = await response.text();
+ console.log("Non-JSON response:", text);
+ throw new Error(
+ `Unexpected response format: ${text.substring(0, 100)}...`
+ );
+ }
+ } catch (parseError) {
+ console.error("Error parsing response:", parseError);
+ throw new Error(
+ "Failed to parse server response: " + parseError.message
+ );
+ }
+ // Now check if the response was successful
if (!response.ok) {
- throw new Error(data.error || "Failed to join team");
+ console.error("Join team failed:", data);
+ throw new Error(
+ data.error || `Failed to join team (Status: ${response.status})`
+ );
}
// Add validation before constructing the URL
if (!data.teamId || isNaN(parseInt(data.teamId))) {
- throw new Error("Invalid team ID received");
+ throw new Error("Invalid team ID received from server");
}
- // Navigate to the team page using the correct URL format
- window.location.href = `/${data.teamId}`;
+ console.log("Join team successful:", data);
+
+ // Update the session with new team info
+ if (data.token) {
+ try {
+ await updateSession();
+ console.log("Session updated successfully");
+ } catch (sessionErr) {
+ console.warn("Session update failed:", sessionErr);
+ }
+ }
+
+ // Navigate to the team page
+ router.push(`/${data.teamId}`);
} catch (err) {
- setError(err.message);
+ console.error("Join team error:", err);
+
+ // If it's an "Invalid session" error, suggest reauthentication
+ if (
+ err.message.includes("session") ||
+ err.message.includes("unauthorized") ||
+ err.message.includes("Unauthorized")
+ ) {
+ setError("Your session has expired. Please log in again.");
+ // Attempt to sign out and redirect to login
+ await signOut({ redirect: false });
+ setTimeout(() => {
+ router.push("/login?error=session_expired");
+ }, 2000);
+ } else {
+ setError(err.message);
+ }
+
setIsLoading(false);
}
};
@@ -100,7 +182,7 @@ export default function TeamSelection() {
type="text"
placeholder="Team Code"
value={teamCode}
- onChange={(e) => setTeamCode(e.target.value)}
+ onChange={(e) => setTeamCode(e.target.value.toUpperCase())}
required
className="auth-input"
/>
@@ -118,8 +200,6 @@ export default function TeamSelection() {