/ src / lib / data / products.ts
products.ts
  1  "use server"
  2  
  3  import { sdk } from "@lib/config"
  4  import { sortProducts } from "@lib/util/sort-products"
  5  import { HttpTypes } from "@medusajs/types"
  6  import { SortOptions } from "@modules/store/components/refinement-list/sort-products"
  7  import { getAuthHeaders, getCacheOptions } from "./cookies"
  8  import { getRegion, retrieveRegion } from "./regions"
  9  
 10  export const listProducts = async ({
 11    pageParam = 1,
 12    queryParams,
 13    countryCode,
 14    regionId,
 15  }: {
 16    pageParam?: number
 17    queryParams?: HttpTypes.FindParams & HttpTypes.StoreProductParams
 18    countryCode?: string
 19    regionId?: string
 20  }): Promise<{
 21    response: { products: HttpTypes.StoreProduct[]; count: number }
 22    nextPage: number | null
 23    queryParams?: HttpTypes.FindParams & HttpTypes.StoreProductParams
 24  }> => {
 25    if (!countryCode && !regionId) {
 26      throw new Error("Country code or region ID is required")
 27    }
 28  
 29    const limit = queryParams?.limit || 12
 30    const _pageParam = Math.max(pageParam, 1)
 31    const offset = (_pageParam === 1) ? 0 : (_pageParam - 1) * limit;
 32  
 33    let region: HttpTypes.StoreRegion | undefined | null
 34  
 35    if (countryCode) {
 36      region = await getRegion(countryCode)
 37    } else {
 38      region = await retrieveRegion(regionId!)
 39    }
 40  
 41    if (!region) {
 42      return {
 43        response: { products: [], count: 0 },
 44        nextPage: null,
 45      }
 46    }
 47  
 48    const headers = {
 49      ...(await getAuthHeaders()),
 50    }
 51  
 52    const next = {
 53      ...(await getCacheOptions("products")),
 54    }
 55  
 56    return sdk.client
 57      .fetch<{ products: HttpTypes.StoreProduct[]; count: number }>(
 58        `/store/products`,
 59        {
 60          method: "GET",
 61          query: {
 62            limit,
 63            offset,
 64            region_id: region?.id,
 65            fields:
 66              "*variants.calculated_price,+variants.inventory_quantity,+metadata,+tags",
 67            ...queryParams,
 68          },
 69          headers,
 70          next,
 71          cache: "force-cache",
 72        }
 73      )
 74      .then(({ products, count }) => {
 75        const nextPage = count > offset + limit ? pageParam + 1 : null
 76  
 77        return {
 78          response: {
 79            products,
 80            count,
 81          },
 82          nextPage: nextPage,
 83          queryParams,
 84        }
 85      })
 86  }
 87  
 88  /**
 89   * This will fetch 100 products to the Next.js cache and sort them based on the sortBy parameter.
 90   * It will then return the paginated products based on the page and limit parameters.
 91   */
 92  export const listProductsWithSort = async ({
 93    page = 0,
 94    queryParams,
 95    sortBy = "created_at",
 96    countryCode,
 97  }: {
 98    page?: number
 99    queryParams?: HttpTypes.FindParams & HttpTypes.StoreProductParams
100    sortBy?: SortOptions
101    countryCode: string
102  }): Promise<{
103    response: { products: HttpTypes.StoreProduct[]; count: number }
104    nextPage: number | null
105    queryParams?: HttpTypes.FindParams & HttpTypes.StoreProductParams
106  }> => {
107    const limit = queryParams?.limit || 12
108  
109    const {
110      response: { products, count },
111    } = await listProducts({
112      pageParam: 0,
113      queryParams: {
114        ...queryParams,
115        limit: 100,
116      },
117      countryCode,
118    })
119  
120    const sortedProducts = sortProducts(products, sortBy)
121  
122    const pageParam = (page - 1) * limit
123  
124    const nextPage = count > pageParam + limit ? pageParam + limit : null
125  
126    const paginatedProducts = sortedProducts.slice(pageParam, pageParam + limit)
127  
128    return {
129      response: {
130        products: paginatedProducts,
131        count,
132      },
133      nextPage,
134      queryParams,
135    }
136  }