1- import { useState } from 'react'
1+ import { useContext , useEffect , useState } from 'react'
2+ import { FilecoinPinContext } from '../../context/filecoin-pin-provider.tsx'
3+ import { useDatasetPieces } from '../../hooks/use-dataset-pieces.ts'
24import { useFilecoinUpload } from '../../hooks/use-filecoin-upload.ts'
5+ import { formatFileSize } from '../../utils/format-file-size.ts'
6+ import { Heading } from '../ui/heading.tsx'
7+ import { LoadingState } from '../ui/loading-state.tsx'
8+ import { PageTitle } from '../ui/page-title.tsx'
39import DragNDrop from '../upload/drag-n-drop.tsx'
10+ import type { UploadProgress as UploadProgressType } from '../upload/upload-progress.tsx'
411import UploadProgress from '../upload/upload-progress.tsx'
512import './content.css'
6- import { PageTitle } from '../ui/page-title.tsx'
7- import { Heading } from '../ui/heading.tsx'
13+
14+ // Completed state for displaying upload history
15+ const COMPLETED_PROGRESS : UploadProgressType [ ] = [
16+ { step : 'creating-car' , status : 'completed' , progress : 100 } ,
17+ { step : 'checking-readiness' , status : 'completed' , progress : 100 } ,
18+ { step : 'uploading-car' , status : 'completed' , progress : 100 } ,
19+ { step : 'announcing-cids' , status : 'completed' , progress : 100 } ,
20+ { step : 'finalizing-transaction' , status : 'completed' , progress : 100 } ,
21+ ]
822
923export default function Content ( ) {
1024 const [ uploadedFile , setUploadedFile ] = useState < { file : File ; cid : string } | null > ( null )
1125 const [ isExpanded , setIsExpanded ] = useState ( true )
26+ const [ expandedHistoryItems , setExpandedHistoryItems ] = useState < Set < string > > ( new Set ( ) )
27+ const [ dragDropKey , setDragDropKey ] = useState ( 0 ) // Key to force DragNDrop remount
1228 const { uploadState, uploadFile, resetUpload } = useFilecoinUpload ( )
29+ const { pieces : uploadHistory , refreshPieces, isLoading : isLoadingPieces } = useDatasetPieces ( )
30+ const context = useContext ( FilecoinPinContext )
31+ if ( ! context ) {
32+ throw new Error ( 'Content must be used within FilecoinPinProvider' )
33+ }
34+
35+ const { providerInfo, wallet, synapse } = context
36+
37+ // Determine if we're still initializing (wallet, synapse, provider)
38+ // Note: We don't block on isLoadingPieces - users can upload while history loads
39+ const isInitializing = wallet . status === 'loading' || wallet . status === 'idle'
40+
41+ // Get loading message based on current state
42+ const getLoadingMessage = ( ) => {
43+ if ( wallet . status === 'loading' || wallet . status === 'idle' ) {
44+ return 'Connecting to Filecoin network...'
45+ }
46+ if ( ! synapse ) {
47+ return 'Initializing storage service...'
48+ }
49+ if ( ! providerInfo ) {
50+ return 'Selecting storage provider...'
51+ }
52+ return 'Preparing upload interface...'
53+ }
54+
55+ // If wallet failed to load, show error instead of spinner
56+ if ( wallet . status === 'error' ) {
57+ return (
58+ < div className = "content" >
59+ < PageTitle />
60+ < div className = "error-message" >
61+ < p > Failed to connect to Filecoin network: { wallet . error } </ p >
62+ </ div >
63+ </ div >
64+ )
65+ }
1366
1467 const handleUpload = ( file : File ) => {
1568 // Set uploadedFile immediately to switch to progress view
@@ -27,61 +80,98 @@ export default function Content() {
2780 } )
2881 }
2982
30- const formatFileSize = ( bytes : number ) : string => {
31- if ( bytes === 0 ) return '0 Bytes'
32- const k = 1024
33- const sizes = [ 'Bytes' , 'KB' , 'MB' , 'GB' ]
34- const i = Math . floor ( Math . log ( bytes ) / Math . log ( k ) )
35- return `${ parseFloat ( ( bytes / k ** i ) . toFixed ( 2 ) ) } ${ sizes [ i ] } `
36- }
83+ // Refresh pieces list when upload completes
84+ useEffect ( ( ) => {
85+ const isUploadComplete = ! uploadState . isUploading && uploadState . progress . every ( ( p ) => p . status === 'completed' )
86+ if ( isUploadComplete && uploadState . currentCid ) {
87+ console . debug ( '[Content] Upload completed, refreshing pieces list' )
88+ // Add a small delay to ensure the piece is indexed
89+ setTimeout ( ( ) => {
90+ refreshPieces ( )
91+ // Clear the uploadedFile after adding to history so the upload form shows again
92+ setUploadedFile ( null )
93+ resetUpload ( )
94+ // Increment key to force DragNDrop to remount and clear its state
95+ setDragDropKey ( ( prev ) => prev + 1 )
96+ } , 2000 )
97+ }
98+ } , [ uploadState . isUploading , uploadState . progress , uploadState . currentCid , refreshPieces , resetUpload ] )
99+
100+ // Auto-clear upload state on error
101+ useEffect ( ( ) => {
102+ if ( uploadState . error ) {
103+ // Keep showing the error for a bit, then auto-clear after 5 seconds
104+ const timer = setTimeout ( ( ) => {
105+ setUploadedFile ( null )
106+ resetUpload ( )
107+ // Increment key to force DragNDrop to remount and clear its state
108+ setDragDropKey ( ( prev ) => prev + 1 )
109+ } , 5000 )
110+ return ( ) => clearTimeout ( timer )
111+ }
112+ } , [ uploadState . error , resetUpload ] )
37113
38114 return (
39115 < div className = "space-y-10" >
40116 < PageTitle />
41117
42- { uploadedFile ? (
118+ { /* Show drag-n-drop - disabled when actively uploading */ }
119+ < div className = "space-y-6" >
120+ < Heading tag = "h2" > Upload a file</ Heading >
121+ < DragNDrop isUploading = { uploadState . isUploading } key = { dragDropKey } onUpload = { handleUpload } />
122+ </ div >
123+
124+ { /* Show active upload progress */ }
125+ { uploadedFile && (
43126 < div className = "space-y-6" >
44- < Heading tag = "h2" > Uploaded files </ Heading >
127+ < Heading tag = "h2" > Current upload </ Heading >
45128 < UploadProgress
129+ cid = { uploadState . currentCid }
46130 fileName = { uploadedFile . file . name }
47131 fileSize = { formatFileSize ( uploadedFile . file . size ) }
48132 isExpanded = { isExpanded }
133+ network = { wallet . status === 'ready' ? wallet . data . network : undefined }
49134 onToggleExpanded = { ( ) => setIsExpanded ( ! isExpanded ) }
135+ pieceCid = { uploadState . pieceCid }
50136 progress = { uploadState . progress }
137+ providerName = { providerInfo ?. name || ( providerInfo ?. id ? String ( providerInfo . id ) : undefined ) }
138+ transactionHash = { uploadState . transactionHash }
51139 />
52- { uploadState . error && (
53- < div className = "error-message" >
54- < p > Upload failed: { uploadState . error } </ p >
55- < button
56- onClick = { ( ) => {
57- setUploadedFile ( null )
58- resetUpload ( )
59- } }
60- type = "button"
61- >
62- Try Again
63- </ button >
64- </ div >
65- ) }
66- { ! uploadState . isUploading && uploadState . progress . every ( ( p ) => p . status === 'completed' ) && (
67- < div className = "success-message" >
68- < p > ✅ File successfully uploaded! CID: { uploadedFile . cid } </ p >
69- < button
70- onClick = { ( ) => {
71- setUploadedFile ( null )
72- resetUpload ( )
73- } }
74- type = "button"
75- >
76- Upload Another File
77- </ button >
78- </ div >
79- ) }
80140 </ div >
81- ) : (
141+ ) }
142+
143+ { ( isLoadingPieces || isInitializing ) && uploadHistory . length === 0 && (
144+ < LoadingState message = { getLoadingMessage ( ) } />
145+ ) }
146+ { /* Always show upload history when available */ }
147+ { uploadHistory . length > 0 && (
82148 < div className = "space-y-6" >
83- < Heading tag = "h2" > Upload a file</ Heading >
84- < DragNDrop isUploading = { uploadState . isUploading } onUpload = { handleUpload } />
149+ < Heading tag = "h2" > Uploaded files</ Heading >
150+ { uploadHistory . map ( ( upload ) => (
151+ < UploadProgress
152+ cid = { upload . cid }
153+ fileName = { upload . fileName }
154+ fileSize = { upload . fileSize }
155+ isExpanded = { expandedHistoryItems . has ( upload . id ) }
156+ key = { upload . id }
157+ network = { upload . network }
158+ onToggleExpanded = { ( ) => {
159+ setExpandedHistoryItems ( ( prev ) => {
160+ const next = new Set ( prev )
161+ if ( next . has ( upload . id ) ) {
162+ next . delete ( upload . id )
163+ } else {
164+ next . add ( upload . id )
165+ }
166+ return next
167+ } )
168+ } }
169+ pieceCid = { upload . pieceCid }
170+ progress = { COMPLETED_PROGRESS }
171+ providerName = { upload . providerName }
172+ transactionHash = { upload . transactionHash }
173+ />
174+ ) ) }
85175 </ div >
86176 ) }
87177 </ div >
0 commit comments