Skip to content

Commit e72f9d1

Browse files
committed
fix: address movement of pending docs
1 parent 76cda0e commit e72f9d1

3 files changed

Lines changed: 147 additions & 139 deletions

File tree

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import { Card, CardContent, CardHeader, CardTitle } from '../../../shared/components/ui/card';
2+
import { Badge } from '../../../shared/components/ui/badge';
3+
import { Button } from '../../../shared/components/ui/button';
4+
import { Sparkles, FileText, RefreshCw, CheckCircle } from 'lucide-react';
5+
6+
interface PendingDocument {
7+
id: string;
8+
filename: string;
9+
status: string;
10+
progress_percentage?: number;
11+
}
12+
13+
interface PendingIngestionsBoxProps {
14+
documents: PendingDocument[];
15+
isLoading: boolean;
16+
onRefresh: () => void;
17+
onReview: (documentId: string, filename: string) => void;
18+
}
19+
20+
export function PendingIngestionsBox({
21+
documents,
22+
isLoading,
23+
onRefresh,
24+
onReview,
25+
}: PendingIngestionsBoxProps) {
26+
return (
27+
<Card>
28+
<CardHeader>
29+
<div className="flex items-center justify-between">
30+
<CardTitle className="flex items-center gap-2 text-lg">
31+
<Sparkles className="h-5 w-5 text-blue-600 dark:text-blue-400" />
32+
Pending Ingestions
33+
</CardTitle>
34+
<div className="flex items-center gap-2">
35+
<Badge variant="outline" className="border-blue-500/20 text-blue-600">
36+
{documents.length} {documents.length === 1 ? 'document' : 'documents'}
37+
</Badge>
38+
<Button
39+
size="sm"
40+
variant="ghost"
41+
onClick={onRefresh}
42+
disabled={isLoading}
43+
className="h-8 w-8 p-0"
44+
>
45+
<RefreshCw className={`h-4 w-4 ${isLoading ? 'animate-spin' : ''}`} />
46+
</Button>
47+
</div>
48+
</div>
49+
</CardHeader>
50+
<CardContent>
51+
{documents.length === 0 ? (
52+
<div className="text-center py-6 text-muted-foreground">
53+
<p className="text-sm">No documents awaiting review or processing</p>
54+
</div>
55+
) : (
56+
<div className="space-y-2 max-h-[400px] overflow-y-auto">
57+
{documents.map((doc) => (
58+
<div
59+
key={doc.id}
60+
className="bg-white dark:bg-slate-900 border border-blue-200 dark:border-blue-800 rounded-lg p-3 flex flex-col sm:flex-row items-start sm:items-center gap-3"
61+
>
62+
<div className="flex-1 min-w-0 w-full sm:w-auto">
63+
<div className="flex items-center gap-2 mb-1">
64+
<FileText className="h-4 w-4 text-blue-600 dark:text-blue-400 flex-shrink-0" />
65+
<p className="text-sm font-medium truncate" title={doc.filename}>
66+
{doc.filename}
67+
</p>
68+
</div>
69+
<div className="flex items-center gap-2 text-xs text-muted-foreground flex-wrap">
70+
<span className="font-mono bg-slate-100 dark:bg-slate-800 px-2 py-0.5 rounded">
71+
{doc.id.substring(0, 8)}...
72+
</span>
73+
<Badge variant={doc.status === 'pending_user_review' ? 'default' : 'secondary'} className="text-xs">
74+
{doc.status.replace(/_/g, ' ')}
75+
</Badge>
76+
{doc.progress_percentage !== undefined && (
77+
<span className="text-blue-600 dark:text-blue-400 font-medium">
78+
{doc.progress_percentage}%
79+
</span>
80+
)}
81+
</div>
82+
</div>
83+
84+
<Button
85+
size="sm"
86+
variant="outline"
87+
onClick={() => onReview(doc.id, doc.filename)}
88+
disabled={doc.status !== 'pending_user_review'}
89+
className="flex-shrink-0 w-full sm:w-auto"
90+
>
91+
<CheckCircle className="h-4 w-4 mr-1" />
92+
<span className="hidden sm:inline">Review & Confirm</span>
93+
<span className="sm:hidden">Review</span>
94+
</Button>
95+
</div>
96+
))}
97+
</div>
98+
)}
99+
</CardContent>
100+
</Card>
101+
);
102+
}

