diff --git a/src/App.jsx b/src/App.jsx
index e315ba4..80dd842 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -1,9 +1,9 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
-import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
+import { Route, createBrowserRouter, createRoutesFromElements, RouterProvider } from "react-router-dom";
import { Home } from './pages/Home';
import { About } from './pages/About';
-import { Vans } from './pages/vans/Vans';
+import { Vans , loader as vanLoader } from './pages/vans/Vans';
import { VanDetail } from './pages/vans/VanDetail';
import { Layout } from './components/Layout';
import { HostLayout } from './components/HostLayout';
@@ -15,33 +15,41 @@ import { HostVanDetail } from './pages/host/HostVanDetail';
import { HostVanInfo } from './pages/host/HostVanInfo';
import { HostVanPrice } from './pages/host/HostVanPrice';
import { HostVanPhoto } from './pages/host/HostVanPhoto';
+import { NotFound } from './pages/NotFound';
+import { Error } from './components/Error';
-export const App =()=>{
- return(
-
-
- }>
- } />
- } />
- } />
- } />
- } >
- } />
- } />
- } />
- } />
+const router = createBrowserRouter(createRoutesFromElements(
+ }>
+ } />
+ } />
+ }
+ loader={vanLoader}
+ errorElement={}
+ />
+ } />
+
+ } >
+ } />
+ } />
+ } />
+ } />
- } >
- } />
- } />
- } />
-
+ } >
+ } />
+ } />
+ } />
+
-
+
+ } />
+
+))
-
-
-
+export const App =()=>{
+ return(
+
)
}
diff --git a/src/api.js b/src/api.js
new file mode 100644
index 0000000..24df5f1
--- /dev/null
+++ b/src/api.js
@@ -0,0 +1,13 @@
+export async function getVans(){
+ const res = await fetch('/api/vans');
+ if (!res.ok) {
+ throw {
+ message: "Failed to fetch vans",
+ statusText: res.statusText,
+ status: res.status
+ }
+ }
+ const data = await res.json();
+ return data.vans;
+}
+
diff --git a/src/components/Error.jsx b/src/components/Error.jsx
new file mode 100644
index 0000000..f3f3fbc
--- /dev/null
+++ b/src/components/Error.jsx
@@ -0,0 +1,14 @@
+import React from "react";
+import { ReactDOM } from "react-dom/client";
+import { useRouteError } from "react-router-dom";
+
+export const Error = ()=>{
+ const error = useRouteError();
+ console.log(error)
+ return (
+ <>
+
Error: {error.message}
+ {error.status} - {error.statusText}
+ >
+ )
+}
diff --git a/src/components/Footer.jsx b/src/components/Footer.jsx
index 20a918d..3c9dea6 100644
--- a/src/components/Footer.jsx
+++ b/src/components/Footer.jsx
@@ -4,7 +4,7 @@ import ReactDOM from 'react-dom/client';
export const Footer = ()=>{
return(
<>
-
+
>
)
}
diff --git a/src/components/Layout.jsx b/src/components/Layout.jsx
index efdbe4c..9c14fcc 100644
--- a/src/components/Layout.jsx
+++ b/src/components/Layout.jsx
@@ -8,9 +8,7 @@ export const Layout = ()=>{
return (
<>
-
-
-
+
>
)
diff --git a/src/index.css b/src/index.css
index b374ef1..1cea216 100644
--- a/src/index.css
+++ b/src/index.css
@@ -5,8 +5,6 @@
html,body{
background-color: #FFF7ED;
font-family: "Inter", sans-serif;
- display: flex;
- flex-direction: column;
}
header {
display: flex;
@@ -162,6 +160,16 @@ ul a:hover {
padding-inline: 23px;
}
+.van-list-filter-buttons {
+ display: flex;
+ flex-wrap: wrap;
+}
+
+.van-list-filter-buttons > a {
+ margin-right: 15px;
+ text-decoration: none;
+}
+
.van-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(400px, 1fr)); /* Responsive grid columns */
@@ -273,6 +281,7 @@ i[class*='van-type-'] {
max-width: 800px;
margin: auto;
padding: 40px;
+ margin-bottom: 27px;
background-color: #f9f9f9;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
@@ -468,8 +477,8 @@ footer {
display: block;
color: black;
text-decoration: none;
- margin-top: 60px;
- margin-left: 26px;
+ margin-left: 6px;
+ padding-bottom: 20px;
}
.back-button span:hover {
@@ -535,6 +544,32 @@ section.host-van-detail-info {
margin-left: 14px;
}
+/* Not Found CSS */
+
+.not-found-container {
+ padding-inline: 26px;
+ height: 80vh;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ text-align: center;
+ flex-direction: column;
+}
+
+.not-found-container .link-button {
+ background-color: #161616;
+ display: block;
+ color: white;
+ padding: 12px;
+ text-decoration: none;
+ border-radius: 9px;
+}
+
+.not-found-h1{
+ display: block;
+ margin-bottom: 16px;
+}
+
/* Responsive CSS */
@media screen and (max-width: 760px) {
diff --git a/src/pages/NotFound.jsx b/src/pages/NotFound.jsx
new file mode 100644
index 0000000..4c916b8
--- /dev/null
+++ b/src/pages/NotFound.jsx
@@ -0,0 +1,13 @@
+import React from 'react'
+import ReactDOM from 'react-dom/client'
+import { Link } from "react-router-dom";
+
+export const NotFound = ()=>{
+ return (
+
+
Sorry, the page you were looking for was not found.
+ Return to Home
+
+ )
+}
+
diff --git a/src/pages/host/HostVans.jsx b/src/pages/host/HostVans.jsx
index fcd7cc8..6d520c5 100644
--- a/src/pages/host/HostVans.jsx
+++ b/src/pages/host/HostVans.jsx
@@ -14,7 +14,7 @@ export const HostVans = ()=>{
const vanListElement = vansList.map((van)=>{
return
diff --git a/src/pages/vans/VanDetail.jsx b/src/pages/vans/VanDetail.jsx
index f61771a..006c9a4 100644
--- a/src/pages/vans/VanDetail.jsx
+++ b/src/pages/vans/VanDetail.jsx
@@ -1,10 +1,11 @@
import React, { useEffect, useState } from 'react';
-import { useParams } from 'react-router-dom';
+import { useParams,Link,useLocation } from 'react-router-dom';
import ReactDOM from 'react-dom/client';
export const VanDetail = ()=>{
const params = useParams();
- const [van, setVan] = React.useState(null)
+ const [van, setVan] = React.useState(null);
+ const location = useLocation();
useEffect(()=>{
fetch(`/api/vans/${params.id}`)
@@ -14,6 +15,12 @@ export const VanDetail = ()=>{
return (
+
←
Back to all {location.state.type} vans
+
{van ? (
![]({van.imageUrl})
diff --git a/src/pages/vans/Vans.jsx b/src/pages/vans/Vans.jsx
index 2031267..de3b247 100644
--- a/src/pages/vans/Vans.jsx
+++ b/src/pages/vans/Vans.jsx
@@ -1,18 +1,32 @@
import React, { useEffect, useState } from 'react';
import ReactDOM from 'react-dom/client';
-import { Link } from 'react-router-dom'
+import { Link,useLoaderData,useSearchParams } from 'react-router-dom';
+import { getVans } from '../../api';
+
+export function loader(){
+ return getVans();
+}
export const Vans = () =>{
- const [vans, setVans] = React.useState([])
- React.useEffect(() => {
- fetch("/api/vans")
- .then(res => res.json())
- .then(data => setVans(data.vans))
- }, [])
-
- const vanElements = vans.map(van => (
+ const [searchParams , setSearchParams] = useSearchParams();
+ const typeFilter = searchParams.get("type");
+ const [loading,setLoading] = React.useState(false);
+ const [error,setError] = React.useState(null);
+ const vans = useLoaderData();
+
+ const filteredVans = typeFilter ? vans.filter(van => van.type === typeFilter) : vans;
+
+ const vanElements = filteredVans.map(van => (
-
+
{van.name}
@@ -23,11 +37,52 @@ export const Vans = () =>{
))
+ function handleFilterChange(key,val){
+ setSearchParams(prevParams =>{
+ if(val == null){
+ prevParams.delete(key);
+ }else{
+ prevParams.set(key,val);
+ }
+ })
+ }
+
+ if(error){
+ return
There was an error : {error.message}
+ }
+
return (
Explore our van options
+
+
+
+
+ {typeFilter && }
+
- {vans.length ? vanElements :
Loading...
}
+ {vanElements}
)