From bb763f1249e85e8220c24f6243bcf7188c0cd142 Mon Sep 17 00:00:00 2001 From: Vaibhav Rathod Date: Sun, 22 Mar 2026 15:20:46 +0530 Subject: [PATCH 1/2] Add in tournamenthub.tsx --- frontend/src/Pages/TournamentHub.tsx | 104 ++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 3 deletions(-) diff --git a/frontend/src/Pages/TournamentHub.tsx b/frontend/src/Pages/TournamentHub.tsx index be73f1c6..15e97f5e 100644 --- a/frontend/src/Pages/TournamentHub.tsx +++ b/frontend/src/Pages/TournamentHub.tsx @@ -47,9 +47,33 @@ export default function TournamentPage() { const [name, setName] = useState(""); const [date, setDate] = useState(""); const [description, setDescription] = useState(""); + // Fix 3: added participantOption state instead of hardcoding 8 + const [participantOption, setParticipantOption] = useState("8"); + const [customParticipants, setCustomParticipants] = useState(""); + const [customError, setCustomError] = useState(""); const [error, setError] = useState(""); const navigate = useNavigate(); + // Derives the final maxParticipants value; returns null if custom input is invalid + const isPowerOfTwo = (n: number) => n > 1 && (n & (n - 1)) === 0; + + const getMaxParticipants = (): number | null => { + if (participantOption === "custom") { + const val = parseInt(customParticipants); + if (isNaN(val) || val < 4) { + setCustomError("Must be at least 4."); + return null; + } + if (!isPowerOfTwo(val)) { + setCustomError("Must be a power of 2 (e.g. 4, 8, 16, 32, 64...)."); + return null; + } + setCustomError(""); + return val; + } + return parseInt(participantOption); + }; + const handleCreate = (e: FormEvent) => { e.preventDefault(); if (!name) { @@ -57,10 +81,13 @@ export default function TournamentPage() { return; } + const maxParticipants = getMaxParticipants(); + if (maxParticipants === null) return; + const newTournament: Tournament = { id: Date.now().toString(), name, - maxParticipants: 8, + maxParticipants, currentParticipants: 0, date, description, @@ -70,6 +97,9 @@ export default function TournamentPage() { setName(""); setDate(""); setDescription(""); + setParticipantOption("8"); + setCustomParticipants(""); + setCustomError(""); setError(""); }; @@ -96,9 +126,14 @@ export default function TournamentPage() { navigate(`/tournament/${tournament.id}/bracket`, { state: { tournament } }); }; + // Fix: cap visible avatars at 6, show +N badge for the rest to prevent card overflow const renderAvatars = (current: number, max: number) => { const avatars = []; - for (let i = 0; i < max; i++) { + const MAX_VISIBLE = 6; + const visible = Math.min(max, MAX_VISIBLE); + const overflow = max - MAX_VISIBLE; + + for (let i = 0; i < visible; i++) { const isActive = i < current; avatars.push(
); } + + if (overflow > 0) { + avatars.push( +
+
+ +{overflow} +
+
+ ); + } + return avatars; }; @@ -139,7 +189,7 @@ export default function TournamentPage() { {tournaments.map((t) => (

@@ -225,14 +275,62 @@ export default function TournamentPage() { + {/* Fix 2: min attribute prevents selecting past dates */} setDate(e.target.value)} required + min={new Date().toISOString().split("T")[0]} className="mt-1 block w-full border border-input rounded-md p-3 bg-background text-foreground focus:ring-2 focus:ring-primary focus:border-transparent transition" />

+ {/* Fix 3: Max Participants selector with custom option */} +
+ + + {/* Custom number input — only shown when "Custom..." is selected */} + {participantOption === "custom" && ( +
+ { + setCustomParticipants(e.target.value); + setCustomError(""); + }} + min={4} + step={1} + placeholder="e.g. 12, 20, 32" + className="block w-full border border-input rounded-md p-3 bg-background text-foreground focus:ring-2 focus:ring-primary focus:border-transparent transition" + /> + {customError ? ( +

+ {customError} +

+ ) : ( +

+ Must be a power of 2 (e.g. 4, 8, 16, 32, 64...) +

+ )} +
+ )} +
- {/* Fix 3: Max Participants selector with custom option */}
); -} +} \ No newline at end of file