190 lines
6.0 KiB
TypeScript
190 lines
6.0 KiB
TypeScript
'use client';
|
|
|
|
import { useState } from 'react';
|
|
|
|
import { handleNavigateToPayment } from '@/lib/services/medusaCart.service';
|
|
import { formatCurrency } from '@/packages/shared/src/utils';
|
|
import { initiatePaymentSession } from '@lib/data/cart';
|
|
import { StoreCart, StoreCartLineItem } from '@medusajs/types';
|
|
import { Loader2 } from 'lucide-react';
|
|
import { useTranslation } from 'react-i18next';
|
|
|
|
import { Button } from '@kit/ui/button';
|
|
import { Card, CardContent, CardHeader } from '@kit/ui/card';
|
|
import { Trans } from '@kit/ui/trans';
|
|
|
|
import AnalysisLocation from './analysis-location';
|
|
import CartItems from './cart-items';
|
|
import DiscountCode from './discount-code';
|
|
|
|
const IS_DISCOUNT_SHOWN = true as boolean;
|
|
|
|
export default function Cart({
|
|
cart,
|
|
synlabAnalyses,
|
|
ttoServiceItems,
|
|
}: {
|
|
cart: StoreCart | null;
|
|
synlabAnalyses: StoreCartLineItem[];
|
|
ttoServiceItems: StoreCartLineItem[];
|
|
}) {
|
|
const {
|
|
i18n: { language },
|
|
} = useTranslation();
|
|
|
|
const [isInitiatingSession, setIsInitiatingSession] = useState(false);
|
|
|
|
const items = cart?.items ?? [];
|
|
|
|
if (!cart || items.length === 0) {
|
|
return (
|
|
<div className="content-container py-5 lg:px-4">
|
|
<div>
|
|
<div
|
|
className="flex flex-col items-center justify-center"
|
|
data-testid="empty-cart-message"
|
|
>
|
|
<h4 className="text-center">
|
|
<Trans i18nKey="cart:emptyCartMessage" />
|
|
</h4>
|
|
<p className="text-center">
|
|
<Trans i18nKey="cart:emptyCartMessageDescription" />
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
async function initiatePayment() {
|
|
setIsInitiatingSession(true);
|
|
const response = await initiatePaymentSession(cart!, {
|
|
provider_id: 'pp_montonio_montonio',
|
|
});
|
|
if (response.payment_collection) {
|
|
const { payment_sessions } = response.payment_collection;
|
|
const paymentSessionId = payment_sessions![0]!.id;
|
|
const url = await handleNavigateToPayment({ language, paymentSessionId });
|
|
window.location.href = url;
|
|
} else {
|
|
setIsInitiatingSession(false);
|
|
}
|
|
}
|
|
|
|
const hasCartItems = Array.isArray(cart.items) && cart.items.length > 0;
|
|
const isLocationsShown = synlabAnalyses.length > 0;
|
|
|
|
return (
|
|
<div className="small:grid-cols-[1fr_360px] grid grid-cols-1 gap-x-40 lg:px-4">
|
|
<div className="flex flex-col gap-y-6 bg-white">
|
|
<CartItems
|
|
cart={cart}
|
|
items={synlabAnalyses}
|
|
productColumnLabelKey="cart:items.synlabAnalyses.productColumnLabel"
|
|
/>
|
|
<CartItems
|
|
cart={cart}
|
|
items={ttoServiceItems}
|
|
productColumnLabelKey="cart:items.ttoServices.productColumnLabel"
|
|
/>
|
|
</div>
|
|
{hasCartItems && (
|
|
<>
|
|
<div className="flex gap-x-4 px-4 pt-2 sm:justify-end sm:px-6 sm:pt-4">
|
|
<div className="w-full sm:mr-[42px] sm:w-auto">
|
|
<p className="text-muted-foreground ml-0 text-sm font-bold">
|
|
<Trans i18nKey="cart:order.subtotal" />
|
|
</p>
|
|
</div>
|
|
<div className={`sm:mr-[112px] sm:w-[50px]`}>
|
|
<p className="text-right text-sm">
|
|
{formatCurrency({
|
|
value: cart.subtotal,
|
|
currencyCode: cart.currency_code,
|
|
locale: language,
|
|
})}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div className="flex gap-x-4 px-4 py-2 sm:justify-end sm:px-6 sm:py-4">
|
|
<div className="w-full sm:mr-[42px] sm:w-auto">
|
|
<p className="text-muted-foreground ml-0 text-sm font-bold">
|
|
<Trans i18nKey="cart:order.promotionsTotal" />
|
|
</p>
|
|
</div>
|
|
<div className={`sm:mr-[112px] sm:w-[50px]`}>
|
|
<p className="text-right text-sm">
|
|
{formatCurrency({
|
|
value: cart.discount_total,
|
|
currencyCode: cart.currency_code,
|
|
locale: language,
|
|
})}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div className="flex gap-x-4 px-4 sm:justify-end sm:px-6">
|
|
<div className="w-full sm:mr-[42px] sm:w-auto">
|
|
<p className="ml-0 text-sm font-bold">
|
|
<Trans i18nKey="cart:order.total" />
|
|
</p>
|
|
</div>
|
|
<div className={`sm:mr-[112px] sm:w-[50px]`}>
|
|
<p className="text-right text-sm">
|
|
{formatCurrency({
|
|
value: cart.total,
|
|
currencyCode: cart.currency_code,
|
|
locale: language,
|
|
})}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</>
|
|
)}
|
|
|
|
<div className="flex flex-col gap-x-4 gap-y-6 py-4 sm:flex-row sm:py-8">
|
|
{IS_DISCOUNT_SHOWN && (
|
|
<Card className="flex w-full flex-col justify-between sm:w-1/2">
|
|
<CardHeader className="pb-4">
|
|
<h5>
|
|
<Trans i18nKey="cart:discountCode.title" />
|
|
</h5>
|
|
</CardHeader>
|
|
<CardContent className="h-full">
|
|
<DiscountCode cart={{ ...cart }} />
|
|
</CardContent>
|
|
</Card>
|
|
)}
|
|
|
|
{isLocationsShown && (
|
|
<Card className="flex w-full flex-col justify-between sm:w-1/2">
|
|
<CardHeader className="pb-4">
|
|
<h5>
|
|
<Trans i18nKey="cart:locations.title" />
|
|
</h5>
|
|
</CardHeader>
|
|
<CardContent className="h-full">
|
|
<AnalysisLocation
|
|
cart={{ ...cart }}
|
|
synlabAnalyses={synlabAnalyses}
|
|
/>
|
|
</CardContent>
|
|
</Card>
|
|
)}
|
|
</div>
|
|
|
|
<div>
|
|
<Button
|
|
className="h-10"
|
|
onClick={initiatePayment}
|
|
disabled={isInitiatingSession}
|
|
>
|
|
{isInitiatingSession && (
|
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
)}
|
|
<Trans i18nKey="cart:checkout.goToCheckout" />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|