Skip to content

Commit c43ade9

Browse files
committed
add country info page
1 parent 414ee48 commit c43ade9

File tree

15 files changed

+321
-54
lines changed

15 files changed

+321
-54
lines changed

src/api/countriesApi.ts

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,45 @@
1+
import { ICountryInfo } from 'components'
12
import axios, { AxiosResponse } from 'axios'
23
import { ICountryCard } from 'components'
34

5+
interface IParams {
6+
[key: string]: string
7+
}
8+
49
const instance = axios.create({
510
baseURL: 'https://restcountries.com/v3.1/',
611
timeout: 10000
712
})
813

914
export const CountriesApi = {
10-
fetchCountryCards: (region: string = 'all'): Promise<AxiosResponse<Array<ICountryCard>>> => {
15+
getCountries: (
16+
region: string = 'all',
17+
params?: IParams
18+
): Promise<AxiosResponse<Array<ICountryCard>>> => {
1119
const request = region !== 'all' ? 'region/' + region : region
12-
20+
1321
return instance.get(request, {
1422
params: {
15-
fields: 'name,population,region,capital,flags'
23+
...params
24+
}
25+
})
26+
},
27+
getCountryByName: (
28+
country: string,
29+
params?: IParams
30+
): Promise<AxiosResponse<Array<ICountryInfo>>> => {
31+
return instance.get(`/name/${country}`, {
32+
params: {
33+
...params
34+
}
35+
})
36+
},
37+
getCountriesByAlfaCode: (alfaCodesArray: Array<string>, params?: IParams): Promise<AxiosResponse<Array<ICountryInfo>>> => {
38+
return instance.get('/alpha', {
39+
params: {
40+
...params,
41+
codes: alfaCodesArray.join(',')
1642
}
1743
})
18-
}
44+
}
1945
}

src/components/CountryCard/CountryCard.module.scss

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,28 @@
66
overflow: hidden;
77
}
88

9+
.inner {
10+
background-color: white;
11+
display: flex;
12+
flex-direction: column;
13+
height: 100%;
14+
}
15+
916
.flag {
1017
aspect-ratio: 3/2;
1118
width: 100%;
12-
height: 100%;
1319
object-fit: cover;
1420
}
1521

1622
.info {
17-
margin-top: auto;
23+
flex-grow: 1;
1824
padding: 22px 20px 35px 20px;
1925
text-align: left;
2026
background-color: white;
2127
}
2228

