product req fixed

master
حسین معصومی پور 2024-02-27 21:23:20 +03:30
parent e2a947a61a
commit 57c7c8c74d
30 changed files with 1836 additions and 1509 deletions

View File

@ -0,0 +1,181 @@
"use client";
import CardCart from "@comp/Cards/CardCart/page";
import NavBarDownCart from "@comp/Carts/component/NavBarDownCart/page";
import Navbar from "@comp/Navbar/page";
import AppContext from "@ctx/AppContext";
import { useRouter } from "next/navigation";
import Chapar from "plugins/Chapar";
import PersianNumber from "plugins/PersianNumber";
import { useContext, useEffect } from "react";
import { toast } from "react-toastify";
const CartData = () => {
const CTX = useContext(AppContext);
const router = useRouter();
const cart = CTX.state.cart;
const calculateTotalCost = cart.reduce(
(total, item) => total + parseInt(item.cost) * item.count,
0
);
const calculateTotalCostWithDiscount = cart.reduce(
(total, item) => total + parseInt(item.costWithDiscount) * item.count,
0
);
const handleGoCheckOut = async () => {
// Check if the user is authorized based on the presence of a token in local storage
const token = localStorage.getItem("token");
if (token) {
// If token exists, proceed to checkout
const productsToSend = cart.map((item) => ({
productId: item.id,
count: parseInt(item.count),
}));
try {
const data = await Chapar.post(
`${process.env.NEXT_PUBLIC_API_URL}/order/bag/add`,
JSON.stringify(productsToSend),
{
headers: {
Authorization: localStorage.getItem("token"),
},
}
);
CTX.setCheckOutData(data);
} catch ({ error, status }) {
toast.error(`${error?.response?.data?.message}`, {
position: "bottom-right",
closeOnClick: true,
});
}
router.push("/cart/checkout"); // Redirect to the checkout Page
} else {
// If token does not exist, redirect to login
router.push("/login"); // Redirect to the login Page
}
};
useEffect(() => {
CTX.setBottomSheetCartOpen(false);
}, []);
return (
<>
<div className=" pb-20">
<Navbar theme={1} />
<div className="xs:w-full lg:w-4/12 mx-auto">
<div className="text-right flex rtl justify-between border-t-[1px] border-gray-200 my-3 px-4 ">
<p className="mb-0 text-sm font-semibold py-4">
محصولات انتخاب شده
</p>
<div className="bg-primary-200 w-fit h-fit relative my-3 p-1 rounded-lg">
<p className="mb-0 text-[11px] text-white rtl">
<PersianNumber number={cart?.length} style={"mx-1"} />
محصول
</p>
</div>
</div>
<div className="">
{cart?.map((e, index) => (
<CardCart key={index} data={e} />
))}
<div className="">
<div className="text-right flex rtl justify-between border-y-[1px] border-gray-200 my-3 px-4 ">
<p className="mb-0 text-sm font-medium py-4">حساب نهایی</p>
{/* <div className="bg-primary-200 w-fit h-fit relative my-3 p-1 rounded-lg">
<p className="mb-0 text-[11px] text-white rtl">
<PersianNumber number={cart?.length} style={"mx-1"} />
محصول
</p>
</div> */}
</div>
<div>
<div className="flex justify-between rtl px-4">
<p className="mb-0 text-[12px] text-gray-500">قیمت </p>
<div className="flex justify-center">
<p className="mb-0 ">
<PersianNumber
number={(calculateTotalCost / 10)?.toLocaleString()}
style={"!text-[14px] !font-medium"}
/>
</p>
<small className="text-gray-500 text-[12px] mt-1 mx-1">
{" "}
تومان
</small>
</div>
</div>
<div className="flex justify-between rtl my-2 px-4">
<p className="mb-0 text-[12px] text-gray-500">تخفیف محصول</p>
<div className="flex justify-center ">
<p className="mb-0 ">
<PersianNumber
number={(
(calculateTotalCost -
calculateTotalCostWithDiscount) /
10
)?.toLocaleString()}
style={"!text-[14px] !font-medium"}
/>
</p>
<small className="text-gray-500 text-[12px] mt-1 mx-1">
{" "}
تومان
</small>
</div>
</div>
<div className="flex justify-between bg-primary-100 p-3 rtl my-2">
<p className="mb-0 text-sm text-primary-600 font-bold">
قابل پرداخت
</p>
<div className="flex justify-center">
<p className="mb-0 ">
<PersianNumber
number={
calculateTotalCostWithDiscount !== 0
? (
calculateTotalCostWithDiscount / 10
)?.toLocaleString()
: 0
}
style={"!text-[14px] !font-semibold text-primary-800"}
/>
</p>
<small className="text-gray-500 text-[12px] mt-1 mx-1">
{" "}
تومان
</small>
</div>
</div>
</div>
</div>
</div>
</div>
<NavBarDownCart
calculateTotalCost={calculateTotalCostWithDiscount / 10}
event={() => handleGoCheckOut()}
permissionGoPay={!!cart.length > 0}
/>
</div>
</>
);
};
export default CartData;

View File

