Refactor team page data fetching; use useCallback for fetch function, improve error handling, and add user actions for leaving team and starting hunt

This commit is contained in:
bobbert committed 2025-03-12 17:02:41 +00:00
1 parent 77e83dc21c
commit ce962162cb
2 files changed
+281 -114

No files matched your search

+128 -72
View File
@@ -1,5 +1,5 @@
"use client";
import { useState, useEffect } from "react";
import { useState, useEffect, useCallback } from "react";
import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation";
import Link from "next/link";
@@ -13,65 +13,126 @@ export default function TeamPage({ params }) {
const router = useRouter();
const { teamId } = params;
useEffect(() => {
async function fetchTeamData() {
try {
if (!teamId || isNaN(parseInt(teamId, 10))) {
throw new Error("Invalid team ID");
}
// Fix the API endpoint path - ensure it matches your route structure
const response = await fetch(`/api/teams/${teamId}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
credentials: "include",
});
// Add better error handling for debugging
if (!response.ok) {
const text = await response.text();
let errorMessage;
try {
const errorData = JSON.parse(text);
errorMessage = errorData.error || "Failed to fetch team data";
} catch (unused) {
// Using 'unused' instead of '_' to avoid the warning
errorMessage = `Failed to fetch team data: ${
response.status
} ${text.slice(0, 100)}`;
}
throw new Error(errorMessage);
}
const data = await response.json();
if (!data.team) {
throw new Error("Team not found");
}
setTeam(data.team);
setTeamMembers(data.members || []);
} catch (err) {
console.error("Team page error:", err);
setError(err.message);
} finally {
setLoading(false);
const fetchTeamData = useCallback(async () => {
try {
if (!teamId || isNaN(parseInt(teamId, 10))) {
throw new Error("Invalid team ID");
}
}
const response = await fetch(`/api/teams/${teamId}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
credentials: "include",
});
if (!response.ok) {
const text = await response.text();
let errorMessage;
try {
const errorData = JSON.parse(text);
errorMessage = errorData.error || "Failed to fetch team data";
} catch (unused) {
errorMessage = `Failed to fetch team data: ${
response.status
} ${text.slice(0, 100)}`;
}
throw new Error(errorMessage);
}
const data = await response.json();
if (!data.team) {
throw new Error("Team not found");
}
setTeam(data.team);
setTeamMembers(data.members || []);
setError("");
} catch (err) {
console.error("Team page error:", err);
setError(err.message);
// If we get a 401 error, redirect to login
if (err.message.includes("401")) {
router.push("/login");
}
} finally {
setLoading(false);
}
}, [teamId, router]);
useEffect(() => {
if (status === "authenticated" && teamId) {
fetchTeamData();
const interval = setInterval(fetchTeamData, 5000); // Refresh every 5 seconds
return () => clearInterval(interval);
}
}, [teamId, status]);
useEffect(() => {
if (status === "unauthenticated") {
} else if (status === "unauthenticated") {
router.push("/login");
}
}, [status, router]);
}, [teamId, status, fetchTeamData, router]);
const handleLeaveTeam = async () => {
try {
setLoading(true);
const response = await fetch(`/api/teams/${teamId}/leave`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
credentials: "include",
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || "Failed to leave team");
}
// Redirect to team selection after leaving
router.push("/team-selection");
} catch (err) {
console.error("Leave team error:", err);
setError(err.message);
} finally {
setLoading(false);
}
};
const handleStartHunt = async () => {
try {
if (session?.user?.role !== "admin") {
setError("Only admins can start a hunt");
return;
}
setLoading(true);
const response = await fetch(`/api/teams/${teamId}/start-hunt`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
credentials: "include",
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || "Failed to start hunt");
}
// You could redirect to a hunt page or refresh the current page
// For now, just refresh the team data
await fetchTeamData();
} catch (err) {
console.error("Start hunt error:", err);
setError(err.message);
} finally {
setLoading(false);
}
};
const handleAddUser = () => {
// Navigate to add user page or open a modal
router.push(`/team/${teamId}/add-user`);
};
if (status === "loading" || loading) {
return <div className="loading">Loading...</div>;
@@ -97,54 +158,49 @@ export default function TeamPage({ params }) {
</div>
<div className="content-container">
<div className="add-users-button">Add Users</div>
<div className="add-users-button" onClick={handleAddUser}>
Add Users
</div>
<div className="users-container">
{teamMembers.map((member) => (
<div key={member.id} className="user-card">
{member.username}
{member.username} {member.id === session?.user?.id && "(You)"}
</div>
))}
<div className="add-user-icon">
<div className="add-user-icon" onClick={handleAddUser}>
<div className="plus-icon">+</div>
</div>
</div>
</div>
<div className="team-footer">
<button
className="leave-button"
onClick={() => {
/* implement leave logic */
}}
>
<button className="leave-button" onClick={handleLeaveTeam}>
Leave Team
</button>
<button
className="start-hunt-button"
disabled={session?.user?.role !== "admin"}
onClick={() => {
/* implement start-hunt logic */
}}
onClick={handleStartHunt}
>
Start Hunt
</button>
</div>
<div className="navbar">
<div className="nav-item">
<Link href="/dashboard" className="nav-item">
<div className="nav-icon">🏠</div>
</div>
<div className="nav-item">
</Link>
<Link href="/leaderboard" className="nav-item">
<div className="nav-icon">📊</div>
</div>
<div className="nav-item">
</Link>
<Link href="/achievements" className="nav-item">
<div className="nav-icon">🏆</div>
</div>
<div className="nav-item">
</Link>
<Link href="/profile" className="nav-item">
<div className="nav-icon">👤</div>
</div>
</Link>
</div>
<style jsx>{`