Skip to content

Commit 7140819

Browse files
committed
feat: categorized equivalents in comparator
1 parent 6d466a1 commit 7140819

12 files changed

Lines changed: 511 additions & 25 deletions

File tree

src/components/comparateur/overscreens/Checkbox.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ const Checkbox = (
1313
equivalent,
1414
equivalents,
1515
setEquivalents,
16+
simple,
1617
}: {
1718
equivalent: ComputedEquivalent
1819
equivalents: string[]
1920
setEquivalents: (value: string[]) => void
21+
simple?: boolean
2022
},
2123
ref: ForwardedRef<HTMLInputElement>
2224
) => {
@@ -66,7 +68,7 @@ const Checkbox = (
6668
</div>
6769
)}
6870
</div>
69-
<EquivalentIcon height={2} equivalent={equivalent} />
71+
{!simple && <EquivalentIcon height={2} equivalent={equivalent} />}
7072
</>
7173
}
7274
/>

src/components/comparateur/overscreens/ComparisonEquivalents.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ const ComparisonEquivalents = ({
99
onClose,
1010
equivalents,
1111
index,
12+
simple,
1213
}: {
1314
onClose: () => void
1415
equivalents: Equivalent[]
1516
index: 0 | 1
17+
simple?: boolean
1618
}) => {
1719
const {
1820
language,
@@ -37,7 +39,7 @@ const ComparisonEquivalents = ({
3739
onClose()
3840
}}>
3941
<span>{getName(language, equivalent, false, 1, false, true)}</span>
40-
<EquivalentIcon height={2} equivalent={equivalent} />
42+
{!simple && <EquivalentIcon height={2} equivalent={equivalent} />}
4143
</button>
4244
</li>
4345
))

src/components/comparateur/overscreens/ComparisonOverscreen.tsx

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,62 @@
11
'use client'
22
import { useTranslations } from 'next-intl'
3-
import { useState } from 'react'
3+
import { useMemo, useState } from 'react'
44
import useParamContext from 'src/providers/ParamProvider'
55
import { useSearchEquivalent } from 'src/providers/useSearchEquivalent'
6+
import { ComputedEquivalent } from 'types/equivalent'
67
import { computedEquivalents } from 'data/categories/computedEquivalents'
78
import { deplacements } from 'data/categories/deplacement'
89
import { getEquivalentWithCarpool } from 'utils/carpool'
910
import Button from 'components/base/buttons/Button'
1011
import HiddenLabel from 'components/form/HiddenLabel'
1112
import Input from 'components/form/Input'
1213
import ComparisonEquivalents from './ComparisonEquivalents'
14+
import SubCategoryEquivalent from './SubCategoryEquivalent'
15+
import { subCategories } from './equivalentCategories'
1316
import styles from './EquivalentsOverscreen.module.css'
1417

18+
const allEquivalents = computedEquivalents('transport', deplacements).flatMap(getEquivalentWithCarpool)
19+
1520
const ComparisonOverscreen = ({ index }: { index: 0 | 1 }) => {
1621
const { setOverscreen } = useParamContext()
1722
const [search, setSearch] = useState('')
18-
const results = useSearchEquivalent(
19-
search,
20-
false,
21-
4,
22-
false,
23-
computedEquivalents('transport', deplacements).flatMap(getEquivalentWithCarpool)
24-
)
23+
const results = useSearchEquivalent(search, false, 4, false, allEquivalents)
2524

2625
const tSearch = useTranslations('comparateur.overscreen')
2726
const t = useTranslations('overscreen.transport')
2827
const tModal = useTranslations('modal')
2928
const onClose = () => {
3029
setOverscreen('transport', '')
3130
}
31+
32+
const { categoriesEquivalents, categorizedSlugs } = useMemo(() => {
33+
const result = {} as Record<string, Record<string, ComputedEquivalent[]>>
34+
Object.entries(subCategories).forEach(([category, categoryEquivalents]) => {
35+
const categories = {} as Record<string, ComputedEquivalent[]>
36+
Object.entries(categoryEquivalents).forEach(([subCategory, subCategoryEquivalents]) => {
37+
const filteredEquivalents = subCategoryEquivalents
38+
.map((subCategoryEquivalent) =>
39+
allEquivalents.find((equivalent) => equivalent.slug === subCategoryEquivalent)
40+
)
41+
.filter((equivalent) => equivalent !== undefined)
42+
if (filteredEquivalents.length > 0) {
43+
categories[subCategory] = filteredEquivalents
44+
}
45+
})
46+
if (Object.keys(categories).length > 0) {
47+
result[category] = categories
48+
}
49+
})
50+
return {
51+
categoriesEquivalents: result,
52+
categorizedSlugs: Object.values(result).flatMap((subCategories) =>
53+
Object.values(subCategories).flatMap((subCategoryEquivalents) =>
54+
subCategoryEquivalents.map((equivalent) => equivalent.slug)
55+
)
56+
),
57+
}
58+
}, [])
59+
3260
return (
3361
<>
3462
<div className={styles.header}>
@@ -68,7 +96,24 @@ const ComparisonOverscreen = ({ index }: { index: 0 | 1 }) => {
6896
</div>
6997
)
7098
) : (
71-
<ComparisonEquivalents onClose={onClose} equivalents={results} index={index} />
99+
<>
100+
{Object.entries(categoriesEquivalents)
101+
.filter(([category]) => category.startsWith('voiture'))
102+
.map(([category, subCategories]) => (
103+
<SubCategoryEquivalent
104+
category={allEquivalents.find((equivalent) => equivalent.slug === category) as ComputedEquivalent}
105+
categoriesEquivalents={subCategories}
106+
onClose={onClose}
107+
index={index}
108+
key={category}
109+
/>
110+
))}
111+
<ComparisonEquivalents
112+
onClose={onClose}
113+
equivalents={results.filter((equivalent) => !categorizedSlugs.includes(equivalent.slug))}
114+
index={index}
115+
/>
116+
</>
72117
)}
73118
</ul>
74119
<div className={styles.footerCenter}>
Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
import { RefObject } from 'react'
1+
import { RefObject, useMemo } from 'react'
22
import { ComputedEquivalent } from 'types/equivalent'
33
import Checkbox from './Checkbox'
4+
import SubCategoryEquivalent from './SubCategoryEquivalent'
5+
import { subCategories } from './equivalentCategories'
46

