@@ -4,12 +4,17 @@ import type { HttpTypes } from "@medusajs/types";
44import type {
55 CatalogFacets ,
66 CatalogListResponse ,
7+ UseCatalogProductsResult ,
78} from "@techsio/storefront-data/catalog/types" ;
9+ import { useMemo } from "react" ;
810import {
911 PLP_PAGE_SIZE ,
1012 type CatalogProductsParams ,
1113 type CatalogQueryState ,
1214} from "./catalog-query-state" ;
15+ import { resolveVariantInventoryState } from "./product-availability" ;
16+ import { STOREFRONT_PRODUCT_CARD_FIELDS } from "./product-query-config" ;
17+ import { useProducts } from "./products" ;
1318import { storefront } from "./storefront" ;
1419
1520export type CatalogProductsInput = CatalogProductsParams & {
@@ -25,7 +30,117 @@ export type CatalogProductsResponse = CatalogListResponse<
2530const catalogService = storefront . services . catalog ;
2631const catalogHooks = storefront . hooks . catalog ;
2732
28- export const useCatalogProducts = catalogHooks . useCatalogProducts ;
33+ type UseCatalogProductsOptions = Parameters <
34+ typeof catalogHooks . useCatalogProducts
35+ > [ 1 ] ;
36+
37+ const productNeedsInventorySnapshot = ( product : HttpTypes . StoreProduct ) =>
38+ ( product . variants ?? [ ] ) . some (
39+ ( variant ) =>
40+ Boolean ( variant . id ) &&
41+ ! resolveVariantInventoryState ( variant ) . isInventoryKnown ,
42+ ) ;
43+
44+ const resolveInventorySnapshotHandles = ( products : HttpTypes . StoreProduct [ ] ) => {
45+ const handles = new Set < string > ( ) ;
46+
47+ for ( const product of products ) {
48+ if ( product . handle && productNeedsInventorySnapshot ( product ) ) {
49+ handles . add ( product . handle ) ;
50+ }
51+ }
52+
53+ return Array . from ( handles ) ;
54+ } ;
55+
56+ const mergeProductInventorySnapshot = (
57+ product : HttpTypes . StoreProduct ,
58+ inventoryProduct ?: HttpTypes . StoreProduct ,
59+ ) : HttpTypes . StoreProduct => {
60+ if ( ! inventoryProduct ?. variants ?. length ) {
61+ return product ;
62+ }
63+
64+ const inventoryVariantById = new Map (
65+ inventoryProduct . variants . map ( ( variant ) => [ variant . id , variant ] ) ,
66+ ) ;
67+
68+ return {
69+ ...product ,
70+ variants :
71+ product . variants ?. map ( ( variant ) => {
72+ const inventoryVariant = inventoryVariantById . get ( variant . id ) ;
73+
74+ return inventoryVariant
75+ ? {
76+ ...variant ,
77+ allow_backorder : inventoryVariant . allow_backorder ,
78+ inventory_quantity : inventoryVariant . inventory_quantity ,
79+ manage_inventory : inventoryVariant . manage_inventory ,
80+ }
81+ : variant ;
82+ } ) ?? product . variants ,
83+ } ;
84+ } ;
85+
86+ export const useCatalogProducts = (
87+ input : CatalogProductsInput ,
88+ options ?: UseCatalogProductsOptions ,
89+ ) : UseCatalogProductsResult < HttpTypes . StoreProduct , CatalogFacets > => {
90+ const catalogQuery = catalogHooks . useCatalogProducts ( input , options ) ;
91+ const inventorySnapshotHandles = useMemo (
92+ ( ) => resolveInventorySnapshotHandles ( catalogQuery . products ) ,
93+ [ catalogQuery . products ] ,
94+ ) ;
95+ const shouldLoadInventorySnapshots = inventorySnapshotHandles . length > 0 ;
96+ const inventorySnapshotsQuery = useProducts ( {
97+ handle : inventorySnapshotHandles ,
98+ limit : Math . max ( 1 , inventorySnapshotHandles . length ) ,
99+ fields : STOREFRONT_PRODUCT_CARD_FIELDS ,
100+ enabled : catalogQuery . isSuccess && shouldLoadInventorySnapshots ,
101+ } ) ;
102+ const inventoryProductByHandle = useMemo (
103+ ( ) =>
104+ new Map (
105+ inventorySnapshotsQuery . products
106+ . filter ( ( product ) => product . handle )
107+ . map ( ( product ) => [ product . handle , product ] ) ,
108+ ) ,
109+ [ inventorySnapshotsQuery . products ] ,
110+ ) ;
111+ const products = useMemo ( ( ) => {
112+ if ( shouldLoadInventorySnapshots && inventorySnapshotsQuery . isLoading ) {
113+ return [ ] ;
114+ }
115+
116+ return catalogQuery . products . map ( ( product ) =>
117+ mergeProductInventorySnapshot (
118+ product ,
119+ product . handle
120+ ? inventoryProductByHandle . get ( product . handle )
121+ : undefined ,
122+ ) ,
123+ ) ;
124+ } , [
125+ catalogQuery . products ,
126+ inventoryProductByHandle ,
127+ inventorySnapshotsQuery . isLoading ,
128+ shouldLoadInventorySnapshots ,
129+ ] ) ;
130+
131+ return {
132+ ...catalogQuery ,
133+ products,
134+ isLoading :
135+ catalogQuery . isLoading ||
136+ ( shouldLoadInventorySnapshots && inventorySnapshotsQuery . isLoading ) ,
137+ isFetching :
138+ catalogQuery . isFetching ||
139+ ( shouldLoadInventorySnapshots && inventorySnapshotsQuery . isFetching ) ,
140+ error : catalogQuery . error ?? inventorySnapshotsQuery . error ,
141+ } ;
142+ } ;
143+
29144export const useSuspenseCatalogProducts = catalogHooks . useSuspenseCatalogProducts ;
30145export const usePrefetchCatalogProducts = catalogHooks . usePrefetchCatalogProducts ;
31146export const prefetchCatalogProducts = catalogHooks . prefetchCatalogProducts ;
0 commit comments