Skip to content

feat: add page satisfaction feedback banner (Vertex app)#3502

Closed
Codebmk wants to merge 15 commits into
stagingfrom
pr/3491
Closed

feat: add page satisfaction feedback banner (Vertex app)#3502
Codebmk wants to merge 15 commits into
stagingfrom
pr/3491

Conversation

@Codebmk

@Codebmk Codebmk commented May 18, 2026

Copy link
Copy Markdown
Member

Summary of Changes (What does this PR do?)

Status of maturity (all need to be checked before merging):

  • I've tested this locally
  • I consider this code done
  • This change ready to hit production in its current state
  • The title of the PR states what changed and the related issues number (used for the release note).
  • I've included issue number in the "Closes #ISSUE-NUMBER" part of the "What are the relevant tickets?" section to link the issue.
  • I've updated corresponding documentation for the changes in this PR.
  • I have written unit and/or e2e tests for my change(s).

How should this be manually tested?

  • Please include the steps to be done inorder to setup and test this PR.

What are the relevant tickets?

Screenshots (optional)

image image image

Summary by CodeRabbit

  • New Features

    • Added Page Satisfaction Feedback Banner enabling users to rate page satisfaction with positive/negative options and provide detailed feedback through a modal.
  • Bug Fixes

    • Fixed multiple UI/layout and banner rendering issues across desktop and mobile viewports.

Review Change Stack

TrivCodez and others added 12 commits May 17, 2026 08:06
- Create PageSatisfactionBanner with thumbs up/down/comment icons
- Add feedback modals for positive/negative ratings with reason selection
- Implement API integration with feedbackService.submitFeedback
- Display dynamic page name based on current route
- Include dark mode support and responsive design

Closes #3480
- Change onSubmit return type to Promise<boolean> to handle submission success/failure
- Only close modal and clear inputs on successful submission
- Keep modal open on failure to allow retry with existing input
- Fix textarea label from "this recommendation" to "this page" for clarity
- Remove setModalType(null) from finally block to prevent premature closure

Fixes code-review feedback from CodeRabbit
- Import PageSatisfactionBanner component from feedback module
- Render banner at bottom of main content area after children
- Banner now appears consistently on all authenticated Vertex pages
- Addresses issue #3480 acceptance criteria for banner placement
- Fix category field: changed from 'page_satisfaction' to 'other' to match API requirements (general, bug, feature_request, performance, ux_design, other)
- Replace textarea with ReusableInputField component for consistency with FeedbackLauncher
- Replace thumb buttons with ReusableButton component with text variant
- Fix banner positioning: removed horizontal padding (px-0) on outer container for full-width layout like Google Cloud example
- Updated inner container to use w-full with responsive padding (px-4 sm:px-6)
- Removed max-w-4xl constraint to allow banner to span full width
- Added proper spacing and alignment for Google Cloud-style layout
- Replaced toast notifications with useBanner hook for consistent UX
- Fixed banner to stick to bottom of page with fixed positioning
- Removed horizontal spacing (px-0) for full-width banner
- Added fixed bottom-0 left-0 right-0 for sticky footer behavior
- Banner now displays success/error messages via banner component
… boundaries

- Changed from `fixed bottom-0 left-0 right-0` to `sticky bottom-0` to stay within main content area
- Removed `w-full` from outer div as it's already full-width by default
- Removed `w-full` from inner div to prevent overflow
- Banner now respects sidebar/layout boundaries while still sticking to bottom
- Maintains edge-to-edge positioning within the content region only
@coderabbitai

coderabbitai Bot commented May 18, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR adds a page satisfaction feedback banner that prompts users to rate page quality with positive/negative actions or open a feedback dialog. Selecting positive/negative opens a modal for selecting a predefined reason and optional message, then submits feedback via an API call. The implementation includes banner infrastructure refactoring and layout integration changes.

Changes

Page Satisfaction Feedback Banner

