Skip to content

Conversation

@SuyashJain17
Copy link
Contributor

@SuyashJain17 SuyashJain17 commented Dec 30, 2025

Proposed change

Resolves #3082

This PR prevents a runtime crash caused by invalid theme values being applied as CSS class names during initial render.

next-themes applies the persisted theme value directly to the class attribute. If the stored value contains spaces (for example "Default Theme"), this results in an InvalidCharacterError and the app crashes before rendering.

The fix validates persisted theme values and falls back safely to a CSS-safe default during initialization.

Checklist

  • Required: I read and followed the contributing guidelines
  • Required: I ran make check-test locally and all tests passed
  • I used AI for code, documentation, or tests in this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 30, 2025

Summary by CodeRabbit

  • New Features

    • Dynamic theme selection (dark and light) with automatic saving and restoration across browser sessions; server/new instances default to dark.
  • Bug Fixes

    • Detects and clears invalid or unsupported saved theme values to prevent client-side theme errors.
  • Chores

    • Removed unused/obsolete frontend dependencies to streamline the project.

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

Adds validated theme handling and persistence in the frontend provider and removes two dependencies from frontend/package.json: rxjs and @types/react-gtm-module.

Changes

Cohort / File(s) Summary
Theme provider & validation
frontend/src/wrappers/provider.tsx
Added ValidTheme type, VALID_THEMES, THEME_STORAGE_KEY, and getInitialTheme() to derive a safe initial theme (server default 'dark', client reads/sanitizes localStorage and removes invalid values). Introduced theme React state and passed defaultTheme, themes={VALID_THEMES}, and storageKey={THEME_STORAGE_KEY} to NextThemesProvider.
Package manifest
frontend/package.json
Removed rxjs from dependencies and @types/react-gtm-module from devDependencies.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The removal of rxjs and @types/react-gtm-module dependencies appears out of scope relative to the theme validation objectives; these removals lack justification within the linked issue context. Clarify whether the dependency removals are related to the theme fix or move them to a separate PR focused on dependency cleanup.
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: preventing crashes from invalid theme classes during initialization, which directly addresses the changeset's theme validation and persistence logic.
Description check ✅ Passed The description is directly related to the changeset, explaining the crash caused by invalid theme values and the fix that validates persisted theme values and falls back to a safe default.
Linked Issues check ✅ Passed The PR directly addresses issue #3082 by implementing theme validation and sanitization to prevent InvalidCharacterError crashes from non-CSS-safe persisted theme values.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b1ad641 and 1d329ce.

⛔ Files ignored due to path filters (1)
  • frontend/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (1)
  • frontend/package.json
💤 Files with no reviewable changes (1)
  • frontend/package.json

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
Contributor

@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: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7caf577 and 606cbc0.

📒 Files selected for processing (1)
  • frontend/src/wrappers/provider.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-17T02:42:41.928Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 2288
