Skip to content

Fix Chapters page responsiveness and country filter reset behavior#4358

Open
anurag2787 wants to merge 7 commits intoOWASP:mainfrom
anurag2787:fix/responsive-chapter-page
Open

Fix Chapters page responsiveness and country filter reset behavior#4358
anurag2787 wants to merge 7 commits intoOWASP:mainfrom
anurag2787:fix/responsive-chapter-page

Conversation

@anurag2787
Copy link
Copy Markdown
Contributor

@anurag2787 anurag2787 commented Mar 24, 2026

Proposed change

This PR improves the Chapters page UI on smaller screens and fixes an issue with the country filter input.

  • Fixed layout and overflow issues to make the page properly responsive on mobile and smaller widths
  • Updated the country filter behavior so clearing the input doesn’t automatically reset it to “All Countries”

Resolves #4282

Screencast.from.2026-03-25.01-09-03.webm

Checklist

  • Required: I followed the contributing workflow
  • Required: I verified that my code works as intended and resolves the issue as described
  • Required: I ran make check-test locally: all warnings addressed, tests passed
  • I used AI for code, documentation, tests, or communication related to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 24, 2026

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Refactors SearchPageLayout into separate mobile/desktop render paths, adjusts CountryFilter selection and responsive sizing, updates Search/SearchPageLayout padding, and modifies multiple unit tests to use plural queries, visibility-based selection, and DOM/class-based assertions instead of single-element or data-testid checks.

Changes

Cohort / File(s) Summary
Tests — resilient queries & visibility
frontend/__tests__/unit/components/SearchPageLayout.test.tsx, frontend/__tests__/unit/pages/Chapters.test.tsx, frontend/__tests__/unit/pages/Committees.test.tsx, frontend/__tests__/unit/pages/Contribute.test.tsx, frontend/__tests__/unit/pages/Projects.test.tsx, frontend/__tests__/unit/pages/Users.test.tsx, frontend/__tests__/unit/components/Search.test.tsx
Replaced single-element queries (getBy*) with plural queries (getAllBy*), added logic to pick the visible element via closest responsive ancestor and getComputedStyle(...).display, removed/avoided data-testid reliance, and switched some assertions to container.querySelector and class/structure checks.
Search layout mobile/desktop split
frontend/src/components/SearchPageLayout.tsx
Refactored header/search area into desktop (md:flex) and mobile (md:hidden) render paths; relocated filterChildren, SearchBar, and sortChildren into responsive positions; removed data-testid="sort-inline" and added mobile-specific spacing and skeleton variants.
Country filter UI & behavior
frontend/src/components/CountryFilter.tsx
Changed Autocomplete selection handling to early-return on null, map '__all__' to empty selection, removed border-r-0 from wrapper, and adjusted sizing from fixed w-52 to responsive w-[10.5rem] md:w-52 and matching popover width rules.
Search padding/responsive tweak
frontend/src/components/Search.tsx
Adjusted padding utilities to be responsive (md:py-4, md:p-4) so vertical padding applies on md+ breakpoints instead of always.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • arkid15r
  • kasya
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Test files were modified beyond scope of the linked issue requirements, including SearchPageLayout and multiple page tests with placeholder/testid assertion changes unrelated to responsiveness or filter reset. Revert unnecessary test modifications (SearchPageLayout.test.tsx, Search.test.tsx) and test assertion changes in Chapters/Committees/Contribute/Projects/Users tests that exceed the scope of fixing responsiveness and filter behavior.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the two main changes: fixing Chapters page responsiveness and updating country filter reset behavior.
Description check ✅ Passed The description is clearly related to the changeset, explaining the responsiveness fixes and country filter behavior changes with linked issue reference.
Linked Issues check ✅ Passed The PR changes comprehensively address issue #4282 requirements: responsive layout via SearchPageLayout restructuring and mobile/desktop splits, country filter reset fix via onSelectionChange logic in CountryFilter.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ 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.

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

5 issues found across 8 files

