Skip to content

Commit

Permalink
Merge pull request #64 from Saurabhchaddha6/master
Browse files Browse the repository at this point in the history
manage tournaments
  • Loading branch information
dinxsh authored Jul 26, 2024
2 parents ea00abd + d60004c commit 2d6e210
Show file tree
Hide file tree
Showing 4 changed files with 330 additions and 0 deletions.
25 changes: 25 additions & 0 deletions app/api/participants/route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { NextResponse } from "next/server";
import dbConnect from "../../../lib/dbConnect";
import UserModel from "../../../models/UserModel";

export async function POST(request) {
try {
await dbConnect();
const body = await request.json();
const { tournamentId, participantName, userId } = body;

const user = await UserModel.findById(userId);
if (!user) {
return NextResponse.json({ message: "User not found" }, { status: 404 });
}

user.eventsRegistered.push(tournamentId);

await user.save();

return NextResponse.json({ message: "Participant added successfully", user });
} catch (error) {
console.error("Error adding participant:", error);
return NextResponse.json({ message: "An error occurred while adding the participant" }, { status: 500 });
}
}
30 changes: 30 additions & 0 deletions app/api/tournaments/[id]/registration/route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { NextResponse } from "next/server";
import dbConnect from "../../../../../lib/dbConnect";
import Tournament from "../../../../../models/Tournament";

export default async function POST(request, { params }) {
await dbConnect();

const id = params.id;
const { registrationData } = await request.json();

try {
const updatedTournament = await Tournament.findByIdAndUpdate(
id,
{ registrations: registrationData },
{ new: true }
);

if (!updatedTournament) {
return NextResponse.status(404).json({ message: "Tournament not found" });
}

return NextResponse.status(200).json({
message: "Registration updated successfully",
tournament: updatedTournament
});
} catch (error) {
console.error("Error while updating tournament", error);
return NextResponse.status(500).json({ message: "Error while updating the registration" });
}
}
32 changes: 32 additions & 0 deletions app/api/tournaments/[id]/structure/route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { NextResponse } from "next/server";
import dbConnect from "../../../../../lib/dbConnect";
import Tournament from "../../../../../models/Tournament";

export default async function POST(request, { params }) {
await dbConnect();

const id = params.id; // Extract the tournament ID from params
const { structureData } = await request.json(); // Correctly parse the request body

try {
const updatedTournament = await Tournament.findByIdAndUpdate(
id,
{ structure: structureData },
{ new: true }
);

if (!updatedTournament) {
return NextResponse.status(404).json({ message: "Tournament not found" });
}

return NextResponse.json({
message: "Tournament structure updated successfully",
tournament: updatedTournament,
});
} catch (error) {
console.error("Error updating tournament structure", error);
return NextResponse.json({
message: "An error occurred while updating the tournament structure",
}, { status: 500 });
}
}
243 changes: 243 additions & 0 deletions app/manage-tournaments/page.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
"use client";
import React, { useState, useEffect } from "react";
import axios from "axios";

