Skip to content

Fix AuthContext Safety Handling in StartDebate Component#336

Open
Abhishek2005-ard wants to merge 22 commits intoAOSSIE-Org:mainfrom
Abhishek2005-ard:fix/authcontext-safety-startdebate
Open

Fix AuthContext Safety Handling in StartDebate Component#336
Abhishek2005-ard wants to merge 22 commits intoAOSSIE-Org:mainfrom
Abhishek2005-ard:fix/authcontext-safety-startdebate

Conversation

@Abhishek2005-ard
Copy link
Contributor

@Abhishek2005-ard Abhishek2005-ard commented Feb 25, 2026

This PR improves the way AuthContext is handled in the StartDebate component.
Previously, the component accessed context using:
const authContext = useContext(AuthContext);

and checked authentication using optional chaining:
if (authContext?.isAuthenticated)
Although this prevents runtime errors, it can silently fail if the AuthContext provider is not properly wrapped around the component. In such cases, authContext becomes undefined, and the authentication check always evaluates to false, leading to unintended redirection to the login page.

This update refactors the context usage to safely destructure with a fallback:
const { isAuthenticated } = useContext(AuthContext) || {};
This improves readability, removes repeated optional chaining, and prevents hidden authentication logic issues, making the component more robust and maintainable.

close #335

Summary by CodeRabbit

Release Notes

  • New Features

    • Admin dashboard now requires authentication
    • Debate transcripts now display Elo rating changes
    • High-contrast mode support added for accessibility
    • Speech recognition improvements with better auto-restart handling
  • Bug Fixes

    • Improved robustness of judgment result parsing
    • Enhanced error handling during debate processing
  • Style

    • Dark mode visual refinements across the UI
    • Design token consistency updates
    • Dynamic copyright year in footer
  • Chores

    • Added json5 dependency

@coderabbitai
Copy link

coderabbitai bot commented Feb 25, 2026

📝 Walkthrough

Walkthrough

This PR extends the debate transcript saving pipeline to track Elo changes in the backend, reorganizes frontend routing with admin protection, enhances styling with dark mode and accessibility tokens, and refactors speech recognition with auto-restart capability and improved error handling.

Changes

Cohort / File(s) Summary
Transcript Elo Tracking
backend/controllers/debatevsbot_controller.go, backend/models/transcript.go, backend/services/transcriptservice.go
Extended SaveDebateTranscript calls and signature to accept and persist EloChange parameter; added custom MarshalJSON method to reset ID fields before serialization; threaded eloChange through transcript save and update paths with new logging for error handling.
Profile Elo Reporting
backend/controllers/profile_controller.go
Updated GetProfile to report actual per-debate eloChange values from transcripts instead of hardcoded zeros.
Admin Routing & Protection
frontend/src/App.tsx, frontend/src/components/ProtectedRoute.tsx
Introduced AdminProtectedRoute component to guard admin dashboard; reorganized App routing structure to nest protected routes and consolidate admin/debate route definitions with redirects for unknown routes.
Dark Mode & Accessibility Styling
frontend/src/components/Header.tsx, frontend/src/components/ui/select.tsx, frontend/src/index.css, frontend/tailwind.config.js
Updated UI components to use design tokens (bg-background, text-foreground, border-border, text-muted-foreground); added high-contrast CSS hook and Tailwind variant for prefers-contrast media query; enhanced SelectItem with accessibility-driven data attributes and highlighting styles.
Judgment & Dark Mode UI Enhancements
frontend/src/Pages/DebateRoom.tsx
Integrated JSON5 parsing for judgment results with try/catch error handling; added judging guard (judgingRef) to prevent re-entrant calls; enhanced dark mode styling across containers, cards, borders, and animations; added navigational side effect on judgment popup close.
Judgment Popup Extensibility
frontend/src/components/JudgementPopup.tsx
Added optional botDesc prop to allow external supply of bot-specific description for display in judgment results.
Speech Recognition Lifecycle Refactor
frontend/src/utils/speechTest.ts
Introduced state management for auto-restart (shouldRestart, isListening, restartTimeout); converted start() and testSpeechRecognition to async; added robust error handling with fatal-error detection; implemented race-safe permission checks and cleanup of pending restart timers.
Minor Updates
frontend/package.json, frontend/src/Pages/About.tsx, frontend/src/Pages/TeamDebateRoom.tsx, frontend/src/components/Matchmaking.tsx
Added json5 dependency; dynamic copyright year in footer; formatting alignment and blank line additions.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • bhavik-mangla