2329
.name {
2430
cursor: pointer;
25-
margin-top: auto;
2631
font-size: 22px;
2732
font-weight: 600;
2833
margin-bottom: 20px;

src/components/CountryCard/CountryCard.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export const CountryCard: FC<Props> = ({ className, country, ...rest }): JSX.Ele
1313
const navigate = useNavigate()
1414

1515
const clickHandler = () => {
16-
navigate(`/${country.name.common}`)
16+
navigate(`/${ country.name.common.toLowerCase()}`)
1717
}
1818

1919
return (
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
.root {
2+
display: flex;
3+
justify-content: space-between;
4+
align-items: center;
5+
}
6+
7+
.flag {
8+
max-width: 500px;
9+
margin-right: 35px;
10+
}
11+
12+
.info {
13+
flex: 1 1 auto;
14+
text-align: left;
15+
}
16+
17+
.name {
18+
font-size: 28px;
19+
font-weight: 600;
20+
margin-bottom: 18px;
21+
}
22+
23+
.stats {
24+
display: flex;
25+
margin-left: -10px;
26+
margin-right: -10px;
27+
28+
&_col {
29+
flex: 1 1 auto;
30+
margin-left: 10px;
31+
margin-right: 10px;
32+
max-width: 350px;
33+
min-width: 150px;
34+
}
35+
36+
&_row {
37+
margin-bottom: 6px;
38+
}
39+
}
40+
41+
.description {
42+
display: inline-block;
43+
font-size: 18px;
44+
font-weight: 600;
45+
margin-right: 10px;
46+
47+
&BorderCountries{
48+
line-height: 40px;
49+
min-width: max-content;
50+
}
51+
}
52+
53+
.value {
54+
display: inline;
55+
font-weight: 400;
56+
57+
&BorderCountries{
58+
line-height: 40px;
59+
}
60+
}
61+
62+
.button {
63+
&BorderCountry {
64+
background-color: white;
65+
border-radius: 4px;
66+
box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.1);
67+
color: black;
68+
font-size: 18px;
69+
line-height: 40px;
70+
padding: 0 15px;
71+
text-decoration: none;
72+
transition: box-shadow 0.2s ease-in-out;
73+
74+
&:hover {
75+
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.2);
76+
}
77+
}
78+
}
79+
80+
.border_countries {
81+
margin-top: 50px;
82+
display: flex;
83+
}
84+
85+
.borderCountriesWrapper {
86+
display: flex;
87+
flex-wrap: wrap;
88+
gap: 10px;
89+
90+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import { CountriesApi } from 'api'
2+
import classNames from 'classnames'
3+
import { ICountryInfo, ICurrencies } from 'components'
4+
import { FC, useEffect, useState } from 'react'
5+
import { Link } from 'react-router-dom'
6+
import classes from './CountryInfo.module.scss'
7+
8+
interface Props {
9+
country: ICountryInfo
10+
}
11+
12+
const placeObjectFieldsInArray = (object: object): Array<string> => {
13+
let array: Array<string> = []
14+
15+
if (object) {
16+
Object.entries(object).forEach(([, value]) => array.push(value))
17+
}
18+
19+
return array
20+
}
21+
22+
const getFormattedCurrencies = (currencies: object): Array<string> => {
23+
let array: Array<string> = []
24+
Object.entries(currencies).forEach(([, currency]: [string, ICurrencies]) => {
25+
array.push(currency.name)
26+
})
27+
return array
28+
}
29+
30+
export const CountryInfo: FC<Props> = ({ country }): JSX.Element => {
31+
console.log(country)
32+
const [borderCounries, setBorderCountries] = useState<Array<ICountryInfo>>([])
33+
const languages: Array<string> = placeObjectFieldsInArray(country.languages)
34+
const currencies = getFormattedCurrencies(country.currencies)
35+
36+
useEffect(() => {
37+
CountriesApi.getCountriesByAlfaCode(country.borders, { fields: 'name' }).then(response => {
38+
setBorderCountries(response.data)
39+
})
40+
}, [country])
41+
42+
return (
43+
<div className={classes.root}>
44+
<img src={country.flags.svg} alt={`flag: ${country.name.common}`} className={classes.flag} />
45+
<div className={classes.info}>
46+
<h2 className={classes.name}>{country.name.common}</h2>
47+
<div className={classes.stats}>
48+
<div className={classes.stats_col}>
49+
<div className={classes.stats_row}>
50+
<span className={classes.description}>Native Name:</span>
51+
<span className={classes.value}>{country.name.official}</span>
52+
</div>
53+
<div className={classes.stats_row}>
54+
<span className={classes.description}>Population:</span>
55+
<span className={classes.value}>{country.population}</span>
56+
</div>
57+
<div className={classes.stats_row}>
58+
<span className={classes.description}>Region:</span>
59+
<span className={classes.value}>{country.region}</span>
60+
</div>
61+
<div className={classes.stats_row}>
62+
<span className={classes.description}>Sub Region:</span>
63+
<span className={classes.value}>{country.subregion}</span>
64+
</div>
65+
<div className={classes.stats_row}>
66+
<span className={classes.description}>Capital:</span>
67+
<span className={classes.value}>{country.capital}</span>
68+
</div>
69+
</div>
70+
<div className={classes.stats_col}>
71+
<div className={classes.stats_row}>
72+
<span className={classes.description}>Top Level Domain:</span>
73+
<span className={classes.value}>{country.tld.join(', ')}</span>
74+
</div>
75+
<div className={classes.stats_row}>
76+
<span className={classes.description}>Currencies:</span>
77+
<span className={classes.value}>{currencies.join(', ')}</span>
78+
</div>
79+
<div className={classes.stats_row}>
80+
<span className={classes.description}>Languages:</span>
81+
<span className={classes.value}>{languages.join(', ')}</span>
82+
</div>
83+
</div>
84+
</div>
85+
<div className={classes.border_countries}>
86+
<span className={classNames(classes.description, classes.descriptionBorderCountries)}>
87+
Border Countries:
88+
</span>
89+
<div className={classes.borderCountriesWrapper}>
90+
{country.borders.length !== 0 ? (
91+
borderCounries.map(borderCountry => (
92+
<Link
93+
className={classes.buttonBorderCountry}
94+
key={borderCountry.name.common}
95+
to={`/${borderCountry.name.common.toLowerCase()}`}
96+
>
97+
{borderCountry.name.common}
98+
</Link>
99+
))
100+
) : (
101+
<span className={classes.valueBorderCountries}>No border countries</span>
102+
)}
103+
</div>
104+
</div>
105+
</div>
106+
</div>
107+
)
108+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { CountryInfo as default } from './CountryInfo'

src/components/CoutriyList/CountryList.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ export const CountriesList: FC = (): JSX.Element => {
99
const { filter } = useContext(FilterContext)
1010

1111
useEffect(() => {
12-
CountriesApi.fetchCountryCards(filter).then(response => {
13-
setCountries(response.data)
14-
})
12+
CountriesApi.getCountries(filter, { fields: 'name,population,region,capital,flags' }).then(
13+
response => {
14+
setCountries(response.data)
15+
}
16+
)
1517
}, [filter])
1618

1719
return (

src/components/Header/Header.module.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
}
1313

1414
.logo {
15+
color: black;
1516
font-size: 24px;
1617
font-weight: 600;
18+
text-decoration: none;
1719
}
1820

1921
.themeMode {

src/components/Header/Header.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
import { Container } from 'components'
22
import React, { FC } from 'react'
3+
import { Link } from 'react-router-dom'
34
import classes from './Header.module.scss'
45

56
export const Header: FC = (): JSX.Element => {
67
return (
78
<div className={classes.header}>
89
<Container>
910
<div className={classes.inner}>
10-
<h1 className={classes.logo}>Where in the world?</h1>
11+
<Link to={'/'} className={classes.logo}>
12+
Where in the world?
13+
</Link>
14+
1115
<div className={classes.themeMode}>Dark Mode</div>
1216
</div>
1317
</Container>

src/components/index.d.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,24 @@ export interface ICountryCard {
66
region: string
77
}
88

9+
export interface ICountryInfo extends ICountryCard {
10+
name: {
11+
common: string
12+
official: string
13+
}
14+
tld: Array<string>
15+
currencies: {
16+
[key: string]: ICurrencies
17+
}
18+
subregion: string
19+
languages: {
20+
[key: string]: string
21+
}
22+
borders: Array<string>
23+
area: number
24+
}
25+
26+
export interface ICurrencies {
27+
name: string
28+
symbol: string
29+
}

0 commit comments

Comments
 (0)