8 minutes

Projet d'Hôtel React Pour Débutants

Dernière mise à jour: 4 mai, 2022

Un excellent projet de site Web pour les débutants. Après avoir créé ce projet, vous saurez comment utiliser le routeur de react, créer des routes dynamiques et gérer les formulaires en react. Vous pouvez ajouter ce projet à votre portfolio (après avoir personnalisé et amélioré certaines parties bien sûr).

Eh bien, je suppose que vous avez au moins une certaine connaissance du fonctionnement de la react. Je n'expliquerai donc pas toutes les petites choses que nous allons faire. Sinon ce post serait trop ennuyeux et trop long. Croyez-moi, même si vous ne savez pas grand-chose sur la react, vous pourrez toujours suivre et comprendre le code. Commençons!

§Créez Le Dossier du Projet

Nous allons créer notre projet avec :

npx create-react-app my-hotel-app

Une fois le téléchargement terminé, exécutez :

npx start

commande pour démarrer votre projet. Si tout va bien jusqu'à présent, accédez à localhost:3000 et vous verrez un logo de react en rotation lente.

Notre projet nécessite beaucoup d'images. Vous pouvez aller sur unsplash pour télécharger des images gratuites. Ou vous pouvez simplement visiter le repository et récupérer les images que j'ai utilisées dans mon projet. Nous avons besoin d'images pour notre banner, nos chambres, nos installations (facilities), etc.

Ajoutons maintenant tailwindcss à notre projet. J'aime utiliser tailwindcss dans mes projets, mais si vous préférez une autre façon de gérer le style dans vos projets, allez-y. Mais si vous ne savez pas grand-chose sur tailwindcss, cela pourrait être une bonne occasion de vous mettre un peu au défi.

Exécutez ces commandes dans la console pour télécharger tailwindcss postcss et autoprefixer en tant que dépendances de développement :

npm install -D tailwindcss postcss autoprefixer npx tailwindcss init -p

Ces commandes créeront un fichier "tailwind.config.js" à la racine (root) de votre projet. Modifiez maintenant les configurations comme suit :

module.exports = { content: [ "./src/**/*.{js,jsx,ts,tsx}", ], theme: { extend: {}, }, plugins: [], }

Dans le fichier src/index.css, ajoutez les lignes suivantes en haut:

@tailwind base; @tailwind components; @tailwind utilities;

Nous pouvons maintenant utiliser tailwindcss dans notre projet. Vous pouvez consulter vous-même la page officielle ici si vous le souhaitez.

Effacez tout ce qui se trouve dans le fichier src/App.js et commencez à créer le vôtre. Je vais créer un composant fonctionnel (fucntional component) ici. Je trouve les composants fonctionnels un peu plus rapides à créer et j'aime travailler avec des "hooks". Ce fichier sera utilisé pour la gestion du routage. Certains développeurs gardent le routage dans le fichier index.js mais j'aime les séparer de cette façon. Si vous ne les aimez pas, vous pouvez suivre de "class". Allez-y et supprimez également le fichier src/app.css.

Maintenant, gérons le css de base que j'aime toujours ajouter avant de commencer un projet. Tels que "padding : 0, margin : 0, box-sizing : border-box", etc. Comme nous n'aurons pas besoin de modifier les propriétés CSS ici pour le reste de l'article, nous pouvons utiliser le code final ici :

@tailwind base; @tailwind components; @tailwind utilities; html, body { padding: 0; margin: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; display: flex; flex-direction: column; max-width: 100vw; min-height: 100vh; } #root { display: flex; flex-direction: column; min-height: 100vh; } img { width:100%; }

Rendre "#root: flex" nous aide à positionner facilement notre mise en page (layout) dans nos pages. Par exemple, de cette façon, nous pourrions simplement utiliser "margin-top : auto" pour notre pied de page (footer) et notre pied de page apparaîtrait toujours en bas de notre page.

Le reste du style de notre projet est géré à l'aide de tailwindcss, il n'y aura donc plus de fichiers CSS. Encore une fois, mon choix personnel, vous pouvez continuer avec votre propre façon de gérer les CSS.