Layer / File(s) Summary
Feedback Modal & Reason Options
src/vertex/components/features/feedback/page-satisfaction-banner.tsx
Predefined positive and negative feedback reason arrays, and FeedbackModal component managing reason/message state with radio selection, textarea input, and success/error handling with state reset on close.
PageSatisfactionBanner Core
src/vertex/components/features/feedback/page-satisfaction-banner.tsx
Main banner component rendering three actions (positive/negative/comment), conditionally opening FeedbackModal, validating user email via useUserContext, submitting feedback with rating/reason/metadata via feedbackService, and handling success/error banners with submission state management.
Banner Infrastructure Refactoring
src/vertex/app/providers.tsx, src/vertex/context/banner-context.tsx
Removes GlobalBannerContainer from providers render tree and imports; updates GlobalBannerContainer padding from px-4 pt-3 to pt-3 to remove horizontal padding.
Layout Integration & Wiring
src/vertex/components/layout/layout.tsx
Imports PageSatisfactionBanner and GlobalBannerContainer; relocates bottom padding from main element to inner content wrapper; conditionally renders PageSatisfactionBanner when userDetails is available.
Release Documentation
src/vertex/app/changelog.md
Changelog entry for Version 1.23.43 describing Page Satisfaction Feedback Banner feature, modal flow, UI fixes, and affected files.

Sequence Diagram

sequenceDiagram
  participant User
  participant PageSatisfactionBanner
  participant FeedbackModal
  participant feedbackService
  participant UserContext
  User->>PageSatisfactionBanner: Click positive/negative action
  PageSatisfactionBanner->>FeedbackModal: Open modal with type
  User->>FeedbackModal: Select reason & enter message
  User->>FeedbackModal: Click submit
  FeedbackModal->>PageSatisfactionBanner: onSubmit(reason, message)
  PageSatisfactionBanner->>UserContext: useUserContext (get email)
  PageSatisfactionBanner->>feedbackService: submitFeedback(email, rating, reason, metadata)
  feedbackService-->>PageSatisfactionBanner: success/error response
  PageSatisfactionBanner->>PageSatisfactionBanner: showBanner(success/error)
  PageSatisfactionBanner->>FeedbackModal: Close & reset state
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related issues

Possibly related PRs

  • airqo-platform/AirQo-frontend#3488: Both PRs extend the shared banner system; this PR adds PageSatisfactionBanner using useBanner while modifying BannerProvider/GlobalBannerContainer wiring in providers and layout.
  • airqo-platform/AirQo-frontend#3481: This PR refactors the banner infrastructure (GlobalBannerContainer removal from providers, banner-context styling) that the related PR initially established.

Suggested labels

ready for review

Suggested reviewers

  • Baalmart
  • OchiengPaul442

📋 A banner born to ask "how are we doing?"
With reasons selected and feedback flowing,
Thumbs up or thumbs down—the choice is yours,
Through modals and banners, satisfaction soars! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title 'feat: add page satisfaction feedback banner (Vertex app)' directly and clearly summarizes the main change—introducing a new page satisfaction feedback banner component integrated into the Vertex app.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pr/3491

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • JIRA integration encountered authorization issues. Please disconnect and reconnect the integration in the CodeRabbit UI.

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.

@Codebmk Codebmk self-assigned this May 18, 2026

@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

🧹 Nitpick comments (4)
src/vertex/components/features/feedback/page-satisfaction-banner.tsx (4)

258-272: 💤 Low value

Consider refactoring to a single conditional FeedbackModal.

Currently, two separate FeedbackModal instances are rendered for positive and negative feedback. Since only one can be open at a time (controlled by modalType), you could simplify to a single modal with conditional props. However, the current approach is clear and works correctly.