Confidence score: 3/5

  • There is a concrete user-facing regression risk in frontend/src/components/SearchPageLayout.tsx: the mobile controls wrapper renders unconditionally, which can introduce unintended empty mt-2 mb-4 spacing on pages without mobile controls.
  • The most severe reliability concern is in frontend/src/components/CountryFilter.tsx, where onSelectionChange may pass null but the value is force-cast to string, creating a plausible runtime contract violation for onCountryChange(country: string) consumers.
  • Several test updates in frontend/__tests__/unit/pages/Users.test.tsx, frontend/__tests__/unit/pages/Projects.test.tsx, and frontend/__tests__/unit/components/SearchPageLayout.test.tsx weaken visibility/styling assertions, reducing regression detection for responsive behavior and class-level UI expectations.
  • Pay close attention to frontend/src/components/SearchPageLayout.tsx and frontend/src/components/CountryFilter.tsx - layout spacing and null-handling behavior are the main merge risks.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="frontend/__tests__/unit/pages/Projects.test.tsx">

<violation number="1" location="frontend/__tests__/unit/pages/Projects.test.tsx:83">
P2: The new fallback (`|| searchInputs[0]`) makes the visibility check ineffective: the test will pass as long as any matching input exists, even if none are visible. This weakens regression protection for the responsive SearchBar behavior.</violation>
</file>

<file name="frontend/__tests__/unit/pages/Users.test.tsx">

<violation number="1" location="frontend/__tests__/unit/pages/Users.test.tsx:74">
P2: The new visibility-selection logic still only asserts DOM presence, so hidden search inputs can pass the test and mask responsive regressions.</violation>
</file>

<file name="frontend/src/components/SearchPageLayout.tsx">

<violation number="1" location="frontend/src/components/SearchPageLayout.tsx:100">
P2: Mobile controls wrapper renders unconditionally, leaving empty `mt-2 mb-4` spacing on pages without mobile filter/sort controls.</violation>
</file>

<file name="frontend/__tests__/unit/components/SearchPageLayout.test.tsx">

<violation number="1" location="frontend/__tests__/unit/components/SearchPageLayout.test.tsx:460">
P3: The `rounded-l-none` styling regression check was removed: the test now only asserts that "Sort" text renders, so it will still pass even if the `rounded-l-none` class is missing or moved, weakening the intended styling regression coverage.</violation>
</file>

<file name="frontend/src/components/CountryFilter.tsx">

<violation number="1" location="frontend/src/components/CountryFilter.tsx:36">
P2: `onSelectionChange` can receive `null` on clear, but the handler force-casts `key` to string and forwards it to `onCountryChange`, violating the `(country: string)` contract and risking runtime issues in parents.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Copy Markdown
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: 3

🧹 Nitpick comments (2)
frontend/__tests__/unit/components/SearchPageLayout.test.tsx (1)

539-542: Consider using String.raw for cleaner CSS selector escaping.

The escaped backslashes work but are harder to read. String.raw provides a cleaner syntax.

♻️ Optional refactor
     const flexRow = container.querySelector(
-      'div.hidden.w-full.items-center.justify-center.md\\:flex.gap-0'
+      String.raw`div.hidden.w-full.items-center.justify-center.md\:flex.gap-0`
     )

Apply similar changes to lines 563-565 and 589.

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

In `@frontend/__tests__/unit/components/SearchPageLayout.test.tsx` around lines
539 - 542, Replace the hard-to-read escaped CSS selector strings passed to
container.querySelector (e.g., the selector used when assigning flexRow from
container.querySelector) with String.raw template literals so you can write the
selector without double backslashes; update the three occurrences referenced
(the selector setting flexRow and the selectors at the later lines called out in
the comment) to use
String.raw`div.hidden.w-full.items-center.justify-center.md\:flex.gap-0` (and
analogous selectors) so the escaping is clearer while keeping the exact selector
text.
frontend/__tests__/unit/pages/Chapters.test.tsx (1)

120-126: Potential runtime error when closest() returns null for both selectors.

