diff --git a/package.json b/package.json index de17b7cb7..78985a100 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "react-email": "2.1.5", "react-hook-form": "^7.52.2", "react-paginate": "^8.2.0", + "react-toastify": "^10.0.5", "recharts": "^2.12.7", "sharp": "^0.33.4", "swiper": "^11.1.9", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d7b81ef63..a058996d6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -152,6 +152,9 @@ importers: react-paginate: specifier: ^8.2.0 version: 8.2.0(react@18.3.1) + react-toastify: + specifier: ^10.0.5 + version: 10.0.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) recharts: specifier: ^2.12.7 version: 2.12.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -4484,6 +4487,12 @@ packages: '@types/react': optional: true + react-toastify@10.0.5: + resolution: {integrity: sha512-mNKt2jBXJg4O7pSdbNUfDdTsK9FIdikfsIE/yUCxbAEXl4HMyJaivrVFcn3Elvt5xvCQYhUZm+hqTIu1UXM3Pw==} + peerDependencies: + react: '>=18' + react-dom: '>=18' + react-transition-group@4.4.5: resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} peerDependencies: @@ -10020,6 +10029,12 @@ snapshots: optionalDependencies: '@types/react': 18.3.3 + react-toastify@10.0.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + clsx: 2.1.1 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-transition-group@4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@babel/runtime': 7.25.0 diff --git a/public/images/productimage.png b/public/images/productimage.png new file mode 100644 index 000000000..55cef508e Binary files /dev/null and b/public/images/productimage.png differ diff --git a/public/images/user.png b/public/images/user.png new file mode 100644 index 000000000..6f728aaa5 Binary files /dev/null and b/public/images/user.png differ diff --git a/src/app/dashboard/(user-dashboard)/products/_components/new-product-modal.tsx b/src/app/dashboard/(user-dashboard)/products/_components/new-product-modal.tsx index 69f7b2c77..04064b833 100644 --- a/src/app/dashboard/(user-dashboard)/products/_components/new-product-modal.tsx +++ b/src/app/dashboard/(user-dashboard)/products/_components/new-product-modal.tsx @@ -1,4 +1,5 @@ // components/admin/NewProductModal.tsx + import { zodResolver } from "@hookform/resolvers/zod"; import { AnimatePresence, motion } from "framer-motion"; import { Loader, X } from "lucide-react"; 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 271c00fce..a49fddded 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 @@ -1,3 +1,5 @@ +"use client"; + import { AnimatePresence, motion } from "framer-motion"; import { Loader2, X } from "lucide-react"; import { useSession } from "next-auth/react"; diff --git a/src/app/dashboard/(user-dashboard)/products/_components/productcadrcomponent.tsx b/src/app/dashboard/(user-dashboard)/products/_components/productcadrcomponent.tsx new file mode 100644 index 000000000..e77bc85ed --- /dev/null +++ b/src/app/dashboard/(user-dashboard)/products/_components/productcadrcomponent.tsx @@ -0,0 +1,67 @@ +"use client"; + +import Image, { StaticImageData } from "next/image"; + +interface ProductCardProperties { + title: string; + price: string; + description: string; + inStock: boolean; + imageUrl: string | StaticImageData; +} + +const Delete = () => { + alert("Are you sure you want to delete"); +}; + +const Edit = () => { + alert("Proceed to edit"); +}; + +const ProductCard: React.FC = ({ + title, + price, + description, + inStock, + imageUrl, +}) => { + return ( +
+ {title} +
+
+

{title}

+

{price}

+
+

{description}

