Skip to content

Commit 8b6e367

Browse files
committed
done Tours
1 parent 3f23325 commit 8b6e367

File tree

7 files changed

+121
-5
lines changed

7 files changed

+121
-5
lines changed

eslint.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export default [
3030
...reactHooks.configs.recommended.rules,
3131
"react/jsx-no-target-blank": "off",
3232
"react/prop-types": "off",
33+
"no-unused-vars": ["warn"],
3334
"react-refresh/only-export-components": [
3435
"warn",
3536
{ allowConstantExport: true },

src/App.jsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { RouterProvider } from "react-router-dom";
22

3-
import router from "../routes/router";
3+
import router from "./routes/router";
44

55
function App() {
66
return (

src/challanges/02-tours/Loading.jsx

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default function Loading() {
2+
return (
3+
<div className="bg-blue-50 min-h-screen py-14 px-10">
4+
<h1 className="text-4xl font-bold my-28 text-center">Loading...</h1>
5+
</div>
6+
);
7+
}

src/challanges/02-tours/Tour.jsx

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { useState } from "react";
2+
3+
export default function Tour({ id, name, info, image, price, handleDelete }) {
4+
const [readMore, setReadMore] = useState(true);
5+
6+
return (
7+
<div className="flex flex-col bg-white rounded-lg shadow-2xl overflow-hidden relative">
8+
<img className="h-60 object-cover" src={image} alt={`name-${name}`} />
9+
<div className="p-8 ">
10+
<h2 className="font-bold text-l text-zinc-800 tracking-widest mb-4">
11+
{name}
12+
</h2>
13+
<p className="text-gray-500 mb-4">
14+
{readMore ? <span>{info.slice(0, 200)}... </span> : info}
15+
<button
16+
onClick={() => setReadMore(!readMore)}
17+
className="text-blue-500"
18+
>
19+
{readMore ? "Read more" : "Show less"}
20+
</button>
21+
</p>
22+
<button
23+
className="border block border-red-800 text-red-800 rounded p-2 w-full cursor-pointer font-medium"
24+
onClick={() => handleDelete(id)}
25+
>
26+
Not Interested
27+
</button>
28+
</div>
29+
<span className="absolute top-0 right-0 bg-blue-100 text-blue-600 rounded-bl-lg p-3">
30+
{price} $
31+
</span>
32+
</div>
33+
);
34+
}

src/challanges/02-tours/Tours.jsx

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { useEffect, useState } from "react";
2+
import Loading from "./Loading";
3+
import Tour from "./Tour";
4+
5+
const url = "https://course-api.com/react-tours-project";
6+
7+
const backgroundClass = "bg-blue-50 min-h-screen py-14 px-10";
8+
9+
export default function Tours() {
10+
const [dataTours, setDataTours] = useState([]);
11+
const [loading, setLoading] = useState(false);
12+
13+
const handleDelete = (id) => {
14+
const data = dataTours.filter((item) => item.id !== id);
15+
setDataTours(data);
16+
};
17+
const fetchTours = async () => {
18+
setLoading(true);
19+
try {
20+
const res = await fetch(url);
21+
const data = await res.json();
22+
setDataTours(data);
23+
setLoading(false);
24+
console.log("data", data);
25+
26+
return data;
27+
} catch (error) {
28+
console.error(error.message);
29+
setLoading(false);
30+
}
31+
};
32+
33+
useEffect(() => {
34+
fetchTours();
35+
}, []);
36+
37+
if (loading) return <Loading />;
38+
39+
if (dataTours.length === 0)
40+
return (
41+
<div className={backgroundClass}>
42+
<div className="my-20 mx-auto w-52">
43+
<p className="text-3xl font-bold text-gray-800 mb-4">No Tours Left</p>
44+
<button
45+
className="p-1 rounded-md text-white bg-blue-400 font-bold cursor-pointer"
46+
onClick={fetchTours}
47+
>
48+
Refresh
49+
</button>
50+
</div>
51+
</div>
52+
);
53+
54+
return (
55+
<div className={backgroundClass}>
56+
<h1 className="text-gray-800 text-4xl font-bold text-center mb-20 relative before:content-[''] before:absolute before:-bottom-4 before:left-0 before:right-0 before:mx-auto before:w-1/10 before:h-1 before:bg-blue-400">
57+
Our Tours
58+
</h1>
59+
<div className="grid grid-cols-3 gap-5">
60+
{dataTours.map((tour) => (
61+
<Tour key={tour.id} {...tour} handleDelete={handleDelete} />
62+
))}
63+
</div>
64+
</div>
65+
);
66+
}

routes/router.jsx renamed to src/routes/router.jsx

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { createBrowserRouter } from "react-router-dom";
2-
import BirthdayReminder from "../src/challanges/01-birthday-reminder/BirthdayReminder";
3-
import Home from "../src/sections/home/Home";
2+
import Home from "../sections/home/Home";
3+
import BirthdayReminder from "../challanges/01-birthday-reminder/BirthdayReminder";
4+
import Tours from "../challanges/02-tours/Tours";
45

56
const router = createBrowserRouter([
67
{
@@ -11,6 +12,10 @@ const router = createBrowserRouter([
1112
path: "/birthday",
1213
element: <BirthdayReminder />,
1314
},
15+
{
16+
path: "/tours",
17+
element: <Tours />,
18+
},
1419
]);
1520

1621
export default router;

src/sections/home/Home.jsx

+5-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@ import { Link } from "react-router-dom";
22

33
export default function Home() {
44
return (
5-
<>
5+
<div className="flex flex-col gap-3">
66
<Link to="/birthday" className="underline text-blue-500">
77
Birthday reminder
88
</Link>
9-
</>
9+
<Link to="/tours" className="underline text-blue-500">
10+
Tours
11+
</Link>
12+
</div>
1013
);
1114
}

0 commit comments

Comments
 (0)