Skip to content
This repository was archived by the owner on Nov 8, 2022. It is now read-only.

Commit f3a9227

Browse files
authored
refactor: parse menu/filter tags (#1151)
* chore: wip * chore: extract TNaviTag * chore: wip * chore(filtersMenu): wip * chore(filtersMenu): fix onSelect * chore(filtersMenu): clean up
1 parent b3ef763 commit f3a9227

File tree

35 files changed

+969
-546
lines changed

35 files changed

+969
-546
lines changed

server/routes.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ router.route('/meetups/:slug?').get((req, res) => {
6262
return renderAndCache({ req, res, path: '/meetups' })
6363
})
6464

65-
// 酷导游
65+
// 酷导航
6666
router.route('/cool-guide/:slug?').get((req, res) => {
6767
return renderAndCache({ req, res, path: '/cool-guide' })
6868
})

src/components/BuyMeChuanChuan/ChuanSelector.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,12 @@ const ChuanSelector: FC<TProps> = ({ active, onSelect }) => {
2424
<Selectors>
2525
<By>x</By>
2626
{options.map((item) => (
27-
<Circle key={item} active={item === 1} onClick={() => onSelect(item)}>
28-
1
27+
<Circle
28+
key={item}
29+
active={item === active}
30+
onClick={() => onSelect(item)}
31+
>
32+
{item}
2933
</Circle>
3034
))}
3135
</Selectors>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { FC, memo } from 'react'
2+
3+
import type { TTag } from '@/spec'
4+
import type { TProps as TFilter } from './index'
5+
import { Wrapper, Dot, Title } from '../styles/filter/tag'
6+
7+
const isActive = (activeMap, expandMenuId, itemId) => {
8+
if (expandMenuId === null) return false
9+
return activeMap[expandMenuId].id === itemId
10+
}
11+
12+
type TProps = Pick<
13+
TFilter,
14+
'expandMenuId' | 'onSelect' | 'revert' | 'activeMap'
15+
> & { tag: TTag }
16+
17+
const ExpandTag: FC<TProps> = ({
18+
tag,
19+
expandMenuId,
20+
activeMap,
21+
onSelect,
22+
revert,
23+
}) => {
24+
return (
25+
<Wrapper onClick={() => onSelect(expandMenuId, tag)}>
26+
{!revert ? (
27+
<>
28+
<Dot active={isActive(activeMap, expandMenuId, tag.id)} />
29+
<Title active={isActive(activeMap, expandMenuId, tag.id)}>
30+
{tag.title}
31+
</Title>
32+
</>
33+
) : (
34+
<>
35+
<Title active={isActive(activeMap, expandMenuId, tag.id)} revert>
36+
{tag.title}
37+
</Title>
38+
<Dot active={isActive(activeMap, expandMenuId, tag.id)} />
39+
</>
40+
)}
41+
</Wrapper>
42+
)
43+
}
44+
45+
export default memo(ExpandTag)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { FC, memo } from 'react'
2+
3+
import type { TTag } from '@/spec'
4+
5+
import type { TProps as TFilter } from './index'
6+
import { Wrapper, FoldDot, Title } from '../styles/filter/tag'
7+
8+
type TProps = Pick<TFilter, 'expandMenuId' | 'onSelect' | 'revert'> & {
9+
tag: TTag
10+
}
11+
12+
const SelectedTag: FC<TProps> = ({ tag, expandMenuId, onSelect, revert }) => {
13+
return (
14+
<Wrapper onClick={() => onSelect(expandMenuId, tag)}>
15+
{!revert ? (
16+
<>
17+
<FoldDot active={tag.title !== '全部'} />
18+
<Title active={tag.title !== '全部'}>
19+
{tag ? tag.title || '全部' : '全部'}
20+
</Title>
21+
</>
22+
) : (
23+
<>
24+
<Title active={tag.title !== '全部'} revert>
25+
{tag ? tag.title || '全部' : '全部'}
26+
</Title>
27+
<FoldDot active={tag.title !== '全部'} />
28+
</>
29+
)}
30+
</Wrapper>
31+
)
32+
}
33+
34+
export default memo(SelectedTag)

src/components/FiltersMenu/Filter/index.tsx

Lines changed: 39 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -4,106 +4,61 @@
44
*
55
*/
66

7-
import { memo } from 'react'
8-
import T from 'prop-types'
7+
import { FC, memo } from 'react'
98

10-
import {
11-
Wrapper,
12-
Item,
13-
RadioWrapper,
14-
RadioItem,
15-
ActiveDot,
16-
RadioTitle,
17-
} from '../styles/filter'
9+
import type { TID, TTag } from '@/spec'
1810

19-
const isActive = (activeMap, expandMenuId, itemId) => {
20-
if (!expandMenuId) return false
21-
return activeMap[expandMenuId].id === itemId
11+
import ExpandTag from './ExpandTag'
12+
import SelectedTag from './SelectedTag'
13+
14+
import { Wrapper, Item, TagsWrapper } from '../styles/filter'
15+
16+
export type TProps = {
17+
id: TID
18+
expandMenuId: TID | null
19+
activeMap: Record<string, TTag>
20+
options: TTag[]
21+
revert: boolean
22+
onSelect: (expandMenuId: TID, tag: TTag) => void
2223
}
2324

24-
const Filter = ({ id, expandMenuId, activeMap, options, onSelect, revert }) => {
25+
const Filter: FC<TProps> = ({
26+
id,
27+
expandMenuId = null,
28+
activeMap,
29+
options,
30+
onSelect,
31+
revert,
32+
}) => {
2533
return (
2634
<Wrapper revert={revert}>
2735
<Item revert={revert}>
2836
{expandMenuId === id && options ? (
29-
<RadioWrapper revert={revert}>
37+
<TagsWrapper revert={revert}>
3038
{options.map((item) => (
31-
<RadioItem
39+
<ExpandTag
3240
key={item.id}
33-
onClick={() => onSelect(expandMenuId, item)}
34-
>
35-
{!revert ? (
36-
<>
37-
<ActiveDot
38-
active={isActive(activeMap, expandMenuId, item.id)}
39-
/>
40-
<RadioTitle
41-
active={isActive(activeMap, expandMenuId, item.id)}
42-
>
43-
{item.title}
44-
</RadioTitle>
45-
</>
46-
) : (
47-
<>
48-
<RadioTitle
49-
active={isActive(activeMap, expandMenuId, item.id)}
50-
revert
51-
>
52-
{item.title}
53-
</RadioTitle>
54-
<ActiveDot
55-
active={isActive(activeMap, expandMenuId, item.id)}
56-
/>
57-
</>
58-
)}
59-
</RadioItem>
41+
tag={item}
42+
activeMap={activeMap}
43+
expandMenuId={expandMenuId}
44+
revert={revert}
45+
onSelect={onSelect}
46+
/>
6047
))}
61-
</RadioWrapper>
48+
</TagsWrapper>
6249
) : (
63-
<RadioWrapper revert={revert}>
64-
<RadioItem>
65-
{!revert ? (
66-
<>
67-
<ActiveDot active />
68-
<RadioTitle active>
69-
{activeMap[id] ? activeMap[id].title || '全部' : '全部'}
70-
</RadioTitle>
71-
</>
72-
) : (
73-
<>
74-
<RadioTitle active revert>
75-
{activeMap[id] ? activeMap[id].title || '全部' : '全部'}
76-
</RadioTitle>
77-
<ActiveDot active />
78-
</>
79-
)}
80-
</RadioItem>
81-
</RadioWrapper>
50+
<TagsWrapper revert={revert}>
51+
<SelectedTag
52+
tag={activeMap[id]}
53+
expandMenuId={expandMenuId}
54+
revert={revert}
55+
onSelect={onSelect}
56+
/>
57+
</TagsWrapper>
8258
)}
8359
</Item>
8460
</Wrapper>
8561
)
8662
}
8763

88-
Filter.propTypes = {
89-
id: T.string.isRequired,
90-
expandMenuId: T.oneOfType([T.string, T.instanceOf(null)]),
91-
activeMap: T.shape({
92-
id: T.string,
93-
title: T.string,
94-
}).isRequired,
95-
options: T.arrayOf(
96-
T.shape({
97-
id: T.string,
98-
title: T.string,
99-
}),
100-
).isRequired,
101-
revert: T.bool.isRequired,
102-
onSelect: T.func.isRequired,
103-
}
104-
105-
Filter.defaultProps = {
106-
expandMenuId: null,
107-
}
108-
10964
export default memo(Filter)

src/components/FiltersMenu/Header.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,25 @@ import { FC, memo } from 'react'
22

33
import { ICON } from '@/config'
44
import Tooltip from '@/components/Tooltip'
5+
import { SpaceGrow } from '@/components/Common'
56

67
import {
78
Wrapper,
8-
Title,
99
OperatorsWrapper,
1010
Operator,
1111
ResetIcon,
1212
HelpHint,
1313
} from './styles/header'
1414

1515
type TProps = {
16-
title: string
1716
showReset: boolean
1817
onReset: () => void
1918
}
2019

21-
const Header: FC<TProps> = ({ title, showReset, onReset }) => {
20+
const Header: FC<TProps> = ({ showReset, onReset }) => {
2221
return (
2322
<Wrapper>
24-
<Title active={showReset}>{title}</Title>
23+
<SpaceGrow />
2524
<OperatorsWrapper>
2625
<Tooltip
2726
content={<HelpHint>重置筛选条件</HelpHint>}
@@ -30,6 +29,7 @@ const Header: FC<TProps> = ({ title, showReset, onReset }) => {
3029
>
3130
<Operator show={showReset} onClick={onReset}>
3231
<ResetIcon src={`${ICON}/shape/reset.svg`} />
32+
重置
3333
</Operator>
3434
</Tooltip>
3535
</OperatorsWrapper>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { keys, isEmpty, filter } from 'ramda'
2+
3+
import type { TTag } from '@/spec'
4+
import { ICON_CMD } from '@/config'
5+
import { groupByKey } from '@/utils/helper'
6+
7+
import type { TMenu } from './spec'
8+
9+
export const tags2Options = (tags: TTag[]): TMenu => {
10+
const groupedTags = groupByKey(tags, 'group')
11+
const formated = []
12+
13+
keys(groupedTags).forEach((group, index) => {
14+
formated.push({
15+
id: index,
16+
title: group,
17+
icon: `${ICON_CMD}/navi/location.svg`,
18+
options: [{ id: '', title: '全部' }, ...groupedTags[group]],
19+
})
20+
})
21+
22+
return formated
23+
}
24+
25+
export const initActiveMap = (items: TMenu) => {
26+
const menuMap = {}
27+
for (let index = 0; index < items.length; index += 1) {
28+
const element = items[index]
29+
30+
const content = element.options ? element.options[0] : element
31+
menuMap[element.id] = { ...content }
32+
}
33+
34+
return menuMap
35+
}
36+
37+
export const getSelectedTags = (activeMap: Record<string, TTag>): TTag[] => {
38+
const tagList = []
39+
40+
const selectedIdx = filter(
41+
(key) => !isEmpty(activeMap[key].id),
42+
keys(activeMap),
43+
)
44+
45+
selectedIdx.forEach((idx) => {
46+
if (activeMap[idx]) {
47+
tagList.push(activeMap[idx])
48+
}
49+
})
50+
51+
return tagList
52+
}

0 commit comments

Comments
 (0)