feat(MED-100): update cart checkout flow and views
This commit is contained in:
91
app/home/(user)/_components/cart/cart-timer.tsx
Normal file
91
app/home/(user)/_components/cart/cart-timer.tsx
Normal file
@@ -0,0 +1,91 @@
|
||||
"use client";
|
||||
|
||||
import { Button } from '@kit/ui/button';
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle
|
||||
} from "@kit/ui/alert-dialog";
|
||||
|
||||
import { Timer } from 'lucide-react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { StoreCartLineItem } from '@medusajs/types';
|
||||
import { handleLineItemTimeout } from '@/lib/services/medusaCart.service';
|
||||
|
||||
const TIMEOUT_MINUTES = 15;
|
||||
|
||||
export default function CartTimer({ cartItem }: { cartItem: StoreCartLineItem }) {
|
||||
const { t } = useTranslation();
|
||||
const [timeLeft, setTimeLeft] = useState<number | null>(null);
|
||||
const [isDialogOpen, setDialogOpen] = useState(false);
|
||||
|
||||
const updatedAt = cartItem.updated_at!;
|
||||
|
||||
useEffect(() => {
|
||||
const date = new Date(updatedAt);
|
||||
date.setMinutes(date.getMinutes() + TIMEOUT_MINUTES);
|
||||
|
||||
const interval = setInterval(() => {
|
||||
const now = new Date();
|
||||
const diff = date.getTime() - now.getTime();
|
||||
setTimeLeft(diff);
|
||||
}, 1000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [updatedAt]);
|
||||
|
||||
const minutes = timeLeft ? Math.floor((timeLeft % (1000 * 60 * 60)) / (1000 * 60)) : 0;
|
||||
const seconds = timeLeft ? Math.floor((timeLeft % (1000 * 60)) / 1000) : 0;
|
||||
|
||||
const isTimeLeftPositive = timeLeft === null || timeLeft > 0;
|
||||
useEffect(() => {
|
||||
if (!isTimeLeftPositive) {
|
||||
void handleLineItemTimeout({
|
||||
lineItem: cartItem,
|
||||
});
|
||||
setDialogOpen(true);
|
||||
}
|
||||
}, [isTimeLeftPositive, cartItem.id]);
|
||||
|
||||
if (timeLeft === null) {
|
||||
return <div className='min-h-[40px]' />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="ml-auto">
|
||||
<Button variant="outline" className="flex items-center gap-x-2 bg-accent hover:bg-accent px-4 cursor-default">
|
||||
<Timer />
|
||||
<span className="text-sm">
|
||||
{t('cart:checkout.timeLeft', {
|
||||
timeLeft: `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`,
|
||||
})}
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<AlertDialog open={isDialogOpen} onOpenChange={setDialogOpen}>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>
|
||||
{t('cart:checkout.timeoutTitle')}
|
||||
</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
{t('cart:checkout.timeoutDescription', { productTitle: cartItem.product?.title })}
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogAction onClick={() => setDialogOpen(false)}>
|
||||
{t('cart:checkout.timeoutAction')}
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user