Diego  Elizondo

Diego Elizondo

1658842023

Cree Una Aplicación De Comercio Electrónico Automatizada Con WhatsApp

En mayo de 2022, Meta (la empresa antes conocida como Facebook, propietaria de WhatsApp) anunció que abriría al público la API empresarial de WhatsApp. Este artículo pretende darle la bienvenida al mundo de oportunidades de Meta, donde los chatbots de WhatsApp pueden ayudarlo a generar clientes potenciales, recibir pedidos, programar citas, realizar encuestas, recibir comentarios de los clientes, brindar atención al cliente escalable, enviar facturas y recibos, y más.

Este tutorial profundizará en los aspectos técnicos de la creación de un chatbot de WhatsApp desde cero.

Al final de este tutorial, habrá creado su propio chatbot de WhatsApp.

Nuestro tutorial se centra en una sencilla tienda de comercio electrónico familiar que vende artículos para el hogar y moda rápida. El negocio tendrá un chatbot de WhatsApp donde los clientes podrán navegar y comprar en la tienda de comercio electrónico.

Cada tienda de comercio electrónico necesita productos (precios, nombres, descripciones, etc.), y para este tutorial, usaremos los productos ficticios de FakeStoreAPI .

requisitos previos

Antes de continuar, este artículo asume que:

Paso 1: Configurando nuestra aplicación en el tablero de Meta Developer

El primer paso para usar cualquiera de las API de Meta es crear una aplicación en el tablero de Meta, que es gratis.

  • Mientras está conectado a su cuenta de desarrollador de Meta, navegue a https://developers.facebook.com/apps
  • Haz clic en Crear aplicación
  • En la siguiente pantalla, seleccione el tipo de aplicación Business

Selección del tipo de aplicación comercial

  • Luego, complete el nombre de su aplicación y su dirección de correo electrónico, y luego seleccione la página/negocio que desea asociar con esta aplicación

Nombrando la aplicación y seleccionando la página asociada a ella

  • Después de enviar el formulario, accederá a una pantalla que se ve así:

Seleccionando la configuración de WhatsApp

En esta pantalla, seleccione WhatsApp y haga clic en su botón Configurar .

Luego será conducido a una nueva pantalla, como se muestra a continuación.

Página de inicio

En esta pantalla, toma nota de:

  • El ID de la aplicación , que es el ID asociado con nuestra aplicación Meta. El mio es1184643492312754
  • El token de acceso temporal , que caduca a las 24 horas. El mio empieza con EAAQ1bU6LdrIBA...
  • El número de teléfono de prueba , que usaremos para enviar mensajes a los clientes. El mio es+1 555 025 3483
    • El ID del número de teléfono . El mio es113362588047543
    • El ID de la cuenta comercial de WhatsApp . El mio es102432872486730

Tenga en cuenta que el token de acceso temporal caduca después de 24 horas, momento en el que tendremos que renovarlo. Cuando cambia su aplicación al modo en vivo, puede solicitar un token de acceso permanente, que no necesitamos hacer ya que nuestra aplicación está en modo de desarrollo.

El ID del número de teléfono y el ID de la cuenta comercial de WhatsApp están vinculados al número de teléfono de prueba.

A continuación, agreguemos un número de teléfono para usar para recibir mensajes.

En el modo de desarrollo, Meta nos restringe a cinco números de destinatarios por motivos relacionados con la prevención del spam/uso indebido. En el modo en vivo/producción, el número representa los números de teléfono de nuestros clientes.

Haga clic en Seleccione un número de teléfono del destinatario y agregue su propio número de WhatsApp, como se muestra en la siguiente captura de pantalla:

Agregar un cuadro de diálogo de número de teléfono del destinatario

Después de agregar su número de destinatario, verá una pantalla similar a la siguiente. Si es la primera vez que agrega su número de teléfono a las plataformas Meta, como las páginas de Facebook, la suite Meta Business o el panel de desarrollo de Meta, recibirá un mensaje OTP de Facebook Business que le pedirá que verifique que realmente es el propietario del número del destinatario. .

Enviar mensajes con la API

Probando nuestra configuración

Probemos si todo hasta este paso funcionó bien. Lo haremos haciendo clic en el botón Enviar mensaje .

Si todo está bien, debería ver un mensaje en su bandeja de entrada de WhatsApp desde su número de prueba.

Mensaje de Hello World de Facebook en la bandeja de entrada de WhatsApp

Hasta este punto, ¡lo estamos haciendo bien! Haz una pausa y abre tu editor de código. No cierres la pestaña de tu navegador todavía porque volveremos al panel de Meta Developer en unos minutos.

Paso 2: Configuración de webhooks para recibir mensajes

Ahora que nuestra configuración puede enviar mensajes con éxito, configuremos una forma de recibir mensajes. Es hora de ensuciarse las manos y sumergirnos en la escritura de código. Todo el código que escribiremos para este tutorial está en este repositorio de GitHub .

Cree una nueva carpeta para contener nuestro proyecto. Abra esta carpeta en una terminal y ejecute el siguiente script:

npm init ---yes

A continuación, instalamos algunos paquetes:

npm install express pdfkit request whatsappcloudapi_wrapper
npm install nodemon --dev

He aquí una breve explicación de cada uno:

  • El expresspaquete es importante para configurar nuestro servidor. El servidor contendrá una ruta que actuará como nuestro webhook.
  • El pdfkitpaquete se utilizará para generar facturas para nuestros clientes cuando realicen el pago.
  • El request paquete nos ayudará a ejecutar solicitudes de recuperación a FakeStoreAPI
  • El whatsappcloudapi_wrappernos ayuda a enviar y recibir mensajes de WhatsApp

A continuación, vamos a crear tres archivos:

  1. ./app.js
  2. ./.env.js
  3. ./routes/index.js

En nuestro ./.env.jsarchivo, escriba el siguiente código:

const production = {
    ...process.env,
    NODE_ENV: process.env.NODE_ENV || 'production',
};

const development = {
    ...process.env,
    NODE_ENV: process.env.NODE_ENV || 'development',
    PORT: '9000',
    Meta_WA_accessToken:'EAAKGUD3eZA28BADAJOmO6L19TmZAIEUpdFGHEGHX5sQ3kk4LDQLlnyh607rKSr0x2SAOPJS0kXOUZAhRDIPPGs4vcXQCo2DnfSJMnnIzFW7vaw8EuL7A0HjGZBwE8VwjRnBNam0ARLmfyOCEh1',
    Meta_WA_SenderPhoneNumberId: '113362588047543',
    Meta_WA_wabaId: '102432872486730',
    Meta_WA_VerifyToken: 'YouCanSetYourOwnToken',
};

const fallback = {
    ...process.env,
    NODE_ENV: undefined,
};

module.exports = (environment) => {
    console.log(`Execution environment selected is: "${environment}"`);
    if (environment === 'production') {
        return production;
    } else if (environment === 'development') {
        return development;
    } else {
        return fallback;
    }
};

En el mismo ./.env.jsarchivo:

  1. Reemplace el valor de Meta_WA_accessTokencon el token de acceso temporal para su aplicación Meta
  2. Reemplace el valor de Meta_WA_SenderPhoneNumberIdcon su ID de número de teléfono
  3. Reemplace el valor de Meta_WA_wabaIdcon su ID de cuenta comercial de WhatsApp
  4. Establezca su propio valor para el Meta_WA_VerifyToken. Puede ser una cadena o un número; verás cómo lo usamos en el paso de webhooks

El código anterior primero importa las variables de entorno actuales y las desestructura, luego agrega nuevas variables de entorno y exporta la combinación de las dos como un objeto.

En el archivo ./app.jsfile, inserte el siguiente código:

process.env = require('./.env.js')(process.env.NODE_ENV || 'development');
const port = process.env.PORT || 9000;
const express = require('express');

let indexRoutes = require('./routes/index.js');

const main = async () => {
    const app = express();
    app.use(express.json());
    app.use(express.urlencoded({ extended: false }));
    app.use('/', indexRoutes);
    app.use('*', (req, res) => res.status(404).send('404 Not Found'));
    app.listen(port, () =>
        console.log(`App now running and listening on port ${port}`)
    );
};
main();

La primera línea del bloque de código anterior simplemente importa el ./.env.jsarchivo y lo asigna a process.env, que es un objeto accesible globalmente en Node.js.

En el archivo ./routes/index.js, inserte el siguiente código:

'use strict';
const router = require('express').Router();

router.get('/meta_wa_callbackurl', (req, res) => {
    try {
        console.log('GET: Someone is pinging me!');

        let mode = req.query['hub.mode'];
        let token = req.query['hub.verify_token'];
        let challenge = req.query['hub.challenge'];

        if (
            mode &&
            token &&
            mode === 'subscribe' &&
            process.env.Meta_WA_VerifyToken === token
        ) {
            return res.status(200).send(challenge);
        } else {
            return res.sendStatus(403);
        }
    } catch (error) {
        console.error({error})
        return res.sendStatus(500);
    }
});

router.post('/meta_wa_callbackurl', async (req, res) => {
    try {
        console.log('POST: Someone is pinging me!');
        return res.sendStatus(200);
    } catch (error) {
                console.error({error})
        return res.sendStatus(500);
    }
});
module.exports = router;

A continuación, abra la terminal y ejecute:

nodemon app.js

El servidor Express se ejecutará en el puerto 9000.

Luego, abra otra terminal separada y ejecute:

ngrok http 9000

Este comando expone nuestra aplicación Express a Internet en general. El objetivo aquí es configurar un webhook al que WhatsApp Cloud pueda hacer ping.

Tome nota de la URL que ngrok asigna a su servidor Express. En mi ejemplo, ngrok me envió esta URL: https://7b9b-102-219-204-54.ngrok.io. Mantenga en funcionamiento tanto el servidor Express como el terminal ngrok.

A continuación, reanudemos nuestro trabajo en el panel de Meta Developer. Desplácese hasta la parte titulada Configurar webhooks para recibir mensajes y haga clic en Configurar webhooks . El enlace mostrará una página que se parece a la siguiente captura de pantalla:

Página de configuración de webhooks

Haga clic en el botón Editar y aparecerá una ventana emergente.

En el campo URL de devolución de llamada , pegue la URL que ngrok le envió y agréguela con la ruta de devolución de llamada, como en la ./routes/index.jsdirectiva. Mi URL completa, en este caso, es https://7b9b-102-219-204-54.ngrok.io/meta_wa_callbackurl.

En el campo Verificar token , ingrese el valor de Meta_WA_VerifyToken tal como aparece en su ./.env.jsarchivo.

Ingresar valor en el campo de token de verificación

Luego haga clic en Verificar y guardar .

Si configuró esto bien, verá un console.logmensaje en la terminal de su servidor Express que dice:

GET: ¡Alguien me está haciendo ping!

Configurando nuestro servidor Express

Ahora, hagamos que nuestro servidor Express reciba mensajes de suscripción de Meta.

En la misma pantalla del tablero de Meta Developers, haga clic en Administrar y aparecerá una ventana emergente.

Administrar la ventana emergente de mensajes de suscripción del servidor express

Seleccione Mensajes y haga clic en Prueba , que se encuentra en la misma fila.

Debería ver un console.logmensaje en la terminal de su servidor Express que dice:

POST: ¡Alguien me está haciendo ping!

Si vio esto, regrese a la misma ventana emergente y haga clic en Suscribirse en la misma fila de mensajes. Luego, haga clic en Listo .

Paso 3: escribir nuestra lógica de negocios

Configuración de una fuente de datos de comercio electrónico

Primero, configuraremos nuestra lógica para obtener datos de FakeStoreAPI, generar una factura en PDF y generar una ubicación ficticia de recogida de pedidos. Envolveremos esta lógica en una clase de JavaScript, que luego importaremos a la lógica de nuestra aplicación.

Cree un archivo y asígnele un nombre ./utils/ecommerce_store.js. En este archivo, pegue el siguiente código:

'use strict';
const request = require('request');
const PDFDocument = require('pdfkit');
const fs = require('fs');

module.exports = class EcommerceStore {
    constructor() {}
    async _fetchAssistant(endpoint) {
        return new Promise((resolve, reject) => {
            request.get(
                `https://fakestoreapi.com${endpoint ? endpoint : '/'}`,
                (error, res, body) => {
                    try {
                        if (error) {
                            reject(error);
                        } else {
                            resolve({
                                status: 'success',
                                data: JSON.parse(body),
                            });
                        }
                    } catch (error) {
                        reject(error);
                    }
                }
            );
        });
    }

    async getProductById(productId) {
        return await this._fetchAssistant(`/products/${productId}`);
    }
    async getAllCategories() {
        return await this._fetchAssistant('/products/categories?limit=100');
    }
    async getProductsInCategory(categoryId) {
        return await this._fetchAssistant(
            `/products/category/${categoryId}?limit=10`
        );
    }

    generatePDFInvoice({ order_details, file_path }) {
        const doc = new PDFDocument();
        doc.pipe(fs.createWriteStream(file_path));
        doc.fontSize(25);
        doc.text(order_details, 100, 100);
        doc.end();
        return;
    }

    generateRandomGeoLocation() {
        let storeLocations = [
            {
                latitude: 44.985613,
                longitude: 20.1568773,
                address: 'New Castle',
            },
            {
                latitude: 36.929749,
                longitude: 98.480195,
                address: 'Glacier Hill',
            },
            {
                latitude: 28.91667,
                longitude: 30.85,
                address: 'Buena Vista',
            },
        ];
        return storeLocations[
            Math.floor(Math.random() * storeLocations.length)
        ];
    }
};

En el código anterior, hemos creado una clase llamada EcommerceStore.

El primer método, _fetchAssistantrecibe un punto final que utiliza para hacer ping a fakestoreapi.com .

Los siguientes métodos actúan como generadores de consultas para el primer método:

  1. getProductById recibe una identificación de producto y luego obtiene datos relacionados con ese producto específico
  2. getAllCategories recupera todas las categorías que están en fakestoreapi.com
  3. getProductsInCategory recibe una categoría de productos y luego procede a buscar todos los productos en esa categoría específica

