diff --git a/public/About/about_hand.png b/public/About/about_hand.png new file mode 100644 index 0000000..cf91903 Binary files /dev/null and b/public/About/about_hand.png differ diff --git a/public/About/about_lap.png b/public/About/about_lap.png new file mode 100644 index 0000000..140f698 Binary files /dev/null and b/public/About/about_lap.png differ diff --git a/public/App/Logo.png b/public/App/Logo.png index 6d64fe9..fe35b31 100644 Binary files a/public/App/Logo.png and b/public/App/Logo.png differ diff --git a/public/App/Logo.svg b/public/App/Logo.svg index b4fa18d..e0303f2 100644 --- a/public/App/Logo.svg +++ b/public/App/Logo.svg @@ -1,6 +1,6 @@ - + diff --git a/public/Cart/empty_card.gif b/public/Cart/empty_card.gif new file mode 100644 index 0000000..55ba611 Binary files /dev/null and b/public/Cart/empty_card.gif differ diff --git a/public/Home/HeroShape.svg b/public/Home/HeroShape.svg index bef788d..cdb988a 100644 --- a/public/Home/HeroShape.svg +++ b/public/Home/HeroShape.svg @@ -1,3 +1,3 @@ - + diff --git a/public/Home/Noise_Cancellation.svg b/public/Home/Noise_Cancellation.svg index ef55a08..29857cf 100644 --- a/public/Home/Noise_Cancellation.svg +++ b/public/Home/Noise_Cancellation.svg @@ -3,7 +3,7 @@ - + diff --git a/public/Layout/DMlOGO.png b/public/Layout/DMlOGO.png new file mode 100644 index 0000000..fe35b31 Binary files /dev/null and b/public/Layout/DMlOGO.png differ diff --git a/public/firebase-messaging-sw.js b/public/firebase-messaging-sw.js index f316b91..df49f92 100644 --- a/public/firebase-messaging-sw.js +++ b/public/firebase-messaging-sw.js @@ -18,7 +18,6 @@ firebase.initializeApp(firebaseConfig); const messaging = firebase.messaging(); messaging.onBackgroundMessage(function (payload) { - console.log("Received background message ", payload); const notificationTitle = payload.notification.title; const notificationOptions = { diff --git a/public/icon/notfound_search.png b/public/icon/notfound_search.png new file mode 100644 index 0000000..dfc2f4c Binary files /dev/null and b/public/icon/notfound_search.png differ diff --git a/public/index.html b/public/index.html index 06a1d83..5913f58 100644 --- a/public/index.html +++ b/public/index.html @@ -4,13 +4,13 @@ - - + + - - - + + + diff --git a/public/site.webmanifest b/public/site.webmanifest index 3be812d..32f1c85 100644 --- a/public/site.webmanifest +++ b/public/site.webmanifest @@ -8,20 +8,20 @@ "theme_color": "#000000", "icons": [ { - "src": "./App/Logo.svg", + "src": "./App/Logo.png", "sizes": "192x192", "type": "image/png" }, { - "src": "./App/Logo.svg", + "src": "./App/Logo.png", "sizes": "512x512", "type": "image/png" }, { - "src": "./App/Logo.svg", + "src": "./App/Logo.png", "sizes": "192x192", "type": "image/png", "purpose": "maskable" } ] -} +} \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx index 999b8b4..b1a15b7 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -19,12 +19,12 @@ const App = () => { } }, [data]); - + const randomtoken = Math.random() useEffect(() => { const fn_firebase = (async () => { - const token = await requestPermission() + // const token = await requestPermission() if (!Guest) { - mutate({ fcm_token: token }); + mutate({ fcm_token: randomtoken }); } }) fn_firebase() diff --git a/src/Components/Categories/Connectivity.tsx b/src/Components/Categories/Connectivity.tsx index c2ed845..ae6a7c6 100644 --- a/src/Components/Categories/Connectivity.tsx +++ b/src/Components/Categories/Connectivity.tsx @@ -13,8 +13,6 @@ const BrandFilter = () => { (Category: Category): CheckboxProps["onChange"] => (e) => { const checked = e.target.checked; - console.log(Category); - console.log(languageObject(Category?.name)); if (checked) { diff --git a/src/Components/HOC/CartWithDrawer.tsx b/src/Components/HOC/CartWithDrawer.tsx index f515486..f413d51 100644 --- a/src/Components/HOC/CartWithDrawer.tsx +++ b/src/Components/HOC/CartWithDrawer.tsx @@ -19,14 +19,18 @@ const CartWithDrawer = () => { const { t } = useTranslation(); const { Cart, calculateTotalPrice, calculateTotalQuantity, removeCart } = useCartState(); - const { user } = useAuthState(); + const { user ,isAuthenticated} = useAuthState(); const { mutate, isLoading, isSuccess } = useAddOrder(); const products = Cart?.map((item: any) => ({ quantity: item?.quantity, id: item?.id, })); - + const addOrder = () => { + if (!isAuthenticated) { + toast.error("sorry you need to be authenticated"); + return; + } mutate({ email: user?.email, products: products, @@ -60,8 +64,8 @@ const CartWithDrawer = () => { onClose={() => setOpen(false)} open={open} key={placement} - width={550} - style={{maxHeight:"90%"}} + width={450} + style={{maxHeight:"60%", minHeight:"500px"}} >
{t("Cart")} @@ -76,6 +80,7 @@ const CartWithDrawer = () => { ))}
+ {Cart?.length > 0 ? (
@@ -97,7 +102,10 @@ const CartWithDrawer = () => {
) : ( -
+
+ {/* +

{t('You have not placed any orders yet')}

*/} +
)} diff --git a/src/Components/HOC/ChangeMode.tsx b/src/Components/HOC/ChangeMode.tsx index e41fe5f..42e295a 100644 --- a/src/Components/HOC/ChangeMode.tsx +++ b/src/Components/HOC/ChangeMode.tsx @@ -16,7 +16,7 @@ export const ChangeModeComp = ({onClickFunction, src, modeText,icon, isImage = t const ModeContainer = memo(() => (
{isImage - ? ModeImage + ? ModeImage : icon } {t(modeText)} diff --git a/src/Components/HOC/SearchWithDrawer.tsx b/src/Components/HOC/SearchWithDrawer.tsx index 53a8c7a..f3ae48e 100644 --- a/src/Components/HOC/SearchWithDrawer.tsx +++ b/src/Components/HOC/SearchWithDrawer.tsx @@ -1,33 +1,22 @@ -import React, { useState, ReactNode } from 'react'; +import { useState } from 'react'; import type { DrawerProps } from 'antd'; -import { Badge, Button, Drawer, Space } from 'antd'; -import CardItem from '../Cart/CardItem'; -import { BsArrowLeft, BsCart, BsSearch } from 'react-icons/bs'; -import { Link } from 'react-router-dom'; -import { ShoppingCartOutlined } from '@ant-design/icons'; -import { useCartData } from '../../Redux/DispatchData'; -import { useTranslation } from 'react-i18next'; +import { Drawer, Space } from 'antd'; import { TiDeleteOutline } from "react-icons/ti"; import SearchButton from '../Utils/Search/SearchButton'; -import { GoClock } from "react-icons/go"; -import { FiDelete } from "react-icons/fi"; -import { RiSearch2Line, RiSearchLine } from "react-icons/ri"; - - +import { RiSearchLine } from "react-icons/ri"; +import Empty from '../Utils/Search/Empty'; const SearchWithDrawer = () => { const [open, setOpen] = useState(false); const [placement, setPlacement] = useState('right'); - const { DataCart,count} = useCartData() - const {t} = useTranslation(); - - + const [noDataFound, setNoDataFound] = useState(false); + return ( <> -
setOpen(true)} className="icon_navbar"> - -
+
setOpen(true)} className="icon_navbar"> + +
{ onClose={() => setOpen(false)} open={open} key={placement} - width ={700} - style={{maxHeight:"40%"}} + width={720} + style={{ maxHeight: "40%" }} >
- - setOpen(false)}> + + setOpen(false)}> +
+
+ {noDataFound ? :"" }
- - -
); }; export default SearchWithDrawer; - diff --git a/src/Components/Home/BestSale.tsx b/src/Components/Home/BestSale.tsx index 9fab39d..d6e55e1 100644 --- a/src/Components/Home/BestSale.tsx +++ b/src/Components/Home/BestSale.tsx @@ -1,6 +1,7 @@ import { useNavigate } from "react-router-dom"; import { useTranslation } from "react-i18next"; import ProductSwiper from "./ProductSwiper"; +import { useGetBaseProduct } from "../../api/baseProduct"; const Products = () => { const {t} = useTranslation(); @@ -9,6 +10,10 @@ const Products = () => { const handelSeeAll = () => { navigate(`/categories?type=best_sale`); }; + + const { data,isLoading } = useGetBaseProduct({ + mostOrderd: "asc", + }) return (
@@ -16,7 +21,7 @@ const Products = () => {
{t("View all")}
- +
); diff --git a/src/Components/Home/BoseHeadphones.tsx b/src/Components/Home/BoseHeadphones.tsx index 98d2cea..56e7337 100644 --- a/src/Components/Home/BoseHeadphones.tsx +++ b/src/Components/Home/BoseHeadphones.tsx @@ -1,4 +1,3 @@ -import React from "react"; import { useTranslation } from "react-i18next"; import { RiArrowRightUpFill } from "react-icons/ri"; import { Link } from "react-router-dom"; diff --git a/src/Components/Home/ProductCard.tsx b/src/Components/Home/ProductCard.tsx index 40978e1..b3aba0e 100644 --- a/src/Components/Home/ProductCard.tsx +++ b/src/Components/Home/ProductCard.tsx @@ -17,10 +17,8 @@ const ProductCard = ({ item }: { item: Product }) => { const [t] = useTranslation(); const navigate = useNavigate(); const { isAuthenticated } = useAuthState(); - // console.log(item); const handel_click = (id: number) => { - console.log(id); navigate(`/product/${id}`); }; @@ -40,10 +38,10 @@ const ProductCard = ({ item }: { item: Product }) => { const queryClient = useQueryClient(); const handelChangeFavorite = (item: Product) => { - if (!isAuthenticated) { - toast.error("sorry you need to be authenticated"); - return; - } + // if (!isAuthenticated) { + // toast.error("sorry you need to be authenticated"); + // return; + // } if (item?.favorite) { @@ -55,6 +53,8 @@ const ProductCard = ({ item }: { item: Product }) => { id: item?.id, }); } + queryClient.invalidateQueries('mainProduct'); + }; useEffect(() => { @@ -71,11 +71,11 @@ const ProductCard = ({ item }: { item: Product }) => { }, [Delete]); const handelAddToCart = (item: Product) => { - if (!isAuthenticated) { + // if (!isAuthenticated) { - toast.error("sorry you need to be authenticated"); - return; - } + // toast.error("sorry you need to be authenticated"); + // return; + // } setCart(item); diff --git a/src/Components/Home/ProductSwiper.tsx b/src/Components/Home/ProductSwiper.tsx index 67d800c..5e78386 100644 --- a/src/Components/Home/ProductSwiper.tsx +++ b/src/Components/Home/ProductSwiper.tsx @@ -1,26 +1,21 @@ -import React, { useRef, useState } from 'react'; +import { useRef, useState } from 'react'; import { Swiper, SwiperSlide } from 'swiper/react'; import 'swiper/css'; import 'swiper/css/free-mode'; import 'swiper/css/pagination'; import ProductCard from './ProductCard'; import { Product } from '../../types/item'; -import { useGetBaseProduct } from '../../api/baseProduct'; import { A11y, Autoplay, Navigation, Pagination, Scrollbar } from 'swiper/modules'; import { Spin } from 'antd'; -const ProductSwiper = () => { +const ProductSwiper = ({data,isLoading}:any) => { const language = localStorage.getItem('language') ; - console.log(language); const [swiperDirection, setSwiperDirection] = useState(language === "ar" ? "rtl" : "ltr"); const swiperRef = useRef(null); - const { data, isLoading } = useGetBaseProduct({ - mostOrderd: "asc", - }); const BaseProducts = (data?.products as Product[]) || ([] as []); return ( @@ -31,7 +26,7 @@ const ProductSwiper = () => { spaceBetween={50} breakpoints={{ 0: { slidesPerView: 1 }, - 400: { slidesPerView: 2 }, + 400: { slidesPerView: 1 }, 600: { slidesPerView: 2 }, 900: { slidesPerView: 4 }, 1200: { slidesPerView: 4 }, diff --git a/src/Components/Home/Products.tsx b/src/Components/Home/Products.tsx index 55fd389..c383618 100644 --- a/src/Components/Home/Products.tsx +++ b/src/Components/Home/Products.tsx @@ -1,6 +1,7 @@ import { useNavigate } from "react-router-dom"; import { useTranslation } from "react-i18next"; import ProductSwiper from "./ProductSwiper"; +import { useGetBaseProduct } from "../../api/baseProduct"; const Products = () => { const {t} = useTranslation(); @@ -10,6 +11,11 @@ const Products = () => { navigate(`/categories?type=new_product`); }; + const { data,isLoading } = useGetBaseProduct({ + lastProducts:"asc" + }); + + return (
@@ -17,7 +23,7 @@ const Products = () => {
{t("View all")}
- +
); diff --git a/src/Components/Products/ProductAdditionalInfo.tsx b/src/Components/Products/ProductAdditionalInfo.tsx new file mode 100644 index 0000000..4d38ecc --- /dev/null +++ b/src/Components/Products/ProductAdditionalInfo.tsx @@ -0,0 +1,27 @@ +import { useTranslation } from 'react-i18next'; +import { languageObject } from '../../utils/languageObject'; + +const ProductAdditionalInfo = (data:any) => { + + const ProductAdditionalInfo = data?.data; + const { t } = useTranslation(); + const infoEntries = ProductAdditionalInfo?.info ? Object.entries(ProductAdditionalInfo.info) : []; + + return ( +
+

{t("Additional Info")}

+ {infoEntries.length > 0 ? ( + infoEntries.map(([key, value]: [any, any]) => ( + +
{languageObject(key)}
+
{languageObject(value)}
+
+ )) + ) : ( +

{t("Product info is empty")}

+ )} +
+ ); +}; + +export default ProductAdditionalInfo; diff --git a/src/Components/Products/ProductDescription.tsx b/src/Components/Products/ProductDescription.tsx new file mode 100644 index 0000000..2c7f383 --- /dev/null +++ b/src/Components/Products/ProductDescription.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import { useTranslation } from 'react-i18next' + +const ProductDescription = ({data}:any) => { + const {t} = useTranslation(); + return ( +
+

{t("Description")}

+

{data?.description}

+
+ ) +} + +export default ProductDescription \ No newline at end of file diff --git a/src/Components/Products/ProductInfo.tsx b/src/Components/Products/ProductInfo.tsx new file mode 100644 index 0000000..597ee36 --- /dev/null +++ b/src/Components/Products/ProductInfo.tsx @@ -0,0 +1,31 @@ +import React from 'react' +import { useTranslation } from 'react-i18next' +import { languageObject } from '../../utils/languageObject'; + +const ProductInfo = (data:any) => { + + const productInfo = data?.data + const {t} = useTranslation(); + + return ( +
+

{t("Info")}

+
+ +
{t("name")}
{languageObject(productInfo?.name)}
+
+ +
{t("Category")}
{languageObject(productInfo?.category?.name)}
+
+ +
{t("Price")}
{productInfo?.price}
+
+ +
{t("Description")}
{languageObject(productInfo?.description)}
+
+
+
+ ) +} + +export default ProductInfo \ No newline at end of file diff --git a/src/Components/Products/ProductsTabs.tsx b/src/Components/Products/ProductsTabs.tsx new file mode 100644 index 0000000..43a34bf --- /dev/null +++ b/src/Components/Products/ProductsTabs.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { Tabs } from 'antd'; +import type { TabsProps } from 'antd'; +import { useTranslation } from 'react-i18next'; +import ProductDescription from './ProductDescription'; +import ProductInfo from './ProductInfo'; +import ProductAdditionalInfo from './ProductAdditionalInfo'; + +const ProductTabs = ({data}:any) => { + + const {t} = useTranslation(); + + const items: TabsProps['items'] = [ + { + key: '1', + label: t('product_info'), + children: , + }, + { + key: '2', + label: t('description'), + children: , + }, + { + key: '3', + label: t('additional information'), + children: , + }, + ]; + + return ( + + ) +} + +export default ProductTabs \ No newline at end of file diff --git a/src/Components/Setting/Tabs/ContactTab.tsx b/src/Components/Setting/Tabs/ContactTab.tsx index abf2201..925c5f0 100644 --- a/src/Components/Setting/Tabs/ContactTab.tsx +++ b/src/Components/Setting/Tabs/ContactTab.tsx @@ -13,20 +13,20 @@ const ContactTab = ({className=""}: {className?: string }) => { const { t } = useTranslation(); const {mutate,isSuccess,isLoading} = useAddSupportMessage() - const SoicalInfo: { icon: any; text: string }[] = [ - { - icon: , - text: "info@yourdomain.com", - }, - { - icon: , - text: "+1 (378) 400-1234", - }, - { - icon: , - text: "www.yourdomain.com", - }, - ]; + const SoicalInfo: { icon: any; text: string }[] = [ + { + icon: , + text: "info@yourdomain.com", + }, + { + icon: , + text: "+1 (378) 400-1234", + }, + { + icon: , + text: "www.yourdomain.com", + }, + ]; const SoicalIcons: { icon: any; }[] = [ { diff --git a/src/Components/Utils/Search/Empty.tsx b/src/Components/Utils/Search/Empty.tsx new file mode 100644 index 0000000..93956d2 --- /dev/null +++ b/src/Components/Utils/Search/Empty.tsx @@ -0,0 +1,17 @@ +import React from 'react' +import { useTranslation } from 'react-i18next' + +const Empty = () => { + const [t] = useTranslation() + return ( +
+ +

{t("There are no suitable products")}

+

+ {t("Please try using other keywords to find the product name")} +

+
+ ) +} + +export default Empty \ No newline at end of file diff --git a/src/Components/Utils/Search/SearchButton.tsx b/src/Components/Utils/Search/SearchButton.tsx index 16c2ae9..8c8f348 100644 --- a/src/Components/Utils/Search/SearchButton.tsx +++ b/src/Components/Utils/Search/SearchButton.tsx @@ -1,53 +1,70 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect, useCallback } from 'react'; import { Select, Spin } from 'antd'; import { useNavigate, useSearchParams } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { LuSearch } from 'react-icons/lu'; import { useGetBaseProduct } from '../../../api/baseProduct'; import { Product } from '../../../types/item'; +import _ from 'lodash'; -const SearchButton: React.FC = () => { +interface SearchButtonProps { + setOpen: (open: boolean) => void; + setNoDataFound: (noData: boolean) => void; +} + +const SearchButton: React.FC = ({ setOpen, setNoDataFound }) => { const navigate = useNavigate(); const { t } = useTranslation(); const [searchParams] = useSearchParams(); const [query, setQuery] = useState(searchParams.get('search')); - + const { data, isLoading } = useGetBaseProduct({ - name: query, + search: query, }); + const BaseProducts = (data?.products as Product[]) || []; + + useEffect(() => { + setNoDataFound(!isLoading && BaseProducts.length < 1); + }, [isLoading, BaseProducts, setNoDataFound]); const options = BaseProducts.map((product: any) => ({ value: product.base_product_id, - label: product?.name as string, // Ensuring the label is a string + label: product?.name as string, })); + + const debouncedSearchChange = useCallback( + _.debounce((value: string) => { + setQuery(value); + navigate(`${window.location.pathname}?search=${value}`, { + replace: true, + }); + }, 500), // Adjust the debounce delay (in milliseconds) as needed + [] + ); - const handleSearchChange = (value: string) => { - setQuery(value); - navigate(`${window.location.pathname}?search=${value}`, { - replace: true, - }); + const handleSearchChange = (value: string) => { + debouncedSearchChange(value); }; const handleSelectChange = (value: number) => { const selectedProduct = BaseProducts.find(product => product.base_product_id === value); if (selectedProduct) { + setOpen(false); navigate(`/product/${selectedProduct.base_product_id}`); } }; const filterOption = (input: string, option?: { label: string }) => { if (!option) return false; - const filteredData = option?.label.toLowerCase().includes(input.toLowerCase()); - - return filteredData; + return option?.label.toLowerCase().includes(input.toLowerCase()); }; return (