forked from ooni/explorer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcountries.js
206 lines (179 loc) · 6.59 KB
/
countries.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
import axios from 'axios'
import debounce from 'lodash.debounce'
import Head from 'next/head'
import {
Box,
Container, Flex, Heading, Input, Link, Text
} from 'ooni-components'
import React, { useMemo, useState } from 'react'
import { FormattedMessage, useIntl } from 'react-intl'
import styled from 'styled-components'
import NavBar from 'components/NavBar'
import countryUtil from 'country-util'
import { getLocalisedRegionName } from 'utils/i18nCountries'
import CountryList from 'components/CountryBox'
import { StyledStickyNavBar } from 'components/SharedStyledComponents'
const CountryLink = styled(Link)`
color: ${props => props.theme.colors.black};
text-decoration: none;
&:hover {
color: ${props => props.theme.colors.blue5};
}
`
const StyledCountryCard = styled(Box)`
border: 1px solid ${props => props.theme.colors.gray3};
`
const Divider = styled.div`
border: 1px solid ${props => props.theme.colors.gray3};
margin-bottom: 12px;
`
// To compenstate for the sticky navigation bar
// :target selector applies only the element with id that matches
// the current URL fragment (e.g '/#Africa')
const RegionHeaderAnchor = styled.div`
:target::before {
content: ' ';
display: block;
width: 0;
/* Height of the combined header (NavBar and Regions) */
/* This is needed to compensate the for the sticky navbar and region
links bar when scrolling to the selected region. And the height of these
bars changes in the mobile layout. This has evolved to be a bad design
that needs to be replaced. */
height: 145px;
margin-top: -145px;
@media(max-width: 768px) {
height: 375px;
margin-top: -375px;
}
}
`
const RegionBlock = ({regionCode, countries}) => {
const intl = useIntl()
countries = countries
.map((c) => ({...c, localisedName: getLocalisedRegionName(c.alpha_2, intl.locale)}))
.sort((a, b) => (new Intl.Collator(intl.locale).compare(a.localisedName, b.localisedName)))
const regionName = getLocalisedRegionName(regionCode, intl.locale)
// Select countries in the region where we have measuremennts from
const measuredCountriesInRegion = countryUtil.regions[regionCode].countries.filter((countryCode) => (
countries.find((item) => item.alpha_2 === countryCode)
))
// When there are no measurements from the region
if (measuredCountriesInRegion.length === 0) {
return null
}
return (
<Box my={3}>
<RegionHeaderAnchor id={regionName} />
<Heading h={1} center py={2}>{regionName}</Heading>
<CountryList
countries={countries.filter((c => ( measuredCountriesInRegion.indexOf(c.alpha_2) > -1 ))).map((c) => ({country: c.alpha_2, measurements: c.count}))}
itemsPerRow={4}
/>
</Box>
)
}
const RegionMenu = styled.div`
background-color: white;
border-bottom: 1px solid ${props => props.theme.colors.gray3};
`
const StyledRegionLink = styled.a`
display: block;
color: ${(props) => props.theme.colors.blue5};
text-decoration: none;
border-bottom: 2px solid transparent;
:hover {
border-bottom: 2px solid ${(props) => props.theme.colors.blue5};
width: 100%;
}
`
const RegionLink = ({ href, label }) => (
<Box px={[1,3]} py={[2,4]}>
<StyledRegionLink href={href}>
<Text fontSize={[16, 20]}>{label}</Text>
</StyledRegionLink>
</Box>
)
const NoCountriesFound = ({ searchTerm }) => (
<Flex justifyContent='center'>
<Box width={1/2} m={5}>
<Text textAlign='center' fontSize={5}>
{/* TODO Add to copy */}
<FormattedMessage
id='Countries.Search.NoCountriesFound'
values={{ searchTerm: `"${searchTerm}"` }}
/>
</Text>
</Box>
</Flex>
)
export const getServerSideProps = async () => {
const client = axios.create({baseURL: process.env.NEXT_PUBLIC_OONI_API}) // eslint-disable-line
const result = await client.get('/api/_/countries')
const responseUrl = result?.request?.res?.responseUrl
return {
props: {
countries: result.data.countries,
}
}
}
const Countries = ({countries}) => {
const intl = useIntl()
const [searchInput, setSearchInput] = useState('')
let filteredCountries = countries
if (searchInput !== '') {
filteredCountries = countries.filter((country) => (
country.name.toLowerCase().indexOf(searchInput.toLowerCase()) > -1
))
}
const searchHandler = (searchTerm) => {
setSearchInput(searchTerm)
}
const debouncedSearchHandler = useMemo(() => debounce(searchHandler, 200), [])
// Africa Americas Asia Europe Oceania Antarctica
const regions = ['002', '019', '142', '150', '009', 'AQ']
return (
<>
<Head>
<title>{intl.formatMessage({id: 'Countries.PageTitle'})}</title>
</Head>
<StyledStickyNavBar>
<NavBar />
<RegionMenu>
<Container>
<Flex
flexDirection={['column', 'row']}
justifyContent={['flex-start', 'flex-end']}
alignItems={['flex-start', 'center']}
>
<Box my={2}>
<Input
onChange={(e) => debouncedSearchHandler(e.target.value)}
placeholder={intl.formatMessage({id: 'Countries.Search.Placeholder'})}
error={filteredCountries.length === 0}
/>
</Box>
<RegionLink href={`#${getLocalisedRegionName('002', intl.locale)}`} label={getLocalisedRegionName('002', intl.locale)} />
<RegionLink href={`#${getLocalisedRegionName('019', intl.locale)}`} label={getLocalisedRegionName('019', intl.locale)} />
<RegionLink href={`#${getLocalisedRegionName('142', intl.locale)}`} label={getLocalisedRegionName('142', intl.locale)} />
<RegionLink href={`#${getLocalisedRegionName('150', intl.locale)}`} label={getLocalisedRegionName('150', intl.locale)} />
<RegionLink href={`#${getLocalisedRegionName('009', intl.locale)}`} label={getLocalisedRegionName('009', intl.locale)} />
<RegionLink href={`#${getLocalisedRegionName('AQ', intl.locale)}`} label={getLocalisedRegionName('AQ', intl.locale)} />
</Flex>
</Container>
</RegionMenu>
</StyledStickyNavBar>
<Container>
{
// Show a message when there are no countries to show, when search is empty
(filteredCountries.length === 0)
? <NoCountriesFound searchTerm={searchInput} />
: regions.map((regionCode, index) => (
<RegionBlock key={index} regionCode={regionCode} countries={filteredCountries} />
))
}
</Container>
</>
)
}
export default Countries