Estos generadores de consultas invocarán el primer método.

Continuando, el método generatePDFInvoice recibe un fragmento de texto y una ruta de archivo. Luego crea un documento PDF, escribe el texto en él y luego almacena el documento en la ruta del archivo proporcionada.

El método generateRandomGeoLocation simplemente devuelve una geolocalización aleatoria. Este método será útil cuando enviemos el lugar de recogida de pedidos de nuestra tienda a un cliente que quiera recoger su artículo.

Configuración de sesiones de clientes

Para manejar el viaje de nuestro cliente, debemos mantener una sesión que incluya un perfil de cliente y su carrito. Cada cliente tendrá, por lo tanto, su propia sesión única.

En producción, podríamos usar una base de datos como MySQL, MongoDB u otra resistente, pero para que nuestro tutorial sea sencillo y breve, usaremos la estructura de datos de ES2015Map . Con Map, podemos almacenar y recuperar datos iterables específicos, como datos de clientes únicos.

En su ./routes/index.jsarchivo, agregue el siguiente código justo arriba router.get('/meta_wa_callbackurl', (req, res).

const EcommerceStore = require('./../utils/ecommerce_store.js');
let Store = new EcommerceStore();
const CustomerSession = new Map();

router.get('/meta_wa_callbackurl', (req, res) => {//this line already exists. Add the above lines

La primera línea importa la EcommerceStoreclase, mientras que la segunda línea la inicializa. La tercera línea crea la sesión del cliente que usaremos para almacenar el viaje del cliente.

Inicializando nuestra API de WhatsApp Cloud

¿Recuerdas el whatsappcloudapi_wrapperpaquete que instalamos antes? Es hora de importarlo e inicializarlo.

En el ./routes/index.jsarchivo, agregue las siguientes líneas de código debajo de la declaración del enrutador Express:

const router = require('express').Router(); // This line already exists. Below it add  the following lines:

const WhatsappCloudAPI = require('whatsappcloudapi_wrapper');
const Whatsapp = new WhatsappCloudAPI({
    accessToken: process.env.Meta_WA_accessToken,
    senderPhoneNumberId: process.env.Meta_WA_SenderPhoneNumberId,
    WABA_ID: process.env.Meta_WA_wabaId,
});

Los siguientes valores son variables de entorno que definimos en nuestro ./.env.jsarchivo:

  • process.env.Meta_WA_accessToken
  • process.env.Meta_WA_SenderPhoneNumberId
  • process.env.Meta_WA_wabaId

Inicializamos la clase WhatsAppCloudAPI con los tres valores anteriores y nombramos nuestra instancia Whatsapp.

A continuación, analicemos todos los datos que ingresan al /meta_wa_callbackurlwebhook POST. Al analizar el cuerpo de las solicitudes, podremos extraer mensajes y otros detalles, como el nombre del remitente, el número de teléfono del remitente, etc.

Tenga en cuenta : todas las ediciones de código que hagamos desde este punto se realizarán por completo en el ./routes/index.jsarchivo.

Agregue las siguientes líneas de código debajo del paréntesis de apertura de la try{instrucción:

try { // This line already exists. Add the below lines

        let data = Whatsapp.parseMessage(req.body);

        if (data?.isMessage) {
            let incomingMessage = data.message;
            let recipientPhone = incomingMessage.from.phone; // extract the phone number of sender
            let recipientName = incomingMessage.from.name;
            let typeOfMsg = incomingMessage.type; // extract the type of message (some are text, others are images, others are responses to buttons etc...)
            let message_id = incomingMessage.message_id; // extract the message id
        }

Ahora, cuando un cliente nos envíe un mensaje, nuestro webhook debería recibirlo. El mensaje está contenido en el cuerpo de solicitud del webhook. Para extraer información útil del cuerpo de la solicitud, debemos pasar el cuerpo al parseMessagemétodo de la instancia de WhatsApp.

Luego, usando una ifdeclaración, verificamos si el resultado del método contiene un mensaje de WhatsApp válido.

Dentro de la ifdeclaración, definimos incomingMessage, que contiene el mensaje. También definimos otras variables:

  • recipientPhonees el número del cliente que nos envió un mensaje. Les enviaremos un mensaje de respuesta, de ahí el prefijo “destinatario”
  • recipientNamees el nombre del cliente que nos envió un mensaje. Este es el nombre que se han puesto en su perfil de WhatsApp
  • typeOfMsges el tipo de mensaje que un cliente nos envió. Como veremos más adelante, algunos mensajes son textos simples, mientras que otros son respuestas a botones (¡no te preocupes, esto tendrá sentido pronto!)
  • message_ides una cadena de caracteres que identifica de forma única un mensaje que hemos recibido. Esto es útil cuando queremos hacer tareas que son específicas de ese mensaje, como marcar un mensaje como leído

Hasta este punto, todo parece estar bien, pero lo confirmaremos en breve.

Comprender y responder a la intención de nuestro cliente.

Dado que nuestro tutorial no se sumergirá en ninguna forma de IA o procesamiento de lenguaje natural (NLP), definiremos nuestro flujo de chat con una if…elselógica simple.

La lógica de la conversación comienza cuando el cliente envía un mensaje de texto. No miraremos el mensaje en sí, por lo que no sabremos qué pretendían hacer, pero podemos decirle al cliente lo que puede hacer nuestro bot.

Démosle a nuestro cliente un contexto simple, al que pueda responder con una intención específica.

Le daremos al cliente dos botones:

  1. Uno que nos permita saber que quieren hablar con un ser humano real, no con un chatbot.
  2. Otro para buscar productos

Para hacer esto, inserte el siguiente código a continuación message_id:

if (typeOfMsg === 'text_message') {
    await Whatsapp.sendSimpleButtons({
        message: `Hey ${recipientName}, \nYou are speaking to a chatbot.\nWhat do you want to do next?`,
        recipientPhone: recipientPhone, 
        listOfButtons: [
            {
                title: 'View some products',
                id: 'see_categories',
            },
            {
                title: 'Speak to a human',
                id: 'speak_to_human',
            },
        ],
    });
}

La ifdeclaración anterior solo nos permite manejar mensajes de texto.

El sendSimpleButtonsmétodo nos permite enviar botones a un cliente. Tome nota de las propiedades titley id. es lo titleque verá el cliente y ides lo que usaremos para saber en qué botón hizo clic el cliente.

Veamos si lo hicimos bien. Abra su aplicación WhatsApp y envíe un mensaje de texto a la cuenta comercial de WhatsApp.

Enviar mensaje de texto a la cuenta comercial de WhatsApp

Si obtiene una respuesta como la captura de pantalla anterior, ¡felicidades! Acabas de enviar tu primer mensaje a través de la API de WhatsApp Cloud.

Dado que el cliente puede hacer clic en cualquiera de los dos botones, también nos ocuparemos del botón Hablar con una persona.

Fuera de la ifdeclaración de la text_messagelógica, inserte el siguiente código:

if (typeOfMsg === 'simple_button_message') {
    let button_id = incomingMessage.button_reply.id;

    if (button_id === 'speak_to_human') {
        await Whatsapp.sendText({
            recipientPhone: recipientPhone,
            message: `Arguably, chatbots are faster than humans.\nCall my human with the below details:`,
        });

        await Whatsapp.sendContact({
            recipientPhone: recipientPhone,
            contact_profile: {
                addresses: [
                    {
                        city: 'Nairobi',
                        country: 'Kenya',
                    },
                ],
                name: {
                    first_name: 'Daggie',
                    last_name: 'Blanqx',
                },
                org: {
                    company: 'Mom-N-Pop Shop',
                },
                phones: [
                    {
                        phone: '+1 (555) 025-3483',
                    },
                                        {
                        phone: '+254712345678',
                    },
                ],
            },
        });
    }
};

El código anterior realiza dos acciones:

  1. Envía un mensaje de texto para decirle al usuario que recibirá una tarjeta de contacto, usando el sendTextmétodo
  2. Envía una tarjeta de contacto usando el sendContactmétodo

Este código también detecta la intención del usuario usando la ID del botón en el que el usuario hizo clic (en nuestro caso, la ID es el incomingMessage.button_reply.id), y luego responde con las dos opciones de acción.

Ahora, regresa a WhatsApp y haz clic en Hablar con un humano . Si lo hiciste bien, verás una respuesta como la siguiente:

Enviar "Hablar con un humano" y recibir un archivo adjunto de contacto

Al hacer clic en la tarjeta de contacto que recibió, debería ver lo siguiente:

La tarjeta de contacto muestra el nombre completo, la empresa y dos números de teléfono

A continuación, trabajemos en el botón Ver algunos productos .

Dentro de la simple_button_message ifdeclaración, pero justo debajo y fuera de la speak_to_human ifdeclaración, agregue el siguiente código:

if (button_id === 'see_categories') {
    let categories = await Store.getAllCategories(); 
    await Whatsapp.sendSimpleButtons({
        message: `We have several categories.\nChoose one of them.`,
        recipientPhone: recipientPhone, 
        listOfButtons: categories.data
            .map((category) => ({
                title: category,
                id: `category_${category}`,
            }))
            .slice(0, 3)
    });
}

Esto es lo que hace el código anterior:

  1. La ifdeclaración asegura que el usuario hizo clic en el botón Ver algunos productos
  2. Obtiene categorías de productos a FakeStoreAPItravés del getAllCategoriesmétodo
  3. Limita la cantidad de botones a tres usando el método de matriz — slice(0,3)— porque WhatsApp solo nos permite enviar tres botones simples
  4. Luego recorre cada categoría, creando un botón con una title y una identificación única que tiene el prefijo concategory_
  5. Con el sendSimpleButtonsmétodo, enviamos estos botones al cliente.

Regrese nuevamente a su aplicación WhatsApp y haga clic en Ver más productos . Si realizó correctamente los pasos anteriores, debería ver una respuesta similar a la siguiente captura de pantalla:

Enviando "ver algunos productos" en el chat de WhatsApp

Obtención de productos por categoría

Ahora, creemos la lógica para obtener productos en la categoría que seleccionó el cliente.

Todavía dentro de la simple_button_message ifdeclaración, pero debajo y fuera de la see_categories ifdeclaración, agregue el siguiente código:

if (button_id.startsWith('category_')) {
    let selectedCategory = button_id.split('category_')[1];
    let listOfProducts = await Store.getProductsInCategory(selectedCategory);

    let listOfSections = [
        {
            title: ` Top 3: ${selectedCategory}`.substring(0,24),
            rows: listOfProducts.data
                .map((product) => {
                    let id = `product_${product.id}`.substring(0,256);
                    let title = product.title.substring(0,21);
                    let description = `${product.price}\n${product.description}`.substring(0,68);
                   
                    return {
                        id,
                        title: `${title}...`,
                        description: `$${description}...`
                    };
                }).slice(0, 10)
        },
    ];

    await Whatsapp.sendRadioButtons({
        recipientPhone: recipientPhone,
        headerText: `#BlackFriday Offers: ${selectedCategory}`,
        bodyText: `Our Santa  has lined up some great products for you based on your previous shopping history.\n\nPlease select one of the products below:`,
        footerText: 'Powered by: BMI LLC',
        listOfSections,
    });
}

La ifdeclaración anterior confirma que el botón en el que el cliente hizo clic era de hecho el botón que contiene una categoría.

Lo primero que hacemos aquí es extraer la categoría específica de la ID del botón. Luego, consultamos nuestra FakeStoreAPI para productos que pertenecen a esa categoría específica.

Después de consultar, recibimos la lista de productos dentro de una matriz, listOfProducts.data. Ahora recorremos esta matriz, y para cada producto en ella extraemos su precio, título, descripción e ID.

Agregamos product_al id, que nos ayudará a seleccionar la selección de un cliente en el siguiente paso. Asegúrese de recortar la longitud de la identificación, el título y la descripción de acuerdo con las restricciones del botón de radio (o lista) de la API de WhatsApp Cloud .

Luego devolvemos tres valores: ID, título y descripción. Dado que WhatsApp solo nos permite un máximo de 10 filas, limitaremos el número de productos a 10 mediante el método array .slice(0,10).

Después de eso, invocamos el sendRadioButtonsmétodo para enviar los productos a los clientes. Tome nota de las propiedades , , y . headerTextbodyTextfooterTextlistOfSections

Regrese a la aplicación WhatsApp y haga clic en cualquier categoría de productos. Si siguió las instrucciones correctamente, debería ver una respuesta similar a la siguiente captura de pantalla:

Elegir categoría de electrónica y recibir respuesta

Al hacer clic en Seleccionar un producto , debería ver la siguiente pantalla:

Seleccionar una pantalla emergente de productoEn este punto, los clientes pueden seleccionar un producto que les parezca interesante, pero ¿podemos saber qué han seleccionado? Todavía no, así que trabajemos en esta parte.

Fuera de la simple_button_message ifdeclaración, agreguemos otra ifdeclaración:

if (typeOfMsg === 'radio_button_message') {
    let selectionId = incomingMessage.list_reply.id; // the customer clicked and submitted a radio button
    
}

Dentro de la ifdeclaración anterior y justo debajo del selectionId, agregue el siguiente código:

if (selectionId.startsWith('product_')) {
    let product_id = selectionId.split('_')[1];
    let product = await Store.getProductById(product_id);
    const { price, title, description, category, image: imageUrl, rating } = product.data;

    let emojiRating = (rvalue) => {
        rvalue = Math.floor(rvalue || 0); // generate as many star emojis as whole number ratings
        let output = [];
        for (var i = 0; i < rvalue; i++) output.push('');
        return output.length ? output.join('') : 'N/A';
    };

    let text = `_Title_: *${title.trim()}*\n\n\n`;
    text += `_Description_: ${description.trim()}\n\n\n`;
    text += `_Price_: $${price}\n`;
    text += `_Category_: ${category}\n`;
    text += `${rating?.count || 0} shoppers liked this product.\n`;
    text += `_Rated_: ${emojiRating(rating?.rate)}\n`;

    await Whatsapp.sendImage({
        recipientPhone,
        url: imageUrl,
        caption: text,
    });

    await Whatsapp.sendSimpleButtons({
        message: `Here is the product, what do you want to do next?`,
        recipientPhone: recipientPhone, 
        listOfButtons: [
            {
                title: 'Add to cart',
                id: `add_to_cart_${product_id}`,
            },
            {
                title: 'Speak to a human',
                id: 'speak_to_human',
            },
            {
                title: 'See more products',
                id: 'see_categories',
            },
        ],
    });
}

El código anterior hace lo siguiente:

  1. Extrae el ID del producto del botón de radio en el que hizo clic el cliente
  2. Consulta FakeStoreAPI con ese ID de producto
  3. Cuando recibe y extrae los datos del producto, formatea el texto. WhatsApp usa guiones bajos para representar el texto en cursiva, mientras que los asteriscos representan el texto en negrita
  4. Renderiza emoji de estrella usando la emojiRatingfunción. Si una calificación es 3.8, generará emojis de tres estrellas.
  5. Adjunta la imagen del producto al texto renderizado y lo envía usando el sendImagemétodo

Después de esto, enviamos al cliente una lista de tres botones usando el sendSimpleButtons. Uno le da al cliente la oportunidad de agregar productos a su carrito. Tome nota de la identificación del botón que tiene el prefijo add_to_cart_.

Ahora, regrese a su aplicación WhatsApp y seleccione un producto. Si siguió las instrucciones correctamente, debería ver una respuesta similar a la siguiente captura de pantalla:

Chatbot envía al cliente tres botones seleccionables

Creación de sesiones para almacenar carritos de clientes

Para realizar un seguimiento de los productos que un cliente agrega a su carrito, necesitamos tener un lugar para almacenar los artículos del carrito. Aquí es donde CustomerSessionentra en juego. Vamos a añadirle algo de lógica.

Fuera de la radio_button_message ifdeclaración, y justo debajo de la message_iddeclaración, agregue el siguiente código:

let message_id = incomingMessage.message_id; // This line already exists. Add the below lines...

// Start of cart logic
if (!CustomerSession.get(recipientPhone)) {
    CustomerSession.set(recipientPhone, {
        cart: [],
    });
}

let addToCart = async ({ product_id, recipientPhone }) => {
    let product = await Store.getProductById(product_id);
    if (product.status === 'success') {
        CustomerSession.get(recipientPhone).cart.push(product.data);
    }
};

let listOfItemsInCart = ({ recipientPhone }) => {
    let total = 0;
    let products = CustomerSession.get(recipientPhone).cart;
    total = products.reduce(
        (acc, product) => acc + product.price,
        total
    );
    let count = products.length;
    return { total, products, count };
};

let clearCart = ({ recipientPhone }) => {
    CustomerSession.get(recipientPhone).cart = [];
};
// End of cart logic

if (typeOfMsg === 'text_message') { ... // This line already exists. Add the above lines...

El código anterior comprueba si se ha creado la sesión de un cliente. Si no se ha creado, crea una nueva sesión que se identifica de forma única por el número de teléfono del cliente. Luego inicializamos una propiedad llamada cart, que comienza como una matriz vacía.

La addToCartfunción toma en un product_idy el número del cliente específico. Luego, hace ping a FakeStoreAPI para obtener los datos del producto específico y empuja el producto a la cartmatriz.

Luego, la listOfItemsInCart función toma el número de teléfono del cliente y recupera el asociado cart, que se usa para calcular la cantidad de productos en el carrito y la suma de sus precios. Finalmente, devuelve los artículos del carrito y su precio total.

La clearCartfunción toma el número de teléfono del cliente y vacía el carrito de ese cliente.

Una vez terminada la lógica del carrito, construyamos el botón Agregar al carrito . Dentro de la simple_button_message ifdeclaración y debajo de su button_iddeclaración, agregue el siguiente código:

if (button_id.startsWith('add_to_cart_')) {
    let product_id = button_id.split('add_to_cart_')[1];
    await addToCart({ recipientPhone, product_id });
    let numberOfItemsInCart = listOfItemsInCart({ recipientPhone }).count;

    await Whatsapp.sendSimpleButtons({
        message: `Your cart has been updated.\nNumber of items in cart: ${numberOfItemsInCart}.\n\nWhat do you want to do next?`,
        recipientPhone: recipientPhone, 
        listOfButtons: [
            {
                title: 'Checkout ',
                id: `checkout`,
            },
            {
                title: 'See more products',
                id: 'see_categories',
            },
        ],
    });
}

El código anterior extrae el ID del producto del botón en el que hizo clic el cliente, luego invoca la addToCartfunción para guardar el producto en el carrito de la sesión del cliente. Luego, extrae la cantidad de artículos en el carrito de la sesión del cliente y le dice al cliente cuántos productos tiene. También envía dos botones, uno de los cuales permite al usuario realizar el pago.

Tome nota del ID del botón y vuelva a su aplicación de WhatsApp. Haz clic en Añadir al carrito . Si siguió bien las instrucciones, debería ver una respuesta similar a la siguiente captura de pantalla:

Añadir a la cesta

Ahora que nuestros clientes pueden agregar artículos al carrito, podemos escribir la lógica para pagar.

Escribir la lógica de pago

Dentro de la simple_button_message ifdeclaración pero fuera de la add_to_cart_ ifdeclaración, agregue el siguiente código:

if (button_id === 'checkout') {
  let finalBill = listOfItemsInCart({ recipientPhone });
  let invoiceText = `List of items in your cart:\n`;

  finalBill.products.forEach((item, index) => {
      let serial = index + 1;
      invoiceText += `\n#${serial}: ${item.title} @ $${item.price}`;
  });

  invoiceText += `\n\nTotal: $${finalBill.total}`;

  Store.generatePDFInvoice({
      order_details: invoiceText,
      file_path: `./invoice_${recipientName}.pdf`,
  });

  await Whatsapp.sendText({
      message: invoiceText,
      recipientPhone: recipientPhone,
  });

  await Whatsapp.sendSimpleButtons({
      recipientPhone: recipientPhone,
      message: `Thank you for shopping with us, ${recipientName}.\n\nYour order has been received & will be processed shortly.`,
      message_id,
      listOfButtons: [
          {
              title: 'See more products',
              id: 'see_categories',
          },
          {
              title: 'Print my invoice',
              id: 'print_invoice',
          },
      ],
  });

  clearCart({ recipientPhone });
}

El código anterior hace lo siguiente:

  1. Toma todos los artículos en el carrito y los pone dentrofinalBill
  2. Inicializa una variable invoiceText, que contendrá el texto que enviaremos al cliente, así como el texto que se redactará en la versión PDF de la factura.
    1. El forEachciclo simplemente concatena el titley pricede cada producto a la factura
  3. El generatePDFInvoicemétodo (el mismo que definimos en nuestra EcommerceStoreclase) toma los detalles del pedido, redacta un documento PDF y lo guarda en la ruta del archivo en nuestro directorio/carpeta local que le proporcionamos
  4. El sendTextmétodo envía un mensaje de texto simple que contiene los detalles del pedido al cliente
  5. sendSimpleButtonsenvía algunos botones al cliente. Toma nota del botón Imprimir mi factura y su ID
  6. Finalmente, el clearCartmétodo vacía el carro .

Ahora, vuelva a su aplicación WhatsApp y haga clic en Finalizar compra . Si siguió bien las instrucciones, verá una respuesta similar a la siguiente captura de pantalla:

Haciendo clic en el botón de pago

En este punto, el cliente debe recibir una factura en PDF imprimible. Por esta razón, trabajemos en alguna lógica con respecto al botón Imprimir mi factura .

Escribiendo nuestra lógica de factura imprimible

Dentro de la simple_button_message ifdeclaración pero fuera de la checkout ifdeclaración, agregue el siguiente código:

if (button_id === 'print_invoice') {
  // Send the PDF invoice
  await Whatsapp.sendDocument({
      recipientPhone: recipientPhone,
      caption:`Mom-N-Pop Shop invoice #${recipientName}`
      file_path: `./invoice_${recipientName}.pdf`,
  });

  // Send the location of our pickup station to the customer, so they can come and pick up their order
  let warehouse = Store.generateRandomGeoLocation();

  await Whatsapp.sendText({
      recipientPhone: recipientPhone,
      message: `Your order has been fulfilled. Come and pick it up, as you pay, here:`,
  });

  await Whatsapp.sendLocation({
      recipientPhone,
      latitude: warehouse.latitude,
      longitude: warehouse.longitude,
      address: warehouse.address,
      name: 'Mom-N-Pop Shop',
  });
}

El código anterior obtiene el documento PDF generado en el paso anterior del sistema de archivos local y lo envía al cliente utilizando el sendDocumentmétodo.

Cuando un cliente solicita un producto en línea, también necesita saber cómo recibirá el producto físico. Por esta razón, generamos algunas coordenadas aleatorias utilizando el generateRandomGeoLocationmétodo de la EcommerceStoreclase y enviamos estas coordenadas al cliente utilizando el sendLocationmétodo para informarle dónde puede recoger físicamente su producto.

Ahora, abra su aplicación WhatsApp y haga clic en Imprimir mi factura .

Si ha seguido las instrucciones anteriores correctamente, debería ver una respuesta similar a la siguiente captura de pantalla:

Enviar mensaje de texto "imprimir mi factura" y recibir un archivo PDF e instrucciones para recoger el producto.

Mostrar confirmaciones de lectura a los clientes

Por último, es posible que haya notado que las marcas de verificación debajo de los mensajes son grises, en lugar de azules. Esto indica que los mensajes que enviamos no devolvieron recibos de lectura a pesar de que nuestro bot los estaba leyendo.

Las marcas grises pueden ser frustrantes para los clientes y, por este motivo, debemos trabajar para mostrar las marcas azules.

Fuera de la simple_button_message ifdeclaración y antes de la llave de cierre de la data?.isMessage ifdeclaración, agregue el siguiente código:

await Whatsapp.markMessageAsRead({ message_id });

Esta simple línea marca un mensaje como leído tan pronto como lo hayamos respondido.

Ahora, abra su aplicación WhatsApp y envíe un mensaje de texto aleatorio. ¿Estás viendo lo que estoy viendo?

Mensajes "hey" y chatbot responde con mensaje predeterminado

Si sus chats anteriores se han actualizado con marcas azules, ¡felicidades! Has llegado al final de este tutorial y has aprendido algunas cosas en el camino.

Pensamientos finales

Con un total de 2000 millones de usuarios activos mensuales, ignorar WhatsApp como estrategia de comercio electrónico es una forma segura de quedarse atrás de la competencia de su negocio, y dado que la mayoría de sus clientes ya usan WhatsApp en sus actividades diarias, ¿por qué no hacerlo? t su negocio encontrarlos allí?

Espero que este tutorial haya sido útil para desmitificar la API de WhatsApp Cloud, y espero que te hayas divertido en el camino. Cuéntame qué otros temas te pueden interesar y no olvides compartir este artículo con tus círculos tecnológicos.

 Fuente: https://blog.logrocket.com/build-ecommerce-app-whatsapp-cloud-api-node-js/

#whatsapp #ecommerce #cloud #api #nodejs 

What is GEEK

Buddha Community

Cree Una Aplicación De Comercio Electrónico Automatizada Con WhatsApp
Diego  Elizondo

Diego Elizondo

1658842023

Cree Una Aplicación De Comercio Electrónico Automatizada Con WhatsApp

En mayo de 2022, Meta (la empresa antes conocida como Facebook, propietaria de WhatsApp) anunció que abriría al público la API empresarial de WhatsApp. Este artículo pretende darle la bienvenida al mundo de oportunidades de Meta, donde los chatbots de WhatsApp pueden ayudarlo a generar clientes potenciales, recibir pedidos, programar citas, realizar encuestas, recibir comentarios de los clientes, brindar atención al cliente escalable, enviar facturas y recibos, y más.

Este tutorial profundizará en los aspectos técnicos de la creación de un chatbot de WhatsApp desde cero.

Al final de este tutorial, habrá creado su propio chatbot de WhatsApp.

Nuestro tutorial se centra en una sencilla tienda de comercio electrónico familiar que vende artículos para el hogar y moda rápida. El negocio tendrá un chatbot de WhatsApp donde los clientes podrán navegar y comprar en la tienda de comercio electrónico.

Cada tienda de comercio electrónico necesita productos (precios, nombres, descripciones, etc.), y para este tutorial, usaremos los productos ficticios de FakeStoreAPI .

requisitos previos

Antes de continuar, este artículo asume que:

Paso 1: Configurando nuestra aplicación en el tablero de Meta Developer

El primer paso para usar cualquiera de las API de Meta es crear una aplicación en el tablero de Meta, que es gratis.

  • Mientras está conectado a su cuenta de desarrollador de Meta, navegue a https://developers.facebook.com/apps
  • Haz clic en Crear aplicación
  • En la siguiente pantalla, seleccione el tipo de aplicación Business

Selección del tipo de aplicación comercial

  • Luego, complete el nombre de su aplicación y su dirección de correo electrónico, y luego seleccione la página/negocio que desea asociar con esta aplicación

Nombrando la aplicación y seleccionando la página asociada a ella

  • Después de enviar el formulario, accederá a una pantalla que se ve así:

Seleccionando la configuración de WhatsApp

En esta pantalla, seleccione WhatsApp y haga clic en su botón Configurar .

Luego será conducido a una nueva pantalla, como se muestra a continuación.

Página de inicio

En esta pantalla, toma nota de:

  • El ID de la aplicación , que es el ID asociado con nuestra aplicación Meta. El mio es1184643492312754
  • El token de acceso temporal , que caduca a las 24 horas. El mio empieza con EAAQ1bU6LdrIBA...
  • El número de teléfono de prueba , que usaremos para enviar mensajes a los clientes. El mio es+1 555 025 3483
    • El ID del número de teléfono . El mio es113362588047543
    • El ID de la cuenta comercial de WhatsApp . El mio es102432872486730

Tenga en cuenta que el token de acceso temporal caduca después de 24 horas, momento en el que tendremos que renovarlo. Cuando cambia su aplicación al modo en vivo, puede solicitar un token de acceso permanente, que no necesitamos hacer ya que nuestra aplicación está en modo de desarrollo.

El ID del número de teléfono y el ID de la cuenta comercial de WhatsApp están vinculados al número de teléfono de prueba.

A continuación, agreguemos un número de teléfono para usar para recibir mensajes.

En el modo de desarrollo, Meta nos restringe a cinco números de destinatarios por motivos relacionados con la prevención del spam/uso indebido. En el modo en vivo/producción, el número representa los números de teléfono de nuestros clientes.

Haga clic en Seleccione un número de teléfono del destinatario y agregue su propio número de WhatsApp, como se muestra en la siguiente captura de pantalla:

Agregar un cuadro de diálogo de número de teléfono del destinatario

Después de agregar su número de destinatario, verá una pantalla similar a la siguiente. Si es la primera vez que agrega su número de teléfono a las plataformas Meta, como las páginas de Facebook, la suite Meta Business o el panel de desarrollo de Meta, recibirá un mensaje OTP de Facebook Business que le pedirá que verifique que realmente es el propietario del número del destinatario. .

Enviar mensajes con la API

Probando nuestra configuración

Probemos si todo hasta este paso funcionó bien. Lo haremos haciendo clic en el botón Enviar mensaje .

Si todo está bien, debería ver un mensaje en su bandeja de entrada de WhatsApp desde su número de prueba.

Mensaje de Hello World de Facebook en la bandeja de entrada de WhatsApp

Hasta este punto, ¡lo estamos haciendo bien! Haz una pausa y abre tu editor de código. No cierres la pestaña de tu navegador todavía porque volveremos al panel de Meta Developer en unos minutos.

Paso 2: Configuración de webhooks para recibir mensajes

Ahora que nuestra configuración puede enviar mensajes con éxito, configuremos una forma de recibir mensajes. Es hora de ensuciarse las manos y sumergirnos en la escritura de código. Todo el código que escribiremos para este tutorial está en este repositorio de GitHub .

Cree una nueva carpeta para contener nuestro proyecto. Abra esta carpeta en una terminal y ejecute el siguiente script:

npm init ---yes

A continuación, instalamos algunos paquetes:

npm install express pdfkit request whatsappcloudapi_wrapper
npm install nodemon --dev

He aquí una breve explicación de cada uno:

  • El expresspaquete es importante para configurar nuestro servidor. El servidor contendrá una ruta que actuará como nuestro webhook.
  • El pdfkitpaquete se utilizará para generar facturas para nuestros clientes cuando realicen el pago.
  • El request paquete nos ayudará a ejecutar solicitudes de recuperación a FakeStoreAPI
  • El whatsappcloudapi_wrappernos ayuda a enviar y recibir mensajes de WhatsApp

A continuación, vamos a crear tres archivos:

  1. ./app.js
  2. ./.env.js
  3. ./routes/index.js

En nuestro ./.env.jsarchivo, escriba el siguiente código:

const production = {
    ...process.env,
    NODE_ENV: process.env.NODE_ENV || 'production',
};

const development = {
    ...process.env,
    NODE_ENV: process.env.NODE_ENV || 'development',
    PORT: '9000',
    Meta_WA_accessToken:'EAAKGUD3eZA28BADAJOmO6L19TmZAIEUpdFGHEGHX5sQ3kk4LDQLlnyh607rKSr0x2SAOPJS0kXOUZAhRDIPPGs4vcXQCo2DnfSJMnnIzFW7vaw8EuL7A0HjGZBwE8VwjRnBNam0ARLmfyOCEh1',
    Meta_WA_SenderPhoneNumberId: '113362588047543',
    Meta_WA_wabaId: '102432872486730',
    Meta_WA_VerifyToken: 'YouCanSetYourOwnToken',
};

const fallback = {
    ...process.env,
    NODE_ENV: undefined,
};

module.exports = (environment) => {
    console.log(`Execution environment selected is: "${environment}"`);
    if (environment === 'production') {
        return production;
    } else if (environment === 'development') {
        return development;
    } else {
        return fallback;
    }
};

En el mismo ./.env.jsarchivo:

  1. Reemplace el valor de Meta_WA_accessTokencon el token de acceso temporal para su aplicación Meta
  2. Reemplace el valor de Meta_WA_SenderPhoneNumberIdcon su ID de número de teléfono
  3. Reemplace el valor de Meta_WA_wabaIdcon su ID de cuenta comercial de WhatsApp
  4. Establezca su propio valor para el Meta_WA_VerifyToken. Puede ser una cadena o un número; verás cómo lo usamos en el paso de webhooks

El código anterior primero importa las variables de entorno actuales y las desestructura, luego agrega nuevas variables de entorno y exporta la combinación de las dos como un objeto.

En el archivo ./app.jsfile, inserte el siguiente código:

process.env = require('./.env.js')(process.env.NODE_ENV || 'development');
const port = process.env.PORT || 9000;
const express = require('express');

let indexRoutes = require('./routes/index.js');

const main = async () => {
    const app = express();
    app.use(express.json());
    app.use(express.urlencoded({ extended: false }));
    app.use('/', indexRoutes);
    app.use('*', (req, res) => res.status(404).send('404 Not Found'));
    app.listen(port, () =>
        console.log(`App now running and listening on port ${port}`)
    );
};
main();

La primera línea del bloque de código anterior simplemente importa el ./.env.jsarchivo y lo asigna a process.env, que es un objeto accesible globalmente en Node.js.

En el archivo ./routes/index.js, inserte el siguiente código:

'use strict';
const router = require('express').Router();

router.get('/meta_wa_callbackurl', (req, res) => {
    try {
        console.log('GET: Someone is pinging me!');

        let mode = req.query['hub.mode'];
        let token = req.query['hub.verify_token'];
        let challenge = req.query['hub.challenge'];

        if (
            mode &&
            token &&
            mode === 'subscribe' &&
            process.env.Meta_WA_VerifyToken === token
        ) {
            return res.status(200).send(challenge);
        } else {
            return res.sendStatus(403);
        }
    } catch (error) {
        console.error({error})
        return res.sendStatus(500);
    }
});

router.post('/meta_wa_callbackurl', async (req, res) => {
    try {
        console.log('POST: Someone is pinging me!');
        return res.sendStatus(200);
    } catch (error) {
                console.error({error})
        return res.sendStatus(500);
    }
});
module.exports = router;

A continuación, abra la terminal y ejecute:

nodemon app.js

El servidor Express se ejecutará en el puerto 9000.

Luego, abra otra terminal separada y ejecute:

ngrok http 9000

Este comando expone nuestra aplicación Express a Internet en general. El objetivo aquí es configurar un webhook al que WhatsApp Cloud pueda hacer ping.

Tome nota de la URL que ngrok asigna a su servidor Express. En mi ejemplo, ngrok me envió esta URL: https://7b9b-102-219-204-54.ngrok.io. Mantenga en funcionamiento tanto el servidor Express como el terminal ngrok.

A continuación, reanudemos nuestro trabajo en el panel de Meta Developer. Desplácese hasta la parte titulada Configurar webhooks para recibir mensajes y haga clic en Configurar webhooks . El enlace mostrará una página que se parece a la siguiente captura de pantalla:

Página de configuración de webhooks

Haga clic en el botón Editar y aparecerá una ventana emergente.

En el campo URL de devolución de llamada , pegue la URL que ngrok le envió y agréguela con la ruta de devolución de llamada, como en la ./routes/index.jsdirectiva. Mi URL completa, en este caso, es https://7b9b-102-219-204-54.ngrok.io/meta_wa_callbackurl.

En el campo Verificar token , ingrese el valor de Meta_WA_VerifyToken tal como aparece en su ./.env.jsarchivo.

Ingresar valor en el campo de token de verificación

Luego haga clic en Verificar y guardar .

Si configuró esto bien, verá un console.logmensaje en la terminal de su servidor Express que dice:

GET: ¡Alguien me está haciendo ping!

Configurando nuestro servidor Express

Ahora, hagamos que nuestro servidor Express reciba mensajes de suscripción de Meta.

En la misma pantalla del tablero de Meta Developers, haga clic en Administrar y aparecerá una ventana emergente.

Administrar la ventana emergente de mensajes de suscripción del servidor express

Seleccione Mensajes y haga clic en Prueba , que se encuentra en la misma fila.

Debería ver un console.logmensaje en la terminal de su servidor Express que dice:

POST: ¡Alguien me está haciendo ping!

Si vio esto, regrese a la misma ventana emergente y haga clic en Suscribirse en la misma fila de mensajes. Luego, haga clic en Listo .

Paso 3: escribir nuestra lógica de negocios

Configuración de una fuente de datos de comercio electrónico

Primero, configuraremos nuestra lógica para obtener datos de FakeStoreAPI, generar una factura en PDF y generar una ubicación ficticia de recogida de pedidos. Envolveremos esta lógica en una clase de JavaScript, que luego importaremos a la lógica de nuestra aplicación.

Cree un archivo y asígnele un nombre ./utils/ecommerce_store.js. En este archivo, pegue el siguiente código:

'use strict';
const request = require('request');
const PDFDocument = require('pdfkit');
const fs = require('fs');

module.exports = class EcommerceStore {
    constructor() {}
    async _fetchAssistant(endpoint) {
        return new Promise((resolve, reject) => {
            request.get(
                `https://fakestoreapi.com${endpoint ? endpoint : '/'}`,
                (error, res, body) => {
                    try {
                        if (error) {
                            reject(error);
                        } else {
                            resolve({
                                status: 'success',
                                data: JSON.parse(body),
                            });
                        }
                    } catch (error) {
                        reject(error);
                    }
                }
            );
        });
    }

    async getProductById(productId) {
        return await this._fetchAssistant(`/products/${productId}`);
    }
    async getAllCategories() {
        return await this._fetchAssistant('/products/categories?limit=100');
    }
    async getProductsInCategory(categoryId) {
        return await this._fetchAssistant(
            `/products/category/${categoryId}?limit=10`
        );
    }

    generatePDFInvoice({ order_details, file_path }) {
        const doc = new PDFDocument();
        doc.pipe(fs.createWriteStream(file_path));
        doc.fontSize(25);
        doc.text(order_details, 100, 100);
        doc.end();
        return;
    }

    generateRandomGeoLocation() {
        let storeLocations = [
            {
                latitude: 44.985613,
                longitude: 20.1568773,
                address: 'New Castle',
            },
            {
                latitude: 36.929749,
                longitude: 98.480195,
                address: 'Glacier Hill',
            },
            {
                latitude: 28.91667,
                longitude: 30.85,
                address: 'Buena Vista',
            },
        ];
        return storeLocations[
            Math.floor(Math.random() * storeLocations.length)
        ];
    }
};

En el código anterior, hemos creado una clase llamada EcommerceStore.

El primer método, _fetchAssistantrecibe un punto final que utiliza para hacer ping a fakestoreapi.com .

Los siguientes métodos actúan como generadores de consultas para el primer método:

  1. getProductById recibe una identificación de producto y luego obtiene datos relacionados con ese producto específico
  2. getAllCategories recupera todas las categorías que están en fakestoreapi.com
  3. getProductsInCategory recibe una categoría de productos y luego procede a buscar todos los productos en esa categoría específica

Estos generadores de consultas invocarán el primer método.

Continuando, el método generatePDFInvoice recibe un fragmento de texto y una ruta de archivo. Luego crea un documento PDF, escribe el texto en él y luego almacena el documento en la ruta del archivo proporcionada.

El método generateRandomGeoLocation simplemente devuelve una geolocalización aleatoria. Este método será útil cuando enviemos el lugar de recogida de pedidos de nuestra tienda a un cliente que quiera recoger su artículo.

Configuración de sesiones de clientes

Para manejar el viaje de nuestro cliente, debemos mantener una sesión que incluya un perfil de cliente y su carrito. Cada cliente tendrá, por lo tanto, su propia sesión única.

En producción, podríamos usar una base de datos como MySQL, MongoDB u otra resistente, pero para que nuestro tutorial sea sencillo y breve, usaremos la estructura de datos de ES2015Map . Con Map, podemos almacenar y recuperar datos iterables específicos, como datos de clientes únicos.

En su ./routes/index.jsarchivo, agregue el siguiente código justo arriba router.get('/meta_wa_callbackurl', (req, res).

const EcommerceStore = require('./../utils/ecommerce_store.js');
let Store = new EcommerceStore();
const CustomerSession = new Map();

router.get('/meta_wa_callbackurl', (req, res) => {//this line already exists. Add the above lines

La primera línea importa la EcommerceStoreclase, mientras que la segunda línea la inicializa. La tercera línea crea la sesión del cliente que usaremos para almacenar el viaje del cliente.

Inicializando nuestra API de WhatsApp Cloud

¿Recuerdas el whatsappcloudapi_wrapperpaquete que instalamos antes? Es hora de importarlo e inicializarlo.

En el ./routes/index.jsarchivo, agregue las siguientes líneas de código debajo de la declaración del enrutador Express:

const router = require('express').Router(); // This line already exists. Below it add  the following lines:

const WhatsappCloudAPI = require('whatsappcloudapi_wrapper');
const Whatsapp = new WhatsappCloudAPI({
    accessToken: process.env.Meta_WA_accessToken,
    senderPhoneNumberId: process.env.Meta_WA_SenderPhoneNumberId,
    WABA_ID: process.env.Meta_WA_wabaId,
});

Los siguientes valores son variables de entorno que definimos en nuestro ./.env.jsarchivo:

  • process.env.Meta_WA_accessToken
  • process.env.Meta_WA_SenderPhoneNumberId
  • process.env.Meta_WA_wabaId

Inicializamos la clase WhatsAppCloudAPI con los tres valores anteriores y nombramos nuestra instancia Whatsapp.

A continuación, analicemos todos los datos que ingresan al /meta_wa_callbackurlwebhook POST. Al analizar el cuerpo de las solicitudes, podremos extraer mensajes y otros detalles, como el nombre del remitente, el número de teléfono del remitente, etc.

Tenga en cuenta : todas las ediciones de código que hagamos desde este punto se realizarán por completo en el ./routes/index.jsarchivo.

Agregue las siguientes líneas de código debajo del paréntesis de apertura de la try{instrucción:

try { // This line already exists. Add the below lines

        let data = Whatsapp.parseMessage(req.body);

        if (data?.isMessage) {
            let incomingMessage = data.message;
            let recipientPhone = incomingMessage.from.phone; // extract the phone number of sender
            let recipientName = incomingMessage.from.name;
            let typeOfMsg = incomingMessage.type; // extract the type of message (some are text, others are images, others are responses to buttons etc...)
            let message_id = incomingMessage.message_id; // extract the message id
        }

Ahora, cuando un cliente nos envíe un mensaje, nuestro webhook debería recibirlo. El mensaje está contenido en el cuerpo de solicitud del webhook. Para extraer información útil del cuerpo de la solicitud, debemos pasar el cuerpo al parseMessagemétodo de la instancia de WhatsApp.

Luego, usando una ifdeclaración, verificamos si el resultado del método contiene un mensaje de WhatsApp válido.

Dentro de la ifdeclaración, definimos incomingMessage, que contiene el mensaje. También definimos otras variables:

  • recipientPhonees el número del cliente que nos envió un mensaje. Les enviaremos un mensaje de respuesta, de ahí el prefijo “destinatario”
  • recipientNamees el nombre del cliente que nos envió un mensaje. Este es el nombre que se han puesto en su perfil de WhatsApp
  • typeOfMsges el tipo de mensaje que un cliente nos envió. Como veremos más adelante, algunos mensajes son textos simples, mientras que otros son respuestas a botones (¡no te preocupes, esto tendrá sentido pronto!)
  • message_ides una cadena de caracteres que identifica de forma única un mensaje que hemos recibido. Esto es útil cuando queremos hacer tareas que son específicas de ese mensaje, como marcar un mensaje como leído

Hasta este punto, todo parece estar bien, pero lo confirmaremos en breve.

Comprender y responder a la intención de nuestro cliente.

Dado que nuestro tutorial no se sumergirá en ninguna forma de IA o procesamiento de lenguaje natural (NLP), definiremos nuestro flujo de chat con una if…elselógica simple.

La lógica de la conversación comienza cuando el cliente envía un mensaje de texto. No miraremos el mensaje en sí, por lo que no sabremos qué pretendían hacer, pero podemos decirle al cliente lo que puede hacer nuestro bot.

Démosle a nuestro cliente un contexto simple, al que pueda responder con una intención específica.

Le daremos al cliente dos botones:

  1. Uno que nos permita saber que quieren hablar con un ser humano real, no con un chatbot.
  2. Otro para buscar productos

Para hacer esto, inserte el siguiente código a continuación message_id:

if (typeOfMsg === 'text_message') {
    await Whatsapp.sendSimpleButtons({
        message: `Hey ${recipientName}, \nYou are speaking to a chatbot.\nWhat do you want to do next?`,
        recipientPhone: recipientPhone, 
        listOfButtons: [
            {
                title: 'View some products',
                id: 'see_categories',
            },
            {
                title: 'Speak to a human',
                id: 'speak_to_human',
            },
        ],
    });
}

La ifdeclaración anterior solo nos permite manejar mensajes de texto.

El sendSimpleButtonsmétodo nos permite enviar botones a un cliente. Tome nota de las propiedades titley id. es lo titleque verá el cliente y ides lo que usaremos para saber en qué botón hizo clic el cliente.

Veamos si lo hicimos bien. Abra su aplicación WhatsApp y envíe un mensaje de texto a la cuenta comercial de WhatsApp.

Enviar mensaje de texto a la cuenta comercial de WhatsApp

Si obtiene una respuesta como la captura de pantalla anterior, ¡felicidades! Acabas de enviar tu primer mensaje a través de la API de WhatsApp Cloud.

Dado que el cliente puede hacer clic en cualquiera de los dos botones, también nos ocuparemos del botón Hablar con una persona.

Fuera de la ifdeclaración de la text_messagelógica, inserte el siguiente código:

if (typeOfMsg === 'simple_button_message') {
    let button_id = incomingMessage.button_reply.id;

    if (button_id === 'speak_to_human') {
        await Whatsapp.sendText({
            recipientPhone: recipientPhone,
            message: `Arguably, chatbots are faster than humans.\nCall my human with the below details:`,
        });

        await Whatsapp.sendContact({
            recipientPhone: recipientPhone,
            contact_profile: {
                addresses: [
                    {
                        city: 'Nairobi',
                        country: 'Kenya',
                    },
                ],
                name: {
                    first_name: 'Daggie',
                    last_name: 'Blanqx',
                },
                org: {
                    company: 'Mom-N-Pop Shop',
                },
                phones: [
                    {
                        phone: '+1 (555) 025-3483',
                    },
                                        {
                        phone: '+254712345678',
                    },
                ],
            },
        });
    }
};

El código anterior realiza dos acciones:

  1. Envía un mensaje de texto para decirle al usuario que recibirá una tarjeta de contacto, usando el sendTextmétodo
  2. Envía una tarjeta de contacto usando el sendContactmétodo

Este código también detecta la intención del usuario usando la ID del botón en el que el usuario hizo clic (en nuestro caso, la ID es el incomingMessage.button_reply.id), y luego responde con las dos opciones de acción.

Ahora, regresa a WhatsApp y haz clic en Hablar con un humano . Si lo hiciste bien, verás una respuesta como la siguiente:

Enviar "Hablar con un humano" y recibir un archivo adjunto de contacto

Al hacer clic en la tarjeta de contacto que recibió, debería ver lo siguiente:

La tarjeta de contacto muestra el nombre completo, la empresa y dos números de teléfono

A continuación, trabajemos en el botón Ver algunos productos .

Dentro de la simple_button_message ifdeclaración, pero justo debajo y fuera de la speak_to_human ifdeclaración, agregue el siguiente código:

if (button_id === 'see_categories') {
    let categories = await Store.getAllCategories(); 
    await Whatsapp.sendSimpleButtons({
        message: `We have several categories.\nChoose one of them.`,
        recipientPhone: recipientPhone, 
        listOfButtons: categories.data
            .map((category) => ({
                title: category,
                id: `category_${category}`,
            }))
            .slice(0, 3)
    });
}

Esto es lo que hace el código anterior:

  1. La ifdeclaración asegura que el usuario hizo clic en el botón Ver algunos productos
  2. Obtiene categorías de productos a FakeStoreAPItravés del getAllCategoriesmétodo
  3. Limita la cantidad de botones a tres usando el método de matriz — slice(0,3)— porque WhatsApp solo nos permite enviar tres botones simples
  4. Luego recorre cada categoría, creando un botón con una title y una identificación única que tiene el prefijo concategory_
  5. Con el sendSimpleButtonsmétodo, enviamos estos botones al cliente.

Regrese nuevamente a su aplicación WhatsApp y haga clic en Ver más productos . Si realizó correctamente los pasos anteriores, debería ver una respuesta similar a la siguiente captura de pantalla:

Enviando "ver algunos productos" en el chat de WhatsApp

Obtención de productos por categoría

Ahora, creemos la lógica para obtener productos en la categoría que seleccionó el cliente.

Todavía dentro de la simple_button_message ifdeclaración, pero debajo y fuera de la see_categories ifdeclaración, agregue el siguiente código:

if (button_id.startsWith('category_')) {
    let selectedCategory = button_id.split('category_')[1];
    let listOfProducts = await Store.getProductsInCategory(selectedCategory);

    let listOfSections = [
        {
            title: ` Top 3: ${selectedCategory}`.substring(0,24),
            rows: listOfProducts.data
                .map((product) => {
                    let id = `product_${product.id}`.substring(0,256);
                    let title = product.title.substring(0,21);
                    let description = `${product.price}\n${product.description}`.substring(0,68);
                   
                    return {
                        id,
                        title: `${title}...`,
                        description: `$${description}...`
                    };
                }).slice(0, 10)
        },
    ];

    await Whatsapp.sendRadioButtons({
        recipientPhone: recipientPhone,
        headerText: `#BlackFriday Offers: ${selectedCategory}`,
        bodyText: `Our Santa  has lined up some great products for you based on your previous shopping history.\n\nPlease select one of the products below:`,
        footerText: 'Powered by: BMI LLC',
        listOfSections,
    });
}

La ifdeclaración anterior confirma que el botón en el que el cliente hizo clic era de hecho el botón que contiene una categoría.

Lo primero que hacemos aquí es extraer la categoría específica de la ID del botón. Luego, consultamos nuestra FakeStoreAPI para productos que pertenecen a esa categoría específica.

Después de consultar, recibimos la lista de productos dentro de una matriz, listOfProducts.data. Ahora recorremos esta matriz, y para cada producto en ella extraemos su precio, título, descripción e ID.

Agregamos product_al id, que nos ayudará a seleccionar la selección de un cliente en el siguiente paso. Asegúrese de recortar la longitud de la identificación, el título y la descripción de acuerdo con las restricciones del botón de radio (o lista) de la API de WhatsApp Cloud .

Luego devolvemos tres valores: ID, título y descripción. Dado que WhatsApp solo nos permite un máximo de 10 filas, limitaremos el número de productos a 10 mediante el método array .slice(0,10).

Después de eso, invocamos el sendRadioButtonsmétodo para enviar los productos a los clientes. Tome nota de las propiedades , , y . headerTextbodyTextfooterTextlistOfSections

Regrese a la aplicación WhatsApp y haga clic en cualquier categoría de productos. Si siguió las instrucciones correctamente, debería ver una respuesta similar a la siguiente captura de pantalla:

Elegir categoría de electrónica y recibir respuesta

Al hacer clic en Seleccionar un producto , debería ver la siguiente pantalla:

Seleccionar una pantalla emergente de productoEn este punto, los clientes pueden seleccionar un producto que les parezca interesante, pero ¿podemos saber qué han seleccionado? Todavía no, así que trabajemos en esta parte.

Fuera de la simple_button_message ifdeclaración, agreguemos otra ifdeclaración:

if (typeOfMsg === 'radio_button_message') {
    let selectionId = incomingMessage.list_reply.id; // the customer clicked and submitted a radio button
    
}

Dentro de la ifdeclaración anterior y justo debajo del selectionId, agregue el siguiente código:

if (selectionId.startsWith('product_')) {
    let product_id = selectionId.split('_')[1];
    let product = await Store.getProductById(product_id);
    const { price, title, description, category, image: imageUrl, rating } = product.data;

    let emojiRating = (rvalue) => {
        rvalue = Math.floor(rvalue || 0); // generate as many star emojis as whole number ratings
        let output = [];
        for (var i = 0; i < rvalue; i++) output.push('');
        return output.length ? output.join('') : 'N/A';
    };

    let text = `_Title_: *${title.trim()}*\n\n\n`;
    text += `_Description_: ${description.trim()}\n\n\n`;
    text += `_Price_: $${price}\n`;
    text += `_Category_: ${category}\n`;
    text += `${rating?.count || 0} shoppers liked this product.\n`;
    text += `_Rated_: ${emojiRating(rating?.rate)}\n`;

    await Whatsapp.sendImage({
        recipientPhone,
        url: imageUrl,
        caption: text,
    });

    await Whatsapp.sendSimpleButtons({
        message: `Here is the product, what do you want to do next?`,
        recipientPhone: recipientPhone, 
        listOfButtons: [
            {
                title: 'Add to cart',
                id: `add_to_cart_${product_id}`,
            },
            {
                title: 'Speak to a human',
                id: 'speak_to_human',
            },
            {
                title: 'See more products',
                id: 'see_categories',
            },
        ],
    });
}

El código anterior hace lo siguiente:

  1. Extrae el ID del producto del botón de radio en el que hizo clic el cliente
  2. Consulta FakeStoreAPI con ese ID de producto
  3. Cuando recibe y extrae los datos del producto, formatea el texto. WhatsApp usa guiones bajos para representar el texto en cursiva, mientras que los asteriscos representan el texto en negrita
  4. Renderiza emoji de estrella usando la emojiRatingfunción. Si una calificación es 3.8, generará emojis de tres estrellas.
  5. Adjunta la imagen del producto al texto renderizado y lo envía usando el sendImagemétodo

Después de esto, enviamos al cliente una lista de tres botones usando el sendSimpleButtons. Uno le da al cliente la oportunidad de agregar productos a su carrito. Tome nota de la identificación del botón que tiene el prefijo add_to_cart_.

Ahora, regrese a su aplicación WhatsApp y seleccione un producto. Si siguió las instrucciones correctamente, debería ver una respuesta similar a la siguiente captura de pantalla:

Chatbot envía al cliente tres botones seleccionables

Creación de sesiones para almacenar carritos de clientes

Para realizar un seguimiento de los productos que un cliente agrega a su carrito, necesitamos tener un lugar para almacenar los artículos del carrito. Aquí es donde CustomerSessionentra en juego. Vamos a añadirle algo de lógica.

Fuera de la radio_button_message ifdeclaración, y justo debajo de la message_iddeclaración, agregue el siguiente código:

let message_id = incomingMessage.message_id; // This line already exists. Add the below lines...

// Start of cart logic
if (!CustomerSession.get(recipientPhone)) {
    CustomerSession.set(recipientPhone, {
        cart: [],
    });
}

let addToCart = async ({ product_id, recipientPhone }) => {
    let product = await Store.getProductById(product_id);
    if (product.status === 'success') {
        CustomerSession.get(recipientPhone).cart.push(product.data);
    }
};

let listOfItemsInCart = ({ recipientPhone }) => {
    let total = 0;
    let products = CustomerSession.get(recipientPhone).cart;
    total = products.reduce(
        (acc, product) => acc + product.price,
        total
    );
    let count = products.length;
    return { total, products, count };
};

let clearCart = ({ recipientPhone }) => {
    CustomerSession.get(recipientPhone).cart = [];
};
// End of cart logic

if (typeOfMsg === 'text_message') { ... // This line already exists. Add the above lines...

El código anterior comprueba si se ha creado la sesión de un cliente. Si no se ha creado, crea una nueva sesión que se identifica de forma única por el número de teléfono del cliente. Luego inicializamos una propiedad llamada cart, que comienza como una matriz vacía.

La addToCartfunción toma en un product_idy el número del cliente específico. Luego, hace ping a FakeStoreAPI para obtener los datos del producto específico y empuja el producto a la cartmatriz.

Luego, la listOfItemsInCart función toma el número de teléfono del cliente y recupera el asociado cart, que se usa para calcular la cantidad de productos en el carrito y la suma de sus precios. Finalmente, devuelve los artículos del carrito y su precio total.

La clearCartfunción toma el número de teléfono del cliente y vacía el carrito de ese cliente.

Una vez terminada la lógica del carrito, construyamos el botón Agregar al carrito . Dentro de la simple_button_message ifdeclaración y debajo de su button_iddeclaración, agregue el siguiente código:

if (button_id.startsWith('add_to_cart_')) {
    let product_id = button_id.split('add_to_cart_')[1];
    await addToCart({ recipientPhone, product_id });
    let numberOfItemsInCart = listOfItemsInCart({ recipientPhone }).count;

    await Whatsapp.sendSimpleButtons({
        message: `Your cart has been updated.\nNumber of items in cart: ${numberOfItemsInCart}.\n\nWhat do you want to do next?`,
        recipientPhone: recipientPhone, 
        listOfButtons: [
            {
                title: 'Checkout ',
                id: `checkout`,
            },
            {
                title: 'See more products',
                id: 'see_categories',
            },
        ],
    });
}

El código anterior extrae el ID del producto del botón en el que hizo clic el cliente, luego invoca la addToCartfunción para guardar el producto en el carrito de la sesión del cliente. Luego, extrae la cantidad de artículos en el carrito de la sesión del cliente y le dice al cliente cuántos productos tiene. También envía dos botones, uno de los cuales permite al usuario realizar el pago.

Tome nota del ID del botón y vuelva a su aplicación de WhatsApp. Haz clic en Añadir al carrito . Si siguió bien las instrucciones, debería ver una respuesta similar a la siguiente captura de pantalla:

Añadir a la cesta

Ahora que nuestros clientes pueden agregar artículos al carrito, podemos escribir la lógica para pagar.

Escribir la lógica de pago

Dentro de la simple_button_message ifdeclaración pero fuera de la add_to_cart_ ifdeclaración, agregue el siguiente código:

if (button_id === 'checkout') {
  let finalBill = listOfItemsInCart({ recipientPhone });
  let invoiceText = `List of items in your cart:\n`;

  finalBill.products.forEach((item, index) => {
      let serial = index + 1;
      invoiceText += `\n#${serial}: ${item.title} @ $${item.price}`;
  });

  invoiceText += `\n\nTotal: $${finalBill.total}`;

  Store.generatePDFInvoice({
      order_details: invoiceText,
      file_path: `./invoice_${recipientName}.pdf`,
  });

  await Whatsapp.sendText({
      message: invoiceText,
      recipientPhone: recipientPhone,
  });

  await Whatsapp.sendSimpleButtons({
      recipientPhone: recipientPhone,
      message: `Thank you for shopping with us, ${recipientName}.\n\nYour order has been received & will be processed shortly.`,
      message_id,
      listOfButtons: [
          {
              title: 'See more products',
              id: 'see_categories',
          },
          {
              title: 'Print my invoice',
              id: 'print_invoice',
          },
      ],
  });

  clearCart({ recipientPhone });
}

El código anterior hace lo siguiente:

  1. Toma todos los artículos en el carrito y los pone dentrofinalBill
  2. Inicializa una variable invoiceText, que contendrá el texto que enviaremos al cliente, así como el texto que se redactará en la versión PDF de la factura.
    1. El forEachciclo simplemente concatena el titley pricede cada producto a la factura
  3. El generatePDFInvoicemétodo (el mismo que definimos en nuestra EcommerceStoreclase) toma los detalles del pedido, redacta un documento PDF y lo guarda en la ruta del archivo en nuestro directorio/carpeta local que le proporcionamos
  4. El sendTextmétodo envía un mensaje de texto simple que contiene los detalles del pedido al cliente
  5. sendSimpleButtonsenvía algunos botones al cliente. Toma nota del botón Imprimir mi factura y su ID
  6. Finalmente, el clearCartmétodo vacía el carro .

Ahora, vuelva a su aplicación WhatsApp y haga clic en Finalizar compra . Si siguió bien las instrucciones, verá una respuesta similar a la siguiente captura de pantalla:

Haciendo clic en el botón de pago

En este punto, el cliente debe recibir una factura en PDF imprimible. Por esta razón, trabajemos en alguna lógica con respecto al botón Imprimir mi factura .

Escribiendo nuestra lógica de factura imprimible

Dentro de la simple_button_message ifdeclaración pero fuera de la checkout ifdeclaración, agregue el siguiente código:

if (button_id === 'print_invoice') {
  // Send the PDF invoice
  await Whatsapp.sendDocument({
      recipientPhone: recipientPhone,
      caption:`Mom-N-Pop Shop invoice #${recipientName}`
      file_path: `./invoice_${recipientName}.pdf`,
  });

  // Send the location of our pickup station to the customer, so they can come and pick up their order
  let warehouse = Store.generateRandomGeoLocation();

  await Whatsapp.sendText({
      recipientPhone: recipientPhone,
      message: `Your order has been fulfilled. Come and pick it up, as you pay, here:`,
  });

  await Whatsapp.sendLocation({
      recipientPhone,
      latitude: warehouse.latitude,
      longitude: warehouse.longitude,
      address: warehouse.address,
      name: 'Mom-N-Pop Shop',
  });
}

El código anterior obtiene el documento PDF generado en el paso anterior del sistema de archivos local y lo envía al cliente utilizando el sendDocumentmétodo.

Cuando un cliente solicita un producto en línea, también necesita saber cómo recibirá el producto físico. Por esta razón, generamos algunas coordenadas aleatorias utilizando el generateRandomGeoLocationmétodo de la EcommerceStoreclase y enviamos estas coordenadas al cliente utilizando el sendLocationmétodo para informarle dónde puede recoger físicamente su producto.

Ahora, abra su aplicación WhatsApp y haga clic en Imprimir mi factura .

Si ha seguido las instrucciones anteriores correctamente, debería ver una respuesta similar a la siguiente captura de pantalla:

Enviar mensaje de texto "imprimir mi factura" y recibir un archivo PDF e instrucciones para recoger el producto.

Mostrar confirmaciones de lectura a los clientes

Por último, es posible que haya notado que las marcas de verificación debajo de los mensajes son grises, en lugar de azules. Esto indica que los mensajes que enviamos no devolvieron recibos de lectura a pesar de que nuestro bot los estaba leyendo.

Las marcas grises pueden ser frustrantes para los clientes y, por este motivo, debemos trabajar para mostrar las marcas azules.

Fuera de la simple_button_message ifdeclaración y antes de la llave de cierre de la data?.isMessage ifdeclaración, agregue el siguiente código:

await Whatsapp.markMessageAsRead({ message_id });

Esta simple línea marca un mensaje como leído tan pronto como lo hayamos respondido.

Ahora, abra su aplicación WhatsApp y envíe un mensaje de texto aleatorio. ¿Estás viendo lo que estoy viendo?

Mensajes "hey" y chatbot responde con mensaje predeterminado

Si sus chats anteriores se han actualizado con marcas azules, ¡felicidades! Has llegado al final de este tutorial y has aprendido algunas cosas en el camino.

Pensamientos finales

Con un total de 2000 millones de usuarios activos mensuales, ignorar WhatsApp como estrategia de comercio electrónico es una forma segura de quedarse atrás de la competencia de su negocio, y dado que la mayoría de sus clientes ya usan WhatsApp en sus actividades diarias, ¿por qué no hacerlo? t su negocio encontrarlos allí?

Espero que este tutorial haya sido útil para desmitificar la API de WhatsApp Cloud, y espero que te hayas divertido en el camino. Cuéntame qué otros temas te pueden interesar y no olvides compartir este artículo con tus círculos tecnológicos.

 Fuente: https://blog.logrocket.com/build-ecommerce-app-whatsapp-cloud-api-node-js/

#whatsapp #ecommerce #cloud #api #nodejs 

joe biden

1617257581

Software de restauración de Exchange para restaurar sin problemas PST en Exchange Server

¿Quiere restaurar los buzones de correo de PST a Exchange Server? Entonces, estás en la página correcta. Aquí, lo guiaremos sobre cómo puede restaurar fácilmente mensajes y otros elementos de PST a MS Exchange Server.

Muchas veces, los usuarios necesitan restaurar los elementos de datos de PST en Exchange Server, pero debido a la falta de disponibilidad de una solución confiable, los usuarios no pueden obtener la solución. Háganos saber primero sobre el archivo PST y MS Exchange Server.

Conozca PST y Exchange Server

PST es un formato de archivo utilizado por MS Outlook, un cliente de correo electrónico de Windows y muy popular entre los usuarios domésticos y comerciales.

Por otro lado, Exchange Server es un poderoso servidor de correo electrónico donde todos los datos se almacenan en un archivo EDB. Los usuarios generalmente guardan la copia de seguridad de los buzones de correo de Exchange en el archivo PST, pero muchas veces, los usuarios deben restaurar los datos del archivo PST en Exchange. Para resolver este problema, estamos aquí con una solución profesional que discutiremos en la siguiente sección de esta publicación.

Un método profesional para restaurar PST a Exchange Server

No le recomendamos que elija una solución al azar para restaurar los datos de PST en Exchange Server. Por lo tanto, al realizar varias investigaciones, estamos aquí con una solución inteligente y conveniente, es decir, Exchange Restore Software. Es demasiado fácil de manejar por todos los usuarios y restaurar cómodamente todos los datos del archivo PST a Exchange Server.

Funciones principales ofrecidas por Exchange Restore Software

El software es demasiado simple de usar y se puede instalar fácilmente en todas las versiones de Windows. Con unos pocos clics, la herramienta puede restaurar los elementos del buzón de Exchange.

No es necesario que MS Outlook restaure los datos PST en Exchange. Todos los correos electrónicos, contactos, notas, calendarios, etc. se restauran desde el archivo PST a Exchange Server.

Todas las versiones de Outlook son compatibles con la herramienta, como Outlook 2019, 2016, 2013, 2010, 2007, etc. La herramienta proporciona varios filtros mediante los cuales se pueden restaurar los datos deseados desde un archivo PST a Exchange Server. El programa se puede instalar en todas las versiones de Windows como Windows 10, 8.1, 8, 7, XP, Vista, etc.

Descargue la versión de demostración del software de restauración de Exchange y analice el funcionamiento del software restaurando los primeros 50 elementos por carpeta.

Líneas finales

No existe una solución manual para restaurar los buzones de correo de Exchange desde el archivo PST. Por lo tanto, hemos explicado una solución fácil e inteligente para restaurar datos de archivos PST en Exchange Server. Simplemente puede usar este software y restaurar todos los datos de PST a Exchange Server.

Más información:- https://www.datavare.com/software/exchange-restore.html

#intercambio de software de restauración #intercambio de restauración #buzón del servidor de intercambio #herramienta de restauración de intercambio

prashant patil

1598286700

whatsapp web-w app web-webs whatsapp »

Through whatsapp web you can easily run whatsapp on your android pc on your android mobile. Just like whatsapp mobile is for android device, whatsapp web is for windows device. Whatsapp web is quite popular which has quite cool features.

whatsapp web

how to use whatsapp web desktop
Whatsapp web is very easy to use. Simply you have to search web.whatsapp.com in your google chrome and click on first result which is the official website of whatsapp web.

As soon as you click, an interface will open in front of you, on which you will see a barcode. Follow the steps given below to use whatsapp web on your desktop

web.whatsapp.com

open your whatsapp on your mobile
You will see 3dots on the right side top inside whatsapp, you have to click
The 3rd option is whatsapp web, you have to click it
Now you have to capture the barcode you see on your desktop through your phone.
Now you can use whatsapp of your android mobile in your desktop
webs whatsapp

note: You can see whatsapp of anyone’s mobile by pointing to the barcode of your desktop. You can also call it whatsapp hack.

Remember that after using whatsapp web, logout it from your desktop. To logout follow the steps given below.

w app web

open your whatsapp on your mobile
You will see 3dots on the right side top inside whatsapp, you have to click
The 3rd option is whatsapp web, you have to click it
You will see the symbol for logout, you have to logout by clicking it.

read more

#whatsapp #whatappweb #https://web.whatsapp.com/ #wsp web #web.whatsapp web #web whatsapp

jack richer

jack richer

1611816521

Launch A Lucrative Instant Messaging App With The Robust Whatsapp Clone

People used to write letters to their friends and families for communication in the olden days. Then came the invention of landline phones, which made it easier to communicate over long-distance. Followed by which came the trendsetting invention, the mobile phones. Communication became much easier. SMS packs were used and those became the fundamental communication mode across the world.

Though years passed by the normal SMS communication, it got largely replaced because of the emergence of instant messaging apps like Whatsapp. It became the household name for many users worldwide by bringing several advantages in the messaging world; one of which is, offering instant communication facilities without any cost but just with the internet connection. It is now topping the chart in the messaging industry by competing with many other apps like Telegram, Snapchat, etc.

Why choose WhatsApp Clone?

Whatsapp is basically a freeware, cross-platform messenger app owned by Facebook. It is an app that allows users to send text messages, videos, images, and documents along with the feature to make video and voice calls. The application runs on mobile devices and they are accessible from desktops as well.

For many business owners and investors, it has been and is being the top role model, and is paving the way to the development of Whatsapp Clone apps. Here are the reasons why developing the instant messaging app can offer you various benefits.

Due to the communication, it provides with just the internet, the app can be used all around the world. They come with some extra features like last seen, whether the message is read or not, with its timings, ability to share locations, and many more. The incredible features of the app made it have an audience of 900 million users.
As the years pass by, the active users of these apps are increasing. There are also many reports proving that messaging apps are more popular than the social media sites like Facebook, Twitter, etc.
Last but not the least, people are welcoming these technologies for the uniqueness and ease-of-access they are offering.

Cost for development:

The cost for developing an instant messaging app like Whatsapp is not fixed, as they will depend on the functionalities and features everyone adds. For every addition of a special feature, the cost may vary and the same goes for the functionality. Apart from that, the total hours of development, addition of plug-ins and add-ons also make the most part. However, purchasing and developing an app from Whatsapp Clone script can cut down the cost.

As a final note,

It is high time for you to reap profits. So select the right development company and get yourself a white-label solution as a smart choice and set foot in the industry soon!

#whatsapp clone app #whatsapp clone #whatsapp clone script #app like whatsapp #whatsapp clone app development

Diego  Elizondo

Diego Elizondo

1654599600

Cree Una Aplicación De Comercio Electrónico Con Next.js Y Shopify

Desde que apareció el COVID-19 en el mundo, el comercio electrónico se ha disparado. Según la Administración de Comercio Internacional, ha habido un aumento del 19 % en los ingresos entre el comercio electrónico anterior y posterior al covid en 2020. Como resultado, los empresarios recurrieron a plataformas en línea como Shopify, WordPress (y su complemento, wooCommerce) y Squarespace. para montar sus tiendas online.

Con Shopify, los usuarios no solo pueden configurar una tienda en línea, sino que, gracias a su Storefront API , los desarrolladores pueden crear una aplicación de cliente personalizada para conectarse a ella.

En este artículo, aprenderá cómo configurar una tienda Shopify y obtener su token API Storefront. Una vez que adquiera su token, creará una aplicación Next.js para enumerar y mostrar sus productos con datos ficticios. Finalmente, conectará su aplicación Next.js a su aplicación Shopify para obtener sus productos reales.

Crear una tienda Shopify (opcional)

Si ya tiene una tienda Shopify configurada, puede omitir este paso y dirigirse al paso 2 .

Si no, dirígete al sitio web de Shopify y regístrate para una prueba gratuita. Una vez hecho esto, puede comenzar creando algunas colecciones, que se utilizan para categorizar sus productos.

Para crear una colección, vaya a Productos , luego a Colecciones . A continuación, haz clic en Crear colección . Ingrese un título y elija Manual para el tipo de colección. Con este último, puede agregar manualmente productos a esta colección.

Para este tutorial son necesarias dos colecciones: Hombre y Mujer.

Una vez que sus colecciones estén configuradas, haga clic en Productos y luego Agregar producto .

Para crear un producto, estos son algunos pasos a seguir:

  1. Introduce un título
  2. Cargue una imagen en la entrada del archivo multimedia
  3. Elija un tipo (es decir, zapatos)
  4. Seleccione una colección (es decir, mujeres u hombres)
  5. Introduce un precio
  6. En la sección de inventario , agregue una cantidad en la columna disponible
  7. Establecer el estado del producto como activo
  8. Finalmente, haga clic en guardar . Esto creará un producto activo en su tienda. Repita estos pasos varias veces para llenar su tienda. Por ejemplo, aquí hay una tienda en línea con algunos zapatos:

 

Obtén el token de la API Storefront de Shopify

Una vez que su tienda esté configurada, necesitará un token de API para acceder a ella desde una aplicación de terceros. Vaya a Aplicaciones , haga clic en Desarrollar aplicaciones para su tienda y siga el paso para habilitar el desarrollo de aplicaciones.

Una vez que esta función esté habilitada, haga clic en Crear una aplicación y complete el nombre de su aplicación.

Una vez que haya creado su aplicación, haga clic en su nueva aplicación y diríjase a Configuración . En la sección Storefront API, haga clic en Configurar .

A continuación, en Alcances de acceso a la API de Storefront , seleccione todas las casillas de verificación. Esto le otorgará la capacidad de obtener datos de su tienda, como sus productos, sin estar autenticado. Haga clic en Guardar .

Para obtener su token de acceso a Storefront, deberá instalar su aplicación recién creada, así que haga clic en el botón verde Instalar .

Ahora puede recuperar su token de acceso volviendo a su aplicación y a las credenciales de la API . Tenga en cuenta ese token, ya que lo necesitará más adelante.

Configurar la aplicación Next.js

Para este tutorial, utilizará MUI . Esta biblioteca de componentes le permite obtener componentes prediseñados para crear una interfaz de usuario mucho más rápido.

Afortunadamente, MUI también viene con un proyecto inicial de Next.js que puede obtener ejecutando este comando:

  curl https://codeload.github.com/mui/material-ui/tar.gz/master | tar -xz --strip=2  material-ui-master/examples/nextjs

El comando anterior, desafortunadamente, creará el proyecto con el nombre predeterminado nextjs. si desea cambiarle el nombre, ejecute:

    mv nextjs <your_app_name> # Mac 
    ren nextjs <your_app_name> # Windows

Una vez hecho esto, ingrese su proyecto e instale las dependencias:

    cd <your_app_name>
    npm install
    npm run dev

Crear su interfaz de usuario será más fácil con algunos datos ficticios. Para hacerlo, cree un data.jsarchivo dentro de su carpeta raíz y agregue algunos productos ficticios:

    const PRODUCTS = [
      {
        handle: 1,
        name: 'Women Black Shoes',
        price: '14.99',
        collection: 'women',
        image: 'https://external-content.duckduckgo.com/iu/?u=http%3A%2F%2Fcohenwoodworking.com%2Fwp-content%2Fuploads%2F2016%2F09%2Fimage-placeholder-500x500.jpg&f=1&nofb=1'
      },
      {
        handle: 2,
        name: 'Women Brown Shoes',
        price: '14.99',
        collection: 'women',
        image: 'https://external-content.duckduckgo.com/iu/?u=http%3A%2F%2Fcohenwoodworking.com%2Fwp-content%2Fuploads%2F2016%2F09%2Fimage-placeholder-500x500.jpg&f=1&nofb=1'
      },
      {
        handle: 3,
        name: 'Women Purple Shoes',
        price: '14.99',
        collection: 'women',
        image: 'https://external-content.duckduckgo.com/iu/?u=http%3A%2F%2Fcohenwoodworking.com%2Fwp-content%2Fuploads%2F2016%2F09%2Fimage-placeholder-500x500.jpg&f=1&nofb=1'
      }
    ];

    export default PRODUCTS;

Cree la página de inicio de la tienda de comercio electrónico con Next.js

Dentro de su carpeta raíz Next.js, cree una componentscarpeta.

Dentro de esta carpeta, creará un componente para listar sus productos llamado ProductList. MUI tiene algunos componentes prediseñados para crear una lista con imágenes y títulos debajo de ellos en formato de cuadrícula.

Estos componentes se denominan: ImageList, ImageListItemy ImageListItemBar. Puede encontrar la documentación aquí .

Dentro de su componentscarpeta, cree ProductsList.js. Importe todos los componentes necesarios desde MUI y configure su cuadrícula. Suponga que su componente recibirá una variedad de productos y mapeará sobre él para crear una sola entrada de producto con una imagen y un título debajo.

 import * as React from 'react';
    import Typography from '@mui/material/Typography';
    import ImageList from '@mui/material/ImageList';
    import ImageListItem from '@mui/material/ImageListItem';
    import ImageListItemBar from '@mui/material/ImageListItemBar';


    export default function ProductsList({products}) {
      return (
        <ImageList cols={5} gap={20}>
          {products.map((product) => (
            <ImageListItem key={product.image}>
              {/* Product's image*/}
              <img
                src={`${product.image}?w=250&fit=crop&auto=format`}
                srcSet={`${product.image}?w=250&fit=crop&auto=format&dpr=2 2x`}
                alt={product.name}
                loading="lazy"
              />
              {/* Product's name + price under the image */}
              <ImageListItemBar
                title={product.name}
                subtitle={<span>Price: {product.price}</span>}
                position="below"
              />
            </ImageListItem>
          ))}
        </ImageList>
      )
    };

Otro componente que necesitará es una barra de navegación. Puede usar MUI AppBary Toolbarcrear uno. En el interior, agregue sus colecciones como texto. Más adelante aprenderá a configurar el enrutamiento.

Aquí está el resultado de su Navigation.jscomponente:

  import * as React from 'react';
    import AppBar from '@mui/material/AppBar';
    import Toolbar from '@mui/material/Toolbar';
    import Typography from '@mui/material/Typography';


    export default function Navigation() {
      return (
        <AppBar position="static">
          <Toolbar>
            <Typography mr={2}>All products</Typography>
            <Typography mr={2}>Women</Typography>
            <Typography>Men</Typography>
          </Toolbar>
        </AppBar>
      )
    };

Finalmente, use sus componentes recién creados ProductsListy Navigation.js, en la página de inicio de su aplicación. Esta página está disponible en la URL y se procesa desde el pages/index.jsarchivo.

Nota: si no está familiarizado con la funcionalidad de la página de Next.js y su representación, consulte la documentación .

Dentro index.js, import Navigation, ProductLists, y sus datos ficticios. Puedes pasar tus datos a tu lista de productos:

  import * as React from 'react';
    import Container from '@mui/material/Container';
    import Box from '@mui/material/Box';




    import Navigation from '../components/Navigation';
    import ProductsList from '../components/ProductsList';
    import PRODUCTS from '../data.js';


    export default function Index() {
      return (
        <Box>
          <Navigation />
          <Container maxWidth="lg">
            <ProductsList products={PRODUCTS} />
          </Container>
        </Box>
      );
    }

En este punto, una vez que actualice su página, debería ver esto:

Crear diferentes páginas de colección en la aplicación de comercio electrónico

Ahora que su página de inicio está configurada, necesita páginas de colecciones. La mayoría de las tiendas en línea dividen sus productos en categorías, por lo que es más fácil para los usuarios navegar por sus catálogos. Como resultado, crearemos una colección específica.

Next.js ofrece enrutamiento dinámico. Si no está familiarizado con él, le permite crear rutas, como /collections/[collectionName. Al hacerlo, las URL como /collections/womeno /collections/menusarán la misma .jspágina.

Dentro de su pagescarpeta, cree una collectionscarpeta y dentro de ella, un [collectionName].jsarchivo. Este componente será muy similar a su página de inicio. Sin embargo, filtrará sus productos para obtener solo los de la colección correcta.

Afortunadamente, Next.js también viene con un enlace useRouterdesde el cual puede obtener los parámetros de consulta de la URL. Una vez que tenga el collectionName, puede usarlo para filtrar sus productos. Finalmente, pase su lista filtrada de productos a ProductsList.

 import * as React from 'react';
    import { useRouter } from 'next/router'


    import Container from '@mui/material/Container';
    import Box from '@mui/material/Box';




    import Navigation from '../../components/Navigation';
    import BreadcrumbsNavigation from '../../components/BreadcrumbsNavigation';
    import ProductsList from '../../components/ProductsList';
    import PRODUCTS from '../../data.js';


    export default function CollectionPage() {
      const router = useRouter()
      const { collectionName } = router.query
      const products = PRODUCTS.filter(product => product.collection === collectionName)
      return (
        <Box>
          <Navigation />
          <Container maxWidth="lg">
            <BreadcrumbsNavigation collection={collectionName} />
            <ProductsList products={products} />
          </Container>
        </Box>
      );
    }

Tenga en cuenta que la página de su colección utiliza un componente personalizado llamado BreadcrumbsNavigation. Esto es para generar migas de pan personalizadas para su tienda.

Para crear este componente, dentro de su componentscarpeta, cree un archivo BreadcrumbsNavigation.js. MIU ofrece un Breadcrumbscomponente para su uso. Sumado a esto, el Linkcomponente le permite agregar enrutamiento para volver a su página de inicio.

Aquí está el resultado final:

    import * as React from 'react';


    import Box from '@mui/material/Box';
    import Breadcrumbs from '@mui/material/Breadcrumbs';
    import Typography from '@mui/material/Typography';
    import Link from '@mui/material/Link';


    export default function BreadcrumbsNavigation({title}) {
      return (
        <Box mt={2}>
          <Breadcrumbs separator="›" aria-label="breadcrumb">
            <Link underline="hover" key="1" color="inherit" href="/">
              Products
            </Link>
            <Typography key="3" color="text.primary">
              {title && title.replace(/^\w/, c => c.toUpperCase())}
            </Typography>
          </Breadcrumbs>
        </Box>
      )
    }

En Navigation.js, importe el componente de MUI Linkque acaba de usar y agregue algunas rutas en la barra de su aplicación para su página de inicio y sus colecciones:

    import * as React from 'react';


    import AppBar from '@mui/material/AppBar';
    import Toolbar from '@mui/material/Toolbar';
    import Typography from '@mui/material/Typography';
    import Link from '@mui/material/Link';


    export default function Navigation() {
      return (
        <AppBar position="static">
          <Toolbar>
            <Link href="/" underline="none" color="inherit"><Typography mr={2}>All products</Typography></Link>
            <Link href="/collections/women" underline="none" color="inherit"><Typography mr={2}>Women</Typography></Link>
            <Link href="/collections/men" underline="none" color="inherit"><Typography>Men</Typography></Link>
          </Toolbar>
        </AppBar>
      )
    };

En su ProductList.js, puede agregar un cheque en caso de que no haya productos:

    import * as React from 'react';


    import Box from '@mui/material/Box';
    import Typography from '@mui/material/Typography';
    ...


    export default function ProductsList({products}) {
      return (
        <Box>
          {
            (products && products.length > 0) ?
            <ImageList cols={5} gap={20}>
              ...
            </ImageList>:
            <Typography variant="body1" align="center">There are no products in this collection</Typography>
          }
        </Box>
      )
    };

Si te diriges a http://localhost:3000/collections/women, ahora deberías ver esto:

Crear una página de producto en Next.js y Shopify

Con su página de inicio y las páginas de colecciones configuradas, puede pasar a la página del producto. Al igual que la página de colecciones, el enrutamiento dinámico de Next.js se puede usar para configurar la página.

Crea una productscarpeta. Dentro, agregue un nuevo archivo llamado [productHandle].js. Ya sea que desee usar ID o identificadores black-conversecomo productHandle, esta página ‌ representará la página de su producto.

Después de obtener el productHandleparámetro de la URL, puede usarlo para obtener su producto. Para mostrar la imagen de su producto, Next.js proporciona un Imagecomponente que viene con optimización de imagen integrada.

Aquí está el resultado de una página de producto:

  import * as React from 'react';
    import { useRouter } from 'next/router';
    import Image from 'next/image';


    import Container from '@mui/material/Container';
    import Box from '@mui/material/Box';
    import Grid from '@mui/material/Grid'
    import Typography from '@mui/material/Typography';
    import Button from '@mui/material/Button';


    import Navigation from '../../components/Navigation';
    import BreadcrumbsNavigation from '../../components/BreadcrumbsNavigation';
    import ProductsList from '../../components/ProductsList';
    import PRODUCTS from '../../data.js';


    export default function ProductPage() {
        const router = useRouter()
      // Get productHandle from url: /products/[productHandle]
      const { productHandle } = router.query
      // Get product data
      const product = PRODUCTS.find(product => product.handle === parseInt(productHandle))
      const { name, image, price } = product || {}


      return (
        <Box>
          <Navigation />
          {product &&
            <Container maxWidth="lg">
              <BreadcrumbsNavigation title={name} />
                <Grid container direction="row">
                  <Grid item xs={6}>
                    <Image
                      src={image}
                      alt={`Picture of ${name}`}
                      width={500}
                      height={500}
                    />
                  </Grid>
                  <Grid item xs={6}>
                    <Typography variant="h3" my={2}>{name}</Typography>
                    <Grid mt={4}>
                      <Typography variant="h6" component="span">Price: </Typography>
                      <Typography variant="body1" component="span">{price}</Typography>
                    </Grid>
                    <Grid mt={1}>
                      <Button variant="contained">Add to cart</Button>
                    </Grid>
                  </Grid>
                </Grid>
            </Container>
          }
        </Box>
      );
    }

Si termina usando el Imagecomponente, deberá agregar el dominio de su imagen a next.config.js, así:

  module.exports = {
      reactStrictMode: true,
      images: {
        domains: ['external-content.duckduckgo.com'],
      },
    };

Tendrá que reiniciar su servidor cuando cambie next.config.js.

Finalmente, implementemos el enrutamiento a la página de su producto. Para hacerlo, regrese a su components/ProductsList.jsy use el enrutador Next.js para navegar a la página de su producto cuando un usuario haga clic en la imagen en la lista del producto. Agregue en onClicksu ImageListItem, junto con el estilo del cursor, y cree un goToProductPagepara navegar.

Aquí está el resultado final:

import * as React from 'react';
    import { useRouter } from 'next/router'


    ...


    export default function ProductsList({products}) {
      const router = useRouter()
      // Navigate to product's page
      const goToProductPage = productHandle => router.push(`/products/${productHandle}`)


      return (
        <Box>
          {
            (products && products.length > 0) ?
            <ImageList cols={5} gap={20}>
              {products.map((product) => (
                <ImageListItem
                  key={product.image}
                  style={{cursor: 'pointer'}}
                  onClick={() => goToProductPage(product.handle)}>
                  ...
                </ImageListItem>
              ))}
            </ImageList>:
            <Typography variant="body1" align="center">There are no products in this collection</Typography>
          }
        </Box>
      )
    };

Una vez renderizado, esto es lo que obtendrá:

Recupera tus productos con la API de Shopify Storefront

Su aplicación de cliente ya está configurada. Sin embargo, se basa en datos ficticios. Para finalizar su proyecto, los datos de su tienda Shopify deben obtenerse y usarse.

Para hacerlo, necesitará Shopify JavaScript Buy SDK , que puede obtener instalando el paquete necesario:

    npm install shopify-buy

¿Recuerda los tokens de Storefront API que obtuvimos al principio de este artículo? Los almacenará en variables de entorno. Dentro de tu proyecto raíz, crea un archivo llamado .env.localy agrega tu token, junto con tu dominio de Shopify:

  SHOPIFY_STORE_FRONT_ACCESS_TOKEN=*****
    SHOPIFY_STORE_DOMAIN=********

También puede encontrar su dominio haciendo clic en Configuración en su tienda Shopify:

Una vez que haya configurado sus variables, cree una libcarpeta en su proyecto raíz y un shopify.jsarchivo dentro. En este archivo, importará su shopify-buybiblioteca y creará un cliente de Shopify con sus variables.

Una vez que realices una llamada a la API de Shopify, la respuesta devuelta deberá especificarse y analizarse para usarse como un objeto JSON más adelante. Como resultado, cree una parseShopifyResponsefunción para que pueda usarla repetidamente en su aplicación:

  import Client from "shopify-buy";
    export const shopifyClient = Client.buildClient({
      storefrontAccessToken: process.env.SHOPIFY_STORE_FRONT_ACCESS_TOKEN,
      domain: process.env.SHOPIFY_STORE_DOMAIN,
    });


    export const parseShopifyResponse = (response) =>  JSON.parse(JSON.stringify(response));

Sigamos buscando todos sus productos para su página de inicio. En index.js, use Next.js' getServerSidePropspara realizar una llamada a la API cuando se solicite la página. Con shopifyClient.product.fetchAll(), puede buscar todos los productos en su tienda. Una vez que se devuelven los datos, se pasarán como accesorios a su página de inicio y en su ProductsListcomponente:

   import * as React from 'react';
    import Container from '@mui/material/Container';
    import Box from '@mui/material/Box';


    import Navigation from '../components/Navigation';
    import ProductsList from '../components/ProductsList';
    import { shopifyClient, parseShopifyResponse } from '../lib/shopify'


    export default function Index({products}) {
      return (
        <Box>
          <Navigation />
          <Container maxWidth="lg">
            <ProductsList products={products} />
          </Container>
        </Box>
      );
    }


    export const getServerSideProps = async () => {
      // Fetch all the products
      const products = await shopifyClient.product.fetchAll();


      return {
       props: {
        products: parseShopifyResponse(products),
      },
     };
    };

El formato de sus datos ficticios no es el mismo que devolverá Shopify. Tendrás que adaptarte ProductsList.jsa estos nuevos datos. Dentro de este archivo, creemos un Productcomponente y tomemos la identificación, el título, la imagen, el precio y el identificador de su producto.

La respuesta de la API de Shopify puede ser un poco confusa. Por ejemplo, el precio de su producto estará en el variantsobjeto. Aquí está la documentación completa para tener una mejor idea de la estructura de un producto.

El producto de Shopify también viene con un handlecampo generado cuando crea productos. Un producto etiquetado como "Conversaciones negras" tendría un asa como black-converses. Esto es muy útil para el SEO, ya que productId/1se prefieren las cadenas a las URL. Lo usará en su enrutamiento cuando navegue a la página de su producto.

Aquí está el resultado actualizado:

  import * as React from 'react';
    import { useRouter } from 'next/router'


    import Box from '@mui/material/Box';
    import Typography from '@mui/material/Typography';
    import ImageList from '@mui/material/ImageList';
    import ImageListItem from '@mui/material/ImageListItem';
    import ImageListItemBar from '@mui/material/ImageListItemBar';


    const Product = ({product, goToProductPage}) => {
      const { id, title, images, variants, handle } = product
      const { src: productImage } = images[0]
      const { price } = variants[0]
      return (
        <ImageListItem
          style={{cursor: 'pointer'}}
          onClick={() => goToProductPage(handle)}>
          <img
            src={`${productImage}?w=250&auto=format`}
            srcSet={`${productImage}?w=250&auto=format&dpr=2 2x`}
            alt={title}
            loading="lazy"
          />
          <ImageListItemBar
            title={title}
            subtitle={<span>Price: {price}</span>}
            position="below"
          />
        </ImageListItem>
      )
   }
    export default function ProductsList({products}) {
      const router = useRouter()
      // Navigate to product page with handle i.e /products/black-converses
      const goToProductPage = productHandle => router.push(`/products/${productHandle}`)


      return (
        <Box>
          {
            (products && products.length > 0) ?
            <ImageList cols={5} gap={20}>
              {products.map((product) => (
                <Product
                  key={product.handle}
                  product={product}
                  goToProductPage={goToProductPage}
                />
              ))}
            </ImageList>:
            <Typography variant="body1" align="center">There are no products in this collection</Typography>
          }
        </Box>
      )
    };

Ahora, puede pasar a actualizar la página de su producto. En su products/[productHandle].js, tome el identificador de su consulta. Shopify JS SDK viene con una función llamada fetchByHandleque obtiene un solo producto de su identificador. Use su productHandlepara obtener su producto y agréguelo a sus accesorios.

Ahora, deberá actualizar la página de su producto como lo hizo con su lista de productos. Puede tomar su título, imagen y precio de la misma manera y usarlos en su página:

    import * as React from 'react';
    import Image from 'next/image'


    import Container from '@mui/material/Container';
    import Box from '@mui/material/Box';
    import Grid from '@mui/material/Grid'
    import Typography from '@mui/material/Typography';
    import Button from '@mui/material/Button';


    import Navigation from '../../components/Navigation';
    import BreadcrumbsNavigation from '../../components/BreadcrumbsNavigation';
    import ProductsList from '../../components/ProductsList';
    import { shopifyClient, parseShopifyResponse } from '../../lib/shopify'


    export default function ProductPage({product}) {


      const { id, title, images, variants, handle } = product
      const { src: productImage } = images[0]
      const { price } = variants[0]


      return (
        <Box>
          <Navigation />
          {product &&
            <Container maxWidth="lg">
              <BreadcrumbsNavigation title={title} />
                <Grid container direction="row">
                  <Grid item xs={6}>
                    <Image
                      src={productImage}
                      alt={`Picture of ${title}`}
                      width={500} automatically provided
                      height={500} automatically provided
                    />
                  </Grid>
                  <Grid item xs={6}>
                    <Typography variant="h3" my={2}>{title}</Typography>
                    <Grid mt={4}>
                      <Typography variant="h6" component="span">Price: </Typography>
                      <Typography variant="body1" component="span">{price}</Typography>
                    </Grid>
                    <Grid mt={1}>
                      <Button variant="contained">Add to cart</Button>
                    </Grid>
                  </Grid>
                </Grid>
            </Container>
          }
        </Box>
      );
    }


    export const getServerSideProps = async ({params}) => {
      const { productHandle } = params
      // Fetch one product
      const product = await shopifyClient.product.fetchByHandle(productHandle);


      return {
       props: {
        product: parseShopifyResponse(product),
      },
     };
    };

Para la página de su colección, lamentablemente necesitará un poco de filtrado. En este momento, Shopify JS SDK solo viene con la opción de buscar productos por ID de colección, pero no con su identificador. En collections/[collectionName].js, puede usar client.collection.fetchAllWithProducts() para buscar todas las colecciones y sus productos.

Una vez que los tengas, puedes agarrar el correcto revisando su mango y pasándolo a tus accesorios.

    import * as React from 'react';


    import Container from '@mui/material/Container';
    import Box from '@mui/material/Box';




    import Navigation from '../../components/Navigation';
    import BreadcrumbsNavigation from '../../components/BreadcrumbsNavigation';
    import ProductsList from '../../components/ProductsList';
    import { shopifyClient, parseShopifyResponse } from '../../lib/shopify'


    export default function CollectionPage({products, collectionName}) {
      return (
        <Box>
          <Navigation />
          <Container maxWidth="lg">
            <BreadcrumbsNavigation title={collectionName} />
            <ProductsList products={products} />
          </Container>
        </Box>
      );
    }


    export const getServerSideProps = async ({params}) => {
      const { collectionName } = params
      // Fetch all the collections
      const collectionsData = await shopifyClient.collection.fetchAllWithProducts();
      const collections = parseShopifyResponse(collectionsData);
      // Get the right one
      const collection = collections.find(collection => collection.handle === collectionName)


      return {
       props: {
        collectionName,
        products: collection.products,
      },
     };
    };

Finalmente, si está utilizando el Imagecomponente, deberá actualizar next.config.jspara agregar el dominio de imagen de Shopify:

   module.exports = {
      reactStrictMode: true,
      images: {
        domains: ['external-content.duckduckgo.com', 'cdn.shopify.com'],
      },
    };

El resultado final se ve así:

El código base completo se puede encontrar en este repositorio de GitHub.

Conclusión

En este artículo, aprendió cómo configurar una tienda Shopify, habilitar la API Storefront y obtener su token de acceso. Luego descubrió cómo crear una aplicación Next.js y configurar su interfaz mediante la creación de una página de inicio, junto con páginas de colección y productos. Finalmente, instaló Shopify JS SDK y aprendió a usarlo para obtener productos de su tienda en línea.

A partir de ahí, se pueden implementar muchas más funcionalidades. Ya sea que se trate de la creación de un carrito, agregarle productos o completar el pago, el JS SDK de Shopify puede ayudarlo a lograr sus objetivos.

Esta historia se publicó originalmente en https://blog.logrocket.com/build-ecommerce-app-nextjs-shopify/

#nextjs #shopify