https://d226lax1qjow5r.cloudfront.net/blog/blogposts/build-an-appointment-scheduler-using-node-firebase-and-vonage/appointment-scheduler.png

Construire un planificateur de rendez-vous en utilisant Node, Firebase et Vonage

Publié le December 16, 2021

Temps de lecture : 13 minutes

Introduction

Dans ce tutoriel, nous allons construire une application web de prise de rendez-vous en utilisant Node.js, Express, Firebase, et l' Vonage Messages API. Le dépôt GitHub pour ce projet est également disponible, n'hésitez pas à le cloner ici.

Configuration de Firebase

Pour commencer, créons un nouveau projet à partir de la console console Firebase.

  • Cliquez sur add a new project

  • Donnez un nom significatif à votre projet, par exemple vonage appointment scheduler

  • Vérifiez si vous aimez l'identifiant unique de votre projet (il est utilisé dans l'URL de votre base de données en temps réel, dans les sous-domaines de Firebase Hosting, etc. Il ne peut pas être modifié après la création du projet)

  • Cliquez sur le bouton pour continuer

Console view with a text field to enter project and name and edit the project idConsole view with a text field to enter project and name and edit the project id

  • Sélectionnez si vous souhaitez activer l'analyse. Nous ne le ferons pas dans ce tutoriel

  • Cliquez sur le bouton pour créer le projet

  • Attendre la création du projet

Project being createdProject being created

  • Une fois que le projet est prêt, cliquez pour continuer. Vous accéderez à la vue de la console de votre projet

  • Définissez le type de facturation en cliquant sur l'icône de l'engrenage, puis sur Usage et facturation, ensuite sur l'onglet Détails et paramètres et modifiez le plan pour utiliser Blaze. Ce plan de paiement à l'utilisation est nécessaire lors de l'utilisation d'une API tierce.

Installer Firebase Tools CLI

Depuis votre terminal, installez les outils Firebase avec NPM si vous ne les avez pas déjà en tapant : npm install -g firebase-tools. Ensuite, tapez firebase login. Cela ouvrira une fenêtre dans votre navigateur qui vous authentifiera automatiquement (si vous êtes déjà connecté) ou vous demandera vos identifiants. Une fois que vous avez terminé, vous avez maintenant installé le CLI Firebase.

Créer et paramétrer une base de données en temps réel

Il est maintenant temps de créer l'instance de la base de données NoSQL qui contiendra les informations relatives aux créneaux de rendez-vous. Notre application comprendra une vue où l'utilisateur pourra prendre ou annuler des rendez-vous. Lorsque la personne qui interagit avec la vue choisit une date et une heure de rendez-vous, ce créneau sera ajouté ou supprimé de la base de données Firebase RealTime.

  • Dans le menu de la console Firebase, cliquez sur "Realtime Database" (base de données en temps réel) sous "Build" (construction).

Button to create the databaseButton to create the database

  • Cliquez sur "Créer une base de données"

  • Sélectionnez l'emplacement de la base de données en temps réel où vos données seront stockées et cliquez sur next

  • Sélectionnez si vous souhaitez utiliser la base de données en mode verrouillée ou en mode test. Pour cet exemple, j'utilise le mode test.

  • Cliquez sur enable

    Database createdDatabase created

Importer le fichier JSON de la base de données

Importons une base de données d'exemple qui contient déjà quelques emplacements attribués et à partir de laquelle vous pourrez ajouter et supprimer de futurs emplacements. Vous pouvez créer un fichier appelé myAppointments.json contenant le JSON de l'extrait ci-dessous, puis importer ce fichier depuis la console.

myAppointments.json
{
  "myAppointments": {
    "0": {
      "date": "2021-06-01T09:00",
      "userId": "1234abcd"
    },
    "new_activity_7kh3a3a3z": {
      "date": "2023-06-01T08:50",
      "userId": "_7kh3a3a3z"
    },
    "new_activity_etxen95x3": {
      "date": "2021-06-01T08:40",
      "userId": "_etxen95x3"
    }
  }
}

Import DatabaseImport Database

