121 lines
3.6 KiB
TypeScript
121 lines
3.6 KiB
TypeScript
'use client';
|
|
|
|
import { useState } from 'react';
|
|
|
|
import { formatCurrency } from '@/packages/shared/src/utils';
|
|
import { StoreProduct } from '@medusajs/types';
|
|
import { HeartPulse, Loader2, ShoppingCart } from 'lucide-react';
|
|
import { useTranslation } from 'react-i18next';
|
|
|
|
import { InfoTooltip } from '@kit/shared/components/ui/info-tooltip';
|
|
import { Button } from '@kit/ui/button';
|
|
import { Card, CardDescription, CardFooter, CardHeader } from '@kit/ui/card';
|
|
import { toast } from '@kit/ui/sonner';
|
|
import { Trans } from '@kit/ui/trans';
|
|
|
|
import { handleAddToCart } from '~/lib/services/medusaCart.service';
|
|
|
|
export type OrderAnalysisCard = Pick<
|
|
StoreProduct,
|
|
'title' | 'description' | 'subtitle'
|
|
> & {
|
|
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 analyses.map(({ title, variant, description, subtitle, price }) => {
|
|
const formattedPrice =
|
|
typeof price === 'number'
|
|
? formatCurrency({
|
|
currencyCode: 'eur',
|
|
locale: language,
|
|
value: price,
|
|
})
|
|
: null;
|
|
return (
|
|
<Card
|
|
key={title}
|
|
variant="gradient-success"
|
|
className="flex flex-col justify-between"
|
|
>
|
|
<CardHeader className="flex-row">
|
|
<div className="bg-primary/10 mb-6 flex size-8 items-center-safe justify-center-safe rounded-full text-white">
|
|
<HeartPulse className="size-4 fill-green-500" />
|
|
</div>
|
|
<div className="bg-warning ml-auto flex size-8 items-center-safe justify-center-safe rounded-full text-white">
|
|
<Button
|
|
size="icon"
|
|
variant="outline"
|
|
className="px-2 text-black"
|
|
onClick={() => handleSelect(variant.id)}
|
|
>
|
|
{variantAddingToCart === variant.id ? (
|
|
<Loader2 className="size-4 animate-spin stroke-2" />
|
|
) : (
|
|
<ShoppingCart className="size-4 stroke-2" />
|
|
)}
|
|
</Button>
|
|
</div>
|
|
</CardHeader>
|
|
<CardFooter className="flex gap-2">
|
|
<div className="flex flex-1 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>
|
|
{subtitle && <CardDescription>{subtitle}</CardDescription>}
|
|
</div>
|
|
<div className="flex flex-col items-end gap-2 self-end text-sm">
|
|
<span>{formattedPrice}</span>
|
|
</div>
|
|
</CardFooter>
|
|
</Card>
|
|
);
|
|
});
|
|
}
|