Search code examples
javascriptnode.jssmooch

pass param to postback method in smooch-bot


I am following the answer of @dstoiko from here

I am calling the API in ADD_MOVIE block and want to pass some value to my postback with payload ADD_TO_FIREBASE

Here is my blocks

'use strict';

const Script = require('smooch-bot').Script;


var YtsHelper = require('./libs/YtsHelper.js');
const FirebaseHelper = require('./libs/FirebaseHelper.js');
var firebaseHelperObj = new FirebaseHelper();

module.exports = new Script({

processing: {
    prompt: (bot) => bot.say('Beep boop...'),
    receive: () => 'processing'
},

start: {
    receive: (bot) => {
        return bot.say('Hi! I\'m Smooch Bot!')
            .then(() => 'showUserMenu');
    }
},

showUserMenu: {

        prompt: (bot) => bot.say("Here are the areas I can help you out. %[Add Movie](postback:ADD_MOVIE) %[Serve Food](postback:SERVE_FOOD)"),
        receive: () => 'finish'
},

ADD_MOVIE : {

    prompt: (bot) => bot.say('Enter movie name or keywords you want to search please.'),
    receive: (bot, message) => {
        const movie_name_searched = message.text;
        return bot.setProp('movie_name_searched', movie_name_searched)
            .then(() => bot.say('Search in progress...'))
            .then(() => {
                YtsHelper.getMoviesList(movie_name_searched,function(movies_array){

                    var movies_postbacks = "";

                    console.log("Movies SIZE " + movies_array.length);

                    for (var i = 0; i < movies_array.length ; i++){
                        movies_postbacks = movies_postbacks + " %["+movies_array[i]+"](postback:ADD_TO_FIREBASE)";
                    }

                    bot.say(movies_postbacks)
                    .then(() => bot.say("Click any movie to add into firebase."));
                    
                });
            });
    }
},

ADD_TO_FIREBASE: {
        prompt: (bot) => bot.say("confirm, y/n"),
        receive: () => 'showUserMenu'
},


finish: {
    receive: (bot, message) => {
        return bot.getProp('name')
            .then((name) => bot.say(`Sorry ${name}, my creator didn't ` +
                    'teach me how to do anything else!'))
            .then(() => 'showUserMenu');
    }
}

});

Questions

Q0. I am new to nodeJS also, What should I call ADD_MOVIE, start, showUserMenu (in my code) blocks? function, method, code, module etc.

Q1. I Have called an yts api in my ADD_MOVIE block. Is this fine to call API in script.js file?

Q2. Important!: How can I pass the param to my postback with payload ADD_MOVIE so that I can perform some conditional code in ADD_TO_FIREBASE block


Solution

  • Q0: Is a question of style.

    Q1: Yes making a DB query in receive is fine, however your receive function isn't waiting for the query to finish before it resolves your bot state. If for example you don't want your bot to accept user input until after the movie list is returned, you could do this:

    receive: (bot, message) => {
        const movie_name_searched = message.text;
        return bot.setProp('movie_name_searched', movie_name_searched)
            .then(() => bot.say('Search in progress...'))
            .then(() => {
                return new Promise((res) => YtsHelper.getMoviesList(movie_name_searched, (movies_array) => res(movies_array)));
            })
            .then((movies_array) => {
                    var movies_postbacks = "";
                    for (var i = 0; i < movies_array.length ; i++){
                        movies_postbacks = movies_postbacks + " %["+movies_array[i]+"](postback:ADD_TO_FIREBASE)";
                    }
    
                    return bot.say(movies_postbacks);
            })
            .then(() => bot.say("Click any movie to add into firebase."))
            .then(() => 'ADD_MOVIE');
    }
    

    Note that I'm resolving the very end of the promise chain with 'ADD_MOVIE', which tells your bot to remain in the same state as it was before.

    Q2: I see two options.

    Option 1: Append the movie ID to the postback payload, eg ADD_TO_FIREBASE.movieid1, ADD_TO_FIREBASE.movieid2 and so on..

    If you did this, you would have to define your own behavior inside handlePostback that parses out the movie ID from your postback payload.

    You would also have to transition your state amchine into the desired ADD_TO_FIREBASE state yourself. Eg, from your custom handlePostback methdod you would do something like this:

    const stateMachine = new StateMachine({
        script,
        bot: createBot(req.body.appUser)
    });
    stateMachine.setState('ADD_TO_FIREBASE');
    

    Option 2: The %[foo](postback:bar) message you're using is actually a shorthand syntax. The real inner workings of postback messages are action buttons which you can send to the Smooch API directly. Action buttons also allow you to specify a metadata object. If instead of using the built-in bot.say, you could post messages ot the API directly, and you could store your movie IDs inside the action metadata. You would again have to retrieve the selected movieId from this metadata via your custom handlePostback as you did in option 1.