If an input element has neither .md:hidden nor .md:flex ancestor, closest returns null and window.getComputedStyle(null) throws a TypeError. The ternary at line 124 only handles the case when closest returns a truthy value, but the || at line 123 means you're passing whichever is truthy (or null if both are null) to getComputedStyle.

🔧 Proposed fix
     await waitFor(() => {
       const searchInputs = screen.getAllByPlaceholderText('Search for chapters...')
       const visibleInput =
         searchInputs.find((input) => {
           const closest = input.closest('.md\\:hidden') || input.closest('.md\\:flex')
-          return closest ? window.getComputedStyle(closest).display !== 'none' : true
+          return closest ? globalThis.getComputedStyle(closest).display !== 'none' : true
         }) || searchInputs[0]
       expect(visibleInput).toBeInTheDocument()

The logic is actually safe because when closest is null, it returns true (treating the input as visible). However, per static analysis, prefer globalThis over window for consistency.

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

In `@frontend/__tests__/unit/pages/Chapters.test.tsx` around lines 120 - 126, The
test's visible input selection uses input.closest(...) then calls
window.getComputedStyle which can throw if closest returns null; update the
logic in the searchInputs / visibleInput block (the code that uses
getAllByPlaceholderText and closest) to first check for a non-null ancestor
before calling getComputedStyle and fall back to treating the input as visible
when no ancestor is found, and replace window.getComputedStyle with
globalThis.getComputedStyle for consistency.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@frontend/__tests__/unit/pages/Contribute.test.tsx`:
- Around line 146-154: The test computes styles on input.closest(...) without
guarding for null, which can throw in getComputedStyle; update the
searchInputs/visibleInput logic so when calling window.getComputedStyle you
first check closest('.md\\:hidden') and closest('.md\\:flex') for truthiness
(e.g., store the result in a variable like ancestor and only call
getComputedStyle(ancestor) if ancestor !== null), and fall back to treating that
input as hidden/visible appropriately before selecting visibleInput used by
fireEvent.change; adjust the visibleInput selection to handle the no-ancestor
case safely.

In `@frontend/src/components/CountryFilter.tsx`:
- Line 46: The Tailwind classes `w-42` and `min-w-42` in the CountryFilter
component are invalid and ignored; remove those tokens from the class
definitions (look for the `base: 'w-42 md:w-52'` entry and the similar
`min-w-42` occurrence) and replace them with a valid spacing utility such as
`w-40` or `w-44` (or alternatively add a custom 42 value to tailwind.config.mjs
if you truly need 42). Ensure both occurrences mentioned in the comment are
updated so only valid Tailwind classes remain.
- Around line 34-38: The onSelectionChange handler currently force-casts key to
string which hides null clear events; update the handler in CountryFilter (the
selectedKey/onSelectionChange block) to explicitly check for key === null and
call onCountryChange('') for clears, otherwise treat key as a string and map the
'__all__' sentinel to ''. Remove the unsafe "key as string" cast so null is
handled explicitly and keep the onCountryChange contract (string) intact.

---

Nitpick comments:
In `@frontend/__tests__/unit/components/SearchPageLayout.test.tsx`:
- Around line 539-542: Replace the hard-to-read escaped CSS selector strings
passed to container.querySelector (e.g., the selector used when assigning
flexRow from container.querySelector) with String.raw template literals so you
can write the selector without double backslashes; update the three occurrences
referenced (the selector setting flexRow and the selectors at the later lines
called out in the comment) to use
String.raw`div.hidden.w-full.items-center.justify-center.md\:flex.gap-0` (and
analogous selectors) so the escaping is clearer while keeping the exact selector
text.

In `@frontend/__tests__/unit/pages/Chapters.test.tsx`:
- Around line 120-126: The test's visible input selection uses
input.closest(...) then calls window.getComputedStyle which can throw if closest
returns null; update the logic in the searchInputs / visibleInput block (the
code that uses getAllByPlaceholderText and closest) to first check for a
non-null ancestor before calling getComputedStyle and fall back to treating the
input as visible when no ancestor is found, and replace window.getComputedStyle
with globalThis.getComputedStyle for consistency.
🪄 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: 78f2b96f-3bf3-46c6-b1fc-306ef6148a43

📥 Commits

Reviewing files that changed from the base of the PR and between 28d4f48 and 0d82161.

📒 Files selected for processing (8)
  • frontend/__tests__/unit/components/SearchPageLayout.test.tsx
  • frontend/__tests__/unit/pages/Chapters.test.tsx
  • frontend/__tests__/unit/pages/Committees.test.tsx
  • frontend/__tests__/unit/pages/Contribute.test.tsx
  • frontend/__tests__/unit/pages/Projects.test.tsx
  • frontend/__tests__/unit/pages/Users.test.tsx
  • frontend/src/components/CountryFilter.tsx
  • frontend/src/components/SearchPageLayout.tsx

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 8 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="frontend/__tests__/unit/pages/Chapters.test.tsx">

<violation number="1" location="frontend/__tests__/unit/pages/Chapters.test.tsx:124">
P2: Responsive visibility assertion relies on Tailwind/media-query CSS, but Jest mocks CSS with identity-obj-proxy so computed styles won’t reflect breakpoints. This makes the visibility check unreliable and can pass even when real responsive behavior is wrong.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Copy Markdown
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.

♻️ Duplicate comments (1)
frontend/src/components/CountryFilter.tsx (1)

35-38: ⚠️ Potential issue | 🔴 Critical

Type safety violation: key as string does not handle null from clear button.

When the clear button is clicked, HeroUI Autocomplete emits null in onSelectionChange. The cast key as string is a type violation—null passes through and reaches onCountryChange(null), which expects a string. While this may work at runtime (the input clears), it violates the component's type contract and is fragile.

Explicitly handle the null case:

♻️ Type-safe fix
         onSelectionChange={(key) => {
+          if (key == null) {
+            onCountryChange('')
+            return
+          }
-          const countryKey = key as string
+          const countryKey = String(key)
           onCountryChange(countryKey === '__all__' ? '' : countryKey)
         }}

This preserves the current behavior (clear doesn't reset to "All Countries") while eliminating the type violation.

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

In `@frontend/src/components/CountryFilter.tsx` around lines 35 - 38, The
onSelectionChange handler in CountryFilter casts key with "key as string" which
lets null slip through to onCountryChange (violating its string type); update
the handler to explicitly handle key === null by calling onCountryChange('') and
otherwise treat key as a string and apply the existing "__all__" check (i.e., if
key === '__all__' call onCountryChange('') else call onCountryChange(key)). This
keeps the current clear behavior (input clears but doesn’t select "All
Countries") while preserving type safety for the CountryFilter component and its
onCountryChange callback.
🧹 Nitpick comments (2)
frontend/__tests__/unit/components/SearchPageLayout.test.tsx (1)

594-595: Use String.raw for consistency with other selectors.

Static analysis correctly flags that String.raw should be used here to avoid manual escaping, matching the pattern used elsewhere in this file (lines 545, 569).

♻️ Proposed fix
-    const filterWrapper = container.querySelector('div[class*="\\[&>div\\]:rounded-r-none"]')
+    const filterWrapper = container.querySelector(String.raw`div[class*="\[&>div\]:rounded-r-none"]`)
     expect(filterWrapper).toBeInTheDocument()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/__tests__/unit/components/SearchPageLayout.test.tsx` around lines
594 - 595, Replace the manually escaped selector string used in
container.querySelector with a String.raw template literal to match the pattern
used elsewhere: update the call that assigns filterWrapper (variable
filterWrapper and the expression container.querySelector(...)) to use
String.raw`div[class*="[&>div]:rounded-r-none"]` (remove the current
backslash-escaped brackets) and run the unit tests to verify the selector still
finds the element.
frontend/__tests__/unit/pages/Contribute.test.tsx (1)

146-154: Consider using a fallback instead of non-null assertion.

The non-null assertion visibleInput! at line 154 is flagged by static analysis. While the preceding assertions verify the input exists, adding a fallback would be more defensive and consistent with how other similar patterns handle this.

♻️ Suggested improvement
       const visibleInput = searchInputs.find((input) => {
         const closest =
           input.closest(String.raw`.md\:hidden`) || input.closest(String.raw`.md\:flex`)
         return closest ? globalThis.getComputedStyle(closest).display !== 'none' : true
-      })
+      }) || searchInputs[0]
       expect(visibleInput).toBeDefined()
       expect(visibleInput).toBeVisible()
