@@ -65,6 +65,9 @@ function App() {
6565 const [ campaigns , setCampaigns ] = useState < Campaign [ ] > ( [ ] ) ;
6666 const [ issues , setIssues ] = useState < OpenIssue [ ] > ( [ ] ) ;
6767 const [ history , setHistory ] = useState < CampaignEvent [ ] > ( [ ] ) ;
68+ const [ isCampaignsLoading , setIsCampaignsLoading ] = useState ( false ) ;
69+ const [ isSelectedLoading , setIsSelectedLoading ] = useState ( false ) ;
70+ const [ initialLoad , setInitialLoad ] = useState ( true ) ;
6871 const [ selectedCampaignId , setSelectedCampaignId ] = useState < string | null > ( null ) ;
6972 const [ selectedCampaignDetails , setSelectedCampaignDetails ] = useState < Campaign | null > ( null ) ;
7073 const [ createError , setCreateError ] = useState < string | null > ( null ) ;
@@ -73,13 +76,22 @@ function App() {
7376 const [ pendingPledgeCampaignId , setPendingPledgeCampaignId ] = useState < string | null > ( null ) ;
7477
7578 async function refreshCampaigns ( nextSelectedId ?: string | null ) {
76- const data = await listCampaigns ( ) ;
77- setCampaigns ( data ) ;
78-
79- const candidateId =
80- nextSelectedId ?? selectedCampaignId ?? ( data . length > 0 ? data [ 0 ] . id : null ) ;
81- const exists = data . some ( ( campaign ) => campaign . id === candidateId ) ;
82- setSelectedCampaignId ( exists ? candidateId : data [ 0 ] ?. id ?? null ) ;
79+ const startedAt = Date . now ( ) ;
80+ setIsCampaignsLoading ( true ) ;
81+ try {
82+ const data = await listCampaigns ( ) ;
83+ setCampaigns ( data ) ;
84+
85+ const candidateId =
86+ nextSelectedId ?? selectedCampaignId ?? ( data . length > 0 ? data [ 0 ] . id : null ) ;
87+ const exists = data . some ( ( campaign ) => campaign . id === candidateId ) ;
88+ setSelectedCampaignId ( exists ? candidateId : data [ 0 ] ?. id ?? null ) ;
89+ } finally {
90+ const elapsed = Date . now ( ) - startedAt ;
91+ const minMs = 300 ;
92+ if ( elapsed < minMs ) await delay ( minMs - elapsed ) ;
93+ setIsCampaignsLoading ( false ) ;
94+ }
8395 }
8496
8597 async function refreshHistory ( campaignId : string | null ) {
@@ -88,29 +100,57 @@ function App() {
88100 return ;
89101 }
90102
91- const data = await getCampaignHistory ( campaignId ) ;
92- setHistory ( data ) ;
103+ const startedAt = Date . now ( ) ;
104+ setIsSelectedLoading ( true ) ;
105+ try {
106+ const data = await getCampaignHistory ( campaignId ) ;
107+ setHistory ( data ) ;
108+ } finally {
109+ const elapsed = Date . now ( ) - startedAt ;
110+ const minMs = 200 ;
111+ if ( elapsed < minMs ) await delay ( minMs - elapsed ) ;
112+ setIsSelectedLoading ( false ) ;
113+ }
93114 }
94115
95116 async function refreshSelectedCampaign ( campaignId : string | null ) {
96117 if ( ! campaignId ) {
97118 setSelectedCampaignDetails ( null ) ;
98119 return ;
99120 }
100- const campaign = await getCampaign ( campaignId ) ;
101- setSelectedCampaignDetails ( campaign ) ;
121+ const startedAt = Date . now ( ) ;
122+ setIsSelectedLoading ( true ) ;
123+ try {
124+ const campaign = await getCampaign ( campaignId ) ;
125+ setSelectedCampaignDetails ( campaign ) ;
126+ } finally {
127+ const elapsed = Date . now ( ) - startedAt ;
128+ const minMs = 200 ;
129+ if ( elapsed < minMs ) await delay ( minMs - elapsed ) ;
130+ setIsSelectedLoading ( false ) ;
131+ }
102132 }
103133
104134 useEffect ( ( ) => {
105135 async function bootstrap ( ) {
106- const [ campaignData , issueData ] = await Promise . all ( [
107- listCampaigns ( ) ,
108- listOpenIssues ( ) ,
109- ] ) ;
110-
111- setCampaigns ( campaignData ) ;
112- setIssues ( issueData ) ;
113- setSelectedCampaignId ( campaignData [ 0 ] ?. id ?? null ) ;
136+ const startedAt = Date . now ( ) ;
137+ setIsCampaignsLoading ( true ) ;
138+ try {
139+ const [ campaignData , issueData ] = await Promise . all ( [
140+ listCampaigns ( ) ,
141+ listOpenIssues ( ) ,
142+ ] ) ;
143+
144+ setCampaigns ( campaignData ) ;
145+ setIssues ( issueData ) ;
146+ setSelectedCampaignId ( campaignData [ 0 ] ?. id ?? null ) ;
147+ } finally {
148+ const elapsed = Date . now ( ) - startedAt ;
149+ const minMs = 350 ;
150+ if ( elapsed < minMs ) await delay ( minMs - elapsed ) ;
151+ setIsCampaignsLoading ( false ) ;
152+ setInitialLoad ( false ) ;
153+ }
114154 }
115155
116156 void bootstrap ( ) ;
@@ -304,6 +344,7 @@ function App() {
304344 actionError = { actionError }
305345 actionMessage = { actionMessage }
306346 isPledgePending = { pendingPledgeCampaignId === selectedCampaignId }
347+ isLoading = { isSelectedLoading || initialLoad }
307348 onPledge = { handlePledge }
308349 onClaim = { handleClaim }
309350 onRefund = { handleRefund }
@@ -312,13 +353,14 @@ function App() {
312353
313354 < CampaignsTable
314355 campaigns = { campaigns }
356+ isLoading = { isCampaignsLoading || initialLoad }
315357 selectedCampaignId = { selectedCampaignId }
316358 onSelect = { setSelectedCampaignId }
317359 />
318360
319361 < section className = "secondary-grid" >
320- < CampaignTimeline history = { history } />
321- < IssueBacklog issues = { issues } />
362+ < CampaignTimeline history = { history } isLoading = { isSelectedLoading || initialLoad } />
363+ < IssueBacklog issues = { issues } isLoading = { isSelectedLoading || initialLoad } />
322364 </ section >
323365 </ div >
324366 ) ;
0 commit comments