Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
innovatixhub authored Nov 26, 2024
1 parent f7fd3ea commit 3144067
Show file tree
Hide file tree
Showing 7 changed files with 351 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { NavLink } from "react-router-dom";
import SvgIcon from "../../MiniComponents/SvgIcon";
import s from "./IconWithCountAndLabel.module.scss";

const IconWithCountAndLabel = ({
props: { iconName, visibility, routePath, countLength, title, text },
}) => {
const count = countLength > 99 ? "99+" : countLength;

return (
visibility && (
<NavLink to={routePath} aria-label={title}>
<div className={s.wrapper}>
<SvgIcon name={iconName} />
{countLength > 0 && <span className={s.count}>{count}</span>}
</div>

<span className={s.text}>{text}</span>
</NavLink>
)
);
};
export default IconWithCountAndLabel;
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
.wrapper {
width: inherit;
height: inherit;
}

.link svg {
width: inherit;
height: inherit;
fill: var(--black);
transition: fill .2s;
}

.count {
display: inline-block;
position: absolute;
left: 0;
top: -1px;
background-color: var(--dark-tomato);
color: #fff;
border-radius: 50%;
font-size: .6rem;
width: 28px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
user-select: none;
z-index: 2;
transform: scale(.6);
}

.text {
padding-inline-start: 16px;
}

.text::selection {
background-color: var(--white) !important;
}
22 changes: 22 additions & 0 deletions src/componants/shared/navtools/SearchInput/SearchInput.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { useTranslation } from "react-i18next";

const SearchInput = ({ searchRef }) => {
const { t } = useTranslation();

function handleSearchOnChange(e) {
const inputValue = e.target.value;
searchRef.current = inputValue?.trim()?.toLowerCase();
}

return (
<input
type="text"
id="search-input"
autoComplete="off"
placeholder={t("inputsPlaceholders.whatYouLookingFor")}
onChange={handleSearchOnChange}
aria-label="Search product field"
/>
);
};
export default SearchInput;
101 changes: 101 additions & 0 deletions src/componants/shared/navtools/SearchInput/SearchProductsInput.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { useEffect, useRef } from "react";
import { useTranslation } from "react-i18next";
import { useDispatch } from "react-redux";
import { useLocation, useNavigate, useSearchParams } from "react-router-dom";
import { productsData } from "src/Data/productsData";
import { updateLoadingState } from "src/Features/loadingSlice";
import { updateProductsState } from "src/Features/productsSlice";
import { searchByObjectKey } from "src/Functions/helper";
import SvgIcon from "../../MiniComponents/SvgIcon";
import SearchInput from "./SearchInput";
import s from "./SearchProductsInput.module.scss";

const SearchProductsInput = () => {
const { t } = useTranslation();
const dispatch = useDispatch();
const navigateTo = useNavigate();
const searchRef = useRef("");
const location = useLocation();
const pathName = location.pathname;
const [searchParams, setSearchParams] = useSearchParams();

function handleSearchProducts(e) {
setSearchParams({ query: searchRef.current });
e.preventDefault();

const isEmptyQuery = searchRef.current?.trim()?.length === 0;
if (isEmptyQuery) return;

updateSearchProducts();
}

function updateSearchProducts() {
dispatch(updateLoadingState({ key: "loadingSearchProducts", value: true }));

const queryValue = searchRef.current || searchParams.get("query");
const isEmptyQuery = queryValue?.trim()?.length === 0;

if (isEmptyQuery) {
dispatch(updateProductsState({ key: "searchProducts", value: [] }));
return;
}

const productsFound = getProducts(queryValue);

dispatch(
updateProductsState({ key: "searchProducts", value: productsFound })
);
navigateTo("/search?query=" + queryValue);
}

useEffect(() => {
const isSearchPage = pathName === "/search";
if (isSearchPage) updateSearchProducts();

return () => {
dispatch(
updateLoadingState({ key: "loadingSearchProducts", value: true })
);
};
}, []);

return (
<form
className={s.searchContainer}
onSubmit={handleSearchProducts}
onClick={focusInput}
role="search"
>
<SearchInput searchRef={searchRef} />

<button type="submit" aria-label={t("tooltips.searchButton")}>
<SvgIcon name="search" />
</button>
</form>
);
};