-      fireEvent.change(visibleInput!, { target: { value: '' } })
+      fireEvent.change(visibleInput, { target: { value: '' } })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/__tests__/unit/pages/Contribute.test.tsx` around lines 146 - 154,
The test currently uses a non-null assertion on visibleInput when calling
fireEvent.change; replace this with a defensive fallback/guard: after computing
visibleInput (from getAllByPlaceholderText and the find callback), assert or
throw if it's null (e.g., if (!visibleInput) throw new Error('Expected visible
input');) or assign const input = visibleInput ?? /* fallback element or fail */
and then call fireEvent.change(input, { target: { value: '' } }); update
references to use input instead of visibleInput! to avoid the non-null assertion
while preserving the existing assertions (expect(visibleInput).toBeDefined(),
expect(visibleInput).toBeVisible()).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@frontend/src/components/CountryFilter.tsx`:
- Around line 35-38: The onSelectionChange handler in CountryFilter casts key
with "key as string" which lets null slip through to onCountryChange (violating
its string type); update the handler to explicitly handle key === null by
calling onCountryChange('') and otherwise treat key as a string and apply the
existing "__all__" check (i.e., if key === '__all__' call onCountryChange('')
else call onCountryChange(key)). This keeps the current clear behavior (input
clears but doesn’t select "All Countries") while preserving type safety for the
CountryFilter component and its onCountryChange callback.

