feat(MED-100): show toast on delete
This commit is contained in:
48
app/home/(user)/_components/cart/cart-item-delete.tsx
Normal file
48
app/home/(user)/_components/cart/cart-item-delete.tsx
Normal file
@@ -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 (
|
||||||
|
<div className="flex items-center justify-between text-small-regular">
|
||||||
|
<button
|
||||||
|
className="flex gap-x-1 text-ui-fg-subtle hover:text-ui-fg-base cursor-pointer"
|
||||||
|
onClick={() => handleDelete()}
|
||||||
|
>
|
||||||
|
{isDeleting ? <Spinner className="animate-spin" /> : <Trash />}
|
||||||
|
<span>{children}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CartItemDelete;
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { HttpTypes } from "@medusajs/types"
|
import { HttpTypes } from "@medusajs/types"
|
||||||
import DeleteButton from "@modules/common/components/delete-button"
|
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
import {
|
import {
|
||||||
TableCell,
|
TableCell,
|
||||||
TableRow,
|
TableRow,
|
||||||
} from '@kit/ui/table';
|
} from '@kit/ui/table';
|
||||||
import { formatCurrency } from "@/packages/shared/src/utils"
|
import { formatCurrency } from "@/packages/shared/src/utils"
|
||||||
import { Trash } from "lucide-react"
|
import CartItemDelete from "./cart-item-delete";
|
||||||
|
|
||||||
export default function CartItem({ item, currencyCode }: {
|
export default function CartItem({ item, currencyCode }: {
|
||||||
item: HttpTypes.StoreCartLineItem
|
item: HttpTypes.StoreCartLineItem
|
||||||
@@ -49,7 +48,7 @@ export default function CartItem({ item, currencyCode }: {
|
|||||||
|
|
||||||
<TableCell className="text-right px-6">
|
<TableCell className="text-right px-6">
|
||||||
<span className="flex gap-x-1 justify-end w-[60px]">
|
<span className="flex gap-x-1 justify-end w-[60px]">
|
||||||
<DeleteButton id={item.id} data-testid="product-delete-button" Icon={<Trash />} />
|
<CartItemDelete id={item.id} />
|
||||||
</span>
|
</span>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useSearchParams } from 'next/navigation';
|
import { useRouter, useSearchParams } from 'next/navigation';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import { Alert, AlertDescription, AlertTitle } from '@kit/ui/alert';
|
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 { Trans } from '@kit/ui/trans';
|
||||||
import { placeOrder } from "@lib/data/cart"
|
import { placeOrder } from "@lib/data/cart"
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
import Loading from '@/app/home/loading';
|
||||||
|
|
||||||
enum Status {
|
enum Status {
|
||||||
LOADING = 'LOADING',
|
LOADING = 'LOADING',
|
||||||
@@ -15,12 +16,14 @@ enum Status {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function MontonioCheckoutCallback() {
|
export function MontonioCheckoutCallback() {
|
||||||
|
const router = useRouter();
|
||||||
const [status, setStatus] = useState<Status>(Status.LOADING);
|
const [status, setStatus] = useState<Status>(Status.LOADING);
|
||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const token = searchParams.get('order-token');
|
const token = searchParams.get('order-token');
|
||||||
if (!token) {
|
if (!token) {
|
||||||
|
router.push('/home/cart');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +47,12 @@ export function MontonioCheckoutCallback() {
|
|||||||
const body = await response.json();
|
const body = await response.json();
|
||||||
const paymentStatus = body.status as string;
|
const paymentStatus = body.status as string;
|
||||||
if (paymentStatus === 'PAID') {
|
if (paymentStatus === 'PAID') {
|
||||||
await placeOrder();
|
try {
|
||||||
|
await placeOrder();
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Error placing order", e);
|
||||||
|
router.push('/home/cart');
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
setStatus(Status.ERROR);
|
setStatus(Status.ERROR);
|
||||||
}
|
}
|
||||||
@@ -83,5 +91,5 @@ export function MontonioCheckoutCallback() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return (<Loading />);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
|
import { useRouter } from 'next/navigation';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
@@ -34,8 +35,9 @@ export default function SelectAnalysisPackage({
|
|||||||
analysisPackage: StoreProduct
|
analysisPackage: StoreProduct
|
||||||
countryCode: string,
|
countryCode: string,
|
||||||
}) {
|
}) {
|
||||||
|
const router = useRouter();
|
||||||
const { t, i18n: { language } } = useTranslation();
|
const { t, i18n: { language } } = useTranslation();
|
||||||
|
|
||||||
const [isAddingToCart, setIsAddingToCart] = useState(false);
|
const [isAddingToCart, setIsAddingToCart] = useState(false);
|
||||||
const handleSelect = async (selectedVariant: StoreProductVariant) => {
|
const handleSelect = async (selectedVariant: StoreProductVariant) => {
|
||||||
if (!selectedVariant?.id) return null
|
if (!selectedVariant?.id) return null
|
||||||
@@ -46,6 +48,7 @@ export default function SelectAnalysisPackage({
|
|||||||
countryCode,
|
countryCode,
|
||||||
});
|
});
|
||||||
setIsAddingToCart(false);
|
setIsAddingToCart(false);
|
||||||
|
router.push('/home/cart');
|
||||||
}
|
}
|
||||||
|
|
||||||
const titleKey = analysisPackage.title;
|
const titleKey = analysisPackage.title;
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export async function retrieveCart(cartId?: string) {
|
|||||||
},
|
},
|
||||||
headers,
|
headers,
|
||||||
next,
|
next,
|
||||||
cache: "force-cache",
|
//cache: "force-cache",
|
||||||
})
|
})
|
||||||
.then(({ cart }) => cart)
|
.then(({ cart }) => cart)
|
||||||
.catch(() => null);
|
.catch(() => null);
|
||||||
@@ -396,7 +396,7 @@ export async function placeOrder(cartId?: string) {
|
|||||||
const id = cartId || (await getCartId());
|
const id = cartId || (await getCartId());
|
||||||
|
|
||||||
if (!id) {
|
if (!id) {
|
||||||
return;
|
throw new Error("No existing cart found when placing an order");
|
||||||
}
|
}
|
||||||
|
|
||||||
const headers = {
|
const headers = {
|
||||||
|
|||||||
@@ -35,6 +35,11 @@
|
|||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
"productColumnLabel": "Service name"
|
"productColumnLabel": "Service name"
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"success": "Item removed from cart",
|
||||||
|
"loading": "Removing item from cart",
|
||||||
|
"error": "Failed to remove item from cart"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"orderConfirmed": {
|
"orderConfirmed": {
|
||||||
|
|||||||
@@ -36,6 +36,11 @@
|
|||||||
},
|
},
|
||||||
"services": {
|
"services": {
|
||||||
"productColumnLabel": "Teenuse nimi"
|
"productColumnLabel": "Teenuse nimi"
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"success": "Toode eemaldatud ostukorvist",
|
||||||
|
"loading": "Toote eemaldamine ostukorvist",
|
||||||
|
"error": "Toote eemaldamine ostukorvist ebaõnnestus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"orderConfirmed": {
|
"orderConfirmed": {
|
||||||
|
|||||||
Reference in New Issue
Block a user