Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Выделить из Header отдельную feature - SearchProduct #175

Merged
merged 4 commits into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 0 additions & 57 deletions src/components/SearchItem/search-item.module.scss

This file was deleted.

4 changes: 2 additions & 2 deletions src/components/header/header.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useMemo } from 'react'
import classNames from 'classnames'
import Logo from '../logo/Logo'
import Search from '../search/search'
import ArrowIcon from '@/assets/icons/arrow.svg'
import LightningIcon from '@/assets/images/header/lightning.svg'
import ContextMenuElement from '../ContextMenuElement/ContextMenuElement'
Expand All @@ -15,6 +14,7 @@ import { CatalogLinksId } from '@/shared/config/catalogLinks/catalogLinks'
import Link from '@/shared/ui/Link/Link'
import IconCategories from '@/assets/icons/IconCategories.svg'
import styles from './header.module.scss'
import SearchProduct from '@/features/SearchProduct'

function Header() {
const aboutUsNode = useMemo(
Expand Down Expand Up @@ -152,7 +152,7 @@ function Header() {

<div className={styles['header__row-two']}>
<Logo width="138px" height="46px" />
<Search />
<SearchProduct />
<HeaderAccount {...headerAccountData} />
</div>

Expand Down
55 changes: 0 additions & 55 deletions src/components/search/search.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@use '../../shared/styles/utils/variables' as var;
@use '@/shared/styles/utils/variables' as var;

.link {
padding: 20px 30px;
Expand All @@ -17,23 +17,6 @@
flex: 0 0 auto;
}

.number {
margin: 0;
font-size: 14px;
line-height: 12px;
font-weight: 400;
color: var.$body-color-light-grey;
}

.price {
display: flex;
align-items: center;
font-size: 16px;
font-weight: 400;
margin: 0;
color: var.$body-color;
}

.wrapper {
display: flex;
flex-direction: column;
Expand All @@ -48,12 +31,29 @@
margin: 0 0 5px;
}

.number {
margin: 0;
font-size: 14px;
line-height: 12px;
font-weight: 400;
color: var.$body-color-light-grey;
}

.price-wrapper {
display: flex;
flex: 0 0 auto;
column-gap: 20px;
}

.price {
display: flex;
align-items: center;
font-size: 16px;
font-weight: 400;
margin: 0;
color: var.$body-color;
}

.image-link {
visibility: visible;
}
22 changes: 22 additions & 0 deletions src/entities/SearchItem/SearchItem.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Meta, Story } from '@storybook/react'
import { searchResponseData } from '@/mockData/searchData'
import SearchItem from './SearchItem'
import { TProduct } from '@/shared/model/types/common'
import { TLinkProps } from '@/shared/ui/Link/Link'

export default {
title: 'Entities/SearchItem',
component: SearchItem,
parameters: {
layout: 'centered'
}
} as Meta

type StoryProps = TProduct & TLinkProps

const Template: Story<StoryProps> = args => <SearchItem {...args} />

export const Default: Story<StoryProps> = Template.bind({})
Default.args = {
...(searchResponseData.data[2] as StoryProps)
}
Original file line number Diff line number Diff line change
@@ -1,32 +1,33 @@
import { FC, useMemo, useState } from 'react'
import { type FC, useMemo, useState } from 'react'
import ArrowRightIcon from '@/assets/images/searchItem/arrow-right.svg'
import { TProduct } from '@/shared/model/types/common'
import Link, { TLinkProps } from '@/shared/ui/Link/Link'
import styles from './searchItem.module.scss'
import styles from './SearchItem.module.scss'

/**
* @param {string} image - фото товара
* @param {string} name - название товара
* @param {number} number - артикул товара
* @param {string} price - цена товара с валютой
* Компонент элемента из поисковой выдачи для тултипа-подсказки
*/
const SearchItem: FC<TProduct & TLinkProps> = props => {
const { image, name, number, price, ...otherProps } = props
const [isVisible, setVisability] = useState(false)
const [isVisible, setVisibility] = useState(false)

const handleMouseEnter = () => {
setVisability(true)
setVisibility(true)
}

const handleMouseLeave = () => {
setVisability(false)
setVisibility(false)
}

const arrowNode = useMemo(() => <ArrowRightIcon className={styles['image-link']} />, [])

return (
<Link className={styles.link} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} {...otherProps}>
<img src={image} alt="product" className={styles.image}></img>
<Link
className={styles.link}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
{...otherProps}>
<img src={image} alt="product" className={styles.image} />
<div className={styles.wrapper}>
<p className={styles.paragraph}>{name}</p>
<span className={styles.number}>{number}</span>
Expand Down
2 changes: 2 additions & 0 deletions src/features/SearchProduct/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import SearchProduct from './ui/SearchProduct'
export default SearchProduct
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@use '../../shared/styles/utils/variables' as var;
@use '@/shared/styles/utils/variables' as var;

.form {
width: 100%;
Expand All @@ -14,14 +14,6 @@
.button {
width: 90px;
height: 38px;
display: flex;
align-items: center;
justify-content: center;
background-color: var.$theme-primary-color;
border: none;
box-sizing: border-box;
color: var.$white;
border-radius: 5px;
margin-right: 5px;
}

Expand Down
12 changes: 12 additions & 0 deletions src/features/SearchProduct/ui/SearchProduct.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Meta, Story } from '@storybook/react'
import SearchProduct from './SearchProduct'

export default {
title: 'Features/SearchProduct',
component: SearchProduct
} as Meta

const Template: Story = () => <SearchProduct />

export const Default = Template.bind({})
Default.args = {}
79 changes: 79 additions & 0 deletions src/features/SearchProduct/ui/SearchProduct.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { useRef, useEffect, useState } from 'react'
import { searchResponseData } from '@/mockData/searchData'
import { TResultData } from '@/shared/model/types/common'
import SearchResult from '@/widgets/SearchResult/SearchResult'
import { Input, InputSize, InputTheme } from '@/shared/ui/Input/Input'
import { Button, ButtonDesign, ButtonSize, ButtonTheme } from '@/shared/ui/Button/Button'
import styles from './SearchProduct.module.scss'

// @TODO: Перевести форму на Formik + Yup
// https://github.com/Studio-Yandex-Practicum/maxboom_frontend/issues/92

/**
* Компонент формы для поиска катгорий/товаров по базе данных магазина
*/
const SearchProduct = () => {
const [visible, setVisibility] = useState(false)
const [resultData, setResultData] = useState<TResultData>({ data: [], success: false })
const [query, setQuery] = useState('')
const searchResultRef = useRef(null)

// @TODO: Добавить интеграцию с бэком - подсказки в поиске при вводе текста
// https://github.com/Studio-Yandex-Practicum/maxboom_frontend/issues/172
const inputEventHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
const { value } = event.target
setResultData(searchResponseData)
setQuery(value)
}

const closeContextMenuHandler = (e: Event) => {
const searchResultNode = searchResultRef.current

if (searchResultNode) {
const withinBoundaries = e.composedPath().includes(searchResultNode)

if (!withinBoundaries && visible) {
setVisibility(false)
}
}
}

useEffect(() => {
if (resultData.success && query.length > 0) {
setVisibility(true)
} else {
setVisibility(false)
}
}, [resultData, query])

useEffect(() => {
document.addEventListener('click', closeContextMenuHandler)
return () => {
document.removeEventListener('click', closeContextMenuHandler)
}
}, [])

return (
<form className={styles.form}>
<Input
name="search"
placeholder="Поиск по товарам и категориям"
customSize={InputSize.M}
theme={InputTheme.ACCENT}
onChange={inputEventHandler}
/>
{/* @TODO: Добавить onClick-интеграцию с бэком для отправки поискового запроса
https://github.com/Studio-Yandex-Practicum/maxboom_frontend/issues/173 */}
<Button
theme={ButtonTheme.PRIMARY}
design={ButtonDesign.SQUARE}
size={ButtonSize.XS}
className={styles.button}>
Найти
</Button>
{visible && <SearchResult results={resultData.data} ref={searchResultRef} />}
</form>
)
}

export default SearchProduct
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
@use '@/shared/styles/utils/variables' as var;

.result {
// @TODO: Определить ширину в соответствии с шириной формы поиска
// https://github.com/Studio-Yandex-Practicum/maxboom_frontend/issues/174
width: 800px;
background-color: var.$white;
position: absolute;
Expand Down
Loading
Loading