Skip to content

[feat]: unify review components between listings and pc-listings#357

Merged
Producdevity merged 8 commits into
stagingfrom
feat/review-modals
May 21, 2026
Merged

[feat]: unify review components between listings and pc-listings#357
Producdevity merged 8 commits into
stagingfrom
feat/review-modals

Conversation

@Producdevity

@Producdevity Producdevity commented May 19, 2026

Copy link
Copy Markdown
Owner

unify review components between listings and pc-listings

Type of change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Refactor
  • Other (please describe):

How Has This Been Tested?

  • Local build
  • Lint
  • Typecheck
  • Unit tests
  • Manual testing

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my code
  • I have made corresponding changes to the documentation
  • I have checked that all checks (lint, typecheck, test) pass

Notes for reviewers

Summary by CodeRabbit

Release Notes

  • New Features

    • Added unified compatibility report review modal for listing approvals on handheld and PC detail pages.
    • Introduced review risk indicators displaying author and submission risk assessments with severity badges.
    • Improved custom field value rendering with enhanced driver version formatting support.
  • Improvements

    • Review risk profiles now visible to moderators when viewing listing details for approval.

Review Change Stack

@vercel

vercel Bot commented May 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
emuready Ready Ready Preview, Comment May 19, 2026 10:09pm

Request Review

@coderabbitai

coderabbitai Bot commented May 19, 2026

Copy link
Copy Markdown

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: dcaab357-1841-4ed3-91c9-434898847a4b

📥 Commits

Reviewing files that changed from the base of the PR and between 04d0955 and 68a19e4.

📒 Files selected for processing (8)
  • src/app/listings/components/shared/CustomFieldsSection.tsx
  • src/app/listings/components/shared/utils/isDefaultValue.ts
  • src/components/compatibility/custom-fields/CompatibilityReportCustomFieldValue.tsx
  • src/components/compatibility/custom-fields/index.ts
  • src/components/compatibility/custom-fields/types.ts
  • src/components/compatibility/review/CompatibilityReportReviewModal.tsx
  • src/components/compatibility/review/index.ts
  • src/components/compatibility/review/reviewItem.ts
✅ Files skipped from review due to trivial changes (1)
  • src/components/compatibility/custom-fields/types.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/components/compatibility/review/index.ts
  • src/app/listings/components/shared/CustomFieldsSection.tsx
  • src/components/compatibility/review/CompatibilityReportReviewModal.tsx

Walkthrough

This PR consolidates approval modal UI across handheld and PC listings into a single CompatibilityReportReviewModal component, introduces server-side role-based risk profile visibility controls, and refactors custom field rendering into a reusable compatibility module. It removes duplicate modal implementations and centralizes review logic while maintaining the same approval workflows.

Changes

Listing Approval Modal Consolidation

