@@ -6,15 +6,17 @@ import { useProjectMetadata } from '@containers';
66import { ProjectFieldsFragment , ProjectsOrderBy } from '@subql/network-query' ;
77import { useGetProjectsLazyQuery } from '@subql/react-hooks' ;
88import { notEmpty } from '@utils' ;
9- import { filterSuccessPromoiseSettledResult } from '@utils' ;
109import { makeCacheKey } from '@utils/limitation' ;
1110import { waitForSomething } from '@utils/waitForSomething' ;
12- import { useInterval , useMount } from 'ahooks' ;
11+ import { useMount } from 'ahooks' ;
1312import localforage from 'localforage' ;
1413import { uniqWith } from 'lodash-es' ;
14+ import { cloneDeep } from 'lodash-es' ;
1515
1616const cacheKey = makeCacheKey ( 'localProjectWithMetadata' ) ;
1717
18+ type ProjectWithMetadata = { description : string ; versionDescription : string ; name : string } & ProjectFieldsFragment ;
19+
1820export const useLocalProjects = ( ) => {
1921 // this hooks want to do these things:
2022 // 1. Get all projects order by order
@@ -35,66 +37,80 @@ export const useLocalProjects = () => {
3537 } ) ;
3638 const { getMetadataFromCid } = useProjectMetadata ( ) ;
3739
38- const projects = useRef <
39- ( { description : string ; versionDescription : string ; name : string } & ProjectFieldsFragment ) [ ]
40- > ( [ ] ) ;
40+ const projects = useRef < ProjectWithMetadata [ ] > ( [ ] ) ;
4141
42- const fetchAllProjects = async ( length = 0 ) => {
43- try {
44- loading . current = true ;
42+ const fetchAllProjects = async ( cachedProjects ?: ProjectWithMetadata [ ] , withLoading = true ) => {
43+ const innerFetch : ( fetchedProjects : ProjectWithMetadata [ ] ) => Promise < ProjectWithMetadata [ ] > = async (
44+ fetchedProjects ,
45+ ) => {
46+ let tempProjects = cloneDeep ( fetchedProjects ) || [ ] ;
4547
46- const res = await getProjects ( {
47- variables : {
48- offset : length ,
49- orderBy : [ ProjectsOrderBy . ID_ASC ] ,
50- ids : [ ] ,
51- } ,
52- defaultOptions : {
53- fetchPolicy : 'network-only' ,
54- } ,
55- } ) ;
56-
57- if ( res . data ?. projects ?. nodes ) {
58- const nonEmptyProjects = res . data . projects ?. nodes . filter ( notEmpty ) ;
59- const allMetadata = await Promise . allSettled ( nonEmptyProjects . map ( ( i ) => getMetadataFromCid ( i . metadata ) ) ) ;
60- const projectsWithMetadata = nonEmptyProjects . map ( ( project , index ) => {
61- const rawMetadata = allMetadata [ index ] ;
62- const metadata =
63- rawMetadata . status === 'fulfilled'
64- ? rawMetadata . value
65- : { name : '' , description : '' , versionDescription : '' } ;
66- return {
67- ...project ,
68- ...metadata ,
69- } ;
70- } ) ;
71- const mergered = uniqWith ( [ ...projects . current , ...projectsWithMetadata ] , ( x , y ) => x . id === y . id ) ;
72- projects . current = mergered ;
73- await localforage . setItem ( cacheKey , mergered ) ;
74- if ( mergered . length >= res . data . projects . totalCount ) {
75- loading . current = false ;
76- return ;
48+ try {
49+ if ( withLoading ) {
50+ loading . current = true ;
7751 }
7852
79- window . requestIdleCallback ( ( ) => fetchAllProjects ( mergered . length ) ) ;
53+ const res = await getProjects ( {
54+ variables : {
55+ offset : tempProjects . length ,
56+ orderBy : [ ProjectsOrderBy . ID_ASC ] ,
57+ ids : [ ] ,
58+ } ,
59+ defaultOptions : {
60+ fetchPolicy : 'network-only' ,
61+ } ,
62+ } ) ;
63+
64+ if ( res . data ?. projects ?. nodes ) {
65+ const nonEmptyProjects = res . data . projects ?. nodes . filter ( notEmpty ) ;
66+ const allMetadata = await Promise . allSettled ( nonEmptyProjects . map ( ( i ) => getMetadataFromCid ( i . metadata ) ) ) ;
67+ const projectsWithMetadata = nonEmptyProjects . map ( ( project , index ) => {
68+ const rawMetadata = allMetadata [ index ] ;
69+ const metadata =
70+ rawMetadata . status === 'fulfilled'
71+ ? rawMetadata . value
72+ : { name : '' , description : '' , versionDescription : '' } ;
73+ return {
74+ ...project ,
75+ ...metadata ,
76+ } ;
77+ } ) ;
78+ const mergered = uniqWith ( [ ...tempProjects , ...projectsWithMetadata ] , ( x , y ) => x . id === y . id ) ;
79+ tempProjects = mergered ;
80+ if ( mergered . length >= res . data . projects . totalCount ) {
81+ loading . current = false ;
82+ return tempProjects ;
83+ }
84+
85+ return await innerFetch ( tempProjects ) ;
86+ }
87+ } catch ( e ) {
88+ setError ( e ) ;
89+ loading . current = false ;
90+ return tempProjects ;
8091 }
81- } catch ( e ) {
82- setError ( e ) ;
83- loading . current = false ;
84- }
92+
93+ return tempProjects ;
94+ } ;
95+
96+ const res = await innerFetch ( cachedProjects || [ ] ) ;
97+
98+ projects . current = res ;
99+ await localforage . setItem ( cacheKey , res ) ;
85100 } ;
86101
87102 const init = async ( ) => {
88103 // When first estiblish the local cache. We need to fetch all of it.
89104 // See fetchAllProject. It's a low-priority(requestsIdleCallback) fetch
90- // if there have cache, just add & update metadata .
105+ // if there have cache, use cache first, and then fetch from initial to update .
91106 const cached = await localforage . getItem <
92107 ( { description : string ; versionDescription : string ; name : string } & ProjectFieldsFragment ) [ ]
93108 > ( cacheKey ) ;
94-
95109 if ( cached ) {
96110 projects . current = cached ;
97- fetchAllProjects ( cached . length ) ;
111+ await fetchAllProjects ( cached ) ;
112+ // update for next search
113+ window . requestIdleCallback ( ( ) => fetchAllProjects ( [ ] , false ) ) ;
98114 return ;
99115 }
100116 fetchAllProjects ( ) ;
@@ -119,39 +135,10 @@ export const useLocalProjects = () => {
119135 } ;
120136 } ;
121137
122- const updateExistMetadata = async ( ) => {
123- await waitForSomething ( { func : ( ) => ! loading . current } ) ;
124- // IPFS can be cache. So fetch all of it would ok.
125- const allMetadata = await Promise . allSettled (
126- projects . current . map ( async ( i ) => {
127- const data = await getMetadataFromCid ( i . metadata ) ;
128- return {
129- [ i . id ] : data ,
130- } ;
131- } ) ,
132- ) ;
133- const successData = allMetadata . filter ( filterSuccessPromoiseSettledResult ) ;
134-
135- const newProjectsData = projects . current . map ( ( i ) => {
136- const find = successData . find ( ( x ) => x . value [ i . id ] ) ;
137- return {
138- ...i ,
139- ...find ,
140- } ;
141- } ) ;
142- await localforage . setItem ( cacheKey , newProjectsData ) ;
143-
144- projects . current = newProjectsData ;
145- } ;
146-
147138 useMount ( ( ) => {
148139 window . requestIdleCallback ( ( ) => init ( ) ) ;
149140 } ) ;
150141
151- useInterval ( ( ) => {
152- window . requestIdleCallback ( ( ) => updateExistMetadata ( ) ) ;
153- } , 60000 ) ;
154-
155142 return {
156143 loading,
157144 error,
0 commit comments