src/credit/hooks/useExtractionDealCreation.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -662,9 +662,17 @@ export function useExtractionDealCreation(options?: UseExtractionDealCreationOpt
662662
if (state.currentDocumentId) {
663663
try {
664664
console.log('[Create Deal] ✅ Confirming deal on ingestion service for document:', state.currentDocumentId);
665+
666+
// Backend expects flat structure with originator_name and investor_name at top level
667+
const flattenedDealData = {
668+
...extractedData,
669+
originator_name: extractedData.originator?.company_name || extractedData.originator?.name || null,
670+
investor_name: extractedData.investor?.company_name || extractedData.investor?.name || null,
671+
};
672+
665673
await ingestionApi.confirmDeal(
666674
state.currentDocumentId,
667-
extractedData,
675+
flattenedDealData,
668676
finalOriginatorUUID,
669677
finalInvestorUUID
670678
);

src/credit/pages/PortfolioPage.tsx

Lines changed: 36 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { PageLayout } from '../components/layout/PageLayout';
22
import { ConnectedMarketValueChart } from '../components/charts/ConnectedMarketValueChart';
33
import { ConnectedIndustryBreakdownChart } from '../components/charts/ConnectedIndustryBreakdownChart';
4-
import { TasksBox } from '../components/portfolio/TasksBox';
4+
import { PendingIngestionsBox } from '../components/portfolio/PendingIngestionsBox';
55
import { LoanRepositoryTable } from '../components/loans/LoanRepositoryTable';
66
import { LoanDetailModal } from '../components/loans/LoanDetailModal';
77
import { DealUploadModal } from '../components/deals/DealUploadModal';
@@ -130,9 +130,17 @@ export default function PortfolioPage() {
130130
userEmail: currentUser?.email,
131131
onSuccess: (dealId) => {
132132
console.log('[PortfolioPage] Deal created successfully:', dealId);
133+
134+
// Optimistically remove the confirmed document from pending list
135+
if (reviewDocumentId) {
136+
console.log('[PortfolioPage] Removing confirmed document from pending list:', reviewDocumentId);
137+
setPendingDocuments(prev => prev.filter(doc => doc.id !== reviewDocumentId));
138+
setReviewDocumentId(null); // Clear the review ID
139+
}
140+
133141
loadCompanyDeals();
134142
cacheAllDataForChatWidget();
135-
loadPendingDocuments(); // Refresh pending list
143+
loadPendingDocuments(); // Refresh pending list from server
136144
},
137145
onError: (error) => {
138146
console.error('[PortfolioPage] Extraction error:', error);
@@ -733,7 +741,17 @@ export default function PortfolioPage() {
733741
documentFilename={reviewDocumentFilename}
734742
onCreateDeal={async (data) => {
735743
console.log('[PortfolioPage] Creating deal from extraction:', data);
744+
745+
// Capture the document ID before it gets cleared
746+
const documentIdToRemove = reviewDocumentId;
747+
736748
await extractionHook.createDealFromExtraction(data);
749+
750+
// Optimistically remove the document from pending list immediately
751+
if (documentIdToRemove) {
752+
console.log('[PortfolioPage] Removing confirmed document from pending list:', documentIdToRemove);
753+
setPendingDocuments(prev => prev.filter(doc => doc.id !== documentIdToRemove));
754+
}
737755
}}
738756
user={currentUser || undefined as any}
739757
/>
@@ -810,145 +828,15 @@ export default function PortfolioPage() {
810828
timeRange="all_time"
811829
/>
812830

813-
{/* Tasks Box */}
814-
<TasksBox
815-
tasks={[]}
816-
onTaskClick={(task) => {
817-
console.log('Task clicked:', task);
818-
// Handle task click - could open a task modal
819-
}}
831+
{/* Pending Ingestions Box */}
832+
<PendingIngestionsBox
833+
documents={pendingDocuments}
834+
isLoading={isLoadingPending}
835+
onRefresh={loadPendingDocuments}
836+
onReview={handleReviewDocument}
820837
/>
821838
</div>
822839

823-
{/* Pending Ingestions Section */}
824-
{pendingDocuments.length > 0 && (
825-
<div className="bg-gradient-to-br from-blue-50 to-indigo-50 dark:from-blue-950/30 dark:to-indigo-950/30 border border-blue-200 dark:border-blue-800 rounded-lg p-6">
826-
<div className="flex items-center justify-between mb-4">
827-
<div className="flex items-center gap-3">
828-
<div className="bg-blue-100 dark:bg-blue-900 rounded-full p-2">
829-
<Sparkles className="h-5 w-5 text-blue-600 dark:text-blue-400" />
830-
</div>
831-
<div>
832-
<h3 className="text-lg font-semibold text-blue-900 dark:text-blue-100">
833-
Pending Ingestions
834-
</h3>
835-
<p className="text-sm text-blue-700 dark:text-blue-300">
836-
{pendingDocuments.length} document{pendingDocuments.length !== 1 ? 's' : ''} awaiting review or processing
837-
</p>
838-
</div>
839-
</div>
840-
<Button
841-
size="sm"
842-
variant="ghost"
843-
onClick={loadPendingDocuments}
844-
disabled={isLoadingPending}
845-
className="text-blue-700 hover:text-blue-900 dark:text-blue-300 dark:hover:text-blue-100"
846-
>
847-
<RefreshCw className={`h-4 w-4 ${isLoadingPending ? 'animate-spin' : ''}`} />
848-
</Button>
849-
</div>
850-
851-
<div className="space-y-2">
852-
{pendingDocuments.map((doc) => (
853-
<div
854-
key={doc.id}
855-
className="bg-white dark:bg-slate-900 border border-blue-200 dark:border-blue-800 rounded-lg p-4 flex items-center justify-between gap-4 hover:shadow-md transition-shadow"
856-
>
857-
<div className="flex-1 min-w-0 space-y-2">
858-
<div className="flex items-center gap-3">
859-
<FileText className="h-5 w-5 text-blue-600 dark:text-blue-400 flex-shrink-0" />
860-
<p className="text-sm font-medium truncate">{doc.filename}</p>
861-
</div>
862-
863-
{/* Progress Bar for Processing Documents */}
864-
{doc.status !== 'pending_user_review' && doc.status !== 'complete' && (
865-
<div className="ml-8 space-y-1">
866-
<div className="flex items-center justify-between text-xs">
867-
<span className="text-muted-foreground">
868-
{doc.status.replace(/_/g, ' ')}
869-
</span>
870-
<span className="text-blue-600 dark:text-blue-400 font-medium">
871-
{doc.progress_percentage || 0}%
872-
</span>
873-
</div>
874-
<Progress value={doc.progress_percentage || 0} className="h-2" />
875-
</div>
876-
)}
877-
878-
<div className="flex items-center gap-3 text-xs text-muted-foreground ml-8">
879-
<span className="font-mono bg-slate-100 dark:bg-slate-800 px-2 py-0.5 rounded">
880-
{doc.id.substring(0, 8)}...
881-
</span>
882-
<Badge
883-
variant={
884-
doc.status === 'pending_user_review' || doc.status === 'pending_mapping_confirmation'
885-
? 'default'
886-
: 'secondary'
887-
}
888-
className={
889-
doc.status === 'pending_user_review'
890-
? 'bg-green-500'
891-
: doc.status === 'pending_mapping_confirmation'
892-
? 'bg-yellow-500'
893-
: ''
894-
}
895-
>
896-
{doc.status.replace(/_/g, ' ')}
897-
</Badge>
898-
</div>
899-
</div>
900-
901-
<div className="flex items-center gap-2">
902-
<Button
903-
size="sm"
904-
onClick={() => {
905-
if (doc.status === 'pending_mapping_confirmation') {
906-
handleCsvMappingReview(doc);
907-
} else {
908-
handleReviewDocument(doc.id, doc.filename);
909-
}
910-
}}
911-
disabled={doc.status !== 'pending_user_review' && doc.status !== 'pending_mapping_confirmation'}
912-
className={
913-
(doc.status === 'pending_user_review' || doc.status === 'pending_mapping_confirmation')
914-
? 'bg-green-600 hover:bg-green-700'
915-
: ''
916-
}
917-
>
918-
{doc.status === 'pending_user_review' ? (
919-
<>
920-
<CheckCircle className="h-4 w-4 mr-1" />
921-
Review & Confirm
922-
</>
923-
) : doc.status === 'pending_mapping_confirmation' ? (
924-
<>
925-
<FileText className="h-4 w-4 mr-1" />
926-
Review Mappings
927-
</>
928-
) : (
929-
'Processing...'
930-
)}
931-
</Button>
932-
933-
<Button
934-
size="sm"
935-
variant="ghost"
936-
onClick={(e) => {
937-
e.stopPropagation();
938-
handleCancelDocument(doc.id, doc.filename);
939-
}}
940-
className="text-red-600 hover:text-red-700 hover:bg-red-50 dark:hover:bg-red-950"
941-
title="Cancel processing"
942-
>
943-
<X className="h-4 w-4" />
944-
</Button>
945-
</div>
946-
</div>
947-
))}
948-
</div>
949-
</div>
950-
)}
951-
952840
{/* Portfolio Loans */}
953841
<LoanRepositoryTable
954842
key={`${selectedCompany?.id}-${currentPage}`}
@@ -1023,7 +911,17 @@ export default function PortfolioPage() {
1023911
documentFilename={reviewDocumentFilename}
1024912
onCreateDeal={async (data) => {
1025913
console.log('[PortfolioPage] Creating deal from extraction:', data);
914+
915+
// Capture the document ID before it gets cleared
916+
const documentIdToRemove = reviewDocumentId;
917+
1026918
await extractionHook.createDealFromExtraction(data);
919+
920+
// Optimistically remove the document from pending list immediately
921+
if (documentIdToRemove) {
922+
console.log('[PortfolioPage] Removing confirmed document from pending list:', documentIdToRemove);
923+
setPendingDocuments(prev => prev.filter(doc => doc.id !== documentIdToRemove));
924+
}
1027925
}}
1028926
user={currentUser || undefined as any}
1029927
/>

0 commit comments

Comments
 (0)