Implement KYC Review Sheet with document list and verify/reject actions

This commit is contained in:
CycroftX
2026-02-03 22:43:48 +05:30
parent 69c6db945a
commit 532ab07961
3 changed files with 242 additions and 64 deletions

View File

@@ -200,5 +200,35 @@ export const mockDocuments: PartnerDocument[] = [
status: 'Verified',
uploadedBy: 'Alex Rivera',
uploadedAt: subMonths(new Date(), 6).toISOString(),
},
{
id: 'doc3',
partnerId: 'p5',
type: 'Compliance',
name: 'Company Registration (Pending)',
url: '#',
status: 'Pending',
uploadedBy: 'John Doe',
uploadedAt: subDays(new Date(), 1).toISOString(),
},
{
id: 'doc4',
partnerId: 'p5',
type: 'Tax',
name: 'PAN Card Copy',
url: '#',
status: 'Pending',
uploadedBy: 'John Doe',
uploadedAt: subDays(new Date(), 1).toISOString(),
},
{
id: 'doc5',
partnerId: 'p5',
type: 'Other',
name: 'Cancelled Cheque',
url: '#',
status: 'Pending',
uploadedBy: 'John Doe',
uploadedAt: subDays(new Date(), 1).toISOString(),
}
];

View File

@@ -0,0 +1,130 @@
import {
Sheet,
SheetContent,
SheetDescription,
SheetHeader,
SheetTitle,
SheetFooter,
} from "@/components/ui/sheet";
import { Button } from "@/components/ui/button";
import { Partner, PartnerDocument } from "@/types/partner";
import { mockDocuments } from "@/data/mockPartnerData";
import { FileText, CheckCircle2, XCircle, Clock, Eye, Download } from "lucide-react";
import { Badge } from "@/components/ui/badge";
import { toast } from "sonner";
import { useState } from "react";
interface KYCReviewSheetProps {
partner: Partner;
open: boolean;
onOpenChange: (open: boolean) => void;
}
export function KYCReviewSheet({ partner, open, onOpenChange }: KYCReviewSheetProps) {
// Filter documents for this partner or use defaults if none found (for demo)
const partnerDocs = mockDocuments.filter(d => d.partnerId === partner.id);
const documentsToDisplay = partnerDocs.length > 0 ? partnerDocs : mockDocuments.slice(0, 3);
const [status, setStatus] = useState<'pending' | 'approved' | 'rejected'>('pending');
const handleApprove = () => {
setStatus('approved');
toast.success(`KYC documents for ${partner.name} verified successfully.`);
setTimeout(() => onOpenChange(false), 1500);
};
const handleReject = () => {
setStatus('rejected');
toast.error(`KYC documents for ${partner.name} rejected. Partner notified.`);
setTimeout(() => onOpenChange(false), 1500);
};
const getStatusIcon = (status: PartnerDocument['status']) => {
switch (status) {
case 'Verified': return <CheckCircle2 className="h-4 w-4 text-success" />;
case 'Rejected': return <XCircle className="h-4 w-4 text-error" />;
case 'Signed': return <CheckCircle2 className="h-4 w-4 text-blue-500" />;
default: return <Clock className="h-4 w-4 text-warning" />;
}
};
return (
<Sheet open={open} onOpenChange={onOpenChange}>
<SheetContent className="w-[400px] sm:w-[540px] overflow-y-auto">
<SheetHeader className="mb-6">
<div className="flex items-center gap-3 mb-2">
<div className="h-10 w-10 rounded-lg bg-orange-500/10 flex items-center justify-center text-orange-600 font-bold">
KYC
</div>
<div>
<SheetTitle>Verification Review</SheetTitle>
<SheetDescription>Review submitted documents for {partner.name}</SheetDescription>
</div>
</div>
</SheetHeader>
<div className="space-y-6">
<div className="rounded-lg border border-border bg-card p-4">
<h4 className="text-sm font-semibold mb-3">Submitted Documents</h4>
<div className="space-y-3">
{documentsToDisplay.map((doc) => (
<div key={doc.id} className="flex items-start gap-3 p-3 rounded-lg bg-secondary/20 hover:bg-secondary/40 transition-colors border border-transparent hover:border-border/50 group">
<div className="mt-1">
<FileText className="h-5 w-5 text-muted-foreground" />
</div>
<div className="flex-1 min-w-0">
<div className="flex items-center justify-between mb-1">
<p className="font-medium text-sm truncate pr-2">{doc.name}</p>
{getStatusIcon(doc.status)}
</div>
<div className="flex items-center justify-between text-xs text-muted-foreground">
<span>{doc.type} {new Date(doc.uploadedAt).toLocaleDateString()}</span>
<Badge variant="outline" className="text-[10px] h-5 px-1.5 font-normal">
{doc.status}
</Badge>
</div>
</div>
<div className="flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
<Button variant="ghost" size="icon" className="h-8 w-8 text-muted-foreground hover:text-foreground">
<Eye className="h-4 w-4" />
</Button>
<Button variant="ghost" size="icon" className="h-8 w-8 text-muted-foreground hover:text-foreground">
<Download className="h-4 w-4" />
</Button>
</div>
</div>
))}
</div>
</div>
<div className="space-y-3">
<h4 className="text-sm font-semibold">Verification Decision</h4>
<div className="flex gap-3">
<Button
className="flex-1 bg-success hover:bg-success/90 text-white gap-2"
onClick={handleApprove}
disabled={status !== 'pending'}
>
<CheckCircle2 className="h-4 w-4" />
Approve & Verify
</Button>
<Button
variant="destructive"
className="flex-1 gap-2"
onClick={handleReject}
disabled={status !== 'pending'}
>
<XCircle className="h-4 w-4" />
Reject & Request Changes
</Button>
</div>
<p className="text-xs text-muted-foreground text-center pt-2">
Actions are logged for audit purposes.
</p>
</div>
</div>
</SheetContent>
</Sheet>
);
}