@ -11,31 +11,39 @@ import AppContext from "@ctx/AppContext";
import { useContext, useEffect, useState } from "react"; import { useContext, useEffect, useState } from "react";
import InfiniteScroll from "react-infinite-scroll-component"; import InfiniteScroll from "react-infinite-scroll-component";
export default function Page({ params }) { export default function CategoriesData({ params }) {
// const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/product?page=0`); console.log("params", params.id[0]);
// const products = await res.json();
const CTX = useContext(AppContext); const CTX = useContext(AppContext);
const pageGetProducts = CTX.state.pageGetProducts; const pageGetProducts = CTX.state.pageGetProducts;
const stopGetTasks = CTX.state.stopGetTasks; const stopGetTasks = CTX.state.stopGetTasks;
const pager = CTX.state.pager; const pager = CTX.state.pager;
const filter = CTX.state.filter;
const [isChecked, setIsChecked] = useState(false); const isChecked = CTX.state.isChecked;
const [selectedBrands, setSelectedBrands] = useState([]); const selectedBrands = CTX.state.selectedBrands;
const [rangePrice, setRangePrice] = useState([1000, 100]); const rangePrice = CTX.state.rangePrice;
const [isRangePrice, setIsRangePrice] = useState(false); const isRangePrice = CTX.state.isRangePrice;
const [sortBy, setSortBy] = useState(null); const sortBy = CTX.state.sortBy;
const fetchBarnds = async () => { const fetchBarnds = async () => {
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/brand`); const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/brand?categoryId=${params.id[0]}`
);
const brands = await res.json(); const brands = await res.json();
CTX.setBrands(brands); CTX.setBrands(brands);
}; };
const decodedName = decodeURIComponent(params.id[1]);
const handleInfiniteNextFetchProducts = () => { const handleInfiniteNextFetchProducts = () => {
CTX.setPageGetProducts((e) => e + 1); // Increment the page number
const nextPage = pageGetProducts + 1;
// Fetch products for the next page
CTX.fetchProducts( CTX.fetchProducts(
pageGetProducts + 1, nextPage,
params.id, params.id[0],
selectedBrands, selectedBrands,
isChecked, isChecked,
rangePrice, rangePrice,
@ -43,14 +51,16 @@ export default function Page({ params }) {
sortBy, sortBy,
isRangePrice isRangePrice
); );
};
// Update the pageGetProducts state for the next fetch
CTX.setPageGetProducts(nextPage);
};
useEffect(() => { useEffect(() => {
window.scrollTo({ window.scrollTo({
top: 0, top: 0,
behavior: "smooth", // Optional: smooth scrolling behavior behavior: "smooth", // Optional: smooth scrolling behavior
}); });
CTX.fetchProducts(0, params.id); CTX.fetchProducts(0, params.id[0]);
fetchBarnds(); fetchBarnds();
}, []); }, []);
@ -62,18 +72,18 @@ export default function Page({ params }) {
<Navbar theme={1} /> <Navbar theme={1} />
{!CTX.state.isMobile && ( {!CTX.state.isMobile && (
<div className="xs:hidden lg:block"> <div className="xs:hidden lg:block">
<div className="pl-20 pr-10 grid lg:grid-cols-8 xl:grid-cols-5 rtl mt-20 "> <div className="text-right px-8 py-5">
<h1 className="font-medium ">{decodedName}</h1>
</div>
<div className="pl-20 pr-10 grid lg:grid-cols-8 xl:grid-cols-5 rtl mt-10 ">
<FilterCategory <FilterCategory
id={params.id} id={params.id}
isChecked={isChecked} isChecked={isChecked}
setIsChecked={setIsChecked}
selectedBrands={selectedBrands} selectedBrands={selectedBrands}
setSelectedBrands={setSelectedBrands}
rangePrice={rangePrice} rangePrice={rangePrice}
setRangePrice={setRangePrice}
sortBy={sortBy} sortBy={sortBy}
setIsRangePrice={setIsRangePrice}
isRangePrice={isRangePrice} isRangePrice={isRangePrice}
filter={filter}
/> />
<div className="lg:col-span-6 xl:col-span-4 "> <div className="lg:col-span-6 xl:col-span-4 ">
@ -88,7 +98,6 @@ export default function Page({ params }) {
isChecked={isChecked} isChecked={isChecked}
selectedBrands={selectedBrands} selectedBrands={selectedBrands}
rangePrice={rangePrice} rangePrice={rangePrice}
setSortBy={setSortBy}
sortBy={sortBy} sortBy={sortBy}
isRangePrice={isRangePrice} isRangePrice={isRangePrice}
/> />
@ -110,17 +119,14 @@ export default function Page({ params }) {
<FilterCategoryMobile <FilterCategoryMobile
id={params.id} id={params.id}
isChecked={isChecked} isChecked={isChecked}
setIsChecked={setIsChecked}
selectedBrands={selectedBrands} selectedBrands={selectedBrands}
setSelectedBrands={setSelectedBrands}
rangePrice={rangePrice} rangePrice={rangePrice}
setRangePrice={setRangePrice}
sortBy={sortBy} sortBy={sortBy}
setIsRangePrice={setIsRangePrice}
isRangePrice={isRangePrice} isRangePrice={isRangePrice}
setSortBy={setSortBy}
/> />
<div className="text-right px-8 py-5">
<h1 className="font-medium text-sm ">{decodedName}</h1>
</div>
<div> <div>
{true ? ( {true ? (
<InfiniteScroll <InfiniteScroll

View File

@ -0,0 +1,482 @@
"use client";
import NavBarDownCart from "@comp/Carts/component/NavBarDownCart/page";
import Navbar from "@comp/Navbar/page";
import PersianNumber from "plugins/PersianNumber";
import { useContext, useEffect, useState } from "react";
import AppContext from "@ctx/AppContext";
import ap from "@img/ap.png";
import zarin from "@img/zarin.png";
import Image from "next/image";
import { useRouter } from "next/navigation";
import Chapar from "plugins/Chapar";
import BottomSheetDiscount from "plugins/bottomSheet/BottomSheetDiscount";
import { toast } from "react-toastify";
const CheckoutData = () => {
const CTX = useContext(AppContext);
const [shippingData, setShippingData] = useState([]);
const [shippingId, setShippingID] = useState(null);
const [addressData, setAddressData] = useState([]);
const [addressId, setAddressId] = useState(null);
const [permissionGoPay, setPermissionGoPay] = useState(false);
const router = useRouter();
const checkOutData = CTX.state.checkOutData;
const body = {
addressId: addressData[addressId]?.id,
orderId: checkOutData?.id,
shippingId: shippingData[shippingId]?.id,
};
console.log(body);
const GetShippingData = async () => {
try {
const data = await Chapar.get(
`${process.env.NEXT_PUBLIC_API_URL}/warehouse/shipping?page=0`
);
setShippingData(data);
} catch ({ error, status }) {
toast.error(`${error?.response?.data?.message}`, {
position: "bottom-right",
closeOnClick: true,
});
}
};
const handleShippingID = async (index) => {
if (addressId !== null) {
setShippingID(index);
try {
const data = await Chapar.post(
`${process.env.NEXT_PUBLIC_API_URL}/order/bag/shipping/${checkOutData?.id}`,
JSON.stringify({
addressId: addressData[addressId]?.id,
orderId: checkOutData?.id,
shippingId: shippingData[index]?.id,
}),
{
headers: {
Authorization: localStorage.getItem("token"),
},
}
);
CTX.setCheckOutData(data);
setPermissionGoPay(true);
console.log(data);
} catch ({ error, status }) {
toast.error(`${error?.response?.data?.message}`, {
position: "bottom-right",
closeOnClick: true,
});
}
} else {
toast.error(`ابتدا آدرس را انتحاب کنید`, {
position: "bottom-right",
closeOnClick: true,
});
}
};
const handleGoPayment = async () => {
try {
const data = await Chapar.post(
`${process.env.NEXT_PUBLIC_API_URL}/order/bag/payment/${checkOutData?.id}?paymentMethod=1`,
{
headers: {
Authorization: localStorage.getItem("token"),
},
}
);
router.push(data?.paymentUrl);
} catch ({ error, status }) {
toast.error(`${error?.response?.data?.message}`, {
position: "bottom-right",
closeOnClick: true,
});
}
};
useEffect(() => {
if (shippingData.length <= 0) {
GetShippingData();
}
if (CTX.state.addressData <= 0) {
CTX.fetchAddressUser();
}
}, [checkOutData]);
useEffect(() => {
setAddressData(CTX.state.addressData);
}, [CTX.state.addressData]);
useEffect(() => {
if (CTX.state.checkOutData.length <= 0) {
router.push("/cart");
}
setPermissionGoPay(false);
}, []);
return (
<>
<div className=" pb-20">
<Navbar theme={1} />
<div className="xs:w-full lg:w-4/12 mx-auto">
<div className="text-right flex rtl justify-between border-y-[1px] border-gray-100 mt-3 px-4 ">
<p className="mb-0 !text-sm font-semibold py-4">آدس ها</p>
<div
className="bg-primary-200 w-fit h-fit relative my-3 p-1 rounded-lg"
onClick={() => CTX.setBottomSheetAddressOpen(true)}
>
<p className="mb-0 text-[11px] text-white rtl">
افزودن آدرس جدید
</p>
</div>
</div>
{addressData.map((e, index) => (
<div
className={`flex rtl px-3 py-4 border-2 border-transparent tr03 mx-2 mt-3 cursor-pointer ${
addressId == index
? "border-2 !border-green-600 rounded-lg bg-green-50"
: ""
}`}
onClick={() => setAddressId(index)}
key={index}
>
<div>
<svg
width="20"
height="20"
viewBox="0 0 188 264"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="opacity-70 mx-auto "
>
<path
d="M94 10.125C47.418 10.125 9.625 46.0957 9.625 90.3984C9.625 141.375 65.875 222.158 86.5293 250.061C87.3866 251.238 88.5103 252.197 89.8087 252.858C91.107 253.518 92.5432 253.863 94 253.863C95.4568 253.863 96.893 253.518 98.1913 252.858C99.4897 252.197 100.613 251.238 101.471 250.061C122.125 222.17 178.375 141.416 178.375 90.3984C178.375 46.0957 140.582 10.125 94 10.125Z"
stroke="black"
stroke-width="18.75"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M94 122.625C109.533 122.625 122.125 110.033 122.125 94.5C122.125 78.967 109.533 66.375 94 66.375C78.467 66.375 65.875 78.967 65.875 94.5C65.875 110.033 78.467 122.625 94 122.625Z"
stroke="black"
stroke-opacity="0.37"
stroke-width="18.75"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</div>
<div className="mx-2">
<p className="mb-0 text-[12px] text-gray-500"> {e.address} </p>
</div>
</div>
))}
<div className="text-right flex rtl justify-between border-y-[1px] border-gray-100 mt-3 px-4 ">
<p className="mb-0 text-sm font-semibold py-4">زمان و نحوه ارسال</p>
<div className="border border-gray-300 w-fit h-fit relative my-3 p-1 rounded-lg">
<div className="flex">
<div>
<svg
width="15"
height="15"
viewBox="0 0 251 200"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="opacity-60"
>
<path
d="M105.625 143.75C110.625 148.75 117.083 151.2 125 151.1C132.917 151 138.75 148.133 142.5 142.5L212.5 37.5L107.5 107.5C101.875 111.25 98.9083 116.979 98.6 124.688C98.2917 132.396 100.633 138.75 105.625 143.75ZM125 0C137.292 0 149.117 1.71667 160.475 5.15C171.833 8.58334 182.508 13.7417 192.5 20.625L168.75 35.625C161.875 32.0833 154.742 29.4292 147.35 27.6625C139.958 25.8958 132.508 25.0083 125 25C97.2917 25 73.6958 34.7417 54.2125 54.225C34.7292 73.7083 24.9917 97.3 25 125C25 133.75 26.2 142.396 28.6 150.938C31 159.479 34.3833 167.5 38.75 175H211.25C216.042 167.083 219.533 158.854 221.725 150.312C223.917 141.771 225.008 132.917 225 123.75C225 116.25 224.113 108.958 222.338 101.875C220.563 94.7917 217.908 87.9167 214.375 81.25L229.375 57.5C235.625 67.2917 240.575 77.7083 244.225 88.75C247.875 99.7917 249.8 111.25 250 123.125C250.208 135 248.854 146.354 245.938 157.188C243.021 168.021 238.75 178.333 233.125 188.125C230.833 191.875 227.708 194.792 223.75 196.875C219.792 198.958 215.625 200 211.25 200H38.75C34.375 200 30.2083 198.958 26.25 196.875C22.2917 194.792 19.1667 191.875 16.875 188.125C11.4583 178.75 7.29167 168.804 4.375 158.288C1.45833 147.771 0 136.675 0 125C0 107.708 3.28334 91.5125 9.85 76.4125C16.4167 61.3125 25.375 48.0833 36.725 36.725C48.075 25.3667 61.35 16.4083 76.55 9.85C91.75 3.29167 107.9 0.00833333 125 0Z"
fill="black"
fill-opacity="0.61"
/>
</svg>
</div>
<p className="mb-0 text-[11px] rtl mr-2 text-gray-600">
سریع ترین زمان ارسال
</p>
</div>
</div>
</div>
<div>
{shippingData?.map((e, index) => (
<div
className={`flex rtl px-2 py-2 mx-2 mt-5 border-2 border-transparent tr03 cursor-pointer ${
shippingId == index
? "border-2 !border-green-600 rounded-lg bg-green-50"
: ""
}`}
onClick={() => handleShippingID(index)}
key={index}
>
<div>
<svg
width="25"
height="25"
viewBox="0 0 234 244"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="mx-auto opacity-70 mt-2"
>
<path
d="M65.8246 162.813C66.1529 163.999 66.7117 165.11 67.4692 166.081C68.2267 167.052 69.168 167.864 70.2394 168.471C71.3107 169.078 72.4911 169.468 73.7133 169.619C74.9354 169.77 76.1752 169.678 77.3621 169.35C78.5489 169.022 79.6594 168.463 80.6303 167.705C81.6011 166.948 82.4133 166.007 83.0203 164.935C83.6274 163.864 84.0175 162.683 84.1683 161.461C84.3192 160.239 84.2279 158.999 83.8996 157.813L65.8246 162.813ZM11.9996 31.0625C10.8081 30.7145 9.55935 30.6066 8.32582 30.745C7.09228 30.8834 5.89851 31.2654 4.81377 31.8688C3.72903 32.4722 2.77491 33.285 2.00678 34.26C1.23864 35.2351 0.671788 36.353 0.3391 37.5488C0.00641134 38.7447 -0.0854865 39.9947 0.0687392 41.2264C0.222965 42.458 0.620244 43.6468 1.23752 44.7237C1.8548 45.8006 2.6798 46.7442 3.66463 47.4997C4.64947 48.2553 5.77454 48.8077 6.97458 49.125L11.9996 31.0625ZM224.35 168.563C225.57 168.28 226.722 167.756 227.737 167.021C228.752 166.286 229.609 165.355 230.257 164.284C230.906 163.212 231.334 162.021 231.515 160.781C231.695 159.541 231.626 158.278 231.31 157.065C230.994 155.853 230.438 154.716 229.676 153.722C228.913 152.728 227.959 151.897 226.869 151.278C225.78 150.659 224.578 150.264 223.333 150.118C222.089 149.971 220.828 150.076 219.625 150.425L224.35 168.563ZM99.4621 191.488C103.337 205.488 94.8371 220.275 79.7871 224.188L84.4996 242.325C109.212 235.913 124.312 211.05 117.537 186.488L99.4621 191.488ZM79.7871 224.188C64.6371 228.125 49.4371 219.325 45.5371 205.2L27.4621 210.2C34.2121 234.638 59.8871 248.725 84.4996 242.325L79.7871 224.188ZM45.5371 205.2C41.6621 191.2 50.1621 176.413 65.2121 172.5L60.4996 154.375C35.7871 160.788 20.6746 185.638 27.4621 210.2L45.5371 205.2ZM65.2121 172.5C80.3621 168.563 95.5621 177.363 99.4621 191.488L117.537 186.488C110.787 162.05 85.1121 147.963 60.4996 154.363L65.2121 172.5ZM83.8996 157.813L56.9996 60.4375L38.9246 65.4375L65.8246 162.813L83.8996 157.813ZM33.2996 36.9625L11.9996 31.0625L6.97458 49.125L28.2871 55.0375L33.2996 36.9625ZM56.9996 60.4375C55.4136 54.8107 52.3969 49.6907 48.2434 45.5766C44.0899 41.4625 38.9413 38.4948 33.2996 36.9625L28.3121 55.0375C33.6246 56.5125 37.5746 60.55 38.9246 65.4375L56.9996 60.4375ZM110.875 198.063L224.35 168.563L219.637 150.425L106.15 179.925L110.875 198.063Z"
fill="black"
/>
<path
d="M211.562 49.9502C205.5 28.0002 202.462 17.0252 193.562 12.0377C184.637 7.03772 173.325 9.98772 150.7 15.8752L126.7 22.1002C104.075 27.9752 92.7623 30.9252 87.6248 39.5752C82.4748 48.2127 85.4998 59.1877 91.5623 81.1252L97.9998 104.413C104.062 126.35 107.087 137.325 116 142.313C124.912 147.313 136.225 144.363 158.85 138.488L182.85 132.238C205.475 126.363 216.787 123.425 221.937 114.788C224.762 110.038 225.125 104.588 223.862 97.0002"
stroke="black"
stroke-opacity="0.44"
stroke-width="18.75"
stroke-linecap="round"
/>
</svg>
</div>
<div className="mx-2">
<h3 className="mb-0 text-sm text-right font-medium text-primary-500 ">
{e.name}{" "}
</h3>
<p className="mb-0 text-[12px] text-gray-500">
{" "}
حداکثر
<PersianNumber
number={e.workingDays}
style={"text-gray-600 mx-1"}
/>
روز کاری
<small className="mx-2">|</small> هزینه ارسال
<PersianNumber
number={(e.deliveryCost / 10)?.toLocaleString()}
style={"text-gray-600 mx-1"}
/>
هزار تومان
</p>
</div>
</div>
))}
</div>
<div className="text-right flex rtl justify-between border-y-[1px] border-gray-100 mt-3 px-4 ">
<p className="mb-0 text-sm font-semibold py-4">روش پرداخت</p>
</div>
<div>
<div
className={`flex rtl px-2 py-2 mx-2 border-2 border-transparent mt-5 ${
true ? "border-2 !border-green-600 rounded-lg bg-green-50" : ""
}`}
>
<div>
<Image src={zarin} className="w-[50px]" alt="" />
</div>
<div className="mx-2">
<h3 className="mb-0 text-sm text-right font-medium text-primary-500 ">
پرداخت آنلاین
</h3>
<p className="mb-0 text-[12px] text-gray-500">زرین پال</p>
</div>
</div>
<div className="flex rtl px-2 py-1 mx-2 mt-5 opacity-40">
<div>
<Image src={ap} className="w-[45px]" alt="" />
</div>
<div className="mx-2">
<h3 className="mb-0 text-sm text-right font-medium text-primary-500 ">
پرداخت آنلاین (به زودی)
</h3>
<p className="mb-0 text-[12px] text-gray-500">آسان پرداخت</p>
</div>
</div>
<div
className={`flex justify-between rtl px-3 mt-5 ${
checkOutData?.discountCode != "" ? "" : ""
}`}
onClick={() => {
if (checkOutData?.discountCode == "") {
CTX.setBottomSheetDiscountOpen(true);
}
}}
>
<div className="flex">
<div>
<svg
width="25"
height="25"
viewBox="0 0 244 194"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="opacity-70 mt-2"
>
<path
d="M122 93.875V100.125M122 47V53.25M122 140.75V147M209.5 184.5C216.13 184.5 222.489 181.866 227.178 177.178C231.866 172.489 234.5 166.13 234.5 159.5V122C227.87 122 221.511 119.366 216.822 114.678C212.134 109.989 209.5 103.63 209.5 97C209.5 90.3696 212.134 84.0107 216.822 79.3223C221.511 74.6339 227.87 72 234.5 72V34.5C234.5 27.8696 231.866 21.5107 227.178 16.8223C222.489 12.1339 216.13 9.5 209.5 9.5H34.5C27.8696 9.5 21.5107 12.1339 16.8223 16.8223C12.1339 21.5107 9.5 27.8696 9.5 34.5V72C16.1304 72 22.4893 74.6339 27.1777 79.3223C31.8661 84.0107 34.5 90.3696 34.5 97C34.5 103.63 31.8661 109.989 27.1777 114.678C22.4893 119.366 16.1304 122 9.5 122V159.5C9.5 166.13 12.1339 172.489 16.8223 177.178C21.5107 181.866 27.8696 184.5 34.5 184.5H209.5Z"
stroke="black"
stroke-opacity="0.54"
stroke-width="18.75"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</div>
<div className="mx-2">
<h3 className="mb-0 text-sm text-right font-medium text-primary-500 ">
افزودن کد تخفیف{" "}
</h3>
<p className="mb-0 text-[12px] text-gray-500">
کد تخفیف خود را وارد کنید
</p>
</div>
</div>
{checkOutData?.discountCode == "" ? (
<div className="pl-3">
<span className="text-[30px] opacity-60">+</span>
</div>
) : (
<div className="text-right flex justify-end px-2 py-1 mx-2">
<p className="text-green-600 mb-0 text-[12px] ">
کد تخفیف ثبت شد{" "}
</p>
</div>
)}
</div>
</div>
<div className="">
<div className="text-right flex rtl justify-between border-y-[1px] border-gray-100 my-3 px-4 ">
<p className="mb-0 text-sm font-semibold py-4">حساب نهایی</p>
<div className="bg-primary-200 w-fit h-fit relative my-3 p-1 rounded-lg">
<p className="mb-0 text-[11px] text-white rtl">مشاهده اقلام</p>
</div>
</div>
<div>
<div className="flex justify-between rtl px-4">
<p className="mb-0 text-[12px] text-gray-500">قیمت </p>
<div className="flex justify-center">
<p className="mb-0 ">
<PersianNumber
number={(
checkOutData?.totalProductsPrice / 10
)?.toLocaleString()}
style={"!text-[14px] !font-semibold"}
/>
</p>
<small className="text-gray-500 text-[12px] mt-1 mx-1">
{" "}
تومان
</small>
</div>
</div>
<div className="flex justify-between rtl my-2 px-4">
<p className="mb-0 text-[12px] text-gray-500">تخفیف محصول</p>
<div className="flex justify-center">
<p className="mb-0 ">
<PersianNumber
number={(
checkOutData?.discountPrice / 10
)?.toLocaleString()}
style={"!text-[14px] !font-semibold"}
/>
</p>
<small className="text-gray-500 text-[12px] mt-1 mx-1">
{" "}
تومان
</small>
</div>
</div>
<div className="flex justify-between rtl my-2 px-4">
<p className="mb-0 text-[12px] text-gray-500">
هزینه بسته بندی
</p>
<div className="flex justify-center">
<p className="mb-0 ">
<PersianNumber
number={(
checkOutData?.packingPrice / 10
)?.toLocaleString()}
style={"!text-[14px] !font-semibold"}
/>
</p>
<small className="text-gray-500 text-[12px] mt-1 mx-1">
{" "}
تومان
</small>
</div>
</div>
<div className="flex justify-between rtl my-2 px-4">
<p className="mb-0 text-[12px] text-gray-500">هزینه ارسال</p>
<div className="flex justify-center">
<p className="mb-0 ">
<PersianNumber
number={(
checkOutData?.deliveryPrice / 10
)?.toLocaleString()}
style={"!text-[14px] !font-semibold"}
/>
</p>
<small className="text-gray-500 text-[12px] mt-1 mx-1">
{" "}
تومان
</small>
</div>
</div>
<div className="flex justify-between bg-primary-100 p-3 rtl my-2">
<p className="mb-0 text-sm text-primary-600 font-bold">
قابل پرداخت
</p>
<div className="flex justify-center">
<p className="mb-0 ">
<PersianNumber
number={(checkOutData?.totalPrice / 10)?.toLocaleString()}
style={"!text-[14px] !font-semibold text-primary-800"}
/>
</p>
<small className="text-gray-500 text-[12px] mt-1 mx-1">
{" "}
تومان
</small>
</div>
</div>
</div>
</div>
</div>
<NavBarDownCart
calculateTotalCost={checkOutData.totalPrice / 10}
event={() => handleGoPayment()}
permissionGoPay={permissionGoPay}
/>
</div>
<BottomSheetDiscount orderId={checkOutData?.id} />
</>
);
};
export default CheckoutData;

View File

@ -0,0 +1,81 @@
"use client";
import Footer from "@comp/Footer/page";
import Navbar from "@comp/Navbar/page";
import { useEffect, useState } from "react";
const FaqData = () => {
const [faq, setFaq] = useState([]);
const [faqSelect, setFaqSelect] = useState(0);
const fetchNavData = async (id) => {
const res = await fetch(`https://jsonplaceholder.typicode.com/comments`);
const post = await res.json();
setFaq(post);
};
useEffect(() => {
fetchNavData();
}, []);
return (
<>
<div className="bg-contact-us ">
<div className=" pb-20">
<Navbar theme={0} />
<div>
<div className="flex justify-center xs:hidden lg:block">
<div className="absolute mr-[-1100px] mt-[-200px]">
<p className="mb-0 text-[300px] opacity-10 font-extrabold text-white ">
{" "}
,
</p>
</div>
</div>
</div>
<div className="my-[80px] ">
<div className="px-5">
<h1 className="text-white font-bold text-center xs:text-[20px] lg:text-[40px]">
پرسشهای متداول
</h1>
</div>
</div>
</div>
</div>
<div className=" xs:px-3 lg:px-20 rtl lg:m-10 xs:m-3 pb-20 ">
{faq?.map((e, index) => (
<div
className={` p-5 w-full rounded-lg my-2 tr03 cursor-pointer ${
faqSelect == index ? "bg-gray-100" : "bg-primary-100"
}`}
onClick={() => setFaqSelect(index)}
key={index}
>
<div className="flex">
<span className="mx-2 text-xl text-gray-900">
{faqSelect == index ? "-" : "+"}
</span>
<h2 className="mb-0 text-gray-700 text-sm text-right mt-1 font-semibold">
{e.name}
</h2>
</div>
{faqSelect == index && (
<>
<div className="h-[1px] bg-gray-300 w-[120px] mr-5 m-5 "></div>
<p className="mb-0 text-right text-gray-500 text-sm">
{e.body}
</p>
</>
)}
</div>
))}
</div>
<Footer />
</>
);
};
export default FaqData;

View File

@ -0,0 +1,405 @@
"use client";
import Footer from "@comp/Footer/page";
import Navbar from "@comp/Navbar/page";
import GalleryBox from "plugins/Gallery/page";
import { useEffect, useState } from "react";
import AddToCart from "@comp/Cards/Components/AddToCart/page";
import Image from "next/image";
import PersianNumber from "plugins/PersianNumber";
import logo from "../../../public/images/logo.png";
const ProductData = ({ params }) => {
const [product, setProduct] = useState([]);
const [specificationsHeader, setSpecificationsHeader] = useState([]);
const [productBarDetail, setProductBarDetail] = useState(0);
const fetchPost = async (id) => {
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/product/${id}`);
const post = await res.json();
setProduct(post.product);
};
console.log("product", product);
const displaySpecifications = (specs) => {
let data = [];
if (specs?.length > 3) {
specs?.slice(0, 3).forEach((spec) => {
const { title, value } = spec;
data.push(`${title}: ${value}`);
});
} else {
specs?.forEach((spec) => {
const { title, value } = spec;
data.push(`${title}: ${value}`);
});
}
setSpecificationsHeader(data); // You can replace console.log with any method to display the content in your header
};
const scrollToSection = (id) => {
const element = document.getElementById(id);
if (element) {
const offset = -80; // Adjust this value as needed
window.scrollTo({
top: element.offsetTop + offset,
behavior: "smooth",
});
}
};
useEffect(() => {
fetchPost(params.id[0]);
}, []);
useEffect(() => {
displaySpecifications(product?.specifications);
}, [product]);
return (
<>
<Navbar theme={1} />
<div className=" py-10">
<div className="grid xs:grid-cols-1 lg:grid-cols-8 rtl gap-6 lg:px-20">
<div className="lg:col-span-3 ">
<GalleryBox file={product.files} />
</div>
<div className="lg:col-span-3 xs:px-5 lg:px-0 ">
<div className="text-right mt-7">
<h1 className="text-lg font-semibold ">{product.persianName} </h1>
<p className="mb-0 text-sm text-gray-400">
{product?.englishName}{" "}
</p>
</div>
<div className="flex my-4">
<div className="bg-primary-400 rounded-full py-1 px-3 ml-2">
<p className="mb-0 text-sm text-white ">اصالت کالای </p>
</div>
{product?.hasDiscount && (
<div className="bg-danger-100 rounded-full py-1 px-3 ml-2">
<p className="mb-0 text-sm text-white ">بمب امروز </p>
</div>
)}
{!product?.warranty == "" && (
<div className="bg-secondary-500 rounded-full py-1 px-3 ml-2">
<p className="mb-0 text-sm text-white ">
{product?.warranty}
</p>
</div>
)}
</div>
{/* <div className="flex my-5">
<div className="w-[30px] h-[30px] rounded-full bg-red-800 border-[5px] border-white shadow mr-2 cursor-pointer "></div>
<div className="w-[30px] h-[30px] rounded-full bg-red-700 border-[5px] border-white shadow mr-2 cursor-pointer "></div>
<div className="w-[30px] h-[30px] rounded-full bg-red-600 border-[5px] border-white shadow mr-2 cursor-pointer "></div>
<div className="w-[30px] h-[30px] rounded-full bg-red-500 border-[5px] border-green-300 scale-110 shadow mr-2 cursor-pointer "></div>
<div className="w-[30px] h-[30px] rounded-full bg-red-400 border-[5px] border-white shadow mr-2 cursor-pointer "></div>
<div className="w-[30px] h-[30px] rounded-full bg-red-300 border-[5px] border-white shadow mr-2 cursor-pointer "></div>
<div className="w-[30px] h-[30px] rounded-full bg-red-200 border-[5px] border-white shadow mr-2 cursor-pointer "></div>
</div> */}
<div>
<div className="text-right mt-3 flex justify-between">
<h2 className="mb-0 text-gray-400 text-sm">
{product?.summery}
</h2>
</div>
</div>
<ul className="mt-3 px-3">
{specificationsHeader.map((e, index) => (
<li className=" flex my-2" key={index}>
<div className="w-[10px] h-[10px] relative rounded-full bg-primary-500 mt-1"></div>
<p className="mb-0 w-full text-sm text-gray-700 mx-2 ">
{e}
</p>
</li>
))}
</ul>
</div>
{/* xs:sticky lg:relative xs:top-[60px] lg:top-0 ==> sticky for price=================== */}
<div className=" w-9/12 lg:col-span-2 sticky top-[80px] xs:hidden lg:block ">
<div className="p-3 h-fit border-[1px] border-gray-300 rounded-xl ">
<div className="flex justify-center">
<div className="w-[130px]">
{product.files?.length > 0 ? (
<Image
src={`${process.env.NEXT_PUBLIC_STORAGE_URL}/${
product.files && product.files[0].fileLocation
}`}
width={350}
height={350}
className=" mx-auto !object-cover"
onClick={() => CTX.setIsOpenLightBox(true)}
alt=""
/>
) : (
<div className="xs:!w-[85px] lg:!w-[85px] my-10 ">
<Image
src={logo}
className="xs:!w-[70px] lg:!w-[70px] mx-auto !object-cover opacity-25 mt-5"
alt=""
/>
</div>
)}
</div>
</div>
<div className="text-center">
<p className="mb-0 text-sm text-gray-500">
{product.persianName}{" "}
</p>
</div>
<div className="w-6/12 mx-auto h-[1px] bg-gray-200 mt-4"></div>
<div className="flex justify-center mt-3">
<div>
<svg
width="15"
height="15"
viewBox="0 0 226 264"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="ml-1 mt-[2px]"
>
<path
d="M94.25 137.531L69.9687 113.25L56.75 126.469L94.25 163.969L169.25 88.9687L156.031 75.75L94.25 137.531Z"
fill="black"
/>
<path
d="M113 263.25L55.1001 232.378C38.5938 223.597 24.7904 210.486 15.1712 194.454C5.552 178.421 0.48019 160.072 0.500058 141.375V19.5C0.505022 14.5287 2.48206 9.76246 5.99729 6.24723C9.51252 2.732 14.2788 0.754964 19.2501 0.75H206.75C211.721 0.754964 216.488 2.732 220.003 6.24723C223.518 9.76246 225.495 14.5287 225.5 19.5V141.375C225.52 160.072 220.448 178.421 210.829 194.454C201.21 210.486 187.406 223.597 170.9 232.378L113 263.25ZM19.2501 19.5V141.375C19.2345 156.673 23.3854 171.687 31.2572 184.804C39.129 197.922 50.4245 208.648 63.9313 215.831L113 241.997L162.069 215.841C175.577 208.656 186.873 197.929 194.745 184.81C202.617 171.69 206.767 156.675 206.75 141.375V19.5H19.2501Z"
fill="black"
/>
</svg>
</div>
<p className="mb-0 text-[12px] font-bold">
گارانتی{" "}
<small className=" text-primary-500 text-[12px]">اصالت</small>{" "}
و{" "}
<small className=" text-primary-500 text-[12px]">
سلامت فیزیکی کالا
</small>
</p>
</div>
<div className="w-6/12 mx-auto h-[1px] bg-gray-200 mt-4"></div>
<div className=" mt-4 flex justify-between ">
{true ? (
<div className="flex justify-end">
<div className="mb-0 font-bold text-sm absolute mt-[-11px] ml-[0px] right-0 mr-[13px] text-red-600 flex rtl">
<del>
<PersianNumber
number={(product?.cost / 10).toLocaleString()}
style={"text-[13px] opacity-40 "}
/>
</del>
</div>
<div className="flex rtl mt-[8px]">
{" "}
<p className="mb-0 font-bold">
<PersianNumber
number={(
product?.costWithDiscount / 10
).toLocaleString()}
/>
</p>
<small className="mr-1 mt-[3px]">تومان</small>
</div>
</div>
) : (
<div className="flex rtl mt-[3px]">
{" "}
<p className="mb-0 font-bold text-lg">
<PersianNumber
number={(data?.cost / 10).toLocaleString()}
/>
</p>
<small className="mr-1 mt-[6px]">تومان</small>
</div>
)}
<AddToCart data={product} theme={2} />
</div>
</div>
</div>
<div className="lg:col-span-6">
<div className="xs:px-[15px] lg:px-[100px]">
<div className="bg-gray-200 rounded-full xs:p-2 lg:p-3 flex w-fit ">
<div
className={` rounded-full p-3 cursor-pointer tr03 ${
productBarDetail == 0 ? "bg-primary-500 text-gray-100" : ""
}`}
onClick={() => {
setProductBarDetail(0);
scrollToSection("section0");
}}
>
<p className=" xs:hidden lg:block mb-0 text-[12px] ">
مشخصات محصول
</p>
<p className=" xs:block lg:hidden mb-0 text-[12px]">مشخصات</p>
</div>
<div
className={` rounded-full p-3 cursor-pointer tr03 ${
productBarDetail == 1 ? "bg-primary-500 text-gray-100" : ""
}`}
onClick={() => {
setProductBarDetail(1);
scrollToSection("section1");
}}
>
<p className="mb-0 text-[13px] ">روش استفاده</p>
</div>
<div
className={` rounded-full p-3 cursor-pointer tr03 ${
productBarDetail == 2 ? "bg-primary-500 text-gray-100" : ""
}`}
onClick={() => {
setProductBarDetail(2);
scrollToSection("section2");
}}
>
<p className="mb-0 text-[13px] ">نقد و بررسی</p>
</div>
<div
className={` rounded-full p-3 cursor-pointer tr03 ${
productBarDetail == 3 ? "bg-primary-500 text-gray-100" : ""
}`}
onClick={() => {
setProductBarDetail(3);
scrollToSection("section3");
}}
>
<p className=" xs:hidden lg:block mb-0 text-[13px] ">
دیدگاه مخاطبان
</p>
<p className=" xs:block lg:hidden mb-0 text-[13px] ">
مخاطبان
</p>
</div>
</div>
<div id="section0">
<h3 className=" text-sm text-gray-400 mt-7 mb-2">
مشخصات محصول
</h3>
<div className="min-w-[200px] mt-5 rounded-xl overflow-hidden border rtl ">
{product?.specifications?.map((e, index) => (
<div
className={
index % 2 === 0 ? "bg-gray-50 p-3" : "bg-gray-100 p-3"
}
key={index}
>
<p className="mb-0 text-sm text-gray-600">
{e.title}:
<small className="text-sm text-gray-800 font-bold ">
{" "}
{e.value}{" "}
</small>
</p>
</div>
))}
</div>
</div>
<div id="section1">
<h3 className=" text-sm text-gray-400 mt-7 mb-2">
روش استفاده
</h3>
<div className="border p-5 rounded-lg">
<div className="flex justify-center py-5">
<div className="bg-white shadow w-fit rounded-full text-sm p-4">
چیزی یافت نشد
</div>
</div>
</div>{" "}
</div>
<div id="section2">
<h3 className=" text-sm text-gray-400 mt-7 mb-2">
نقد و برسی{" "}
</h3>
<div className="border p-5 rounded-lg">
<div className="flex justify-center py-5">
<div className="bg-white shadow w-fit rounded-full text-sm p-4">
چیزی یافت نشد
</div>
</div>
</div>{" "}
</div>
<div id="section3">
<h3 className=" text-sm text-gray-400 mt-7 mb-2">
دیدگاه مخاطبان{" "}
</h3>
<div className="border p-5 rounded-lg">
<div className="flex justify-center py-5">
<div className="bg-white shadow w-fit rounded-full text-sm p-4">
چیزی یافت نشد
</div>
</div>
</div>{" "}
</div>
</div>
<div className="xs:block lg:hidden sticky bottom-0 ">
<div className="w-full bg-[white] p-2 border-t-[1px] border-gray-100 mt-[30px]">
<div className="py-4 flex ltr justify-between px-4 relative">
{product?.hasDiscount ? (
<>
<p className="mb-0 font-bold text-sm absolute ml-[33px] opacity-30 mt-[-5px] text-red-600">
<del>
<PersianNumber
number={(product?.cost / 10).toLocaleString()}
style="!text-[11px]"
/>
</del>
</p>
<div className="flex rtl mt-[8px]">
{" "}
<p className="mb-0 font-bold">
<PersianNumber
number={(
product?.costWithDiscount / 10
).toLocaleString()}
/>
</p>
<small className="mr-1 mt-[3px]">تومان</small>
</div>
</>
) : (
<div className="flex rtl mt-[3px]">
{" "}
<p className="mb-0 font-bold text-lg">
<PersianNumber
number={(product?.cost / 10).toLocaleString()}
/>
</p>
<small className="mr-1 mt-[6px]">تومان</small>
</div>
)}
<AddToCart data={product} theme={2} />
</div>
</div>
</div>
</div>
</div>
</div>
<Footer />
</>
);
};
export default ProductData;

View File

@ -0,0 +1,366 @@
"use client";
import AppContext from "@ctx/AppContext";
import Chapar from "plugins/Chapar";
import Loading from "plugins/Loading/page";
import BottomSheetAddress from "plugins/bottomSheet/BottomSheetAddress";
import BottomSheetLogOut from "plugins/bottomSheet/BottomSheetLogOut";
import { useEffect, useState } from "react";
import "react-image-gallery/styles/css/image-gallery.css";
import "react-image-lightbox/style.css";
import "react-spring-bottom-sheet/dist/style.css";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import "swiper/css";
import "../../../style/fontiran.css";
import "../../../style/globals.css";
import Goftino from "plugins/Goftino/page";
import { useRouter } from "next/navigation";
const RootData = ({ children }) => {
const [cart, setCart] = useState([]);
const [products, setProducts] = useState([]);
const [pager, setPager] = useState([]);
const [filter, setFilter] = useState([]);
const [navData, setNavData] = useState([]);
const [brands, setBrands] = useState([]);
const [loading, setLoading] = useState(false);
const [closeNavbar, setCloseNavbar] = useState(false);
const [bottomSheetCartOpen, setBottomSheetCartOpen] = useState(false);
const [bottomSheetFilterOpen, setBottomSheetFilterOpen] = useState(false);
const [bottomSheetDiscountOpen, setBottomSheetDiscountOpen] = useState(false);
const [bottomSheetAddressOpen, setBottomSheetAddressOpen] = useState(false);
const [bottomSheetLogOutOpen, setBottomSheetLogOutOpen] = useState(false);
const [bottomSheetDeleteAddressOpen, setBottomSheetDeleteAddressOpen] =
useState(false);
const [checkOutData, setCheckOutData] = useState([]);
const [addressData, setAddressData] = useState([]);
const [profile, setProfile] = useState([]);
const [stopProducts, setStopProducts] = useState(false);
const [pageGetProducts, setPageGetProducts] = useState(0);
const [isMobile, setIsMobile] = useState(false);
const [isOpenLightBox, setIsOpenLightBox] = useState(false);
const [isChecked, setIsChecked] = useState(false);
const [selectedBrands, setSelectedBrands] = useState([]);
const [rangePrice, setRangePrice] = useState([1000, 100]);
const [isRangePrice, setIsRangePrice] = useState(false);
const [sortBy, setSortBy] = useState(-1);
const router = useRouter();
const AddItemToCart = (
id,
persianName,
cost,
costWithDiscount,
mainImage,
hasDiscount,
maxOrderCount
) => {
setCart((prevCart) => {
// Check if the item is already in the cart
const existingItem = prevCart.find((item) => item.id === id);
let updatedCart;
if (existingItem) {
// If the item is already in the cart, update its count
if (existingItem.count < maxOrderCount) {
updatedCart = prevCart.map((item) =>
item.id === id ? { ...item, count: item.count + 1 } : item
);
} else {
// Notify user if maxOrderCount is exceeded
toast.error(
`
نمیتوانید بیشتراز
${maxOrderCount}
عدد ثبت کنید `,
{
position: "bottom-right",
closeOnClick: true,
}
);
updatedCart = prevCart;
}
} else {
// If the item is not in the cart, add it with a count of 1
updatedCart = [
...prevCart,
{
id,
count: 1,
persianName,
cost,
costWithDiscount,
mainImage,
hasDiscount,
maxOrderCount,
},
];
}
// Store the updated cart in local storage
localStorage.setItem("cart", JSON.stringify(updatedCart));
// Return the updated cart
return updatedCart;
});
};
const RemoveItemFromCart = (id) => {
setCart((prevCart) => {
// Check if the item is already in the cart
const existingItem = prevCart.find((item) => item.id === id);
if (existingItem) {
// If the item is already in the cart
if (existingItem.count === 1) {
// If the item count is 1, remove it from the cart
const updatedCart = prevCart.filter((item) => item.id !== id);
// Store the updated cart in local storage
localStorage.setItem("cart", JSON.stringify(updatedCart));
// Return the updated cart
return updatedCart;
} else {
// If the item count is greater than 1, update its count
const updatedCart = prevCart.map((item) =>
item.id === id ? { ...item, count: item.count - 1 } : item
);
// Store the updated cart in local storage
localStorage.setItem("cart", JSON.stringify(updatedCart));
// Return the updated cart
return updatedCart;
}
} else {
// If the item is not in the cart, do nothing
return prevCart;
}
});
};
const fetchNavData = async (id) => {
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/product/category?sortByMain=true`
);
const post = await res.json();
setNavData(post);
};
const fetchProducts = async (
pageGetProducts,
id,
selectedBrands,
isChecked,
minPrice,
maxPrice,
sort,
isRangePrice,
paginationSay
) => {
const brandIds = selectedBrands?.map((brand) => brand.id);
const queryString = `${`page=${pageGetProducts}`}${
id ? `&categoryId=${id}` : ""
}${
brandIds?.length > 0 ? `&brandIds=${brandIds?.join("&brandIds=")}` : ""
}${isChecked ? `&isActive=${isChecked}` : ""}${
isRangePrice ? `&minPrice=${minPrice}` : ""
}${isRangePrice ? `&maxPrice=${maxPrice}` : ""}${
!!sort ? `&sortBy=${sort}` : ""
}`;
const cleanQueryString = decodeURIComponent(
queryString.replace(/\%20/g, " ")
);
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/product?${cleanQueryString}`
);
const post = await res.json();
setPager(post.pager);
setFilter(post.filters);
if (paginationSay) {
// If it's a paginated request (not the first Page)
window.scrollTo({
top: 0,
behavior: "smooth", // Optional: smooth scrolling behavior
});
console.log();
setProducts(post.products);
setStopProducts(true); // Assuming this stops pagination
}
if (post.products.length <= 19) {
// If the length of fetched products is less than or equal to 19, indicating the last Page
setStopProducts(true); // Assuming this stops pagination
}
if (!paginationSay && pageGetProducts == 0) {
// If it's not a paginated request and it's the first Page
setProducts(post.products);
} else if (!paginationSay && pageGetProducts != 0) {
// If it's not a paginated request and it's not the first Page
setProducts((data) => [...(data ? data : []), ...post.products]);
}
};
const fetchAddressUser = async () => {
try {
const data = await Chapar.get(
`${process.env.NEXT_PUBLIC_API_URL}/user/address`,
{
headers: {
Authorization: localStorage.getItem("token"),
},
}
);
setAddressData(data);
} catch ({ error, status }) {
toast.error(`${error?.response?.data?.message}`, {
position: "bottom-right",
closeOnClick: true,
});
setLoading(false);
}
};
const fetchUserInfo = async () => {
try {
const data = await Chapar.get(
`${process.env.NEXT_PUBLIC_API_URL}/user/info`,
{
headers: {
Authorization: localStorage.getItem("token"),
},
}
);
setProfile(data);
} catch ({ error, status }) {
localStorage.removeItem("token");
toast.error(`${error?.response?.data?.message}`, {
position: "bottom-right",
closeOnClick: true,
});
}
};
useEffect(() => {
const storedCart = localStorage.getItem("cart");
const token = localStorage.getItem("token");
if (storedCart) {
setCart(JSON.parse(storedCart));
}
if (token) {
fetchUserInfo();
}
fetchNavData();
}, []);
useEffect(() => {
const mediaQuery = window.matchMedia("(max-width: 768px)"); // Adjust the width according to your mobile breakpoint
const checkDeviceType = (mediaQuery) => {
if (mediaQuery.matches) {
setIsMobile(true);
} else {
setIsMobile(false);
}
};
// Initial check
checkDeviceType(mediaQuery);
// Listen for changes in media query
const listener = () => checkDeviceType(mediaQuery);
mediaQuery.addEventListener("change", listener);
// Clean up
return () => {
mediaQuery.removeEventListener("change", listener);
};
}, []);
return (
<AppContext.Provider
value={{
state: {
cart,
products,
navData,
loading,
brands,
closeNavbar,
bottomSheetCartOpen,
bottomSheetFilterOpen,
bottomSheetDiscountOpen,
bottomSheetAddressOpen,
bottomSheetDeleteAddressOpen,
bottomSheetLogOutOpen,
checkOutData,
addressData,
profile,
stopProducts,
pageGetProducts,
pager,
isMobile,
isOpenLightBox,
filter,
sortBy,
isRangePrice,
rangePrice,
selectedBrands,
isChecked,
},
setCart,
setProducts,
setNavData,
setLoading,
setBrands,
setBottomSheetCartOpen,
setBottomSheetFilterOpen,
setBottomSheetDiscountOpen,
setBottomSheetAddressOpen,
setBottomSheetDeleteAddressOpen,
setBottomSheetLogOutOpen,
setCheckOutData,
setStopProducts,
setProfile,
setPageGetProducts,
setPager,
setIsMobile,
setIsOpenLightBox,
setFilter,
setSortBy,
setIsRangePrice,
setRangePrice,
setSelectedBrands,
setIsChecked,
AddItemToCart,
RemoveItemFromCart,
fetchNavData,
fetchProducts,
setCloseNavbar,
setAddressData,
fetchAddressUser,
}}
>
{children}
<ToastContainer position="bottom-right" closeOnClick={true} rtl />
<Loading />
<BottomSheetAddress />
<BottomSheetLogOut />
<Goftino />
</AppContext.Provider>
);
};
export default RootData;

View File

@ -12,7 +12,7 @@ const CardCart = ({ data }) => {
return ( return (
<div className="group border-t-[1px] border-gray-100 w-full hover:bg-white z-40 tr03 flex rtl pt-2"> <div className="group border-t-[1px] border-gray-100 w-full hover:bg-white z-40 tr03 flex rtl pt-2">
<Link href={`/products/${data.id}`}> <Link href={`/products/${data.id}/${data.persianName}`}>
<div className=" h-fit "> <div className=" h-fit ">
{!!data.mainImage ? ( {!!data.mainImage ? (
<Image <Image
@ -34,7 +34,7 @@ const CardCart = ({ data }) => {
</div> </div>
</Link> </Link>
<div className="p-3 text-right w-full"> <div className="p-3 text-right w-full">
<Link href={`/products/${data.id}`}> <Link href={`/products/${data.id}/${data.persianName}`}>
<p className="mb-0 xs:text-[12px] lg:text-[11px] xl:text-[15px] max-h-[50px] tr03 "> <p className="mb-0 xs:text-[12px] lg:text-[11px] xl:text-[15px] max-h-[50px] tr03 ">
{data?.persianName} {data?.persianName}
</p> </p>

View File

@ -44,7 +44,7 @@ const CardCategories = ({ data }) => {
</div>{" "} </div>{" "}
</div> </div>
)} )}
<Link href={`/products/${data.id}`}> <Link href={`/products/${data.id}/${data.persianName}`}>
<div className="w-full h-fit flex justify-center "> <div className="w-full h-fit flex justify-center ">
{!!data.mainImage ? ( {!!data.mainImage ? (
<Image <Image

View File

@ -14,7 +14,7 @@ const CardCategoriesMobile = ({ data }) => {
return ( return (
<div className="group border-t-[1px] border-gray-200 w-full hover:bg-white z-40 tr03 flex rtl pt-2 px-3"> <div className="group border-t-[1px] border-gray-200 w-full hover:bg-white z-40 tr03 flex rtl pt-2 px-3">
<Link href={`/products/${data.id}`}> <Link href={`/products/${data.id}/${data.persianName}`}>
<div className=" h-fit "> <div className=" h-fit ">
{!!data.mainImage ? ( {!!data.mainImage ? (
<Image <Image
@ -38,7 +38,7 @@ const CardCategoriesMobile = ({ data }) => {
<div className="p-3 text-right w-full"> <div className="p-3 text-right w-full">
{" "} {" "}
<Link href={`/products/${data.id}`}> <Link href={`/products/${data.id}/${data.persianName}`}>
<p className="mb-0 xs:text-[12px] lg:text-[11px] xl:text-[15px] max-h-[50px] tr03 "> <p className="mb-0 xs:text-[12px] lg:text-[11px] xl:text-[15px] max-h-[50px] tr03 ">
{data?.persianName} {data?.persianName}
</p> </p>

View File

@ -12,11 +12,13 @@ import Link from "next/link";
const CardNormal = ({ data }) => { const CardNormal = ({ data }) => {
const CTX = useContext(AppContext); const CTX = useContext(AppContext);
const cart = CTX.state.cart; const cart = CTX.state.cart;
console.log(data);
return ( return (
<> <>
{" "} {" "}
<> <>
<Link href={`/products/${data.id}`}> <Link href={`/products/${data.id}/${data.persianName}`}>
<div <div
className={` tr03 py-2 overflow-hidden xs:h-[200px] lg:h-[230px] border border-gray-100 ${ className={` tr03 py-2 overflow-hidden xs:h-[200px] lg:h-[230px] border border-gray-100 ${
1 == 1 ? "bg-white rounded-xl" : " opacity-70" 1 == 1 ? "bg-white rounded-xl" : " opacity-70"

View File

@ -15,7 +15,7 @@ const CardSurprise = ({ data }) => {
<> <>
{" "} {" "}
<> <>
<Link href={`/products/${data.id}`}> <Link href={`/products/${data.id}/${data.persianName}`}>
<div <div
className={` tr03 py-2 overflow-hidden xs:h-[200px] lg:h-[230px] border border-gray-100 ${ className={` tr03 py-2 overflow-hidden xs:h-[200px] lg:h-[230px] border border-gray-100 ${
1 == 1 ? "bg-white rounded-xl" : " opacity-70" 1 == 1 ? "bg-white rounded-xl" : " opacity-70"

View File

@ -65,7 +65,7 @@ const AddToCart = ({ data, theme }) => {
<> <>
{" "} {" "}
{data?.stock == 0 ? ( {data?.stock == 0 ? (
<div className="bg-red-900 w-fit px-5 h-fit p-2 rounded-xl"> <div className="bg-gray-200 w-fit px-5 h-fit p-2 rounded-xl">
<p className="mb-0 text-[12px] text-center ">اتمام موجودی</p> <p className="mb-0 text-[12px] text-center ">اتمام موجودی</p>
</div> </div>
) : ( ) : (

View File

@ -3,30 +3,33 @@ import AppContext from "@ctx/AppContext";
import { Switch } from "@headlessui/react"; import { Switch } from "@headlessui/react";
import PersianNumber from "plugins/PersianNumber"; import PersianNumber from "plugins/PersianNumber";
import RangeSlider from "plugins/RangeSlider/page"; import RangeSlider from "plugins/RangeSlider/page";
import { useContext, useEffect } from "react"; import { useContext, useEffect, useRef } from "react";
const FilterCategory = ({ const FilterCategory = ({
id, id,
setSelectedBrands,
selectedBrands, selectedBrands,
setIsChecked,
isChecked, isChecked,
rangePrice, rangePrice,
setRangePrice,
sortBy, sortBy,
isRangePrice, isRangePrice,
theme, theme,
filter,
}) => { }) => {
const CTX = useContext(AppContext); const CTX = useContext(AppContext);
const brands = CTX.state.brands; const brands = CTX.state.brands;
const pageGetProducts = CTX.state.pageGetProducts; const pageGetProducts = CTX.state.pageGetProducts;
const isFirstRender = useRef(true);
console.log(filter);
const handleCheckboxChange = () => { const handleCheckboxChange = () => {
setIsChecked(!isChecked); CTX.setIsChecked(!isChecked);
}; };
const handleRangeChange = (values) => { const handleRangeChange = (values) => {
setRangePrice(values); CTX.setIsRangePrice(true);
console.log(values);
CTX.setRangePrice(values);
console.log("rangePrice", rangePrice);
}; };
const handleFilterBrand = (name, id) => { const handleFilterBrand = (name, id) => {
@ -35,19 +38,19 @@ const FilterCategory = ({
if (!isBrandSelected) { if (!isBrandSelected) {
// If the brand is not already selected, add it to the state // If the brand is not already selected, add it to the state
setSelectedBrands((prevBrands) => [...prevBrands, { name, id }]); CTX.setSelectedBrands((prevBrands) => [...prevBrands, { name, id }]);
} else { } else {
// If the brand is already selected, remove it from the state // If the brand is already selected, remove it from the state
setSelectedBrands((prevBrands) => CTX.setSelectedBrands((prevBrands) =>
prevBrands.filter((brand) => brand.id !== id) prevBrands.filter((brand) => brand.id !== id)
); );
} }
}; };
useEffect(() => { const handleRangePriceFilter = () => {
CTX.fetchProducts( CTX.fetchProducts(
pageGetProducts, 0,
id, id[0],
selectedBrands, selectedBrands,
isChecked, isChecked,
rangePrice[0], rangePrice[0],
@ -55,7 +58,32 @@ const FilterCategory = ({
sortBy, sortBy,
isRangePrice isRangePrice
); );
}, [selectedBrands, isChecked]); };
useEffect(() => {
if (isFirstRender.current) {
isFirstRender.current = false;
return;
}
CTX.fetchProducts(
0,
id[0],
selectedBrands,
isChecked,
rangePrice[0],
rangePrice[1],
sortBy,
isRangePrice
);
}, [CTX.state.selectedBrands, CTX.state.isChecked]);
useEffect(() => {
CTX.setRangePrice([
filter?.price?.minimumValue,
filter?.price?.maximumValue,
]);
}, [filter]);
return ( return (
<div <div
@ -96,7 +124,7 @@ const FilterCategory = ({
{brands?.map((e, index) => ( {brands?.map((e, index) => (
<div <div
key={index} key={index}
onClick={() => handleFilterBrand(e.name, e.id)} onClick={() => handleFilterBrand(e.persianName, e.id)}
> >
<div className="flex my-2 cursor-pointer"> <div className="flex my-2 cursor-pointer">
<div <div
@ -106,7 +134,9 @@ const FilterCategory = ({
: "" : ""
} `} } `}
></div> ></div>
<p className="mb-0 text-gray-600 text-sm mt-1">{e.name}</p> <p className="mb-0 text-gray-600 text-sm mt-1">
{e.persianName}
</p>
</div> </div>
</div> </div>
))} ))}
@ -160,26 +190,33 @@ const FilterCategory = ({
</div> </div>
</div> </div>
<div className="mt-10 px-5"> <div className="mt-10 px-5">
<RangeSlider min={0} max={100} onChange={handleRangeChange} /> <RangeSlider
min={filter?.price?.minimumValue}
max={filter?.price?.maximumValue}
onChange={(e) => handleRangeChange(e)}
/>
</div> </div>
<div className="flex mt-5"> <div className="flex mt-5">
<div className="w-full text-center"> <div className="w-full text-center">
<p className="mb-0 text-sm">تا قیمت</p> <p className="mb-0 text-sm">تا قیمت</p>
<p className="mb-0"> <p className="mb-0">
<PersianNumber number={rangePrice[0]} style="font-bold" /> <PersianNumber number={rangePrice[1]} style="font-bold" />
</p> </p>
</div> </div>
<div className="w-full text-center"> <div className="w-full text-center">
<p className="mb-0 text-sm">از قیمت</p> <p className="mb-0 text-sm">از قیمت</p>
<p className="mb-0"> <p className="mb-0">
<PersianNumber number={rangePrice[1]} style="font-bold" /> <PersianNumber number={rangePrice[0]} style="font-bold" />
</p> </p>
</div> </div>
</div> </div>
<div className="mt-4"> <div className="mt-4">
<button className="btn btn-primary w-full rounded-full text-sm "> <button
className="btn btn-primary w-full rounded-full text-sm "
onClick={() => handleRangePriceFilter()}
>
اعمال فیلتر اعمال فیلتر
</button> </button>
</div> </div>

View File

@ -6,7 +6,6 @@ import { useContext, useEffect } from "react";
const ListProdocts = ({ const ListProdocts = ({
sortBy, sortBy,
setSortBy,
rangePrice, rangePrice,
selectedBrands, selectedBrands,
isChecked, isChecked,
@ -19,10 +18,18 @@ const ListProdocts = ({
const stopGetTasks = CTX.state.stopGetTasks; const stopGetTasks = CTX.state.stopGetTasks;
const pageGetProducts = CTX.state.pageGetProducts; const pageGetProducts = CTX.state.pageGetProducts;
console.log(
"soretby--------------------------------------------------------",
sortBy
);
console.log(products);
useEffect(() => { useEffect(() => {
if (sortBy != -1) {
CTX.fetchProducts( CTX.fetchProducts(
pageGetProducts, 0,
id, id[0],
selectedBrands, selectedBrands,
isChecked, isChecked,
rangePrice, rangePrice,
@ -30,6 +37,7 @@ const ListProdocts = ({
sortBy, sortBy,
isRangePrice isRangePrice
); );
}
}, [sortBy]); }, [sortBy]);
return ( return (
@ -47,7 +55,7 @@ const ListProdocts = ({
className={`w-fit rounded-full px-2 mx-2 tr03 ${ className={`w-fit rounded-full px-2 mx-2 tr03 ${
sortBy == 1 ? "bg-primary-600" : " opacity-60 " sortBy == 1 ? "bg-primary-600" : " opacity-60 "
}`} }`}
onClick={() => setSortBy(1)} onClick={() => CTX.setSortBy(1)}
> >
<p <p
className={`mb-0 lg:text-sm xl:text-base ${ className={`mb-0 lg:text-sm xl:text-base ${
@ -61,7 +69,7 @@ const ListProdocts = ({
className={`w-fit rounded-full px-2 mx-2 tr03 ${ className={`w-fit rounded-full px-2 mx-2 tr03 ${
sortBy == 2 ? "bg-primary-600" : " opacity-60 " sortBy == 2 ? "bg-primary-600" : " opacity-60 "
}`} }`}
onClick={() => setSortBy(2)} onClick={() => CTX.setSortBy(2)}
> >
<p <p
className={`mb-0 lg:text-sm xl:text-base ${ className={`mb-0 lg:text-sm xl:text-base ${
@ -75,7 +83,7 @@ const ListProdocts = ({
className={`w-fit rounded-full px-2 mx-2 tr03 ${ className={`w-fit rounded-full px-2 mx-2 tr03 ${
sortBy == 3 ? "bg-primary-600" : " opacity-60 " sortBy == 3 ? "bg-primary-600" : " opacity-60 "
}`} }`}
onClick={() => setSortBy(3)} onClick={() => CTX.setSortBy(3)}
> >
<p <p
className={`mb-0 lg:text-sm xl:text-base ${ className={`mb-0 lg:text-sm xl:text-base ${
@ -89,7 +97,7 @@ const ListProdocts = ({
className={`w-fit rounded-full px-2 mx-2 tr03 ${ className={`w-fit rounded-full px-2 mx-2 tr03 ${
sortBy == 4 ? "bg-primary-600" : " opacity-60 " sortBy == 4 ? "bg-primary-600" : " opacity-60 "
}`} }`}
onClick={() => setSortBy(4)} onClick={() => CTX.setSortBy(4)}
> >
<p <p
className={`mb-0 lg:text-sm xl:text-base ${ className={`mb-0 lg:text-sm xl:text-base ${
@ -103,7 +111,7 @@ const ListProdocts = ({
className={`w-fit rounded-full px-2 mx-2 tr03 ${ className={`w-fit rounded-full px-2 mx-2 tr03 ${
sortBy == 5 ? "bg-primary-600" : " opacity-60 " sortBy == 5 ? "bg-primary-600" : " opacity-60 "
}`} }`}
onClick={() => setSortBy(5)} onClick={() => CTX.setSortBy(5)}
> >
<p <p
className={`mb-0 lg:text-sm xl:text-base ${ className={`mb-0 lg:text-sm xl:text-base ${

View File

@ -10,9 +10,10 @@ const FilterCategoryMobile = (props) => {
const [trendFilter, setTrendFilter] = useState(false); const [trendFilter, setTrendFilter] = useState(false);
useEffect(() => { useEffect(() => {
if (props.sortBy != -1) {
CTX.fetchProducts( CTX.fetchProducts(
pageGetProducts, 0,
props.id, props.id[0],
props.selectedBrands, props.selectedBrands,
props.isChecked, props.isChecked,
props.rangePrice, props.rangePrice,
@ -20,6 +21,7 @@ const FilterCategoryMobile = (props) => {
props.sortBy, props.sortBy,
props.isRangePrice props.isRangePrice
); );
}
}, [props.sortBy]); }, [props.sortBy]);
return ( return (
@ -95,7 +97,7 @@ const FilterCategoryMobile = (props) => {
className={`w-fit rounded-full px-2 mx-1 tr03 ${ className={`w-fit rounded-full px-2 mx-1 tr03 ${
props.sortBy == 1 ? "bg-primary-600" : " opacity-60 " props.sortBy == 1 ? "bg-primary-600" : " opacity-60 "
}`} }`}
onClick={() => props.setSortBy(1)} onClick={() => CTX.setSortBy(1)}
> >
<p <p
className={`mb-0 lg:text-sm xl:text-base text-sm ${ className={`mb-0 lg:text-sm xl:text-base text-sm ${
@ -109,7 +111,7 @@ const FilterCategoryMobile = (props) => {
className={`w-fit rounded-full px-2 mx-1 tr03 ${ className={`w-fit rounded-full px-2 mx-1 tr03 ${
props.sortBy == 2 ? "bg-primary-600" : " opacity-60 " props.sortBy == 2 ? "bg-primary-600" : " opacity-60 "
}`} }`}
onClick={() => props.setSortBy(2)} onClick={() => CTX.setSortBy(2)}
> >
<p <p
className={`mb-0 lg:text-sm xl:text-base text-sm ${ className={`mb-0 lg:text-sm xl:text-base text-sm ${
@ -123,7 +125,7 @@ const FilterCategoryMobile = (props) => {
className={`w-fit rounded-full px-2 mx-1 tr03 ${ className={`w-fit rounded-full px-2 mx-1 tr03 ${
props.sortBy == 3 ? "bg-primary-600" : " opacity-60 " props.sortBy == 3 ? "bg-primary-600" : " opacity-60 "
}`} }`}
onClick={() => props.setSortBy(3)} onClick={() => CTX.setSortBy(3)}
> >
<p <p
className={`mb-0 lg:text-sm xl:text-base text-sm ${ className={`mb-0 lg:text-sm xl:text-base text-sm ${
@ -137,7 +139,7 @@ const FilterCategoryMobile = (props) => {
className={`w-fit rounded-full px-2 mx-1 tr03 ${ className={`w-fit rounded-full px-2 mx-1 tr03 ${
props.sortBy == 4 ? "bg-primary-600" : " opacity-60 " props.sortBy == 4 ? "bg-primary-600" : " opacity-60 "
}`} }`}
onClick={() => props.setSortBy(4)} onClick={() => CTX.setSortBy(4)}
> >
<p <p
className={`mb-0 lg:text-sm xl:text-base text-sm ${ className={`mb-0 lg:text-sm xl:text-base text-sm ${
@ -151,7 +153,7 @@ const FilterCategoryMobile = (props) => {
className={`w-fit rounded-full px-2 mx-1 tr03 ${ className={`w-fit rounded-full px-2 mx-1 tr03 ${
props.sortBy == 5 ? "bg-primary-600" : " opacity-60 " props.sortBy == 5 ? "bg-primary-600" : " opacity-60 "
}`} }`}
onClick={() => props.setSortBy(5)} onClick={() => CTX.setSortBy(5)}
> >
<p <p
className={`mb-0 lg:text-sm xl:text-base text-sm ${ className={`mb-0 lg:text-sm xl:text-base text-sm ${

View File

@ -24,7 +24,7 @@ const PaginationCategoory = (props) => {
setCurrentPageIndex(i); setCurrentPageIndex(i);
CTX.fetchProducts( CTX.fetchProducts(
i, i,
props.id, props.id[0],
props.selectedBrands, props.selectedBrands,
props.isChecked, props.isChecked,
props.rangePrice, props.rangePrice,

View File

@ -50,7 +50,7 @@ const Footer = () => {
<div> <div>
<ul> <ul>
<Link <Link
href={`/categories/bdf6b13c-4be5-4a93-bcdb-612440bdbd6e`} href={`/categories/bdf6b13c-4be5-4a93-bcdb-612440bdbd6e/کرم مرطوب کننده دست و پا`}
> >
<li className="text-sm text-gray-600 mt-2"> <li className="text-sm text-gray-600 mt-2">
کرم مرطوب کننده دست و پا{" "} کرم مرطوب کننده دست و پا{" "}
@ -58,28 +58,28 @@ const Footer = () => {
</Link> </Link>
<Link <Link
href={`/categories/20dce1e7-1dfe-4b2a-9764-6f3ddf46fdb2`} href={`/categories/20dce1e7-1dfe-4b2a-9764-6f3ddf46fdb2/مرطوب کننده و آبرسان صورت`}
> >
<li className="text-sm text-gray-600 mt-2"> <li className="text-sm text-gray-600 mt-2">
مرطوب کننده و آبرسان صورت{" "} مرطوب کننده و آبرسان صورت{" "}
</li> </li>
</Link> </Link>
<Link <Link
href={`/categories/16bcdc90-6842-4201-9d5c-54cd8f565148`} href={`/categories/16bcdc90-6842-4201-9d5c-54cd8f565148/شوینده سطوح`}
> >
<li className="text-sm text-gray-600 mt-2"> <li className="text-sm text-gray-600 mt-2">
شوینده سطوح شوینده سطوح
</li> </li>
</Link> </Link>
<Link <Link
href={`/categories/b7549222-87f7-4b0b-8938-210539b3a395`} href={`/categories/b7549222-87f7-4b0b-8938-210539b3a395/بهداشت دهان و دندان`}
> >
<li className="text-sm text-gray-600 mt-2"> <li className="text-sm text-gray-600 mt-2">
بهداشت دهان و دندان بهداشت دهان و دندان
</li> </li>
</Link> </Link>
<Link <Link
href={`/categories/f3e79ed0-d608-470d-8656-7a98ff933c1e`} href={`/categories/f3e79ed0-d608-470d-8656-7a98ff933c1e/نرم کننده مو`}
> >
<li className="text-sm text-gray-600 mt-2"> <li className="text-sm text-gray-600 mt-2">
نرم کننده مو نرم کننده مو
@ -90,28 +90,28 @@ const Footer = () => {
<div> <div>
<ul> <ul>
<Link <Link
href={`/categories/b909db09-2188-4a4d-8578-e1f7102947bc`} href={`/categories/b909db09-2188-4a4d-8578-e1f7102947bc/کیت رنگ مو`}
> >
<li className="text-sm text-gray-600 mt-2"> <li className="text-sm text-gray-600 mt-2">
کیت رنگ مو{" "} کیت رنگ مو{" "}
</li> </li>
</Link> </Link>
<Link <Link
href={`/categories/effe5d98-d4b7-47e1-9bfb-4d3c77ab3347`} href={`/categories/effe5d98-d4b7-47e1-9bfb-4d3c77ab3347/بهداشت خانه و آشپرخانه`}
> >
<li className="text-sm text-gray-600 mt-2"> <li className="text-sm text-gray-600 mt-2">
بهداشت خانه و آشپرخانه{" "} بهداشت خانه و آشپرخانه{" "}
</li> </li>
</Link> </Link>
<Link <Link
href={`/categories/debf7aad-4f08-4d03-ba70-6663ae1aa90d`} href={`/categories/debf7aad-4f08-4d03-ba70-6663ae1aa90d/سرم مو`}
> >
<li className="text-sm text-gray-600 mt-2"> <li className="text-sm text-gray-600 mt-2">
سرم مو{" "} سرم مو{" "}
</li> </li>
</Link> </Link>
<Link <Link
href={`/categories/8bf20569-c3e3-457f-b9ad-140ef449741b`} href={`/categories/8bf20569-c3e3-457f-b9ad-140ef449741b/ژل بهداشتی بانوان`}
> >
<li className="text-sm text-gray-600 mt-2"> <li className="text-sm text-gray-600 mt-2">
ژل بهداشتی بانوان{" "} ژل بهداشتی بانوان{" "}

View File

@ -20,7 +20,9 @@ const HeroSection = () => {
</div> </div>
<div className="flex xs:flex-wrap justify-center xs:mt-[50px] lg:mt-[100px] xl:mt-[180px] "> <div className="flex xs:flex-wrap justify-center xs:mt-[50px] lg:mt-[100px] xl:mt-[180px] ">
<div className="xs:m-2 lg:m-0"> <div className="xs:m-2 lg:m-0">
<Link href={`/categories/62b94d76-a025-4d08-a663-6cf8685d24c5`}> <Link
href={`/categories/62b94d76-a025-4d08-a663-6cf8685d24c5/مراقبت پوست`}
>
<div className="lg:w-[130px] xs:w-[75px] lg:h-[130px] xs:h-[75px] bg-glass rounded-full mx-2"> <div className="lg:w-[130px] xs:w-[75px] lg:h-[130px] xs:h-[75px] bg-glass rounded-full mx-2">
{" "} {" "}
<div className="flex justify-center"> <div className="flex justify-center">
@ -38,7 +40,9 @@ const HeroSection = () => {
</div> </div>
<div className="xs:m-2 lg:m-0"> <div className="xs:m-2 lg:m-0">
<Link href={`/categories/991c9adb-934d-43d6-9dab-e0ebde035d8e`}> <Link
href={`/categories/991c9adb-934d-43d6-9dab-e0ebde035d8e/آرایش لب`}
>
<div className="lg:w-[130px] xs:w-[75px] lg:h-[130px] xs:h-[75px] bg-glass rounded-full mx-2"> <div className="lg:w-[130px] xs:w-[75px] lg:h-[130px] xs:h-[75px] bg-glass rounded-full mx-2">
{" "} {" "}
<div className="flex justify-center"> <div className="flex justify-center">
@ -56,7 +60,9 @@ const HeroSection = () => {
</div> </div>
<div className="xs:m-2 lg:m-0"> <div className="xs:m-2 lg:m-0">
<Link href={`/categories/9c95ca17-c041-497b-a7bf-b58b716e2155`}> <Link
href={`/categories/9c95ca17-c041-497b-a7bf-b58b716e2155/آرایش ناخن`}
>
<div className="lg:w-[130px] xs:w-[75px] lg:h-[130px] xs:h-[75px] bg-glass rounded-full mx-2 group tr03"> <div className="lg:w-[130px] xs:w-[75px] lg:h-[130px] xs:h-[75px] bg-glass rounded-full mx-2 group tr03">
{" "} {" "}
<div className="flex justify-center"> <div className="flex justify-center">
@ -74,7 +80,9 @@ const HeroSection = () => {
</div> </div>
<div className="xs:m-2 lg:m-0"> <div className="xs:m-2 lg:m-0">
<Link href={`/categories/7202f039-339e-44ff-90d8-113b2991a958`}> <Link
href={`/categories/7202f039-339e-44ff-90d8-113b2991a958/بهداشت جنسی`}
>
<div className="lg:w-[130px] xs:w-[75px] lg:h-[130px] xs:h-[75px] bg-glass rounded-full mx-2"> <div className="lg:w-[130px] xs:w-[75px] lg:h-[130px] xs:h-[75px] bg-glass rounded-full mx-2">
{" "} {" "}
<div className="flex justify-center"> <div className="flex justify-center">
@ -92,7 +100,9 @@ const HeroSection = () => {
</div> </div>
<div className="xs:m-2 lg:m-0"> <div className="xs:m-2 lg:m-0">
<Link href={`/categories/2e11e55c-0941-49f8-9d22-dfa21088f639`}> <Link
href={`/categories/2e11e55c-0941-49f8-9d22-dfa21088f639/آرایش چشم`}
>
<div className="lg:w-[130px] xs:w-[75px] lg:h-[130px] xs:h-[75px] bg-glass rounded-full mx-2"> <div className="lg:w-[130px] xs:w-[75px] lg:h-[130px] xs:h-[75px] bg-glass rounded-full mx-2">
{" "} {" "}
<div className="flex justify-center"> <div className="flex justify-center">
@ -110,7 +120,9 @@ const HeroSection = () => {
</div> </div>
<div className="xs:m-2 lg:m-0"> <div className="xs:m-2 lg:m-0">
<Link href={`/categories/7e92af7d-0370-451f-9770-5e26b5c8dc63`}> <Link
href={`/categories/7e92af7d-0370-451f-9770-5e26b5c8dc63/کرم پودر`}
>
<div className="lg:w-[130px] xs:w-[75px] lg:h-[130px] xs:h-[75px] bg-glass rounded-full mx-2"> <div className="lg:w-[130px] xs:w-[75px] lg:h-[130px] xs:h-[75px] bg-glass rounded-full mx-2">
{" "} {" "}
<div className="flex justify-center"> <div className="flex justify-center">

View File

@ -116,7 +116,7 @@ const SideBarNavBarMobile = () => {
<ul> <ul>
<li> <li>
<Link <Link
href={`/categories/${e.id}`} href={`/categories/${e.id}/${e.name}`}
onClick={() => CTX.setCloseNavbar(false)} onClick={() => CTX.setCloseNavbar(false)}
> >
<p className="mb-0 text-sm py-3 px-1 text-gray-700"> <p className="mb-0 text-sm py-3 px-1 text-gray-700">
@ -127,7 +127,7 @@ const SideBarNavBarMobile = () => {
{firstChild.map((e, index) => ( {firstChild.map((e, index) => (
<li key={index}> <li key={index}>
<Link <Link
href={`/categories/${e.id}`} href={`/categories/${e.id}/${e.name}`}
onClick={() => CTX.setCloseNavbar(false)} onClick={() => CTX.setCloseNavbar(false)}
> >
<div className="py-3 flex justify-between rtl px-1 rounded-lg my-1 text-gray-700"> <div className="py-3 flex justify-between rtl px-1 rounded-lg my-1 text-gray-700">

View File

@ -21,6 +21,8 @@ const Navbar = ({ theme }) => {
const profile = CTX.state.profile; const profile = CTX.state.profile;
const cart = CTX.state.cart; const cart = CTX.state.cart;
console.log("dataNav", dataNav);
const [navItemHover, setNavItemHover] = useState(null); const [navItemHover, setNavItemHover] = useState(null);
const [isDesktop, setIsDesktop] = useState(null); const [isDesktop, setIsDesktop] = useState(null);
const [closeNavbar, setClosNavbar] = useState(false); const [closeNavbar, setClosNavbar] = useState(false);
@ -241,7 +243,7 @@ const Navbar = ({ theme }) => {
<li className=" my-2" key={index}> <li className=" my-2" key={index}>
<div className="flex"> <div className="flex">
<div className="w-[10px] h-[10px] rounded-full bg-primary-500 mt-1 mx-2"></div> <div className="w-[10px] h-[10px] rounded-full bg-primary-500 mt-1 mx-2"></div>
<Link href={`/categories/${e.id}`}> <Link href={`/categories/${e.id}/${e.name}`}>
<p className="mb-0 font-bold text-sm hover:text-primary-500 tr03 cursor-pointer"> <p className="mb-0 font-bold text-sm hover:text-primary-500 tr03 cursor-pointer">
{e.name} {e.name}
</p> </p>
@ -275,7 +277,7 @@ const Navbar = ({ theme }) => {
{e.children.map((child, index) => ( {e.children.map((child, index) => (
<Link <Link
key={index} key={index}
href={`/categories/${child.id}`} href={`/categories/${child.id}/${e.name}`}
> >
<p <p
key={child.id} key={child.id}

View File

@ -2,13 +2,13 @@ import Slider from "rc-slider";
import "rc-slider/assets/index.css"; import "rc-slider/assets/index.css";
const RangeSlider = ({ min, max, onChange }) => { const RangeSlider = ({ min, max, onChange }) => {
const handleStyle = { const handleStyleMin = {
borderColor: "#2189A8", borderColor: "#2189A8",
height: 25, height: 25,
width: 25, width: 25,
marginLeft: 0,
marginTop: -9, marginTop: -9,
backgroundColor: "white", backgroundColor: "white",
// left: 0,
}; };
const trackStyle = [{ backgroundColor: "#2189A8", height: 8 }]; const trackStyle = [{ backgroundColor: "#2189A8", height: 8 }];
@ -20,9 +20,9 @@ const RangeSlider = ({ min, max, onChange }) => {
min={min} min={min}
max={max} max={max}
allowCross={false} allowCross={false}
defaultValue={[min, max]} // defaultValue={[min, max]}
onChange={onChange} onChange={onChange}
handleStyle={[handleStyle, handleStyle]} handleStyle={[handleStyleMin, handleStyleMin]}
trackStyle={trackStyle} trackStyle={trackStyle}
railStyle={railStyle} railStyle={railStyle}
/> />

View File

@ -1,6 +1,10 @@
import Footer from "@comp/Footer/page"; import Footer from "@comp/Footer/page";
import Navbar from "@comp/Navbar/page"; import Navbar from "@comp/Navbar/page";
export const metadata = {
title: "درباره ما ",
};
const Page = () => { const Page = () => {
const number = "02188195164"; const number = "02188195164";
return ( return (

View File

@ -1,481 +1,14 @@
"use client"; import CheckoutData from "@comp/AppsComponent/CheckoutData/page";
import NavBarDownCart from "@comp/Carts/component/NavBarDownCart/page"; import React from "react";
import Navbar from "@comp/Navbar/page";
import PersianNumber from "plugins/PersianNumber";
import { useContext, useEffect, useState } from "react";
import AppContext from "@ctx/AppContext"; export const metadata = {
import ap from "@img/ap.png"; title: "اعتبار سنجی خرید",
import zarin from "@img/zarin.png"; };
import Image from "next/image";
import { useRouter } from "next/navigation";
import Chapar from "plugins/Chapar";
import BottomSheetDiscount from "plugins/bottomSheet/BottomSheetDiscount";
import { toast } from "react-toastify";
const Page = () => { const Page = () => {
const CTX = useContext(AppContext);
const [shippingData, setShippingData] = useState([]);
const [shippingId, setShippingID] = useState(null);
const [addressData, setAddressData] = useState([]);
const [addressId, setAddressId] = useState(null);
const [permissionGoPay, setPermissionGoPay] = useState(false);
const router = useRouter();
const checkOutData = CTX.state.checkOutData;
const body = {
addressId: addressData[addressId]?.id,
orderId: checkOutData?.id,
shippingId: shippingData[shippingId]?.id,
};
console.log(body);
const GetShippingData = async () => {
try {
const data = await Chapar.get(
`${process.env.NEXT_PUBLIC_API_URL}/warehouse/shipping?page=0`
);
setShippingData(data);
} catch ({ error, status }) {
toast.error(`${error?.response?.data?.message}`, {
position: "bottom-right",
closeOnClick: true,
});
}
};
const handleShippingID = async (index) => {
if (addressId !== null) {
setShippingID(index);
try {
const data = await Chapar.post(
`${process.env.NEXT_PUBLIC_API_URL}/order/bag/shipping/${checkOutData?.id}`,
JSON.stringify({
addressId: addressData[addressId]?.id,
orderId: checkOutData?.id,
shippingId: shippingData[index]?.id,
}),
{
headers: {
Authorization: localStorage.getItem("token"),
},
}
);
CTX.setCheckOutData(data);
setPermissionGoPay(true);
console.log(data);
} catch ({ error, status }) {
toast.error(`${error?.response?.data?.message}`, {
position: "bottom-right",
closeOnClick: true,
});
}
} else {
toast.error(`ابتدا آدرس را انتحاب کنید`, {
position: "bottom-right",
closeOnClick: true,
});
}
};
const handleGoPayment = async () => {
try {
const data = await Chapar.post(
`${process.env.NEXT_PUBLIC_API_URL}/order/bag/payment/${checkOutData?.id}?paymentMethod=1`,
{
headers: {
Authorization: localStorage.getItem("token"),
},
}
);
router.push(data?.paymentUrl);
} catch ({ error, status }) {
toast.error(`${error?.response?.data?.message}`, {
position: "bottom-right",
closeOnClick: true,
});
}
};
useEffect(() => {
if (shippingData.length <= 0) {
GetShippingData();
}
if (CTX.state.addressData <= 0) {
CTX.fetchAddressUser();
}
}, [checkOutData]);
useEffect(() => {
setAddressData(CTX.state.addressData);
}, [CTX.state.addressData]);
useEffect(() => {
if (CTX.state.checkOutData.length <= 0) {
router.push("/cart");
}
setPermissionGoPay(false);
}, []);
return ( return (
<> <>
<div className=" pb-20"> <CheckoutData />
<Navbar theme={1} />
<div className="xs:w-full lg:w-4/12 mx-auto">
<div className="text-right flex rtl justify-between border-y-[1px] border-gray-100 mt-3 px-4 ">
<p className="mb-0 !text-sm font-semibold py-4">آدس ها</p>
<div
className="bg-primary-200 w-fit h-fit relative my-3 p-1 rounded-lg"
onClick={() => CTX.setBottomSheetAddressOpen(true)}
>
<p className="mb-0 text-[11px] text-white rtl">
افزودن آدرس جدید
</p>
</div>
</div>
{addressData.map((e, index) => (
<div
className={`flex rtl px-3 py-4 border-2 border-transparent tr03 mx-2 mt-3 cursor-pointer ${
addressId == index
? "border-2 !border-green-600 rounded-lg bg-green-50"
: ""
}`}
onClick={() => setAddressId(index)}
key={index}
>
<div>
<svg
width="20"
height="20"
viewBox="0 0 188 264"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="opacity-70 mx-auto "
>
<path
d="M94 10.125C47.418 10.125 9.625 46.0957 9.625 90.3984C9.625 141.375 65.875 222.158 86.5293 250.061C87.3866 251.238 88.5103 252.197 89.8087 252.858C91.107 253.518 92.5432 253.863 94 253.863C95.4568 253.863 96.893 253.518 98.1913 252.858C99.4897 252.197 100.613 251.238 101.471 250.061C122.125 222.17 178.375 141.416 178.375 90.3984C178.375 46.0957 140.582 10.125 94 10.125Z"
stroke="black"
stroke-width="18.75"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M94 122.625C109.533 122.625 122.125 110.033 122.125 94.5C122.125 78.967 109.533 66.375 94 66.375C78.467 66.375 65.875 78.967 65.875 94.5C65.875 110.033 78.467 122.625 94 122.625Z"
stroke="black"
stroke-opacity="0.37"
stroke-width="18.75"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</div>
<div className="mx-2">
<p className="mb-0 text-[12px] text-gray-500"> {e.address} </p>
</div>
</div>
))}
<div className="text-right flex rtl justify-between border-y-[1px] border-gray-100 mt-3 px-4 ">
<p className="mb-0 text-sm font-semibold py-4">زمان و نحوه ارسال</p>
<div className="border border-gray-300 w-fit h-fit relative my-3 p-1 rounded-lg">
<div className="flex">
<div>
<svg
width="15"
height="15"
viewBox="0 0 251 200"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="opacity-60"
>
<path
d="M105.625 143.75C110.625 148.75 117.083 151.2 125 151.1C132.917 151 138.75 148.133 142.5 142.5L212.5 37.5L107.5 107.5C101.875 111.25 98.9083 116.979 98.6 124.688C98.2917 132.396 100.633 138.75 105.625 143.75ZM125 0C137.292 0 149.117 1.71667 160.475 5.15C171.833 8.58334 182.508 13.7417 192.5 20.625L168.75 35.625C161.875 32.0833 154.742 29.4292 147.35 27.6625C139.958 25.8958 132.508 25.0083 125 25C97.2917 25 73.6958 34.7417 54.2125 54.225C34.7292 73.7083 24.9917 97.3 25 125C25 133.75 26.2 142.396 28.6 150.938C31 159.479 34.3833 167.5 38.75 175H211.25C216.042 167.083 219.533 158.854 221.725 150.312C223.917 141.771 225.008 132.917 225 123.75C225 116.25 224.113 108.958 222.338 101.875C220.563 94.7917 217.908 87.9167 214.375 81.25L229.375 57.5C235.625 67.2917 240.575 77.7083 244.225 88.75C247.875 99.7917 249.8 111.25 250 123.125C250.208 135 248.854 146.354 245.938 157.188C243.021 168.021 238.75 178.333 233.125 188.125C230.833 191.875 227.708 194.792 223.75 196.875C219.792 198.958 215.625 200 211.25 200H38.75C34.375 200 30.2083 198.958 26.25 196.875C22.2917 194.792 19.1667 191.875 16.875 188.125C11.4583 178.75 7.29167 168.804 4.375 158.288C1.45833 147.771 0 136.675 0 125C0 107.708 3.28334 91.5125 9.85 76.4125C16.4167 61.3125 25.375 48.0833 36.725 36.725C48.075 25.3667 61.35 16.4083 76.55 9.85C91.75 3.29167 107.9 0.00833333 125 0Z"
fill="black"
fill-opacity="0.61"
/>
</svg>
</div>
<p className="mb-0 text-[11px] rtl mr-2 text-gray-600">
سریع ترین زمان ارسال
</p>
</div>
</div>
</div>
<div>
{shippingData?.map((e, index) => (
<div
className={`flex rtl px-2 py-2 mx-2 mt-5 border-2 border-transparent tr03 cursor-pointer ${
shippingId == index
? "border-2 !border-green-600 rounded-lg bg-green-50"
: ""
}`}
onClick={() => handleShippingID(index)}
key={index}
>
<div>
<svg
width="25"
height="25"
viewBox="0 0 234 244"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="mx-auto opacity-70 mt-2"
>
<path
d="M65.8246 162.813C66.1529 163.999 66.7117 165.11 67.4692 166.081C68.2267 167.052 69.168 167.864 70.2394 168.471C71.3107 169.078 72.4911 169.468 73.7133 169.619C74.9354 169.77 76.1752 169.678 77.3621 169.35C78.5489 169.022 79.6594 168.463 80.6303 167.705C81.6011 166.948 82.4133 166.007 83.0203 164.935C83.6274 163.864 84.0175 162.683 84.1683 161.461C84.3192 160.239 84.2279 158.999 83.8996 157.813L65.8246 162.813ZM11.9996 31.0625C10.8081 30.7145 9.55935 30.6066 8.32582 30.745C7.09228 30.8834 5.89851 31.2654 4.81377 31.8688C3.72903 32.4722 2.77491 33.285 2.00678 34.26C1.23864 35.2351 0.671788 36.353 0.3391 37.5488C0.00641134 38.7447 -0.0854865 39.9947 0.0687392 41.2264C0.222965 42.458 0.620244 43.6468 1.23752 44.7237C1.8548 45.8006 2.6798 46.7442 3.66463 47.4997C4.64947 48.2553 5.77454 48.8077 6.97458 49.125L11.9996 31.0625ZM224.35 168.563C225.57 168.28 226.722 167.756 227.737 167.021C228.752 166.286 229.609 165.355 230.257 164.284C230.906 163.212 231.334 162.021 231.515 160.781C231.695 159.541 231.626 158.278 231.31 157.065C230.994 155.853 230.438 154.716 229.676 153.722C228.913 152.728 227.959 151.897 226.869 151.278C225.78 150.659 224.578 150.264 223.333 150.118C222.089 149.971 220.828 150.076 219.625 150.425L224.35 168.563ZM99.4621 191.488C103.337 205.488 94.8371 220.275 79.7871 224.188L84.4996 242.325C109.212 235.913 124.312 211.05 117.537 186.488L99.4621 191.488ZM79.7871 224.188C64.6371 228.125 49.4371 219.325 45.5371 205.2L27.4621 210.2C34.2121 234.638 59.8871 248.725 84.4996 242.325L79.7871 224.188ZM45.5371 205.2C41.6621 191.2 50.1621 176.413 65.2121 172.5L60.4996 154.375C35.7871 160.788 20.6746 185.638 27.4621 210.2L45.5371 205.2ZM65.2121 172.5C80.3621 168.563 95.5621 177.363 99.4621 191.488L117.537 186.488C110.787 162.05 85.1121 147.963 60.4996 154.363L65.2121 172.5ZM83.8996 157.813L56.9996 60.4375L38.9246 65.4375L65.8246 162.813L83.8996 157.813ZM33.2996 36.9625L11.9996 31.0625L6.97458 49.125L28.2871 55.0375L33.2996 36.9625ZM56.9996 60.4375C55.4136 54.8107 52.3969 49.6907 48.2434 45.5766C44.0899 41.4625 38.9413 38.4948 33.2996 36.9625L28.3121 55.0375C33.6246 56.5125 37.5746 60.55 38.9246 65.4375L56.9996 60.4375ZM110.875 198.063L224.35 168.563L219.637 150.425L106.15 179.925L110.875 198.063Z"
fill="black"
/>
<path
d="M211.562 49.9502C205.5 28.0002 202.462 17.0252 193.562 12.0377C184.637 7.03772 173.325 9.98772 150.7 15.8752L126.7 22.1002C104.075 27.9752 92.7623 30.9252 87.6248 39.5752C82.4748 48.2127 85.4998 59.1877 91.5623 81.1252L97.9998 104.413C104.062 126.35 107.087 137.325 116 142.313C124.912 147.313 136.225 144.363 158.85 138.488L182.85 132.238C205.475 126.363 216.787 123.425 221.937 114.788C224.762 110.038 225.125 104.588 223.862 97.0002"
stroke="black"
stroke-opacity="0.44"
stroke-width="18.75"
stroke-linecap="round"
/>
</svg>
</div>
<div className="mx-2">
<h3 className="mb-0 text-sm text-right font-medium text-primary-500 ">
{e.name}{" "}
</h3>
<p className="mb-0 text-[12px] text-gray-500">
{" "}
حداکثر
<PersianNumber
number={e.workingDays}
style={"text-gray-600 mx-1"}
/>
روز کاری
<small className="mx-2">|</small> هزینه ارسال
<PersianNumber
number={(e.deliveryCost / 10)?.toLocaleString()}
style={"text-gray-600 mx-1"}
/>
هزار تومان
</p>
</div>
</div>
))}
</div>
<div className="text-right flex rtl justify-between border-y-[1px] border-gray-100 mt-3 px-4 ">
<p className="mb-0 text-sm font-semibold py-4">روش پرداخت</p>
</div>
<div>
<div
className={`flex rtl px-2 py-2 mx-2 border-2 border-transparent mt-5 ${
true ? "border-2 !border-green-600 rounded-lg bg-green-50" : ""
}`}
>
<div>
<Image src={zarin} className="w-[50px]" alt="" />
</div>
<div className="mx-2">
<h3 className="mb-0 text-sm text-right font-medium text-primary-500 ">
پرداخت آنلاین
</h3>
<p className="mb-0 text-[12px] text-gray-500">زرین پال</p>
</div>
</div>
<div className="flex rtl px-2 py-1 mx-2 mt-5 opacity-40">
<div>
<Image src={ap} className="w-[45px]" alt="" />
</div>
<div className="mx-2">
<h3 className="mb-0 text-sm text-right font-medium text-primary-500 ">
پرداخت آنلاین (به زودی)
</h3>
<p className="mb-0 text-[12px] text-gray-500">آسان پرداخت</p>
</div>
</div>
<div
className={`flex justify-between rtl px-3 mt-5 ${
checkOutData?.discountCode != "" ? "" : ""
}`}
onClick={() => {
if (checkOutData?.discountCode == "") {
CTX.setBottomSheetDiscountOpen(true);
}
}}
>
<div className="flex">
<div>
<svg
width="25"
height="25"
viewBox="0 0 244 194"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="opacity-70 mt-2"
>
<path
d="M122 93.875V100.125M122 47V53.25M122 140.75V147M209.5 184.5C216.13 184.5 222.489 181.866 227.178 177.178C231.866 172.489 234.5 166.13 234.5 159.5V122C227.87 122 221.511 119.366 216.822 114.678C212.134 109.989 209.5 103.63 209.5 97C209.5 90.3696 212.134 84.0107 216.822 79.3223C221.511 74.6339 227.87 72 234.5 72V34.5C234.5 27.8696 231.866 21.5107 227.178 16.8223C222.489 12.1339 216.13 9.5 209.5 9.5H34.5C27.8696 9.5 21.5107 12.1339 16.8223 16.8223C12.1339 21.5107 9.5 27.8696 9.5 34.5V72C16.1304 72 22.4893 74.6339 27.1777 79.3223C31.8661 84.0107 34.5 90.3696 34.5 97C34.5 103.63 31.8661 109.989 27.1777 114.678C22.4893 119.366 16.1304 122 9.5 122V159.5C9.5 166.13 12.1339 172.489 16.8223 177.178C21.5107 181.866 27.8696 184.5 34.5 184.5H209.5Z"
stroke="black"
stroke-opacity="0.54"
stroke-width="18.75"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</div>
<div className="mx-2">
<h3 className="mb-0 text-sm text-right font-medium text-primary-500 ">
افزودن کد تخفیف{" "}
</h3>
<p className="mb-0 text-[12px] text-gray-500">
کد تخفیف خود را وارد کنید
</p>
</div>
</div>
{checkOutData?.discountCode == "" ? (
<div className="pl-3">
<span className="text-[30px] opacity-60">+</span>
</div>
) : (
<div className="text-right flex justify-end px-2 py-1 mx-2">
<p className="text-green-600 mb-0 text-[12px] ">
کد تخفیف ثبت شد{" "}
</p>
</div>
)}
</div>
</div>
<div className="">
<div className="text-right flex rtl justify-between border-y-[1px] border-gray-100 my-3 px-4 ">
<p className="mb-0 text-sm font-semibold py-4">حساب نهایی</p>
<div className="bg-primary-200 w-fit h-fit relative my-3 p-1 rounded-lg">
<p className="mb-0 text-[11px] text-white rtl">مشاهده اقلام</p>
</div>
</div>
<div>
<div className="flex justify-between rtl px-4">
<p className="mb-0 text-[12px] text-gray-500">قیمت </p>
<div className="flex justify-center">
<p className="mb-0 ">
<PersianNumber
number={(
checkOutData?.totalProductsPrice / 10
)?.toLocaleString()}
style={"!text-[14px] !font-semibold"}
/>
</p>
<small className="text-gray-500 text-[12px] mt-1 mx-1">
{" "}
تومان
</small>
</div>
</div>
<div className="flex justify-between rtl my-2 px-4">
<p className="mb-0 text-[12px] text-gray-500">تخفیف محصول</p>
<div className="flex justify-center">
<p className="mb-0 ">
<PersianNumber
number={(
checkOutData?.discountPrice / 10
)?.toLocaleString()}
style={"!text-[14px] !font-semibold"}
/>
</p>
<small className="text-gray-500 text-[12px] mt-1 mx-1">
{" "}
تومان
</small>
</div>
</div>
<div className="flex justify-between rtl my-2 px-4">
<p className="mb-0 text-[12px] text-gray-500">
هزینه بسته بندی
</p>
<div className="flex justify-center">
<p className="mb-0 ">
<PersianNumber
number={(
checkOutData?.packingPrice / 10
)?.toLocaleString()}
style={"!text-[14px] !font-semibold"}
/>
</p>
<small className="text-gray-500 text-[12px] mt-1 mx-1">
{" "}
تومان
</small>
</div>
</div>
<div className="flex justify-between rtl my-2 px-4">
<p className="mb-0 text-[12px] text-gray-500">هزینه ارسال</p>
<div className="flex justify-center">
<p className="mb-0 ">
<PersianNumber
number={(
checkOutData?.deliveryPrice / 10
)?.toLocaleString()}
style={"!text-[14px] !font-semibold"}
/>
</p>
<small className="text-gray-500 text-[12px] mt-1 mx-1">
{" "}
تومان
</small>
</div>
</div>
<div className="flex justify-between bg-primary-100 p-3 rtl my-2">
<p className="mb-0 text-sm text-primary-600 font-bold">
قابل پرداخت
</p>
<div className="flex justify-center">
<p className="mb-0 ">
<PersianNumber
number={(checkOutData?.totalPrice / 10)?.toLocaleString()}
style={"!text-[14px] !font-semibold text-primary-800"}
/>
</p>
<small className="text-gray-500 text-[12px] mt-1 mx-1">
{" "}
تومان
</small>
</div>
</div>
</div>
</div>
</div>
<NavBarDownCart
calculateTotalCost={checkOutData.totalPrice / 10}
event={() => handleGoPayment()}
permissionGoPay={permissionGoPay}
/>
</div>
<BottomSheetDiscount orderId={checkOutData?.id} />
</> </>
); );
}; };

View File

@ -1,196 +1,15 @@
"use client"; import CartData from "@comp/AppsComponent/CartData/page";
import CardCart from "@comp/Cards/CardCart/page"; import React from "react";
import NavBarDownCart from "@comp/Carts/component/NavBarDownCart/page";
import Navbar from "@comp/Navbar/page";
import AppContext from "@ctx/AppContext";
import { useRouter } from "next/navigation";
import Chapar from "plugins/Chapar";
import PersianNumber from "plugins/PersianNumber";
import { useContext, useEffect } from "react";
import { toast } from "react-toastify";
const Page = () => {
const CTX = useContext(AppContext);
const router = useRouter();
const cart = CTX.state.cart;
const calculateTotalCost = cart.reduce(
(total, item) => total + parseInt(item.cost) * item.count,
0
);
const calculateTotalCostWithDiscount = cart.reduce(
(total, item) => total + parseInt(item.costWithDiscount) * item.count,
0
);
// const calculateTotalCostWithDiscount = cart.reduce((total, item) => {
// // Check if costWithDiscount is defined and a valid number
// if (
// typeof item.costWithDiscount === "number" &&
// !isNaN(item.costWithDiscount)
// ) {
// // If costWithDiscount is defined and valid, include it in the calculation
// return total + item.costWithDiscount * item.count;
// } else {
// // If costWithDiscount is not defined or not a valid number, use regular cost
// return total + item.cost * item.count;
// }
// }, 0);
const handleGoCheckOut = async () => {
// Check if the user is authorized based on the presence of a token in local storage
const token = localStorage.getItem("token");
if (token) {
// If token exists, proceed to checkout
const productsToSend = cart.map((item) => ({
productId: item.id,
count: parseInt(item.count),
}));
try {
const data = await Chapar.post(
`${process.env.NEXT_PUBLIC_API_URL}/order/bag/add`,
JSON.stringify(productsToSend),
{
headers: {
Authorization: localStorage.getItem("token"),
},
}
);
CTX.setCheckOutData(data);
} catch ({ error, status }) {
toast.error(`${error?.response?.data?.message}`, {
position: "bottom-right",
closeOnClick: true,
});
}
router.push("/cart/checkout"); // Redirect to the checkout Page
} else {
// If token does not exist, redirect to login
router.push("/login"); // Redirect to the login Page
}
};
useEffect(() => {
CTX.setBottomSheetCartOpen(false);
}, []);
export const metadata = {
title: "سبد خرید",
};
const page = () => {
return ( return (
<> <>
<div className=" pb-20"> <CartData />
<Navbar theme={1} />
<div className="xs:w-full lg:w-4/12 mx-auto">
<div className="text-right flex rtl justify-between border-t-[1px] border-gray-200 my-3 px-4 ">
<p className="mb-0 text-sm font-semibold py-4">
محصولات انتخاب شده
</p>
<div className="bg-primary-200 w-fit h-fit relative my-3 p-1 rounded-lg">
<p className="mb-0 text-[11px] text-white rtl">
<PersianNumber number={cart?.length} style={"mx-1"} />
محصول
</p>
</div>
</div>
<div className="">
{cart?.map((e, index) => (
<CardCart key={index} data={e} />
))}
<div className="">
<div className="text-right flex rtl justify-between border-y-[1px] border-gray-200 my-3 px-4 ">
<p className="mb-0 text-sm font-medium py-4">حساب نهایی</p>
{/* <div className="bg-primary-200 w-fit h-fit relative my-3 p-1 rounded-lg">
<p className="mb-0 text-[11px] text-white rtl">
<PersianNumber number={cart?.length} style={"mx-1"} />
محصول
</p>
</div> */}
</div>
<div>
<div className="flex justify-between rtl px-4">
<p className="mb-0 text-[12px] text-gray-500">قیمت </p>
<div className="flex justify-center">
<p className="mb-0 ">
<PersianNumber
number={(calculateTotalCost / 10)?.toLocaleString()}
style={"!text-[14px] !font-medium"}
/>
</p>
<small className="text-gray-500 text-[12px] mt-1 mx-1">
{" "}
تومان
</small>
</div>
</div>
<div className="flex justify-between rtl my-2 px-4">
<p className="mb-0 text-[12px] text-gray-500">تخفیف محصول</p>
<div className="flex justify-center ">
<p className="mb-0 ">
<PersianNumber
number={(
(calculateTotalCost -
calculateTotalCostWithDiscount) /
10
)?.toLocaleString()}
style={"!text-[14px] !font-medium"}
/>
</p>
<small className="text-gray-500 text-[12px] mt-1 mx-1">
{" "}
تومان
</small>
</div>
</div>
<div className="flex justify-between bg-primary-100 p-3 rtl my-2">
<p className="mb-0 text-sm text-primary-600 font-bold">
قابل پرداخت
</p>
<div className="flex justify-center">
<p className="mb-0 ">
<PersianNumber
number={
calculateTotalCostWithDiscount !== 0
? (
calculateTotalCostWithDiscount / 10
)?.toLocaleString()
: 0
}
style={"!text-[14px] !font-semibold text-primary-800"}
/>
</p>
<small className="text-gray-500 text-[12px] mt-1 mx-1">
{" "}
تومان
</small>
</div>
</div>
</div>
</div>
</div>
</div>
<NavBarDownCart
calculateTotalCost={calculateTotalCostWithDiscount / 10}
event={() => handleGoCheckOut()}
permissionGoPay={!!cart.length > 0}
/>
</div>
</> </>
); );
}; };
export default Page; export default page;

View File

@ -0,0 +1,43 @@
import CategoriesData from "@comp/AppsComponent/CategoriesData/page";
import React from "react";
export async function generateMetadata({ params }) {
const decodedName = decodeURIComponent(params.id[1]);
return {
title: decodedName,
description: ` خرید ${decodedName}| برندهای متنوع با پایین ترین قیمت | فروشگاه اینترنتی وسمه`,
metadataBase: new URL(
`https://www.vesmeh.com/categories/${params.id[0]}/${decodedName}`
),
keywords: [
"آرایشی",
"بهداشت خانگی",
"محصولات زیبایی",
"لوازم تمیزی",
"مراقبت شخصی",
],
openGraph: {
title: decodedName,
description: ` خرید ${decodedName}| برندهای متنوع با پایین ترین قیمت | فروشگاه اینترنتی وسمه`,
url: `https://www.vesmeh.com/categories/${params.id[0]}/${decodedName}`,
type: "website",
},
twitter: {
site: "@vesmehstore",
description: ` خرید ${decodedName}| برندهای متنوع با پایین ترین قیمت | فروشگاه اینترنتی وسمه`,
title: decodedName,
creator: "@vesmehstore",
},
};
}
const page = ({ params }) => {
return (
<div>
<CategoriesData params={params} />
</div>
);
};
export default page;

View File

@ -2,6 +2,9 @@ import Footer from "@comp/Footer/page";
import Navbar from "@comp/Navbar/page"; import Navbar from "@comp/Navbar/page";
import PersianNumber from "plugins/PersianNumber"; import PersianNumber from "plugins/PersianNumber";
export const metadata = {
title: "ارتباط با ما ",
};
const Page = () => { const Page = () => {
const number = "02188195164"; const number = "02188195164";
return ( return (

View File

@ -1,79 +1,11 @@
"use client"; import FaqData from "@comp/AppsComponent/FaqData/page";
export const metadata = {
import Footer from "@comp/Footer/page"; title: "سوالات متدادول",
import Navbar from "@comp/Navbar/page"; };
import { useEffect, useState } from "react";
const Page = () => { const Page = () => {
const [faq, setFaq] = useState([]);
const [faqSelect, setFaqSelect] = useState(0);
const fetchNavData = async (id) => {
const res = await fetch(`https://jsonplaceholder.typicode.com/comments`);
const post = await res.json();
setFaq(post);
};
useEffect(() => {
fetchNavData();
}, []);
return ( return (
<> <>
<div className="bg-contact-us "> <FaqData />
<div className=" pb-20">
<Navbar theme={0} />
<div>
<div className="flex justify-center xs:hidden lg:block">
<div className="absolute mr-[-1100px] mt-[-200px]">
<p className="mb-0 text-[300px] opacity-10 font-extrabold text-white ">
{" "}
,
</p>
</div>
</div>
</div>
<div className="my-[80px] ">
<div className="px-5">
<h1 className="text-white font-bold text-center xs:text-[20px] lg:text-[40px]">
پرسشهای متداول
</h1>
</div>
</div>
</div>
</div>
<div className=" xs:px-3 lg:px-20 rtl lg:m-10 xs:m-3 pb-20 ">
{faq?.map((e, index) => (
<div
className={` p-5 w-full rounded-lg my-2 tr03 cursor-pointer ${
faqSelect == index ? "bg-gray-100" : "bg-primary-100"
}`}
onClick={() => setFaqSelect(index)}
key={index}
>
<div className="flex">
<span className="mx-2 text-xl text-gray-900">
{faqSelect == index ? "-" : "+"}
</span>
<h2 className="mb-0 text-gray-700 text-sm text-right mt-1 font-semibold">
{e.name}
</h2>
</div>
{faqSelect == index && (
<>
<div className="h-[1px] bg-gray-300 w-[120px] mr-5 m-5 "></div>
<p className="mb-0 text-right text-gray-500 text-sm">
{e.body}
</p>
</>
)}
</div>
))}
</div>
<Footer />
</> </>
); );
}; };

View File

@ -1,353 +1,52 @@
"use client"; import RootData from "@comp/AppsComponent/RootData/page";
import AppContext from "@ctx/AppContext";
import Chapar from "plugins/Chapar";
import Loading from "plugins/Loading/page";
import BottomSheetAddress from "plugins/bottomSheet/BottomSheetAddress";
import BottomSheetLogOut from "plugins/bottomSheet/BottomSheetLogOut";
import { useEffect, useState } from "react";
import "react-image-gallery/styles/css/image-gallery.css";
import "react-image-lightbox/style.css";
import "react-spring-bottom-sheet/dist/style.css";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
import "swiper/css";
import "../../style/fontiran.css";
import "../../style/globals.css";
import Goftino from "plugins/Goftino/page";
export const metadata = { export const metadata = {
title: "Acme", title: {
template:
"%s | خرید لوازم آرایشی و بهداشتی قیمت مناسب و اصل | فروشگاه اینترنتی وسمه",
default:
"فروشگاه اینترنتی وسمه - خرید لوازم آرایشی و بهداشتی قیمت مناسب و اصل",
},
description:
"مقایسه و خرید آنلاین انواع لوازم آرایشی، بهداشتی، خانه ، بهداشت جنسی | برندهای متنوع با پایین ترین قیمت | فروشگاه اینترنتی وسمه vesmeh.com",
metadataBase: new URL("https://www.vesmeh.com"),
authors: [
{
name: "وسمه",
url: "https://www.vesmeh.com",
},
],
keywords: [
"آرایشی",
"بهداشت خانگی",
"محصولات زیبایی",
"لوازم تمیزی",
"مراقبت شخصی",
],
openGraph: { openGraph: {
title: "Acme", title:
description: "Acme is a...", "خرید لوازم آرایشی و بهداشتی قیمت مناسب و اصل | فروشگاه اینترنتی وسمه",
description:
"مقایسه و خرید آنلاین انواع لوازم آرایشی، بهداشتی، خانه ، بهداشت جنسی | برندهای متنوع با پایین ترین قیمت | فروشگاه اینترنتی وسمه vesmeh.com",
url: "https://www.vesmeh.com",
type: "website",
},
twitter: {
site: "@vesmehstore",
description:
"مقایسه و خرید آنلاین انواع لوازم آرایشی، بهداشتی، خانه ، بهداشت جنسی | برندهای متنوع با پایین ترین قیمت | فروشگاه اینترنتی وسمه vesmeh.com",
title:
"خرید لوازم آرایشی و بهداشتی قیمت مناسب و اصل | فروشگاه اینترنتی وسمه",
creator: "@vesmehstore",
}, },
}; };
export default function RootLayout({ children }) { export default function RootLayout({ children }) {
const [cart, setCart] = useState([]);
const [products, setProducts] = useState([]);
const [pager, setPager] = useState([]);
const [navData, setNavData] = useState([]);
const [brands, setBrands] = useState([]);
const [loading, setLoading] = useState(false);
const [closeNavbar, setCloseNavbar] = useState(false);
const [bottomSheetCartOpen, setBottomSheetCartOpen] = useState(false);
const [bottomSheetFilterOpen, setBottomSheetFilterOpen] = useState(false);
const [bottomSheetDiscountOpen, setBottomSheetDiscountOpen] = useState(false);
const [bottomSheetAddressOpen, setBottomSheetAddressOpen] = useState(false);
const [bottomSheetLogOutOpen, setBottomSheetLogOutOpen] = useState(false);
const [bottomSheetDeleteAddressOpen, setBottomSheetDeleteAddressOpen] =
useState(false);
const [checkOutData, setCheckOutData] = useState([]);
const [addressData, setAddressData] = useState([]);
const [profile, setProfile] = useState([]);
const [stopProducts, setStopProducts] = useState(false);
const [pageGetProducts, setPageGetProducts] = useState(0);
const [isMobile, setIsMobile] = useState(false);
const [isOpenLightBox, setIsOpenLightBox] = useState(false);
const AddItemToCart = (
id,
persianName,
cost,
costWithDiscount,
mainImage,
hasDiscount,
maxOrderCount
) => {
setCart((prevCart) => {
// Check if the item is already in the cart
const existingItem = prevCart.find((item) => item.id === id);
let updatedCart;
if (existingItem) {
// If the item is already in the cart, update its count
if (existingItem.count < maxOrderCount) {
updatedCart = prevCart.map((item) =>
item.id === id ? { ...item, count: item.count + 1 } : item
);
} else {
// Notify user if maxOrderCount is exceeded
toast.error(
`
نمیتوانید بیشتراز
${maxOrderCount}
عدد ثبت کنید `,
{
position: "bottom-right",
closeOnClick: true,
}
);
updatedCart = prevCart;
}
} else {
// If the item is not in the cart, add it with a count of 1
updatedCart = [
...prevCart,
{
id,
count: 1,
persianName,
cost,
costWithDiscount,
mainImage,
hasDiscount,
maxOrderCount,
},
];
}
// Store the updated cart in local storage
localStorage.setItem("cart", JSON.stringify(updatedCart));
// Return the updated cart
return updatedCart;
});
};
const RemoveItemFromCart = (id) => {
setCart((prevCart) => {
// Check if the item is already in the cart
const existingItem = prevCart.find((item) => item.id === id);
if (existingItem) {
// If the item is already in the cart
if (existingItem.count === 1) {
// If the item count is 1, remove it from the cart
const updatedCart = prevCart.filter((item) => item.id !== id);
// Store the updated cart in local storage
localStorage.setItem("cart", JSON.stringify(updatedCart));
// Return the updated cart
return updatedCart;
} else {
// If the item count is greater than 1, update its count
const updatedCart = prevCart.map((item) =>
item.id === id ? { ...item, count: item.count - 1 } : item
);
// Store the updated cart in local storage
localStorage.setItem("cart", JSON.stringify(updatedCart));
// Return the updated cart
return updatedCart;
}
} else {
// If the item is not in the cart, do nothing
return prevCart;
}
});
};
const fetchNavData = async (id) => {
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/product/category?sortByMain=true`
);
const post = await res.json();
setNavData(post);
};
const fetchProducts = async (
pageGetProducts,
id,
selectedBrands,
isChecked,
minPrice,
maxPrice,
sort,
isRangePrice,
paginationSay
) => {
const brandIds = selectedBrands?.map((brand) => brand.id);
const queryString = `${`page=${pageGetProducts}`}${
id ? `&categoryId=${id}` : ""
}${
brandIds?.length > 0 ? `&brandIds=${brandIds?.join("&brandIds=")}` : ""
}${isChecked ? `&isActive=${isChecked}` : ""}${
isRangePrice ? `&minPrice=${minPrice}` : ""
}${isRangePrice ? `&maxPrice=${maxPrice}` : ""}${
!!sort ? `&sortBy=${sort}` : ""
}`;
const cleanQueryString = decodeURIComponent(
queryString.replace(/\%20/g, " ")
);
const res = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/product?${cleanQueryString}`
);
const post = await res.json();
if (paginationSay) {
// If it's a paginated request (not the first Page)
window.scrollTo({
top: 0,
behavior: "smooth", // Optional: smooth scrolling behavior
});
console.log();
setProducts(post.products);
setStopProducts(true); // Assuming this stops pagination
}
if (post.length <= 19) {
// If the length of fetched products is less than or equal to 19, indicating the last Page
setStopProducts(true); // Assuming this stops pagination
}
if (!paginationSay && pageGetProducts == 0) {
// If it's not a paginated request and it's the first Page
setProducts(post.products);
setPager(post.pager);
} else if (!paginationSay && pageGetProducts != 0) {
// If it's not a paginated request and it's not the first Page
console.log("kir", products, !!products ? products : [], post.products);
setProducts((data) => [...(data ? data : []), ...post.products]);
}
};
const fetchAddressUser = async () => {
try {
const data = await Chapar.get(
`${process.env.NEXT_PUBLIC_API_URL}/user/address`,
{
headers: {
Authorization: localStorage.getItem("token"),
},
}
);
setAddressData(data);
} catch ({ error, status }) {
toast.error(`${error?.response?.data?.message}`, {
position: "bottom-right",
closeOnClick: true,
});
setLoading(false);
}
};
const fetchUserInfo = async () => {
try {
const data = await Chapar.get(
`${process.env.NEXT_PUBLIC_API_URL}/user/info`,
{
headers: {
Authorization: localStorage.getItem("token"),
},
}
);
setProfile(data);
} catch ({ error, status }) {
localStorage.removeItem("token");
toast.error(`${error?.response?.data?.message}`, {
position: "bottom-right",
closeOnClick: true,
});
}
};
useEffect(() => {
const storedCart = localStorage.getItem("cart");
const token = localStorage.getItem("token");
if (storedCart) {
setCart(JSON.parse(storedCart));
}
if (token) {
fetchUserInfo();
}
fetchNavData();
}, []);
useEffect(() => {
const mediaQuery = window.matchMedia("(max-width: 768px)"); // Adjust the width according to your mobile breakpoint
const checkDeviceType = (mediaQuery) => {
if (mediaQuery.matches) {
setIsMobile(true);
} else {
setIsMobile(false);
}
};
// Initial check
checkDeviceType(mediaQuery);
// Listen for changes in media query
const listener = () => checkDeviceType(mediaQuery);
mediaQuery.addEventListener("change", listener);
// Clean up
return () => {
mediaQuery.removeEventListener("change", listener);
};
}, []);
return ( return (
<AppContext.Provider
value={{
state: {
cart,
products,
navData,
loading,
brands,
closeNavbar,
bottomSheetCartOpen,
bottomSheetFilterOpen,
bottomSheetDiscountOpen,
bottomSheetAddressOpen,
bottomSheetDeleteAddressOpen,
bottomSheetLogOutOpen,
checkOutData,
addressData,
profile,
stopProducts,
pageGetProducts,
pager,
isMobile,
isOpenLightBox,
},
setCart,
setProducts,
setNavData,
setLoading,
setBrands,
setBottomSheetCartOpen,
setBottomSheetFilterOpen,
setBottomSheetDiscountOpen,
setBottomSheetAddressOpen,
setBottomSheetDeleteAddressOpen,
setBottomSheetLogOutOpen,
setCheckOutData,
setStopProducts,
setProfile,
setPageGetProducts,
setPager,
setIsMobile,
setIsOpenLightBox,
AddItemToCart,
RemoveItemFromCart,
fetchNavData,
fetchProducts,
setCloseNavbar,
setAddressData,
fetchAddressUser,
}}
>
<html lang="en"> <html lang="en">
<body> <body>
{children} <RootData children={children} />
<ToastContainer position="bottom-right" closeOnClick={true} rtl />
<Loading />
<BottomSheetAddress />
<BottomSheetLogOut />
<Goftino />
</body> </body>
</html> </html>
</AppContext.Provider>
); );
} }

View File

@ -1,331 +1,39 @@
"use client"; import ProductData from "@comp/AppsComponent/ProductData/page";
import Footer from "@comp/Footer/page";
import Navbar from "@comp/Navbar/page";
import GalleryBox from "plugins/Gallery/page";
import { useEffect, useState } from "react";
import AddToCart from "@comp/Cards/Components/AddToCart/page"; export async function generateMetadata({ params }) {
import Image from "next/image"; const decodedName = decodeURIComponent(params.id[1]);
import PersianNumber from "plugins/PersianNumber";
import logo from "../../../../public/images/logo.png";
return {
title: decodedName,
description: ` خرید ${decodedName}| برندهای متنوع با پایین ترین قیمت | فروشگاه اینترنتی وسمه`,
metadataBase: new URL(
`https://www.vesmeh.com/categories/${params.id[0]}/${decodedName}`
),
keywords: [
"آرایشی",
"بهداشت خانگی",
"محصولات زیبایی",
"لوازم تمیزی",
"مراقبت شخصی",
],
openGraph: {
title: decodedName,
description: ` خرید ${decodedName}| برندهای متنوع با پایین ترین قیمت | فروشگاه اینترنتی وسمه`,
url: `https://www.vesmeh.com/categories/${params.id[0]}/${decodedName}`,
type: "website",
},
twitter: {
site: "@vesmehstore",
description: ` خرید ${decodedName}| برندهای متنوع با پایین ترین قیمت | فروشگاه اینترنتی وسمه`,
title: decodedName,
creator: "@vesmehstore",
},
};
}
const Page = ({ params }) => { const Page = ({ params }) => {
const [product, setProduct] = useState([]);
const [specificationsHeader, setSpecificationsHeader] = useState([]);
const fetchPost = async (id) => {
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/product/${id}`);
const post = await res.json();
setProduct(post.product);
};
console.log("product", product);
const displaySpecifications = (specs) => {
let data = [];
if (specs?.length > 3) {
specs?.slice(0, 3).forEach((spec) => {
const { title, value } = spec;
data.push(`${title}: ${value}`);
});
} else {
specs?.forEach((spec) => {
const { title, value } = spec;
data.push(`${title}: ${value}`);
});
}
setSpecificationsHeader(data); // You can replace console.log with any method to display the content in your header
};
useEffect(() => {
fetchPost(params.id[0]);
}, []);
useEffect(() => {
displaySpecifications(product?.specifications);
}, [product]);
return ( return (
<> <>
<Navbar theme={1} /> <ProductData params={params} />
<div className=" py-10">
<div className="grid xs:grid-cols-1 lg:grid-cols-8 rtl gap-6 lg:px-20">
<div className="lg:col-span-3 ">
<GalleryBox file={product.files} />
</div>
<div className="lg:col-span-3 xs:px-5 lg:px-0 ">
<div className="text-right mt-7">
<h1 className="text-lg font-semibold ">{product.persianName} </h1>
<p className="mb-0 text-sm text-gray-400">
{product?.englishName}{" "}
</p>
</div>
<div className="flex my-4">
<div className="bg-primary-400 rounded-full py-1 px-3 ml-2">
<p className="mb-0 text-sm text-white ">اصالت کالای </p>
</div>
{product?.hasDiscount && (
<div className="bg-danger-100 rounded-full py-1 px-3 ml-2">
<p className="mb-0 text-sm text-white ">بمب امروز </p>
</div>
)}
{!product?.warranty == "" && (
<div className="bg-secondary-500 rounded-full py-1 px-3 ml-2">
<p className="mb-0 text-sm text-white ">
{product?.warranty}
</p>
</div>
)}
</div>
{/* <div className="flex my-5">
<div className="w-[30px] h-[30px] rounded-full bg-red-800 border-[5px] border-white shadow mr-2 cursor-pointer "></div>
<div className="w-[30px] h-[30px] rounded-full bg-red-700 border-[5px] border-white shadow mr-2 cursor-pointer "></div>
<div className="w-[30px] h-[30px] rounded-full bg-red-600 border-[5px] border-white shadow mr-2 cursor-pointer "></div>
<div className="w-[30px] h-[30px] rounded-full bg-red-500 border-[5px] border-green-300 scale-110 shadow mr-2 cursor-pointer "></div>
<div className="w-[30px] h-[30px] rounded-full bg-red-400 border-[5px] border-white shadow mr-2 cursor-pointer "></div>
<div className="w-[30px] h-[30px] rounded-full bg-red-300 border-[5px] border-white shadow mr-2 cursor-pointer "></div>
<div className="w-[30px] h-[30px] rounded-full bg-red-200 border-[5px] border-white shadow mr-2 cursor-pointer "></div>
</div> */}
<div>
<div className="text-right mt-3 flex justify-between">
<h2 className="mb-0 text-gray-400 text-sm">
{product?.summery}
</h2>
</div>
</div>
<ul className="mt-3 px-3">
{specificationsHeader.map((e, index) => (
<li className=" flex my-2" key={index}>
<div className="w-[10px] h-[10px] relative rounded-full bg-primary-500 mt-1"></div>
<p className="mb-0 w-full text-sm text-gray-700 mx-2 ">
{e}
</p>
</li>
))}
</ul>
</div>
{/* xs:sticky lg:relative xs:top-[60px] lg:top-0 ==> sticky for price=================== */}
<div className=" w-9/12 lg:col-span-2 sticky top-[80px] xs:hidden lg:block ">
<div className="p-3 h-fit border-[1px] border-gray-300 rounded-xl ">
<div className="flex justify-center">
<div className="w-[130px]">
{product.files?.length > 0 ? (
<Image
src={`${process.env.NEXT_PUBLIC_STORAGE_URL}/${
product.files && product.files[0].fileLocation
}`}
width={350}
height={350}
className=" mx-auto !object-cover"
onClick={() => CTX.setIsOpenLightBox(true)}
alt=""
/>
) : (
<div className="xs:!w-[85px] lg:!w-[85px] my-10 ">
<Image
src={logo}
className="xs:!w-[70px] lg:!w-[70px] mx-auto !object-cover opacity-25 mt-5"
alt=""
/>
</div>
)}
</div>
</div>
<div className="text-center">
<p className="mb-0 text-sm text-gray-500">
{product.persianName}{" "}
</p>
</div>
<div className="w-6/12 mx-auto h-[1px] bg-gray-200 mt-4"></div>
<div className="flex justify-center mt-3">
<div>
<svg
width="15"
height="15"
viewBox="0 0 226 264"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="ml-1 mt-[2px]"
>
<path
d="M94.25 137.531L69.9687 113.25L56.75 126.469L94.25 163.969L169.25 88.9687L156.031 75.75L94.25 137.531Z"
fill="black"
/>
<path
d="M113 263.25L55.1001 232.378C38.5938 223.597 24.7904 210.486 15.1712 194.454C5.552 178.421 0.48019 160.072 0.500058 141.375V19.5C0.505022 14.5287 2.48206 9.76246 5.99729 6.24723C9.51252 2.732 14.2788 0.754964 19.2501 0.75H206.75C211.721 0.754964 216.488 2.732 220.003 6.24723C223.518 9.76246 225.495 14.5287 225.5 19.5V141.375C225.52 160.072 220.448 178.421 210.829 194.454C201.21 210.486 187.406 223.597 170.9 232.378L113 263.25ZM19.2501 19.5V141.375C19.2345 156.673 23.3854 171.687 31.2572 184.804C39.129 197.922 50.4245 208.648 63.9313 215.831L113 241.997L162.069 215.841C175.577 208.656 186.873 197.929 194.745 184.81C202.617 171.69 206.767 156.675 206.75 141.375V19.5H19.2501Z"
fill="black"
/>
</svg>
</div>
<p className="mb-0 text-[12px] font-bold">
گارانتی{" "}
<small className=" text-primary-500 text-[12px]">اصالت</small>{" "}
و{" "}
<small className=" text-primary-500 text-[12px]">
سلامت فیزیکی کالا
</small>
</p>
</div>
<div className="w-6/12 mx-auto h-[1px] bg-gray-200 mt-4"></div>
<div className=" mt-4 flex justify-between ">
{true ? (
<div className="flex justify-end">
<div className="mb-0 font-bold text-sm absolute mt-[-11px] ml-[0px] right-0 mr-[13px] text-red-600 flex rtl">
<del>
<PersianNumber
number={(product?.cost / 10).toLocaleString()}
style={"text-[13px] opacity-40 "}
/>
</del>
</div>
<div className="flex rtl mt-[8px]">
{" "}
<p className="mb-0 font-bold">
<PersianNumber
number={(
product?.costWithDiscount / 10
).toLocaleString()}
/>
</p>
<small className="mr-1 mt-[3px]">تومان</small>
</div>
</div>
) : (
<div className="flex rtl mt-[3px]">
{" "}
<p className="mb-0 font-bold text-lg">
<PersianNumber
number={(data?.cost / 10).toLocaleString()}
/>
</p>
<small className="mr-1 mt-[6px]">تومان</small>
</div>
)}
<AddToCart data={product} theme={2} />
</div>
</div>
</div>
<div className="lg:col-span-6">
<div className="xs:px-[15px] lg:px-[100px]">
<div className="bg-gray-200 rounded-full xs:p-2 lg:p-3 flex w-fit ">
<div className="bg-primary-500 rounded-full p-3 ">
<p className=" xs:hidden lg:block mb-0 text-[12px] text-white">
مشخصات محصول
</p>
<p className=" xs:block lg:hidden mb-0 text-[12px] text-white">
مشخصات
</p>
</div>
<div className=" rounded-full p-3 ">
<p className="mb-0 text-[13px] text-gray-500">روش استفاده</p>
</div>
<div className=" rounded-full p-3 ">
<p className="mb-0 text-[13px] text-gray-500">نقد و بررسی</p>
</div>
<div className=" rounded-full p-3 ">
<p className=" xs:hidden lg:block mb-0 text-[13px] text-gray-500">
دیدگاه مخاطبان
</p>
<p className=" xs:block lg:hidden mb-0 text-[13px] text-gray-500">
مخاطبان
</p>
</div>
</div>
<div>
<h3 className=" text-sm text-gray-400 mt-7 mb-2">
مشخصات محصول
</h3>
<div className="min-w-[200px] mt-5 rounded-xl overflow-hidden border rtl ">
{product?.specifications?.map((e, index) => (
<div
className={
index % 2 === 0 ? "bg-gray-50 p-3" : "bg-gray-100 p-3"
}
key={index}
>
<p className="mb-0 text-sm text-gray-600">
{e.title}:
<small className="text-sm text-gray-800 font-bold ">
{" "}
{e.value}{" "}
</small>
</p>
</div>
))}
</div>
</div>
<div>
<h3 className=" text-sm text-gray-400 mt-7 mb-2">
روش استفاده
</h3>
<div dangerouslySetInnerHTML={{ __html: product.summery }} />
</div>
</div>
<div className="xs:block lg:hidden sticky bottom-0 ">
<div className="w-full bg-[white] p-2 border-t-[1px] border-gray-100 mt-[30px]">
<div className="py-4 flex ltr justify-between px-4 relative">
{product?.hasDiscount ? (
<>
<p className="mb-0 font-bold text-sm absolute ml-[33px] opacity-30 mt-[-5px] text-red-600">
<del>
<PersianNumber
number={(product?.cost / 10).toLocaleString()}
style="!text-[11px]"
/>
</del>
</p>
<div className="flex rtl mt-[8px]">
{" "}
<p className="mb-0 font-bold">
<PersianNumber
number={(
product?.costWithDiscount / 10
).toLocaleString()}
/>
</p>
<small className="mr-1 mt-[3px]">تومان</small>
</div>
</>
) : (
<div className="flex rtl mt-[3px]">
{" "}
<p className="mb-0 font-bold text-lg">
<PersianNumber
number={(product?.cost / 10).toLocaleString()}
/>
</p>
<small className="mr-1 mt-[6px]">تومان</small>
</div>
)}
<AddToCart data={product} theme={2} />
</div>
</div>
</div>
</div>
</div>
</div>
<Footer />
</> </>
); );
}; };

View File

@ -1,6 +1,8 @@
import Footer from "@comp/Footer/page"; import Footer from "@comp/Footer/page";
import Navbar from "@comp/Navbar/page"; import Navbar from "@comp/Navbar/page";
export const metadata = {
title: "قوانین و مقررات فروشگاه وسمه ",
};
const Page = () => { const Page = () => {
const number = "02188195164"; const number = "02188195164";
return ( return (