225 lines
7.3 KiB
TypeScript
225 lines
7.3 KiB
TypeScript
'use client';
|
|
|
|
import { useState } from 'react';
|
|
|
|
import { formatCurrency } from '@/packages/shared/src/utils';
|
|
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';
|
|
import { initiatePayment } from '../../_lib/server/cart-actions';
|
|
import { useRouter } from 'next/navigation';
|
|
import { AccountBalanceSummary } from '@kit/accounts/services/account-balance.service';
|
|
|
|
const IS_DISCOUNT_SHOWN = true as boolean;
|
|
|
|
export default function Cart({
|
|
accountId,
|
|
cart,
|
|
synlabAnalyses,
|
|
ttoServiceItems,
|
|
balanceSummary,
|
|
}: {
|
|
accountId: string;
|
|
cart: StoreCart | null;
|
|
synlabAnalyses: StoreCartLineItem[];
|
|
ttoServiceItems: StoreCartLineItem[];
|
|
balanceSummary: AccountBalanceSummary | null;
|
|
}) {
|
|
const {
|
|
i18n: { language },
|
|
} = useTranslation();
|
|
|
|
const [isInitiatingSession, setIsInitiatingSession] = useState(false);
|
|
const router = useRouter();
|
|
const items = cart?.items ?? [];
|
|
const hasCartItems = cart && Array.isArray(items) && items.length > 0;
|
|
|
|
if (!hasCartItems) {
|
|
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 initiateSession() {
|
|
setIsInitiatingSession(true);
|
|
|
|
try {
|
|
const { url, isFullyPaidByBenefits, orderId } = await initiatePayment({
|
|
accountId,
|
|
balanceSummary: balanceSummary!,
|
|
cart: cart!,
|
|
language,
|
|
});
|
|
if (url) {
|
|
window.location.href = url;
|
|
} else if (isFullyPaidByBenefits) {
|
|
if (typeof orderId !== 'number') {
|
|
throw new Error('Order ID is missing');
|
|
}
|
|
router.push(`/home/order/${orderId}/confirmed`);
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to initiate payment', error);
|
|
setIsInitiatingSession(false);
|
|
}
|
|
}
|
|
|
|
const isLocationsShown = synlabAnalyses.length > 0;
|
|
|
|
const companyBenefitsTotal = balanceSummary?.totalBalance ?? 0;
|
|
const montonioTotal = cart && companyBenefitsTotal > 0 ? cart.total - companyBenefitsTotal : cart.total;
|
|
|
|
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 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.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>
|
|
{companyBenefitsTotal > 0 && (
|
|
<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.companyBenefitsTotal" />
|
|
</p>
|
|
</div>
|
|
<div className={`sm:mr-[112px] sm:w-[50px]`}>
|
|
<p className="text-right text-sm">
|
|
{formatCurrency({
|
|
value: (companyBenefitsTotal > cart.total ? cart.total : companyBenefitsTotal),
|
|
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: montonioTotal < 0 ? 0 : montonioTotal,
|
|
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={initiateSession}
|
|
disabled={isInitiatingSession}
|
|
>
|
|
{isInitiatingSession && (
|
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
)}
|
|
<Trans i18nKey="cart:checkout.goToCheckout" />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|