@@ -5,46 +5,65 @@ import axiosInstance from './axiosInstance.js';
55 * @param {Object } apiProduct - The product object from the API.
66 * @returns {Object } Transformed product object.
77 */
8- const transformProduct = ( apiProduct ) => {
9- const originalPrice = apiProduct . sale > 0
10- ? Number ( ( apiProduct . price / ( 1 - apiProduct . sale / 100 ) ) . toFixed ( 2 ) )
11- : null ;
8+ const transformProduct = ( apiProduct = { } ) => {
9+ if ( ! apiProduct || typeof apiProduct !== 'object' ) return null ;
10+
11+ const price = Number ( apiProduct . price ?? 0 ) ;
12+ const sale = Number ( apiProduct . sale ?? 0 ) ;
13+ const originalPrice = sale > 0 ? Number ( ( price / ( 1 - sale / 100 ) ) . toFixed ( 2 ) ) : null ;
1214
1315 return {
14- id : apiProduct . _id ,
15- name : apiProduct . name ,
16- description : apiProduct . description || apiProduct . shortDescription ,
17- price : apiProduct . price ,
18- originalPrice : originalPrice ,
19- category : apiProduct . category ,
20- imageUrl : apiProduct . image ,
21- rating : apiProduct . rating ,
22- reviewCount : apiProduct . reviewsCount ,
23- stock : 15 , // Consider fetching stock from the API if available
24- isNew : apiProduct . new ,
25- onSale : apiProduct . sale > 0 ,
26- flavors : apiProduct . flavors || [ ] ,
27- features : apiProduct . quality || [ ] ,
28- goals : apiProduct . goals || [ ] ,
29- sizes : apiProduct . sizes || [ ] ,
30- salePercentage : apiProduct . sale ,
31- longDescription : apiProduct . longDescription ,
32- usageTips : apiProduct . usageTips || [ ]
16+ id : apiProduct . _id ?? apiProduct . id ?? null ,
17+ name : apiProduct . name ?? apiProduct . title ?? 'Unnamed Product' ,
18+ description : apiProduct . description ?? apiProduct . shortDescription ?? '' ,
19+ shortDescription : apiProduct . shortDescription ?? apiProduct . description ?? '' ,
20+ longDescription : apiProduct . longDescription ?? '' ,
21+ price,
22+ originalPrice,
23+ category : apiProduct . category ?? null ,
24+ imageUrl : apiProduct . image ?? apiProduct . imageUrl ?? '/images/product-default-image.jpg' ,
25+ imageGallery : Array . isArray ( apiProduct . images ) ? apiProduct . images : Array . isArray ( apiProduct . gallery ) ? apiProduct . gallery : [ ] ,
26+ rating : Number ( apiProduct . rating ?? 0 ) ,
27+ reviewCount : Number ( apiProduct . reviewsCount ?? apiProduct . reviewCount ?? 0 ) ,
28+ stock : Number ( apiProduct . stock ?? apiProduct . inventory ?? 0 ) ,
29+ isNew : Boolean ( apiProduct . new ) ,
30+ onSale : sale > 0 ,
31+ salePercentage : sale ,
32+ flavors : Array . isArray ( apiProduct . flavors ) ? apiProduct . flavors : [ ] ,
33+ sizes : Array . isArray ( apiProduct . sizes ) ? apiProduct . sizes : [ ] ,
34+ quality : Array . isArray ( apiProduct . quality ) ? apiProduct . quality : [ ] ,
35+ goals : Array . isArray ( apiProduct . goals ) ? apiProduct . goals : [ ] ,
36+ collections : Array . isArray ( apiProduct . collections ) ? apiProduct . collections : [ ] ,
37+ usageTips : typeof apiProduct . usageTips === 'object' ? apiProduct . usageTips : { } ,
38+ createdAt : apiProduct . createdAt ? new Date ( apiProduct . createdAt ) . toISOString ( ) : null ,
39+ updatedAt : apiProduct . updatedAt ? new Date ( apiProduct . updatedAt ) . toISOString ( ) : null ,
40+ raw : apiProduct , // keep original object for debugging if needed
3341 } ;
3442} ;
3543
3644/**
3745 * Transforms the API response containing multiple products.
46+ * Accepts several shapes returned by different backends.
3847 * @param {Object } apiResponse - The response object from the API.
3948 * @returns {Object } Transformed response object.
4049 */
41- const transformApiResponse = ( apiResponse ) => {
50+ const transformApiResponse = ( apiResponse = { } ) => {
51+ // apiResponse may be { products: [...], total, page, pages } or { data: { products: [...] } }
52+ const payload = apiResponse . products ?? apiResponse . data ?. products ?? apiResponse . data ?? apiResponse ;
53+ const productsArray = Array . isArray ( payload ) ? payload : Array . isArray ( payload . products ) ? payload . products : [ ] ;
54+
55+ const mapped = productsArray . map ( transformProduct ) . filter ( Boolean ) ;
56+
57+ const total = Number ( apiResponse . total ?? apiResponse . data ?. total ?? payload . total ?? mapped . length ) ;
58+ const page = Number ( apiResponse . page ?? apiResponse . data ?. page ?? payload . page ?? 1 ) ;
59+ const pages = Number ( apiResponse . pages ?? apiResponse . data ?. pages ?? payload . pages ?? 1 ) ;
60+
4261 return {
43- products : apiResponse . products . map ( transformProduct ) ,
44- totalCount : apiResponse . total ,
45- currentPage : apiResponse . page ,
46- hasNextPage : apiResponse . page < apiResponse . pages ,
47- totalPages : apiResponse . pages
62+ products : mapped ,
63+ totalCount : total ,
64+ currentPage : page ,
65+ hasNextPage : page < pages ,
66+ totalPages : pages ,
4867 } ;
4968} ;
5069
@@ -73,20 +92,39 @@ export const getProducts = async (params = {}) => {
7392
7493 const data = response . data ;
7594
95+ // support multiple payload shapes
96+ if ( Array . isArray ( data ) ) {
97+ return {
98+ success : true ,
99+ data : {
100+ products : data . map ( transformProduct ) . filter ( Boolean ) ,
101+ total : data . length ,
102+ page : 1 ,
103+ pages : 1 ,
104+ } ,
105+ status : response . status ,
106+ } ;
107+ }
108+
109+ // If API returns wrapper like { products: [...], total, page, pages }
110+ if ( data . products || data . data ?. products ) {
111+ return {
112+ success : true ,
113+ data : transformApiResponse ( data ) ,
114+ status : response . status ,
115+ } ;
116+ }
117+
118+ // If API returns nested data or other shapes, attempt to transform generically
76119 return {
77120 success : true ,
78- data : Array . isArray ( data ) ? {
79- products : data ,
80- total : data . length ,
81- page : 1 ,
82- pages : 1 ,
83- } : transformApiResponse ( data ) ,
121+ data : transformApiResponse ( data ) ,
84122 status : response . status ,
85123 } ;
86124 } catch ( error ) {
87125 return {
88126 success : false ,
89- error : error . response ?. data ?. message || 'Failed to fetch products' ,
127+ error : error . response ?. data ?. message || error . message || 'Failed to fetch products' ,
90128 status : error . response ?. status || 500 ,
91129 } ;
92130 }
@@ -104,16 +142,20 @@ export const getProductById = async (id) => {
104142 }
105143
106144 const response = await axiosInstance . get ( `/products/${ id } ` ) ;
145+ const data = response . data ;
146+
147+ // Accept shapes: { ...product }, { product: {...} }, { data: { product: {...} } }
148+ const productPayload = data . product ?? data . data ?. product ?? data . data ?? data ;
107149
108150 return {
109151 success : true ,
110- data : transformProduct ( response . data ) ,
152+ data : transformProduct ( productPayload ) ,
111153 status : response . status ,
112154 } ;
113155 } catch ( error ) {
114156 return {
115157 success : false ,
116- error : error . response ?. data ?. message || 'Failed to fetch product' ,
158+ error : error . response ?. data ?. message || error . message || 'Failed to fetch product' ,
117159 status : error . response ?. status || 500 ,
118160 } ;
119161 }
@@ -134,15 +176,30 @@ export const searchProducts = async (query, params = {}) => {
134176 } ,
135177 } ) ;
136178
179+ const data = response . data ;
180+
181+ if ( Array . isArray ( data ) ) {
182+ return {
183+ success : true ,
184+ data : {
185+ products : data . map ( transformProduct ) . filter ( Boolean ) ,
186+ total : data . length ,
187+ page : 1 ,
188+ pages : 1 ,
189+ } ,
190+ status : response . status ,
191+ } ;
192+ }
193+
137194 return {
138195 success : true ,
139- data : response . data ,
196+ data : transformApiResponse ( data ) ,
140197 status : response . status ,
141198 } ;
142199 } catch ( error ) {
143200 return {
144201 success : false ,
145- error : error . response ?. data ?. message || 'Failed to search products' ,
202+ error : error . response ?. data ?. message || error . message || 'Failed to search products' ,
146203 status : error . response ?. status || 500 ,
147204 } ;
148205 }
@@ -164,7 +221,7 @@ export const getProductCategories = async () => {
164221 } catch ( error ) {
165222 return {
166223 success : false ,
167- error : error . response ?. data ?. message || 'Failed to fetch categories' ,
224+ error : error . response ?. data ?. message || error . message || 'Failed to fetch categories' ,
168225 status : error . response ?. status || 500 ,
169226 } ;
170227 }
@@ -182,19 +239,25 @@ export const getRecommendedProducts = async (id, limit = 3) => {
182239 throw new Error ( 'Product ID is required' ) ;
183240 }
184241
185- // const response = await axiosInstance.get(`/products/recommended/${id}?limit=${limit}`);
186242 const response = await axiosInstance . get ( `/products/${ id } /recommended?limit=${ limit } ` ) ;
243+ const data = response . data ;
187244
245+ // data may be { products: [...] } or an array
246+ const productsArray = Array . isArray ( data )
247+ ? data
248+ : Array . isArray ( data . products )
249+ ? data . products
250+ : data . data ?. products ?? [ ] ;
188251
189252 return {
190253 success : true ,
191- data : response . data . products . map ( transformProduct ) ,
254+ data : productsArray . map ( transformProduct ) . filter ( Boolean ) ,
192255 status : response . status ,
193256 } ;
194257 } catch ( error ) {
195258 return {
196259 success : false ,
197- error : error . response ?. data ?. message || 'Failed to fetch recommended products' ,
260+ error : error . response ?. data ?. message || error . message || 'Failed to fetch recommended products' ,
198261 status : error . response ?. status || 500 ,
199262 } ;
200263 }
0 commit comments