prompt.js 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  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(
  10. description +
  11. choices.map(({name, emote}) => `${emote} ${name}`).join('\n')
  12. )
  13. const msg = await channel.send(embed)
  14. const reactionFilter = (react, user) =>
  15. user.id === userID &&
  16. choices.find(c => c.emote.toString() === react.emoji.toString())
  17. const reactionP = msg
  18. .awaitReactions(reactionFilter, {max: 1})
  19. .then(reactions => reactions.first())
  20. .then(reaction =>
  21. choices.find(c => c.emote.toString() === reaction.emoji.toString())
  22. )
  23. for (const choice of choices) {
  24. await msg.react(choice.emote)
  25. }
  26. // TODO: textual selection? - see https://git.io/fAjFH
  27. const chosen = await reactionP
  28. await msg.delete()
  29. return chosen
  30. }
  31. async function multi(opts) {
  32. const {chooseMin, chooseMax} = opts
  33. const chosen = []
  34. while (chosen.length < chooseMax) {
  35. // Disallow choosing the same choice twice
  36. const choosable = opts.choices.filter(choice => !chosen.includes(choice))
  37. // Prompt for next
  38. const choice = await prompt(
  39. Object.assign({}, opts, {
  40. choices:
  41. chosen.length >= chooseMin
  42. ? [...choosable, {emote: EMOTE_DONE, name: 'Done'}]
  43. : choosable,
  44. })
  45. )
  46. if (choice.emote === EMOTE_DONE) {
  47. return chosen
  48. }
  49. chosen.push(choice)
  50. }
  51. return chosen
  52. }
  53. module.exports = Object.assign(prompt, {multi})