♻️ Optional refactor to single modal
-   <FeedbackModal
-    isOpen={modalType === 'positive'}
-    onClose={() => setModalType(null)}
-    onSubmit={handleSubmitFeedback}
-    isSubmitting={isSubmitting}
-    type="positive"
-   />
-
-   <FeedbackModal
-    isOpen={modalType === 'negative'}
-    onClose={() => setModalType(null)}
-    onSubmit={handleSubmitFeedback}
-    isSubmitting={isSubmitting}
-    type="negative"
-   />
+   {modalType && (
+    <FeedbackModal
+     isOpen={true}
+     onClose={() => setModalType(null)}
+     onSubmit={handleSubmitFeedback}
+     isSubmitting={isSubmitting}
+     type={modalType}
+    />
+   )}
🤖 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/vertex/components/features/feedback/page-satisfaction-banner.tsx` around
lines 258 - 272, Replace the two FeedbackModal renderings with a single
FeedbackModal driven by modalType: use isOpen based on modalType (e.g.,
modalType !== null), pass type using modalType (coerced or defaulted as needed),
keep onClose={() => setModalType(null)}, onSubmit={handleSubmitFeedback} and
isSubmitting={isSubmitting}; this collapses the duplicated JSX while preserving
behavior and opens the correct modal content based on modalType.

184-187: 💤 Low value

Document why browser user agent is truncated to 80 characters.

The UA string is truncated to 80 chars without explanation. Modern UA strings can be longer than 80 characters, and truncation might lose valuable debugging information (e.g., specific browser version, OS details).

📝 Consider documenting the truncation rationale
     browser:
      typeof window !== 'undefined'
-       ? navigator.userAgent.slice(0, 80)
+       ? navigator.userAgent.slice(0, 80) // Truncate to fit API field limit
        : 'Unknown',
🤖 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/vertex/components/features/feedback/page-satisfaction-banner.tsx` around
lines 184 - 187, The user-agent is being truncated via
navigator.userAgent.slice(0, 80) when building the browser field—add a short
inline comment (or extract the number into a named constant like
UA_TRUNCATE_LENGTH) that documents why 80 chars was chosen and the tradeoffs
(what is preserved, what may be lost), and consider making the length
configurable or removing truncation if full UA is required; update the code
around the browser assignment (the browser field and the
navigator.userAgent.slice(0, 80) usage) to include this explanatory
comment/constant so future readers understand the rationale.

202-202: 💤 Low value

Remove unnecessary blank line.

The empty line before return true serves no purpose and can be removed for consistency.