Nous pouvons créer les pages de base pour tester le routeur et la barre de navigation (navbar) que nous créerons sous peu. Créons maintenant un dossier "pages" dans src. Ici, nous devons créer 5 fichiers. contact.jsx pour les informations de l'hôtel. facilitys.jsx pour toutes les choses intéressantes que notre hôtel a à offrir. home.jsx pour accueillir nos invités bien sûr. fichier rooms.jsx montrant aux clients les options de chambre. room.jsx pour le calcul du prix et la réservation.

Comme nous n'avons pas de backend pour ce projet, nous allons simplement imiter le comportement.

§Routage avec react-router-dom

Au fur et à mesure que vos projets grandissent, vous finissez par utiliser des dizaines de composants (voire des centaines). Cela permet de garder vos projets propres, faciles à lire et il est beaucoup plus facile d'apporter de petites modifications à certaines parties de vos projets.

Nous pouvons installer le package de routeur que nous utiliserons pour gérer le routage dans notre projet avec cette commande :

npm install react-router-dom

Créons maintenant notre barre de navigation. Dans notre dossier src, créez un dossier "components". Nous allons créer tous les composants nécessaires que nous voulons utiliser dans notre projet ici. Créez ici un fichier "Navbar.js". Dans notre barre de navigation au lieu de "a tag", nous devons utiliser "Link" (vous pouvez utiliser Navlink, je ne voulais plus créer de confusion) pour les liens internes. Le lien pour la documentation est ici. Cela vaut vraiment la peine d'être lu si vous voulez travailler avec React à l'avenir. Comme je veux styliser les liens ici, j'ai créé un autre composant appelé NavLink.js dans le dossier des components. C'est très basique et prend "to" comme "prop". "to" déterminera où le lien enverra l'utilisateur qui clique dessus. Il remplace la valeur href dans balise "a".

Le code complet pour NavLink.js est ici:

import React from 'react' import { Link } from 'react-router-dom' const NavLink = ({to}) => { return ( <Link className='font-bold m-1 text-xl uppercase' to={`/${to}`} >{to}</Link> ) } export default NavLink

Comme vous pouvez le voir, rien de trop compliqué, il suffit d'ajouter un peu de style. L'accessoire apparaîtra en majuscule dans la section de texte de cette façon, grâce au style.

Notre code pour Navbar.js est ici :

import React from 'react' import { Link } from 'react-router-dom' import NavLink from './NavLink' const Navbar = () => { return ( <nav className='text-white px-8 py-6 bg-cyan-500 flex flex-row justify-between'> <Link className='font-bold text-2xl' to="/">HOME</Link> <div> <NavLink to="rooms"/> <NavLink to="facilities"/> <NavLink to="contact"/> </div> </nav> ) } export default Navbar

Semble très propre et facile à lire. Chaque page a besoin d'un pied de page (footer) approprié. Nous allons également en ajouter un au nôtre. Et après avoir créé notre pied de page, nous allons créer un composant de mise en page (layout) et emballer nos pages avec.

Pour notre pied de page, dans le dossier des composants, créez un fichier Footer.js. Ce que nous aurons dans ce fichier n'est vraiment que notre nom, nous le gardons basique. Le code complet est ici pour le composant de pied de page (Footer.js) :

import React from 'react' const Footer = () => { return (<> <footer className='mt-auto p-10 bg-gray-400'> <p className='text-center text-white'>Ilker AKBIYIK</p> </footer> </>) } export default Footer

N'hésitez pas à remplacer mon nom ;).

Après avoir créé le pied de page, créez un fichier Layout.js dans le dossier des composants (components) et importez le pied de page et la barre de navigation. Nous utiliserons également "Outlet" du package react-router-dom. L'Outlet déterminera où les composants ou les pages enveloppés apparaîtront dans notre mise en page. Dans cet exemple, nous voulons envelopper nos pages avec notre mise en page (les pages seront sous la barre de navigation et au-dessus du pied de page). Le code du fichier Layout.js est ici :