Layer / File(s) Summary
Review item domain types and converters
src/components/compatibility/review/reviewItem.ts
Introduces CompatibilityReportReviewDecision, CompatibilityReportReviewItem, and hardware discriminated union types; exports toCompatibilityReportReviewItem and platform-specific conversion functions to map source listing data into the unified review item format.
Compatibility Report Review Modal component
src/components/compatibility/review/CompatibilityReportReviewModal.tsx, src/components/compatibility/review/CompatibilityReportReviewModal.test.tsx
Implements the core modal with composed sections (game, hardware, emulator, user, performance, notes, custom fields), risk warning banner, conditional rejection notes textarea, and wired submit/cancel buttons; test coverage includes approval/rejection flows, custom field rendering, preset interactions, and adapter mapping.
Review Risk Warning Banner
src/components/compatibility/review/ReviewRiskWarningBanner.tsx, src/components/admin/review-risk/ReviewRiskWarningBanner.tsx
Adds risk banner component to compatibility module that computes and renders severity-keyed risk groups and signals; maintains backward-compatible re-export from admin module.
Custom field types and component
src/components/compatibility/custom-fields/types.ts, src/components/compatibility/custom-fields/CompatibilityReportCustomFieldValue.tsx, src/constants/customFields.ts
Introduces CompatibilityCustomFieldValue type with typed definitions; creates CompatibilityReportCustomFieldValue component with option validation and driver-version formatting; extracts DRIVER_VERSION_FIELD_NAME to shared constants.
Custom field integration
src/app/listings/components/shared/CustomFieldRenderer.tsx, src/app/listings/components/shared/CustomFieldsSection.tsx, src/app/listings/components/shared/utils/isDefaultValue.ts
Updates custom field consumers to import constant from shared module and use the new CompatibilityReportCustomFieldValue component with CompatibilityCustomFieldValue type signature.
Modal state management and adapter
src/components/compatibility/review/useCompatibilityReportReviewDecisionModal.ts, src/components/compatibility/review/CompatibilityReportReviewModalAdapter.tsx, src/components/compatibility/review/index.ts
Adds generic hook for managing modal open/close/decision/notes state; creates adapter to convert review sources into item format; exports all review components from barrel file.
CompatibilityReportApprovalActions refactored
src/components/compatibility/review/CompatibilityReportApprovalActions.tsx
Renames ListingApprovalActions to CompatibilityReportApprovalActions; uses state hook and adapter; routes mutations based on listingType; updates button titles and error/success messages with dynamic reportLabel.
Admin approvals pages refactored
src/app/admin/approvals/page.tsx, src/app/admin/pc-listing-approvals/page.tsx
Replaces local ApprovalModal state with useCompatibilityReportReviewDecisionModal hook; updates row action buttons to open modal; derives analytics IDs from approvalModal.selectedReport; uses adapter for modal rendering.
Listing detail pages wired to approval actions
src/app/listings/[id]/components/ListingDetailsClient.tsx, src/app/pc-listings/[id]/components/PcListingDetailsClient.tsx
Updates both detail pages to use CompatibilityReportApprovalActions instead of generic ListingApprovalActions with the same prop shape and callbacks.
Review risk module consolidation
src/components/admin/review-risk/ReviewRiskIndicator.tsx
Updates to import review-risk helpers from the consolidated compatibility module.
Server risk service enhancements
src/server/services/review-risk.service.ts
Adds attachHiddenReviewRiskProfiles, getActiveAuthorBansForReviewRisk, and attachReviewRiskProfile helpers; updates attachReviewRiskProfileForViewer to return either full or hidden profiles based on user role (moderators vs. non-reviewers).
API endpoints with role-based enrichment
src/server/api/routers/listings/core.ts, src/server/api/routers/pcListings.ts
Updates byId endpoints to call attachReviewRiskProfileForViewer with user role, returning role-specific risk profile visibility.
Risk service and API tests
src/server/services/review-risk.service.test.ts, src/server/api/routers/listings/core.test.ts, src/server/api/routers/pcListings.test.ts
Adds unit tests for new risk service helpers and integration tests verifying role-based risk profile visibility in API responses.
E2E test infrastructure
tests/helpers/data-factory.ts, tests/listing-approval.spec.ts
Adds pending listing fixtures for handheld and PC; adds Playwright helpers and workflow tests verifying the unified approval modal on detail pages.
Removed old components
src/app/admin/approvals/components/ApprovalModal.tsx, src/app/listings/components/shared/approval/ListingApprovalModal.tsx
Removes old approval modal implementations and shared components; consolidates their functionality into the unified CompatibilityReportReviewModal.

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly Related PRs

  • Producdevity/EmuReady#353: Both PRs touch review-risk components and approval modal logic, consolidating risk banner and decision flow behavior.

Poem

🐰 Hops through approval flows with glee,
Risk profiles hidden for all but thee,
One modal reigns o'er listings vast,
Custom fields consolidated at last!
Modal adapters dance with state so free, 🎪

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 1.89% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description is incomplete. While the type of change is marked (New feature and Refactor), all testing checkboxes are unchecked and testing details are missing. No issue reference, motivation, context, or reviewer notes are provided. Add testing verification (mark at least local build, lint, typecheck, and manual testing as completed) and provide context about the unification approach and any breaking changes.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: unifying review components between listings and pc-listings, which is the central theme of the changeset.
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 feat/review-modals

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 `@src/components/compatibility/review/CompatibilityReportReviewModal.tsx`:
- Around line 294-303: The map in CompatibilityReportReviewModal uses
customFieldDefinition.label as the React key which can collide; update the key
to use a stable unique identifier (e.g., fieldValue.customFieldDefinition.id or
fieldValue.id) and fall back to the loop index if no unique id exists so rows
reconcile correctly; locate the remainingFields.map(...) (and the
CompatibilityReportCustomFieldValue usage) and replace the key with the
unique-id-with-index-fallback approach.
🪄 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: f19d7d85-2660-4dde-a642-52ce6e9475a2

