-
Notifications
You must be signed in to change notification settings - Fork 3
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
feat: 식품 필터 선택 후 선택한 필터 보여주는 기능 추가 #461
Changes from 9 commits
d22bd2f
78ef6de
d30e005
c365b50
b4695a9
7bc3ba5
62a3a8c
372ebc3
0047a05
09617b0
7ff4276
cf1f927
15d21c2
d31c5da
d1fe339
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { styled } from 'styled-components'; | ||
|
||
import { useFilterSelectionDisplay } from '@/hooks/food/useFilterSelectionDisplay'; | ||
import { KeywordEn } from '@/types/food/client'; | ||
|
||
const FilterSelectionDisplay = () => { | ||
const { filterListQueryString, removeFilter } = useFilterSelectionDisplay(); | ||
|
||
return ( | ||
<SelectedFilterList> | ||
{Object.entries(filterListQueryString).map(([category, values]) => | ||
values.split(',').map(value => ( | ||
<SelectedFilterItem key={value}> | ||
{value} | ||
<FilterToggleButton | ||
type="button" | ||
aria-label={`${value}필터 선택 해제`} | ||
onClick={() => removeFilter(category as KeywordEn, value)} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 현재 사용하고 오버로딩중인
Object.entries(invariantOf(filterListQueryString)).map(([category, values]) =>{
...
}) 타입 단언 없이 추론이 가능할 것 같아요! |
||
> | ||
x | ||
</FilterToggleButton> | ||
</SelectedFilterItem> | ||
)), | ||
)} | ||
</SelectedFilterList> | ||
); | ||
}; | ||
|
||
export default FilterSelectionDisplay; | ||
|
||
const SelectedFilterList = styled.ul` | ||
scrollbar-width: none; | ||
|
||
overflow-x: scroll; | ||
display: flex; | ||
gap: 0.4rem; | ||
align-items: center; | ||
|
||
width: calc(100% - 8.8rem - 1rem); | ||
margin-left: 1rem; | ||
|
||
&::-webkit-scrollbar { | ||
width: 0; | ||
height: 0; | ||
} | ||
`; | ||
|
||
const SelectedFilterItem = styled.li` | ||
overflow: hidden; | ||
flex-shrink: 0; | ||
|
||
height: 3.2rem; | ||
padding: 0.4rem; | ||
|
||
font-size: 1.2rem; | ||
font-weight: 500; | ||
line-height: 2.4rem; | ||
color: ${({ theme }) => theme.color.grey400}; | ||
text-align: center; | ||
text-overflow: ellipsis; | ||
white-space: nowrap; | ||
`; | ||
|
||
const FilterToggleButton = styled.button` | ||
cursor: pointer; | ||
|
||
display: inline-block; | ||
|
||
margin-left: 0.4rem; | ||
|
||
color: ${({ theme }) => theme.color.grey300}; | ||
|
||
background: none; | ||
border: none; | ||
`; |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,33 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { KEYWORD_EN } from '@/constants/food'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { useFoodFilterContext } from '@/context/food'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { generateQueryString } from '@/router/routes'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import { KeywordEn } from '@/types/food/client'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import useEasyNavigate from '../@common/useEasyNavigate'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
import useValidQueryString from '../common/useValidQueryString'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
export const useFilterSelectionDisplay = () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const { replaceQueryString } = useEasyNavigate(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const { toggleFilter } = useFoodFilterContext(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const filterListQueryString = useValidQueryString(KEYWORD_EN); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const removeFilter = (category: KeywordEn, value: string) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 타입명과 일치하도록 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
let newFilterString; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (filterListQueryString[category]?.includes(`,${value}`)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
newFilterString = filterListQueryString[category]?.replace(`,${value}`, ''); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} else if (filterListQueryString[category]?.includes(`${value},`)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
newFilterString = filterListQueryString[category]?.replace(`${value},`, ''); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} else newFilterString = filterListQueryString[category]?.replace(value, ''); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
const newQueryString = generateQueryString({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
...filterListQueryString, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
[category]: newFilterString, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
toggleFilter(category, value); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 현재 필터에서 선택된 상태와 url의 쿼리스트링이 일치하지 않는 현상이 발생하는데요! 쿼리스트링이 변경될 때 마다 그에 따라 필터 상태를 업데이트 하도록 변경하면 문제점도 해결되면서 28번 라인도 제거할 수 있을 것 같습니다! |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
replaceQueryString(newQueryString, { exclude: [] }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return { filterListQueryString, removeFilter }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { useState } from 'react'; | ||
|
||
import { initialSelectedFilterList } from '@/context/food'; | ||
import type { KeywordEn } from '@/types/food/client'; | ||
import { parseCheckList } from '@/utils/parseCheckList'; | ||
|
||
export const useFoodListFilter = () => { | ||
const [selectedFilterList, setSelectedFilterList] = useState(initialSelectedFilterList); | ||
|
||
const parsedSelectedFilterList = parseCheckList(selectedFilterList); | ||
|
||
const toggleFilter = (keyword: KeywordEn, filter: string) => { | ||
const targetFilterList = structuredClone(selectedFilterList)[keyword]; | ||
const selected = targetFilterList.has(filter); | ||
|
||
selected ? targetFilterList.delete(filter) : targetFilterList.add(filter); | ||
|
||
setSelectedFilterList(prev => ({ ...prev, [keyword]: new Set(targetFilterList) })); | ||
}; | ||
|
||
const resetSelectedFilterList = () => { | ||
setSelectedFilterList(initialSelectedFilterList); | ||
}; | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. useEffect(() => {
const newFilterList = Object.entries(invariantOf(filterListQueryString)).reduce(
(newFilterList, [category, queryString]) => ({
...newFilterList,
[category]: new Set(queryString?.split(',')),
}),
initialSelectedFilterList,
);
setSelectedFilterList(newFilterList);
}, [Object.values(filterListQueryString).join()]); 이렇게 쿼리스트링이 변경될 때 필터 상태도 동기화하면 어떨까요? |
||
return { selectedFilterList, parsedSelectedFilterList, toggleFilter, resetSelectedFilterList }; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
x 버튼이 너무 작아서 누르기 불편해요 😭
SelectedFilterItem
에 등록하는건 어떨까요!?