View File

@@ -9,6 +9,8 @@ import {
DropdownMenuTrigger
} from '@/components/ui/dropdown-menu';
import { useNavigate } from 'react-router-dom';
import { useState } from 'react';
import { KYCReviewSheet } from './KYCReviewSheet';
interface PartnerCardProps {
partner: Partner;
@@ -16,8 +18,10 @@ interface PartnerCardProps {
export function PartnerCard({ partner }: PartnerCardProps) {
const navigate = useNavigate();
const [showKYCSheet, setShowKYCSheet] = useState(false);
return (
<>
<div
className="group relative neu-card p-5 hover:border-accent/50 transition-all duration-300 cursor-pointer"
onClick={() => navigate(`/partners/${partner.id}`)}
@@ -61,9 +65,16 @@ export function PartnerCard({ partner }: PartnerCardProps) {
</div>
{partner.verificationStatus === 'Pending' && (
<div className="mb-4 bg-warning/10 text-warning px-3 py-1.5 rounded-md text-xs font-medium flex items-center justify-between">
<div className="mb-4 bg-warning/10 text-warning px-3 py-1.5 rounded-md text-xs font-medium flex items-center justify-between" onClick={(e) => e.stopPropagation()}>
<span>KYC Verification Pending</span>
<Button variant="ghost" size="sm" className="h-6 px-2 text-warning hover:text-warning hover:bg-warning/20">Review</Button>
<Button
variant="ghost"
size="sm"
className="h-6 px-2 text-warning hover:text-warning hover:bg-warning/20"
onClick={() => setShowKYCSheet(true)}
>
Review
</Button>
</div>
)}
@@ -89,5 +100,12 @@ export function PartnerCard({ partner }: PartnerCardProps) {
</span>
</div>
</div>
<KYCReviewSheet
partner={partner}
open={showKYCSheet}
onOpenChange={setShowKYCSheet}
/>
</>
);
}