From 7ccc45ce7767775babc0bcf25984ce37f1df9939 Mon Sep 17 00:00:00 2001 From: k4rli Date: Thu, 17 Jul 2025 10:44:05 +0300 Subject: [PATCH] feat(MED-100): show toast on delete --- .../_components/cart/cart-item-delete.tsx | 48 +++++++++++++++++++ .../(user)/_components/cart/cart-item.tsx | 5 +- .../cart/montonio-checkout-callback.tsx | 16 +++++-- components/select-analysis-package.tsx | 5 +- .../medusa-storefront/src/lib/data/cart.ts | 4 +- public/locales/en/cart.json | 5 ++ public/locales/et/cart.json | 5 ++ 7 files changed, 78 insertions(+), 10 deletions(-) create mode 100644 app/home/(user)/_components/cart/cart-item-delete.tsx diff --git a/app/home/(user)/_components/cart/cart-item-delete.tsx b/app/home/(user)/_components/cart/cart-item-delete.tsx new file mode 100644 index 0000000..4c359cf --- /dev/null +++ b/app/home/(user)/_components/cart/cart-item-delete.tsx @@ -0,0 +1,48 @@ +"use client"; + +import { Trash } from "lucide-react"; +import { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { toast } from 'sonner'; + +import { deleteLineItem } from "@lib/data/cart"; +import { Spinner } from "@medusajs/icons"; + +const CartItemDelete = ({ + id, + children, +}: { + id: string; + children?: React.ReactNode; +}) => { + const [isDeleting, setIsDeleting] = useState(false); + const { t } = useTranslation(); + + const handleDelete = async () => { + setIsDeleting(true); + + const promise = async () => { + await deleteLineItem(id); + }; + + toast.promise(promise, { + success: t(`cart:items.delete.success`), + loading: t(`cart:items.delete.loading`), + error: t(`cart:items.delete.error`), + }); + }; + + return ( +
+ +
+ ); +}; + +export default CartItemDelete; diff --git a/app/home/(user)/_components/cart/cart-item.tsx b/app/home/(user)/_components/cart/cart-item.tsx index a25e535..db6a4ec 100644 --- a/app/home/(user)/_components/cart/cart-item.tsx +++ b/app/home/(user)/_components/cart/cart-item.tsx @@ -1,14 +1,13 @@ "use client" import { HttpTypes } from "@medusajs/types" -import DeleteButton from "@modules/common/components/delete-button" import { useTranslation } from "react-i18next" import { TableCell, TableRow, } from '@kit/ui/table'; import { formatCurrency } from "@/packages/shared/src/utils" -import { Trash } from "lucide-react" +import CartItemDelete from "./cart-item-delete"; export default function CartItem({ item, currencyCode }: { item: HttpTypes.StoreCartLineItem @@ -49,7 +48,7 @@ export default function CartItem({ item, currencyCode }: { - } /> + diff --git a/app/home/(user)/_components/cart/montonio-checkout-callback.tsx b/app/home/(user)/_components/cart/montonio-checkout-callback.tsx index 7c29c59..9f2c1eb 100644 --- a/app/home/(user)/_components/cart/montonio-checkout-callback.tsx +++ b/app/home/(user)/_components/cart/montonio-checkout-callback.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useSearchParams } from 'next/navigation'; +import { useRouter, useSearchParams } from 'next/navigation'; import { useEffect, useState } from 'react'; import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert'; @@ -8,6 +8,7 @@ import { Button } from '@kit/ui/button'; import { Trans } from '@kit/ui/trans'; import { placeOrder } from "@lib/data/cart" import Link from 'next/link'; +import Loading from '@/app/home/loading'; enum Status { LOADING = 'LOADING', @@ -15,12 +16,14 @@ enum Status { } export function MontonioCheckoutCallback() { + const router = useRouter(); const [status, setStatus] = useState(Status.LOADING); const searchParams = useSearchParams(); - + useEffect(() => { const token = searchParams.get('order-token'); if (!token) { + router.push('/home/cart'); return; } @@ -44,7 +47,12 @@ export function MontonioCheckoutCallback() { const body = await response.json(); const paymentStatus = body.status as string; if (paymentStatus === 'PAID') { - await placeOrder(); + try { + await placeOrder(); + } catch (e) { + console.error("Error placing order", e); + router.push('/home/cart'); + } } else { setStatus(Status.ERROR); } @@ -83,5 +91,5 @@ export function MontonioCheckoutCallback() { ); } - return null; + return (); } diff --git a/components/select-analysis-package.tsx b/components/select-analysis-package.tsx index 20afe6c..2b55ac2 100644 --- a/components/select-analysis-package.tsx +++ b/components/select-analysis-package.tsx @@ -3,6 +3,7 @@ import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import Image from 'next/image'; +import { useRouter } from 'next/navigation'; import { Card, @@ -34,8 +35,9 @@ export default function SelectAnalysisPackage({ analysisPackage: StoreProduct countryCode: string, }) { + const router = useRouter(); const { t, i18n: { language } } = useTranslation(); - + const [isAddingToCart, setIsAddingToCart] = useState(false); const handleSelect = async (selectedVariant: StoreProductVariant) => { if (!selectedVariant?.id) return null @@ -46,6 +48,7 @@ export default function SelectAnalysisPackage({ countryCode, }); setIsAddingToCart(false); + router.push('/home/cart'); } const titleKey = analysisPackage.title; diff --git a/packages/features/medusa-storefront/src/lib/data/cart.ts b/packages/features/medusa-storefront/src/lib/data/cart.ts index 3ae27c8..d739abf 100644 --- a/packages/features/medusa-storefront/src/lib/data/cart.ts +++ b/packages/features/medusa-storefront/src/lib/data/cart.ts @@ -44,7 +44,7 @@ export async function retrieveCart(cartId?: string) { }, headers, next, - cache: "force-cache", + //cache: "force-cache", }) .then(({ cart }) => cart) .catch(() => null); @@ -396,7 +396,7 @@ export async function placeOrder(cartId?: string) { const id = cartId || (await getCartId()); if (!id) { - return; + throw new Error("No existing cart found when placing an order"); } const headers = { diff --git a/public/locales/en/cart.json b/public/locales/en/cart.json index 50d34d1..8f83aa1 100644 --- a/public/locales/en/cart.json +++ b/public/locales/en/cart.json @@ -35,6 +35,11 @@ }, "services": { "productColumnLabel": "Service name" + }, + "delete": { + "success": "Item removed from cart", + "loading": "Removing item from cart", + "error": "Failed to remove item from cart" } }, "orderConfirmed": { diff --git a/public/locales/et/cart.json b/public/locales/et/cart.json index 42f21a8..8db2419 100644 --- a/public/locales/et/cart.json +++ b/public/locales/et/cart.json @@ -36,6 +36,11 @@ }, "services": { "productColumnLabel": "Teenuse nimi" + }, + "delete": { + "success": "Toode eemaldatud ostukorvist", + "loading": "Toote eemaldamine ostukorvist", + "error": "Toote eemaldamine ostukorvist ebaõnnestus" } }, "orderConfirmed": {