+ + {inStock ? "In stock" : "Out of stock"} + +
+ + +
+
+
+ ); +}; + +export default ProductCard; diff --git a/src/app/dashboard/(user-dashboard)/products/mainproductdetailpage/page.tsx b/src/app/dashboard/(user-dashboard)/products/mainproductdetailpage/page.tsx new file mode 100644 index 000000000..55ba4ce42 --- /dev/null +++ b/src/app/dashboard/(user-dashboard)/products/mainproductdetailpage/page.tsx @@ -0,0 +1,382 @@ +"use client"; + +import Image from "next/image"; +import Link from "next/link"; +import { ChangeEvent, FormEvent, useState } from "react"; + +import user from "../../../../../../public/images/user.png"; + +const Discard = () => { + alert("Changes discard"); +}; + +const ProductDetail = () => { + const [textValue, setTextValue] = useState("Product 2"); + const [messageValue, setmessageValue] = useState( + "A fusion of ripe bananas, pure honey, and succulent raspberries with our bread. Crafted to perfection.", + ); + const [image, setImage] = useState(); + const [smallQuantity, setSmallQuantity] = useState(0); + const [standardQuantity, setStandardQuantity] = useState(24); + const [largeQuantity, setLargeQuantity] = useState(0); + const [smallPrice, setSmallPrice] = useState("$12.00"); + const [standardPrice, setStandardPrice] = useState("$29.00"); + const [largePrice, setLargePrice] = useState("$32.00"); + + const handleSubmit = (event: FormEvent) => { + event.preventDefault(); + + if ( + !textValue.trim() || + !messageValue.trim() || + !smallQuantity || + !standardQuantity || + !largeQuantity || + !smallPrice || + !standardPrice || + !largePrice || + !largePrice || + !image + ) { + alert( + "Please fill in all the necessary fields including your image before submitting.", + ); + return; + } + alert("Details updated"); + }; + + const handleSmallQty = (event: ChangeEvent) => { + setSmallQuantity(Number(event.target.value)); + }; + + const handleStandardQty = (event: ChangeEvent) => { + setStandardQuantity(Number(event.target.value)); + }; + + const handleLargeQty = (event: ChangeEvent) => { + setLargeQuantity(Number(event.target.value)); + }; + + //upload media section + const handleImageChange = (event: ChangeEvent) => { + const file = event.target.files?.[0]; + if (file) { + const reader = new FileReader(); + reader.onloadend = () => { + setImage(reader.result as string); + }; + reader.readAsDataURL(file); + } + }; + + //comment section + const [comments, setComments] = useState([ + { + name: "Adetunji Oluwatobi", + date: "02 Jan, 2020", + time: "Wed 02:30pm", + comment: "Living a balanced lifestyle is essential...", + }, + { + name: "Afolabi Oyewole", + date: "02 Jan, 2020", + time: "Wed 02:30pm", + comment: "Living a balanced lifestyle is essential...", + }, + ]); + const [newComment, setNewComment] = useState(""); + + const handleCommentChange = ( + event: React.ChangeEvent, + ) => { + setNewComment(event.target.value); + }; + + const handleCommentSubmit = () => { + if (newComment.trim()) { + const currentDate = new Date(); + const formattedDate = `${currentDate.getDate()} ${currentDate.toLocaleString("default", { month: "short" })}, ${currentDate.getFullYear()}`; + const formattedTime = `${currentDate.toLocaleString("default", { weekday: "short" })} ${currentDate.getHours()}:${currentDate.getMinutes() < 10 ? "0" : ""}${currentDate.getMinutes()}pm`; + + const commentToAdd = { + name: "New User", + date: formattedDate, + time: formattedTime, + comment: newComment, + }; + + setComments([...comments, commentToAdd]); + setNewComment(""); + } + }; + + return ( +
+
+
+
+ + Products + + + {">"} + + + Product Details + +
+
+
+
+ +

Product 2

+ ● In stock +
+
+
+ Discard +
+ +
+
+ +
+
+
+

Product Details

+

+ Make quick changes to your product. +

+
+ +
+ + setTextValue(event.target.value)} + placeholder="Product title" + className="w-full rounded-md border border-gray-300 p-2 focus:outline-none" + /> +
+
+ + +
+
+ +
+

Stock

+

Add and remove products

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SizeStockPrice
Small + + + setSmallPrice(event.target.value)} + /> +
+
+
Standard + + + + setStandardPrice(event.target.value) + } + /> +
+
+
Large + + + setLargePrice(event.target.value)} + /> +
+ + +
+
+ +
+
+

Media

+
+

+ Upload media for your product. +

+
+
+ {image ? ( + Uploaded + ) : ( +

Image here

+ )} +
+ +
+
+ +
+
+

Status

+

Availability

+
+ +
+
+

Archive

+

Archive a product.

+
+ +
+
+
+
+
+ +
+

Comments

+ {comments.map((comment, index) => ( +
+
+ User Avatar +
+

{comment.name}

+

{`${comment.date} ${comment.time}`}

+
+
+

{comment.comment}

+
+ ))} + +
+ +
+
+
+ ); +}; + +export default ProductDetail; diff --git a/src/app/dashboard/(user-dashboard)/products/productcard/page.tsx b/src/app/dashboard/(user-dashboard)/products/productcard/page.tsx new file mode 100644 index 000000000..baca39210 --- /dev/null +++ b/src/app/dashboard/(user-dashboard)/products/productcard/page.tsx @@ -0,0 +1,19 @@ +import productimage from "/public/images/productimage.png"; + +import ProductCard from "../_components/productcadrcomponent"; + +const Home: React.FC = () => { + return ( +
+ +
+ ); +}; + +export default Home; diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx index ed5aa8a33..324697dbb 100644 --- a/src/components/ui/input.tsx +++ b/src/components/ui/input.tsx @@ -6,7 +6,7 @@ export interface InputProperties extends React.InputHTMLAttributes {} const Input = React.forwardRef( - ({ className, type, ...properties }, reference) => { + ({ className, type, value, ...properties }, reference) => { return ( ( "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50", className, )} + value={value} ref={reference} {...properties} />