From b665678dbb32bdea75dba058fb7ff8b1c800a3d1 Mon Sep 17 00:00:00 2001 From: k4rli Date: Mon, 4 Aug 2025 11:51:49 +0300 Subject: [PATCH] feat(MED-131): display analyses options and add to cart --- .../(dashboard)/order-analysis/page.tsx | 5 ++ .../_components/order-analyses-cards.tsx | 76 +++++++++++++++++++ app/home/(user)/_lib/server/load-analyses.ts | 41 ++++++++++ .../src/lib/data/categories.ts | 24 ++++-- .../src/lib/data/products.ts | 2 +- 5 files changed, 142 insertions(+), 6 deletions(-) create mode 100644 app/home/(user)/_components/order-analyses-cards.tsx create mode 100644 app/home/(user)/_lib/server/load-analyses.ts diff --git a/app/home/(user)/(dashboard)/order-analysis/page.tsx b/app/home/(user)/(dashboard)/order-analysis/page.tsx index e8d28ad..942f78e 100644 --- a/app/home/(user)/(dashboard)/order-analysis/page.tsx +++ b/app/home/(user)/(dashboard)/order-analysis/page.tsx @@ -3,6 +3,8 @@ import { withI18n } from '~/lib/i18n/with-i18n'; import { PageBody } from '@kit/ui/page'; import { Trans } from '@kit/ui/trans'; import { HomeLayoutPageHeader } from '../../_components/home-page-header'; +import { loadAnalyses } from '../../_lib/server/load-analyses'; +import OrderAnalysesCards from '../../_components/order-analyses-cards'; export const generateMetadata = async () => { const { t } = await createI18nServerInstance(); @@ -13,6 +15,8 @@ export const generateMetadata = async () => { }; async function OrderAnalysisPage() { + const { analyses, countryCode } = await loadAnalyses(); + return ( <> } /> + ); diff --git a/app/home/(user)/_components/order-analyses-cards.tsx b/app/home/(user)/_components/order-analyses-cards.tsx new file mode 100644 index 0000000..bc4a690 --- /dev/null +++ b/app/home/(user)/_components/order-analyses-cards.tsx @@ -0,0 +1,76 @@ +"use client"; + +import { HeartPulse, ShoppingCart } from 'lucide-react'; + +import { Button } from '@kit/ui/button'; +import { + Card, + CardHeader, + CardFooter, +} from '@kit/ui/card'; +import { StoreProduct, StoreProductVariant } from '@medusajs/types'; +import { useState } from 'react'; +import { handleAddToCart } from '~/lib/services/medusaCart.service'; +import { useRouter } from 'next/navigation'; + +export default function OrderAnalysesCards({ + analyses, + countryCode, +}: { + analyses: StoreProduct[]; + countryCode: string; +}) { + const router = useRouter(); + + const [isAddingToCart, setIsAddingToCart] = useState(false); + const handleSelect = async (selectedVariant: StoreProductVariant) => { + if (!selectedVariant?.id) return null + + setIsAddingToCart(true); + await handleAddToCart({ + selectedVariant, + countryCode, + }); + setIsAddingToCart(false); + router.push('/home/cart'); + } + + return ( +
+ {analyses.map(({ + title, + variants + }) => ( + + +
+ +
+
+ +
+ +
+
+ {title} +
+
+
+ ))} +
+ ); +} diff --git a/app/home/(user)/_lib/server/load-analyses.ts b/app/home/(user)/_lib/server/load-analyses.ts new file mode 100644 index 0000000..d6bc2e2 --- /dev/null +++ b/app/home/(user)/_lib/server/load-analyses.ts @@ -0,0 +1,41 @@ +import { cache } from 'react'; + +import { listProductTypes } from "@lib/data/products"; +import { listRegions } from '@lib/data/regions'; +import { getProductCategories } from '@lib/data/categories'; + +async function countryCodesLoader() { + const countryCodes = await listRegions().then((regions) => + regions?.map((r) => r.countries?.map((c) => c.iso_2)).flat(), + ); + return countryCodes ?? []; +} +export const loadCountryCodes = cache(countryCodesLoader); + +async function productCategoriesLoader() { + const productCategories = await getProductCategories({ fields: "*products, *products.variants" }); + return productCategories.product_categories ?? []; +} +export const loadProductCategories = cache(productCategoriesLoader); + +async function productTypesLoader() { + const { productTypes } = await listProductTypes(); + return productTypes ?? []; +} +export const loadProductTypes = cache(productTypesLoader); + +async function analysesLoader() { + const [countryCodes, productCategories] = await Promise.all([ + loadCountryCodes(), + loadProductCategories(), + ]); + const countryCode = countryCodes[0]!; + + const category = productCategories.find(({ metadata }) => metadata?.page === 'order-analysis'); + + return { + analyses: category?.products ?? [], + countryCode, + } +} +export const loadAnalyses = cache(analysesLoader); diff --git a/packages/features/medusa-storefront/src/lib/data/categories.ts b/packages/features/medusa-storefront/src/lib/data/categories.ts index f847745..7b3987d 100644 --- a/packages/features/medusa-storefront/src/lib/data/categories.ts +++ b/packages/features/medusa-storefront/src/lib/data/categories.ts @@ -27,8 +27,22 @@ export const listCategories = async (query?: Record) => { } export const getCategoryByHandle = async (categoryHandle: string[]) => { - const handle = `${categoryHandle.join("/")}` + const { product_categories } = await getProductCategories({ + handle: `${categoryHandle.join("/")}`, + limit: 1, + }); + return product_categories[0]; +} +export const getProductCategories = async ({ + handle, + limit, + fields = "*category_children, *products", +}: { + handle?: string; + limit?: number; + fields?: string; +} = {}) => { const next = { ...(await getCacheOptions("categories")), } @@ -38,12 +52,12 @@ export const getCategoryByHandle = async (categoryHandle: string[]) => { `/store/product-categories`, { query: { - fields: "*category_children, *products", + fields, handle, + limit, }, next, - cache: "force-cache", + //cache: "force-cache", } - ) - .then(({ product_categories }) => product_categories[0]) + ); } diff --git a/packages/features/medusa-storefront/src/lib/data/products.ts b/packages/features/medusa-storefront/src/lib/data/products.ts index 2548058..3608d2d 100644 --- a/packages/features/medusa-storefront/src/lib/data/products.ts +++ b/packages/features/medusa-storefront/src/lib/data/products.ts @@ -159,7 +159,7 @@ export const listProductTypes = async (): Promise<{ productTypes: HttpTypes.Stor "/store/product-types", { next, - cache: "force-cache", + //cache: "force-cache", query: { fields: "id,value,metadata", },