Ajouter les règles de la base de données

Les règles de base de données en temps réel de Firebase déterminent qui peut accéder à votre base de données, comment vos index sont construits et comment vos données sont structurées.

  • Dans la console Firebase, sur la vue de la base de données en temps réel, vous pouvez voir "Règles", cliquez sur cet onglet. Vous serez dirigé vers un écran qui vous permettra d'éditer vos règles.

  • Copiez et collez les règles de l'extrait de code ci-dessous dans votre console afin de définir la collection myAppointments pour qu'elle soit indexée par le champ date champ.

  • Cliquez sur Publish

{
  "rules": {
    ".read": "now < 1643842800000",  // 2022-2-3
    ".write": "now < 1643842800000",  // 2022-2-3
    "myAppointments": {
      ".indexOn": ["date"]
    }
  }
}

Edit Firebase Database RulesEdit Firebase Database Rules

Créer la structure du projet

À la fin de ce tutoriel, voici à peu près à quoi ressemblera la structure de votre projet. Dans les étapes suivantes, nous allons créer les fichiers qui vont construire le contenu, l'apparence, les fonctionnalités et gérer les services que nous allons utiliser.

Project Structure also displayed as a code block below for accessibilityProject Structure

appointment-scheduler | public | |- styles | | | L styles.css | |- favicon.ico | L index.html |- script | |- server.js |- .env |- .firebaserc |- README.md |- firebase.json |- package-lock.json |- package.json |- serviceAccountKey.json

Mise en place

  • Créez le dossier du projet et cd dans celui-ci : mkdir appointment-scheduler && cd appointment-scheduler

  • Initialiser NPM : npm init. Cette commande vous invite à ajouter des informations sur le projet

  • Installer les dépendances : npm install @vonage/server-sdk dotenv uuid express firebase-admin firebase-functions

  • Type firebase init. Puisque nous avons déjà créé un projet dans le tableau de bord, vous pouvez sélectionner Use an existing project ce qui vous invitera à choisir le projet souhaité. Vous pouvez voir mon exemple avec l'identifiant de mon projet vonage-appointment-scheduler ci-dessous. J'ai également choisi d'utiliser la Realtime Database fonctionnalité

? Which Firebase features do you want to set up for this directory? Press Space to select features, then Enter to confirm your choices. Realtime Database: Configure a security rules file for Realtime Database and (optionally) provision default instance === Project Setup First, let's associate this project directory with a Firebase project. You can create multiple project aliases by running firebase use --add, but for now, we'll just set up a default project. ? Please select an option: Use an existing project ? Select a default Firebase project for this directory: vonage-appointment-scheduler (vonage appointment scheduler) i Using project vonage-appointment-scheduler (vonage appointment scheduler)

Créer le contenu HTML

Saviez-vous que l'élément de saisie HTML dispose de nombreuses options de type pour la sélection de la date et de l'heure ? Par exemple, nous avons : date, datetime-local, time. Pour ce tutoriel, nous utiliserons <input type="datetime-local">. Cette approche n'est peut-être pas aussi robuste que l'utilisation de la bibliothèque de dates et d'heures, car il peut y avoir des incohérences, mais elle fonctionne pour les besoins de ce tutoriel. L'utilisateur pourra réserver des créneaux horaires toutes les 5 minutes se terminant par 0 ou 5, par exemple 18:00 est réservable mais 18:01 ne l'est pas.

  • Créez le fichier public/index.html qui contient le contenu de la vue permettant de sélectionner un nouveau rendez-vous ou de l'annuler en ajoutant l'extrait de code suivant

  <!-- index.html -->