import React from 'react' import { Outlet } from 'react-router-dom' import Navbar from './Navbar' import Footer from './Footer' const Layout = () => { return (<> <Navbar /> <Outlet /> <Footer /> </>) } export default Layout

Créons maintenant les routes dans notre fichier App.js, qui se trouve dans le dossier src. Au lieu de l'expliquer ici, je vais essayer d'expliquer la fonctionnalité du code dans les commentaires ci-dessous. Vous devez savoir qu'il existe plusieurs façons de gérer le routage dans nos projets de réaction. C'est comme ça que j'ai fait :

import { BrowserRouter, Route, Routes } from 'react-router-dom'; import Layout from './components/Layout'; import Home from './pages/home'; import Facilities from './pages/facilities'; import Contact from './pages/contact'; import Rooms from './pages/rooms'; import Room from './pages/room'; function App() { return ( // nous devons envelopper notre routage avec BrowserRouter <BrowserRouter> <Routes> {/* Tout d'abord, nous emballons toutes nos pages avec notre mise en page de cette façon */} <Route path="/" element={<Layout/>}> {/* La page d'accueil apparaîtra comme index pour le chemin "/" */} {/* the index property is important determining what to serve */} {/* en chemin avec partageant le même nom */} <Route index element={<Home />} /> <Route path="contact" element={<Contact/>} /> <Route path="facilities" element={<Facilities/>} /> <Route path="rooms"> {/* Les regards détaillés et la réservation seront traités dans le */} {/* page appelée pièce et l'url de cette page sera créée */} {/* dynamiquement pour chaque pièce, par exemple, pièce avec l'id de 1 */} {/* se trouvera dans l'url rooms/1 */} <Route path=":id" element={<Room/>} /> {/* et enfin rendre les salles comme index pour /rooms */} <Route index element={<Rooms/>}/> </Route> </Route> </Routes> </BrowserRouter> ); } export default App;

Si tout s'est bien passé jusqu'à ce point, vous devriez pouvoir naviguer en utilisant les boutons de votre barre de navigation ou en écrivant l'URL vers laquelle vous voulez aller directement.

§Saluer Nos Invités

Nous pouvons commencer à rendre notre application un peu meilleure maintenant. Nous allons commencer par télécharger quelques images.

Nous avons besoin d'images pour les chambres, les installations et quelques photos de vue. Allez télécharger quelques images et revenez au projet. Si vous vous sentez trop paresseux, récupérez simplement les images que j'ai dans mon projet depuis le repository.

Ok maintenant, dans le dossier src, créez le dossier "images" et ajoutez les images ici. Si nous avions une base de données pour notre projet, nous obtiendrions nos informations sur les chambres à partir de là. Mais pour ce projet, nous allons simplement imiter ce comportement en créant un fichier et en exportant toutes les données à partir de là. Créez un dossier nommé "db" dans le dossier src. À l'intérieur de la base de données, créez "index.js". Dans ce fichier, nous pouvons créer nos chambres maintenant. Le code complet est ici :

// N'hésitez pas à modifier les informations ici aussi import room1pic from '../images/room1.jpg' import room2pic from '../images/room2.jpg' import room3pic from '../images/room3.jpg' import room4pic from '../images/room4.jpg' import room5pic from '../images/room5.jpg' import room6pic from '../images/room6.jpg' const rooms = [ { id:1, src: room1pic, info:"A cozy room for 2", name:"Twin", people: 2, dailyPrice:100, availableFor: 7 }, { id:2, src: room2pic, info:"A cozy room for 2", name:"Desert", people: 4, dailyPrice:150, availableFor: 10 }, { id:3, src: room3pic, info:"A cozy room for 2", name:"Standard", people: 2, dailyPrice:200, availableFor: 20 }, { id:4, src: room4pic, info:"A cozy room for 2", name:"Villa", people: 4, dailyPrice:100, availableFor: 5 }, { id:5, src: room5pic, info:"A cozy room for 2", name:"Open", people: 2, dailyPrice:50, availableFor: 30 }, { id:6, src: room6pic, info:"A cozy room for 2", name:"Suite", people: 2, dailyPrice:250, availableFor: 14 }, ]; export default rooms

Je voulais ajouter un carrousel cool et simple qui montre les pièces à l'intérieur de notre page d'accueil. J'ai créé le carrousel avec le package "react-responsive-carousel". Installez ce package et dans le dossier des composants (components), créez un fichier "Carousel.js". Dans ce fichier, nous allons gérer notre carrousel. Les données que nous utiliserons dans le carrousel seront acquises à partir de la page d'accueil en tant que prop.

/* eslint-disable jsx-a11y/alt-text */ import React from 'react' import "react-responsive-carousel/lib/styles/carousel.min.css"; // nécessite un chargeur // J'ai dû changer le nom car j'ai aussi nommé mon composant Carousel import { Carousel as C } from 'react-responsive-carousel'; import { Link } from 'react-router-dom'; // Les données seront transmises à ces composants const Carousel = ({rooms}) => { return (<> <C className='m-auto md:w-3/5 sm:w-4/5'> {/* nous allons créer notre carrousel */} {rooms.map(i => { return <div> <img src={i.src} /> <p className="legend">{i.name}</p> </div> })} </C> <Link className='m-auto text-2xl text-cyan-500' to="/rooms"> Choose your room and make your reservation </Link> </>) } export default Carousel

Maintenant que cela est fait, créons un composant pour afficher nos installations sur notre page d'accueil. Dans le dossier du composant, créez le fichier "HomeFacilities.js". Le code de ce composant est très basique. Juste un peu de HTML et de style avec tailwindcss. J'ai transformé l'ensemble du composant en un lien afin qu'à chaque fois qu'un utilisateur clique dessus, il soit envoyé au /facilities, afin qu'il puisse obtenir plus d'informations. Bien sûr, toutes les informations que nous avons ici sont en latin, donc pas très utiles :

import React from 'react' import { Link } from 'react-router-dom' const HomeFacilities = () => { return ( <Link to="/facilities"> <div className='text-white grid grid-cols-2 gap-4 m-auto mb-6 w-11/12'> <h2 className='col-span-full text-center text-4xl my-8 underline font-bold text-cyan-500'>Explore the facilities</h2> <div class="rounded p-8 bg-gradient-to-r from-cyan-500 to-blue-500"> <h3 className='font-bold text-2xl'>POOL</h3> <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati error corrupti exercitationem possimus expedita inventore, dolores amet repellat veniam mollitia, est iure praesentium fuga sit architecto quam neque facilis dolorum!</p> </div> <div class="rounded p-8 bg-gradient-to-r from-sky-500 to-indigo-500"> <h3 className='font-bold text-2xl'>GYM</h3> <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati error corrupti exercitationem possimus expedita inventore, dolores amet repellat veniam mollitia, est iure praesentium fuga sit architecto quam neque facilis dolorum!</p> </div> <div class="rounded p-8 bg-gradient-to-r from-violet-500 to-fuchsia-500"> <h3 className='font-bold text-2xl'>RESTAURANT</h3> <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati error corrupti exercitationem possimus expedita inventore, dolores amet repellat veniam mollitia, est iure praesentium fuga sit architecto quam neque facilis dolorum!</p> </div> <div class="rounded p-8 bg-gradient-to-r from-purple-500 to-pink-500"> <h3 className='font-bold text-2xl'>PRIVATE BEACH</h3> <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati error corrupti exercitationem possimus expedita inventore, dolores amet repellat veniam mollitia, est iure praesentium fuga sit architecto quam neque facilis dolorum!</p> </div> </div> </Link> ) } export default HomeFacilities

Finally our home.jsx page will look like this:

import React from 'react' import Carousel from '../components/Carousel' import HomeFacilities from '../components/HomeFacilities' import beach from '../images/beach.jpg' import { Link } from 'react-router-dom' import rooms from '../db/index'; const Home = () => { return (<> <h1 className='text-center text-6xl font-bold text-cyan-500 underline'>Welcome to Our Super Awesome Hotel</h1> <img className='mt-10 object-cover h-96' src={beach} alt="A beautiful beach" /> <Link to="/rooms"><h2 className='text-center text-4xl my-8 underline font-bold text-cyan-500'>Available Rooms</h2></Link> <Carousel images={rooms} /> <HomeFacilities /> </>) } export default Home

Si tout s'était bien passé jusqu'à ce point, vous devriez voir une page d'accueil avec un carrousel fonctionnel d'images de pièces et un composant pour les installations.

§Impressionnons Nos Invités avec des Installations

Cette page sera très simple. Juste un peu de HTML. Le style est fait en utilisant tailwindcss ici. Si vous avez quelque chose en tête qui, selon vous, rendra la page beaucoup plus utile, ajoutez-le. Je pense que c'est une très bonne pratique d'améliorer tous les projets ou tutoriels que vous voyez en ligne. Cela accélérera votre apprentissage.

Le code complet est ici :

import React from 'react' import pBeach from '../images/pbeach.jpg'; import pool from '../images/pool3.jpg'; import restaurant from '../images/restaurant.jpg'; import spa from '../images/spa.jpg'; import gym from '../images/gym.jpg'; const Facilities = () => { return (<> <div className='text-cyan-500 flex flex-col items-center'> <div className='border-b-2 border-cyan-500 p-2 m-4 w-4/5 gap-4 grid grid-cols-3'> <h2 className='font-bold col-span-3 text-center text-4xl'>POOL</h2> <img className='col-span-3 lg:col-span-2' src={pool} alt="pool pic" /> <p className='text-4xl col-span-3 lg:col-span-1'>Lorem ipsum dolor sit amet consectetur adipisicing elit. Doloribus cupiditate quia dolor perferendis, magnam quod rerum reprehenderit, nostrum temporibus sequi suscipit veniam, ea iste ipsum qui delectus enim autem incidunt.</p> </div> <div className='border-b-2 border-cyan-500 p-2 m-4 w-4/5 gap-4 grid grid-cols-3'> <h2 className='font-bold col-span-3 text-center text-4xl'>GYM</h2> <p className='text-4xl col-span-3 lg:col-span-1'>Lorem ipsum dolor sit amet consectetur adipisicing elit. Doloribus cupiditate quia dolor perferendis, magnam quod rerum reprehenderit, nostrum temporibus sequi suscipit veniam, ea iste ipsum qui delectus enim autem incidunt.</p> <img className='lg:col-span-2 col-span-3' src={gym} alt="" /> </div> <div className='border-b-2 border-cyan-500 p-2 m-4 w-4/5 gap-4 grid grid-cols-3'> <h2 className='font-bold col-span-3 text-center text-4xl'>RESTAURANT</h2> <img className='lg:col-span-2 col-span-3' src={restaurant} alt="pool pic" /> <p className='text-4xl col-span-3 lg:col-span-1'>Lorem ipsum dolor sit amet consectetur adipisicing elit. Doloribus cupiditate quia dolor perferendis, magnam quod rerum reprehenderit, nostrum temporibus sequi suscipit veniam, ea iste ipsum qui delectus enim autem incidunt.</p> </div> <div className='border-b-2 border-cyan-500 p-2 m-4 w-4/5 gap-4 grid grid-cols-3'> <h2 className='font-bold col-span-3 text-center text-4xl'>PRIVATE BEACH</h2> <p className='text-4xl col-span-3 lg:col-span-1'>Lorem ipsum dolor sit amet consectetur adipisicing elit. Doloribus cupiditate quia dolor perferendis, magnam quod rerum reprehenderit, nostrum temporibus sequi suscipit veniam, ea iste ipsum qui delectus enim autem incidunt.</p> <img className='col-span-3 lg:col-span-2' src={pBeach} alt="" /> </div> <div className='border-b-2 border-cyan-500 p-2 m-4 w-4/5 gap-4 grid grid-cols-3'> <h2 className='font-bold col-span-3 text-center text-4xl'>SPA</h2> <img className='col-span-3 lg:col-span-2' src={spa} alt="pool pic" /> <p className='text-4xl col-span-3 lg:col-span-1'>Lorem ipsum dolor sit amet consectetur adipisicing elit. Doloribus cupiditate quia dolor perferendis, magnam quod rerum reprehenderit, nostrum temporibus sequi suscipit veniam, ea iste ipsum qui delectus enim autem incidunt.</p> </div> </div> </>) } export default Facilities

Oui, c'était tout pour la page des installations (facilities).

§Permettez à Vos Invités de Vous Contacter

Nous voulons que nos clients se sentent à l'aise de communiquer avec nous. Nous allons donc ajouter un joli formulaire. Comme nous n'avons aucune logique back-end pour gérer le mailing pour nous (ni une base de données), nous enregistrerons uniquement les informations qui nous sont envoyées et alerterons l'invité avec un message de remerciement. Si vous souhaitez continuer à créer un backend, vous pouvez envoyer un e-mail de confirmation pour remercier les invités de vous avoir contacté automatiquement.

Les commentaires expliqueront les parties qui, à mon avis, peuvent sembler un peu difficiles à comprendre si vous êtes débutant. Le code et son explication sont ici pour la page contact.jsx complète (à l'intérieur de src/pages):

import React, { useState } from 'react' const Contact = () => { // Voici comment l'état (state) est géré dans les composants fonctionnels // Nous initialisons les valeurs que nous utiliserons comme chaînes vides (empty strings) // et les deuxièmes mots clés des tableaux seront utilisés pour les définir // le voir en action ci-dessous sera plus explicatif const [email, setEmail] = useState(""); const [subject, setSubject] = useState(""); const [text, setText] = useState(""); const handleSubmit = (e) => { // empêcher le rechargement e.preventDefault() // alertez le client et enregistrez les informations qui nous sont envoyées alert("merci de nous avoir contacté, nous vous répondrons dans les plus brefs délais."); console.log(email, subject, text) } return (<> {/* lorsque l'utilisateur clique sur soumettre (ou "enter") */} {/* exécutez la fonction handleSubmit avec l'événement comme argument */} <form onSubmit={e => handleSubmit(e)} className='m-auto mb-6 sm:w-4/5 lg:w-3/5'> <div className='mt-2 flex flex-col'> <label htmlFor="f-email" > Your email address: </label> <input // chaque fois que l'entrée change, mettre à jour l'état onChange={(e) => setEmail(e.target.value)} className='rounded p-4 bg-cyan-100' type="email" name="f-email" /> </div> <div className='mt-2 flex flex-col'> <label htmlFor="f-subject"> Subject </label> <input // chaque fois que l'entrée change, mettre à jour l'état onChange={(e) => setSubject(e.target.value)} className='rounded bg-cyan-100 p-4' type="text" name="f-subject" /> </div> <div className='mt-2 flex flex-col'> <label htmlFor="f-text"> What would you like to tell us </label> <textarea // chaque fois que l'entrée change, mettre à jour l'état onChange={(e) => setText(e.target.value)} className='rounded bg-cyan-100 p-4' name="f-text" id="" cols="30" rows="10" ></textarea> </div> <input className='p-4 rounded mt-4 font-bold text-white text-2xl cursor-pointer hover:bg-cyan-700 w-full m-auto bg-cyan-800' type="submit" value="SUBMIT" /> </form> </>) } export default Contact

§Nos Chambres

Notre page qui contient les chambres comprendra un formulaire de base pour filtrer les chambres en fonction de la saisie du formulaire et de tous les détails des chambres. Les utilisateurs peuvent choisir de n'afficher que les pièces qu'ils souhaitent voir. Nous rendrons toutes les pièces lorsqu'il n'y aura pas de critères. Le code complet et les explications des fonctions sont ici :

Notre page qui contient les chambres comprendra un formulaire de base pour filtrer les chambres en fonction de la saisie du formulaire et de tous les détails des chambres. Les utilisateurs peuvent choisir de n'afficher que les chambres qu'ils souhaitent voir. Nous rendrons toutes les chambres lorsqu'il n'y aura pas de critères. Le code complet et les explications des fonctions sont ici :

import React, { useEffect, useState } from 'react'; import { Link } from 'react-router-dom'; import rooms from '../db'; const Rooms = () => { // nog est l'abréviation de "number of guests" const [nog, setNog] = useState(); const [budget, setBudget] = useState(); const [days, setDays] = useState(); // Lorsque le composant est monté, nous rendrons toutes les chambres // et lorsque "filtered" est également "undefined" const [allRooms, setAllRooms] = useState(); // filtered inclura les paramètres par lesquels // nous voulons filtrer les chambres existantes const [filtered, setFiltered] = useState(undefined) useEffect(() => { // Lors du montage des composants // C'est l'équivalent de componentDidMount dans les classes setAllRooms(rooms); }) const filterRooms = (e) => { // empêcher à nouveau le rafraîchissement e.preventDefault(); // filtrer les chambres const result = allRooms.filter(room => room.dailyPrice <= budget && room.people >= nog && room.availableFor >= days ) // Définissez le filtered, ce sont ceux que nous voulons voir setFiltered([...result]); } const clearFilter = () => { // Affichage de toutes les pièces setAllRooms(rooms); setFiltered(undefined) } return (<> <div className='flex flex-col items-center'> <form onSubmit={filterRooms} className='min-w-[300px] bg-purple-50 p-4 mt-6' > <div className='flex flex-col'> <label htmlFor="nog">Number of Guests (Max)</label> <input className='bg-cyan-100 p-2' type="number" onChange={(e) => setNog(e.target.value)} name='nog' placeholder="1" max={4} min={1} /> </div> <div className='flex flex-col'> <label htmlFor="price">Budget (Daily Max)</label> <input className='bg-cyan-100 p-2' type="number" name='price' onChange={(e) => setBudget(e.target.value)} placeholder="100" min={100} max={250} /> </div> <div className='flex flex-col'> <label htmlFor="days">Days</label> <input className='bg-cyan-100 p-2' type="number" name='days' onChange={(e) => setDays(e.target.value)} placeholder="2" min={1} max={30} /> </div> <input type="submit" value="FILTER" className='bg-cyan-700 text-white p-2 mt-2 rounded w-full cursor-pointer hover:bg-cyan-600' /> </form> <button onClick={clearFilter} className='bg-purple-700 text-white p-2 mt-2 rounded w-full cursor-pointer hover:bg-purple-600 max-w-[300px]'>CLEAR FILTER</button> <div className='grid sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 w-5/6 my-4'> {/* s'il n'y a pas de filtre, rendre toutes les pièces */} {allRooms && !filtered ? allRooms.map(r => <Link key={r.id} to={`${r.id}`}> <div > <img src={r.src} alt="" /> <p className='text-2xl'>{r.name}</p> <p>Daily Price: {r.dailyPrice} Money Units</p> <p>Capacity: {r.people} People</p> <p>Available For: {r.availableFor} Days</p> </div> </Link>): filtered ? filtered.map(r => <Link key={r.id} to={`${r.id}`}> <div > <img src={r.src} alt="" /> <p className='text-2xl'>{r.name}</p> <p>Daily Price: {r.dailyPrice} Money Units</p> <p>Capacity: {r.people} People</p> <p>Available For: {r.availableFor} Days</p> </div> </Link>): ""} </div> </div> </>) } export default Rooms

§Rendu Dynamique de La Pièce Sélectionnée

L'URL de l'objet "room" sera créée dynamiquement avec la valeur id que nous avons définie lors de la création des "rooms". Cette valeur d'identifiant apparaîtra dans l'url (par exemple /rooms/2). Cette valeur d'identifiant dans l'url sera utilisée pour trouver la chambre que nous voulons dans la "base de données". Nous allons utiliser le hook useParams pour obtenir la valeur id de l'url afin de filtrer les pièces.

Nous devons calculer le coût du séjour pour le client avant la réservation. Comme nous n'avons pas de backend, nous n'enregistrerons à nouveau que les messages qui nous sont envoyés. Le code complet est ici :

import React, { useState } from 'react' import { useParams } from 'react-router-dom'; import rooms from '../db'; const getRoomData = (roomId) => { const data = rooms.filter(r => parseInt(r.id) === parseInt(roomId)) return data; } const Room = () => { const roomId = useParams().id; const [days, setDays] = useState(); const [fullName, setFullName] = useState(); const [amountToPay, setAmountToPay] = useState() const [roomInfo, setRoomInfo] = useState(getRoomData(roomId)); const calculate = (e) => { e.preventDefault(); // juste une mesure supplémentaire if(days>roomInfo[0].availableFor || days<=0){ alert("invalid input for days") return } const result = parseInt(days) * parseInt(roomInfo[0].dailyPrice) setAmountToPay(result); } const makeReservations = () => { window.confirm("Votre réservation est faite, profitez de votre séjour ") } return (<> <div className='font-bold w-5/6 text-cyan-500 flex flex-col items-center m-auto'> <h1 className='text-6xl text-center m-4 uppercase'>{roomInfo[0].name}</h1> <img src={roomInfo[0].src} alt="" /> <p className='text-2xl'>{roomInfo[0].info}</p> <p className='text-2xl'>Daily Price is: {roomInfo[0].dailyPrice} Money Units</p> <p className='text-2xl'>For: {roomInfo[0].people}</p> <p className='text-2xl mb-4'>Available For: {roomInfo[0].availableFor} Days</p> <div className='mb-10'> <form onSubmit={calculate} className='bg-purple-50 p-5 '> <div className='flex flex-col min-w-[300px]'> <label htmlFor="full-name">Full Name</label> <input placeholder='John Doe' className='p-4' name='full-name' type="text" onChange={(e) => setFullName(e.target.value)} /> </div> <div className='flex flex-col min-w-[300px]'> <label htmlFor="days">Days</label> <input placeholder='1' className='p-4' name='days' type="number" min={1} max={roomInfo[0].availableFor} onChange={(e) => setDays(e.target.value)} /> </div> <input className='w-full mt-4 hover:bg-cyan-600 cursor-pointer rounded p-4 text-white text-2xl bg-cyan-700' type="submit" value="CALCULATE" /> </form> </div> <div className='my-6'> {amountToPay ? <div className='mt-6 flex flex-col items-center'><p className='text-2xl'>Make reservation with the following information:</p><p className='text-xl'>Name: {fullName}</p><p>Amount To Pay: {amountToPay} Money</p><button className='w-full bg-purple-700 text-white p-4 rounded text-2xl mt-2' onClick={makeReservations}>Make Reservation</button></div> : ""} </div> </div> </>) } export default Room

Eh bien, le code est très explicite, mais s'il y a des parties que vous avez du mal à comprendre, modifiez-le un peu. Modifiez certaines valeurs pour voir comment cela affectera le projet. Je suis sûr que vous pouvez trouver beaucoup de choses qui peuvent être améliorées dans le projet.

§Conclusion

Ce projet était très amusant à créer pour moi. Si vous souhaitez devenir développeur Web, vous avez besoin de sites Web comme celui-ci dans votre portefeuille. Je veux que ce projet soit assez simple pour que les débutants puissent comprendre. Pourtant, il est assez compliqué d'apprendre. Nous avons travaillé avec react-router-dom (même si nous n'avons pas utilisé de Navlink de react-router-dom) et nous avons filtré dynamiquement en définissant nos états (state). Vous avez également vu comment gérer les formulaires dans react.js.

N'hésitez pas à améliorer le projet. Créez votre propre design, ajoutez plus de chambres, créez un backend, etc. Vous pouvez toujours faire mieux, il y a toujours place à l'amélioration. J'espère que vous avez appris quelques choses de ce post et que ce n'était pas une perte de temps totale pour vous.

Le code du projet (et les images) peuvent être trouvés ici.

Ilker Akbiyik