export default function Page() {
const [tournaments, setTournaments] = useState([]);
const [newParticipantName, setNewParticipantName] = useState("");
const [selectedTournamentId, setSelectedTournamentId] = useState(null);
const [tournamentDetails, setTournamentDetails] = useState({});
const [loading, setLoading] = useState(false);
const [stageName, setStageName] = useState(""); // Added missing state for stage name

useEffect(() => {
async function fetchTournaments() {
try {
const response = await axios.get("/api/tournaments");
setTournaments(response.data);
} catch (error) {
console.error("Error fetching tournaments:", error);
}
}
fetchTournaments();
}, []);

useEffect(() => {
if (selectedTournamentId) {
fetchTournamentDetails(selectedTournamentId);
}
}, [selectedTournamentId]);

const fetchTournamentDetails = async (tournamentId) => {
try {
const response = await axios.get(`/api/tournaments/${tournamentId}`);
setTournamentDetails(response.data);
} catch (error) {
console.error("Error fetching tournament details:", error);
}
};

const addParticipant = async () => {
if (!selectedTournamentId || !newParticipantName) return;

try {
setLoading(true);
const response = await axios.post("/api/participants", {
tournamentId: selectedTournamentId,
participantName: newParticipantName,
});

console.log("Participant added:", response.data.participant);
setNewParticipantName("");
fetchTournamentDetails(selectedTournamentId); // Refresh details
} catch (error) {
console.error("Error adding participant:", error);
} finally {
setLoading(false);
}
};

const handleCreateStage = async () => {
if (!selectedTournamentId || !stageName) return;

try {
setLoading(true);
const response = await axios.post(`/api/tournaments/${selectedTournamentId}/structure`, {
structureData: { name: stageName }, // Send the new stage data
});

console.log("Stage created:", response.data.tournament);
setStageName(""); // Clear input after success
fetchTournamentDetails(selectedTournamentId); // Refresh details
} catch (error) {
console.error("Error creating stage:", error);
} finally {
setLoading(false);
}
};

const handleEnableRegistration = async () => {
if (!selectedTournamentId) return;

try {
const response = await axios.put(`/api/tournaments/${selectedTournamentId}`, {
registrationData: {
enabled: true,
},
});

console.log("Registration enabled:", response.data.tournament);
fetchTournamentDetails(selectedTournamentId); // Refresh details
} catch (error) {
console.error("Error enabling registration:", error);
}
};

return (
<div className="px-[5%] xl:px-[18%] pt-20 pb-20 transition-all">
<div className="p-4">
<h1 className="text-2xl font-sans">Manage Tournaments</h1>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 p-4">
{tournaments.map((tournament) => (
<div
key={tournament.id}
className="box-content p-8 bg-white rounded-md border-2 border-slate-700 shadow-lg"
>
<div className="flex flex-row justify-between items-center mb-4">
<div className="text-black">{tournament.tournamentName}</div>
<div
className={`bg-${
tournament.status === "Draft" ? "orange" : "green"
}-500 rounded-sm p-1 text-white`}
>
{tournament.status}
</div>
</div>
<div className="text-slate-700 text-xs mb-4">
{tournament.platform}
</div>
<div className="flex flex-row justify-between items-center text-sm mb-4">
<div className="text-black">SETUP</div>
<div className="text-slate-700">PENDING</div>
<div className="text-slate-700">RUNNING</div>
</div>
<div className="w-full bg-gray-200 rounded-full h-2.5 dark:bg-blue-300 mb-4">
<div
className="bg-blue-600 h-2.5 rounded-full"
style={{ width: "45%" }}
></div>
</div>
<div className="flex align-top">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className="w-6 h-6 mr-2"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M11.25 11.25l.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z"
/>
</svg>
<p className="text-black text-xs">
You should now enable the registration or manually add
participants. You could also create the tournament structure.
</p>
</div>
</div>
))}
<div className="box-content p-8 bg-white rounded-md border-2 border-slate-700 shadow-lg">
<div className="flex flex-row justify-between items-center mb-4">
<div className="text-black text-xl font-sans">Participants</div>
<div
className="text-green-500 text-xl font-sans cursor-pointer"
onClick={addParticipant}
>
+ADD
</div>
</div>
<div className="text-slate-600 text-sm text-center mb-4">
You can manually create participants, especially if you do not use
the registration. You may configure the check-in either way.
</div>
<div className="flex flex-col items-center">
<select
className="mb-2 border-2 border-slate-700 rounded-md"
onChange={(e) => setSelectedTournamentId(e.target.value)}
value={selectedTournamentId}
>
<option value="">Select Tournament</option>
{tournaments.map((tournament) => (
<option key={tournament.id} value={tournament.id}>
{tournament.tournamentName}
</option>
))}
</select>
<input
type="text"
className="mb-2 border-2 border-slate-700 rounded-md p-2"
placeholder="Participant Name"
value={newParticipantName}
onChange={(e) => setNewParticipantName(e.target.value)}
/>
<button
className="p-3 bg-green-400 rounded-md text-white"
onClick={addParticipant}
disabled={loading}
>
{loading ? "Adding..." : "+Add Participant"}
</button>
</div>
<div className="text-blue-500 text-center cursor-pointer">
Configure check-in
</div>
</div>
<div className="box-content p-8 bg-white rounded-md border-2 border-slate-700 shadow-lg">
<div className="text-black text-xl font-sans mb-4">Structure</div>
<div className="text-center text-slate-500 text-sm mb-4">
The tournament does not have any stage yet. You should create the
first stage and may use our Structure Guide if you are not sure of
which stage to create.
</div>
<div className="flex flex-col items-center">
<input
type="text"
className="mb-2 border-2 border-slate-700 rounded-md p-2"
placeholder="Stage Name"
value={stageName}
onChange={(e) => setStageName(e.target.value)}
/>
<button
className="p-3 bg-green-400 rounded-md text-white"
onClick={handleCreateStage}
disabled={loading}
>
{loading ? "Creating..." : "+Create new stage"}
</button>
</div>
</div>
<div className="box-content p-8 bg-white rounded-md border-2 border-slate-700 shadow-lg">
<div className="text-black text-xl font-sans mb-4">Registrations</div>
<div className="text-slate-500 text-sm mb-4">
Enable the registration to have participants register to the
tournament. They will enjoy all the participants features the
platform offers: check-in, matches list, results report, and more.
</div>
<div className="flex justify-center">
<button
className="p-3 bg-blue-400 rounded-md text-white"
onClick={handleEnableRegistration}
disabled={loading}
>
{loading ? "Enabling..." : "Enable Registration"}
</button>
</div>
</div>
</div>
</div>
);
}

0 comments on commit 2d6e210

Please sign in to comment.