export default SearchProductsInput;

function focusInput(e) {
const searchInput = e.currentTarget.querySelector("#search-input");
searchInput.focus();
}

function getProducts(query) {
let productsFound = searchByObjectKey({
data: productsData,
key: "shortName",
query,
});

if (productsFound.length === 0) {
productsFound = searchByObjectKey({
data: productsData,
key: "category",
query,
});
}

return productsFound;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
@import "src/Styles/mixins";

.searchContainer {
background-color: var(--secondary-white);
display: flex;
justify-content: center;
align-items: center;
width: 250px;
padding: 10px 12px 10px 20px;
border-radius: 4px;
margin-right: 24px;
user-select: none;
cursor: pointer;
position: relative;
outline: solid 1px var(--black);
border: 6px solid var(--secondary-white);
transition: border-color .1s, outline-color .1s, background-color .1s .05s;

&:hover {
outline-color: #ff7b00;
}

&:has(:focus) {
outline-color: #ff7b00;
background-color: rgba(255, 166, 0, .08);
}
}

.searchContainer>input {
all: unset;
font-size: .75rem;
font-weight: 400;
line-height: 18px;
width: 100%;
}

.searchContainer>button {
all: unset;
position: relative;
}

.searchContainer>button::before {
content: '';
position: absolute;
left: 2.3px;
top: 2.7px;
width: 10px;
height: 10px;
border-radius: 50%;
}

.searchContainer>button>svg {
width: 18px;
height: 18px;
transition: fill .1s;
fill: #757575;
}

.searchContainer:has(:focus)>button>svg {
fill: var(--black);
}

.searchContainer>button:active svg {
fill: var(--black);
}

.searchContainer>button:active::before {
background-color: var(--white);
}

.searchContainer>button:focus svg {
fill: var(--black)
}

// Arabic styles
[lang=ar] .searchContainer {
padding: 10px 12px;
direction: rtl;
}

@include medium {
[lang=ar] .searchContainer {
padding: 6px 12px 6px 18px;
width: 190px;
}
}

// Hungarian styles
@include medium {
[lang=hu] .searchContainer {
padding: 6px 12px 6px 18px;
width: 220px;
}
}
35 changes: 35 additions & 0 deletions src/componants/shared/navtools/UserMenuIcon/UserMenuIcon.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { useTranslation } from "react-i18next";
import useToggle from "src/Hooks/Helper/useToggle";
import SvgIcon from "../../MiniComponents/SvgIcon";
import ToolTip from "../../MiniComponents/ToolTip";
import UserMenu from "../../UserMenu/UserMenu";
import s from "./UserMenuIcon.module.scss";

const UserMenuIcon = ({ visibility }) => {
const { t } = useTranslation();
const [isMenuUserActive, toggleMenuUserActive] = useToggle(false);
const activeClass = isMenuUserActive ? s.active : "";

function openMenu() {
toggleMenuUserActive(true);
}

if (!visibility) return null;

return (
<div
className={`${s.userContainer} ${activeClass}`}
onClick={toggleMenuUserActive}
onFocus={openMenu}
aria-label={t("navTools.userMenu")}
aria-haspopup="true"
>
<SvgIcon name="user" />
<ToolTip bottom="26px" left="50%" content={t("navTools.userMenu")} />

<UserMenu isActive={isMenuUserActive} toggler={toggleMenuUserActive} />
</div>
);
};

export default UserMenuIcon;
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
.userContainer {
-webkit-tap-highlight-color: transparent;
position: relative;
padding: 6px;
cursor: pointer;
outline: dashed 0 var(--regular-light-gray);
outline-offset: 0;

&:focus-visible {
transition: opacity .3s, var(--outline-transition);
outline: 2px dashed var(--very-dark-gray);
outline-offset: 3px;
color: var(--very-dark-gray);
}

&.active {
background-color: var(--dark-tomato);
fill: var(--white);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
}

.userContainer>svg {
width: 20px;
height: 20px;
transition: fill .2s;
}

.userContainer:not(.active):hover>svg {
fill: #6f6f6f;
}

.userContainer.active>svg {
scale: .7;
}

0 comments on commit 3144067

Please sign in to comment.