feat: add dedicated FAQ page#80
Conversation
🚀 PR Received SuccessfullyHello @saurabhhhcodes, Thank you for taking the initiative to contribute to this project. Please ensure that your PR follows all project guidelines properly before requesting review.
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a centralized ChangesFAQ Page Feature
Sequence Diagram(s)sequenceDiagram
participant Client
participant Router
participant FAQPage
participant FAQIndex
participant Accordion
Client->>Router: navigate to /faq
Router->>FAQPage: render FAQPage
FAQPage->>FAQIndex: build index from faqs
FAQPage->>Accordion: render accordion items from faqs
FAQIndex->>FAQPage: toggleFaq(index, scroll=true)
FAQPage->>Accordion: open item (openIdx change) and requestAnimationFrame scroll
Accordion->>Client: reveal answer panel (item.a)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai review this entire PR thoroughly and point out every area that can be improved, optimized, or made more logically consistent so the overall implementation becomes cleaner, stronger, and production-ready for the project. |
🧩 Analysis chain🏁 Script executed: Length of output: 24720
1.
|
| Issue | Location | Fix |
|---|---|---|
+ / - <span> not hidden from screen readers |
Accordion toggle button | Add aria-hidden="true" to the span |
No aria-controls on accordion buttons |
Each <button> |
Add aria-controls={item.id} and id={item.id} on the panel <div> |
No id on answer panel |
<div> after button |
Add id={item.id} |
Corrected button:
<button
type="button"
onClick={() => setOpenIdx(isOpen ? null : index)}
className="..."
aria-expanded={isOpen}
aria-controls={`faq-panel-${item.id}`}
>
<span className="...">{item.q}</span>
<span className="text-4xl font-black leading-none" aria-hidden="true">
{isOpen ? "−" : "+"}
</span>
</button>
<div id={`faq-panel-${item.id}`} ...>E. key={item.q} is fragile
Use the stable id proposed above: key={item.id}.
F. supportTopics array is hardcoded and disconnected from data
const supportTopics = [
"Platform tracking",
"Data privacy",
"Open source",
"Account setup",
];These four labels don't map to any FAQ entry. Either derive them from a category field on the FAQ objects, or remove the chips to avoid implying filterable categories that don't work.
G. "Back To Explore" CTA always hardcodes /explore
If a user arrives at /faq from the Footer or any other path, clicking the CTA always sends them to /explore regardless of history. A simple improvement:
import { useNavigate } from "react-router-dom";
const navigate = useNavigate();
// ...
<button onClick={() => navigate(-1)}>Go Back</button>Or at minimum label it "Explore the Platform" to set correct expectations.
H. No document <title> for SEO
The page has no <title> update. Use the React Router <title> element (v7) or a <Helmet> equivalent:
// React Router v7
<title>FAQ – CodeLens</title>3. src/components/explore/FAQSection.jsx
A. type="button" missing on accordion toggle
// ❌ current
<button onClick={() => toggle(index)} className="...">
// ✅ fix
<button type="button" onClick={() => toggle(index)} className="...">Without type="button", if this component is ever nested in a <form>, clicking will submit the form.
B. key={index} is an anti-pattern
// ❌ current
<div key={index} ...>
// ✅ fix — once id is added to faqs.js
<div key={item.id} ...>C. maxHeight: "500px" will clip long answers
style={{ maxHeight: isOpen ? "500px" : "0px" }}If any answer exceeds ~500px of rendered height (especially on mobile), it will be silently truncated with no scroll or indicator. Use CSS Grid animation instead:
<div
className="overflow-hidden transition-all duration-300 ease-in-out"
style={{ maxHeight: isOpen ? "1000px" : "0px" }} // or use a ref-measured value
>Or better, use a CSS Grid approach:
<div
className={`grid transition-all duration-300 ease-in-out ${isOpen ? "grid-rows-[1fr]" : "grid-rows-[0fr]"}`}
>
<div className="overflow-hidden">
<p className="...">{item.a}</p>
</div>
</div>D. "border-3" is not a valid Tailwind CSS class
className="border-3 border-black ..." // ❌ — no such class in default Tailwind configTailwind's border-width scale goes border (1px), border-2 (2px), border-4 (4px). border-3 silently produces no border. Change to border-2 or border-4.
4. src/App.jsx
A. Missing blank line before FAQPage import
Minor but inconsistent with the rest of the file's import style — the FAQPage import is placed directly before export default function App() without a blank line. Group it with the other page imports.
// ❌ current (at bottom, right before export)
import FAQPage from "./pages/FAQPage";
export default function App() {
// ✅ fix — move into the page imports block above
import TermsPage from "./pages/TermsPage";
import PrivacyPage from "./pages/PrivacyPage";
import FAQPage from "./pages/FAQPage"; // ← here
import NotFoundPage from "./pages/NotFoundPage";5. src/components/shared/Footer.jsx
A. /codeforces is a protected route in the public Platform list
{ to: "/dashboard", label: "Dashboard" },
{ to: "/explore", label: "Explore" },
{ to: "/faq", label: "FAQ" }, // ✅ public — correct
{ to: "/codeforces", label: "Codeforces" }, // ⚠️ protected routeUnauthenticated users clicking "Codeforces" from the footer will be redirected to login, with no explanation. Either remove it from the footer, add an auth-aware wrapper, or add a tooltip/badge (e.g., "Login required"). This isn't introduced by this PR but is exposed now that you're auditing footer links.
Summary of Issues by Priority
| Priority | File | Issue |
|---|---|---|
| 🔴 High | FAQPage.jsx |
Sidebar & accordion state logic inconsistency |
| 🔴 High | FAQSection.jsx |
border-3 is not a valid Tailwind class — no border rendered |
| 🔴 High | FAQSection.jsx |
maxHeight: 500px clips long answers |
| 🟠 Medium | FAQPage.jsx |
No scroll-to-item on sidebar click |
| 🟠 Medium | FAQPage.jsx |
supportTopics chips disconnected from FAQ data |
| 🟠 Medium | FAQPage.jsx |
Missing aria-controls / aria-hidden on toggle |
| 🟠 Medium | faqs.js |
No id field — fragile key usage in both components |
| 🟠 Medium | FAQSection.jsx |
Missing type="button" on accordion toggle |
| 🟡 Low | FAQPage.jsx |
openIdx initialized to 0 instead of null |
| 🟡 Low | FAQPage.jsx |
"Back To Explore" ignores navigation history |
| 🟡 Low | FAQPage.jsx |
No page <title> for SEO |
| 🟡 Low | App.jsx |
FAQPage import placement out of group |
✅ Actions performed
Full review triggered.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
frontend/src/pages/FAQPage.jsx (1)
80-99: ⚡ Quick winBind each toggle button to its panel with ARIA ids.
Add
aria-controlson the button, andid+aria-labelledbyon the panel; mark the symbol as decorative.♿ Proposed fix
{faqs.map((item, index) => { const isOpen = openIdx === index; + const panelId = `faq-panel-${index}`; + const buttonId = `faq-button-${index}`; return ( <article key={item.q} className="border-4 border-black bg-white shadow-[8px_8px_0_0_rgba(0,0,0,1)]" > <button type="button" onClick={() => setOpenIdx(isOpen ? null : index)} className="flex w-full items-center justify-between gap-6 p-6 text-left sm:p-8" aria-expanded={isOpen} + aria-controls={panelId} + id={buttonId} > <span className="text-2xl font-black uppercase leading-tight tracking-tight sm:text-4xl"> {item.q} </span> - <span className="text-4xl font-black leading-none"> + <span className="text-4xl font-black leading-none" aria-hidden="true"> {isOpen ? "-" : "+"} </span> </button> {isOpen && ( - <div className="border-t-4 border-black px-6 py-6 sm:px-8"> + <div + id={panelId} + aria-labelledby={buttonId} + className="border-t-4 border-black px-6 py-6 sm:px-8" + > <p className="max-w-3xl text-base font-bold leading-relaxed text-black sm:text-lg"> {item.a} </p> </div> )}🤖 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 `@frontend/src/pages/FAQPage.jsx` around lines 80 - 99, The button and panel need ARIA linking: give the toggle button a unique id (e.g., `faq-button-${index}`) and add aria-controls pointing to the panel id; give the panel a matching id (e.g., `faq-panel-${index}`) and aria-labelledby referencing the button id; mark the decorative +/- span as aria-hidden="true". Update the JSX around the toggle (where setOpenIdx, isOpen, index, item.q/item.a are used) to generate these ids so each button-panel pair is uniquely bound.frontend/src/data/faqs.js (1)
1-18: ⚡ Quick winAdd a stable
idfield to each FAQ item.Using mutable text (
q) as identity is actively causing issues across two components.FAQPage.jsxrenders FAQs withkey={item.q}at two locations (lines 56 and 77), andFAQSection.jsxuseskey={index}at line 23. Both patterns are fragile: if question text is edited or the list is reordered, React loses component identity and state association. Add a stableidto each FAQ and consume it downstream.♻️ Proposed change
export const faqs = [ { + id: "what-is-codelens", q: "What is CodeLens?", a: "CodeLens is a platform that helps developers track their coding progress across different platforms like Codeforces, LeetCode, and GitHub in one place.", }, { + id: "problem-codelens-solves", q: "What problem does CodeLens solve?", a: "It brings all your coding activity into one place so you can understand your progress, stay consistent, and know what to improve next.", }, { + id: "repository-data-privacy", q: "Is my repository data private?", a: "CodeLens only uses publicly available data from connected platforms and does not store any sensitive information.", }, { + id: "how-to-contribute", q: "How can I contribute to CodeLens?", a: "You can contribute by solving issues, adding features, improving UI, or fixing bugs. Check the repository and start with beginner-friendly issues.", }, ];🤖 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 `@frontend/src/data/faqs.js` around lines 1 - 18, The faqs array items lack stable IDs which breaks React identity in FAQPage.jsx (uses key={item.q}) and FAQSection.jsx (uses key={index}); add a unique, stable id property to each object in the exported faqs array (e.g., "id": "faq-1", etc.) and update the consuming components to use key={item.id} instead of key={item.q} or key={index} so component identity is preserved when text changes or items reorder.
🤖 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 `@frontend/src/pages/FAQPage.jsx`:
- Around line 55-59: The button's onClick currently always sets open via
setOpenIdx(index) while the accordion header uses toggle logic; change the
button's handler to the same toggle pattern used by the accordion header by
calling setOpenIdx(prev => (prev === index ? null : index)) so it closes when
already open and opens otherwise; locate the onClick on the button that
references setOpenIdx and update it to use the toggle function, keeping openIdx
and index as the comparison keys.
---
Nitpick comments:
In `@frontend/src/data/faqs.js`:
- Around line 1-18: The faqs array items lack stable IDs which breaks React
identity in FAQPage.jsx (uses key={item.q}) and FAQSection.jsx (uses
key={index}); add a unique, stable id property to each object in the exported
faqs array (e.g., "id": "faq-1", etc.) and update the consuming components to
use key={item.id} instead of key={item.q} or key={index} so component identity
is preserved when text changes or items reorder.
In `@frontend/src/pages/FAQPage.jsx`:
- Around line 80-99: The button and panel need ARIA linking: give the toggle
button a unique id (e.g., `faq-button-${index}`) and add aria-controls pointing
to the panel id; give the panel a matching id (e.g., `faq-panel-${index}`) and
aria-labelledby referencing the button id; mark the decorative +/- span as
aria-hidden="true". Update the JSX around the toggle (where setOpenIdx, isOpen,
index, item.q/item.a are used) to generate these ids so each button-panel pair
is uniquely bound.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 4c9c87f3-447a-453f-a027-cb1b819b5faa
📒 Files selected for processing (5)
frontend/src/App.jsxfrontend/src/components/explore/FAQSection.jsxfrontend/src/components/shared/Footer.jsxfrontend/src/data/faqs.jsfrontend/src/pages/FAQPage.jsx
|
Addressed the CodeRabbit review feedback in commit |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@frontend/src/components/explore/FAQSection.jsx`:
- Around line 48-55: The FAQ panel div with id `landing-faq-panel-${item.id}` is
kept mounted for animation but lacks hidden semantics; update that div to
include aria-hidden={isOpen ? "false" : "true"} (or aria-hidden={!isOpen}) and
add accessible region attributes such as role="region" and aria-labelledby
pointing to the question toggle (e.g., `landing-faq-button-${item.id}`), and
ensure the toggle button that controls `isOpen` has the matching id so screen
readers know which heading labels the region.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: 5551b5b4-74d0-4685-bb30-0029b2c16390
📒 Files selected for processing (4)
frontend/src/App.jsxfrontend/src/components/explore/FAQSection.jsxfrontend/src/data/faqs.jsfrontend/src/pages/FAQPage.jsx
|
Pushed Updated the landing FAQ accordion so each animated panel is now explicitly bound to its toggle:
Validation:
|
|
@coderabbitai please check whether @saurabhhhcodes resolved every level issues you mentioned before or something else |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 26164
Verification Report✅ All High-Priority Issues — Fixed
✅ All Medium-Priority Issues — Fixed
✅ /
|
| Issue | Status |
|---|---|
🟡 openIdx initialized to 0 |
✅ Changed to null |
🟡 No <title> for SEO |
✅ <title>FAQ - CodeLens</title> present |
🟡 FAQPage import out of group |
✅ Now correctly placed before NotFoundPage |
🟡 "Back To Explore" hardcodes /explore |
to="/explore" — not fixed, but low impact |
🆕 New Issue Found — Medium Priority
FAQPage.jsx: aria-controls points to a conditionally-rendered panel
The answer panel in FAQPage is rendered only when isOpen is true:
{isOpen && (
<div id={`faq-panel-${item.id}`} ...> // ← Only exists in DOM when open
...
</div>
)}But the toggle button always has:
aria-controls={`faq-panel-${item.id}`}When the panel is collapsed, the id it references doesn't exist in the DOM, so screen readers cannot find or announce the controlled region. FAQSection.jsx already handles this correctly by always rendering the panel and using grid-rows-[0fr] to collapse it visually.
The fix is to adopt the same pattern used in FAQSection.jsx:
<article key={item.id} ref={(el) => { itemRefs.current[index] = el; }} className="...">
<button
type="button"
onClick={() => toggleFaq(index)}
aria-expanded={isOpen}
aria-controls={`faq-panel-${item.id}`}
className="..."
>
<span className="...">{item.q}</span>
<span aria-hidden="true">{isOpen ? "−" : "+"}</span>
</button>
{/* Always in DOM — collapsed via CSS grid, not conditional rendering */}
<div
id={`faq-panel-${item.id}`}
role="region"
aria-labelledby={`faq-btn-${item.id}`}
aria-hidden={!isOpen}
className={`grid transition-all duration-300 ease-in-out border-t-4 border-black ${
isOpen ? "grid-rows-[1fr]" : "grid-rows-[0fr]"
}`}
>
<div className="overflow-hidden">
<p className="px-6 py-6 sm:px-8 max-w-3xl text-base font-bold leading-relaxed text-black sm:text-lg">
{item.a}
</p>
</div>
</div>
</article>Summary for Merge Decision
The PR is in good shape overall — all high and medium issues from the original review are resolved. Before merging, it's worth asking @saurabhhhcodes to fix the aria-controls / conditional rendering issue above (medium severity, screen-reader regression introduced in the latest accessibility commit). The "Back To Explore" link is low priority and can be deferred if needed.
|
@coderabbitai what do you mean by hardcoding /explore |
|
Tip For best results, initiate chat on the files or code changes.
"Hardcoding // ❌ Hardcoded — always goes to /explore, even if user came from /dashboard or /faq via Footer
<Link to="/explore">Back To Explore</Link>The problem: If a user clicks "FAQ" from the Footer (while on The better alternative — import { useNavigate } from "react-router-dom";
const navigate = useNavigate();
// ✅ Goes back to wherever the user came from
<button type="button" onClick={() => navigate(-1)}>
← Go Back
</button>This uses the browser's history stack, so the user always returns to the page they were on before — whether that was If you want to keep it simple and always go to ʕ •ᴥ•ʔ |
|
@saurabhhhcodes implement the better alternative that coderabbitai mentioned put neccessary screenshot of final result and also put a video also showcasing result (via drive link) |
|
Implemented the requested follow-up in What changed:
Validation:
The PR should be ready for your review again. |
|
Pushed one more small polish commit: What changed:
Validation run after this commit:
CodeRabbit was already green on the prior head, and this latest change is scoped to responsive containment only. The PR should be ready for maintainer review again. |
|
Quick follow-up: this PR is still clean and mergeable from my side after the last polish commit. Since the PR already carries the GSSoC labels and mentor tag, please merge it when you get a chance if there is no further feedback. |
|
@saurabhhhcodes attach screen shot plus working site video for that page and also show browser console while opring faq page |
|
Hi! Checking back on this PR since the branch is still cleanly mergeable on GitHub. If there are any requested adjustments, I can turn them around quickly. |
|
Please perform one final deep and complete review of this PR from a production-quality perspective before merge. Do a holistic review of the entire implementation and verify whether this contribution is genuinely clean, professional, scalable, and well integrated with the existing CodeLens codebase. Please specifically review:
Also verify:
Please review the actual final state carefully instead of only checking incremental diffs so we can confidently decide whether this PR should be merged. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 30148
✅ Issues from All Previous Reviews — Resolution Status
🔍 Final Deep Review — Remaining Findings🟠 Medium —
|
| Area | Verdict |
|---|---|
| Architecture / file layout | ✅ Clean — data in /data, page in /pages, component in /components/explore |
| Route registration | ✅ Public /faq route, correctly ordered before * wildcard |
| Data layer reuse | ✅ Single faqs.js source, consumed by both FAQPage and FAQSection — no duplication |
| Accordion state logic | ✅ Correct toggle, collapsed by default, functional setState update pattern |
| Stable React keys | ✅ item.id used everywhere, no index keys |
| Accessibility (ARIA) | ✅ aria-expanded, aria-controls, aria-labelledby, aria-hidden, role="region" — all correct and consistent |
aria-controls DOM integrity |
✅ Panels always mounted, collapsed visually only |
| ID namespacing | ✅ FAQSection uses landing-faq-* prefix to avoid collision with FAQPage's faq-* IDs |
| Animations | ✅ CSS grid transition — smooth, no JS height measurement needed |
| Mobile responsiveness | ✅ break-words on sidebar labels, stacked chips on mobile, sticky sidebar on desktop |
<title> SEO |
✅ Valid React 19 metadata element, hoisted to <head> |
navigate(-1) |
✅ Correct behavior — but needs fallback (see Medium issue above) |
| Import grouping | ✅ Correct |
No console.log |
✅ Clean |
border-3 |
✅ Replaced with border-2 |
type="button" |
✅ Present on all toggle buttons |
Footer /faq link |
✅ Added and routes correctly |
| React 19 + RR v7 compatibility | ✅ No deprecated APIs used |
Merge Verdict
This PR is mergeable. All high and medium issues from the original review have been cleanly resolved. The two remaining medium items (navigate(-1) fallback and the CTA copy mismatch) are UX polish items — the navigate(-1) fallback in particular is worth a quick fix before merge since a user arriving via a direct link will get a broken "Go Back" button. The low-priority items can be addressed in a follow-up.
Recommended before merge:
- 🟠 Add the
navigate(-1)fallback (2-line fix) - 🟠 Fix the CTA section heading to match the "Go Back" button label
Can be deferred to a follow-up PR:
3. 🟡 Replace width: 100vw with w-full
4. 🟡 Double-rAF scroll timing
5. 🟡 4th FAQ category / more entries
|
Got it — I’m working on the proof bundle you asked for for the FAQ page flow, including the screenshot/browser-console check, and I’ll add that as a follow-up on this PR. |
|
Pushed one more polish commit on this PR just now. It addresses the latest review points by adding a safe fallback for the |
|
Quick follow-up here — I already pushed the FAQ polish pass requested in review. The main remaining ask on my side is visual proof once the local frontend runner cooperates again. |
|
Please perform one final extremely deep and production-level review of this entire PR from an engineering, scalability, maintainability, and architecture perspective. I want this review to be very strict and highly critical — not just surface-level checks. Please thoroughly verify:
Also verify carefully:
Please review the FINAL current state of the PR holistically instead of only checking incremental diffs so we can confidently decide whether this should be merged into production. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
echo "=== App.jsx ==="
cat frontend/src/App.jsx
echo ""
echo "=== FAQPage.jsx (full) ==="
cat frontend/src/pages/FAQPage.jsx
echo ""
echo "=== FAQSection.jsx (full) ==="
cat frontend/src/components/explore/FAQSection.jsx
echo ""
echo "=== Footer.jsx (full) ==="
cat frontend/src/components/shared/Footer.jsx
echo ""
echo "=== faqs.js (full) ==="
cat frontend/src/data/faqs.js
echo ""
echo "=== Existing page components for consistency check ==="
cat frontend/src/pages/ExplorePage.jsx 2>/dev/null || echo "ExplorePage.jsx not found"
cat frontend/src/pages/TermsPage.jsx 2>/dev/null || echo "TermsPage.jsx not found"
echo ""
echo "=== Router / App structure ==="
rg -n "Route\|route\|path=" frontend/src/App.jsx
echo ""
echo "=== Check duplicate FAQ data anywhere in codebase ==="
rg -rn "What is CodeLens\|faqs\|FAQ" --type jsx --type js -g '!node_modules' 2>/dev/null || \
rg -rn "What is CodeLens\|faqs\|FAQ" -g '!node_modules' -g '!*.test.*' -g '!dist'
echo ""
echo "=== Check aria attributes in FAQPage ==="
rg -n "aria-" frontend/src/pages/FAQPage.jsx
echo ""
echo "=== Check aria in FAQSection ==="
rg -n "aria-" frontend/src/components/explore/FAQSection.jsx
echo ""
echo "=== Check navigate usage in FAQPage ==="
rg -n "navigate\|history\|window.history\|useNavigate" frontend/src/pages/FAQPage.jsx
echo ""
echo "=== Check for conditional rendering of panels ==="
rg -n "isOpen &&\|isOpen ?\|{isOpen\|grid-rows" frontend/src/pages/FAQPage.jsx frontend/src/components/explore/FAQSection.jsx
echo ""
echo "=== Check for 100vw or w-full in FAQPage ==="
rg -n "100vw\|w-full\|overflow-x" frontend/src/pages/FAQPage.jsx
echo ""
echo "=== Check requestAnimationFrame usage ==="
rg -n "requestAnimationFrame\|rAF\|scrollIntoView" frontend/src/pages/FAQPage.jsx
echo ""
echo "=== Check type=button presence ==="
rg -n 'type="button"' frontend/src/pages/FAQPage.jsx frontend/src/components/explore/FAQSection.jsx
echo ""
echo "=== Check for console.log ==="
rg -n "console\." frontend/src/pages/FAQPage.jsx frontend/src/components/explore/FAQSection.jsx frontend/src/data/faqs.js
echo ""
echo "=== Check border-3 still exists ==="
rg -n "border-3" frontend/src/pages/FAQPage.jsx frontend/src/components/explore/FAQSection.jsx
echo ""
echo "=== Check stable keys ==="
rg -n "key={" frontend/src/pages/FAQPage.jsx frontend/src/components/explore/FAQSection.jsx
echo ""
echo "=== Check package.json for React Router version ==="
python3 -c "
import json, sys
with open('frontend/package.json') as f:
d = json.load(f)
deps = {**d.get('dependencies',{}), **d.get('devDependencies',{})}
for k,v in sorted(deps.items()):
if any(x in k.lower() for x in ['react', 'router', 'vite', 'eslint', 'tailwind']):
print(f'{k}: {v}')
" 2>/dev/null || cat frontend/package.json
echo ""
echo "=== Check for any hardcoded /explore ==="
rg -n '"/explore"\|to="/explore"' frontend/src/pages/FAQPage.jsx
echo ""
echo "=== Check CTA copy ==="
rg -n "Still Curious\|Go Back\|Explore The Platform\|Back To Explore\|Done" frontend/src/pages/FAQPage.jsx
echo ""
echo "=== Check title element ==="
rg -n "<title\|document.title" frontend/src/pages/FAQPage.jsx
echo ""
echo "=== Check for id collisions between FAQPage and FAQSection ==="
rg -n 'id={`faq\|id="faq' frontend/src/pages/FAQPage.jsx frontend/src/components/explore/FAQSection.jsx
echo ""
echo "=== Check FAQSection ViewAll link ==="
rg -n "View All\|/faq" frontend/src/components/explore/FAQSection.jsx
echo ""
echo "=== Check all existing data files ==="
fd --type f --extension js src/data 2>/dev/null || find frontend/src/data -type f 2>/dev/null
echo ""
echo "=== Check imports of faqs across the codebase ==="
rg -rn "from.*faqs\|require.*faqs" -g '!node_modules'
echo ""
echo "=== Check focusable elements / keyboard nav in FAQPage ==="
rg -n "tabIndex\|onKeyDown\|onKeyPress\|focus" frontend/src/pages/FAQPage.jsx
echo ""
echo "=== Total lines in FAQPage ==="
wc -l frontend/src/pages/FAQPage.jsxLength of output: 35329
Final Production-Level Review — PR
|
| # | Issue | Status |
|---|---|---|
| 1 | Sidebar/accordion state inconsistency | ✅ Unified toggleFaq() |
| 2 | border-3 invalid Tailwind class |
✅ → border-2 |
| 3 | maxHeight: 500px clips answers |
✅ → CSS grid grid-rows-[1fr/0fr] |
| 4 | No scroll-to-item on sidebar click | ✅ Double rAF + scrollIntoView |
| 5 | supportTopics disconnected from data |
✅ Derived via [...new Set(faqs.map(f => f.category))] |
| 6 | Missing aria-controls / aria-hidden |
✅ Present on both FAQPage and FAQSection |
| 7 | No stable id in faqs.js |
✅ id + category on every entry |
| 8 | Missing type="button" |
✅ All three buttons in FAQPage, toggle in FAQSection |
| 9 | openIdx initialized to 0 |
✅ → null |
| 10 | No <title> for SEO |
✅ <title>FAQ - CodeLens</title> (React 19 metadata hoisting) |
| 11 | FAQPage import out of group |
✅ Correctly between PrivacyPage and NotFoundPage |
| 12 | aria-controls → conditionally-rendered panel |
✅ Panels always mounted, collapsed via CSS only |
| 13 | Hardcoded /explore + CTA copy mismatch |
✅ navigate(-1) with window.history.length > 1 fallback; copy updated to "All Caught Up? / Head Back To The Platform." |
Remaining Issues Found in Final State
🟠 Medium — border-t-4 border-black Is Always Visible on the Collapsed Panel
In FAQPage.jsx, the answer panel div always carries border-t-4 border-black:
className={`grid border-t-4 border-black transition-all duration-300 ease-in-out ${
isOpen ? "grid-rows-[1fr]" : "grid-rows-[0fr]"
}`}With grid-rows-[0fr], the inner content collapses to 0px, but the CSS border is on the outer panel div and remains 4px tall regardless. Every collapsed question in FAQPage will render a persistent black hairline below the toggle button — it never disappears. FAQSection.jsx does not have this issue because its border is not on the panel div.
If this is intentional (as a brutalist bottom separator between cards), the card's own border-4 border-black already provides that. If unintentional, fix by making the border conditional:
className={`grid transition-all duration-300 ease-in-out ${
isOpen
? "grid-rows-[1fr] border-t-4 border-black"
: "grid-rows-[0fr]"
}`}🟡 Low — 3 Chips in a sm:grid-cols-2 Grid (Unbalanced Layout)
faqs.js has two entries with category: "Platform tracking", so [...new Set(...)] yields exactly 3 unique categories. On tablet and desktop the chip grid is sm:grid-cols-2, which renders the third chip alone in a second row:
[ Platform tracking ] [ Data privacy ]
[ Open source ]
Options:
- Add a 4th FAQ entry with a new category (e.g.,
"Account setup") - Or switch to
sm:grid-cols-3for exactly 3 chips
🟡 Low — Redundant <p> + <span className="block"> in Answer Panel
<p className="max-w-3xl text-base font-bold ...">
<span className="block px-6 py-6 sm:px-8">{item.a}</span>
</p>A <span> with display: block inside a <p> is valid HTML but unnecessarily layered. Simplify to:
<p className="max-w-3xl px-6 py-6 sm:px-8 text-base font-bold leading-relaxed text-black sm:text-lg">
{item.a}
</p>🟡 Low — window.history.length > 1 Is Browser-Dependent
The fallback guard is sensible and the best available approach without complex history state management. On some browsers a fresh tab starts with history.length === 2 rather than 1, so the guard will trigger navigate(-1) even for direct-link arrivals — but the user would navigate to the browser's previous page (a new tab or home), which is acceptable. No action required; just worth being aware of.
ℹ️ Pre-existing (Not Introduced by This PR) — /codeforces in Public Footer
{ to: "/codeforces", label: "Codeforces" }, // protected routeUnauthenticated users clicking this from the footer land on a redirect-to-login flow with no warning. This predates this PR and should be addressed separately.
Architecture & Scalability Assessment
| Dimension | Assessment |
|---|---|
| File structure | ✅ Data in /data, page in /pages, embed in /components/explore — clean separation |
| Data layer | ✅ Single source of truth (faqs.js); both consumers import from it — no duplication |
| Scalability | ✅ Adding more FAQs requires only a new entry in faqs.js; categories auto-propagate to chips |
| Routing | ✅ Public /faq route, correctly placed before the * wildcard |
| Navigation | ✅ navigate(-1) with graceful /explore fallback |
| Accessibility | ✅ aria-expanded, aria-controls, aria-labelledby, role="region", aria-hidden, type="button", aria-hidden on decorative icons — correctly namespaced IDs prevent DOM collisions between FAQSection (landing-faq-*) and FAQPage (faq-*) |
| Keyboard nav | ✅ Native <button> handles Enter/Space; no custom key handlers needed |
| Animations | ✅ CSS grid transition — no JS height measurement, GPU-friendly |
| React keys | ✅ Stable item.id keys everywhere |
| Mobile layout | ✅ break-words on sidebar labels, stacked chips, w-full container, lg:sticky sidebar |
| React version compat | ✅ React 19 + RR v7 — <title> hoisting works, no deprecated APIs |
| No debug artifacts | ✅ Zero console.log calls |
| Content depth |
Merge Verdict
The PR is merge-ready. All 13 previously flagged issues have been properly resolved. The implementation is clean, well-structured, accessible, and integrates correctly with the existing CodeLens architecture.
One item recommended before merge:
- 🟠 Fix the always-visible
border-t-4 border-blackon collapsed panels inFAQPage.jsx(2-line fix above) — unless it is intentionally part of the design.
Can be deferred to a follow-up:
- 🟡 4th FAQ category to balance the chip grid
- 🟡 Redundant
<p>/<span>nesting - 🟡 More FAQ content entries
- 🟡 Footer
/codeforcesauth-awareness (pre-existing)
|
@saurabhhhcodes you havent attached screenshots and proper video ? |
|
Thanks for the nudge. I pushed one final polish commit ( Validation done:
|



Summary
Adds a dedicated FAQ page for CodeLens and wires the existing FAQ CTA/footer navigation to the new route.
Fixes #31
Changes
/faqroute and a full-page FAQ experiencesrc/data/faqs.jsValidation
Local checks run:
Notes:
npm run buildis blocked in this macOS environment by the Rolldown native binding code-signature error after a fresh install; the failure occurs before app source bundling.Summary by CodeRabbit
New Features
Refactor
Accessibility & UX
Style
Suggested GSSoC labels if accepted:
gssoc:approved,level:beginner,quality:clean,type:feature,type:design.