Poem

🐰 With transcripts now glowing in Elo-hued light,
Admin gates standing tall, decisions made right,
Dark themes and contrasts for eyes that can see,
Speech loops restart when they stumble with glee—
A rabbit salutes this most thoughtful PR spree! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 4

❌ Failed checks (4 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title references fixing AuthContext safety in StartDebate component, but the changeset shows no modifications to StartDebate or AuthContext—only unrelated changes to debate transcripts, ELO changes, frontend styling, and UI components. Update PR title to accurately reflect the actual changes (e.g., 'Add ELO tracking to debate transcripts and enhance frontend styling'), or ensure the referenced StartDebate/AuthContext changes are included in this PR.
Linked Issues check ⚠️ Warning Issue #335 requires fixing AuthContext safety in the StartDebate component to replace optional chaining with destructuring, but the changeset contains no modifications to StartDebate component or AuthContext usage. Add the missing changes to StartDebate component to destructure AuthContext with a fallback pattern as specified in issue #335, or close/unlink the issue if the changes are out of scope.
Out of Scope Changes check ⚠️ Warning The changeset includes extensive unrelated modifications: ELO tracking in transcripts, dark mode styling, JSON5 parsing, admin route protection, and speech recognition logic—none of which address the stated PR objective of fixing AuthContext safety in StartDebate. Separate unrelated changes into distinct PRs. Keep this PR focused solely on the StartDebate/AuthContext fix as described in issue #335, or redefine the PR scope to accurately describe all included changes.
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
frontend/src/components/JudgementPopup.tsx (1)

94-107: ⚠️ Potential issue | 🟠 Major

Hardcoded localhost URLs will break in deployed environments.

The coachSkills URLs are hardcoded to http://localhost:5173/.... These should use relative paths or be driven by an environment variable.

🐛 Proposed fix
 const coachSkills: CoachSkill[] = [
   {
     title: 'Strengthen Argument',
     description:
       'Master the art of crafting compelling, persuasive arguments that win debates.',
-    url: 'http://localhost:5173/coach/strengthen-argument',
+    url: '/coach/strengthen-argument',
   },
   {
     title: 'Pros and Cons Challenge',
     description:
       'Test your critical thinking by crafting up to 5 pros and cons for engaging debate topics.',
-    url: 'http://localhost:5173/coach/pros-cons',
+    url: '/coach/pros-cons',
   },
 ];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/JudgementPopup.tsx` around lines 94 - 107, The
coachSkills array currently hardcodes full localhost URLs which will fail in
production; update the coachSkills definition (the coachSkills constant in
JudgementPopup.tsx) to use relative paths (e.g. "/coach/strengthen-argument") or
build the URLs from a runtime environment variable (e.g. VITE_BASE_URL /
process.env.BASE_URL) so links resolve correctly in deployed environments;
replace the url fields accordingly and ensure any link rendering code still
treats these values as safe hrefs.
backend/controllers/debatevsbot_controller.go (1)

270-280: ⚠️ Potential issue | 🟠 Major

Handle the SaveDebateTranscript error instead of discarding it.

This call is currently unchecked, so a transcript persistence failure is silent and the API still returns success.

🛠️ Proposed fix
-services.SaveDebateTranscript(
+if err := services.SaveDebateTranscript(
 	userID,
 	email,
 	"user_vs_bot",
 	latestDebate.Topic,
 	latestDebate.BotName,
 	resultStatus,
 	req.History,
 	nil,
 	0.0,
-)
+); err != nil {
+	log.Printf("failed to save bot debate transcript for user %s: %v", userID.Hex(), err)
+	c.JSON(500, gin.H{"error": "Failed to save debate transcript"})
+	return
+}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/controllers/debatevsbot_controller.go` around lines 270 - 280, The
call to services.SaveDebateTranscript is ignoring its returned error so
transcript persistence failures are silent; update the code to capture the
returned error (err := services.SaveDebateTranscript(...)) and handle it: if err
!= nil then log the error (include context: userID, latestDebate.Topic,
latestDebate.BotName) and return an error HTTP response instead of continuing to
return success (e.g., respond with a 500 and a helpful message). Keep the same
arguments (userID, email, "user_vs_bot", latestDebate.Topic,
latestDebate.BotName, resultStatus, req.History, nil, 0.0) but ensure error
handling occurs right after the call so persistence failures are surfaced to the
caller.
🧹 Nitpick comments (3)
frontend/src/Pages/DebateRoom.tsx (3)

598-603: JSON5 parse with rethrow is reasonable but consider logging the raw string on failure.

When the parse fails, the error message includes e but not the jsonString that failed to parse. This can make debugging difficult since the raw LLM output is the critical context.

♻️ Suggested improvement
       try {
         judgment = JSON5.parse(jsonString);
       }catch (e) {
-        throw new Error(`Failed to parse judgment JSON: ${e}`);
+        console.error("Failed to parse judgment JSON string:", jsonString);
+        throw new Error(`Failed to parse judgment JSON: ${e}`);
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/Pages/DebateRoom.tsx` around lines 598 - 603, The catch block
currently rethrows a new Error with only the parse exception (e) and omits the
raw LLM output; update the catch in the code around JSON5.parse (where judgment
is parsed from jsonString) to log or include jsonString when the parse fails:
capture the thrown error in the catch, record the offending jsonString (e.g.,
via console.error or the existing logger) along with a descriptive message, then
rethrow the Error including both the original error message and a truncated or
full jsonString for easier debugging while avoiding leaking sensitive data.

579-579: Indentation inconsistency in judgeDebateResult.

The function declaration at Line 579 is indented with 4 spaces, while the rest of the file's top-level declarations within the component use 2 spaces. This makes the function visually inconsistent with siblings like formatTime (Line 658), renderPhaseMessages (Line 673), etc.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/Pages/DebateRoom.tsx` at line 579, The function declaration for
judgeDebateResult is indented with 4 spaces while other top-level declarations
inside the component (e.g., formatTime and renderPhaseMessages) use 2-space
indentation; fix by adjusting the indentation of the judgeDebateResult
declaration and its entire body to match the 2-space style used for the
component's sibling functions (search for the function name judgeDebateResult to
locate it).

610-650: Default judgment data on error is good UX but consider clearer user messaging.

Showing zeroed-out scores after an error could confuse users into thinking they performed poorly. The error message in the popup (Lines 615-617) is displayed for only 3 seconds, which may not be enough time for users to read and understand it before the zero-score judgment appears.

Consider either extending the timeout or adding a visible error banner within the JudgmentPopup itself so users understand the scores are not real.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/Pages/DebateRoom.tsx` around lines 610 - 650, The popup and
default judgment flow currently auto-hides after 3s and immediately shows zeroed
scores, which can confuse users; update the error handling around setPopup,
setJudgmentData, setTimeout and setShowJudgment (and the JudgmentPopup
component) so that either (A) the timeout is extended and the popup includes an
explicit error flag/message (e.g., popup.isError) that the JudgmentPopup renders
as a persistent banner until user dismisses, or (B) replace the fixed timeout
with a dismiss callback that only calls setShowJudgment(true) after the user
acknowledges the error; also mark the default judgment state (e.g.,
judgmentData.isDefaultDueToError) so the UI can clearly label scores as
placeholders.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/services/transcriptservice.go`:
- Line 668: The SaveDebateTranscript signature was changed to include an
eloChange float64 parameter, but callers like the one in
debatevsbot_controller.go (around the handler invoking SaveDebateTranscript)
were not updated; update all call sites to pass a float64 eloChange (e.g.,
computed elo delta or 0.0 if not applicable) when calling
SaveDebateTranscript(userID, email, debateType, topic, opponent, result,
messages, transcripts, eloChange), ensuring the value you pass matches the
intended logic and type.
- Around line 182-210: The current code logs errors from SaveDebateTranscript
but continues and later deletes the original transcripts
(forSubmission.Transcripts and againstSubmission.Transcripts), risking data
loss; modify the logic around SaveDebateTranscript calls so that if
SaveDebateTranscript returns an error (for either the forUser or againstUser
call) you abort further processing and do not delete the source
transcripts—return or propagate the error instead of only logging (update the
error handling around the SaveDebateTranscript calls and the subsequent deletion
code that references forSubmission.Transcripts and againstSubmission.Transcripts
to be conditional on successful saves).
- Around line 190-207: The two calls to SaveDebateTranscript are passing a
hardcoded 0.0 for eloChange, so SavedDebateTranscript.EloChange is always zero;
replace those literals with the actual computed elo delta values (e.g.,
eloDeltaForUser / eloDeltaAgainstUser or whatever variables compute rating
movement in this flow) so the first SaveDebateTranscript call for forUser uses
the for-user delta and the second call for againstUser uses the against-user
delta; update references around SaveDebateTranscript, SaveDebateTranscript(...)
and any place that computes elo changes to pass the correct variables instead of
0.0.

In `@frontend/src/components/ProtectedRoute.tsx`:
- Around line 8-12: The ProtectedRoute check uses
localStorage.getItem("adminData") but the admin signup/login flow stores the
payload under "admin" (mismatch between adminData and admin); update the
ProtectedRoute component to read the same key used by the login/signup flow
(replace uses of adminData with localStorage.getItem("admin")) so the condition:
const adminToken = localStorage.getItem("adminToken"); const admin =
localStorage.getItem("admin"); if (!adminToken || !admin) return <Navigate
to="/admin/login" replace />; (ensure the symbol names adminToken and admin in
ProtectedRoute match the storage key used in AdminSignup).

In `@frontend/src/index.css`:
- Around line 90-93: The .high-contrast CSS rule defines variables
(--hc-hover-bg, --hc-hover-text) that are never used at runtime; either remove
the .high-contrast block from index.css or ensure the class is applied when
high-contrast mode is enabled (e.g., add logic in your high-contrast
toggle/feature to add/remove the "high-contrast" class on the root or target
elements so the --hc-hover-bg and --hc-hover-text variables become effective).
Locate the .high-contrast rule in index.css and choose the fix: delete the rule
or wire up the runtime code that toggles the "high-contrast" class where
accessibility/theme toggles are implemented.

In `@frontend/src/Pages/DebateRoom.tsx`:
- Around line 697-703: The user section in the DebateRoom component lacks
dark-mode Tailwind variants (it uses "bg-white border border-gray-200" and
header/message elements use "bg-gray-50") while the bot section includes
"dark:bg-zinc-900" and "dark:border-zinc-700"; update the user section and
shared inner elements to mirror the bot's dark variants by adding corresponding
dark: classes (e.g., replace/add dark:bg-zinc-900 or dark:bg-zinc-800 for
container/header backgrounds and dark:border-zinc-700 for borders) and add
dark:bg-... for message bubbles so the styles between the bot and user blocks
(and headers) match in dark mode within the DebateRoom component.
- Around line 758-761: In JudgementPopup.tsx locate the navigate call that uses
the lowercase path '/startdebate' (the onClose handler or any direct
navigate('/startdebate') invocation) and change it to the camelCase
'/startDebate' to match the route defined for StartDebate in App.tsx; update any
related occurrences in the JudgementPopup component (e.g., the onClose handler
that calls setShowJudgment and navigate) so the path casing is consistent with
other components like DebateRoom, Header, and Sidebar.

In `@frontend/src/utils/speechTest.ts`:
- Around line 60-73: The auto-restart race happens because restart() calls
this.recognition.start() without setting this.isListening, so a concurrent
stop() can see isListening false and skip calling recognition.stop(); to fix, in
the restart logic (where this.restartTimeout is set and where
recognition.start() is invoked) set this.isListening = true immediately before
calling this.recognition.start() (or immediately when scheduling the restart)
and ensure restartTimeout is cleared on stop(); also review the other restart
path (the similar block around lines 132–145) and apply the same change so
start/stop always have a consistent isListening state and stop() reliably calls
recognition.stop().
- Line 155: The lint error comes from using an expression-bodied arrow callback
in the call to stream.getTracks().forEach; change the callback passed to forEach
in speechTest.ts so it uses a block-bodied function that invokes track.stop()
(e.g., replace the expression-bodied arrow with a block-bodied arrow or
function) to satisfy lint/suspicious/useIterableCallbackReturn while maintaining
the same behavior.

---

Outside diff comments:
In `@backend/controllers/debatevsbot_controller.go`:
- Around line 270-280: The call to services.SaveDebateTranscript is ignoring its
returned error so transcript persistence failures are silent; update the code to
capture the returned error (err := services.SaveDebateTranscript(...)) and
handle it: if err != nil then log the error (include context: userID,
latestDebate.Topic, latestDebate.BotName) and return an error HTTP response
instead of continuing to return success (e.g., respond with a 500 and a helpful
message). Keep the same arguments (userID, email, "user_vs_bot",
latestDebate.Topic, latestDebate.BotName, resultStatus, req.History, nil, 0.0)
but ensure error handling occurs right after the call so persistence failures
are surfaced to the caller.

In `@frontend/src/components/JudgementPopup.tsx`:
- Around line 94-107: The coachSkills array currently hardcodes full localhost
URLs which will fail in production; update the coachSkills definition (the
coachSkills constant in JudgementPopup.tsx) to use relative paths (e.g.
"/coach/strengthen-argument") or build the URLs from a runtime environment
variable (e.g. VITE_BASE_URL / process.env.BASE_URL) so links resolve correctly
in deployed environments; replace the url fields accordingly and ensure any link
rendering code still treats these values as safe hrefs.

---

Nitpick comments:
In `@frontend/src/Pages/DebateRoom.tsx`:
- Around line 598-603: The catch block currently rethrows a new Error with only
the parse exception (e) and omits the raw LLM output; update the catch in the
code around JSON5.parse (where judgment is parsed from jsonString) to log or
include jsonString when the parse fails: capture the thrown error in the catch,
record the offending jsonString (e.g., via console.error or the existing logger)
along with a descriptive message, then rethrow the Error including both the
original error message and a truncated or full jsonString for easier debugging
while avoiding leaking sensitive data.
- Line 579: The function declaration for judgeDebateResult is indented with 4
spaces while other top-level declarations inside the component (e.g., formatTime
and renderPhaseMessages) use 2-space indentation; fix by adjusting the
indentation of the judgeDebateResult declaration and its entire body to match
the 2-space style used for the component's sibling functions (search for the
function name judgeDebateResult to locate it).
- Around line 610-650: The popup and default judgment flow currently auto-hides
after 3s and immediately shows zeroed scores, which can confuse users; update
the error handling around setPopup, setJudgmentData, setTimeout and
setShowJudgment (and the JudgmentPopup component) so that either (A) the timeout
is extended and the popup includes an explicit error flag/message (e.g.,
popup.isError) that the JudgmentPopup renders as a persistent banner until user
dismisses, or (B) replace the fixed timeout with a dismiss callback that only
calls setShowJudgment(true) after the user acknowledges the error; also mark the
default judgment state (e.g., judgmentData.isDefaultDueToError) so the UI can
clearly label scores as placeholders.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cb07eaf and 233cdb7.

⛔ Files ignored due to path filters (1)
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (17)
  • backend/controllers/debatevsbot_controller.go
  • backend/controllers/profile_controller.go
  • backend/models/transcript.go
  • backend/services/transcriptservice.go
  • frontend/package.json
  • frontend/src/App.tsx
  • frontend/src/Pages/About.tsx
  • frontend/src/Pages/DebateRoom.tsx
  • frontend/src/Pages/TeamDebateRoom.tsx
  • frontend/src/components/Header.tsx
  • frontend/src/components/JudgementPopup.tsx
  • frontend/src/components/Matchmaking.tsx
  • frontend/src/components/ProtectedRoute.tsx
  • frontend/src/components/ui/select.tsx
  • frontend/src/index.css
  • frontend/src/utils/speechTest.ts
  • frontend/tailwind.config.js

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve AuthContext Usage Safety in StartDebate Component

1 participant