---

Nitpick comments:
In `@frontend/__tests__/unit/components/SearchPageLayout.test.tsx`:
- Around line 594-595: Replace the manually escaped selector string used in
container.querySelector with a String.raw template literal to match the pattern
used elsewhere: update the call that assigns filterWrapper (variable
filterWrapper and the expression container.querySelector(...)) to use
String.raw`div[class*="[&>div]:rounded-r-none"]` (remove the current
backslash-escaped brackets) and run the unit tests to verify the selector still
finds the element.

In `@frontend/__tests__/unit/pages/Contribute.test.tsx`:
- Around line 146-154: The test currently uses a non-null assertion on
visibleInput when calling fireEvent.change; replace this with a defensive
fallback/guard: after computing visibleInput (from getAllByPlaceholderText and
the find callback), assert or throw if it's null (e.g., if (!visibleInput) throw
new Error('Expected visible input');) or assign const input = visibleInput ?? /*
fallback element or fail */ and then call fireEvent.change(input, { target: {
value: '' } }); update references to use input instead of visibleInput! to avoid
the non-null assertion while preserving the existing assertions
(expect(visibleInput).toBeDefined(), expect(visibleInput).toBeVisible()).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 00f6cb17-f8f3-4dcb-98dd-dc909a7418d9

📥 Commits

Reviewing files that changed from the base of the PR and between 0d82161 and e13bd5e.

📒 Files selected for processing (8)
  • frontend/__tests__/unit/components/SearchPageLayout.test.tsx
  • frontend/__tests__/unit/pages/Chapters.test.tsx
  • frontend/__tests__/unit/pages/Committees.test.tsx
  • frontend/__tests__/unit/pages/Contribute.test.tsx
  • frontend/__tests__/unit/pages/Projects.test.tsx
  • frontend/__tests__/unit/pages/Users.test.tsx
  • frontend/src/components/CountryFilter.tsx
  • frontend/src/components/SearchPageLayout.tsx
✅ Files skipped from review due to trivial changes (1)
  • frontend/tests/unit/pages/Committees.test.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • frontend/tests/unit/pages/Users.test.tsx
  • frontend/tests/unit/pages/Projects.test.tsx
  • frontend/src/components/SearchPageLayout.tsx

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 4 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="frontend/src/components/CountryFilter.tsx">