🤖 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/vertex/components/features/feedback/page-satisfaction-banner.tsx` at line
202, Remove the unnecessary blank line in the function around the conditional
that currently has an empty line immediately before the `return true` statement
in page-satisfaction-banner.tsx; locate the function or method (e.g., the helper
that returns a boolean in this component) and delete the stray blank line so
`return true` follows the previous statement directly for consistent formatting.

182-182: 💤 Low value

The pathname fallback to window.location.pathname is unnecessary in App Router.

Since this component uses usePathname() from 'next/navigation' (App Router), the pathname is always available as a string during client-side rendering. The fallback is defensive but redundant—no need to keep it.

🤖 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/vertex/components/features/feedback/page-satisfaction-banner.tsx` at line
182, Remove the unnecessary fallback to window.location.pathname in the
PageSatisfactionBanner component: where the payload sets page: pathname ||
window.location.pathname, replace it to use the pathname value directly (page:
pathname) since usePathname() from next/navigation always supplies a string in
the App Router; update any related references in the same component to rely on
pathname only and remove the window global usage.
🤖 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/vertex/app/changelog.md`:
- Line 8: The changelog entry currently marks the PR as released ("Released: May
17, 2026") even though the PR is open; update the header in
src/vertex/app/changelog.md to an unreleased marker (e.g., "Unreleased" or "Not
released") or remove the release date until the actual release cut so history
stays accurate—locate the line containing the exact text "Released: May 17,
2026" and replace it accordingly.

In `@src/vertex/components/features/feedback/page-satisfaction-banner.tsx`:
- Line 196: The feedback category for the page satisfaction component is too
generic—replace the hardcoded "other" category in the PageSatisfactionBanner
(the object where `category: 'other'` is set) with a specific value such as
"page_satisfaction" or "satisfaction" so backend analytics can distinguish this
feedback type; update the category field used where the component constructs the
feedback payload (look for the object/constant inside PageSatisfactionBanner or
its submit handler) to the chosen specific string and ensure any related type
definitions or telemetry mappings accept that new category name.
- Around line 66-72: The banner is being shown while the modal is still closing
(setTimeout of 150ms), causing overlap with ReusableDialog's exit animation;
either increase the delay to >=250ms or invoke showBanner after the dialog's
close animation completes. Locate the setTimeout(...) call that wraps showBanner
in page-satisfaction-banner.tsx (and the showBanner(...) invocation) and replace
the 150ms delay with ~250ms (or better: move the showBanner call into the dialog
close/afterClose callback or promise from ReusableDialog so it runs only after
the dialog's exit animation finishes). Ensure you update the call site to use
the dialog's provided onClose/afterClose hook or callback rather than a
hardcoded short timeout.

In `@src/vertex/components/layout/layout.tsx`:
- Around line 140-144: The mobile bottom padding was moved from the outer <main>
to the inner content wrapper, so Footer and PageSatisfactionBanner now sit
outside that padded area and may overlap fixed bottom UI; update the layout so
mobile bottom spacing applies to elements that include
Footer/PageSatisfactionBanner — either restore the mobile padding (pb-20) to the
outer container that uses isSecondarySidebarCollapsed (the element with the long
className including transition-[margin-left]) or add safe bottom spacing (e.g.,
safe-area-inset-bottom or pb-20 on the wrapper that renders
Footer/PageSatisfactionBanner) so those components don’t overlap persistent
bottom navigation on small screens. Ensure the change targets the className on
the outer flex-1 container or the wrapper that actually contains
Footer/PageSatisfactionBanner.

---

Nitpick comments:
In `@src/vertex/components/features/feedback/page-satisfaction-banner.tsx`:
- Around line 258-272: Replace the two FeedbackModal renderings with a single
FeedbackModal driven by modalType: use isOpen based on modalType (e.g.,
modalType !== null), pass type using modalType (coerced or defaulted as needed),
keep onClose={() => setModalType(null)}, onSubmit={handleSubmitFeedback} and
isSubmitting={isSubmitting}; this collapses the duplicated JSX while preserving
behavior and opens the correct modal content based on modalType.
- Around line 184-187: The user-agent is being truncated via
navigator.userAgent.slice(0, 80) when building the browser field—add a short
inline comment (or extract the number into a named constant like
UA_TRUNCATE_LENGTH) that documents why 80 chars was chosen and the tradeoffs
(what is preserved, what may be lost), and consider making the length
configurable or removing truncation if full UA is required; update the code
around the browser assignment (the browser field and the
navigator.userAgent.slice(0, 80) usage) to include this explanatory
comment/constant so future readers understand the rationale.
- Line 202: Remove the unnecessary blank line in the function around the
conditional that currently has an empty line immediately before the `return
true` statement in page-satisfaction-banner.tsx; locate the function or method
(e.g., the helper that returns a boolean in this component) and delete the stray
blank line so `return true` follows the previous statement directly for
consistent formatting.
- Line 182: Remove the unnecessary fallback to window.location.pathname in the
PageSatisfactionBanner component: where the payload sets page: pathname ||
window.location.pathname, replace it to use the pathname value directly (page:
pathname) since usePathname() from next/navigation always supplies a string in
the App Router; update any related references in the same component to rely on
pathname only and remove the window global usage.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5536b18e-935a-403a-9388-7779250cf1e1

📥 Commits

Reviewing files that changed from the base of the PR and between 38be11f and ec97fd8.

📒 Files selected for processing (5)
  • src/vertex/app/changelog.md
  • src/vertex/app/providers.tsx
  • src/vertex/components/features/feedback/page-satisfaction-banner.tsx
  • src/vertex/components/layout/layout.tsx
  • src/vertex/context/banner-context.tsx

Comment thread src/vertex/app/changelog.md
Comment thread src/vertex/components/features/feedback/page-satisfaction-banner.tsx Outdated
Comment thread src/vertex/components/features/feedback/page-satisfaction-banner.tsx Outdated
Comment thread src/vertex/components/layout/layout.tsx
@Codebmk Codebmk closed this May 18, 2026
@Codebmk Codebmk reopened this May 18, 2026
@Codebmk Codebmk closed this May 18, 2026
@Codebmk
Codebmk deleted the pr/3491 branch May 18, 2026 02:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Vertex App: Feature] Add Page Satisfaction Feedback Banner

2 participants