📥 Commits

Reviewing files that changed from the base of the PR and between 5852ab4 and 28f8d16.

📒 Files selected for processing (27)
  • src/app/admin/approvals/components/ApprovalModal.tsx
  • src/app/admin/pc-listing-approvals/components/ApprovalModal.tsx
  • src/app/listings/[id]/components/ListingDetailsClient.tsx
  • src/app/listings/components/shared/CustomFieldRenderer.tsx
  • src/app/listings/components/shared/CustomFieldsSection.tsx
  • src/app/listings/components/shared/approval/ApprovalModalSharedComponents.tsx
  • src/app/listings/components/shared/approval/ListingApprovalModal.tsx
  • src/app/listings/components/shared/utils/isDefaultValue.ts
  • src/app/pc-listings/[id]/components/PcListingDetailsClient.tsx
  • src/components/admin/review-risk/ReviewRiskIndicator.tsx
  • src/components/admin/review-risk/ReviewRiskWarningBanner.tsx
  • src/components/compatibility/review/CompatibilityReportApprovalActions.tsx
  • src/components/compatibility/review/CompatibilityReportCustomFieldValue.tsx
  • src/components/compatibility/review/CompatibilityReportReviewModal.test.tsx
  • src/components/compatibility/review/CompatibilityReportReviewModal.tsx
  • src/components/compatibility/review/ReviewRiskWarningBanner.tsx
  • src/components/compatibility/review/index.ts
  • src/components/compatibility/review/reviewRiskDisplay.ts
  • src/constants/customFields.ts
  • src/server/api/routers/listings/core.test.ts
  • src/server/api/routers/listings/core.ts
  • src/server/api/routers/pcListings.test.ts
  • src/server/api/routers/pcListings.ts
  • src/server/services/review-risk.service.test.ts
  • src/server/services/review-risk.service.ts
  • tests/helpers/data-factory.ts
  • tests/listing-approval.spec.ts
💤 Files with no reviewable changes (2)
  • src/app/listings/components/shared/approval/ApprovalModalSharedComponents.tsx
  • src/app/listings/components/shared/approval/ListingApprovalModal.tsx

Comment thread src/components/compatibility/review/CompatibilityReportReviewModal.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/app/admin/approvals/page.tsx (1)

216-223: ⚡ Quick win

Avoid refetching the admin datasets twice after bulk actions.

Both bulk mutations already run invalidateQueries() in onSuccess, so these extra calls immediately trigger the same refetch fan-out again. That adds avoidable network churn and loading flicker on every bulk approve/reject.

♻️ Proposed cleanup
   const handleBulkApprovalWithConfirmation = async (listingIds: string[]) => {
     const confirmed = await confirmBulkApproval(listings, listingIds, confirm, 'listings')
     if (!confirmed) return

     await bulkApproveMutation.mutateAsync({ listingIds })
-    await invalidateQueries()
     approvalModal.close()
   }
             reject: {
               label: 'Reject Selected',
               onAction: async (listingIds, notes) => {
                 await bulkRejectMutation.mutateAsync({ listingIds, notes })
-                await invalidateQueries()
               },
             },

Also applies to: 352-355

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

