diff --git a/src/app/dashboard/(user-dashboard)/products/_components/product-body-shadcn.tsx b/src/app/dashboard/(user-dashboard)/products/_components/product-body-shadcn.tsx index 07e45a345..3bd423007 100644 --- a/src/app/dashboard/(user-dashboard)/products/_components/product-body-shadcn.tsx +++ b/src/app/dashboard/(user-dashboard)/products/_components/product-body-shadcn.tsx @@ -1,4 +1,7 @@ -import { MoreVertical } from "lucide-react"; +/* eslint-disable react-hooks/exhaustive-deps */ +import { AnimatePresence, motion } from "framer-motion"; +import { Edit2, MoreVertical, Trash } from "lucide-react"; +import { useEffect, useRef } from "react"; import BlurImage from "~/components/miscellaneous/blur-image"; import { Button } from "~/components/ui/button"; @@ -21,14 +24,49 @@ const ProductBodyShadcn = ({ searchTerm, }: Properties) => { const { products } = useProducts(); - const { updateOpen, updateProductId, product_id } = useProductModal(); + const { + updateOpen, + updateProductId, + product_id, + isActionModal, + setIsActionModal, + setIsDelete, + } = useProductModal(); + const modalReference = useRef(null); + useEffect(() => { + if (!isActionModal || !modalReference.current) return; + modalReference.current.scrollIntoView({ behavior: "smooth" }); + // handle click outside modal + const handleOutsideClick = (event: MouseEvent) => { + if ( + modalReference.current && + !modalReference.current.contains(event.target as Node) + ) { + setIsActionModal(false); + } + }; + document.addEventListener("click", handleOutsideClick); + return () => { + document.removeEventListener("click", handleOutsideClick); + }; + }, [isActionModal]); if (!products) return; + const handleOpenDetail = (product_id: string) => { + setIsActionModal(false); + updateProductId(product_id); + updateOpen(true); + }; + const handleDeleteAction = (id: string) => { + setIsActionModal(false); + updateProductId(id); + setIsDelete(true); + }; return ( filteredProducts.length > 0 && subset.length > 0 && - subset.map((product) => ( + subset.map((product, index) => ( {" "} { - updateProductId(product.product_id); - updateOpen(true); - }} + onClick={() => handleOpenDetail(product.product_id)} className="hide_scrollbar overflow-x-auto text-neutral-dark-2 md:w-[200px] lg:w-[200px]" > {searchTerm.length > 1 ? ( @@ -78,31 +113,28 @@ const ProductBodyShadcn = ({ )} - {product.product_id} { - updateProductId(product.product_id); - updateOpen(true); - }} + onClick={() => handleOpenDetail(product.product_id)} + className="uppercase" + > + {product.product_id} + + handleOpenDetail(product.product_id)} > {product.category} { - updateProductId(product.product_id); - updateOpen(true); - }} + onClick={() => handleOpenDetail(product.product_id)} > {formatPrice(product.price)} { - updateProductId(product.product_id); - updateOpen(true); - }} + onClick={() => handleOpenDetail(product.product_id)} > - - + + {isActionModal && product_id === product.product_id && ( + + + Actions + +
+ + +
+
+ )} +
)) diff --git a/src/app/dashboard/(user-dashboard)/products/_components/product-delete-modal.tsx b/src/app/dashboard/(user-dashboard)/products/_components/product-delete-modal.tsx new file mode 100644 index 000000000..f47c45e1e --- /dev/null +++ b/src/app/dashboard/(user-dashboard)/products/_components/product-delete-modal.tsx @@ -0,0 +1,125 @@ +import { AnimatePresence, motion } from "framer-motion"; + +import { Button } from "~/components/ui/button"; +import { toast } from "~/components/ui/use-toast"; +import { useProductModal } from "~/hooks/admin-product/use-product.modal"; +import { useProducts } from "~/hooks/admin-product/use-products.persistence"; +import { cn } from "~/lib/utils"; + +const variantProperties = { + left: "50%", + top: "50%", + translateX: "-50%", + translateY: "-50%", +}; +const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); +const ProductDeleteModal = () => { + const { products, deleteProduct } = useProducts(); + + const { product_id, updateProductId, updateOpen, isDelete, setIsDelete } = + useProductModal(); + + const product = products?.find( + (product) => product.product_id === product_id, + ); + + const handleDelete = async (id: string) => { + toast({ + title: "Deleting product", + description: "Please wait...", + variant: "destructive", + }); + setIsDelete(false); + + await delay(3000); + deleteProduct(id); + toast({ + title: `Product deleted`, + description: ( + + {product?.name} has been deleted. + + ), + variant: "default", + className: "z-[99999]", + }); + updateOpen(false); + updateProductId("null"); + }; + + return ( + <> +
{ + updateOpen(false); + updateProductId("null"); + + setIsDelete(false); + }} + className={cn( + "fixed left-0 top-0 z-[99999] min-h-screen w-full overflow-hidden bg-neutral-700/10 transition-all duration-300 lg:hidden", + isDelete + ? "pointer-events-auto opacity-100" + : "pointer-events-none opacity-0", + )} + /> + + + {isDelete && ( + +
+

+ Are you sure you want to delete {product?.name}? +

+
+ + +
+
+
+ )} +
+ + ); +}; + +export default ProductDeleteModal; diff --git a/src/app/dashboard/(user-dashboard)/products/_components/product-detail-modal.tsx b/src/app/dashboard/(user-dashboard)/products/_components/product-detail-modal.tsx index 4c27eccbe..39ada15c9 100644 --- a/src/app/dashboard/(user-dashboard)/products/_components/product-detail-modal.tsx +++ b/src/app/dashboard/(user-dashboard)/products/_components/product-detail-modal.tsx @@ -64,7 +64,11 @@ const ProductDetailModal = () => { document.body.style.overflow = isOpen && winWidth < 1024 ? "hidden" : "unset"; }, [isOpen, winWidth]); - + useEffect(() => { + document.title = isOpen + ? `Product - ${product?.name}` + : "Products - HNG Boilerplate"; + }, [isOpen, product?.name]); return ( <>
{ exit={{ ...variantProperties, opacity: 0, - scale: 2, + scale: 0.5, }} transition={{ duration: 0.2 }} className={cn( @@ -112,7 +116,7 @@ const ProductDetailModal = () => { )} >

- Are you sure you want to delete this {product?.name}? + Are you sure you want to delete {product?.name}?