|
1 | 1 | import { PageLayout } from '../components/layout/PageLayout'; |
2 | 2 | import { ConnectedMarketValueChart } from '../components/charts/ConnectedMarketValueChart'; |
3 | 3 | import { ConnectedIndustryBreakdownChart } from '../components/charts/ConnectedIndustryBreakdownChart'; |
4 | | -import { TasksBox } from '../components/portfolio/TasksBox'; |
| 4 | +import { PendingIngestionsBox } from '../components/portfolio/PendingIngestionsBox'; |
5 | 5 | import { LoanRepositoryTable } from '../components/loans/LoanRepositoryTable'; |
6 | 6 | import { LoanDetailModal } from '../components/loans/LoanDetailModal'; |
7 | 7 | import { DealUploadModal } from '../components/deals/DealUploadModal'; |
@@ -130,9 +130,17 @@ export default function PortfolioPage() { |
130 | 130 | userEmail: currentUser?.email, |
131 | 131 | onSuccess: (dealId) => { |
132 | 132 | 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 | + |
133 | 141 | loadCompanyDeals(); |
134 | 142 | cacheAllDataForChatWidget(); |
135 | | - loadPendingDocuments(); // Refresh pending list |
| 143 | + loadPendingDocuments(); // Refresh pending list from server |
136 | 144 | }, |
137 | 145 | onError: (error) => { |
138 | 146 | console.error('[PortfolioPage] Extraction error:', error); |
@@ -733,7 +741,17 @@ export default function PortfolioPage() { |
733 | 741 | documentFilename={reviewDocumentFilename} |
734 | 742 | onCreateDeal={async (data) => { |
735 | 743 | console.log('[PortfolioPage] Creating deal from extraction:', data); |
| 744 | + |
| 745 | + // Capture the document ID before it gets cleared |
| 746 | + const documentIdToRemove = reviewDocumentId; |
| 747 | + |
736 | 748 | 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 | + } |
737 | 755 | }} |
738 | 756 | user={currentUser || undefined as any} |
739 | 757 | /> |
@@ -810,145 +828,15 @@ export default function PortfolioPage() { |
810 | 828 | timeRange="all_time" |
811 | 829 | /> |
812 | 830 |
|
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} |
820 | 837 | /> |
821 | 838 | </div> |
822 | 839 |
|
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 | | - |
952 | 840 | {/* Portfolio Loans */} |
953 | 841 | <LoanRepositoryTable |
954 | 842 | key={`${selectedCompany?.id}-${currentPage}`} |
@@ -1023,7 +911,17 @@ export default function PortfolioPage() { |
1023 | 911 | documentFilename={reviewDocumentFilename} |
1024 | 912 | onCreateDeal={async (data) => { |
1025 | 913 | console.log('[PortfolioPage] Creating deal from extraction:', data); |
| 914 | + |
| 915 | + // Capture the document ID before it gets cleared |
| 916 | + const documentIdToRemove = reviewDocumentId; |
| 917 | + |
1026 | 918 | 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 | + } |
1027 | 925 | }} |
1028 | 926 | user={currentUser || undefined as any} |
1029 | 927 | /> |
|
0 commit comments