Skip to content

[REFACTOR] Split app/page.tsx into composable section#677

Open
Aditya8369 wants to merge 5 commits into
knoxiboy:mainfrom
Aditya8369:493
Open

[REFACTOR] Split app/page.tsx into composable section#677
Aditya8369 wants to merge 5 commits into
knoxiboy:mainfrom
Aditya8369:493

Conversation

@Aditya8369

@Aditya8369 Aditya8369 commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

User description

src/app/page.tsx was split into composable landing sections under src/components/landing/*.

What changed

Created src/components/landing/landingContent.ts
Exports features, howItWorks, testimonials arrays (moved out of the page).
Created (section components) under src/components/landing/
HeroSection.tsx
FeaturesSection.tsx
HowItWorksSection.tsx
TestimonialsSection.tsx
Created src/components/landing/SignOutDialog.tsx
Presentational sign-out confirmation dialog (receives open, onOpenChange, onSignOut).
Rewrote src/app/page.tsx into a minimal "use client" composition root
Keeps only:
hash-based scroll behavior (scrollToSection)
Clerk signOut handler + dialog open state
Renders the new section components and the existing ScrollToTopButton.

closes #493


CodeAnt-AI Description

Split the landing page into reusable sections

What Changed

  • Moved the sign-out confirmation into its own dialog component, while keeping the same message and sign-out flow.
  • Broke the homepage into separate hero, features, how-it-works, and testimonials sections so the landing page still looks and behaves the same.
  • Kept hash-link scrolling on the homepage so section links still jump to the right place.

Impact

✅ Same landing page experience
✅ Easier navigation to homepage sections
✅ Sign-out confirmation still works as expected

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

Summary by CodeRabbit

  • Refactor
    • Landing page restructured into modular components for improved organization and maintainability.
    • Enhanced section navigation experience with improved scrolling behavior.
    • Improved sign-out confirmation flow with a dedicated dialog component.

@vercel

vercel Bot commented Jun 19, 2026

Copy link
Copy Markdown

@Aditya8369 is attempting to deploy a commit to the Karan Mani Tripathi 's projects Team on Vercel.

A member of the Team first needs to authorize it.

@codeant-ai

codeant-ai Bot commented Jun 19, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@github-actions github-actions Bot added size/xl gssoc'26 GSSoC program issue level:advanced Advanced level task type:refactor Code refactoring review-needed labels Jun 19, 2026
@github-actions github-actions Bot requested a review from knoxiboy June 19, 2026 06:25
@github-actions

Copy link
Copy Markdown

@coderabbitai review

@codeant-ai codeant-ai Bot added the size:L This PR changes 100-499 lines, ignoring generated files label Jun 19, 2026
@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

src/app/page.tsx is refactored from a monolithic component into a composition root. Content arrays (features, howItWorks, testimonials) and their TypeScript types move to landingContent.ts. Landing sections are extracted into HeroSection, FeaturesSection, HowItWorksSection, TestimonialsSection, and SignOutDialog components under src/components/landing/.

Changes

Landing Page Decomposition

Layer / File(s) Summary
Shared landing content types and data
src/components/landing/landingContent.ts
Introduces LandingFeature, LandingHowItWorksStep, and LandingTestimonial types, and exports the features (6 entries with lucide-react icons), howItWorks (3 steps), and testimonials (6 entries) data arrays consumed by all section components.
Extracted landing section components
src/components/landing/HeroSection.tsx, src/components/landing/FeaturesSection.tsx, src/components/landing/HowItWorksSection.tsx, src/components/landing/TestimonialsSection.tsx
Adds HeroSection with ShapeGrid background, layered gradient overlays, auth-conditional CTAs via Clerk SignedIn/SignedOut, and a LiveCampusThreadPanel right-side panel. Adds FeaturesSection, HowItWorksSection, and TestimonialsSection, each mapping over shared content data with per-card index-based animationDelay.
Extracted SignOutDialog component
src/components/landing/SignOutDialog.tsx
Adds SignOutDialog as a standalone controlled AlertDialog with open, onOpenChange, and onSignOut props, replacing the previously inline sign-out confirmation markup in page.tsx.
page.tsx refactored as composition root
src/app/page.tsx
Rewrites Home to import and compose HeroSection, FeaturesSection, HowItWorksSection, TestimonialsSection, SignOutDialog, and ScrollToTopButton; adds a scrollFromHash effect using requestAnimationFrame and scrollToSection with updateHash: false.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

  • #493 [REFACTOR] Split app/page.tsx into composable sections — This PR directly implements the refactor described in the issue: extracting SignOutDialog, HeroSection, FeaturesSection, HowItWorksSection, TestimonialsSection, and landingContent.ts from page.tsx into components/landing/.

Possibly related PRs

  • knoxiboy/DoubtDesk#405: Both PRs add hash-based scroll logic in src/app/page.tsx using window.location.hash with scrollToSection(..., { updateHash: false }) inside requestAnimationFrame.
  • knoxiboy/DoubtDesk#633: Both PRs modify the testimonials implementation — this PR extracts a TestimonialsSection consuming a shared testimonials array, while PR #633 updates testimonial data shape and rendering via TestimonialCard/TestimonialsMarquee, causing a direct overlap.
  • knoxiboy/DoubtDesk#666: Both PRs modify src/app/page.tsx's landing page implementation around the features section markup and scroll behavior, creating close overlap at the code level.

Suggested labels

frontend, level:intermediate, quality:clean

Suggested reviewers

  • knoxiboy
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main objective of this PR: refactoring app/page.tsx by splitting it into composable section components.
Linked Issues check ✅ Passed The PR successfully addresses all coding requirements from issue #493: extracted presentational sections into dedicated components, moved content arrays to landingContent.ts, created SignOutDialog component, preserved all existing behaviors (scroll-to-top, smooth scrolling, sign-out redirect), and maintained client/server component split appropriately.
Out of Scope Changes check ✅ Passed All changes are directly aligned with the refactoring objectives in issue #493; no out-of-scope modifications were introduced beyond the planned component extraction and content consolidation.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@github-actions github-actions Bot added size/l and removed size:L This PR changes 100-499 lines, ignoring generated files size/xl labels Jun 19, 2026
Comment thread src/app/page.tsx
Comment on lines +48 to +52
<SignOutDialog
open={showSignOutDialog}
onOpenChange={setShowSignOutDialog}
onSignOut={handleSignOut}
/>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: The sign-out dialog is wired as a controlled component but nothing in this page ever sets open to true, so the dialog can never be opened and this sign-out flow is effectively dead code. Add a trigger (for example, pass an onRequestSignOut callback into a section/header button that calls setShowSignOutDialog(true)) or remove this dialog/state if sign-out is handled elsewhere. [incomplete implementation]

Severity Level: Major ⚠️
- ⚠️ Landing page includes an unreachable sign-out confirmation dialog.
- ⚠️ Dead state and handler add maintenance and cognitive overhead.
Steps of Reproduction ✅
1. Note that the root layout at `src/app/layout.tsx:109-125` renders `{children}`
(including `Home` from `src/app/page.tsx`) inside a `<main className="flex-1">`, so the
landing page `Home` is always used for the `/` route.

2. In `src/app/page.tsx:22-24`, `Home` defines local state `const [showSignOutDialog,
setShowSignOutDialog] = useState(false);`, initializing `showSignOutDialog` to `false` and
never changing it directly in this component.

3. In `src/app/page.tsx:48-52`, `Home` renders `<SignOutDialog open={showSignOutDialog}
onOpenChange={setShowSignOutDialog} onSignOut={handleSignOut} />`, making `SignOutDialog`
a controlled component whose visibility depends entirely on `showSignOutDialog`.

4. A repo-wide search for `showSignOutDialog` (Grep results at `src/app/page.tsx:23` and
`:49`, plus an unrelated dashboard usage in
`src/components/DashboardLayout.tsx:28,112-113`) shows no code in `Home` that ever calls
`setShowSignOutDialog(true)` or otherwise sets `open` to `true`, so in practice the dialog
can never become visible and this sign-out confirmation flow is dead code on the landing
page.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/app/page.tsx
**Line:** 48:52
**Comment:**
	*Incomplete Implementation: The sign-out dialog is wired as a controlled component but nothing in this page ever sets `open` to `true`, so the dialog can never be opened and this sign-out flow is effectively dead code. Add a trigger (for example, pass an `onRequestSignOut` callback into a section/header button that calls `setShowSignOutDialog(true)`) or remove this dialog/state if sign-out is handled elsewhere.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎


export default function HeroSection() {
return (
<main className="flex-1 relative overflow-hidden scroll-smooth">

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: Rendering a <main> here creates a nested <main> landmark because the app layout already wraps page content in <main>, which breaks document landmark semantics and can confuse assistive technologies. Use a non-landmark container like <section>/<div> in this component. [code quality]

Severity Level: Major ⚠️
- ⚠️ Nested main landmarks degrade accessibility semantics.
- ⚠️ Screen readers may misinterpret primary content region.
- ⚠️ Layout structure becomes harder to reason about long-term.
Steps of Reproduction ✅
1. The root layout in `src/app/layout.tsx:109-125` wraps all page content in a `<main
className="flex-1">` element that contains `{children}`, where `children` is the `Home`
page for the `/` route.

2. The `Home` component at `src/app/page.tsx:44-60` returns a root `<div>` that includes
`<HeroSection />` at line 54, so `HeroSection` is nested inside the layout's `<main>`.

3. In `src/components/landing/HeroSection.tsx:11-13`, `HeroSection` itself returns a
top-level `<main className="flex-1 relative overflow-hidden scroll-smooth">`, making
`main` the semantic root of that component.

4. When composed, the DOM structure becomes `<main> <div> <main> ... </main> </div>
</main>`, which creates nested `<main>` landmarks; this violates HTML landmark semantics
and can confuse assistive technologies that rely on a single main region per
document/page.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/components/landing/HeroSection.tsx
**Line:** 13:13
**Comment:**
	*Code Quality: Rendering a `<main>` here creates a nested `<main>` landmark because the app layout already wraps page content in `<main>`, which breaks document landmark semantics and can confuse assistive technologies. Use a non-landmark container like `<section>`/`<div>` in this component.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment on lines +56 to +65
<Link href="/rooms" className="w-full sm:w-auto">
<button className="group w-full sm:w-auto px-10 py-5 bg-[#5E8CFF] text-white rounded-2xl text-lg font-bold hover:bg-[#8BB8FF] hover:shadow-[0_0_24px_rgba(94,140,255,0.35)] transition-all flex items-center justify-center gap-2 hover:scale-[1.02] active:scale-[0.98]">
<span
className={`${staatliches.className} uppercase tracking-[0.08em]`}
>
Open Classroom
</span>
<ArrowRight className="w-5 h-5 group-hover:translate-x-1.5 transition-transform duration-300" />
</button>
</Link>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: This nests a <button> inside a Next.js <Link> (anchor), which creates invalid nested interactive elements and can cause inconsistent click/keyboard behavior across browsers. Replace the inner <button> with a styled non-interactive element (e.g., <span>/<div>) or style the Link directly as the button. [code quality]

Severity Level: Major ⚠️
- ⚠️ Hero CTA renders invalid nested interactive elements.
- ⚠️ Potentially inconsistent click and keyboard navigation behavior.
- ⚠️ Accessibility semantics degraded for primary call-to-action.
Steps of Reproduction ✅
1. The landing page component `Home` at `src/app/page.tsx:54` renders `<HeroSection />`,
so `HeroSection` is always part of the `/` route UI.

2. In `src/components/landing/HeroSection.tsx:55-66`, for signed-in users the JSX renders:

   - `<SignedIn>` wrapper (line 55),

   - `<Link href="/rooms" className="w-full sm:w-auto">` (line 56),

   - and inside that `Link`, a nested `<button ...>Open Classroom</button>` (lines 57-64),

   - followed by closing `</Link>` (line 65).

3. At runtime Next.js `Link` renders an `<a>` element; this structure therefore becomes
`<a href="/rooms"> <button>Open Classroom</button> </a>`, which is invalid HTML because it
nests an interactive `<button>` inside an interactive `<a>`.

4. This invalid nesting occurs every time a signed-in user views the landing page, and can
lead to inconsistent click/keyboard behavior and accessibility issues because assistive
technologies and browsers may handle the nested interactive elements unpredictably.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/components/landing/HeroSection.tsx
**Line:** 56:65
**Comment:**
	*Code Quality: This nests a `<button>` inside a Next.js `<Link>` (anchor), which creates invalid nested interactive elements and can cause inconsistent click/keyboard behavior across browsers. Replace the inner `<button>` with a styled non-interactive element (e.g., `<span>`/`<div>`) or style the `Link` directly as the button.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

Comment on lines +37 to +42
<AlertDialogAction
onClick={onSignOut}
className="bg-red-600 hover:bg-red-700 text-white border-none rounded-xl transition-all duration-200"
>
Sign Out
</AlertDialogAction>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: onSignOut is typed to allow async promises, but it is passed directly to onClick without handling rejections. If sign-out fails (network/auth error), the promise rejection can go unhandled and the dialog still proceeds with the action flow, leaving the UI in an inconsistent state. Wrap the click handler in an async function that awaits onSignOut and handles errors explicitly. [possible bug]

Severity Level: Major ⚠️
- ❌ Landing page sign-out dialog crashes on Clerk errors.
- ⚠️ Users receive no feedback on failed sign-out attempts.
- ⚠️ Unhandled promise rejections degrade frontend reliability and logs.
Steps of Reproduction ✅
1. Render the landing page at `/`, which uses the `Home` component in
`src/app/page.tsx:22-62` (already configured as the default export for this route).

2. Note that `Home` obtains `signOut` from Clerk via `useClerk` at `src/app/page.tsx:4,24`
and defines an async `handleSignOut` that awaits `signOut({ redirectUrl: "/" })` at
`src/app/page.tsx:40-42`, passing it as `onSignOut` into `SignOutDialog` at
`src/app/page.tsx:48-52`.

3. In a test or during development, stub or mock Clerk's `signOut` (used in
`handleSignOut`) to `() => Promise.reject(new Error("sign out failed"))`, so that
`handleSignOut` returns a rejected Promise when invoked.

4. Ensure `SignOutDialog` is open (it is rendered from
`src/components/landing/SignOutDialog.tsx:18-47`), then click the "Sign Out" button wired
via `<AlertDialogAction onClick={onSignOut}>` at
`src/components/landing/SignOutDialog.tsx:37-42`; observe that the async `handleSignOut`
rejection is neither awaited nor caught, leading to an unhandled Promise rejection while
the dialog still proceeds with its close/action flow.

Fix in Cursor Fix in VSCode Claude

(Use Cmd/Ctrl + Click for best experience)

Prompt for AI Agent 🤖
This is a comment left during a code review.

**Path:** src/components/landing/SignOutDialog.tsx
**Line:** 37:42
**Comment:**
	*Possible Bug: `onSignOut` is typed to allow async promises, but it is passed directly to `onClick` without handling rejections. If sign-out fails (network/auth error), the promise rejection can go unhandled and the dialog still proceeds with the action flow, leaving the UI in an inconsistent state. Wrap the click handler in an async function that awaits `onSignOut` and handles errors explicitly.

Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix
👍 | 👎

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

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

⚠️ Outside diff range comments (1)
src/app/page.tsx (1)

23-52: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Sign-out dialog has no open trigger in this composition root.

showSignOutDialog is never set to true in this file, so SignOutDialog cannot be opened from the current flow. Wire an explicit trigger (or callback prop into a child) to open it, or remove dead state/dialog wiring.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/page.tsx` around lines 23 - 52, The showSignOutDialog state is
initialized to false and passed to the SignOutDialog component through the open
prop and setShowSignOutDialog through the onOpenChange prop, but there is no
mechanism to set showSignOutDialog to true anywhere in the code. Add a trigger
(such as a button with an onClick handler that calls setShowSignOutDialog(true))
in the component's JSX to allow users to open the SignOutDialog, or
alternatively remove the unused showSignOutDialog state, the SignOutDialog
component, and the related handleSignOut function if the sign-out functionality
is not needed.
🧹 Nitpick comments (5)
src/components/landing/SignOutDialog.tsx (1)

27-41: ⚡ Quick win

Extract dialog copy and labels into constants.

Dialog text and action labels are hardcoded in TSX; centralize them in constants/content config.

As per coding guidelines, "No hardcoded strings (use constants)".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/landing/SignOutDialog.tsx` around lines 27 - 41, The
SignOutDialog component contains multiple hardcoded strings including the title
"Are you sure you want to sign out?", the description about logging in again,
and the action labels "Cancel" and "Sign Out". Extract all these hardcoded
strings from the AlertDialogTitle, AlertDialogDescription, and AlertDialogAction
elements and move them into a constants file or content configuration object.
Then replace each hardcoded string in the component with references to the
corresponding constant to comply with the no hardcoded strings guideline.

Source: Coding guidelines

src/components/landing/FeaturesSection.tsx (1)

17-27: ⚡ Quick win

Extract section-level copy into constants.

The section label/headline/description are hardcoded in TSX. Keep all user-facing copy in content constants to match the new decomposition pattern.

As per coding guidelines, "No hardcoded strings (use constants)".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/landing/FeaturesSection.tsx` around lines 17 - 27, Extract the
hardcoded user-facing copy strings in the FeaturesSection component into
constants at the top of the file. The strings to extract are: the "Features"
label, the main headline beginning with "Everything your classroom needs...",
and the description paragraph starting with "Built for modern study teams...".
Replace each hardcoded string in the JSX with a reference to its corresponding
constant to align with the no-hardcoded-strings guideline.

Source: Coding guidelines

src/components/landing/TestimonialsSection.tsx (1)

11-19: ⚡ Quick win

Move testimonials section copy into constants.

The section title/subtitle are hardcoded in TSX; extract to constants/content for consistency and localization-readiness.

As per coding guidelines, "No hardcoded strings (use constants)".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/landing/TestimonialsSection.tsx` around lines 11 - 19, The
TestimonialsSection component contains hardcoded strings for section labels and
copy. Extract the three hardcoded strings ("Testimonials", "What students say",
and "Real feedback from learners and educators") into named constants,
preferably in a dedicated constants file or at the top of the component file,
and then reference those constants in place of the inline strings to maintain
consistency and support future localization efforts.

Source: Coding guidelines

src/components/landing/HowItWorksSection.tsx (1)

11-19: ⚡ Quick win

Centralize the "How it works" header copy.

This TSX block hardcodes user-visible strings; move them into shared constants/content so section copy is managed consistently.

As per coding guidelines, "No hardcoded strings (use constants)".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/landing/HowItWorksSection.tsx` around lines 11 - 19, The
HowItWorksSection component contains hardcoded user-visible strings: "Process",
"How it works", and "Simple flow from doubt → solution → understanding". Extract
these strings into a shared constants or content file, then import and use them
in the HowItWorksSection component instead of hardcoding them directly in the
JSX. This ensures consistent management of section copy across the application
and follows the no hardcoded strings guideline.

Source: Coding guidelines

src/components/landing/HeroSection.tsx (1)

31-51: ⚡ Quick win

Move hero copy and CTA labels into constants/content config.

This section still hardcodes multiple user-facing strings in TSX. Extract these into shared constants (similar to landingContent.ts) to keep copy centralized and localization-ready.

As per coding guidelines, "No hardcoded strings (use constants)".

Also applies to: 61-88

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/landing/HeroSection.tsx` around lines 31 - 51, Extract all
hardcoded user-facing strings from the HeroSection component (specifically the
text content "Empower Your Learning with", "Collaborative AI.", "Collaborative
classrooms", and "Built for collaborative classrooms, instant doubt solving, and
smarter learning.") into a centralized constants file similar to
landingContent.ts. Replace these hardcoded strings in the JSX with references to
the constant values to maintain consistency with the no-hardcoded-strings coding
guideline and make content localization-ready.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/app/page.tsx`:
- Around line 14-18: The page.tsx file is marked as a client component with "use
client" directive, which causes the imported landing section components
(HeroSection, FeaturesSection, HowItWorksSection, TestimonialsSection) to be
unnecessarily bundled client-side even though they contain no client-side logic.
To fix this, refactor the architecture to use the composition pattern: instead
of importing these sections directly in the client component, move them to a
server component and pass them as children to the client boundary, or verify if
these section components and their dependencies (like Clerk's SignedIn/SignedOut
used in SignOutDialog) can be converted to server components. This will ensure
only truly client-side interactive components remain in the client bundle.

In `@src/components/landing/HeroSection.tsx`:
- Around line 56-91: The code has nested interactive controls with button
elements wrapped inside Link components for the three CTA sections (the ones
with href="/rooms", href="/sign-up", and href="/public-rooms"), which creates
invalid HTML and accessibility issues. Remove the button element wrapper from
each Link and apply all the button styling and className attributes directly to
the Link component instead. This way, the Link itself becomes the interactive
control without nesting elements, maintaining all the visual styling and hover
effects while following proper HTML semantics and accessibility guidelines.

In `@src/components/landing/SignOutDialog.tsx`:
- Around line 37-42: The AlertDialogAction component with onClick={onSignOut}
does not handle the async nature of the sign-out operation, leaving users
without feedback during the request. Add a loading/pending state using useState
to track whether the sign-out is in progress, disable the AlertDialogAction
button while pending to prevent duplicate submissions, display loading feedback
(such as text or spinner) to the user during the operation, and handle any
errors that occur during sign-out by capturing them in the onClick handler and
providing appropriate error feedback to the user.

In `@src/components/landing/TestimonialsSection.tsx`:
- Around line 23-26: The testimonials.map function is currently using t.name as
the React key, which can cause key collisions if multiple testimonials share the
same name. Replace key={t.name} with key={t.id} in the testimonials.map callback
to ensure each testimonial has a unique, stable identifier that won't collide
with other entries.

---

Outside diff comments:
In `@src/app/page.tsx`:
- Around line 23-52: The showSignOutDialog state is initialized to false and
passed to the SignOutDialog component through the open prop and
setShowSignOutDialog through the onOpenChange prop, but there is no mechanism to
set showSignOutDialog to true anywhere in the code. Add a trigger (such as a
button with an onClick handler that calls setShowSignOutDialog(true)) in the
component's JSX to allow users to open the SignOutDialog, or alternatively
remove the unused showSignOutDialog state, the SignOutDialog component, and the
related handleSignOut function if the sign-out functionality is not needed.

---

Nitpick comments:
In `@src/components/landing/FeaturesSection.tsx`:
- Around line 17-27: Extract the hardcoded user-facing copy strings in the
FeaturesSection component into constants at the top of the file. The strings to
extract are: the "Features" label, the main headline beginning with "Everything
your classroom needs...", and the description paragraph starting with "Built for
modern study teams...". Replace each hardcoded string in the JSX with a
reference to its corresponding constant to align with the no-hardcoded-strings
guideline.

In `@src/components/landing/HeroSection.tsx`:
- Around line 31-51: Extract all hardcoded user-facing strings from the
HeroSection component (specifically the text content "Empower Your Learning
with", "Collaborative AI.", "Collaborative classrooms", and "Built for
collaborative classrooms, instant doubt solving, and smarter learning.") into a
centralized constants file similar to landingContent.ts. Replace these hardcoded
strings in the JSX with references to the constant values to maintain
consistency with the no-hardcoded-strings coding guideline and make content
localization-ready.

In `@src/components/landing/HowItWorksSection.tsx`:
- Around line 11-19: The HowItWorksSection component contains hardcoded
user-visible strings: "Process", "How it works", and "Simple flow from doubt →
solution → understanding". Extract these strings into a shared constants or
content file, then import and use them in the HowItWorksSection component
instead of hardcoding them directly in the JSX. This ensures consistent
management of section copy across the application and follows the no hardcoded
strings guideline.

In `@src/components/landing/SignOutDialog.tsx`:
- Around line 27-41: The SignOutDialog component contains multiple hardcoded
strings including the title "Are you sure you want to sign out?", the
description about logging in again, and the action labels "Cancel" and "Sign
Out". Extract all these hardcoded strings from the AlertDialogTitle,
AlertDialogDescription, and AlertDialogAction elements and move them into a
constants file or content configuration object. Then replace each hardcoded
string in the component with references to the corresponding constant to comply
with the no hardcoded strings guideline.

In `@src/components/landing/TestimonialsSection.tsx`:
- Around line 11-19: The TestimonialsSection component contains hardcoded
strings for section labels and copy. Extract the three hardcoded strings
("Testimonials", "What students say", and "Real feedback from learners and
educators") into named constants, preferably in a dedicated constants file or at
the top of the component file, and then reference those constants in place of
the inline strings to maintain consistency and support future localization
efforts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 61e9af4c-0962-4e56-b58b-20346c70440c

📥 Commits

Reviewing files that changed from the base of the PR and between a851fd0 and 1cc78b9.

📒 Files selected for processing (7)
  • src/app/page.tsx
  • src/components/landing/FeaturesSection.tsx
  • src/components/landing/HeroSection.tsx
  • src/components/landing/HowItWorksSection.tsx
  • src/components/landing/SignOutDialog.tsx
  • src/components/landing/TestimonialsSection.tsx
  • src/components/landing/landingContent.ts

Comment thread src/app/page.tsx
Comment on lines +14 to +18
import SignOutDialog from "@/components/landing/SignOutDialog";
import HeroSection from "@/components/landing/HeroSection";
import FeaturesSection from "@/components/landing/FeaturesSection";
import HowItWorksSection from "@/components/landing/HowItWorksSection";
import TestimonialsSection from "@/components/landing/TestimonialsSection";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In Next.js App Router, if a file marked "use client" imports components that do not themselves contain "use client", are those imported components still included in the client bundle?

💡 Result:

Yes, if a file is marked with "use client", all components it imports—even those without the "use client" directive—are included in the client bundle [1][2][3]. In the Next.js App Router, the "use client" directive establishes a boundary that marks the file and its entire transitive dependency tree as part of the client module graph [1][2][4]. Because these imported components become part of this graph, they are bundled for the client, regardless of whether they contain the directive themselves [2][5]. However, there is an important distinction between being bundled and being rendered as a "Client Component": 1. Bundling: If you import a component into a "use client" file, it is automatically included in the client-side JavaScript bundle [1][3]. 2. Component Composition (Children): You can avoid forcing a component into the client bundle by passing it as a child or prop to the Client Component [1][4]. When a Server Component is passed as a child (e.g., ), the Server Component is rendered on the server, and its rendered result is passed to the Client Component [1][6]. In this pattern, the Server Component is not imported into the Client Component's module graph, so it is not included in the client bundle [1][4]. To optimize bundle size, it is recommended to keep "use client" boundaries as small as possible, ideally at the "leaves" of your component tree, and to use the composition pattern (passing Server Components as children) to maintain server-side rendering for non-interactive parts of your UI [1][3][5].

Citations:


🏁 Script executed:

# First, check if src/app/page.tsx exists and view its full content
cat -n src/app/page.tsx

Repository: knoxiboy/DoubtDesk

Length of output: 2473


🏁 Script executed:

# Check if the imported landing section components have "use client" directives
for component in SignOutDialog HeroSection FeaturesSection HowItWorksSection TestimonialsSection; do
  echo "=== Checking $component ==="
  find . -name "${component}.tsx" -o -name "${component}.ts" | head -1 | xargs head -5
done

Repository: knoxiboy/DoubtDesk

Length of output: 951


🏁 Script executed:

# Check the very first line of each component to see if they have "use client"
for component in SignOutDialog HeroSection FeaturesSection HowItWorksSection TestimonialsSection; do
  echo "=== First line of $component ==="
  find . -name "${component}.tsx" | head -1 | xargs sed -n '1p'
done

Repository: knoxiboy/DoubtDesk

Length of output: 452


🏁 Script executed:

# Search for "use client" directive in the landing components
rg '"use client"' components/landing/

Repository: knoxiboy/DoubtDesk

Length of output: 122


🏁 Script executed:

# Find the actual locations of these components
find . -name "HeroSection.tsx" -o -name "FeaturesSection.tsx" -o -name "HowItWorksSection.tsx" -o -name "TestimonialsSection.tsx" -o -name "SignOutDialog.tsx"

Repository: knoxiboy/DoubtDesk

Length of output: 287


🏁 Script executed:

# Search for "use client" in the landing components
rg '"use client"' src/components/landing/

Repository: knoxiboy/DoubtDesk

Length of output: 44


🏁 Script executed:

# Check if these components use hooks or client-side features (useEffect, useState, etc.)
rg 'use(Effect|State|Ref|Callback|Context|Reducer|Memo|Transition|Deferred|Id|Search|FormStatus|FormState|DebugValue|LayoutEffect|InsertionEffect|TransitionEffect)' src/components/landing/

Repository: knoxiboy/DoubtDesk

Length of output: 44


🏁 Script executed:

# Check what's actually in these component files
for file in src/components/landing/HeroSection.tsx src/components/landing/FeaturesSection.tsx src/components/landing/HowItWorksSection.tsx src/components/landing/TestimonialsSection.tsx; do
  echo "=== $file ==="
  head -30 "$file"
done

Repository: knoxiboy/DoubtDesk

Length of output: 6970


🏁 Script executed:

# Check SignOutDialog and ScrollToTopButton to understand which components truly need client-side features
echo "=== SignOutDialog ===" && head -40 src/components/landing/SignOutDialog.tsx && echo -e "\n=== ScrollToTopButton ===" && head -40 src/components/ScrollToTopButton.tsx

Repository: knoxiboy/DoubtDesk

Length of output: 3017


Landing section components are being bundled client-side despite not requiring client interactivity.

Because page.tsx is marked "use client", importing HeroSection, FeaturesSection, HowItWorksSection, and TestimonialsSection directly includes them in the client bundle, even though they don't have "use client" directives themselves and don't use hooks. This works against the bundle-size reduction objective.

Consider using the composition pattern—pass these sections as children to the client boundary rather than importing them directly. Alternatively, convert them to server components if their dependencies (like Clerk's SignedIn/SignedOut) support server-side rendering.

Also applies to: 44-58

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/app/page.tsx` around lines 14 - 18, The page.tsx file is marked as a
client component with "use client" directive, which causes the imported landing
section components (HeroSection, FeaturesSection, HowItWorksSection,
TestimonialsSection) to be unnecessarily bundled client-side even though they
contain no client-side logic. To fix this, refactor the architecture to use the
composition pattern: instead of importing these sections directly in the client
component, move them to a server component and pass them as children to the
client boundary, or verify if these section components and their dependencies
(like Clerk's SignedIn/SignedOut used in SignOutDialog) can be converted to
server components. This will ensure only truly client-side interactive
components remain in the client bundle.

Comment on lines +56 to +91
<Link href="/rooms" className="w-full sm:w-auto">
<button className="group w-full sm:w-auto px-10 py-5 bg-[#5E8CFF] text-white rounded-2xl text-lg font-bold hover:bg-[#8BB8FF] hover:shadow-[0_0_24px_rgba(94,140,255,0.35)] transition-all flex items-center justify-center gap-2 hover:scale-[1.02] active:scale-[0.98]">
<span
className={`${staatliches.className} uppercase tracking-[0.08em]`}
>
Open Classroom
</span>
<ArrowRight className="w-5 h-5 group-hover:translate-x-1.5 transition-transform duration-300" />
</button>
</Link>
</SignedIn>

<SignedOut>
<Link href="/sign-up" className="w-full sm:w-auto">
<button className="group w-full sm:w-auto px-10 py-5 bg-white text-slate-950 rounded-2xl text-lg font-bold hover:bg-slate-200 transition-all flex items-center justify-center gap-2 hover:scale-[1.02] active:scale-[0.98]">
<span
className={`${staatliches.className} uppercase tracking-[0.08em]`}
>
Open
</span>
<span>Classroom</span>
<ArrowRight className="w-5 h-5 group-hover:translate-x-1.5 transition-transform duration-300" />
</button>
</Link>
</SignedOut>

<Link href="/public-rooms" className="w-full sm:w-auto">
<button className="group w-full sm:w-auto px-10 py-5 bg-slate-100 dark:bg-white/5 hover:bg-slate-200 dark:hover:bg-white/10 text-slate-900 dark:text-white rounded-2xl text-lg font-bold border border-slate-200 dark:border-white/10 transition-all hover:shadow-[0_0_20px_rgba(94,140,255,0.15)] flex items-center justify-center gap-2 hover:scale-[1.02] active:scale-[0.98]">
<span
className={`${staatliches.className} uppercase tracking-[0.08em]`}
>
Explore Community
</span>
<Globe className="w-5 h-5 text-slate-600 dark:text-slate-400 group-hover:text-blue-600 dark:group-hover:text-[#8BB8FF] group-hover:rotate-12 transition-transform duration-300" />
</button>
</Link>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid nested interactive controls in CTA markup.

Line 56 through Line 91 wraps <button> inside <Link>, creating nested interactive elements. This is invalid HTML and can cause keyboard/focus issues.

Suggested fix pattern
-<Link href="/rooms" className="w-full sm:w-auto">
-  <button className="group w-full sm:w-auto px-10 py-5 bg-[`#5E8CFF`] text-white rounded-2xl text-lg font-bold hover:bg-[`#8BB8FF`] hover:shadow-[0_0_24px_rgba(94,140,255,0.35)] transition-all flex items-center justify-center gap-2 hover:scale-[1.02] active:scale-[0.98]">
+<Link
+  href="/rooms"
+  className="group w-full sm:w-auto px-10 py-5 bg-[`#5E8CFF`] text-white rounded-2xl text-lg font-bold hover:bg-[`#8BB8FF`] hover:shadow-[0_0_24px_rgba(94,140,255,0.35)] transition-all inline-flex items-center justify-center gap-2 hover:scale-[1.02] active:scale-[0.98]"
+>
     ...
-  </button>
 </Link>

Apply the same pattern to the other CTA links in this block.

As per coding guidelines, "Accessibility (aria labels, keyboard navigation)".

📝 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.

Suggested change
<Link href="/rooms" className="w-full sm:w-auto">
<button className="group w-full sm:w-auto px-10 py-5 bg-[#5E8CFF] text-white rounded-2xl text-lg font-bold hover:bg-[#8BB8FF] hover:shadow-[0_0_24px_rgba(94,140,255,0.35)] transition-all flex items-center justify-center gap-2 hover:scale-[1.02] active:scale-[0.98]">
<span
className={`${staatliches.className} uppercase tracking-[0.08em]`}
>
Open Classroom
</span>
<ArrowRight className="w-5 h-5 group-hover:translate-x-1.5 transition-transform duration-300" />
</button>
</Link>
</SignedIn>
<SignedOut>
<Link href="/sign-up" className="w-full sm:w-auto">
<button className="group w-full sm:w-auto px-10 py-5 bg-white text-slate-950 rounded-2xl text-lg font-bold hover:bg-slate-200 transition-all flex items-center justify-center gap-2 hover:scale-[1.02] active:scale-[0.98]">
<span
className={`${staatliches.className} uppercase tracking-[0.08em]`}
>
Open
</span>
<span>Classroom</span>
<ArrowRight className="w-5 h-5 group-hover:translate-x-1.5 transition-transform duration-300" />
</button>
</Link>
</SignedOut>
<Link href="/public-rooms" className="w-full sm:w-auto">
<button className="group w-full sm:w-auto px-10 py-5 bg-slate-100 dark:bg-white/5 hover:bg-slate-200 dark:hover:bg-white/10 text-slate-900 dark:text-white rounded-2xl text-lg font-bold border border-slate-200 dark:border-white/10 transition-all hover:shadow-[0_0_20px_rgba(94,140,255,0.15)] flex items-center justify-center gap-2 hover:scale-[1.02] active:scale-[0.98]">
<span
className={`${staatliches.className} uppercase tracking-[0.08em]`}
>
Explore Community
</span>
<Globe className="w-5 h-5 text-slate-600 dark:text-slate-400 group-hover:text-blue-600 dark:group-hover:text-[#8BB8FF] group-hover:rotate-12 transition-transform duration-300" />
</button>
</Link>
<Link
href="/rooms"
className="group w-full sm:w-auto px-10 py-5 bg-[`#5E8CFF`] text-white rounded-2xl text-lg font-bold hover:bg-[`#8BB8FF`] hover:shadow-[0_0_24px_rgba(94,140,255,0.35)] transition-all inline-flex items-center justify-center gap-2 hover:scale-[1.02] active:scale-[0.98]"
>
<span
className={`${staatliches.className} uppercase tracking-[0.08em]`}
>
Open Classroom
</span>
<ArrowRight className="w-5 h-5 group-hover:translate-x-1.5 transition-transform duration-300" />
</Link>
</SignedIn>
<SignedOut>
<Link
href="/sign-up"
className="group w-full sm:w-auto px-10 py-5 bg-white text-slate-950 rounded-2xl text-lg font-bold hover:bg-slate-200 transition-all inline-flex items-center justify-center gap-2 hover:scale-[1.02] active:scale-[0.98]"
>
<span
className={`${staatliches.className} uppercase tracking-[0.08em]`}
>
Open
</span>
<span>Classroom</span>
<ArrowRight className="w-5 h-5 group-hover:translate-x-1.5 transition-transform duration-300" />
</Link>
</SignedOut>
<Link
href="/public-rooms"
className="group w-full sm:w-auto px-10 py-5 bg-slate-100 dark:bg-white/5 hover:bg-slate-200 dark:hover:bg-white/10 text-slate-900 dark:text-white rounded-2xl text-lg font-bold border border-slate-200 dark:border-white/10 transition-all hover:shadow-[0_0_20px_rgba(94,140,255,0.15)] inline-flex items-center justify-center gap-2 hover:scale-[1.02] active:scale-[0.98]"
>
<span
className={`${staatliches.className} uppercase tracking-[0.08em]`}
>
Explore Community
</span>
<Globe className="w-5 h-5 text-slate-600 dark:text-slate-400 group-hover:text-blue-600 dark:group-hover:text-[`#8BB8FF`] group-hover:rotate-12 transition-transform duration-300" />
</Link>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/landing/HeroSection.tsx` around lines 56 - 91, The code has
nested interactive controls with button elements wrapped inside Link components
for the three CTA sections (the ones with href="/rooms", href="/sign-up", and
href="/public-rooms"), which creates invalid HTML and accessibility issues.
Remove the button element wrapper from each Link and apply all the button
styling and className attributes directly to the Link component instead. This
way, the Link itself becomes the interactive control without nesting elements,
maintaining all the visual styling and hover effects while following proper HTML
semantics and accessibility guidelines.

Source: Coding guidelines

Comment on lines +37 to +42
<AlertDialogAction
onClick={onSignOut}
className="bg-red-600 hover:bg-red-700 text-white border-none rounded-xl transition-all duration-200"
>
Sign Out
</AlertDialogAction>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add pending/error handling for async sign-out action.

onSignOut is async-capable, but the dialog provides no loading state, no failure feedback, and no click guard against repeated submits. This can leave users with unclear outcomes on network/auth failures.

As per coding guidelines, "Missing loading/error states".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/landing/SignOutDialog.tsx` around lines 37 - 42, The
AlertDialogAction component with onClick={onSignOut} does not handle the async
nature of the sign-out operation, leaving users without feedback during the
request. Add a loading/pending state using useState to track whether the
sign-out is in progress, disable the AlertDialogAction button while pending to
prevent duplicate submissions, display loading feedback (such as text or
spinner) to the user during the operation, and handle any errors that occur
during sign-out by capturing them in the onClick handler and providing
appropriate error feedback to the user.

Source: Coding guidelines

Comment on lines +23 to +26
{testimonials.map((t, index) => (
<div
key={t.name}
style={{ animationDelay: `${index * 200}ms` }}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use t.id as the React key instead of t.name.

Line 25 should key by id to avoid potential key collisions when names repeat.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/landing/TestimonialsSection.tsx` around lines 23 - 26, The
testimonials.map function is currently using t.name as the React key, which can
cause key collisions if multiple testimonials share the same name. Replace
key={t.name} with key={t.id} in the testimonials.map callback to ensure each
testimonial has a unique, stable identifier that won't collide with other
entries.

@knoxiboy

Copy link
Copy Markdown
Owner

@Aditya8369 look into the suggestions from coderabbit and codeant and implement them to improve the code quality of the pr

@knoxiboy knoxiboy added quality : needs-work merge-conflict PR has merge conflicts that need resolution labels Jun 27, 2026

@knoxiboy knoxiboy left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

@Aditya8369 look into the suggestions from coderabbit and codeant and implement them to improve the code quality of the pr
Also resolve merge conflicts

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

Labels

gssoc'26 GSSoC program issue level:advanced Advanced level task merge-conflict PR has merge conflicts that need resolution review-needed size/l type:refactor Code refactoring

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[REFACTOR] Split app/page.tsx into composable sections

2 participants