Skip to content

Commit 041e2a1

Browse files
committed
Completed exercise jonasschmedtmann#12: Atomic Blog in section 18 of the course
1 parent bc30e4a commit 041e2a1

File tree

16 files changed

+492
-95
lines changed

16 files changed

+492
-95
lines changed

11-worldwise/starter/data/cities.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,42 @@
3535
"lng": 13.376933665713324
3636
},
3737
"id": 98443197
38+
},
39+
{
40+
"cityName": "Lisbon",
41+
"country": "Portugal",
42+
"emoji": "🇵🇹",
43+
"date": "2027-10-31T15:59:59.138Z",
44+
"notes": "My favorite city so far!",
45+
"position": {
46+
"lat": 38.727881642324164,
47+
"lng": -9.140900099907554
48+
},
49+
"id": 73930382
50+
},
51+
{
52+
"cityName": "Madrid",
53+
"country": "Spain",
54+
"emoji": "🇪🇸",
55+
"date": "2027-07-15T08:22:53.976Z",
56+
"notes": "",
57+
"position": {
58+
"lat": 40.46635901755316,
59+
"lng": -3.7133789062500004
60+
},
61+
"id": 17806752
62+
},
63+
{
64+
"cityName": "Berlin",
65+
"country": "Germany",
66+
"emoji": "🇩🇪",
67+
"date": "2027-02-12T09:24:11.863Z",
68+
"notes": "Amazing 😃",
69+
"position": {
70+
"lat": 52.53586782505711,
71+
"lng": 13.376933665713324
72+
},
73+
"id": 98443192
3874
}
3975
]
4076
}

11-worldwise/starter/src/App.jsx

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1-
import { BrowserRouter, Route, Routes } from "react-router-dom";
1+
import { useEffect, useState } from "react";
2+
import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom";
3+
24
import Homepage from "./pages/Homepage/Homepage";
35
import Products from "./pages/Product/Products";
46
import Pricing from "./pages/Product/Pricing";
57
import Login from "./pages/Login/Login";
68
import AppLayout from "./pages/AppLayout/AppLayout";
79
import PageNotFound from "./pages/PageNotFound";
810
import CityList from "./components/City/CityList";
9-
import { useEffect, useState } from "react";
11+
import CountryList from "./components/Country/CountryList";
12+
import City from "./components/City/City";
13+
import Form from "./components/Form/Form";
1014

1115
const BASE_URL = "http://localhost:9000";
1216

