11import { getCollectionData , getCollectionDataStatistics , getCollections } from "./index.js" ;
22
3+ // Request deduplication map
4+ const pendingRequests = new Map ( ) ;
5+
36export const fetchCollections = async ( dispatch , organization , project ) => {
7+ const requestKey = `collections_${ organization } _${ project } ` ;
8+
9+ // Check for pending request
10+ if ( pendingRequests . has ( requestKey ) ) {
11+ return pendingRequests . get ( requestKey ) ;
12+ }
13+
414 try {
5- const response = await getCollections ( organization , project ) ;
15+ const requestPromise = getCollections ( organization , project )
16+ . then ( ( response ) => {
17+ if ( response . success === false ) {
18+ dispatch ( {
19+ type : "FETCH_ERROR" ,
20+ payload : { response } ,
21+ error : "No collections found" ,
22+ } ) ;
23+ console . warn ( "Warning: Collections fetched are empty." ) ;
24+ } else {
25+ dispatch ( {
26+ type : "FETCH_SUCCESS" ,
27+ payload : { response } ,
28+ } ) ;
29+ console . log ( "Collections fetched:" , response ) ;
30+ }
631
7- if ( response . success === false ) {
8- dispatch ( {
9- type : "FETCH_ERROR" ,
10- payload : { response } ,
11- error : "No collections found" ,
32+ return { response } ;
33+ } )
34+ . finally ( ( ) => {
35+ pendingRequests . delete ( requestKey ) ;
1236 } ) ;
13- console . warn ( "Warning: Collections fetched are empty." ) ;
14- } else {
15- dispatch ( {
16- type : "FETCH_SUCCESS" ,
17- payload : { response } ,
18- } ) ;
19- console . log ( "Collections fetched:" , response ) ;
20- }
2137
22- return { response } ;
38+ pendingRequests . set ( requestKey , requestPromise ) ;
39+ return await requestPromise ;
2340 } catch ( error ) {
41+ pendingRequests . delete ( requestKey ) ;
2442 dispatch ( {
2543 type : "FETCH_ERROR" ,
2644 payload : { error } ,
@@ -29,55 +47,136 @@ export const fetchCollections = async (dispatch, organization, project) => {
2947 }
3048} ;
3149
32- export const fetchData = async ( dispatch , organization , project , collection , params , plotId , type = "data" ) => {
50+ // Optimized fetchData that returns structured results without dispatching
51+ export const fetchData = async ( organization , project , collection , params , plotId , type = "data" ) => {
52+ const requestKey = `${ type } _${ organization } _${ project } _${ collection } _${ plotId } _${ JSON . stringify ( params ) } ` ;
53+
54+ // Check for pending request
55+ if ( pendingRequests . has ( requestKey ) ) {
56+ return pendingRequests . get ( requestKey ) ;
57+ }
58+
3359 try {
34- const response = await ( type === "stats"
60+ const requestPromise = ( type === "stats"
3561 ? getCollectionDataStatistics ( organization , project , collection , params )
36- : getCollectionData ( organization , project , collection , params ) ) ;
62+ : getCollectionData ( organization , project , collection , params ) )
63+ . then ( ( response ) => {
64+ const isEmpty = ( Array . isArray ( response ) && response . length === 0 ) || response . success === false ;
65+
66+ return {
67+ plotId,
68+ response : isEmpty ? [ ] : response ,
69+ isEmpty,
70+ warning : isEmpty ? `No data available for ${ plotId } ` : null ,
71+ type : plotId . toLowerCase ( ) . includes ( "price" ) ? "price"
72+ : plotId . toLowerCase ( ) . includes ( "production" ) ? "production"
73+ : "general" ,
74+ } ;
75+ } )
76+ . catch ( ( error ) => ( {
77+ plotId,
78+ error : error . message || "Unknown error" ,
79+ hasError : true ,
80+ type : plotId . toLowerCase ( ) . includes ( "price" ) ? "price"
81+ : plotId . toLowerCase ( ) . includes ( "production" ) ? "production"
82+ : "general" ,
83+ } ) )
84+ . finally ( ( ) => {
85+ pendingRequests . delete ( requestKey ) ;
86+ } ) ;
87+
88+ pendingRequests . set ( requestKey , requestPromise ) ;
89+ return await requestPromise ;
90+ } catch ( error ) {
91+ pendingRequests . delete ( requestKey ) ;
92+ return {
93+ plotId,
94+ error : error . message || "Unknown error" ,
95+ hasError : true ,
96+ type : plotId . toLowerCase ( ) . includes ( "price" ) ? "price"
97+ : plotId . toLowerCase ( ) . includes ( "production" ) ? "production"
98+ : "general" ,
99+ } ;
100+ }
101+ } ;
102+
103+ // Optimized batch fetching with better error handling
104+ const fetchAllData = async ( dispatch , organization , fetchConfigs ) => {
105+ if ( ! Array . isArray ( fetchConfigs ) ) {
106+ throw new TypeError ( "fetchConfigs should be an array" ) ;
107+ }
37108
38- if ( ( Array . isArray ( response ) && response . length === 0 ) || response . success === false ) {
109+ // Group configs by type for optimized dispatching
110+ const configsByType = fetchConfigs . reduce ( ( acc , config ) => {
111+ const type = config . plotId . toLowerCase ( ) . includes ( "price" ) ? "price"
112+ : config . plotId . toLowerCase ( ) . includes ( "production" ) ? "production"
113+ : "general" ;
114+
115+ if ( ! acc [ type ] ) acc [ type ] = [ ] ;
116+ acc [ type ] . push ( config ) ;
117+ return acc ;
118+ } , { } ) ;
119+
120+ // Process each type separately for better performance
121+ const processTypeGroup = async ( configs , dataType ) => {
122+ const promises = configs . map (
123+ ( { project, collection, params, plotId, type } ) => fetchData ( organization , project , collection , params , plotId , type ) ,
124+ ) ;
125+
126+ const results = await Promise . allSettled ( promises ) ;
127+ return results . map ( ( result , index ) => ( {
128+ ...result . value ,
129+ dataType,
130+ config : configs [ index ] ,
131+ } ) ) ;
132+ } ;
133+
134+ try {
135+ // Process all types in parallel
136+ const typeResults = await Promise . all ( [
137+ configsByType . price ? processTypeGroup ( configsByType . price , "price" ) : [ ] ,
138+ configsByType . production ? processTypeGroup ( configsByType . production , "production" ) : [ ] ,
139+ configsByType . general ? processTypeGroup ( configsByType . general , "general" ) : [ ] ,
140+ ] ) ;
141+
142+ // Flatten results
143+ const allResults = typeResults . flat ( ) ;
144+
145+ // Group results by status and type
146+ const successResults = allResults . filter ( ( r ) => ! r . hasError && ! r . isEmpty ) ;
147+ const warningResults = allResults . filter ( ( r ) => ! r . hasError && r . isEmpty ) ;
148+ const errorResults = allResults . filter ( ( r ) => r . hasError ) ;
149+
150+ // Batch dispatch by type
151+ if ( successResults . length > 0 ) {
152+ dispatch ( {
153+ type : "FETCH_SUCCESS_BATCH" ,
154+ payload : { results : successResults } ,
155+ } ) ;
156+ }
157+
158+ if ( warningResults . length > 0 ) {
39159 dispatch ( {
40- type : "FETCH_WARNING" ,
41- payload : { plotId, response } ,
42- warning : "Some values may be missing" ,
160+ type : "FETCH_WARNING_BATCH" ,
161+ payload : { results : warningResults } ,
43162 } ) ;
44- console . warn ( `Warning: Data fetched for plot ${ plotId } is empty.` ) ;
45- } else {
163+ }
164+
165+ if ( errorResults . length > 0 ) {
46166 dispatch ( {
47- type : "FETCH_SUCCESS " ,
48- payload : { plotId , response } ,
167+ type : "FETCH_ERROR_BATCH " ,
168+ payload : { results : errorResults } ,
49169 } ) ;
50170 }
51171
52- return { response } ;
172+ return allResults ;
53173 } catch ( error ) {
54174 dispatch ( {
55175 type : "FETCH_ERROR" ,
56- payload : { plotId , error } ,
176+ payload : { error : error . message } ,
57177 } ) ;
58178 throw error ;
59179 }
60180} ;
61181
62- const fetchAllData = ( dispatch , organization , fetchConfigs ) => {
63- if ( ! Array . isArray ( fetchConfigs ) ) {
64- throw new TypeError ( "fetchConfigs should be an array" ) ;
65- }
66-
67- // Create an array of promises for each fetch operation
68- const promises = fetchConfigs . map (
69- ( { project, collection, params, plotId, type } ) => fetchData (
70- dispatch ,
71- organization ,
72- project ,
73- collection ,
74- params ,
75- plotId ,
76- type ,
77- ) ,
78- ) ;
79-
80- return Promise . all ( promises ) ;
81- } ;
82-
83182export default fetchAllData ;
0 commit comments