Skip to content

Feat/admin file verification UI#294

Open
Praxhant97 wants to merge 3 commits intoamina69:mainfrom
Praxhant97:feat/admin-file-verification-ui
Open

Feat/admin file verification UI#294
Praxhant97 wants to merge 3 commits intoamina69:mainfrom
Praxhant97:feat/admin-file-verification-ui

Conversation

@Praxhant97
Copy link
Copy Markdown

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:

  • Added the AdminDocumentReviewPanel React component, which allows admins to view, approve, or reject adoption documents, including inline rejection reasons and progress tracking.
  • Integrated the admin review panel into the SettlementSummaryPage, making it visible to admins when appropriate. [1] [2] [3] [4]

API and Data Layer:

  • Implemented the documentService API client with methods for fetching adoption documents and submitting document reviews.
  • Created the useMutateReviewDocument React hook to handle review mutations and cache invalidation.

Type Definitions and Mock API:

  • Extended the AdoptionDocument type and related types to include reviewStatus, reviewReason, onChainVerified, and anchorTxHash.
  • Updated the mock API handlers and seed data to support document review, including PATCH endpoints and review state. [1] [2] [3] [4] [5]

Testing:

  • Added comprehensive tests for the AdminDocumentReviewPanel, covering visibility, approval, rejection, and UI updates.

Copilot AI review requested due to automatic review settings March 29, 2026 16:40
@drips-wave
Copy link
Copy Markdown

drips-wave bot commented Mar 29, 2026

@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! 🚀

Learn more about application limits

Copy link
Copy Markdown

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

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 a documentService client + useMutateReviewDocument hook.
  • Implemented AdminDocumentReviewPanel UI and integrated it into SettlementSummaryPage.
  • 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.

Comment on lines +136 to +137
document.reviewStatus = body.decision;
document.reviewReason = body.decision === "REJECTED" ? (body.reason ?? "") : null;
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

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.

Suggested change
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;
}

Copilot uses AI. Check for mistakes.
/>
)}

{adoptionId ? <AdminDocumentReviewPanel adoptionId={adoptionId} /> : null}
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

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.

Suggested change
{adoptionId ? <AdminDocumentReviewPanel adoptionId={adoptionId} /> : null}
{canAdminReview && adoptionId ? (
<AdminDocumentReviewPanel adoptionId={adoptionId} />
) : null}

Copilot uses AI. Check for mistakes.
const { data, isLoading, isError } = useApiQuery<AdoptionDocument[]>(
["adoption", adoptionId, "documents"],
() => documentService.getAdoptionDocuments(adoptionId),
{ enabled: Boolean(adoptionId) },
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

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).

Suggested change
{ enabled: Boolean(adoptionId) },
{ enabled: Boolean(adoptionId) && isAdmin },

Copilot uses AI. Check for mistakes.
Comment on lines +125 to +127
const isRowPending = isPending && activeDocumentId === document.id;
const isRejecting = rejectingDocumentId === document.id;

Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
Comment on lines +22 to +25
export interface ReviewDocumentPayload {
decision: DocumentReviewDecision;
reason?: string;
} No newline at end of file
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

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

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.

Suggested change
export interface ReviewDocumentPayload {
decision: DocumentReviewDecision;
reason?: string;
}
export type ReviewDocumentPayload =
| {
decision: "APPROVED";
reason?: string;
}
| {
decision: "REJECTED";
reason: string;
};

Copilot uses AI. Check for mistakes.
@amina69
Copy link
Copy Markdown
Owner

amina69 commented Mar 30, 2026

@Praxhant97 conflicts

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.

[Frontend · File verification UI] Create AdminDocumentReviewPanel component

3 participants