initial commit
This commit is contained in:
258
src/components/Navbar/Navbar.module.scss
Normal file
258
src/components/Navbar/Navbar.module.scss
Normal file
@@ -0,0 +1,258 @@
|
||||
.navbar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
background-color: #fff;
|
||||
justify-content: center;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 99;
|
||||
|
||||
.navbarUp {
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
margin-bottom: 1px;
|
||||
border-bottom: 3px solid #f3f4f6;
|
||||
}
|
||||
|
||||
.btn{
|
||||
display: flex;
|
||||
width: max-content;
|
||||
font-size: 14px;
|
||||
border-radius: 4px;
|
||||
border: #000000;
|
||||
background-color: #000000;
|
||||
padding: 6px 10px;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.navbarDown {
|
||||
width: 100%;
|
||||
background-color: #ffffff;
|
||||
max-width: 1366px;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
padding-left: 1.375rem;
|
||||
padding-right: 1.375rem;
|
||||
box-sizing: border-box;
|
||||
display: none;
|
||||
@media screen and (min-width: 1024px) {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.logo {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding: 10px 22px 0px;
|
||||
height: 60px;
|
||||
gap: 10px;
|
||||
margin: 0 auto;
|
||||
cursor: pointer;
|
||||
@media screen and (max-width: 426px) {
|
||||
height: 40px;
|
||||
justify-content: flex-start;
|
||||
padding: 10px 15px 6px;
|
||||
}
|
||||
}
|
||||
.logoContainer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
border-radius: 10px;
|
||||
padding: 8px 14px 6px;
|
||||
box-sizing: border-box;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
@media screen and (max-width: 426px) {
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
svg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
}
|
||||
}
|
||||
.stick {
|
||||
width: 0.5px !important;
|
||||
background-color: #4b5563;
|
||||
height: auto;
|
||||
@media screen and (max-width: 1023px) {
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.navLinks ul {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 0 auto 0 auto;
|
||||
box-sizing: border-box;
|
||||
gap: 5px;
|
||||
|
||||
li,
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #4b5563;
|
||||
font-size: 14px;
|
||||
}
|
||||
li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
margin: 0;
|
||||
svg {
|
||||
fill: #4b5563;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
.searchWrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 1;
|
||||
flex-direction: row-reverse;
|
||||
|
||||
|
||||
svg {
|
||||
position: absolute;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
transform: translateX(-35%);
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
border-radius: 8px;
|
||||
font-size: 0.75rem;
|
||||
padding: 4px 16px;
|
||||
background-color: #e5e7eb;
|
||||
box-sizing: border-box;
|
||||
border: none;
|
||||
outline: none;
|
||||
&::placeholder {
|
||||
color: #9ca3af;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.navButton {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
border: none;
|
||||
padding-top: 0.25rem;
|
||||
padding-bottom: 0.25rem;
|
||||
padding-left: 0.875rem;
|
||||
padding-right: 0.875rem;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 0.5rem;
|
||||
height: 2.5rem;
|
||||
font-size: 0.875rem;
|
||||
color: #4b5563;
|
||||
font-weight: 600;
|
||||
background-color: transparent;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background-color: #f3f4f6;
|
||||
}
|
||||
}
|
||||
|
||||
.cartSection {
|
||||
.cartLink {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
|
||||
.cartIcon {
|
||||
margin-right: 5px;
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mobile
|
||||
.navbarContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 11px 0;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
position: sticky;
|
||||
@media screen and (min-width: 1024px) {
|
||||
display: none;
|
||||
}
|
||||
@media screen and (max-width: 426px) {
|
||||
padding: 9px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.navbarContent {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
max-width: 1024px;
|
||||
color: #4b5563;
|
||||
font-size: 14px;
|
||||
padding: 0 1.375rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.categories,
|
||||
.location {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
}
|
||||
.searchIcon {
|
||||
min-width: 60px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
svg {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
.searchInputWrapper {
|
||||
margin-top: 10px;
|
||||
width: 100%;
|
||||
max-width: 1024px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 0 1.375rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.searchInput {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
border-radius: 8px;
|
||||
font-size: 0.75rem;
|
||||
padding: 4px 16px;
|
||||
background-color: #e5e7eb;
|
||||
box-sizing: border-box;
|
||||
border: none;
|
||||
outline: none;
|
||||
|
||||
|
||||
&::placeholder {
|
||||
color: #9ca3af;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
}
|
||||
307
src/components/Navbar/NavbarDown.jsx
Normal file
307
src/components/Navbar/NavbarDown.jsx
Normal file
@@ -0,0 +1,307 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { CartIcon, WishlistIcon, BrandIcon, OrderIcon } from "../Icons";
|
||||
import styles from "./Navbar.module.scss";
|
||||
import { UserOutlined, LogoutOutlined, HomeOutlined } from "@ant-design/icons";
|
||||
import { FaGlobe } from "react-icons/fa6";
|
||||
import { Input, Badge, Menu, Dropdown } from "antd";
|
||||
const { Search } = Input;
|
||||
import DropdownMenu from "../CategoryDropdown/index";
|
||||
import LoginModal from "../LogIn/index";
|
||||
import SignUpModal from "../SignUp/index";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { CiSearch } from "react-icons/ci";
|
||||
import tm from "../../assets/tm.png";
|
||||
import ru from "../../assets/ru.png";
|
||||
import en from "../../assets/en.png";
|
||||
import { CiLocationOn } from "react-icons/ci";
|
||||
import Sidebar from "../CategorySideBar";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useSearchProductQuery } from "../../app/api/searchApi";
|
||||
import { useGetCartQuery } from "../../app/api/cartApi";
|
||||
import { useGetOrdersQuery } from "../../app/api/orderApi";
|
||||
import { useGetFavoritesQuery } from "../../app/api/favoritesApi";
|
||||
import { useAuth } from "../../context/authContext";
|
||||
import ProfileModal from "../../components/MyProfileModal/index";
|
||||
const NavbarDown = () => {
|
||||
const [isSearchVisible, setSearchVisible] = useState(false);
|
||||
const { t, i18n } = useTranslation();
|
||||
const [searchQuery, setSearchQuery] = useState("");
|
||||
const navigate = useNavigate();
|
||||
const { data: searchData, refetch } = useSearchProductQuery(searchQuery, {
|
||||
skip: !searchQuery,
|
||||
});
|
||||
const { data: cartData } = useGetCartQuery(undefined, {
|
||||
refetchOnMountOrArgChange: false,
|
||||
});
|
||||
const { isAuthenticated, logout } = useAuth();
|
||||
const cartItemCount =
|
||||
cartData?.data?.reduce((total, item) => {
|
||||
return total + (parseInt(item.product_quantity, 10) || 0);
|
||||
}, 0) || 0;
|
||||
|
||||
const { data: ordersData } = useGetOrdersQuery();
|
||||
const ordersItemCount = ordersData?.length || 0;
|
||||
|
||||
const { data: favoritesData } = useGetFavoritesQuery();
|
||||
const favoritesItemCount = favoritesData?.length || 0;
|
||||
const [profileModalVisible, setProfileModalVisible] = useState(false);
|
||||
const handleSearch = () => {
|
||||
if (searchQuery.trim()) {
|
||||
refetch();
|
||||
navigate(`/search?keyword=${encodeURIComponent(searchQuery)}`, {
|
||||
state: {
|
||||
searchData,
|
||||
searchQuery,
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const toggleSearch = () => {
|
||||
setSearchVisible(!isSearchVisible);
|
||||
};
|
||||
|
||||
const changeLanguage = (langCode) => {
|
||||
i18n.changeLanguage(langCode);
|
||||
localStorage.setItem("preferredLanguage", langCode);
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
const handleLogout = async () => {
|
||||
await logout();
|
||||
|
||||
};
|
||||
|
||||
useEffect(() => {}, [isAuthenticated]);
|
||||
|
||||
const items = [
|
||||
{
|
||||
key: "tk",
|
||||
label: (
|
||||
<div onClick={() => changeLanguage("tk")}>
|
||||
<img
|
||||
src={tm}
|
||||
alt={t("navbar.languages.tm")}
|
||||
style={{ width: "20px", marginRight: "10px" }}
|
||||
/>
|
||||
{t("navbar.languages.tm")}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "ru",
|
||||
label: (
|
||||
<div onClick={() => changeLanguage("ru")}>
|
||||
<img
|
||||
src={ru}
|
||||
alt={t("navbar.languages.ru")}
|
||||
style={{ width: "20px", marginRight: "10px" }}
|
||||
/>
|
||||
{t("navbar.languages.ru")}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "en",
|
||||
label: (
|
||||
<div onClick={() => changeLanguage("en")}>
|
||||
<img
|
||||
src={en}
|
||||
alt={t("navbar.languages.en")}
|
||||
style={{ width: "20px", marginRight: "10px" }}
|
||||
/>
|
||||
{t("navbar.languages.en")}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
const profileItems = [
|
||||
{
|
||||
key: "profile",
|
||||
label: (
|
||||
<div onClick={() => setProfileModalVisible(true)}>
|
||||
<UserOutlined style={{ marginRight: "10px" }} />
|
||||
{t("profile.my_profile")}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
// {
|
||||
// key: "address",
|
||||
// label: (
|
||||
// <Link to="/addresses">
|
||||
// <HomeOutlined style={{ marginRight: "10px" }} />
|
||||
// {t("profile.my_address")}
|
||||
// </Link>
|
||||
// ),
|
||||
// },
|
||||
{
|
||||
key: "logout",
|
||||
label: (
|
||||
<div onClick={handleLogout}>
|
||||
<LogoutOutlined style={{ marginRight: "10px" }} />
|
||||
{t("profile.logout")}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<header className={styles.navbar}>
|
||||
<div className={styles.navbarDown} style={{ position: "sticky" }}>
|
||||
<nav className={styles.navLinks}>
|
||||
<ul>
|
||||
<li>
|
||||
<DropdownMenu />
|
||||
</li>
|
||||
<div className={styles.stick}></div>
|
||||
<li>
|
||||
{" "}
|
||||
<Link to={"/brands"}>
|
||||
<button className={styles.navButton}>
|
||||
<BrandIcon />
|
||||
{t("navbar.brands")}
|
||||
</button>
|
||||
</Link>
|
||||
</li>
|
||||
<li className={styles.searchWrapper}>
|
||||
<CiSearch />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Haryt ady boyunca gozle..."
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
onKeyPress={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
handleSearch();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</li>
|
||||
<li>
|
||||
<Dropdown
|
||||
menu={{ items }}
|
||||
placement="bottomLeft"
|
||||
trigger={["click"]}
|
||||
>
|
||||
<span
|
||||
className={styles.navButton}
|
||||
style={{ cursor: "pointer" }}
|
||||
>
|
||||
<FaGlobe />
|
||||
</span>
|
||||
</Dropdown>
|
||||
</li>
|
||||
<div className={styles.stick}></div>
|
||||
|
||||
{!isAuthenticated ? (
|
||||
<>
|
||||
<li>
|
||||
<LoginModal />
|
||||
</li>
|
||||
<div className={styles.stick}></div>
|
||||
{/* <li>
|
||||
<SignUpModal />
|
||||
</li> */}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<li>
|
||||
<Dropdown
|
||||
menu={{ items: profileItems }}
|
||||
placement="bottomLeft"
|
||||
trigger={["click"]}
|
||||
>
|
||||
<span
|
||||
className={styles.navButton}
|
||||
style={{ cursor: "pointer" }}
|
||||
>
|
||||
<UserOutlined /> {t("profile.my_profile")}
|
||||
</span>
|
||||
</Dropdown>
|
||||
</li>
|
||||
<div className={styles.stick}></div>
|
||||
</>
|
||||
)}
|
||||
<li>
|
||||
<Link to={"/orders"}>
|
||||
<Badge
|
||||
style={{ marginRight: "4px" }}
|
||||
count={ordersItemCount}
|
||||
offset={[10, 0]}
|
||||
>
|
||||
<button className={styles.navButton}>
|
||||
<OrderIcon />
|
||||
</button>
|
||||
</Badge>
|
||||
</Link>
|
||||
</li>
|
||||
<div className={styles.stick}></div>
|
||||
<li>
|
||||
<Link to={"/wishlist"}>
|
||||
<Badge
|
||||
style={{ marginRight: "4px" }}
|
||||
count={favoritesItemCount}
|
||||
offset={[10, 0]}
|
||||
>
|
||||
<button className={styles.navButton}>
|
||||
<WishlistIcon />
|
||||
</button>
|
||||
</Badge>
|
||||
</Link>
|
||||
</li>
|
||||
<div className={styles.stick}></div>
|
||||
<li>
|
||||
<Link to={"/cart"}>
|
||||
<Badge count={cartItemCount} offset={[10, 0]}>
|
||||
<button className={styles.navButton}>
|
||||
<CartIcon />
|
||||
</button>
|
||||
</Badge>
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
{/* Mobile */}
|
||||
<div className={styles.navbarContainer}>
|
||||
<div className={styles.navbarContent}>
|
||||
<div className={styles.categories}>
|
||||
<Sidebar />
|
||||
</div>
|
||||
<div className={styles.stick}></div>
|
||||
<div className={styles.location}>
|
||||
<CiLocationOn /> Aşgabat
|
||||
</div>
|
||||
<div className={styles.stick}></div>
|
||||
<div className={styles.searchIcon} onClick={toggleSearch}>
|
||||
<CiSearch />
|
||||
</div>
|
||||
</div>
|
||||
{isSearchVisible && (
|
||||
<div className={styles.searchInputWrapper}>
|
||||
<input
|
||||
className={styles.searchInput}
|
||||
type="text"
|
||||
placeholder="Haryt ady boyunca gozle..."
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
onKeyPress={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
handleSearch();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{isAuthenticated && (
|
||||
<ProfileModal
|
||||
visible={profileModalVisible}
|
||||
onClose={() => setProfileModalVisible(false)}
|
||||
/>
|
||||
)}
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
||||
export default NavbarDown;
|
||||
54
src/components/Navbar/index.jsx
Normal file
54
src/components/Navbar/index.jsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import styles from "./Navbar.module.scss";
|
||||
import { Modal } from "antd";
|
||||
import SignupForm from "../BeSeller/index";
|
||||
import React, { useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { LogoWithText } from "../Icons";
|
||||
import Logo from "../../assets/logo2.png"
|
||||
const Navbar = () => {
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
const showModal = () => {
|
||||
setIsModalVisible(true);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
setIsModalVisible(false);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<header className={styles.navbar}>
|
||||
<div className={styles.navbarUp}>
|
||||
<div
|
||||
style={{ maxWidth: "1366px", display: "flex", margin: "0 auto", alignItems: "center"}}
|
||||
>
|
||||
<div className={styles.logo}>
|
||||
<div
|
||||
className={styles.logoContainer}
|
||||
onClick={() => navigate("/")}
|
||||
>
|
||||
{/* <LogoWithText /> */}
|
||||
<img style={{width: "200px"}} src={Logo} alt="" />
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ display: "flex", alignItems: "center", padding: "8px 14px 6px" }}>
|
||||
<button className={styles.btn} onClick={showModal}>
|
||||
Satyjy bol
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<Modal
|
||||
open={isModalVisible}
|
||||
onCancel={handleCancel}
|
||||
footer={null}
|
||||
width={900}
|
||||
>
|
||||
<SignupForm />
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Navbar;
|
||||
Reference in New Issue
Block a user