136 lines
4.1 KiB
TypeScript
136 lines
4.1 KiB
TypeScript
"use client";
|
|
|
|
import { HeartPulse, Loader2, ShoppingCart } from 'lucide-react';
|
|
import { useTranslation } from 'react-i18next';
|
|
|
|
import { Button } from '@kit/ui/button';
|
|
import {
|
|
Card,
|
|
CardHeader,
|
|
CardFooter,
|
|
CardDescription,
|
|
} from '@kit/ui/card';
|
|
import { StoreProduct } from '@medusajs/types';
|
|
import { useState } from 'react';
|
|
import { handleAddToCart } from '~/lib/services/medusaCart.service';
|
|
import { InfoTooltip } from '@kit/shared/components/ui/info-tooltip';
|
|
import { Trans } from '@kit/ui/trans';
|
|
import { toast } from '@kit/ui/sonner';
|
|
import { formatCurrency } from '@/packages/shared/src/utils';
|
|
|
|
export type OrderAnalysisCard = Pick<
|
|
StoreProduct, 'title' | 'description' | 'subtitle'
|
|
> & {
|
|
isAvailable: boolean;
|
|
variant: { id: string };
|
|
price: number | null;
|
|
};
|
|
|
|
export default function OrderAnalysesCards({
|
|
analyses,
|
|
countryCode,
|
|
}: {
|
|
analyses: OrderAnalysisCard[];
|
|
countryCode: string;
|
|
}) {
|
|
|
|
const { i18n: { language } } = useTranslation()
|
|
|
|
const [variantAddingToCart, setVariantAddingToCart] = useState<string | null>(null);
|
|
const handleSelect = async (variantId: string) => {
|
|
if (variantAddingToCart) {
|
|
return null;
|
|
}
|
|
|
|
setVariantAddingToCart(variantId);
|
|
try {
|
|
await handleAddToCart({
|
|
selectedVariant: { id: variantId },
|
|
countryCode,
|
|
});
|
|
toast.success(<Trans i18nKey={'order-analysis:analysisAddedToCart'} />);
|
|
setVariantAddingToCart(null);
|
|
} catch (e) {
|
|
toast.error(<Trans i18nKey={'order-analysis:analysisAddToCartError'} />);
|
|
setVariantAddingToCart(null);
|
|
console.error(e);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="grid 2xs:grid-cols-3 gap-6 mt-4">
|
|
{analyses.map(({
|
|
title,
|
|
variant,
|
|
description,
|
|
subtitle,
|
|
isAvailable,
|
|
price,
|
|
}) => {
|
|
const formattedPrice = typeof price === 'number'
|
|
? formatCurrency({
|
|
currencyCode: 'eur',
|
|
locale: language,
|
|
value: price,
|
|
})
|
|
: null;
|
|
return (
|
|
<Card
|
|
key={title}
|
|
variant={isAvailable ? "gradient-success" : "gradient-warning"}
|
|
className="flex flex-col justify-between"
|
|
>
|
|
<CardHeader className="flex-row">
|
|
<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>
|
|
{isAvailable && (
|
|
<div className='ml-auto 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(variant.id)}
|
|
>
|
|
{variantAddingToCart ? <Loader2 className="size-4 stroke-2 animate-spin" /> : <ShoppingCart className="size-4 stroke-2" />}
|
|
</Button>
|
|
</div>
|
|
)}
|
|
</CardHeader>
|
|
<CardFooter className="flex flex-col items-start gap-2">
|
|
<h5>
|
|
{title}
|
|
{description && (
|
|
<>
|
|
{' '}
|
|
<InfoTooltip
|
|
content={
|
|
<div className='flex flex-col gap-2'>
|
|
<span>{formattedPrice}</span>
|
|
<span>{description}</span>
|
|
</div>
|
|
}
|
|
/>
|
|
</>
|
|
)}
|
|
</h5>
|
|
{isAvailable && subtitle && (
|
|
<CardDescription>
|
|
{subtitle}
|
|
</CardDescription>
|
|
)}
|
|
{!isAvailable && (
|
|
<CardDescription>
|
|
<Trans i18nKey={'order-analysis:analysisNotAvailable'} />
|
|
</CardDescription>
|
|
)}
|
|
</CardFooter>
|
|
</Card>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
}
|