chore: Update cloud API message sending for lists and buttons

This commit updates the way messages are sent to the cloud API for lists and buttons,
adjusting the structure of the request payload. The affected files include:
- sendMessage.dto.ts: updates the format of the Button class
- sendMessage.router.ts: adds a new route for sending button messages
- whatsapp.business.service.ts: updates the handling of list and button messages
- message.schema.ts: adds a new schema for button messages

These changes improve the integration with the cloud API and allow for better handling of lists and buttons in messages.
This commit is contained in:
Davidson Gomes 2024-07-12 09:40:15 -03:00
parent 4737c71ae1
commit f6d4f940a3
4 changed files with 88 additions and 44 deletions

View File

@ -90,18 +90,15 @@ export class SendAudioDto extends Metadata {
}
class Button {
buttonText: string;
buttonId: string;
text: string;
id: string;
}
class ButtonMessage {
export class SendButtonDto extends Metadata {
title: string;
description: string;
footerText?: string;
buttons: Button[];
}
export class SendButtonDto extends Metadata {
buttonMessage: ButtonMessage;
}
export class SendLocationDto extends Metadata {
latitude: number;

View File

@ -2,6 +2,7 @@ import { RequestHandler, Router } from 'express';
import {
audioMessageSchema,
buttonMessageSchema,
contactMessageSchema,
listMessageSchema,
locationMessageSchema,
@ -16,6 +17,7 @@ import {
import { RouterBroker } from '../abstract/abstract.router';
import {
SendAudioDto,
SendButtonDto,
SendContactDto,
SendListDto,
SendLocationDto,
@ -144,17 +146,17 @@ export class MessageRouter extends RouterBroker {
});
return res.status(HttpStatus.CREATED).json(response);
});
// .post(this.routerPath('sendButtons'), ...guards, async (req, res) => {
// const response = await this.dataValidate<SendButtonDto>({
// request: req,
// schema: buttonMessageSchema,
// ClassRef: SendButtonDto,
// execute: (instance, data) => sendMessageController.sendButtons(instance, data),
// });
})
.post(this.routerPath('sendButtons'), ...guards, async (req, res) => {
const response = await this.dataValidate<SendButtonDto>({
request: req,
schema: buttonMessageSchema,
ClassRef: SendButtonDto,
execute: (instance, data) => sendMessageController.sendButtons(instance, data),
});
// return res.status(HttpStatus.CREATED).json(response);
// })
return res.status(HttpStatus.CREATED).json(response);
});
}
public readonly router = Router();

View File

@ -738,7 +738,7 @@ export class BusinessStartupService extends ChannelStartupService {
message = { conversation: `${message['text'] || 'Select'}\n` + formattedText };
return await this.post(content, 'messages');
}
if (message['sections']) {
if (message['listMessage']) {
content = {
messaging_product: 'whatsapp',
recipient_type: 'individual',
@ -748,29 +748,29 @@ export class BusinessStartupService extends ChannelStartupService {
type: 'list',
header: {
type: 'text',
text: message['title'],
text: message['listMessage']['title'],
},
body: {
text: message['text'],
text: message['listMessage']['description'],
},
footer: {
text: message['footerText'],
text: message['listMessage']['footerText'],
},
action: {
button: message['buttonText'],
sections: message['sections'],
button: message['listMessage']['buttonText'],
sections: message['listMessage']['sections'],
},
},
};
quoted ? (content.context = { message_id: quoted.id }) : content;
let formattedText = '';
for (const section of message['sections']) {
for (const section of message['listMessage']['sections']) {
formattedText += `${section?.title}\n`;
for (const row of section.rows) {
formattedText += `${row?.title}\n`;
}
}
message = { conversation: `${message['title']}\n` + formattedText };
message = { conversation: `${message['listMessage']['title']}\n` + formattedText };
return await this.post(content, 'messages');
}
if (message['template']) {
@ -993,8 +993,8 @@ export class BusinessStartupService extends ChannelStartupService {
const embeddedMedia: any = {};
const btnItems = {
text: data.buttonMessage.buttons.map((btn) => btn.buttonText),
ids: data.buttonMessage.buttons.map((btn) => btn.buttonId),
text: data.buttons.map((btn) => btn.text),
ids: data.buttons.map((btn) => btn.id),
};
if (!arrayUnique(btnItems.text) || !arrayUnique(btnItems.ids)) {
@ -1004,13 +1004,13 @@ export class BusinessStartupService extends ChannelStartupService {
return await this.sendMessageWithTyping(
data.number,
{
text: !embeddedMedia?.mediaKey ? data.buttonMessage.title : undefined,
buttons: data.buttonMessage.buttons.map((button) => {
text: !embeddedMedia?.mediaKey ? data.title : undefined,
buttons: data.buttons.map((button) => {
return {
type: 'reply',
reply: {
title: button.buttonText,
id: button.buttonId,
title: button.text,
id: button.id,
},
};
}),
@ -1058,11 +1058,10 @@ export class BusinessStartupService extends ChannelStartupService {
throw new BadRequestException('Section tiles cannot be repeated');
}
return await this.sendMessageWithTyping(
data.number,
{
const sendData: any = {
listMessage: {
title: data.title,
text: data.description,
description: data.description,
footerText: data?.footerText,
buttonText: data?.buttonText,
sections: data.sections.map((section) => {
@ -1071,22 +1070,23 @@ export class BusinessStartupService extends ChannelStartupService {
rows: section.rows.map((row) => {
return {
title: row.title,
description: row.description,
description: row.description.substring(0, 72),
id: row.rowId,
};
}),
};
}),
},
{
delay: data?.delay,
presence: 'composing',
quoted: data?.quoted,
linkPreview: data?.linkPreview,
mentionsEveryOne: data?.mentionsEveryOne,
mentioned: data?.mentioned,
},
);
};
return await this.sendMessageWithTyping(data.number, sendData, {
delay: data?.delay,
presence: 'composing',
quoted: data?.quoted,
linkPreview: data?.linkPreview,
mentionsEveryOne: data?.mentionsEveryOne,
mentioned: data?.mentioned,
});
}
public async templateMessage(data: SendTemplateDto, isIntegration = false) {

View File

@ -358,3 +358,48 @@ export const listMessageSchema: JSONSchema7 = {
},
required: ['number', 'title', 'footerText', 'buttonText', 'sections'],
};
export const buttonMessageSchema: JSONSchema7 = {
$id: v4(),
type: 'object',
properties: {
number: { ...numberDefinition },
title: { type: 'string' },
description: { type: 'string' },
footerText: { type: 'string' },
buttons: {
type: 'array',
minItems: 1,
uniqueItems: true,
items: {
type: 'object',
properties: {
text: { type: 'string' },
id: { type: 'string' },
},
required: ['text', 'id'],
...isNotEmpty('text', 'id'),
},
},
media: { type: 'string' },
fileName: { type: 'string' },
mediatype: { type: 'string', enum: ['image', 'document', 'video'] },
delay: {
type: 'integer',
description: 'Enter a value in milliseconds',
},
quoted: { ...quotedOptionsSchema },
everyOne: { type: 'boolean', enum: [true, false] },
mentioned: {
type: 'array',
minItems: 1,
uniqueItems: true,
items: {
type: 'string',
pattern: '^\\d+',
description: '"mentioned" must be an array of numeric strings',
},
},
},
required: ['number', 'title', 'buttons'],
};