<!DOCTYPE html>
<html>
  <head>
    <title>Appointment Scheduler</title>

    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="stylesheet" href="styles/styles.css" />
  </head>
  <body>
    <main>
      <h1>Appointment Scheduler</h1>
      <!-- datepicker from html. Source: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/datetime-local -->
      <form action="/appointment" method="POST">
        <div>
          <label for="slot">Choose your slot: </label>
          <input
            id="slot"
            type="datetime-local"
            name="slotdate"
            min="2021-06-01T08:30"
            max="2023-10-30T16:30"
            step="300"
            required
          />
          <span class="validity"></span>
        </div>
        <div>
          <label for="phonenumber">Your phone number:</label>
          <input type="tel" id="phonenumber" name="phonenumber" required />
          <span class="validity"></span>
        </div>
        <div>
          <input type="submit" value="Book slot!" />
        </div>
      </form>
      <form action="/cancelAppointment" method="POST">
        <div>
          <input type="text" name="code" placeholder="code" />
          <input type="submit" value="Remove slot!" />
        </div>
      </form>
    </main>
  </body>
</html>

Ajouter un style CSS

Pour cette application web de démonstration, nous ajouterons quelques éléments de style pour centrer le contenu sur la page et afficher un ✖ rouge si la saisie n'est pas valide et un ✓ si elle l'est.

  • Créer le public/styles.css fichier

  • Collez le code CSS ci-dessous

body {
    margin: auto;
    width: 50%;
    padding: 10px;
}

div {
    margin-bottom: 10px;
    display: flex;
    align-items: center;
}

label {
  display: inline-block;
  width: 300px;
}

input:invalid+span:after {
    content: '✖';
    color: red;
    padding-left: 5px;
}

input:valid+span:after {
    content: '✓';
    color: green;
    padding-left: 5px;
}

Créer le fichier des variables d'environnement

  • Créez le formulaire .env et l'alimenter avec les informations suivantes

FIREBASE_DATABASE_URL= VONAGE_API_KEY= VONAGE_API_SECRET= VONAGE_FROM_NUMBER= VONAGE_TO_NUMBER=
  • Les FIREBASE_DATABASE_URL se trouve dans la console Firebase

  • Les VONAGE_API_KEYet le VONAGE_API_SECRET peuvent être trouvés dans le tableau de bord Vonage

  • Le message VONAGE_FROM_NUMBER contient le numéro, le nom ou la marque qui apparaîtra comme l'expéditeur du message

  • Le VONAGE_TO_NUMBER est le numéro qui recevra les SMS

Créer le fichier JavaScriptserver.js

Nous allons créer l'élément server.js pour indiquer à Express comment traiter les requêtes postées par l'interface utilisateur. Je vais vous montrer pas à pas comment nous allons le construire. Vous pouvez trouver le fichier serveur complet ici.

Notre application web utilisera express et lira les fichiers statiques que nous avons précédemment créés dans le dossier public dans le dossier

  • Pour ajouter les dépendances et les fichiers d'importation, ajoutez l'extrait de code ci-dessous à votre fichier script/server.js

// script/server.js
require('dotenv').config();
const express = require('express');
const app = require('express')();
const port = 3000; //setting the port to listen to as 3000
const admin = require('firebase-admin');
const Vonage = require('@vonage/server-sdk');
const SMS = require('@vonage/server-sdk/lib/Messages/SMS';
const { v4: uuidv4 } = require('uuid');

app.use(express.static('public'));

app.use(express.json());

app.use(express.urlencoded({ extended: true }));

Ajouter le Service Account

Un compte de service Firebase peut être utilisé pour authentifier diverses fonctionnalités de Firebase ; pour notre projet, nous utiliserons le SDK Admin Firebase pour accéder à l'URL de notre base de données.

  • Dans la console Firebase, cliquez sur l'engrenage et sélectionnez l'onglet Compte de service

  • Cliquez sur le bouton pour generate key

  • Ajoutez le fichier généré à la racine de votre projet et renommez-le en serviceAccountKey.json

  • Copiez et collez l'extrait de configuration Admin SDK dans votre projet, comme vous pouvez le voir dans l'étape suivante de ce tutoriel, pour initialiser Firebase. Nous utilisons ${process.env.FIREBASE_DATABASE_URL pour lire l'URL du fichier .env mais il s'agit de la même URL de base de données que celle trouvée dans la configuration du SDK d'administration de Firebase.

Admin SDK configurationAdmin SDK configuration

Initialiser Firebase

Nous utilisons initializeApp pour créer et initialiser une instance d'application Firebase qui utilisera l'instance de base de données Firebase /myAppointments instance de base de données Firebase que nous avons précédemment créée et alimentée à partir de la console Firebase.

  • Ajoutez l'extrait de code ci-dessous à votre server.js pour initialiser Firebase.

const serviceAccount = require('../serviceAccountKey.json');

// Initializes firebase
admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
  databaseURL: `${process.env.FIREBASE_DATABASE_URL}`,
});