@@ -35,20 +39,21 @@ const App = () => {
3539
<BrowserRouter>
3640
<Routes>
3741
<Route index element={<Homepage />} />
38-
<Route path="/products" element={<Products />} />
39-
<Route path="/pricing" element={<Pricing />} />
40-
<Route path="/login" element={<Login />} />
41-
<Route path="/app" element={<AppLayout />}>
42+
<Route path="products" element={<Products />} />
43+
<Route path="pricing" element={<Pricing />} />
44+
<Route path="login" element={<Login />} />
45+
<Route path="app" element={<AppLayout />}>
46+
<Route index element={<Navigate replace to="cities" />} />
4247
<Route
43-
index
48+
path="cities"
4449
element={<CityList cities={cities} isLoading={isLoading} />}
4550
/>
51+
<Route path="cities/:id" element={<City />} />
4652
<Route
47-
path="cities"
48-
element={<CityList cities={cities} isLoading={isLoading} />}
53+
path="countries"
54+
element={<CountryList cities={cities} isLoading={isLoading} />}
4955
/>
50-
<Route path="countries" element={<p>Countries</p>} />
51-
<Route path="form" element={<p>Form</p>} />
56+
<Route path="form" element={<Form />} />
5257
</Route>
5358
<Route path="*" element={<PageNotFound />} />
5459
</Routes>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import styles from "./Button.module.css";
2+
3+
function Button({ children, onClick, type }) {
4+
return (
5+
<button onClick={onClick} className={`${styles.btn} ${styles[type]}`}>
6+
{children}
7+
</button>
8+
);
9+
}
10+
11+
export default Button;
Lines changed: 60 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,21 @@
1+
import { useParams, useSearchParams } from "react-router-dom";
12
import styles from "./City.module.css";
23

4+
const formatDate = (date) =>
5+
new Intl.DateTimeFormat("en", {
6+
day: "numeric",
7+
month: "long",
8+
year: "numeric",
9+
weekday: "long",
10+
}).format(new Date(date));
11+
312
function City() {
13+
const [searchParams, setSearchParams] = useSearchParams();
14+
const { id } = useParams();
15+
16+
const lat = searchParams.get("lat");
17+
const lng = searchParams.get("lng");
18+
419
// TEMP DATA
520
const currentCity = {
621
cityName: "Lisbon",
@@ -12,42 +27,52 @@ function City() {
1227
const { cityName, emoji, date, notes } = currentCity;
1328

1429
return (
15-
<div className={styles.city}>
16-
<div className={styles.row}>
17-
<h6>City name</h6>
18-
<h3>
19-
<span>{emoji}</span> {cityName}
20-
</h3>
21-
</div>
22-
23-
<div className={styles.row}>
24-
<h6>You went to {cityName} on</h6>
25-
<p>{formatDate(date || null)}</p>
26-
</div>
27-
28-
{notes && (
29-
<div className={styles.row}>
30-
<h6>Your notes</h6>
31-
<p>{notes}</p>
32-
</div>
33-
)}
34-
35-
<div className={styles.row}>
36-
<h6>Learn more</h6>
37-
<a
38-
href={`https://en.wikipedia.org/wiki/${cityName}`}
39-
target="_blank"
40-
rel="noreferrer"
41-
>
42-
Check out {cityName} on Wikipedia &rarr;
43-
</a>
44-
</div>
45-
46-
<div>
47-
<ButtonBack />
48-
</div>
49-
</div>
30+
<>
31+
<h1>City {id}</h1>
32+
<p>
33+
Position : {lat}, {lng}
34+
</p>
35+
<button onClick={() => setSearchParams({ lat: "12", lng: "190" })}>
36+
Change
37+
</button>
38+
</>
5039
);
40+
41+
// return (
42+
// <div className={styles.city}>
43+
// <div className={styles.row}>
44+
// <h6>City name</h6>
45+
// <h3>
46+
// <span>{emoji}</span> {cityName}
47+
// </h3>
48+
// </div>
49+
50+
// <div className={styles.row}>
51+
// <h6>You went to {cityName} on</h6>
52+
// <p>{formatDate(date || null)}</p>
53+
// </div>
54+
55+
// {notes && (
56+
// <div className={styles.row}>
57+
// <h6>Your notes</h6>
58+
// <p>{notes}</p>
59+
// </div>
60+
// )}
61+
62+
// <div className={styles.row}>
63+
// <h6>Learn more</h6>
64+
// <a
65+
// href={`https://en.wikipedia.org/wiki/${cityName}`}
66+
// target="_blank"
67+
// rel="noreferrer"
68+
// >
69+
// Check out {cityName} on Wikipedia &rarr;
70+
// </a>
71+
// </div>
72+
73+
// <div></div>
74+
// </div>
75+
// );
5176
}
5277

5378
export default City;

11-worldwise/starter/src/components/City/City.module.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
max-height: 70%;
44
background-color: var(--color-dark--2);
55
border-radius: 7px;
6-
overflow: scroll;
6+
overflow: auto;
77

88
width: 100%;
99
display: flex;

11-worldwise/starter/src/components/City/CityItem.jsx

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Link } from "react-router-dom";
12
import styles from "./CityItem.module.css";
23

34
const formatDate = (date) =>
@@ -9,14 +10,19 @@ const formatDate = (date) =>
910
}).format(new Date(date));
1011

