-
Notifications
You must be signed in to change notification settings - Fork 60
Add Loading States for Tournament Data in TournamentHub and TournamentBracketPage #106 #107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
WalkthroughIntroduces loading states and skeleton UIs in TournamentHub and TournamentBracket pages with simulated async data fetching; converts tournament bracket to data-driven rendering using a Participant interface; adds global CSS variables for theming, base styles, and animations; updates HTML title to “DebateAI.” Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Hub as TournamentHub
participant Timer as Simulated API (setTimeout)
participant State as React State
participant UI as UI
User->>Hub: Navigate to TournamentHub
Hub->>State: set isLoading = true, tournaments = []
Hub->>Timer: request tournaments (simulate 1s)
alt Loading
State-->>UI: Render skeleton cards/title (animate-pulse)
end
Timer-->>Hub: Return initialTournaments
Hub->>State: set tournaments, isLoading = false
State-->>UI: Render tournament cards and Create form
sequenceDiagram
autonumber
actor User
participant Bracket as TournamentBracketPage
participant Timer as Simulated API (setTimeout)
participant State as React State
participant UI as UI
User->>Bracket: Open Bracket Page
Bracket->>State: set isLoading = true, participants = []
Bracket->>Timer: request participants (simulate delay)
alt Loading
State-->>UI: Render bracket skeletons (animate-pulse)
end
Timer-->>Bracket: Return participants[]
Bracket->>Bracket: Compute round1Winners → semiFinalWinners → champion
Bracket->>State: set participants, isLoading = false
State-->>UI: Render dynamic bracket (R1, SF, Final, Champion)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (1)
frontend/src/Pages/TournamentHub.tsx (1)
117-121
: Add error handling for external avatar images.Similar to the bracket page, avatar URLs use an external service without fallback handling. This duplicates the issue identified in
TournamentBracketPage.tsx
.Consider extracting avatar rendering logic into a shared component to avoid duplication and ensure consistent error handling across both tournament pages.
Example shared component:
// components/ParticipantAvatar.tsx interface Props { src: string; alt: string; className?: string; } export function ParticipantAvatar({ src, alt, className }: Props) { const [imgSrc, setImgSrc] = useState(src); return ( <img src={imgSrc} alt={alt} onError={() => setImgSrc('/default-avatar.png')} className={className} /> ); }
🧹 Nitpick comments (3)
frontend/src/index.css (1)
115-129
: Remove unused animation or document its purpose.The
floatUp
animation and.animate-floating
class are defined but not referenced in any of the changed files in this PR.If this animation is intended for future use, consider adding a comment explaining its purpose. Otherwise, remove it to keep the codebase clean:
-/* Floating animation */ -@keyframes floatUp { - 0% { - transform: translateY(0); - opacity: 1; - } - 100% { - transform: translateY(-150px); - opacity: 0; - } -} - -.animate-floating { - animation: floatUp 2s ease-out forwards; -}frontend/src/Pages/TournamentBracketPage.tsx (1)
18-25
: Handle potential failures when loading external avatar images.The avatar URLs use an external service (
https://i.pravatar.cc/
) without error handling. If this service is unavailable or rate-limited, avatars will fail to load, degrading the user experience.Consider adding:
- Fallback avatars using the
onError
event handler- A local default avatar image
- Or generate avatar placeholders using the user's initials
Example implementation:
<img src={participant.avatar} alt={participant.name} onError={(e) => { e.currentTarget.src = '/default-avatar.png'; }} className="w-full h-full object-cover" />Or use a library like
react-avatar
for more robust avatar generation.frontend/src/Pages/TournamentHub.tsx (1)
16-62
: MoveinitialTournaments
outside the component to prevent unnecessary re-renders.The
initialTournaments
array is defined inside the component body, creating a new reference on every render. While the currentuseEffect
has an empty dependency array, this pattern is inefficient and could cause issues if the data is later added as a dependency.Move the constant outside the component:
+const initialTournaments: Tournament[] = [ + { + id: '1', + name: 'Spring Showdown', + maxParticipants: 8, + currentParticipants: 6, + date: '2025-04-20', + description: + 'Compete in our annual spring debate championship with top contenders from around the globe.', + }, + // ... rest of tournaments +]; + export default function TournamentPage() { - const initialTournaments: Tournament[] = [ - { - id: '1', - name: 'Spring Showdown', - // ... - }, - // ... - ]; - const [tournaments, setTournaments] = useState<Tournament[]>([]);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
frontend/index.html
(1 hunks)frontend/src/Pages/TournamentBracketPage.tsx
(1 hunks)frontend/src/Pages/TournamentHub.tsx
(4 hunks)frontend/src/index.css
(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/src/Pages/TournamentBracketPage.tsx (1)
backend/routes/rooms.go (1)
Participant
(28-32)
🔇 Additional comments (3)
frontend/index.html (1)
7-7
: LGTM!The title update appropriately reflects the application branding.
frontend/src/Pages/TournamentHub.tsx (1)
137-139
: Verify consistent animation usage across loading states.The title uses
animate-pulse
in both the loading skeleton (line 137) and the actual page (line 160), causing it to pulse indefinitely even after data loads. This might be intentional for visual flair, but if it's meant only for loading states, it should be removed from line 160.If the pulsing title is intentional for the loaded state, consider adding a comment to clarify this design choice. Otherwise, remove it:
- <h1 className="text-4xl sm:text-5xl font-extrabold mb-10 text-center text-primary animate-pulse"> + <h1 className="text-4xl sm:text-5xl font-extrabold mb-10 text-center text-primary"> Tournament Arena </h1>frontend/src/index.css (1)
90-93
: Retain global@apply border-border
This rule only sets the default border-color (no borders are added) and is intentionally used so all Tailwind border utilities inherit the theme’s border color.Likely an incorrect or invalid review comment.
interface Participant { | ||
id: number; | ||
name: string; | ||
avatar: string; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Align the Participant interface with the backend schema.
The frontend Participant
interface doesn't match the backend's Participant
struct from backend/routes/rooms.go
(lines 27-31). The backend defines:
id
asstring
(frontend usesnumber
)username
instead ofname
elo
(rating) instead ofavatar
This mismatch will cause integration issues when connecting to the real API.
Apply this diff to align with the backend:
interface Participant {
- id: number;
- name: string;
- avatar: string;
+ id: string;
+ username: string;
+ elo: number;
+ avatar?: string; // Optional if you plan to derive it from the username or ID
}
Then update the mock data (lines 17-26) and all references to participant.name
throughout the file to use participant.username
.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
interface Participant { | |
id: number; | |
name: string; | |
avatar: string; | |
} | |
interface Participant { | |
id: string; | |
username: string; | |
elo: number; | |
avatar?: string; // Optional if you plan to derive it from the username or ID | |
} |
🤖 Prompt for AI Agents
In frontend/src/Pages/TournamentBracketPage.tsx around lines 4 to 8 (and update
mock data at lines 17 to 26), the Participant interface must match
backend/routes/rooms.go: change id: number to id: string, rename name to
username (string), and replace avatar with elo: number; then update the mock
participant objects at lines 17-26 to use id as strings, username properties,
and an elo number, and replace all usages of participant.name in this file with
participant.username so types and runtime behavior align with the backend.
const round1Winners = [participants[0], participants[2], participants[4], participants[7]]; | ||
const semiFinalWinners = [round1Winners[0], round1Winners[3]]; | ||
const champion = semiFinalWinners[1]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace hard-coded winners with actual match results.
The bracket logic hard-codes winners by selecting specific array indices rather than determining winners based on actual match results. This means the bracket will always show the same winners regardless of the tournament data.
For the simulated data, consider one of these approaches:
- Add a
winner
property to mock data: Include match results in your simulated API response - Add match result state: Allow the UI to accept or simulate match outcomes
- Document as placeholder logic: If this is intentional for now, add a TODO comment
Example for approach 1:
useEffect(() => {
const timer = setTimeout(() => {
const data: Participant[] = [
// ... participant data ...
];
+ // Mock match results (in production, this comes from the API)
+ const matchResults = {
+ round1Winners: [0, 2, 4, 7], // indices of winners
+ semiFinalWinners: [0, 7],
+ championId: 7
+ };
setParticipants(data);
+ setMatchResults(matchResults);
setIsLoading(false);
}, 1000);
return () => clearTimeout(timer);
}, []);
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In frontend/src/Pages/TournamentBracketPage.tsx around lines 62-64 the code
currently hard-codes winners using specific participant indices which forces the
same bracket outcome; instead compute winners from the actual match data or
simulated results: update the mock API response to include a winner property on
each match (or add local matchResult state), then derive round1Winners by
mapping the round1 matches to their match.winner (or resolving matchResult for
that match) and similarly compute semiFinalWinners from semi-final matches and
champion from the final match winner; if this is intentionally temporary,
replace the hard-coded arrays with a clear TODO comment and/or fallback to using
match.winner when present.
Description
This PR adds proper loading states to improve the user experience while fetching tournament data.
Changes
isLoading
state inTournamentHub.tsx
andTournamentBracketPage.tsx
.TournamentHub.tsx
.TournamentBracketPage.tsx
.Benefits
Related Issue
#106
Summary by CodeRabbit