Skip to content

Commit

Permalink
feat(whatsapp): button
Browse files Browse the repository at this point in the history
  • Loading branch information
XxLittleCxX committed Oct 14, 2023
1 parent f129772 commit b703a75
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 3 deletions.
4 changes: 4 additions & 0 deletions adapters/whatsapp/src/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ export class WhatsAppAdapter extends Adapter<WhatsAppBot> {
bot.selfId = item.id
bot.adapter = this
bot.internal = internal
bot.user = {
id: item.id,
name: item.display_phone_number,
}
this.bots.push(bot)
bot.online()
}
Expand Down
27 changes: 26 additions & 1 deletion adapters/whatsapp/src/message.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Dict, h, MessageEncoder } from '@satorijs/satori'
import { WhatsAppBot } from './bot'
import FormData from 'form-data'
import { SendMessage } from './types'
import { Button, SendMessage } from './types'

const SUPPORTED_MEDIA = [
'audio/aac',
Expand All @@ -28,8 +28,10 @@ const SUPPORTED_MEDIA = [
export class WhatsAppMessageEncoder extends MessageEncoder<WhatsAppBot> {
private buffer = ''
quoteId: string = null
private buttons: Button[] = []

async flush(): Promise<void> {
if (this.buttons.length) await this.flushButton()
await this.flushTextMessage()
}

Expand All @@ -38,6 +40,17 @@ export class WhatsAppMessageEncoder extends MessageEncoder<WhatsAppBot> {
this.buffer = ''
}

async flushButton() {
for (let i = 0; i < this.buttons.length; i += 3) {
await this.sendMessage('button', {
body: { text: this.buffer || ' ' },
action: { buttons: this.buttons.slice(i, i + 3) },
})
this.buffer = ''
}
this.buttons = []
}

async sendMessage<T extends SendMessage['type']>(type: T, data: Dict) {
if (type === 'text' && !this.buffer.length) return
if (type !== 'text' && this.buffer.length) await this.flushTextMessage()
Expand Down Expand Up @@ -89,6 +102,14 @@ export class WhatsAppMessageEncoder extends MessageEncoder<WhatsAppBot> {
return r.id
}

decodeButton(attrs: Dict, label: string): Button {
return {
id: attrs.id,
type: 'reply',
title: label,
}
}

async visit(element: h): Promise<void> {
const { type, attrs, children } = element
if (type === 'text') {
Expand Down Expand Up @@ -123,6 +144,10 @@ export class WhatsAppMessageEncoder extends MessageEncoder<WhatsAppBot> {
if (attrs.id) {
this.buffer += `@${attrs.id}`
}
} else if (type === 'button') {
this.buttons.push(this.decodeButton(attrs, children.join('')))
} else if (type === 'button-group') {
await this.render(children)
} else if (type === 'message') {
await this.flush()
await this.render(children)
Expand Down
44 changes: 42 additions & 2 deletions adapters/whatsapp/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,24 @@ export interface MessageBodyLocation extends MessageBodyBase {
}
}

export type MessageBody = MessageBodyText | MessageBodyMedia | MessageBodySticker | MessageBodyLocation
export interface MessageBodyInteractive extends MessageBodyBase {
type: 'interactive'
interactive: {
type: 'button_reply'
button_reply: {
id: string
title: string
}
} | {
type: 'list_reply'
list_reply: {
id: string
title: string
}
}
}

export type MessageBody = MessageBodyText | MessageBodyMedia | MessageBodySticker | MessageBodyLocation | MessageBodyInteractive

export interface SendMessageBase {
messaging_product: 'whatsapp'
Expand All @@ -91,14 +108,37 @@ export type SendMessage =
SendMediaMessage<'audio'> |
SendMediaMessage<'video'> |
SendMediaMessage<'document'> |
SendMediaMessage<'sticker'>
SendMediaMessage<'sticker'> |
SendButtonMessage

export interface SendTextMessage extends SendMessageBase {
type: 'text'
text: {
body: string
}
}

export interface Button {
type: "reply"
title: string
id: string
}

/** https://developers.facebook.com/docs/whatsapp/on-premises/reference/messages#interactive-object */
export interface SendButtonMessage extends SendMessageBase {
type: 'button'
header?: object
body: {
text: string
}
footer?: {
text: string
}
action: {
buttons: Button[]
}
}

export type MediaType = 'image' | 'audio' | 'video' | 'document' | 'sticker'

type MediaDetail = { id?: string; link?: string }
Expand Down
5 changes: 5 additions & 0 deletions adapters/whatsapp/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ export async function decodeMessage(bot: WhatsAppBot, entry: Entry) {
latitude: message.location.latitude,
longitude: message.location.longitude,
})]
} else if (message.type === 'interactive' && message.interactive.type === 'button_reply') {
session.type = 'interaction/button'
session.event.button = {
id: message.interactive.button_reply.id
}
} else {
continue
}
Expand Down

0 comments on commit b703a75

Please sign in to comment.