Skip to content

softwaregroup-bg/ut-ussd

Repository files navigation

ut-ussd - USSD menu engine

Configuration options

{
  utUssd: {
    ussd: {
      exposeState: 'true|false', // this will expose runtime
      // state if set to true, defaults: false
      // refresh: gets refreshed on every cycle;
      // static(default): sets only once and will expire
      // in predefined period of time (timeOut);
      expireRule:  'refresh|static',
      timeOut: 1000, // expiration period definition
      shortCodes: { // short codes
        "*877#": "menu/entrance"
      },
      maintenanceModeState: "menu/maintenance", // maintenance mode state
      wrongInputState: "error/wrongInput", // wrong input state
      resumeState: "menu/resume", // resume state
      strings: [ // USSD strings
        "*877*1*1#",
        "*877*1*2#",
        "*877*2*1#",
        "*877*2*2#",
        "*877*2*3#",
        "*877*3*1#",
        "*877*3*2#",
        "*877*4#"
      ],
      defaultPhone: "1234", // default phone number for the simulator
      defaultShortCode: "*131#", // default short code for the simulator
      charsCount: true, // if characters count should be visible in the simulator
      // To display a slogan with the respective text above the phone number input
      // (no slogan will be displayed by default)
      slogan: 'Test'
    }
  }
}

Views

USSD menu is defined in template files named view.xml, each one being in a separate folder. Folders are usually structured to mirror the USSD menu structure.

For example:

ussd
├── components
|   ├── back.xml
|   ├── backToHome.xml
|   └── footer.xml
└── menu
    ├── home
    |   └── view.xml
    ├── login
    |   └── view.xml
    └── error
    |   ├── runtimeError
    |   |   └── view.xml
    |   └── wrongInput
    |       └── view.xml
    └── account
        ├── balanceEnquiry
        |   └── view.xml
        └── miniStatement
            └── view.xml

The template files are JavaScript template literals, passed to ut-function.template engine. Each view file can contain some specific markup as in the below examples:

  1. Links - links are defined with the tag <a id="" href="">, where the attribute id represents the USSD input, and href represents the next menu to show when this input is received.

    Menu
    <a id="1" href="menu/account">1. Account information</a>
  2. Expressions - the standard syntax ${} applicable to JS template literals can be used to define expressions, either simple ones like:

    ${params.system.prevState}
    

    or more complex like iterating over array:

    ${
      params.miniStatement.map(
        rec => `${rec.amount} on ${rec.postDate}`
      ).join(`<br/>`)
    }
    

    or for conditional rendering:

    ${
      params.view === 'pin' ? 'Please enter your PIN' :
      params.view === 'wrongPin' ? `Wrong PIN.<br/>Please try again' :
        'Unexpected Error'
    }
    
  3. Translations - the USSD template engine includes the function T, which can be used to translate text:

    ${T`Please enter your PIN`}
    

    The syntax is based on JS tagged templates.

  4. Includes - repeated fragments can be included in multiple views using the syntax:

    Some menu
    
    ${include('../../components/back.xml')}
    

The essential API objects available in the views ${} expressions are:

  • All node.js global objects
  • T - the function used for translation
  • include - the function used to include fragments
  • params - object, containing the template parameters

The essential tags available in the views are:

  • <a id="" href="">link</a> - for defining links to other menus
  • <br/> - for line breaks

Controllers

Each menu can have an optional controller.js file, which handles actions related to the menu. This file resides in the same folder as the menu's respective view.js. There are two optional actions, that can be defined:

  1. send: This is executed before rendering the current menu. It can call other services to fetch data to be displayed in the menu.
  2. receive: This is executed after receiving the response for a particular menu.

Controllers can be defined as object:

module.exports = {
    async send(params) {
        // some processing
        return params;
    },
    async receive(params) {
        // some processing
        return params;
    }
};

Controllers can be also be defined as a function, returning an object. This is useful when external API must be called using the familiar destructuring syntax: import:{}.

Note that import is the only available property at the moment.

module.exports = ({
    import: {
        subjectObjectPredicate
    }
}) => ({
    async send(params) {
        try {
            const result = await subjectObjectPredicate({});
            // some processing
            return params;
        } catch (error) {
            params.error = error;
            this.redirect('menu/error/runtimeError');
            return params;
        }
    }
});

The official API objects available in the controllers are:

  • import: {subjectObjectPredicate} - proxy for obtaining external API
  • this.redirect(view) - for selecting the next view