Skip to content

Commit f36540a

Browse files
committed
fix: interactive buttons not rendering (viewOnceMessage → relayMessage)
- Replaced viewOnceMessage wrapper with direct interactiveMessage - Used relayMessage with additionalNodes (biz/interactive/native_flow/bot) - Added generateMessageIDV2 import from baileys - Buttons now render correctly on WhatsApp clients Fixes #1234
1 parent fa09d37 commit f36540a

1 file changed

Lines changed: 112 additions & 56 deletions

File tree

src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts

Lines changed: 112 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ import makeWASocket, {
104104
DisconnectReason,
105105
downloadContentFromMessage,
106106
downloadMediaMessage,
107+
generateMessageIDV2,
107108
generateWAMessageFromContent,
108109
getAggregateVotesInPollMessage,
109110
GetCatalogOptions,
@@ -3337,29 +3338,16 @@ export class BaileysStartupService extends ChannelStartupService {
33373338
if (hasOtherButtons) {
33383339
throw new BadRequestException('PIX button cannot be mixed with other button types');
33393340
}
3341+
}
33403342

3341-
const message: proto.IMessage = {
3342-
viewOnceMessage: {
3343-
message: {
3344-
interactiveMessage: {
3345-
nativeFlowMessage: {
3346-
buttons: [{ name: this.mapType.get('pix'), buttonParamsJson: this.toJSONString(data.buttons[0]) }],
3347-
messageParamsJson: JSON.stringify({ from: 'api', templateId: v4() }),
3348-
},
3349-
},
3350-
},
3351-
},
3352-
};
3353-
3354-
return await this.sendMessageWithTyping(data.number, message, {
3355-
delay: data?.delay,
3356-
presence: 'composing',
3357-
quoted: data?.quoted,
3358-
mentionsEveryOne: data?.mentionsEveryOne,
3359-
mentioned: data?.mentioned,
3360-
});
3343+
const isWA = (await this.whatsappNumber({ numbers: [data.number] }))?.shift();
3344+
if (!isWA.exists && !isJidGroup(isWA.jid) && !isWA.jid.includes('@broadcast')) {
3345+
throw new BadRequestException(isWA);
33613346
}
33623347

3348+
const sender = isWA.jid.toLowerCase();
3349+
const isGroup = isJidGroup(sender);
3350+
33633351
const generate = await (async () => {
33643352
if (data?.thumbnailUrl) {
33653353
return await this.prepareMediaMessage({ mediatype: 'image', media: data.thumbnailUrl });
@@ -3370,46 +3358,114 @@ export class BaileysStartupService extends ChannelStartupService {
33703358
return { name: this.mapType.get(value.type), buttonParamsJson: this.toJSONString(value) };
33713359
});
33723360

3361+
const interactiveMessage: proto.Message.IInteractiveMessage = {
3362+
body: {
3363+
text: (() => {
3364+
let t = '*' + data.title + '*';
3365+
if (data?.description) {
3366+
t += '\n\n';
3367+
t += data.description;
3368+
t += '\n';
3369+
}
3370+
return t;
3371+
})(),
3372+
},
3373+
footer: { text: data?.footer },
3374+
header: (() => {
3375+
if (generate?.message?.imageMessage) {
3376+
return {
3377+
hasMediaAttachment: !!generate.message.imageMessage,
3378+
imageMessage: generate.message.imageMessage,
3379+
};
3380+
}
3381+
})(),
3382+
nativeFlowMessage: {
3383+
buttons: buttons,
3384+
messageParamsJson: JSON.stringify({ from: 'api', templateId: v4() }),
3385+
},
3386+
};
3387+
33733388
const message: proto.IMessage = {
3374-
viewOnceMessage: {
3375-
message: {
3376-
interactiveMessage: {
3377-
body: {
3378-
text: (() => {
3379-
let t = '*' + data.title + '*';
3380-
if (data?.description) {
3381-
t += '\n\n';
3382-
t += data.description;
3383-
t += '\n';
3384-
}
3385-
return t;
3386-
})(),
3387-
},
3388-
footer: { text: data?.footer },
3389-
header: (() => {
3390-
if (generate?.message?.imageMessage) {
3391-
return {
3392-
hasMediaAttachment: !!generate.message.imageMessage,
3393-
imageMessage: generate.message.imageMessage,
3394-
};
3395-
}
3396-
})(),
3397-
nativeFlowMessage: {
3398-
buttons: buttons,
3399-
messageParamsJson: JSON.stringify({ from: 'api', templateId: v4() }),
3389+
interactiveMessage: interactiveMessage,
3390+
};
3391+
3392+
try {
3393+
if (data?.delay) {
3394+
this.logger.verbose(`Typing for ${data.delay}ms to ${sender}`);
3395+
await this.client.presenceSubscribe(sender);
3396+
await this.client.sendPresenceUpdate('composing', sender);
3397+
await delay(data.delay);
3398+
await this.client.sendPresenceUpdate('paused', sender);
3399+
}
3400+
3401+
let quoted: WAMessage;
3402+
if (data?.quoted) {
3403+
const m = data?.quoted;
3404+
const msg = m?.message ? m : ((await this.getMessage(m.key, true)) as WAMessage);
3405+
if (msg) {
3406+
quoted = msg;
3407+
}
3408+
}
3409+
3410+
const messageId = generateMessageIDV2();
3411+
const m = generateWAMessageFromContent(sender, message, {
3412+
timestamp: new Date(),
3413+
userJid: this.instance.wuid,
3414+
messageId,
3415+
quoted,
3416+
});
3417+
3418+
const additionalNodes: any[] = [
3419+
{
3420+
tag: 'biz',
3421+
attrs: {},
3422+
content: [
3423+
{
3424+
tag: 'interactive',
3425+
attrs: { type: 'native_flow', v: '1' },
3426+
content: [
3427+
{
3428+
tag: 'native_flow',
3429+
attrs: { v: '2', name: 'mixed' },
3430+
content: undefined,
3431+
},
3432+
],
34003433
},
3401-
},
3434+
],
34023435
},
3403-
},
3404-
};
3436+
];
34053437

3406-
return await this.sendMessageWithTyping(data.number, message, {
3407-
delay: data?.delay,
3408-
presence: 'composing',
3409-
quoted: data?.quoted,
3410-
mentionsEveryOne: data?.mentionsEveryOne,
3411-
mentioned: data?.mentioned,
3412-
});
3438+
if (!isGroup) {
3439+
additionalNodes[0].content.push({
3440+
tag: 'bot',
3441+
attrs: { biz_bot: '1' },
3442+
content: undefined,
3443+
});
3444+
}
3445+
3446+
const id = await this.client.relayMessage(sender, message, {
3447+
messageId,
3448+
additionalNodes,
3449+
});
3450+
3451+
m.key = {
3452+
id: id,
3453+
remoteJid: sender,
3454+
participant: isPnUser(sender) ? sender : undefined,
3455+
fromMe: true,
3456+
};
3457+
3458+
for (const [key, value] of Object.entries(m)) {
3459+
if (!value || (isArray(value) && value.length) === 0) {
3460+
delete m[key];
3461+
}
3462+
}
3463+
3464+
return m;
3465+
} catch (error) {
3466+
this.logger.error(error);
3467+
throw new InternalServerErrorException(error);
3468+
}
34133469
}
34143470

34153471
public async locationMessage(data: SendLocationDto) {

0 commit comments

Comments
 (0)