57
const Equivalents = ({
68
equivalentsToDisplay,
@@ -16,16 +18,63 @@ const Equivalents = ({
1618
list?: boolean
1719
}) => {
1820
const Container = list ? 'li' : 'div'
19-
return equivalentsToDisplay.map((equivalent, index) => (
20-
<Container key={equivalent.slug}>
21-
<Checkbox
22-
equivalents={equivalents}
23-
equivalent={equivalent}
24-
setEquivalents={setEquivalents}
25-
ref={index === 0 ? firstRef : undefined}
26-
/>
27-
</Container>
28-
))
21+
const { categoriesEquivalents, categorizedSlugs } = useMemo(() => {
22+
if (list) {
23+
return { categoriesEquivalents: {}, categorizedSlugs: [] }
24+
}
25+
const result = {} as Record<string, Record<string, ComputedEquivalent[]>>
26+
Object.entries(subCategories).forEach(([category, categoryEquivalents]) => {
27+
const categories = {} as Record<string, ComputedEquivalent[]>
28+
Object.entries(categoryEquivalents).forEach(([subCategory, subCategoryEquivalents]) => {
29+
const filteredEquivalents = subCategoryEquivalents
30+
.map((subCategoryEquivalent) =>
31+
equivalentsToDisplay.find((equivalent) => equivalent.slug === subCategoryEquivalent)
32+
)
33+
.filter((equivalent) => equivalent !== undefined)
34+
if (filteredEquivalents.length > 0) {
35+
categories[subCategory] = filteredEquivalents
36+
}
37+
})
38+
if (Object.keys(categories).length > 0) {
39+
result[category] = categories
40+
}
41+
})
42+
return {
43+
categoriesEquivalents: result,
44+
categorizedSlugs: Object.values(result).flatMap((subCategories) =>
45+
Object.values(subCategories).flatMap((subCategoryEquivalents) =>
46+
subCategoryEquivalents.map((equivalent) => equivalent.slug)
47+
)
48+
),
49+
}
50+
}, [equivalentsToDisplay, list])
51+
52+
return (
53+
<>
54+
{Object.entries(categoriesEquivalents).map(([category, subCategories]) => (
55+
<SubCategoryEquivalent
56+
category={equivalentsToDisplay.find((equivalent) => equivalent.slug === category) as ComputedEquivalent}
57+
categoriesEquivalents={subCategories}
58+
equivalents={equivalents}
59+
setEquivalents={setEquivalents}
60+
checkbox
61+
key={category}
62+
/>
63+
))}
64+
{equivalentsToDisplay
65+
.filter((equivalent) => !categorizedSlugs.includes(equivalent.slug))
66+
.map((equivalent, index) => (
67+
<Container key={equivalent.slug}>
68+
<Checkbox
69+
equivalents={equivalents}
70+
equivalent={equivalent}
71+
setEquivalents={setEquivalents}
72+
ref={index === 0 ? firstRef : undefined}
73+
/>
74+
</Container>
75+
))}
76+
</>
77+
)
2978
}
3079

3180
export default Equivalents
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
.header {
2+
cursor: pointer;
3+
display: flex;
4+
padding: 0.75rem;
5+
align-items: center;
6+
gap: 0.75rem;
7+
width: 100%;
8+
background-color: transparent;
9+
border-radius: 0.5rem;
10+
font-weight: 500;
11+
color: var(--neutral-50);
12+
13+
&:hover {
14+
color: var(--neutral-80);
15+
background-color: var(--primary-10);
16+
}
17+
}
18+
19+
.coloredNumber {
20+
color: var(--primary-60);
21+
font-weight: 700;
22+
}
23+
24+
.title {
25+
display: flex;
26+
flex: 1;
27+
justify-content: space-between;
28+
}
29+
30+
.button {
31+
padding: 0.5rem;
32+
border-radius: 50%;
33+
border: solid 2px var(--primary-30);
34+
display: flex;
35+
justify-content: center;
36+
align-items: center;
37+
color: var(--primary-50);
38+
39+
svg {
40+
width: 1.5rem;
41+
height: 1.5rem;
42+
}
43+
}
44+
45+
.subCategories {
46+
display: flex;
47+
flex-direction: column;
48+
gap: 1rem;
49+
margin-top: 0.5rem;
50+
padding: 0.5rem 0 1.5rem 0.75rem;
51+
}
52+
53+
.subCategory {
54+
color: var(--neutral-50);
55+
font-size: 0.875rem;
56+
font-weight: 500;
57+
line-height: 1.5rem;
58+
text-transform: uppercase;
59+
}
60+
61+
.checkbox {
62+
&:not(:last-child) {
63+
border-bottom: 2px solid var(--neutral-20);
64+
}
65+
}

0 commit comments

Comments
 (0)