From 167439c97abcf76cbb9ddb9f5d3f7688d49f26be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D8=AD=D8=B3=DB=8C=D9=86=20=D9=85=D8=B9=D8=B5=D9=88=D9=85?= =?UTF-8?q?=DB=8C=20=D9=BE=D9=88=D8=B1?= Date: Fri, 24 May 2024 16:39:21 +0330 Subject: [PATCH] add offer blog page --- .env.production | 2 +- Dockerfile.x | 18 +++ components/AppsComponent/ProductData/page.jsx | 28 +++- components/AppsComponent/RootData/page.jsx | 37 +++++ .../SliderProductsOffer/page.jsx | 138 ++++++++++++++++++ components/Blog/BlogComponents/styleBlog.css | 35 ++++- components/Blog/BlogData/page.jsx | 53 +++++-- components/Blog/BlogsData/page.jsx | 1 + components/TimerDown/TimerDown.jsx | 38 ++--- components/TimerDownBlog/TimerDown.jsx | 103 +++++++++++++ package-lock.json | 38 +++++ src/app/603413.txt | 0 src/app/blogs/[...id]/page.jsx | 4 +- src/app/blogs/page.jsx | 7 +- src/app/categories/[...id]/page.jsx | 5 +- src/app/page.jsx | 38 ++--- src/app/products/[...id]/page.jsx | 5 +- 17 files changed, 466 insertions(+), 84 deletions(-) create mode 100644 Dockerfile.x create mode 100644 components/Blog/BlogComponents/SliderProductsOffer/page.jsx create mode 100644 components/TimerDownBlog/TimerDown.jsx delete mode 100644 src/app/603413.txt diff --git a/.env.production b/.env.production index bc930c3..5c1b4a3 100644 --- a/.env.production +++ b/.env.production @@ -6,4 +6,4 @@ NEXT_PUBLIC_PUBLIC_URL=https://api.vesmeh.com NEXT_PUBLIC_API_URL=https://api.vesmeh.com/api NEXT_PUBLIC_STORAGE_URL=http://storage.vesmeh.com STORAGE_URL=http://storage.vesmeh.com -NEXT_PUBLIC_PACKAGE_VERSION=0.31.3 \ No newline at end of file +NEXT_PUBLIC_PACKAGE_VERSION=0.32.31 \ No newline at end of file diff --git a/Dockerfile.x b/Dockerfile.x new file mode 100644 index 0000000..3c72cc0 --- /dev/null +++ b/Dockerfile.x @@ -0,0 +1,18 @@ +FROM node:20-alpine3.18 AS runner +WORKDIR /app +ARG NODE_ENV=production +COPY public ./public +COPY .next ./.next +COPY node_modules ./node_modules +COPY package.json ./package.json +COPY .env.production ./.env.production +COPY next.config.js ./next.config.js + +EXPOSE 3000 +ENV PORT 3000 +CMD ["node_modules/.bin/next", "start"] + + + + +# docker build -f Dockerfile.x -t registry.vnfco.ir/netinashop/vesmeh:0.32.31 . \ No newline at end of file diff --git a/components/AppsComponent/ProductData/page.jsx b/components/AppsComponent/ProductData/page.jsx index 28821c4..dca2197 100644 --- a/components/AppsComponent/ProductData/page.jsx +++ b/components/AppsComponent/ProductData/page.jsx @@ -10,6 +10,7 @@ import PersianNumber from "plugins/PersianNumber"; import logo from "../../../public/images/logo.png"; const ProductData = ({ params, data }) => { + console.log("data", data); const [product, setProduct] = useState([]); const [specificationsHeader, setSpecificationsHeader] = useState([]); const [productBarDetail, setProductBarDetail] = useState(0); @@ -128,10 +129,10 @@ const ProductData = ({ params, data }) => { {/* xs:sticky lg:relative xs:top-[60px] lg:top-0 ==> sticky for price=================== */} -
+
-
+
{data?.product?.files?.length > 0 ? ( {
-

+

{data?.product?.persianName}{" "}

@@ -332,13 +333,24 @@ const ProductData = ({ params, data }) => {

نقد و برسی{" "}

-
-
-
- چیزی یافت نشد + + {!!data?.product.expertCheck ? ( +
+
+
+ ) : ( +
+
+
+ چیزی یافت نشد +
-
{" "} + )}
diff --git a/components/AppsComponent/RootData/page.jsx b/components/AppsComponent/RootData/page.jsx index 58560d7..e85e035 100644 --- a/components/AppsComponent/RootData/page.jsx +++ b/components/AppsComponent/RootData/page.jsx @@ -53,6 +53,10 @@ const RootData = ({ children }) => { const [searchResultData, setSearchResultData] = useState([]); const [isSearched, setIsSearched] = useState(false); + const [specialOfferData, setSpecialOfferData] = useState([]); + const [cosmeticData, setCosmeticData] = useState([]); + const [HomeCosmeticData, setHomeCosmeticData] = useState([]); + const [isChecked, setIsChecked] = useState(false); const [selectedBrands, setSelectedBrands] = useState([]); const [rangePrice, setRangePrice] = useState([1000, 100]); @@ -431,6 +435,30 @@ const RootData = ({ children }) => { } }; + const fetchSpecialOffer = async () => { + const res = await fetch( + `${process.env.NEXT_PUBLIC_API_URL}/product?page=0&specialOffer=true` + ); + const specialOffer = await res.json(); + setSpecialOfferData(specialOffer); + }; + + const fetchCosmetic = async () => { + const res = await fetch( + `${process.env.NEXT_PUBLIC_API_URL}/product?page=0&categoryId=553af942-7a14-4757-9a03-a3ebec6c865a` + ); + const Cosmetic = await res.json(); + setCosmeticData(Cosmetic); + }; + + const fetchHomeCosmetic = async () => { + const res = await fetch( + `${process.env.NEXT_PUBLIC_API_URL}/product?page=0&categoryId=effe5d98-d4b7-47e1-9bfb-4d3c77ab3347` + ); + const HomeCosmetic = await res.json(); + setHomeCosmeticData(HomeCosmetic); + }; + useEffect(() => { const storedCart = localStorage.getItem("cart"); const token = localStorage.getItem("token"); @@ -506,6 +534,9 @@ const RootData = ({ children }) => { cooperationSystemProfileData, searchResultData, isSearched, + cosmeticData, + HomeCosmeticData, + specialOfferData, }, setCart, setProducts, @@ -550,6 +581,12 @@ const RootData = ({ children }) => { fetchCooperationSystemProfileContract, setSearchResultData, fetchSearchResult, + setHomeCosmeticData, + setCosmeticData, + setSpecialOfferData, + fetchHomeCosmetic, + fetchCosmetic, + fetchSpecialOffer, }} > {children} diff --git a/components/Blog/BlogComponents/SliderProductsOffer/page.jsx b/components/Blog/BlogComponents/SliderProductsOffer/page.jsx new file mode 100644 index 0000000..72c6a9b --- /dev/null +++ b/components/Blog/BlogComponents/SliderProductsOffer/page.jsx @@ -0,0 +1,138 @@ +import TimerDownBlog from "@comp/TimerDown/TimerDown"; +import Image from "next/image"; +import Link from "next/link"; +import hyphenateString from "plugins/HyphenateString/page"; +import PersianNumber from "plugins/PersianNumber"; +import React, { useEffect, useState } from "react"; + +const SliderProductsOffer = ({ data }) => { + const [currentIndex, setCurrentIndex] = useState(0); + + // Filter to get the latest 10 products + const latestProducts = data?.products?.slice(-10) || []; + + useEffect(() => { + const interval = setInterval(() => { + setCurrentIndex((prevIndex) => (prevIndex + 1) % latestProducts.length); + }, 10000); // 10 seconds + + return () => clearInterval(interval); // Clean up on unmount + }, [latestProducts.length]); + + const handleDotClick = (index) => { + setCurrentIndex(index); + }; + + return ( +
+ {" "} + {data?.products?.map((e, index) => ( +
+ +
+
+
+
+
+ {/* Uncomment and adjust the Image component as needed */} + {e?.persianName} +
+
+ +
+

+ {e?.persianName} +

+
+
+ +
+

+ + تومان +

+
+
+

+ تضمین بهترین قیمت +

+
+
+
+ +
+
+ +
+
+
+ +
+ + + +
+
+ +
+ + + +
+
+ +
+
+
+
+ +
+ ))} +
+ {latestProducts.map((_, index) => ( +
handleDotClick(index)} + className={`w-3 h-3 mx-[1px] mt-1 rounded-full cursor-pointer ${ + index === currentIndex + ? "bg-contact-us w-7" + : "bg-primary-200 opacity-80" + }`} + >
+ ))} +
+
+ ); +}; + +export default SliderProductsOffer; diff --git a/components/Blog/BlogComponents/styleBlog.css b/components/Blog/BlogComponents/styleBlog.css index 26aac25..a6c3970 100644 --- a/components/Blog/BlogComponents/styleBlog.css +++ b/components/Blog/BlogComponents/styleBlog.css @@ -1,20 +1,39 @@ -h2 { +#blog-content > h2 { color: rgb(0, 49, 155); - font-weight: 700; margin-top: 15px; margin-bottom: 2px; + font-size: 16px; } -p { +#blog-content > p { color: rgb(54, 54, 54); font-weight: 400; + @apply leading-8 text-base; +} +#blog-content > li { + color: rgb(54, 54, 54); + font-weight: 400; + @apply leading-8 text-base; +} +#blog-content > a { + color: rgb(54, 54, 54); + font-weight: 400; + @apply leading-8 text-base text-blue-700 hover:text-blue-900; } -h3 { - color: rgb(216, 16, 16); - - font-weight: 600; +#blog-content > h3 { + color: rgb(216, 16, 16) !important; + font-weight: 400; margin-top: 15px; margin-bottom: 2px; - margin-right: 10px; + font-size: 20px; + /* margin-right: 10px; */ +} + +#blog-content > img { + @apply rounded-xl mx-auto shadow-lg my-8; +} + +#blog-content > iframe { + @apply rounded-xl mx-auto shadow-lg my-8; } diff --git a/components/Blog/BlogData/page.jsx b/components/Blog/BlogData/page.jsx index 03a0241..ffab896 100644 --- a/components/Blog/BlogData/page.jsx +++ b/components/Blog/BlogData/page.jsx @@ -1,29 +1,52 @@ "use client"; import Image from "next/image"; -import React, { useEffect, useState } from "react"; +import React, { useContext, useEffect, useState } from "react"; import Footer from "@comp/Footer/page"; import Navbar from "@comp/Navbar/page"; - +import "../BlogComponents/styleBlog.css"; +import TimerDown from "@comp/TimerDown/TimerDown"; +import TimerDownBlog from "@comp/TimerDown/TimerDown"; +import PersianNumber from "plugins/PersianNumber"; +import SliderProductsOffer from "../BlogComponents/SliderProductsOffer/page"; +import AppContext from "@ctx/AppContext"; const BlogData = ({ data }) => { + const CTX = useContext(AppContext); + + const specialOfferData = CTX.state.specialOfferData; + + useEffect(() => { + if (specialOfferData.length <= 0) { + CTX.fetchSpecialOffer(); + } + }, []); return (
-
-
- -

- {data.title} -

-
-
+
+
+
+ +

+ {data.title} +

+
+
+
+
+ +
+
diff --git a/components/Blog/BlogsData/page.jsx b/components/Blog/BlogsData/page.jsx index 4a744c5..09fbd78 100644 --- a/components/Blog/BlogsData/page.jsx +++ b/components/Blog/BlogsData/page.jsx @@ -9,6 +9,7 @@ import Cart from "../BlogComponents/Cart"; import PaginationBlogs from "../BlogComponents/PaginationBlogs"; const BlogsData = ({ dataCaetgories, data }) => { + console.log("data", data); const pathname = usePathname(); const searchParams = useSearchParams(); const router = useRouter(); diff --git a/components/TimerDown/TimerDown.jsx b/components/TimerDown/TimerDown.jsx index 445da7c..90340ea 100644 --- a/components/TimerDown/TimerDown.jsx +++ b/components/TimerDown/TimerDown.jsx @@ -3,7 +3,7 @@ import Link from "next/link"; import PersianNumber from "plugins/PersianNumber"; import { useEffect, useState } from "react"; -const TimerDown = () => { +const TimerDownBlog = () => { const [timeRemaining, setTimeRemaining] = useState({ days: 0, hours: 0, @@ -54,50 +54,50 @@ const TimerDown = () => { }, []); return ( -
-
-

+

+
+

-

روز

+

روز

-
-

+

+

-

ساعت

+

ساعت

-
-

+

+

-

دقیقه

+

دقیقه

-
+
{" "} -

+

-

ثانیه

+

ثانیه

); }; -export default TimerDown; +export default TimerDownBlog; diff --git a/components/TimerDownBlog/TimerDown.jsx b/components/TimerDownBlog/TimerDown.jsx new file mode 100644 index 0000000..445da7c --- /dev/null +++ b/components/TimerDownBlog/TimerDown.jsx @@ -0,0 +1,103 @@ +"use client"; +import Link from "next/link"; +import PersianNumber from "plugins/PersianNumber"; +import { useEffect, useState } from "react"; + +const TimerDown = () => { + const [timeRemaining, setTimeRemaining] = useState({ + days: 0, + hours: 0, + minutes: 0, + seconds: 0, + milliseconds: 0, + }); + + useEffect(() => { + const calculateTimeRemaining = () => { + // Get current date and time + const now = new Date(); + + // Calculate yesterday's date + const yesterday = new Date(now); + yesterday.setDate(now.getDate() - 1); + yesterday.setHours(23, 59, 0, 0); // Set time to 23:59:00 + + // Calculate tomorrow's date + const tomorrow = new Date(now); + tomorrow.setDate(now.getDate() + 1); + tomorrow.setHours(23, 59, 0, 0); // Set time to 23:59:00 + + // Calculate time difference + const difference = tomorrow - now; + + // Convert time difference to days, hours, minutes, seconds, and milliseconds + const days = Math.floor(difference / (1000 * 60 * 60 * 24)); + const hours = Math.floor( + (difference % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60) + ); + const minutes = Math.floor((difference % (1000 * 60 * 60)) / (1000 * 60)); + const seconds = Math.floor((difference % (1000 * 60)) / 1000); + const milliseconds = difference % 1000; + + // Update state + setTimeRemaining({ days, hours, minutes, seconds, milliseconds }); + }; + + // Call calculateTimeRemaining once to set initial state + calculateTimeRemaining(); + + // Update time remaining every second + const intervalId = setInterval(calculateTimeRemaining, 1000); + + // Clean up interval on component unmount + return () => clearInterval(intervalId); + }, []); + + return ( +
+
+

+ +

+ +

روز

+
+ +
+

+ +

+

ساعت

+
+
+

+ +

+

دقیقه

+
+
+ + {" "} +

+ +

+

ثانیه

+ +
+
+ ); +}; + +export default TimerDown; diff --git a/package-lock.json b/package-lock.json index a5c26e7..699a249 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4649,6 +4649,30 @@ } } }, + "node_modules/react-spring-bottom-sheet/node_modules/react-dom": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", + "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.2" + }, + "peerDependencies": { + "react": "17.0.2" + } + }, + "node_modules/react-spring-bottom-sheet/node_modules/scheduler": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", + "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, "node_modules/react-toastify": { "version": "9.1.3", "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.1.3.tgz", @@ -5547,6 +5571,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", diff --git a/src/app/603413.txt b/src/app/603413.txt deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/blogs/[...id]/page.jsx b/src/app/blogs/[...id]/page.jsx index 2d76191..5aec8fa 100644 --- a/src/app/blogs/[...id]/page.jsx +++ b/src/app/blogs/[...id]/page.jsx @@ -2,7 +2,9 @@ import BlogData from "@comp/Blog/BlogData/page"; import React from "react"; async function getData(id) { - const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/blog/${id}`); + const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/blog/${id}`, { + cache: "no-cache", + }); const post = await res.json(); return post; } diff --git a/src/app/blogs/page.jsx b/src/app/blogs/page.jsx index 5179a43..8afeb6a 100644 --- a/src/app/blogs/page.jsx +++ b/src/app/blogs/page.jsx @@ -11,13 +11,18 @@ async function getData(sParams) { const res = await fetch( `${process.env.NEXT_PUBLIC_API_URL}/blog?` + - new URLSearchParams({ ...query }) + new URLSearchParams({ ...query }), + { + cache: "no-cache", + } // ?page=${params.page ?? 0} // { cache: "no-cache" } ); const post = await res.json(); // + console.log("post", post); + return post; } diff --git a/src/app/categories/[...id]/page.jsx b/src/app/categories/[...id]/page.jsx index cb78cf4..b78aebe 100644 --- a/src/app/categories/[...id]/page.jsx +++ b/src/app/categories/[...id]/page.jsx @@ -63,7 +63,10 @@ const fetchProducts = async (categoryId, searchParams) => { const res = await fetch( `${process.env.NEXT_PUBLIC_API_URL}/product?` + new URLSearchParams({ ...query }) + - brandIdsQuery + brandIdsQuery, + { + cache: "no-cache", + } ); if (!res.ok) return []; const products = await res.json(); diff --git a/src/app/page.jsx b/src/app/page.jsx index 95cda91..b4e05a9 100644 --- a/src/app/page.jsx +++ b/src/app/page.jsx @@ -7,41 +7,21 @@ import HeroSection from "@comp/LandingPage/HeroSection/page"; import HomeSection from "@comp/LandingPage/HomeSection/page"; import SurpriseSection from "@comp/LandingPage/SurpriseSection/page"; import Navbar from "@comp/Navbar/page"; +import AppContext from "@ctx/AppContext"; import Head from "next/head"; -import { useEffect, useState } from "react"; +import { useContext, useEffect, useState } from "react"; export default function Page() { - const [specialOfferData, setSpecialOfferData] = useState([]); - const [cosmeticData, setCosmeticData] = useState([]); - const [HomeCosmeticData, setHomeCosmeticData] = useState([]); - const fetchSpecialOffer = async () => { - const res = await fetch( - `${process.env.NEXT_PUBLIC_API_URL}/product?page=0&specialOffer=true` - ); - const specialOffer = await res.json(); - setSpecialOfferData(specialOffer); - }; + const CTX = useContext(AppContext); - const fetchCosmetic = async () => { - const res = await fetch( - `${process.env.NEXT_PUBLIC_API_URL}/product?page=0&categoryId=553af942-7a14-4757-9a03-a3ebec6c865a` - ); - const Cosmetic = await res.json(); - setCosmeticData(Cosmetic); - }; - - const fetchHomeCosmetic = async () => { - const res = await fetch( - `${process.env.NEXT_PUBLIC_API_URL}/product?page=0&categoryId=effe5d98-d4b7-47e1-9bfb-4d3c77ab3347` - ); - const HomeCosmetic = await res.json(); - setHomeCosmeticData(HomeCosmetic); - }; + const specialOfferData = CTX.state.specialOfferData; + const cosmeticData = CTX.state.cosmeticData; + const HomeCosmeticData = CTX.state.HomeCosmeticData; useEffect(() => { - fetchSpecialOffer(); - fetchCosmetic(); - fetchHomeCosmetic(); + CTX.fetchSpecialOffer(); + CTX.fetchCosmetic(); + CTX.fetchHomeCosmetic(); }, []); return ( <> diff --git a/src/app/products/[...id]/page.jsx b/src/app/products/[...id]/page.jsx index 1f35c20..523ac1a 100644 --- a/src/app/products/[...id]/page.jsx +++ b/src/app/products/[...id]/page.jsx @@ -1,8 +1,11 @@ import ProductData from "@comp/AppsComponent/ProductData/page"; async function getData(id) { - const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/product/${id}`); + const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/product/${id}`, { + cache: "no-cache", + }); const post = await res.json(); + console.log("object11", post); return post; }