File: frontend/src/components/ActionButton.tsx:0-0
Timestamp: 2025-09-17T02:42:41.928Z
Learning: In frontend/src/components/ActionButton.tsx, the user Rajgupta36 intentionally changed text-blue-600 to text-[#1D7BD7] to align the text color with the border color (#1D7BD7) for visual consistency, prioritizing design alignment over theme tokens.

Applied to files:

  • frontend/src/wrappers/provider.tsx

@SuyashJain17
Copy link
Contributor Author

Thanks for the feedback. Agreed that forcing the theme breaks ModeToggle.

I’ll update the PR to validate persisted theme values and preserve theme switching instead of forcing a single theme.

coderabbitai[bot]
coderabbitai bot previously approved these changes Dec 30, 2025
@arkid15r arkid15r marked this pull request as draft December 30, 2025 17:40
Copy link
Collaborator

@arkid15r arkid15r left a comment

Choose a reason for hiding this comment

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

Please also fix all sonar wanrings

@SuyashJain17 SuyashJain17 marked this pull request as ready for review December 30, 2025 18:17
Copy link
Contributor

@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: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0ddc488 and 8aabaf4.

📒 Files selected for processing (1)
  • frontend/src/wrappers/provider.tsx
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-09-17T02:42:41.928Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 2288
File: frontend/src/components/ActionButton.tsx:0-0
Timestamp: 2025-09-17T02:42:41.928Z
Learning: In frontend/src/components/ActionButton.tsx, the user Rajgupta36 intentionally changed text-blue-600 to text-[#1D7BD7] to align the text color with the border color (#1D7BD7) for visual consistency, prioritizing design alignment over theme tokens.

Applied to files:

  • frontend/src/wrappers/provider.tsx
📚 Learning: 2025-07-13T11:29:25.245Z
Learnt from: Rajgupta36
Repo: OWASP/Nest PR: 1717
File: frontend/src/app/mentorship/programs/page.tsx:59-61
Timestamp: 2025-07-13T11:29:25.245Z
Learning: In Next.js 13+ app router, components with the 'use client' directive run entirely on the client side and don't require window object existence checks or SSR hydration considerations. Direct access to window.location and other browser APIs is safe in client components.

Applied to files:

  • frontend/src/wrappers/provider.tsx
🧬 Code graph analysis (1)
frontend/src/wrappers/provider.tsx (1)
frontend/src/hooks/useDjangoSession.ts (1)
  • useDjangoSession (10-83)
🔇 Additional comments (3)
frontend/src/wrappers/provider.tsx (3)

11-12: LGTM! Clean type-safe theme definition.

The const assertion and derived ValidTheme type provide compile-time safety for theme values throughout the component.


44-49: NextThemesProvider configuration is correct.

The configuration properly restricts allowed themes via themes={VALID_THEMES} and uses a consistent storageKey that matches getValidTheme(). The defaultTheme={theme} provides a validated fallback when no theme is stored or after invalid values are cleaned up.

Note: enableSystem defaults to true in next-themes, so the provider will detect and respect the user's system theme preference when no explicit theme is stored.


38-38: The code pattern is correct and follows next-themes best practices. The React.useState lazy initialization properly calls getValidTheme only once on client mount. While a theoretical hydration difference exists (server returns 'dark' when window is undefined, client might read localStorage), next-themes is specifically designed to handle this scenario: it suppresses theme application during hydration and reconciles the state afterward without warnings.

Additionally, ModeToggle.tsx implements the standard hydration safety pattern with the mounted state check, preventing any issues when reading the current theme. No actual hydration mismatches are evident in the codebase.

coderabbitai[bot]
coderabbitai bot previously approved these changes Dec 30, 2025
@SuyashJain17
Copy link
Contributor Author

I noticed a low-severity SonarCloud warning suggesting globalThis.window.
I kept typeof window === 'undefined' here as it’s the standard SSR pattern
in Next.js and aligns with the CodeRabbit feedback.

Please let me know if you’d prefer a different approach.

Copy link
Collaborator

@arkid15r arkid15r left a comment

Choose a reason for hiding this comment

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

I don't think I understand the code and the issues it fixes.
Also have some doubts about specific code parts:

if (stored) {
localStorage.removeItem('__nest_theme__')
}
} catch {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think it's a good idea.

// It ensures the session is synced with Django when the app starts.
// AppInitializer is mounted once. Its job is to call useDjangoSession(),
// which syncs the GitHub access token (stored in the NextAuth session) with the Django session.
const VALID_THEMES = ['dark', 'light'] as const
Copy link
Collaborator

Choose a reason for hiding this comment

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

Don't remove existing comments.

// It ensures the session is synced with Django when the app starts.
// AppInitializer is mounted once. Its job is to call useDjangoSession(),
// which syncs the GitHub access token (stored in the NextAuth session) with the Django session.
const VALID_THEMES = ['dark', 'light'] as const
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why do you need const twice here?

@arkid15r arkid15r marked this pull request as draft January 1, 2026 20:03
@SuyashJain17 SuyashJain17 marked this pull request as ready for review January 2, 2026 05:19
@SuyashJain17
Copy link
Contributor Author

Thanks for the detailed feedback - that helps.

The issue this PR fixes is a runtime crash caused by next-themes applying a persisted theme value directly as a CSS class during initial render. If the stored value contains spaces (for example "Default Theme"), the browser throws an InvalidCharacterError and the app crashes before rendering.

The cleanup logic only removes the persisted value when it’s invalid (i.e. not one of ['dark', 'light']). This allows next-themes to fall back to a safe default and prevents the crash. Valid user preferences are not touched.

I agree the intent wasn’t clear enough from the code. I’ll:

  • Add an explicit comment explaining the crash scenario and why the cleanup is needed

  • Move the theme validation helpers away from the Django session–related comments

  • Simplify the typing to avoid confusion around const / as const

Please let me know if you’d prefer a different approach (for example sanitizing instead of removing). I’m happy to adjust.

coderabbitai[bot]
coderabbitai bot previously approved these changes Jan 2, 2026
coderabbitai[bot]
coderabbitai bot previously approved these changes Jan 2, 2026
@SuyashJain17
Copy link
Contributor Author

Closing this PR since it contains multiple unrelated changes from an earlier branch.
I’ll open a clean, scoped PR for the assigned issue. Thanks!

@arkid15r
Copy link
Collaborator

arkid15r commented Jan 2, 2026

You should never close a PR unless you're asked to. PR is a "shell" for your code to be reviewed/merged. As an author you can do whatever you need w/ your branch linked to this PR.

@arkid15r arkid15r reopened this Jan 2, 2026
@SuyashJain17
Copy link
Contributor Author

Thanks for clarifying, that makes sense - appreciate it.

I closed the PR earlier because the branch had accumulated multiple unrelated commits from experimentation, and I didn’t want to risk merging unintended changes.

I understand now that the PR can remain open while I clean up the branch history. I’ll rebase this PR onto a clean state and update it accordingly.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Jan 2, 2026

@SuyashJain17
Copy link
Contributor Author

Removed the dependency cleanup commit so this PR focuses only on the theme initialization crash fix.

Comment on lines +25 to +34
/**
* next-themes applies the persisted theme value directly as a CSS class
* during initial render.
*
* If the stored value contains spaces (e.g. "Default Theme"), the browser
* throws InvalidCharacterError and the app crashes before rendering.
*
* To prevent this, we validate the persisted value and remove it only
* if it is invalid, allowing next-themes to safely fall back to default.
*/
Copy link
Collaborator

Choose a reason for hiding this comment

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

@SuyashJain17 can you provide steps how to replicate this issue you're trying to fix? 👀
Current default theme is set to "dark", so I'm not sure how it's possible to have it set to something like "Default Theme", unless user goes in and manually updates it in local storage.

Is that the scenario you're working with?

Even if so, I believe toggling the theme toggle again - would update the value.
However, even if we'd want to add extra validation, I believe the solution can be much much simpler - like a 1-2 lines change 🤔

Copy link
Collaborator

@kasya kasya left a comment

Choose a reason for hiding this comment

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

There's also unresolved Sonar issue still - you're required to resolve them all before we review, no matter how high the priority is on them.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Local dev crash: InvalidCharacterError caused by non-CSS-safe theme value

3 participants