Conversation
|
@Praxhant97 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
There was a problem hiding this comment.
Pull request overview
Introduces an admin-facing adoption document review workflow (view/approve/reject with reasons) by adding document types, API client + mutation hook, a new admin review panel UI, mock API support, and unit tests.
Changes:
- Added document review types (
reviewStatus,reviewReason, on-chain verification fields) and adocumentServiceclient +useMutateReviewDocumenthook. - Implemented
AdminDocumentReviewPanelUI and integrated it intoSettlementSummaryPage. - Extended MSW mock handlers and added unit tests for the new review panel.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/types/document.ts | Adds document + review payload types used across UI/API. |
| src/api/documentService.ts | Adds client methods for listing documents and submitting reviews. |
| src/hooks/useMutateReviewDocument.ts | Adds mutation hook with cache invalidation for document reviews. |
| src/components/adoption/AdminDocumentReviewPanel.tsx | Implements the admin review panel UI (approve/reject + progress). |
| src/components/adoption/tests/AdminDocumentReviewPanel.test.tsx | Adds unit tests for panel visibility and interactions. |
| src/mocks/handlers/files.ts | Extends mock documents and adds PATCH review endpoint. |
| src/pages/SettlementSummaryPage.tsx | Wires the admin review panel into the settlement summary page. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| document.reviewStatus = body.decision; | ||
| document.reviewReason = body.decision === "REJECTED" ? (body.reason ?? "") : null; |
There was a problem hiding this comment.
When rejecting, the mock handler defaults a missing reason to an empty string. This makes it easy for callers to accidentally produce a “rejected with no reason” state and diverges from the intended workflow. Consider validating the payload (return 400/422 if decision === "REJECTED" and reason is missing/blank) and/or storing null instead of "" to keep state unambiguous.
| document.reviewStatus = body.decision; | |
| document.reviewReason = body.decision === "REJECTED" ? (body.reason ?? "") : null; | |
| if (body.decision === "REJECTED") { | |
| const reason = | |
| typeof body.reason === "string" ? body.reason.trim() : ""; | |
| if (!reason) { | |
| return HttpResponse.json( | |
| { | |
| message: | |
| "Review reason is required when rejecting a document.", | |
| }, | |
| { status: 422 }, | |
| ); | |
| } | |
| document.reviewStatus = body.decision; | |
| document.reviewReason = reason; | |
| } else { | |
| document.reviewStatus = body.decision; | |
| document.reviewReason = null; | |
| } |
| /> | ||
| )} | ||
|
|
||
| {adoptionId ? <AdminDocumentReviewPanel adoptionId={adoptionId} /> : null} |
There was a problem hiding this comment.
AdminDocumentReviewPanel is rendered whenever adoptionId is present, even for non-admin users. Because the panel’s hooks run before it returns null, this can still trigger document fetches/mutations setup for non-admins. Render the panel only when canAdminReview is true (or otherwise gate mounting) to avoid unnecessary/unauthorized requests.
| {adoptionId ? <AdminDocumentReviewPanel adoptionId={adoptionId} /> : null} | |
| {canAdminReview && adoptionId ? ( | |
| <AdminDocumentReviewPanel adoptionId={adoptionId} /> | |
| ) : null} |
| const { data, isLoading, isError } = useApiQuery<AdoptionDocument[]>( | ||
| ["adoption", adoptionId, "documents"], | ||
| () => documentService.getAdoptionDocuments(adoptionId), | ||
| { enabled: Boolean(adoptionId) }, |
There was a problem hiding this comment.
useApiQuery is enabled whenever adoptionId is truthy. Since hooks execute even when the component later returns null for non-admins, this will still fetch documents for users without admin privileges. Gate the query with enabled: Boolean(adoptionId) && isAdmin (or split into an admin-only inner component so non-admins never instantiate the query/mutation hooks).
| { enabled: Boolean(adoptionId) }, | |
| { enabled: Boolean(adoptionId) && isAdmin }, |
| const isRowPending = isPending && activeDocumentId === document.id; | ||
| const isRejecting = rejectingDocumentId === document.id; | ||
|
|
There was a problem hiding this comment.
isPending is global for the mutation, but isRowPending only disables the active row. This allows starting another approve/reject while a mutation is already pending, and activeDocumentId will be overwritten (so the UI can show the wrong row as “pending”). Consider disabling all row actions while isPending is true, or track a set/map of pending document IDs to support safe concurrency.
| export interface ReviewDocumentPayload { | ||
| decision: DocumentReviewDecision; | ||
| reason?: string; | ||
| } No newline at end of file |
There was a problem hiding this comment.
reason is optional even when decision is "REJECTED". Since the UI flow requires a rejection reason, consider modeling ReviewDocumentPayload as a discriminated union (e.g., { decision: "APPROVED" } | { decision: "REJECTED"; reason: string }) so callers can’t accidentally submit a rejection without a reason.
| export interface ReviewDocumentPayload { | |
| decision: DocumentReviewDecision; | |
| reason?: string; | |
| } | |
| export type ReviewDocumentPayload = | |
| | { | |
| decision: "APPROVED"; | |
| reason?: string; | |
| } | |
| | { | |
| decision: "REJECTED"; | |
| reason: string; | |
| }; |
|
@Praxhant97 conflicts |
Closes #264
This pull request introduces a complete admin-facing document review workflow for adoption documents, including backend API integration, UI components, hooks, and tests. Admins can now view, approve, or reject adoption documents with reasons, and see real-time updates to document status. The mock API and document types have been extended to support review status and reasons.
The most important changes are:
Admin Document Review Feature:
AdminDocumentReviewPanelReact component, which allows admins to view, approve, or reject adoption documents, including inline rejection reasons and progress tracking.SettlementSummaryPage, making it visible to admins when appropriate. [1] [2] [3] [4]API and Data Layer:
documentServiceAPI client with methods for fetching adoption documents and submitting document reviews.useMutateReviewDocumentReact hook to handle review mutations and cache invalidation.Type Definitions and Mock API:
AdoptionDocumenttype and related types to includereviewStatus,reviewReason,onChainVerified, andanchorTxHash.Testing:
AdminDocumentReviewPanel, covering visibility, approval, rejection, and UI updates.