In `@src/app/admin/approvals/page.tsx` around lines 216 - 223, The extra call to
invalidateQueries() inside handleBulkApprovalWithConfirmation is redundant
because bulkApproveMutation.mutateAsync already triggers invalidateQueries() in
its onSuccess; remove the await invalidateQueries() line from
handleBulkApprovalWithConfirmation (keep the confirm call, mutateAsync call and
approvalModal.close()), and do the same cleanup in the other bulk action handler
(e.g., the bulk reject handler such as handleBulkRejectionWithConfirmation or
wherever bulkRejectMutation.mutateAsync is used) so you don't double-invalidate
and refetch.
🤖 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/components/compatibility/review/CompatibilityReportReviewModal.tsx`:
- Around line 127-130: The Link element in CompatibilityReportReviewModal (the
<Link href={`/users/${props.author.id}`} target="_blank` />) opens an external
tab without tab-isolation attributes; add rel="noopener noreferrer" to that Link
(the element rendering the author profile link) so external pages opened with
target="_blank" cannot access window.opener or leak referrer information.

In `@src/components/compatibility/review/reviewItem.ts`:
- Around line 3-8: The import currently brings ApprovalStatus in using a
type-only import which removes its runtime value needed by the
CompatibilityReportReviewDecision union; change the import so ApprovalStatus is
imported as a value (not only with the `type` modifier) and update
CompatibilityReportReviewDecision to use the actual enum/value members (e.g.,
ApprovalStatus.APPROVED and ApprovalStatus.REJECTED) instead of typeof
expressions; keep CustomFieldType as a type-only import if it’s only used in
type positions.

---

Nitpick comments:
In `@src/app/admin/approvals/page.tsx`:
- Around line 216-223: The extra call to invalidateQueries() inside
handleBulkApprovalWithConfirmation is redundant because
bulkApproveMutation.mutateAsync already triggers invalidateQueries() in its
onSuccess; remove the await invalidateQueries() line from
handleBulkApprovalWithConfirmation (keep the confirm call, mutateAsync call and
approvalModal.close()), and do the same cleanup in the other bulk action handler
(e.g., the bulk reject handler such as handleBulkRejectionWithConfirmation or
wherever bulkRejectMutation.mutateAsync is used) so you don't double-invalidate
and refetch.
🪄 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: 3645c56b-4224-4784-965b-e29c28886468

📥 Commits

Reviewing files that changed from the base of the PR and between 28f8d16 and 949eb6c.

📒 Files selected for processing (17)
  • src/app/admin/approvals/components/ApprovalModal.tsx
  • src/app/admin/approvals/page.tsx
  • src/app/admin/pc-listing-approvals/components/ApprovalModal.tsx
  • src/app/admin/pc-listing-approvals/page.tsx
  • src/components/compatibility/review/CompatibilityReportApprovalActions.tsx
  • src/components/compatibility/review/CompatibilityReportCustomFieldValue.tsx
  • src/components/compatibility/review/CompatibilityReportReviewModal.test.tsx
  • src/components/compatibility/review/CompatibilityReportReviewModal.tsx
  • src/components/compatibility/review/CompatibilityReportReviewModalAdapter.tsx
  • src/components/compatibility/review/index.ts
  • src/components/compatibility/review/reviewItem.ts
  • src/components/compatibility/review/useCompatibilityReportReviewDecisionModal.ts
  • src/server/api/routers/listings/core.test.ts
  • src/server/api/routers/listings/core.ts
  • src/server/api/routers/pcListings.ts
  • src/server/services/review-risk.service.test.ts
  • src/server/services/review-risk.service.ts
💤 Files with no reviewable changes (2)
  • src/app/admin/pc-listing-approvals/components/ApprovalModal.tsx
  • src/app/admin/approvals/components/ApprovalModal.tsx
✅ Files skipped from review due to trivial changes (1)
  • src/components/compatibility/review/useCompatibilityReportReviewDecisionModal.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/server/services/review-risk.service.test.ts
  • src/components/compatibility/review/index.ts
  • src/components/compatibility/review/CompatibilityReportCustomFieldValue.tsx

Comment thread src/components/compatibility/review/reviewItem.ts Outdated
…place FieldValueLike with CompatibilityCustomFieldValue across codebase
@Producdevity Producdevity merged commit 797b154 into staging May 21, 2026
8 checks passed
@Producdevity Producdevity deleted the feat/review-modals branch May 21, 2026 06:57
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.

1 participant