prompt.js 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. const discord = require('discord.js')
  2. const EMOTE_DONE = '✅'
  3. // TODO: timeout
  4. async function prompt({ channel, user, title, description='', choices }) {
  5. const userID = user.discordID || user
  6. if (description !== '') description += '\n\n'
  7. const embed = new discord.RichEmbed()
  8. .setTitle(title)
  9. .setDescription(description + choices.map(
  10. ({ name, emote }) => `${emote} ${name}`).join('\n'))
  11. const msg = await channel.send(embed)
  12. const reactionFilter = (react, user) =>
  13. user.id === userID
  14. && choices.map(c => c.emote).includes(react.emoji.name)
  15. const reactionP = msg.awaitReactions(reactionFilter, {max: 1})
  16. .then(reactions => reactions.first())
  17. .then(reaction => choices.find(c => c.emote === reaction.emoji.name))
  18. for (const choice of choices) {
  19. await msg.react(choice.emote)
  20. }
  21. // TODO: textual selection? - see https://git.io/fAjFH
  22. const chosen = await reactionP
  23. await msg.delete()
  24. return chosen
  25. }
  26. async function multi(opts) {
  27. const { chooseMin, chooseMax } = opts
  28. const chosen = []
  29. while (chosen.length < chooseMax) {
  30. // Disallow choosing the same choice twice
  31. const choosable = opts.choices.filter(choice => !chosen.includes(choice))
  32. // Prompt for next
  33. const choice = await prompt(Object.assign({}, opts, {
  34. choices: chosen.length >= chooseMin
  35. ? [...choosable, {emote: EMOTE_DONE, name: '(Finish)'}]
  36. : choosable
  37. }))
  38. if (choice.emote === EMOTE_DONE) {
  39. return chosen
  40. }
  41. chosen.push(choice)
  42. }
  43. return chosen
  44. }
  45. module.exports = Object.assign(prompt, {multi})