@@ -2,40 +2,20 @@ import { faCircleNotch } from "@fortawesome/free-solid-svg-icons";
2
2
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" ;
3
3
import React , { useState } from "react" ;
4
4
import InfiniteScroll from "react-infinite-scroll-component" ;
5
- import Select from "react-select" ;
6
-
5
+ import { IndexedTopics } from "../topics" ;
7
6
import { Repository } from "../types" ;
8
7
import { RepositoryItem } from "./RepositoryItem" ;
8
+ import { GeneralFilter } from "./GeneralFilter" ;
9
+ import { LanguageFilter } from "./LanguageFilter" ;
10
+ import { SDGFilter } from "./SDGFilter" ;
9
11
10
12
type RepositoryListProps = {
11
13
repositories : Repository [ ] ;
12
14
} ;
13
15
14
- const indexedTopics : { [ key : string ] : string } = {
15
- "sdg-1" : "SDG-1 - No Poverty" ,
16
- "sdg-2" : "SDG-2 - Zero Hunger" ,
17
- "sdg-3" : "SDG-3 - Good Health And Well-Being" ,
18
- "sdg-4" : "SDG-4 - Quality Education" ,
19
- "sdg-5" : "SDG-5 - Gender Equality" ,
20
- "sdg-6" : "SDG-6 - Clean Water and Sanitation" ,
21
- "sdg-7" : "SDG-7 - Affordable and Clean Energy" ,
22
- "sdg-8" : "SDG-8 - Decent Work and Economic Growth" ,
23
- "sdg-9" : "SDG-9 - Industry, Innovation, and Infrastructure" ,
24
- "sdg-10" : "SDG-10 - Reduced Inequalities" ,
25
- "sdg-11" : "SDG-11 - Sustainable Cities and Communities" ,
26
- "sdg-12" : "SDG-12 - Responsible Consumption and Production" ,
27
- "sdg-13" : "SDG-13 - Climate Action" ,
28
- "sdg-14" : "SDG-14 - Life Below Water" ,
29
- "sdg-15" : "SDG-15 - Life on Land" ,
30
- "sdg-16" : "SDG-16 - Peace, Justice, and Strong Institutions" ,
31
- "sdg-17" : "SDG-17 - Partnerships for the Goals"
32
- } ;
33
-
34
16
const Loader = ( ) => (
35
- < div className = "p-4 w-full" >
36
- < div className = "flex items-center justify-center" >
37
- < FontAwesomeIcon icon = { faCircleNotch } className = "fa-spin" />
38
- </ div >
17
+ < div className = "p-4 w-full flex items-center justify-center" >
18
+ < FontAwesomeIcon icon = { faCircleNotch } className = "fa-spin" />
39
19
</ div >
40
20
) ;
41
21
@@ -46,89 +26,33 @@ export const RepositoryList = ({ repositories }: RepositoryListProps) => {
46
26
const [ selectedLanguages , setSelectedLanguages ] = useState < string [ ] > ( [ ] ) ;
47
27
const [ selectedTopics , setSelectedTopics ] = useState < string [ ] > ( [ ] ) ;
48
28
49
- console . log ( selectedTopics ) ;
50
29
const filteredRepositories = repositories . filter ( ( repository ) => {
51
- const languageFilter =
52
- selectedLanguages . length === 0 || selectedLanguages . includes ( repository . language . display ) ;
53
-
54
- const topicFilter =
55
- selectedTopics . length === 0 ||
56
- selectedTopics . some ( ( value ) => repository . topics ?. some ( ( topic ) => topic . display === value ) ) ;
57
-
58
- const nameFilter = Object . values ( repository ) . some ( ( value ) => {
59
- if ( value === null ) {
60
- return false ;
61
- }
62
- return value . toString ( ) . toLowerCase ( ) . includes ( filter . toLowerCase ( ) ) ;
63
- } ) ;
64
-
30
+ const languageFilter = selectedLanguages . length === 0 || selectedLanguages . includes ( repository . language . display ) ;
31
+ const topicFilter = selectedTopics . length === 0 || repository . topics ?. some ( ( topic ) => selectedTopics . includes ( topic . display ) ) ;
32
+ const nameFilter = Object . values ( repository ) . some ( ( value ) => value && value . toString ( ) . toLowerCase ( ) . includes ( filter . toLowerCase ( ) ) ) ;
65
33
return languageFilter && nameFilter && topicFilter ;
66
34
} ) ;
67
35
68
- const allLanguages = repositories . map ( ( repository ) => repository . language . display ) ;
69
- const uniqueLanguages = allLanguages . filter (
70
- ( language , index ) => allLanguages . indexOf ( language ) === index
71
- ) ;
72
- const languageOptions = uniqueLanguages . map ( ( language ) => ( {
73
- value : language ,
74
- label : language
75
- } ) ) ;
36
+ const uniqueLanguages = [ ...new Set ( repositories . map ( ( repository ) => repository . language . display ) ) ] ;
37
+ const languageOptions = uniqueLanguages . map ( ( language ) => ( { value : language , label : language } ) ) ;
38
+
39
+ const uniqueTopics = [ ...new Set ( repositories . flatMap ( ( repository ) => repository . topics ?. map ( ( topic ) => topic . display ) ?? [ ] ) ) ] . sort ( ( a , b ) => parseInt ( a . slice ( 4 ) ) - parseInt ( b . slice ( 4 ) ) ) ;
40
+ const topicOptions = uniqueTopics . map ( ( topic ) => ( { value : topic , label : IndexedTopics [ topic ] } ) ) ;
76
41
77
- const topicList = repositories . map ( ( repository ) => repository . topics ) ;
78
- const allTopics = topicList . map ( ( repos ) => repos ?. map ( ( topic ) => topic . display ) ) ?? [ ] ;
79
- const uniqueTopics = allTopics
80
- . filter ( ( topic , index ) => allTopics . indexOf ( topic ) === index )
81
- . flat ( ) ;
82
- const topicOptions = uniqueTopics . map ( ( topic ) => ( {
83
- value : topic ,
84
- label : indexedTopics [ topic ?? "" ]
85
- } ) ) ;
42
+ const loadMoreItems = ( ) => setItems ( items + itemsPerScroll ) ;
43
+ const hasMoreItems = items < filteredRepositories . length ;
86
44
87
45
return (
88
46
< main className = "grow" >
89
47
< div className = "p-4 w-full" >
90
48
< div className = "flex flex-wrap" >
91
- < input
92
- type = "text"
93
- value = { filter }
94
- onChange = { ( e ) => setFilter ( e . target . value ) }
95
- placeholder = "Search Repositories"
96
- className = "flex-1 mx-2 border rounded-sm p-2 mb-4"
97
- />
98
- < label className = "p-2" > Filter by Language</ label >
99
- < Select
100
- isMulti
101
- closeMenuOnSelect = { false }
102
- className = "flex-1 mx-2 border rounded-sm p-2 mb-4"
103
- onChange = { ( selectedOptions ) => {
104
- setSelectedLanguages ( selectedOptions . map ( ( option ) => option . value ) ) ;
105
- } }
106
- options = { languageOptions }
107
- classNamePrefix = "select"
108
- />
109
- < label className = "p-2" > Sustainable Development Goal (SDG)</ label >
110
- < Select
111
- isMulti
112
- className = "flex-1 mx-2 border rounded-sm p-2 mb-4"
113
- options = { topicOptions }
114
- getOptionLabel = { ( option ) => option . label }
115
- getOptionValue = { ( option ) => option . value ?? "" }
116
- onChange = { ( selectedOptions ) => {
117
- setSelectedTopics ( selectedOptions . map ( ( option ) => option . value ?? "" ) ) ;
118
- } }
119
- />
49
+ < GeneralFilter filter = { filter } setFilter = { setFilter } />
50
+ < LanguageFilter setSelectedLanguages = { setSelectedLanguages } languageOptions = { languageOptions } />
51
+ < SDGFilter setSelectedTopics = { setSelectedTopics } topicOptions = { topicOptions } />
120
52
</ div >
121
53
122
- < InfiniteScroll
123
- dataLength = { items }
124
- next = { ( ) => setItems ( items + itemsPerScroll ) }
125
- hasMore = { items < filteredRepositories . length }
126
- loader = { < Loader /> }
127
- >
128
- { filteredRepositories . slice ( 0 , items ) . map ( ( repository ) => {
129
- const key = `${ repository . id } _${ new Date ( ) . getTime ( ) } _${ Math . random ( ) } ` ;
130
- return < RepositoryItem key = { key } repository = { repository } /> ;
131
- } ) }
54
+ < InfiniteScroll dataLength = { items } next = { loadMoreItems } hasMore = { hasMoreItems } loader = { < Loader /> } >
55
+ { filteredRepositories . slice ( 0 , items ) . map ( ( repository ) => < RepositoryItem key = { repository . id } repository = { repository } /> ) }
132
56
</ InfiniteScroll >
133
57
</ div >
134
58
</ main >
0 commit comments