feat(MED-131): display analyses options and add to cart

This commit is contained in:
2025-08-04 11:51:49 +03:00
parent 8c4df731aa
commit b665678dbb
5 changed files with 142 additions and 6 deletions

View File

@@ -3,6 +3,8 @@ import { withI18n } from '~/lib/i18n/with-i18n';
import { PageBody } from '@kit/ui/page'; import { PageBody } from '@kit/ui/page';
import { Trans } from '@kit/ui/trans'; import { Trans } from '@kit/ui/trans';
import { HomeLayoutPageHeader } from '../../_components/home-page-header'; 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 () => { export const generateMetadata = async () => {
const { t } = await createI18nServerInstance(); const { t } = await createI18nServerInstance();
@@ -13,6 +15,8 @@ export const generateMetadata = async () => {
}; };
async function OrderAnalysisPage() { async function OrderAnalysisPage() {
const { analyses, countryCode } = await loadAnalyses();
return ( return (
<> <>
<HomeLayoutPageHeader <HomeLayoutPageHeader
@@ -20,6 +24,7 @@ async function OrderAnalysisPage() {
description={<Trans i18nKey={'order-analysis:description'} />} description={<Trans i18nKey={'order-analysis:description'} />}
/> />
<PageBody> <PageBody>
<OrderAnalysesCards analyses={analyses} countryCode={countryCode} />
</PageBody> </PageBody>
</> </>
); );

View File

@@ -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 (
<div className="grid grid-cols-3 gap-6 mt-4">
{analyses.map(({
title,
variants
}) => (
<Card
key={title}
variant="gradient-success"
className="flex flex-col justify-between"
>
<CardHeader className="items-end-safe">
<div className='flex size-8 items-center-safe justify-center-safe rounded-full text-white bg-warning'>
<Button
size="icon"
variant="outline"
className="px-2 text-black"
onClick={() => handleSelect(variants![0]!)}
disabled={isAddingToCart}
>
<ShoppingCart className="size-4 stroke-2" />
</Button>
</div>
</CardHeader>
<CardFooter className="flex flex-col items-start gap-2">
<div
className={'flex size-8 items-center-safe justify-center-safe rounded-full text-white bg-primary\/10 mb-6'}
>
<HeartPulse className="size-4 fill-green-500" />
</div>
<h5>
{title}
</h5>
</CardFooter>
</Card>
))}
</div>
);
}

View File

@@ -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);

View File

@@ -27,8 +27,22 @@ export const listCategories = async (query?: Record<string, any>) => {
} }
export const getCategoryByHandle = async (categoryHandle: string[]) => { 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 = { const next = {
...(await getCacheOptions("categories")), ...(await getCacheOptions("categories")),
} }
@@ -38,12 +52,12 @@ export const getCategoryByHandle = async (categoryHandle: string[]) => {
`/store/product-categories`, `/store/product-categories`,
{ {
query: { query: {
fields: "*category_children, *products", fields,
handle, handle,
limit,
}, },
next, next,
cache: "force-cache", //cache: "force-cache",
} }
) );
.then(({ product_categories }) => product_categories[0])
} }

View File

@@ -159,7 +159,7 @@ export const listProductTypes = async (): Promise<{ productTypes: HttpTypes.Stor
"/store/product-types", "/store/product-types",
{ {
next, next,
cache: "force-cache", //cache: "force-cache",
query: { query: {
fields: "id,value,metadata", fields: "id,value,metadata",
}, },