// A Reference represents a specific location in your Database and can be 
// used for reading or writing data to that Database location.
ref = admin.database().ref('/myAppointments');

Initialiser l'objet API Vonage

Nous créons l'instance de la classe client Vonage, en l'initialisant avec la clé et le secret de l'API Vonage que vous avez précédemment ajoutés à votre fichier .env fichier

  • Ajoutez l'extrait de code ci-dessous à votre server.js pour ajouter Vonage.

const vonage = new Vonage({
  apiKey: process.env.VONAGE_API_KEY,
  apiSecret: process.env.VONAGE_API_SECRET,
});

Création de la fonction getDateTime()

Le type d'entrée HTML datetime-local est formaté comme suit YYYY-MM-DDTh:mm. Nous allons donc écrire une fonction pour séparer la date de l'heure en la séparant par le caractère T. Par exemple, dans l'exemple 2018-06-12T19:30nous aurions 2018-06-12 pour la date et 19:30 pour l'heure.

  • Ajoutez l'extrait de code ci-dessous à votre server.js pour ajouter la fonction getDateTime() fonction

  const getDateTime = (slot) => {
    return slot.split('T');
  };

Créer le/appointment point final

Il est temps de créer le point de terminaison /appointment pour gérer les requêtes POST pour la création d'un rendez-vous. Ce point de terminaison vérifiera si le créneau est disponible, ajoutera le créneau à la base de données Firebase et, enfin, enverra un SMS de confirmation au téléphone de l'utilisateur à l'aide de l'API Messages de Vonage.

  • Ajoutez l'extrait de code ci-dessous à votre server.js pour créer le point de terminaison /appointment point final.

app.post('/appointment', async (request, response) => {
  let phonenumber = request.body.phonenumber;
  let slot = request.body.slotdate;
  let [date, time] = getDateTime(slot);

  // Checks if a slot is available
  checkIfAvailable = async (slot) => {};
  
  // Adds to Database
  addToDatabase = () =>  {};
  
  // Sends an SMS back to the user's phone using the Vonage Messages API
  sendSMStoUser = async (code) => {};
});

Vous avez peut-être remarqué qu'une grande partie des fonctionnalités du gestionnaire de requêtes n'a pas encore été implémentée, nous allons donc développer les stubs pour les fonctionnalités requises.

Vérifier la disponibilité des créneaux

Cette fonction valide la disponibilité d'un créneau en vérifiant s'il existe déjà dans la base de données. Nous interrogeons ref.orderByChild('date'). Les requêtes sont autorisées à commander une clé à la fois. Nous avons préalablement défini notre index via l'option .indexOn sur les règles Firebase pour une meilleure performance. Ensuite, nous utilisons .once('value') pour écouter exactement un événement de la valeur, puis il s'arrête d'écouter.

  • Ajoutez l'extrait de code ci-dessous à votre server.js pour créer la checkIfAvailable() fonction

  // Checks if a slot is available
  checkIfAvailable = async (slot) => {
    let snapshot = await ref.orderByChild('date').once('value');

    let available = true;
    
    snapshot.forEach((data) => {
      let dataval = data.val();
      for (let key in dataval) {
        let datapoint = dataval[key];
        if (slot === datapoint) {
          available = false;
        }
      }
    });
    return available;
  };

Ajouter le créneau à la base de données

La fonction suivante addToDatabase() ajoute le créneau et un code à la base de données Firebase. Ce code est nécessaire pour annuler le rendez-vous.

  // Adds the slot to the database
  addToDatabase = () => {
    let code = uuidv4();

    ref.child(code).set({
      date: slot,
      userId: code,
    });

    return code;
  };

