
Crear un programador de citas con Node, Firebase y Vonage
Tiempo de lectura: 12 minutos
Introducción
En este tutorial, vamos a crear una aplicación web de programación de citas utilizando Node.js, Express, Firebase y la Mensajes API de Vonage. El repositorio repositorio de GitHub para este proyecto también está disponible, no dude en clonarlo aquí.
Configurar Firebase
Para empezar, vamos a crear un nuevo proyecto desde la consola de Firebase.
Haga clic en
add a new projectDé a su proyecto un nombre significativo, por ejemplo
vonage appointment schedulerComprueba si te gusta el identificador único para tu proyecto (se utiliza en la URL de tu base de datos en tiempo real, subdominios de Firebase Hosting y más. No se puede cambiar después de la creación del proyecto)
Pulse el botón para continuar
Console view with a text field to enter project and name and edit the project id
Seleccione si desea activar el análisis. No lo haremos en este tutorial
Haga clic en el botón para crear el proyecto
Esperar a que se cree el proyecto
Project being created
Una vez que el proyecto esté listo, haga clic para continuar. Accederá a la vista de consola de su proyecto
Establezca el tipo de facturación haciendo clic en el icono de engranaje, seguido de Uso y facturación, luego en la pestaña Detalles y configuración y modifique el plan para utilizar Blaze. Este plan de pago por uso es necesario cuando se utiliza una API de terceros
Instalar Firebase Tools CLI
Desde tu terminal, instala las herramientas Firebase con NPM si aún no las tienes escribiendo: npm install -g firebase-tools. A continuación, escribe firebase login. Esto abrirá una ventana en tu navegador que te autenticará automáticamente (si ya has iniciado sesión) o te pedirá tus credenciales. Una vez completado esto, ya tienes el Firebase CLI instalado.
Crear y configurar una base de datos en tiempo real
Ahora es el momento de crear la instancia de base de datos NoSQL que contendrá la información de las franjas horarias de las citas. Nuestra aplicación incluirá una vista en la que el usuario podrá concertar o cancelar citas. A medida que la persona que interactúa con la vista elige una fecha y hora de la cita, esa ranura se añadirá o eliminará de la base de datos Firebase RealTime.
En el menú de la consola Firebase, haga clic en "Realtime Database" en Build
Button to create the database
Haga clic en "Crear base de datos".
Seleccione la ubicación de la base de datos en tiempo real donde se almacenarán sus datos y haga clic en
nextSeleccione si va a utilizar la base de datos en modo bloqueado o de prueba. Para este ejemplo, estoy utilizando el modo de prueba
Haga clic en
enable
Database created
Importar el archivo JSON de la base de datos
Vamos a importar una base de datos de ejemplo que ya contiene algunas franjas horarias asignadas, y desde la que podrá añadir y eliminar futuras franjas horarias. Puede crear un archivo llamado myAppointments.json que contenga el JSON del siguiente fragmento y, a continuación, importarlo desde la consola.
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 Database
Añadir las reglas de la base de datos
Las Reglas de Base de Datos en Tiempo Real de Firebase determinan quién puede acceder a su base de datos, cómo se construyen sus índices y cómo se estructuran sus datos.
Desde la consola Firebase en la vista de la base de datos en tiempo real, puedes ver "Reglas", haz clic en esa pestaña. Se le llevará a una pantalla que le permitirá editar sus reglas
Copie y pegue las reglas del siguiente fragmento de código en la consola para que la colección
myAppointmentspara que sea indexada por el campodatecampo.Haga clic en
Publish
{
"rules": {
".read": "now < 1643842800000", // 2022-2-3
".write": "now < 1643842800000", // 2022-2-3
"myAppointments": {
".indexOn": ["date"]
}
}
}
Edit Firebase Database Rules
Crear la estructura del proyecto
Al final de este tutorial, esta será aproximadamente la estructura de tu proyecto. En los siguientes pasos, crearemos los archivos que construirán el contenido, la apariencia, las funcionalidades y manejarán los servicios que utilizaremos.
Project Structure
Configurar
Cree la carpeta del proyecto y
cden ella:mkdir appointment-scheduler && cd appointment-schedulerInicializar NPM:
npm init. Este comando le pide que añada información sobre el proyectoInstale las dependencias:
npm install @vonage/server-sdk dotenv uuid express firebase-admin firebase-functionsTipo
firebase init. Como ya hemos creado un proyecto en el cuadro de mandos, puede seleccionarUse an existing projectque le pedirá que elija el proyecto deseado. Puede ver mi ejemplo con mi id de proyectovonage-appointment-schedulerabajo. También elegí utilizar laRealtime Databasefunción
Crear el contenido HTML
¿Sabías que el elemento de entrada HTML tiene muchas opciones de tipo para la selección de fecha y hora? Por ejemplo, tenemos: date, datetime-local, time. En este tutorial utilizaremos <input type="datetime-local">. Este enfoque quizás no sea tan robusto como el uso de la librería fecha-hora, ya que puede haber algunas inconsistencias, pero funciona para el propósito de este tutorial. El usuario podrá reservar franjas horarias cada 5 minutos que terminen en 0 o 5. Por ejemplo, las 18:00 se pueden reservar, pero las 18:01 no.
Cree el archivo
public/index.htmlque contiene el contenido para que la vista seleccione una nueva cita o las cancele añadiendo el siguiente fragmento de código
<!-- 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>
Añadir estilo CSS
Para esta aplicación web de demostración, añadiremos algunos estilos para centrar el contenido en la página, y también mostraremos un ✖ rojo en caso de que la entrada no sea válida y un ✓ en caso de que sea válida.
Cree el
public/styles.cssarchivoPegue el siguiente código CSS
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;
} Crear el archivo de variables de entorno
Cree el
.envy rellénalo con la siguiente información
La dirección
FIREBASE_DATABASE_URLpuede encontrarse en la consola de FirebaseEn
VONAGE_API_KEYy elVONAGE_API_SECRETse pueden encontrar en el Panel de VonageLa dirección
VONAGE_FROM_NUMBERcontiene el número, nombre o marca que aparecerá como remitente del mensajeEl
VONAGE_TO_NUMBERes el número que recibirá los SMS
Crear el archivo JavaScriptserver.js
Crearemos el archivo server.js para decirle a Express cómo manejar las peticiones enviadas por la UI. Te mostraré paso a paso cómo lo construiremos. Puedes encontrar el archivo completo del servidor aquí.
Nuestra aplicación web utilizará express y leerá los archivos estáticos que creamos previamente desde la carpeta public carpeta.
Para añadir las dependencias y los archivos de importación, añada el siguiente fragmento de código a su archivo
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 })); Añadir la cuenta de servicio
Una Account de servicio Firebase puede ser usada para autenticar varias características de Firebase; para nuestro proyecto, usaremos el SDK Firebase Admin para acceder a la URL de nuestra Base de Datos.
En la consola Firebase, haga clic en el engranaje y seleccione la pestaña Service Account.
Pulse el botón para
generate keyAñade el archivo generado a la raíz de tu proyecto y renómbralo a
serviceAccountKey.jsonCopia y pega el fragmento de configuración de Admin SDK en tu proyecto, como puedes ver en el siguiente paso de este tutorial, para inicializar Firebase. Estamos usando
${process.env.FIREBASE_DATABASE_URLpara leer la URL del archivo.envpero es la misma URL de la base de datos que se encuentra en la configuración de Firebase Admin SDK.
Admin SDK configuration
Inicializar Firebase
Usamos initializeApp para crear e inicializar una instancia de aplicación Firebase que utilizará la instancia de base de datos /myAppointments Firebase que hemos creado y rellenado previamente desde la Consola Firebase.
Añada el siguiente fragmento de código a su
server.jspara inicializar 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'); Inicializar el objeto API de Vonage
Creamos la instancia de la clase cliente de Vonage, inicializándola con la clave y el secreto de la API de Vonage que agregaste previamente a tu archivo .env archivo.
Agrega el siguiente fragmento de código a tu
server.jspara añadir Vonage.
const vonage = new Vonage({
apiKey: process.env.VONAGE_API_KEY,
apiSecret: process.env.VONAGE_API_SECRET,
}); Crear la función getDateTime()
El tipo de entrada HTML datetime-local tiene el formato AAAA-MM-DDThh:mm. Así que escribiremos una función para separar la fecha de la hora dividiéndola en el carácter T. Por ejemplo, en el ejemplo 2018-06-12T19:30tendríamos 2018-06-12 para la fecha y 19:30 para la hora.
Añada este fragmento de código a su
server.jspara añadir la funcióngetDateTime()función
const getDateTime = (slot) => {
return slot.split('T');
};
Crear el/appointment punto final
Es hora de crear el endpoint /appointment para manejar las solicitudes POST para crear una cita. Este punto final verificará si el espacio está disponible, agregará el espacio a la base de datos de Firebase y, por último, enviará un SMS de confirmación al teléfono del usuario mediante la API de Messages API de Vonage.
Añada el siguiente fragmento de código a su
server.jspara crear el endpoint/appointmentpunto 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) => {};
});
Te habrás dado cuenta de que gran parte de la funcionalidad dentro del manejador de peticiones aún no se ha implementado, así que ahora vamos a ampliar los stubs para las funcionalidades requeridas.
Comprobar disponibilidad de franjas horarias
Esta función valida si una ranura está disponible comprobando si la ranura ya existe en la base de datos. Estamos consultando ref.orderByChild('date'). Las consultas pueden ordenar una clave cada vez. Hemos definido previamente nuestro índice a través de la función .indexOn en las reglas de Firebase para un mejor rendimiento. Y luego hacemos uso .once('value') para escuchar exactamente un evento del valor, y luego deja de escuchar.
Añada el siguiente fragmento de código a su
server.jspara crear la funcióncheckIfAvailable()función
// 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;
};
Añadir la ranura a la base de datos
La siguiente función addToDatabase() añade la franja horaria y un código a la base de datos Firebase. Este código es necesario para cancelar la cita.
// Adds the slot to the database
addToDatabase = () => {
let code = uuidv4();
ref.child(code).set({
date: slot,
userId: code,
});
return code;
};
Enviar un SMS con la información de la cita
Por último, una vez reservada la plaza, se envía un SMS de confirmación al usuario con el mensaje Meeting booked at ${time} on date: ${date}. Please save this code: ${code} in case you'd like to cancel your appointment. como puede verse en la función sendSMStoUser().
Añada el siguiente fragmento de código a su
server.jspara crear la funciónsendSMStoUser()función
// 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);
}
}
);
});
};
Finalizar la lógica empresarial
El siguiente fragmento de código se encarga de llamar a las funciones de ayuda creadas anteriormente. Si la franja horaria está disponible, se añadirá a la base de datos y se enviará el SMS al usuario. En caso contrario, se le pedirá que elija otra franja horaria.
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.`
);
} Anular la cita/cancelAppointment
Vamos a crear el endpoint /cancelAppointment que gestiona las peticiones POST para cancelar una cita desde la base de datos utilizando un código proporcionado por el usuario al concertar su cita.
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.`);
});
Escuchar el puerto
Por último, la aplicación estará a la escucha en el puerto especificado; si se ejecuta localmente, será accesible en https://localhost:${port}. En esta URL, puede interactuar con la interfaz de usuario de esta aplicación de demostración y comprobar las ranuras que se añaden/eliminan en la página web de la consola de Firebase.
app.listen(port, () => {
console.log(`I run on port ${port}`);
});
Pruébelo
En su
package.jsonañada el script de inicio"start": "node script/server.js"justo debajo de"test": "echo \"Error: no test specified\" && exit 1",. Debería tener este aspecto:
Instalar todas las dependencias
npm installEjecute el comando NPM para ejecutar el proyecto
npm run startVaya a
http://localhost:3000Añadir y eliminar franjas horarias de citas y ver cómo se añaden y eliminan de la base de datos en tiempo real de Firebase.
Example adding a slot and it being shown on the Firebase Realtime database
Conclusión y próximos pasos
Hoy has visto cómo construir una aplicación web de demostración de un programador de citas. Ahora puedes seguir adelante y añadir un estilo más elegante y otras funcionalidades. Puedes tomar lo que has aprendido aquí para crear muchos programadores de citas, ya sea para un gimnasio o para un espacio de vacunación - ¡deja que fluya la creatividad!
Contáctanos en Twitter y únete a nuestra comunidad en Slack.