Skip to content

feat(surveys): show per-user response status on me lens#680

Merged
manishdixitlfx merged 4 commits into
mainfrom
fix/survey-bug
May 11, 2026
Merged

feat(surveys): show per-user response status on me lens#680
manishdixitlfx merged 4 commits into
mainfrom
fix/survey-bug

Conversation

@manishdixitlfx
Copy link
Copy Markdown
Contributor

@manishdixitlfx manishdixitlfx commented May 11, 2026

Summary

  • Joins indexed survey_response records (by user email/username) against the surveys list so each row on the Me lens reflects whether the current user has actually submitted. response_status='responded' is stamped only when survey_response.response_datetime is populated — distinguishing invited-only rows from real submissions.
  • New GET /api/surveys/:uid/my-response endpoint plus a new lfx-my-response-drawer for per-user response viewing on the Me lens. The aggregate Results drawer is no longer reachable from Me lens (Stephan/Jim feedback — most takers shouldn't see aggregate).
  • My Surveys table status badge is now informative: amber Open for action-needed, green Submitted for done, gray Closed. Actions: Take Survey (primary CTA) only when open and not responded; Update (same SurveyMonkey link) when open + responded; View on every closed survey.
  • Committee Overview pending actions filter out responded surveys and show a green Submitted card with an Update link instead.
  • getMySurveys now renders a stub Survey when the upstream /surveys/{uid} detail fetch fails, so invited rows are not silently dropped.

JIRA: LFXV2-1726

Shared package changes

  • New MySurveyResponse / MySurveyQuestionAnswer / MySurveyAnswer interfaces.
  • PendingActionType union extended with 'Submitted'; matching green severity added to PENDING_ACTION_SEVERITY.

Behavior changes worth calling out

  • Aggregate Results drawer is no longer reachable from the Me lens (survey name, row click, and Results action all route to the per-user drawer instead). Foundation/Project lens behavior is unchanged.
  • getSurveys now makes one extra parallel query to type=survey_response to compute response_status for the requesting user. Returns an empty set on failure — surveys still render as not-responded.

Test plan

  • My Surveys page: open survey you haven't taken → amber Open badge + blue Take Survey button
  • My Surveys page: open survey you submitted → green Submitted badge + gray Update link (opens SurveyMonkey to edit)
  • My Surveys page: closed survey → gray Closed badge + gray View link
  • Click survey name or row on Me lens → per-user drawer opens (not aggregate)
  • Per-user drawer (NPS survey) → shows your score with 0–10 caption
  • Per-user drawer (Standard survey) → shows each question with your selected answers
  • Per-user drawer (closed + no response) → friendly "you didn't respond" empty state
  • Foundation lens / Project lens: aggregate Results drawer still opens (admins/participants)
  • Committee Overview: responded surveys show as green "Submitted" cards with "Update" link; unresponded surveys still appear in the amber "Survey" pending action cards

🤖 Generated with Claude Code

LFXV2-1726

Joins survey_response records (keyed by user email/username) against the
surveys list so each survey on the Me lens reflects whether the current
user has actually submitted a response. response_status='responded' is
stamped only when survey_response.response_datetime is populated, which
distinguishes invited-only rows from real submissions.

Backend:
- GET /api/surveys/:uid/my-response — returns the user's submitted
  response (NPS value or SurveyMonkey question/answer pairs), or 404.
- getSurveys and getMySurveys now run the join in parallel with the
  primary fetch; both stamp response_status='responded' on matched
  surveys. getMySurveys also renders a stub Survey when the upstream
  detail fetch fails so invited rows are not silently dropped.

UI (My Surveys / Me lens):
- Status badge: amber 'Open' (action needed), green 'Submitted'
  (done), gray 'Closed'.
- Actions: 'Take Survey' (primary CTA) only when open and not
  responded; 'Update' (same SurveyMonkey link) when open + responded;
  'View' on every closed survey.
- New my-response-drawer component renders the user's NPS score or
  question/answer pairs for the selected survey. Replaces the
  aggregate Results drawer on Me lens — aggregate is admin/participant
  only (Stephan/Jim).
- Survey-name click and row-click on Me lens route to the per-user
  drawer instead of aggregate.

UI (Committee Overview pending actions):
- 'Submitted' card with green check icon and 'Update' link replaces
  the amber 'Survey' card when the user has already responded.
- pendingSurveys filters out responded; new respondedSurveys signal
  drives the Submitted cards.

Shared:
- MySurveyResponse / MySurveyQuestionAnswer / MySurveyAnswer
  interfaces describe the per-user response payload.
- PendingActionType union extended with 'Submitted' (with matching
  green severity in PENDING_ACTION_SEVERITY).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
Copilot AI review requested due to automatic review settings May 11, 2026 20:59
@manishdixitlfx manishdixitlfx requested a review from a team as a code owner May 11, 2026 20:59
Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 11, 2026

Review Change Stack
No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e36b973f-1cb4-42c3-8388-6d717c1cd95c

📥 Commits

Reviewing files that changed from the base of the PR and between 73b9be9 and 5a55fae.

📒 Files selected for processing (5)
  • apps/lfx-one/src/app/modules/committees/components/committee-meetings/committee-meetings.component.ts
  • apps/lfx-one/src/app/modules/surveys/components/my-response-drawer/my-response-drawer.component.html
  • apps/lfx-one/src/app/modules/surveys/components/my-response-drawer/my-response-drawer.component.ts
  • apps/lfx-one/src/server/services/survey.service.ts
  • packages/shared/src/interfaces/survey.interface.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/shared/src/interfaces/survey.interface.ts
  • apps/lfx-one/src/app/modules/surveys/components/my-response-drawer/my-response-drawer.component.ts

Walkthrough

Adds a "Me Lens" allowing users to view their personal survey responses: new backend API, server service methods to mark responded surveys, a frontend SurveyService method, a standalone MyResponseDrawer component (UI + styles), and UI updates in dashboard, table, and committee overview to surface responded vs pending surveys.

Changes

Me Lens Survey Response Feature

Layer / File(s) Summary
Data Model & Pending Action Types
packages/shared/src/interfaces/survey.interface.ts, packages/shared/src/interfaces/components.interface.ts, packages/shared/src/constants/pending-action.constants.ts
Introduces MySurveyResponse, MySurveyAnswer, MySurveyQuestionAnswer interfaces; widens Survey.survey_cutoff_date to `string
Backend API Route & Controller
apps/lfx-one/src/server/routes/surveys.route.ts, apps/lfx-one/src/server/controllers/survey.controller.ts
New GET /surveys/:uid/my-response endpoint with UID extraction/validation, response fetching, 404 handling via ResourceNotFoundError, and error forwarding.
Backend Survey Service Enhancement
apps/lfx-one/src/server/services/survey.service.ts
Parallel fetching and response-status enrichment in getSurveys(); includes response_datetime tracking and responded-UID stamping in getMySurveys(); returns stubs on detail fetch failure; adds getMyResponse() and fetchRespondedSurveyUidsForUser().
Frontend Survey Service Integration
apps/lfx-one/src/app/shared/services/survey.service.ts
New getMyResponse(surveyUid) method returning `MySurveyResponse
Response Drawer Component
apps/lfx-one/src/app/modules/surveys/components/my-response-drawer/my-response-drawer.component.ts, .html, .scss
Standalone component using surveyId input to fetch the user's response, manages loading, renders NPS or question-answer views, shows submitted timestamp, and exposes an update link when allowed.
Dashboard Integration & Me Lens Support
apps/lfx-one/src/app/modules/surveys/surveys-dashboard/surveys-dashboard.component.ts, .html
Imports MyResponseDrawerComponent, adds myResponseDrawerVisible signal, toggles me-drawer vs results-drawer in onViewResults(), and passes isMeLens to the surveys table.
Surveys Table Response Status UI
apps/lfx-one/src/app/modules/surveys/components/surveys-table/surveys-table.component.ts, .html
Adds isMeLens input; adjusts header widths; shows "Submitted" success tag for open/responded surveys; action button switches label/severity between "Take Survey" (primary) and "Update" (secondary) based on response_status.
Committee Overview Pending Actions
apps/lfx-one/src/app/modules/committees/components/committee-overview/committee-overview.component.ts
Partitions open surveys into pendingSurveys and respondedSurveys; pending action rows use composed "Sent" / optional "Due" date text; responded surveys emit Submitted action rows with View button text and success severity.
Committee Meetings Event Fix
apps/lfx-one/src/app/modules/committees/components/committee-meetings/committee-meetings.component.ts
Calendar event start now uses survey.survey_cutoff_date ?? undefined to avoid invalid event start values when cutoff is missing.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Dashboard
  participant MyResponseDrawer
  participant SurveyServiceClient
  participant API
  User->>Dashboard: open Me lens / click View Results
  Dashboard->>MyResponseDrawer: set surveyId & visible
  MyResponseDrawer->>MyResponseDrawer: set loading
  MyResponseDrawer->>SurveyServiceClient: getMyResponse(surveyId)
  SurveyServiceClient->>API: GET /surveys/:uid/my-response
  API-->>SurveyServiceClient: MySurveyResponse | null
  SurveyServiceClient-->>MyResponseDrawer: response (or null)
  MyResponseDrawer->>MyResponseDrawer: clear loading, render response or empty state
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • linuxfoundation/lfx-v2-ui#254: Adds Survey.response_status field and matching interface changes to support "responded" survey states across frontend and backend.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main feature: adding per-user response status visibility on the Me lens of the surveys module.
Description check ✅ Passed The description comprehensively explains the changeset including backend joins, new drawer component, status badge semantics, and behavior modifications with clear test coverage.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

✏️ 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 fix/survey-bug

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds per-user survey response awareness across the “Me” lens experience by enriching survey rows with whether the current user has actually submitted, and introduces a dedicated “My Response” drawer + API endpoint for viewing an individual’s submitted answers (instead of aggregate results).

Changes:

  • Add shared interfaces for per-user survey responses and extend pending-action typing/severity for a new “Submitted” action state.
  • Enrich server survey list results with per-user response_status='responded' (based on survey_response.response_datetime) and add GET /api/surveys/:uid/my-response.
  • Update Surveys UI to open a per-user response drawer on the Me lens and adjust badges/CTAs (Take Survey / Update / View), plus update Committee Overview pending actions to split responded vs unresponded surveys.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
packages/shared/src/interfaces/survey.interface.ts Adds MySurveyResponse and related answer/question interfaces for the per-user response payload.
packages/shared/src/interfaces/components.interface.ts Extends PendingActionType union with 'Submitted'.
packages/shared/src/constants/pending-action.constants.ts Adds Submitted to PENDING_ACTION_SEVERITY.
apps/lfx-one/src/server/services/survey.service.ts Enriches getSurveys with per-user responded status; enhances getMySurveys; adds getMyResponse endpoint logic.
apps/lfx-one/src/server/routes/surveys.route.ts Registers the new /:uid/my-response route.
apps/lfx-one/src/server/controllers/survey.controller.ts Adds controller handler for GET /surveys/:uid/my-response.
apps/lfx-one/src/app/shared/services/survey.service.ts Adds Angular client method getMyResponse() for the new endpoint.
apps/lfx-one/src/app/modules/surveys/surveys-dashboard/surveys-dashboard.component.ts Routes Me-lens “results” actions to the new per-user drawer.
apps/lfx-one/src/app/modules/surveys/surveys-dashboard/surveys-dashboard.component.html Wires isMeLens to the table and mounts the lfx-my-response-drawer.
apps/lfx-one/src/app/modules/surveys/components/surveys-table/surveys-table.component.ts Adds an isMeLens input to customize table actions.
apps/lfx-one/src/app/modules/surveys/components/surveys-table/surveys-table.component.html Updates status badge + CTAs (Take Survey / Update / View / Results) with Me-lens-specific behavior.
apps/lfx-one/src/app/modules/surveys/components/my-response-drawer/my-response-drawer.component.ts New per-user response drawer component (data loading + computed view state).
apps/lfx-one/src/app/modules/surveys/components/my-response-drawer/my-response-drawer.component.html Drawer UI rendering NPS or question/answer details + empty states.
apps/lfx-one/src/app/modules/surveys/components/my-response-drawer/my-response-drawer.component.scss Drawer styling overrides.
apps/lfx-one/src/app/modules/committees/components/committee-overview/committee-overview.component.ts Splits pending vs responded surveys and introduces “Submitted” pending-action rows.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread apps/lfx-one/src/server/services/survey.service.ts Outdated
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: 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 `@apps/lfx-one/src/server/services/survey.service.ts`:
- Around line 357-367: The getMyResponse method currently returns the matched
record (`match`) directly, which can include an unvalidated `survey_link`;
update getMyResponse to sanitize/validate `match.survey_link` against the
existing SURVEY_LINK_ALLOWLIST (same approach used in getMySurveys) before
returning: locate where `responses` and `match` are computed, check
`match.survey_link` against SURVEY_LINK_ALLOWLIST and either keep it, normalize
it, or remove/null it if it fails validation, then return the sanitized object
(not the raw `match`) to ensure unsafe URLs do not propagate to the UI.
🪄 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: 8f1f9347-e96d-4101-bcfd-d1fc956c2302

📥 Commits

Reviewing files that changed from the base of the PR and between 9518b2f and e563ad6.

📒 Files selected for processing (15)
  • apps/lfx-one/src/app/modules/committees/components/committee-overview/committee-overview.component.ts
  • apps/lfx-one/src/app/modules/surveys/components/my-response-drawer/my-response-drawer.component.html
  • apps/lfx-one/src/app/modules/surveys/components/my-response-drawer/my-response-drawer.component.scss
  • apps/lfx-one/src/app/modules/surveys/components/my-response-drawer/my-response-drawer.component.ts
  • apps/lfx-one/src/app/modules/surveys/components/surveys-table/surveys-table.component.html
  • apps/lfx-one/src/app/modules/surveys/components/surveys-table/surveys-table.component.ts
  • apps/lfx-one/src/app/modules/surveys/surveys-dashboard/surveys-dashboard.component.html
  • apps/lfx-one/src/app/modules/surveys/surveys-dashboard/surveys-dashboard.component.ts
  • apps/lfx-one/src/app/shared/services/survey.service.ts
  • apps/lfx-one/src/server/controllers/survey.controller.ts
  • apps/lfx-one/src/server/routes/surveys.route.ts
  • apps/lfx-one/src/server/services/survey.service.ts
  • packages/shared/src/constants/pending-action.constants.ts
  • packages/shared/src/interfaces/components.interface.ts
  • packages/shared/src/interfaces/survey.interface.ts

Comment thread apps/lfx-one/src/server/services/survey.service.ts
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 11, 2026

🚀 Deployment Status

Your branch has been deployed to: https://ui-pr-680.dev.v2.cluster.linuxfound.info

Deployment Details:

  • Environment: Development
  • Namespace: ui-pr-680
  • ArgoCD App: ui-pr-680

The deployment will be automatically removed when this PR is closed.

Address review comments from @copilot-pull-request-reviewer and @coderabbitai:

- packages/shared/src/constants/pending-action.constants.ts: change
  PENDING_ACTION_SEVERITY.Survey from 'success' (green) to 'warn' (amber)
  so pending Survey cards visually differ from the new 'Submitted' cards
  on the committee overview (per @copilot)
- committee-overview.component.ts: normalize response_status comparisons
  to lowercase in pendingSurveys / respondedSurveys filters to absorb
  upstream casing (e.g. 'RESPONDED') (per @copilot)
- committee-overview.component.ts: drop buttonLink and rename the
  Submitted card CTA from 'Update' to 'View' — survey_link is Me-lens-
  only data, and handlePendingActionClick falls through to surveys-tab
  navigation for non-Vote items, so the previous label was misleading
  (per @copilot)
- surveys-table.component.html: normalize response_status comparisons
  via @let isResponded / @let actionIsResponded (per @copilot)
- surveys-dashboard.component.ts: onViewResults now explicitly closes
  the non-target drawer before opening the chosen one so a mid-session
  lens switch can't leave both visibility signals true (per @copilot)
- server survey.service.ts: refresh getMySurveys inline comment to
  describe current behavior (per-user drawer + 'Update' CTA) instead of
  the stale 'Take Survey' to 'Results' description (per @copilot)
- server survey.service.ts: validate survey_link against
  SURVEY_LINK_ALLOWLIST in getMyResponse before returning, matching the
  existing getMySurveys defense-in-depth (per @coderabbitai)
- my-response-drawer.component.html: add aria-label='Close' on the
  icon-only close button (per @copilot)
- my-response-drawer.component.html: track key fallback to $index when
  question_id is missing to avoid DOM reuse collisions (per @copilot)
- my-response-drawer.component.html: render answer text with
  text ?? choice_id ?? '—' fallback to avoid empty bullets (per @copilot)
- my-response-drawer.component.ts: infer NPS mode from response.nps_value
  as a fallback so stub Survey rows (rendered when /surveys/{uid} detail
  fetch fails) don't mis-render NPS responses as 'no answers' (per @copilot)

Resolves 11 review threads.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
@manishdixitlfx
Copy link
Copy Markdown
Contributor Author

Review Feedback Addressed

Commit: ee2a503

Changes Made

  • packages/shared/src/constants/pending-action.constants.ts: PENDING_ACTION_SEVERITY.Survey'warn' (amber) so pending vs Submitted cards differ visually (per @copilot-pull-request-reviewer)
  • committee-overview.component.ts: case-insensitive response_status comparison in pendingSurveys / respondedSurveys; dropped buttonLink and renamed Submitted CTA from "Update" to "View" to match what handlePendingActionClick actually does (per @copilot-pull-request-reviewer)
  • surveys-table.component.html: case-insensitive response_status via @let isResponded / @let actionIsResponded (per @copilot-pull-request-reviewer)
  • surveys-dashboard.component.ts: onViewResults explicitly closes the non-target drawer before opening the chosen one (per @copilot-pull-request-reviewer)
  • server/survey.service.ts: refreshed stale inline comment to describe current behavior; getMyResponse now sanitizes survey_link against SURVEY_LINK_ALLOWLIST (per @copilot-pull-request-reviewer, @coderabbitai)
  • my-response-drawer.component.html: aria-label="Close" on the icon-only close button; track key fallback to $index; answer text fallback a.text ?? a.choice_id ?? '—' (per @copilot-pull-request-reviewer)
  • my-response-drawer.component.ts: isNps falls back to response.nps_value != null so stub Survey rows still render NPS responses correctly (per @copilot-pull-request-reviewer)

Threads Resolved

11 of 11 unresolved threads addressed in this iteration.

Follow-up (not in this PR)

  • For an in-place "Update Response" CTA on committee overview Submitted cards to actually open SurveyMonkey, the committee/project surveys query would need to enrich each row with the current user's survey_response.survey_link. Treating that as a follow-up under LFXV2-1726.

🤖 Generated with Claude Code

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 11, 2026

@manishdixitlfx Thanks for the thorough summary and for addressing all 11 threads in commit ee2a5039! The fixes look well-scoped:

  • survey_link allowlist sanitization in server/survey.service.ts — glad that landed; it closes the open-redirect risk I flagged.
  • Case-insensitive response_status comparisons across committee-overview, surveys-table — good defensive choice given that backend casing can drift.
  • Drawer mutual-exclusion in surveys-dashboard.component.ts — explicitly closing the non-target drawer prevents stale state.
  • isNps fallback on stub rows and answer text fallback (a.text ?? a.choice_id ?? '—') — solid resilience improvements.

The follow-up you described (enriching committee/project surveys with the current user's survey_response.survey_link to enable the in-place "Update Response" CTA) sounds like a clean scope boundary. Would you like me to open a GitHub issue to track it as a follow-up under LFXV2-1726?

Triggering a re-review now.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Member

@jordane jordane left a comment

Choose a reason for hiding this comment

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

One error-handling pattern issue worth fixing before merge — see inline comment. The rest of the feature looks solid; the survey_link sanitization and Update-button issues are already covered by the bot reviews.

Comment thread apps/lfx-one/src/server/controllers/survey.controller.ts Outdated
Address review comment from @jordane:

- apps/lfx-one/src/server/controllers/survey.controller.ts:
  replace the manual `res.status(404).json(...)` in getMyResponse with
  `next(new ResourceNotFoundError(...))` so the central apiErrorHandler
  middleware emits a structured 404 with request_id correlation and a
  consistent error envelope. Matches the pattern in
  public-meeting.controller.ts. Frontend behavior is unchanged — the
  Angular getMyResponse catchError still swallows 404 and the drawer
  renders its empty state.

Resolves 1 review thread.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
Copilot AI review requested due to automatic review settings May 11, 2026 21:41
@manishdixitlfx
Copy link
Copy Markdown
Contributor Author

Review Feedback Addressed — Iteration 2

Commit: 73b9be9

Changes Made

  • apps/lfx-one/src/server/controllers/survey.controller.ts: getMyResponse now throws ResourceNotFoundError instead of writing the 404 directly with res.status().json(), so the response flows through apiErrorHandler for structured logging, request_id correlation, and a consistent error envelope (per @jordane)

Threads Resolved

1 of 1 new unresolved thread addressed in this iteration.

🤖 Generated with Claude Code

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 5 comments.

Comment thread apps/lfx-one/src/server/services/survey.service.ts
Comment thread apps/lfx-one/src/server/services/survey.service.ts Outdated
Comment thread apps/lfx-one/src/server/services/survey.service.ts
Address review comments from @copilot-pull-request-reviewer:

- packages/shared/src/interfaces/survey.interface.ts: relax
  Survey.survey_cutoff_date to `string | null` so the getMySurveys stub
  can use null instead of an empty string that would crash Angular's
  DatePipe in the Me-lens table.
- apps/lfx-one/src/server/services/survey.service.ts: stub Survey now
  uses survey_cutoff_date: null; also guard the sort comparator's
  new Date(...) call against null.
- apps/lfx-one/src/server/services/survey.service.ts: rename the
  get_surveys debug log field from `responded_count` to
  `responded_in_result` and compute the intersection with the current
  result set, so the metric can't exceed final_count.
- apps/lfx-one/src/server/services/survey.service.ts: clarify
  getMyResponse JSDoc — survey_uid filtering is in-memory in the
  service, not "client-side".
- apps/lfx-one/src/app/modules/surveys/components/my-response-drawer/
  my-response-drawer.component.html: remove doubled padding
  (p-4 sm:p-6 on the inner wrapper duplicated the SCSS-applied
  .p-drawer-content padding).
- apps/lfx-one/src/app/modules/surveys/components/my-response-drawer/
  my-response-drawer.component.{ts,html}: branch the empty state on
  displayStatus. Open + unresponded surveys now show "You haven't
  responded yet" with an optional "Take the survey" CTA when
  survey_link is available; closed surveys keep the "didn't respond
  before survey closed" copy.
- apps/lfx-one/src/app/modules/committees/components/committee-meetings/
  committee-meetings.component.ts: handle nullable
  survey.survey_cutoff_date when constructing the FullCalendar event.

Resolves 5 review threads.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Manish Dixit <mdixit@linuxfoundation.org>
@manishdixitlfx
Copy link
Copy Markdown
Contributor Author

Review Feedback Addressed — Iteration 3

Commit: 5a55fae

Changes Made

  • packages/shared/src/interfaces/survey.interface.ts + server/survey.service.ts: relaxed Survey.survey_cutoff_date to string | null and stub now uses null (was '') so Angular's DatePipe doesn't crash on stub rows; sort comparator guarded against null (per @copilot-pull-request-reviewer)
  • server/survey.service.ts: get_surveys debug log field renamed responded_countresponded_in_result, computed as the intersection with the current result set (per @copilot-pull-request-reviewer)
  • server/survey.service.ts: getMyResponse JSDoc clarified — survey_uid filtering is in-memory in the service, not "client-side" (per @copilot-pull-request-reviewer)
  • my-response-drawer.component.html: removed duplicate p-4 sm:p-6 on the inner wrapper; spacing now comes solely from the SCSS-applied .p-drawer-content padding (per @copilot-pull-request-reviewer)
  • my-response-drawer.component.{ts,html}: empty-state branches on display status. Open + unresponded shows "You haven't responded yet" + a "Take the survey" link when survey_link is present; closed surveys keep the "didn't respond before the survey closed" copy (per @copilot-pull-request-reviewer)
  • committee-meetings.component.ts: handled nullable survey_cutoff_date when building the FullCalendar event start (downstream of the interface relaxation)

Threads Resolved

5 of 5 unresolved threads addressed in this iteration.

🤖 Generated with Claude Code

@manishdixitlfx
Copy link
Copy Markdown
Contributor Author

@jordane — your feedback has been addressed across three iterations. Ready for another look when you have a moment.

Your thread (survey.controller.ts 404 → apiErrorHandler):

  • Commit 73b9be93getMyResponse now throws ResourceNotFoundError and lets the central middleware emit the structured 404 with request_id correlation, matching the public-meeting.controller.ts pattern.

Other review feedback addressed in the same session:

  • Commit ee2a5039 (iteration 1) — 11 threads from @copilot-pull-request-reviewer + @coderabbitai (severity color hierarchy, case-insensitive response_status, drawer state isolation, a11y aria-label, track-key fallback, sanitize survey_link, etc.)
  • Commit 5a55fae2 (iteration 3) — 5 more threads from @copilot-pull-request-reviewer (nullable survey_cutoff_date in stub Survey so DatePipe doesn't crash, log field intersection rename, drawer padding dedup, OPEN-vs-CLOSED empty-state copy split)

All 17 review threads are resolved. Lint, type-check, and build are green on the latest commit. No new functional behavior since your review — only your requested fix + the Copilot suggestions.

🤖 Generated with Claude Code

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 11, 2026

@manishdixitlfx Thanks for the detailed summary across all three iterations! My previously flagged issues are confirmed addressed — survey_link allowlist sanitization, case-insensitive response_status comparisons, and drawer mutual-exclusion all landed in commit ee2a5039.

Triggering a re-review to pick up commits 73b9be93 and 5a55fae2 that came in after my last pass.

Also — my earlier offer still stands: happy to open a GitHub issue to track the follow-up (enriching committee/project survey rows with the current user's survey_response.survey_link to enable the in-place "Update Response" CTA on committee overview Submitted cards). Just let me know.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Member

@jordane jordane left a comment

Choose a reason for hiding this comment

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

All 17 review comments (2 rounds of Copilot + CodeRabbit + my initial REQUEST_CHANGES) verified against HEAD 5a55fae — every item is correctly addressed:

  • PENDING_ACTION_SEVERITY.Survey → 'warn', Submitted stays 'success'
  • Both pendingSurveys/respondedSurveys and table template use ?.toLowerCase() === 'responded'
  • onViewResults explicitly clears the non-target drawer before opening the selected one
  • Stale 'Take Survey → Results' comment updated to reflect per-user drawer + Update CTA
  • getMyResponse validates survey_link against SURVEY_LINK_ALLOWLIST before returning (security fix)
  • Controller 404 now routes through ResourceNotFoundError → apiErrorHandler
  • my-response-drawer: aria-label on close button, track qa.question_id ?? $index, a.text ?? a.choice_id ?? '—', isNps falls back to nps_value != null, single-source padding, isOpenUnresponded branch with Take Survey link
  • Committee overview: Submitted cards labeled 'View', buttonLink dropped
  • Stub survey: survey_cutoff_date: null (DatePipe-safe), downstream sort guards in place
  • responded_in_result now counts only the intersection with the current result set
  • JSDoc reworded to 'in-memory after the query returns'

No new concerns found.

@manishdixitlfx manishdixitlfx merged commit 91bd910 into main May 11, 2026
13 checks passed
@manishdixitlfx manishdixitlfx deleted the fix/survey-bug branch May 11, 2026 22:41
@github-actions
Copy link
Copy Markdown

🧹 Deployment Removed

The deployment for PR #680 has been removed.

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.

3 participants