<violation number="1" location="frontend/src/components/CountryFilter.tsx:37">
P2: Clear action is ignored in a controlled country filter, so parent state can remain stale and filtering may not reset.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Copy link
Copy Markdown
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.

♻️ Duplicate comments (1)
frontend/src/components/CountryFilter.tsx (1)

34-42: ⚠️ Potential issue | 🟠 Major

Clear now leaves the parent filter stuck on the previous country.

selectedKey is still controlled by selectedCountry, and frontend/src/app/chapters/page.tsx:117-122 only updates that value through onCountryChange. Returning on key == null means the clear action never reaches the parent, so the old country can remain applied and any rerender can snap the selection back. The clear path needs a distinct propagated state instead of being ignored.

💡 Suggested direction
         selectedKey={selectedCountry === '' ? '__all__' : selectedCountry}
         onSelectionChange={(key) => {
           if (key == null) {
-            return // Don't update on clear - keeps input empty
+            onCountryChange(null)
+            return
           }
-          const countryKey = key as string
+          const countryKey = String(key)
           onCountryChange(countryKey === '__all__' ? '' : countryKey)
         }}

This also needs the CountryFilter contract and the parent selectedCountry state to represent a cleared value distinctly (for example null), or a separate inputValue state if you want to keep the selected filter as string.

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

