UNPKG

bottender-form

Version:

An experimental package for handling conversational form with Bottender.

102 lines (89 loc) 2.15 kB
// const step = { // question: // validation: // stateKey: // } const set = require('lodash/set'); const alwaysFalse = () => false; const noop = () => {}; const RETRY_MESSAGE = 'Validation failed. Please try again.'; module.exports = ({ name, shouldStart = alwaysFalse, shouldStop = alwaysFalse, didFinish = noop, steps, retryMessage = RETRY_MESSAGE, retryTimes = 3, } = {}) => async (context, next) => { const { $form } = context.state; if (!$form) { if (shouldStart(context)) { if (typeof steps[0].question === 'function') { await steps[0].question(context); } else { await context.sendText(steps[0].question); } context.setState({ $form: { name, index: 0, }, }); return; } return next(); } if (shouldStop(context)) return; if ($form.name !== name) return next(); const step = steps[$form.index]; const shouldRetry = !context.event.isText || (step.validation && !await Promise.resolve(step.validation(context.event.text))); if (shouldRetry) { const retry = ($form.retry || 0) + 1; if (retry === retryTimes) { context.setState({ $form: null, }); return; } await context.sendText(retryMessage); if (typeof step.question === 'function') { await step.question(context); } else { await context.sendText(step.question); } context.setState({ $form: { ...$form, retry, }, }); return; } const map = step.map || (val => val); context.setState({ ...set(context.state, step.stateKey, map(context.event.text)), }); if ($form.index === steps.length - 1) { context.setState({ $form: null, }); await didFinish(context); } else { const nextIndex = $form.index + 1; if (typeof steps[nextIndex].question === 'function') { await steps[nextIndex].question(context); } else { await context.sendText(steps[nextIndex].question); } context.setState({ $form: { ...$form, index: nextIndex, }, }); } };