Skip to content

Commit

Permalink
Merge pull request #114 from nori-dongsan/view_product/#80
Browse files Browse the repository at this point in the history
[ ViewProduct ] 필터 태그 구현
  • Loading branch information
say-young516 authored Jul 20, 2022
2 parents 2f95c51 + a1a1178 commit 7031def
Show file tree
Hide file tree
Showing 13 changed files with 335 additions and 91 deletions.
66 changes: 52 additions & 14 deletions components/viewProduct/FilterDropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import styled from '@emotion/styled';
import { FilterDropdownProps } from '../../types/viewProduct';
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
import { checkedItemsState, filterTagState } from '../../core/atom';
import { FilterDropdownProps, FilterTagProps } from '../../types/viewProduct';

export default function FilterDropdown(props: FilterDropdownProps) {
const {
Expand All @@ -8,31 +10,67 @@ export default function FilterDropdown(props: FilterDropdownProps) {
isExcept,
categoryIdx,
checkedItem,
handleCheckedItems,
categoryKey,
} = props;
const [checkedItems, setCheckedItems] = useRecoilState(checkedItemsState);
const [filterTagList, setFilterTagList] =
useRecoilState<FilterTagProps[]>(filterTagState);
const filterTagKeys = Object.keys(filterTagList);
const filterTagValues = Object.values(filterTagList);
const handleCheckedItems = (
categoryIdx: number,
elementIdx: number,
tagText: string,
) => {
const tag: FilterTagProps = {
categoryIdx: categoryIdx,
elementIdx: elementIdx,
categoryKey: categoryKey,
tagText: tagText,
};
if (checkedItems[categoryIdx].has(elementIdx)) {
checkedItems[categoryIdx].delete(elementIdx);
const deleteidx = filterTagList.findIndex((item) => {
return (
item.categoryIdx === categoryIdx && item.elementIdx === elementIdx
);
});

const handleCheckedItem = (elementIdx: number) => {
if (checkedItem.has(elementIdx)) {
checkedItem.delete(elementIdx);
let copyFilterTagList = [...filterTagList];
copyFilterTagList.splice(deleteidx, 1);
setFilterTagList(copyFilterTagList);
console.log(filterTagList);
} else {
checkedItem.add(elementIdx);
checkedItems[categoryIdx].add(elementIdx);
setFilterTagList([...filterTagList, tag]);
console.log(filterTagList);
}

handleCheckedItems(checkedItem, categoryIdx);
setCheckedItems({
...checkedItems,
[categoryIdx]: checkedItems[categoryIdx],
});
};

return (
<StDropdownWrapper isDrop={isDrop} isExcept={isExcept}>
{categoryInfo.map((sort: string, elementIdx: number) => {
{categoryInfo.map((tagText: string, elementIdx: number) => {
return (
<StLabel
htmlFor={sort}
key={sort}
onChange={() => handleCheckedItem(elementIdx)}
isChecked={checkedItem.has(elementIdx)}
htmlFor={`${tagText}${categoryIdx}`}
key={`${tagText}${categoryIdx}`}
onChange={() =>
handleCheckedItems(categoryIdx, elementIdx, tagText)
}
isChecked={checkedItems[categoryIdx].has(elementIdx)}
>
<StInput type="checkbox" id={sort} name={sort} />
<StFilterElement>{sort}</StFilterElement>
<StInput
type="checkbox"
id={`${tagText}${categoryIdx}`}
name={`${tagText}${categoryIdx}`}
checked={checkedItems[categoryIdx].has(elementIdx)}
/>
<StFilterElement>{tagText}</StFilterElement>
</StLabel>
);
})}
Expand Down
76 changes: 76 additions & 0 deletions components/viewProduct/FilterTag.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import styled from '@emotion/styled';
import { useRecoilState, useRecoilValue } from 'recoil';
import {
checkedItemsState,
filterListState,
filterTagState,
} from '../../core/atom';
import { IcDeleteTag } from '../../public/assets/icons';
import { FilterTagProps } from '../../types/viewProduct';

export default function FilterTag(props: FilterTagProps) {
const { categoryIdx, elementIdx, categoryKey, tagText } = props;
const [checkedItems, setCheckedItems] = useRecoilState(checkedItemsState);
const [filterTagList, setFilterTagList] =
useRecoilState<FilterTagProps[]>(filterTagState);
const filterTagValues = Object.values(filterTagList);
const handleFilterTag = (
categoryIdx: number,
elementIdx: number,
tagText: string,
) => {
const tag: FilterTagProps = {
categoryIdx: categoryIdx,
elementIdx: elementIdx,
categoryKey: categoryKey,
tagText: tagText,
};
if (checkedItems[categoryIdx].has(elementIdx)) {
checkedItems[categoryIdx].delete(elementIdx);
const deleteidx = filterTagList.findIndex((item) => {
return (
item.categoryIdx === categoryIdx && item.elementIdx === elementIdx
);
});

let copyFilterTagList = [...filterTagList];
copyFilterTagList.splice(deleteidx, 1);
setFilterTagList(copyFilterTagList);
} else {
checkedItems[categoryIdx].add(elementIdx);
setFilterTagList([...filterTagList, tag]);
console.log(filterTagList);
}

setCheckedItems({
...checkedItems,
[categoryIdx]: checkedItems[categoryIdx],
});
};
return (
<StFilterTag>
<h2>{tagText === '기타' ? `${tagText} (${categoryKey})` : tagText}</h2>
<StDeleteBtn
onClick={() => handleFilterTag(categoryIdx, elementIdx, tagText)}
/>
</StFilterTag>
);
}
const StFilterTag = styled.div`
display: flex;
align-items: center;
width: fit-content;
padding: 0.6rem 0.8rem 0.6rem 1rem;
margin: 0.5rem;
border-radius: 0.6rem;
background-color: ${({ theme }) => theme.colors.gray002};
color: ${({ theme }) => theme.colors.gray009};
${({ theme }) => theme.fonts.b5_14_medium_140};
`;
const StDeleteBtn = styled(IcDeleteTag)`
margin-left: 0.713rem;
cursor: pointer;
`;
79 changes: 8 additions & 71 deletions components/viewProduct/ProductFilter.tsx
Original file line number Diff line number Diff line change
@@ -1,88 +1,29 @@
import styled from '@emotion/styled';
import { LoaderValue } from 'next/dist/shared/lib/image-config';
import React, { EventHandler, useState } from 'react';
import { useState } from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import { checkedItemsState, filterListState } from '../../core/atom';
import { IcClose, IcOpen } from '../../public/assets/icons';
import FilterDropdown from './FilterDropdown';

interface ProductFilterIcon {
title: string;
value: boolean;
}
export default function ProductFilter() {
const filterList = {
스토어: [
'국민장난감',
'그린키드',
'러브로',
'리틀베이비',
'빌리바바',
'어텐션홈이벤트',
'장난감점빵',
'젤리바운스',
'해피장난감',
],
'사용 연령': [
'0~5개월',
'6~11개월',
'12~17개월',
'18~23개월',
'24~35개월',
'36~47개월',
'48~60개월',
'기타',
],
가격: ['1만원 미만', '1-3만원', '3-5만원', '5-8만원', '8만원이상'],
특성: ['타고 노는', '만지고 노는', '기타'],
'장난감 종류': [
'아기체육관',
'모빌',
'바운서',
'쏘서',
'점퍼루',
'위고',
'보행기',
'걸음마 보조기',
'러닝홈',
'러닝테이블',
'기타 학습완구',
'미끄럼틀',
'에어바운스',
'트램펄린',
'어린이 자동차',
'흔들말',
'그네',
'소꿉놀이',
'역할놀이',
'기타',
],
};
const filterListData = Object.values(filterList);
const filterListKeys = Object.keys(filterList);
const filterlist = useRecoilValue(filterListState);
const [visibility, setVisibility] = useState<boolean[]>([
false,
false,
false,
false,
false,
]);
const [checkedItems, setCheckedItems] = useState<Set<number>[]>([
new Set<number>(),
new Set<number>(),
new Set<number>(),
new Set<number>(),
new Set<number>(),
]);
const filterListData = Object.values(filterlist.filterList);
const filterListKeys = Object.keys(filterlist.filterList);
const [checkedItems, setcheckedItems] = useRecoilState(checkedItemsState);
const handleDropdown = (idx: number) => {
setVisibility({
...visibility,
[idx]: !visibility[idx],
});
};

const handleCheckedItems = (copyCheckedItem: Set<number>, idx: number) => {
setCheckedItems({ ...checkedItems, [idx]: copyCheckedItem });
};

//const [repeat, setRepeat] = useState<null | number | void | string>();
// const handleDrop = (idx: number) => {
// if (visibility[idx]) {
Expand Down Expand Up @@ -124,7 +65,7 @@ export default function ProductFilter() {
isExcept={idx == 3 ? true : false}
isDrop={visibility[idx]}
checkedItem={checkedItems[idx]}
handleCheckedItems={handleCheckedItems}
categoryKey={title}
/>
)}
</StFilterSection>
Expand Down Expand Up @@ -156,7 +97,3 @@ const StFilterSection = styled.section<{ isDrop: boolean }>`
${({ theme }) => theme.fonts.b4_15_semibold_146};
cursor: pointer;
`;

// function repeat(repeat: any) {
// throw new Error('Function not implemented.');
// }
65 changes: 65 additions & 0 deletions components/viewProduct/TagSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import styled from '@emotion/styled';
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
import { filterListState, filterTagState } from '../../core/atom';
import { IcUndoBtn } from '../../public/assets/icons';
import { FilterTagProps } from '../../types/viewProduct';
import FilterTag from './FilterTag';

export default function TagSection() {
const filterTagList = useRecoilValue<FilterTagProps[]>(filterTagState);

return (
<StTagSection>
<StTagWrapper>
{filterTagList.map(
({ categoryIdx, elementIdx, categoryKey, tagText }) => {
return (
<FilterTag
key={`${categoryKey}${tagText}`}
categoryIdx={categoryIdx}
elementIdx={elementIdx}
categoryKey={categoryKey}
tagText={tagText}
/>
);
},
)}
</StTagWrapper>
<StUndoAllTagBtn>
<h2>모두 해제</h2>
<IcUndoBtn />
</StUndoAllTagBtn>
</StTagSection>
);
}

const StTagWrapper = styled.article`
display: flex;
justify-content: flex-start;
flex-flow: row wrap;
width: 77.6rem;
height: fit-content;
`;
const StTagSection = styled.div`
display: flex;
align-items: flex-start;
justify-content: space-between;
padding: 1.5rem 0;
margin-left: 2.4rem;
border-bottom: 0.1rem solid ${({ theme }) => theme.colors.gray002};
`;
const StUndoAllTagBtn = styled.button`
display: flex;
align-items: center;
padding: 0 0 0 1rem;
margin-top: 0.5rem;
background-color: ${({ theme }) => theme.colors.white};
border-radius: 0.6rem;
border: 0.1rem solid ${({ theme }) => theme.colors.gray004};
color: ${({ theme }) => theme.colors.gray007};
${({ theme }) => theme.fonts.b5_14_medium_140};
`;
2 changes: 2 additions & 0 deletions components/viewProduct/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,6 @@ export { default as ProductFilter } from './ProductFilter';
export { default as FilterDropdown } from './FilterDropdown';
export { default as ToyList } from './ToyList';
export { default as ToyPreview } from './ToyPreview';
export { default as FilterTag } from './FilterTag';
export { default as TagSection } from './TagSection';
export { default as TopFloatingBtn } from './TopFloatingBtn';
Loading

0 comments on commit 7031def

Please sign in to comment.