147 lines
4.0 KiB
TypeScript
147 lines
4.0 KiB
TypeScript
'use client';
|
|
|
|
import { useState } from 'react';
|
|
|
|
import { formatCurrency, formatDateAndTime } from '@/packages/shared/src/utils';
|
|
import { useTranslation } from 'react-i18next';
|
|
|
|
import { Button } from '@kit/ui/button';
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from '@kit/ui/dialog';
|
|
import { TableCell, TableRow } from '@kit/ui/table';
|
|
import { Trans } from '@kit/ui/trans';
|
|
|
|
import BookingContainer from '../booking/booking-container';
|
|
import CartItemDelete from './cart-item-delete';
|
|
import { EnrichedCartItem } from './types';
|
|
|
|
const EditCartServiceItemModal = ({
|
|
item,
|
|
onComplete,
|
|
}: {
|
|
item: EnrichedCartItem | null;
|
|
onComplete: () => void;
|
|
}) => {
|
|
if (!item) return null;
|
|
|
|
return (
|
|
<Dialog defaultOpen>
|
|
<DialogContent className="xs:max-w-[90vw] flex max-h-screen max-w-full flex-col items-center gap-4 space-y-4 overflow-y-scroll">
|
|
<DialogHeader className="items-center text-center">
|
|
<DialogTitle>
|
|
<Trans i18nKey="cart:editServiceItem.title" />
|
|
</DialogTitle>
|
|
<DialogDescription>
|
|
<Trans i18nKey="cart:editServiceItem.description" />
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
<div>
|
|
{item.product && item.reservation.countryCode ? (
|
|
<BookingContainer
|
|
category={{
|
|
products: [item.product],
|
|
countryCode: item.reservation.countryCode,
|
|
}}
|
|
cartItem={item}
|
|
onComplete={onComplete}
|
|
/>
|
|
) : (
|
|
<p>
|
|
<Trans i18nKey="booking:noProducts" />
|
|
</p>
|
|
)}
|
|
</div>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
};
|
|
|
|
export default function CartServiceItem({
|
|
item,
|
|
currencyCode,
|
|
isUnavailable,
|
|
}: {
|
|
item: EnrichedCartItem;
|
|
currencyCode: string;
|
|
isUnavailable?: boolean;
|
|
}) {
|
|
const [editingItem, setEditingItem] = useState<EnrichedCartItem | null>(null);
|
|
const {
|
|
i18n: { language },
|
|
} = useTranslation();
|
|
|
|
return (
|
|
<>
|
|
<TableRow className="w-full" data-testid="product-row">
|
|
<TableCell className="w-[100%] px-4 text-left sm:px-6">
|
|
<p
|
|
className="txt-medium-plus text-ui-fg-base"
|
|
data-testid="product-title"
|
|
>
|
|
{item.product_title}
|
|
</p>
|
|
</TableCell>
|
|
|
|
<TableCell className="px-4 sm:px-6">
|
|
{formatDateAndTime(item.reservation.startTime.toString())}
|
|
</TableCell>
|
|
|
|
<TableCell className="px-4 sm:px-6">
|
|
{item.reservation.location?.address ?? '-'}
|
|
</TableCell>
|
|
|
|
<TableCell className="px-4 sm:px-6">{item.quantity}</TableCell>
|
|
|
|
<TableCell className="min-w-[80px] px-4 sm:px-6">
|
|
{formatCurrency({
|
|
value: item.unit_price,
|
|
currencyCode,
|
|
locale: language,
|
|
})}
|
|
</TableCell>
|
|
|
|
<TableCell className="min-w-[80px] px-4 text-right sm:px-6">
|
|
{formatCurrency({
|
|
value: item.total,
|
|
currencyCode,
|
|
locale: language,
|
|
})}
|
|
</TableCell>
|
|
|
|
<TableCell className="px-4 text-right sm:px-6">
|
|
<span className="flex justify-end gap-x-1">
|
|
<Button size="sm" onClick={() => setEditingItem(item)}>
|
|
<Trans i18nKey="common:change" />
|
|
</Button>
|
|
</span>
|
|
</TableCell>
|
|
|
|
<TableCell className="px-4 text-right sm:px-6">
|
|
<span className="flex w-[60px] justify-end gap-x-1">
|
|
<CartItemDelete id={item.id} />
|
|
</span>
|
|
</TableCell>
|
|
</TableRow>
|
|
{isUnavailable && (
|
|
<TableRow>
|
|
<TableCell
|
|
colSpan={8}
|
|
className="text-destructive px-4 text-left sm:px-6"
|
|
>
|
|
<Trans i18nKey="booking:timeSlotUnavailable" />
|
|
</TableCell>
|
|
</TableRow>
|
|
)}
|
|
<EditCartServiceItemModal
|
|
item={editingItem}
|
|
onComplete={() => setEditingItem(null)}
|
|
/>
|
|
</>
|
|
);
|
|
}
|