Envoyer un SMS avec les informations relatives au rendez-vous

Enfin, une fois le créneau réservé, un SMS de confirmation est envoyé à l'utilisateur avec le message suivant Meeting booked at ${time} on date: ${date}. Please save this code: ${code} in case you'd like to cancel your appointment. comme vous pouvez le voir dans la fonction sendSMStoUser().

  • Ajoutez l'extrait de code ci-dessous à votre server.js pour créer la sendSMStoUser() fonction

// Sends an SMS back to the user's phone using the Vonage Messages API
sendSMStoUser = async (code) => {
  const to = phonenumber;
  const text = `Meeting booked at ${time} on date: ${date}. Please save this code: ${code} in case you'd like to cancel your appointment.`;
  const result = await new Promise((resolve, reject) => {
    vonage.messages.send(
      new SMS(text, process.env.VONAGE_TO_NUMBER, "Vonage"),
      (err, data) => {
        if (err) {
          console.error(err);
        } else {
          console.log(data.message_uuid);
        }
      }
    );
  });
};

Finaliser la logique d'entreprise

Le morceau de code ci-dessous est chargé d'appeler les fonctions d'aide créées précédemment. Si le créneau est disponible, l'utilisateur verra son créneau ajouté à la base de données et le SMS lui sera renvoyé. Dans le cas contraire, il lui sera demandé de choisir un autre créneau horaire.

let available = await checkIfAvailable(slot);

if (available) {
	let code = addToDatabase();
	await sendSMStoUser(code);
	response.send(`This slot is available, booking it for you now: ${slot}`);
} else {
	// Sends user error
	response.send(
		`Sorry, you'll need to choose a different slot.${slot} is already busy.`
	);
}

Annuler le rendez-vous/cancelAppointment

Créons le point de terminaison /cancelAppointment qui gère les requêtes POST pour l'annulation d'un rendez-vous à partir de la base de données en utilisant un code fourni par l'utilisateur qu'il a reçu lors de la prise de rendez-vous.

app.post('/cancelAppointment', async (request, response) => {
  let code = request.body.code;

  // Removes slot from the database
  removeSlotFromDB = (code) => {
    ref.child(code).remove();
  };
  removeSlotFromDB(code);

  response.send(`This slot has been removed.`);
});

Écouter le port

Enfin, l'application écoutera sur le port spécifié ; si elle est exécutée localement, elle sera accessible sur https://localhost:${port}. Dans cette URL, vous pouvez interagir avec l'interface utilisateur de cette application de démonstration et vérifier les emplacements ajoutés/supprimés sur la page web de la console Firebase.

app.listen(port, () => {
  console.log(`I run on port ${port}`);
});

Testez-le

  • Dans votre fichier package.json ajoutez le script de démarrage "start": "node script/server.js" juste en dessous de "test": "echo \"Error: no test specified\" && exit 1",. Il devrait ressembler à ceci :

"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "node script/server.js" },
  • Installer toutes les dépendances npm install

  • Lancer la commande NPM pour exécuter le projet npm run start

  • Naviguez jusqu'à http://localhost:3000

  • Ajouter et supprimer des créneaux de rendez-vous et les voir ajoutés et supprimés de la base de données Firebase Realtime.

Example adding a slot and it is shown on the Firebase Realtime databaseExample adding a slot and it being shown on the Firebase Realtime database

Conclusion et prochaines étapes

Aujourd'hui, vous avez vu comment construire une application web de démonstration de prise de rendez-vous. Vous pouvez maintenant aller de l'avant et ajouter un style plus fantaisiste et d'autres fonctionnalités. Vous pouvez utiliser ce que vous avez appris ici pour créer de nombreux planificateurs de rendez-vous, que ce soit pour une salle de sport ou pour un créneau de vaccination - laissez libre cours à votre créativité !

Contactez-nous sur Twitter et rejoignez notre communauté sur Slack.

Partager:

https://a.storyblok.com/f/270183/400x400/3f6b0c045f/amanda-cavallaro.png
Amanda CavallaroDéfenseur des développeurs