Skip to content

Commit

Permalink
Added Loaders
Browse files Browse the repository at this point in the history
  • Loading branch information
Adi-204 committed Dec 22, 2023
1 parent 797d7bc commit c65d5dd
Show file tree
Hide file tree
Showing 10 changed files with 190 additions and 47 deletions.
58 changes: 33 additions & 25 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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(
<BrowserRouter>
<Routes>
<Route path='/' element = {<Layout />}>
<Route index element = {<Home />} />
<Route path='about' element = {<About />} />
<Route path='vans' element = {<Vans />} />
<Route path='vans/:id' element = {<VanDetail />} />

<Route path='/host' element = {<HostLayout />} >
<Route index element = {<Dashboard />} />
<Route path='income' element = {<Income />} />
<Route path='reviews' element = {<Review />} />
<Route path='vans' element={<HostVans />} />
const router = createBrowserRouter(createRoutesFromElements(
<Route path='/' element = {<Layout />}>
<Route index element = {<Home />} />
<Route path='about' element = {<About />} />
<Route
path='vans'
element = {<Vans />}
loader={vanLoader}
errorElement={<Error />}
/>
<Route path='vans/:id' element = {<VanDetail />} />

<Route path='/host' element = {<HostLayout />} >
<Route index element = {<Dashboard />} />
<Route path='income' element = {<Income />} />
<Route path='reviews' element = {<Review />} />
<Route path='vans' element={<HostVans />} />

<Route path='vans/:id' element={<HostVanDetail />} >
<Route index element = {<HostVanInfo />} />
<Route path='pricing' element = {<HostVanPrice />} />
<Route path='photos' element = {<HostVanPhoto />} />
</Route>
<Route path='vans/:id' element={<HostVanDetail />} >
<Route index element = {<HostVanInfo />} />
<Route path='pricing' element = {<HostVanPrice />} />
<Route path='photos' element = {<HostVanPhoto />} />
</Route>

</Route>
</Route>
<Route path='*' element = {<NotFound />} />
</Route>
))

</Route>
</Routes>
</BrowserRouter>
export const App =()=>{
return(
<RouterProvider router={router} />
)
}
13 changes: 13 additions & 0 deletions src/api.js
Original file line number Diff line number Diff line change
@@ -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;
}

14 changes: 14 additions & 0 deletions src/components/Error.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<>
<h1>Error: {error.message}</h1>
<pre>{error.status} - {error.statusText}</pre>
</>
)
}
2 changes: 1 addition & 1 deletion src/components/Footer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import ReactDOM from 'react-dom/client';
export const Footer = ()=>{
return(
<>
<footer>&#169; 2022 #VANLIFE</footer>
<footer>&#169; 2023 #VANLIFE</footer>
</>
)
}
4 changes: 1 addition & 3 deletions src/components/Layout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ export const Layout = ()=>{
return (
<>
<Header />
<main>
<Outlet />
</main>
<Outlet />
<Footer />
</>
)
Expand Down
43 changes: 39 additions & 4 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
html,body{
background-color: #FFF7ED;
font-family: "Inter", sans-serif;
display: flex;
flex-direction: column;
}
header {
display: flex;
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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) {
Expand Down
13 changes: 13 additions & 0 deletions src/pages/NotFound.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import { Link } from "react-router-dom";

export const NotFound = ()=>{
return (
<div className="not-found-container">
<h1 className='not-found-h1'>Sorry, the page you were looking for was not found.</h1>
<Link to="/" className="link-button">Return to Home</Link>
</div>
)
}

2 changes: 1 addition & 1 deletion src/pages/host/HostVans.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const HostVans = ()=>{

const vanListElement = vansList.map((van)=>{
return <Link
to={`/host/vans/${van.id}`}
to={`${van.id}`}
key={van.id}
className="host-van-link-wrapper"
>
Expand Down
11 changes: 9 additions & 2 deletions src/pages/vans/VanDetail.jsx
Original file line number Diff line number Diff line change
@@ -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}`)
Expand All @@ -14,6 +15,12 @@ export const VanDetail = ()=>{

return (
<div className="van-detail-container">
<Link
to={location.state ? `/vans/?${location.state.search}` : '' }
relative="path"
className="back-button"
>&larr; <span>Back to all {location.state.type} vans</span>
</Link>
{van ? (
<div className="van-detail">
<img src={van.imageUrl} />
Expand Down
77 changes: 66 additions & 11 deletions src/pages/vans/Vans.jsx
Original file line number Diff line number Diff line change
@@ -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 => (
<div key={van.id} className="van-tile">
<Link to={`/vans/${van.id}`} >
<Link
to={`${van.id}` }
state={
{
search : searchParams.toString(),
type : typeFilter
}
}
>
<img src={van.imageUrl} />
<div className="van-info">
<h3>{van.name}</h3>
Expand All @@ -23,11 +37,52 @@ export const Vans = () =>{
</div>
))

function handleFilterChange(key,val){
setSearchParams(prevParams =>{
if(val == null){
prevParams.delete(key);
}else{
prevParams.set(key,val);
}
})
}

if(error){
return <h1 aria-live='assertive'>There was an error : {error.message}</h1>
}

return (
<div className="van-list-container">
<h1>Explore our van options</h1>
<div className="van-list-filter-buttons">
<button
className={`van-type simple ${typeFilter === 'simple' ? 'selected' : null}`}
onClick={() => handleFilterChange("type","simple")}
>
Simple
</button>
<button
className={`van-type luxury ${typeFilter === 'luxury' ? 'selected' : null}`}
onClick={() => handleFilterChange("type","luxury")}
>
Luxury
</button>
<button
className={`van-type rugged ${typeFilter === 'rugged' ? 'selected' :
null}`}
onClick={() => handleFilterChange("type","rugged")}
>
Rugged
</button>
{typeFilter && <button
className='van-type clear-filters'
onClick={() => handleFilterChange("type",null)}
>
Clear
</button>}
</div>
<div className="van-list">
{vans.length ? vanElements : <h2>Loading...</h2>}
{vanElements}
</div>
</div>
)
Expand Down

0 comments on commit c65d5dd

Please sign in to comment.