In `@frontend/src/components/CountryFilter.tsx` around lines 34 - 42, The clear
action is being swallowed because onSelectionChange returns early when key ==
null, leaving the parent selectedCountry unchanged; update the CountryFilter
contract and handlers so clearing propagates: modify onSelectionChange to call
onCountryChange with a distinct cleared value (e.g., null or '') instead of
returning when key == null, and ensure the parent state (selectedCountry in the
parent component and any usage in frontend/src/app/chapters/page.tsx) accepts
and treats that distinct cleared value as “no filter” (or alternatively
introduce a separate inputValue in CountryFilter to track UI clearing and
continue to call onCountryChange('__all__' or null) so selectedKey (controlled
by selectedCountry) stays in sync). Ensure selectedKey, onSelectionChange, and
onCountryChange consistently use the chosen cleared sentinel.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@frontend/src/components/CountryFilter.tsx`:
- Around line 34-42: The clear action is being swallowed because
onSelectionChange returns early when key == null, leaving the parent
selectedCountry unchanged; update the CountryFilter contract and handlers so
clearing propagates: modify onSelectionChange to call onCountryChange with a
distinct cleared value (e.g., null or '') instead of returning when key == null,
and ensure the parent state (selectedCountry in the parent component and any
usage in frontend/src/app/chapters/page.tsx) accepts and treats that distinct
cleared value as “no filter” (or alternatively introduce a separate inputValue
in CountryFilter to track UI clearing and continue to call
onCountryChange('__all__' or null) so selectedKey (controlled by
selectedCountry) stays in sync). Ensure selectedKey, onSelectionChange, and
onCountryChange consistently use the chosen cleared sentinel.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6a63e8c2-1d90-4557-a061-79a3ca572b1c

📥 Commits

Reviewing files that changed from the base of the PR and between e13bd5e and eb8dfbe.

📒 Files selected for processing (4)
  • frontend/__tests__/unit/components/SearchPageLayout.test.tsx
  • frontend/__tests__/unit/pages/Chapters.test.tsx
  • frontend/__tests__/unit/pages/Contribute.test.tsx
  • frontend/src/components/CountryFilter.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • frontend/tests/unit/pages/Chapters.test.tsx
  • frontend/tests/unit/pages/Contribute.test.tsx
  • frontend/tests/unit/components/SearchPageLayout.test.tsx

coderabbitai[bot]
coderabbitai bot previously approved these changes Mar 24, 2026
cubic-dev-ai[bot]
cubic-dev-ai bot previously approved these changes Mar 24, 2026
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

0 issues found across 1 file (changes from recent commits).

Copy link
Copy Markdown
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.

♻️ Duplicate comments (1)
frontend/src/components/CountryFilter.tsx (1)

33-37: ⚠️ Potential issue | 🟠 Major

Clearing the field is not propagating state reset to the parent filter.

At Line 33-34, returning on null skips onCountryChange, so selectedCountry in frontend/src/app/chapters/page.tsx is not reset and downstream filter/refetch logic stays stale.

Proposed fix
-        selectedKey={selectedCountry}
+        selectedKey={selectedCountry || null}
         onSelectionChange={(key) => {
           if (key == null) {
-            return
+            onCountryChange('')
+            return
           }
-          const countryKey = key as string
-          onCountryChange(countryKey === '__all__' ? '' : countryKey)
+          onCountryChange(String(key))
         }}
For `@heroui/autocomplete` v2.3.34, confirm:
1) `onSelectionChange` emits `null` when the clear action is used.
2) `selectedKey={null}` is the intended controlled "empty selection" state.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/CountryFilter.tsx` around lines 33 - 37, The handler
currently returns early when the autocomplete selection handler receives null,
preventing propogation of the reset to the parent; update the onSelectionChange
logic in the CountryFilter component so that when key === null it calls
onCountryChange('') (treating null as cleared selection) instead of returning,
preserving the existing branch that converts '__all__' to '' for non-null keys;
ensure this uses the same onCountryChange symbol so the parent selectedCountry
is reset.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@frontend/src/components/CountryFilter.tsx`:
- Around line 33-37: The handler currently returns early when the autocomplete
selection handler receives null, preventing propogation of the reset to the
parent; update the onSelectionChange logic in the CountryFilter component so
that when key === null it calls onCountryChange('') (treating null as cleared
selection) instead of returning, preserving the existing branch that converts
'__all__' to '' for non-null keys; ensure this uses the same onCountryChange
symbol so the parent selectedCountry is reset.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b4e5a44d-8610-44ff-9f09-f05a8605d599

📥 Commits

Reviewing files that changed from the base of the PR and between eb8dfbe and 65500f6.

📒 Files selected for processing (1)
  • frontend/src/components/CountryFilter.tsx

coderabbitai[bot]
coderabbitai bot previously approved these changes Mar 24, 2026
@anurag2787 anurag2787 marked this pull request as ready for review March 24, 2026 19:40
@anurag2787
Copy link
Copy Markdown
Contributor Author

Hi @arkid15r @kasya the pr is ready for review Thanks!

Copy link
Copy Markdown
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.

Thanks for improving that @anurag2787
Would it be possible to align the search bar width with the components below (see the screenshot)

Image

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="frontend/src/components/Search.tsx">

<violation number="1" location="frontend/src/components/Search.tsx:84">
P2: Unconditional `md:py-4` overrides the `p-0` branch at medium+ breakpoints, reintroducing vertical padding for `rounded-none`/`rounded-r-none` inline layouts.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

coderabbitai[bot]
coderabbitai bot previously approved these changes Mar 25, 2026
@anurag2787
Copy link
Copy Markdown
Contributor Author

anurag2787 commented Mar 25, 2026

Hi @arkid15r i have updated it could you please re-review it Thanks!
image

@anurag2787 anurag2787 requested a review from arkid15r March 25, 2026 07:29
Copy link
Copy Markdown
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.

@anurag2787 thanks for working on this! I like the update for keyboard navigation with backspace 👍🏼

Noticed a couple of issues with the UI on some screen sizes though ⬇️

))}
</div>

{/* Mobile layout */}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can we update this so there's no gap between the two on the mobile screens? This way we can keep border-r-0 on the filter too.
Right now, it looks weird on larger screens and I feel like that would make more sense for these 2 components to fill the whole width.

Image Image

@sonarqubecloud
Copy link
Copy Markdown

@anurag2787
Copy link
Copy Markdown
Contributor Author

Hi @kasya i have updated it but keeped the layout same so that UI doesnot breaks in medium screen
Screencast from 2026-03-28 11-10-01.webm

@anurag2787 anurag2787 requested a review from kasya March 28, 2026 06:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Chapters page not responsive and country filter input resets when clearing selection

3 participants