1112
function CityItem({ city }) {
12-
const { cityName, emoji, date } = city;
13+
const { cityName, emoji, date, id, position } = city;
1314

1415
return (
15-
<li className={styles.cityItem}>
16-
<span className={styles.emoji}>{emoji}</span>
17-
<h3 className={styles.name}>{cityName}</h3>
18-
<time className={styles.date}>({formatDate(date)})</time>
19-
<button className={styles.deleteBtn}>&times;</button>
16+
<li>
17+
<Link
18+
to={`${id}?lat=${position.lat}&lng=${position.lng}`}
19+
className={styles.cityItem}
20+
>
21+
<span className={styles.emoji}>{emoji}</span>
22+
<h3 className={styles.name}>{cityName}</h3>
23+
<time className={styles.date}>({formatDate(date)})</time>
24+
<button className={styles.deleteBtn}>&times;</button>
25+
</Link>
2026
</li>
2127
);
2228
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import Message from "../Message/Message";
2+
import Spinner from "../Spinner/Spinner";
3+
import CountryItem from "./CountryItem";
4+
import styles from "./CountryList.module.css";
5+
6+
const CountryList = ({ cities, isLoading }) => {
7+
if (isLoading) return <Spinner />;
8+
9+
if (!cities.length)
10+
return (
11+
<Message message="Add your first city by clicking on a city on the map" />
12+
);
13+
14+
const countries = cities.reduce((arr, city) => {
15+
if (!arr.map((el) => el.country).includes(city.country))
16+
return [...arr, { country: city.country, emoji: city.emoji }];
17+
else return arr;
18+
}, []);
19+
20+
return (
21+
<ul className={styles.countryList}>
22+
{countries.map((country) => (
23+
<CountryItem country={country} key={country.country} />
24+
))}
25+
</ul>
26+
);
27+
};
28+
29+
export default CountryList;

11-worldwise/starter/src/components/Country/CountryList.module.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
width: 100%;
33
height: 65vh;
44
list-style: none;
5-
overflow-y: scroll;
5+
overflow-y: auto;
66
overflow-x: hidden;
77

88
display: grid;

11-worldwise/starter/src/components/Form/Form.jsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import { useState } from "react";
44

55
import styles from "./Form.module.css";
6+
import Button from "../Button/Button";
7+
import { useNavigate } from "react-router-dom";
68

79
export function convertToEmoji(countryCode) {
810
const codePoints = countryCode
@@ -13,6 +15,8 @@ export function convertToEmoji(countryCode) {
1315
}
1416

1517
function Form() {
18+
const navigate = useNavigate();
19+
1620
const [cityName, setCityName] = useState("");
1721
const [country, setCountry] = useState("");
1822
const [date, setDate] = useState(new Date());
@@ -49,8 +53,16 @@ function Form() {
4953
</div>
5054

5155
<div className={styles.buttons}>
52-
<button>Add</button>
53-
<button>&larr; Back</button>
56+
<Button type="primary">Add</Button>
57+
<Button
58+
type="back"
59+
onClick={(e) => {
60+
e.preventDefault();
61+
navigate(-1);
62+
}}
63+
>
64+
&larr; Back
65+
</Button>
5466
</div>
5567
</form>
5668
);
Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
1+
import { useNavigate, useSearchParams } from "react-router-dom";
12
import styles from "./Map.module.css";
23

34
const Map = () => {
4-
return <div className={styles.mapContainer}>Map</div>;
5+
const navigate = useNavigate();
6+
7+
const [searchParams, setSearchParams] = useSearchParams();
8+
9+
const lat = searchParams.get("lat");
10+
const lng = searchParams.get("lng");
11+
12+
return (
13+
<div className={styles.mapContainer} onClick={() => navigate("form")}>
14+
<h1>Map</h1>
15+
<h2>
16+
Position : {lat}, {lng}
17+
</h2>
18+
</div>
19+
);
520
};
621

722
export default Map;

0 commit comments

Comments
 (0)