diff --git a/src/api/integrations/chatbot/typebot/services/typebot.service.ts b/src/api/integrations/chatbot/typebot/services/typebot.service.ts index 8a113a2c..a9a92843 100644 --- a/src/api/integrations/chatbot/typebot/services/typebot.service.ts +++ b/src/api/integrations/chatbot/typebot/services/typebot.service.ts @@ -223,7 +223,51 @@ export class TypebotService { formattedText = formattedText.replace(/\n$/, ''); - if (formattedText.includes('[buttons]')) { + if (formattedText.includes('[list]')) { + const listJson = { + number: remoteJid.split('@')[0], + title: '', + description: '', + buttonText: '', + footerText: '', + sections: [], + }; + + const titleMatch = formattedText.match(/\[title\]([\s\S]*?)(?=\[description\])/); + const descriptionMatch = formattedText.match(/\[description\]([\s\S]*?)(?=\[buttonText\])/); + const buttonTextMatch = formattedText.match(/\[buttonText\]([\s\S]*?)(?=\[footerText\])/); + const footerTextMatch = formattedText.match(/\[footerText\]([\s\S]*?)(?=\[menu\])/); + + if (titleMatch) listJson.title = titleMatch[1].trim(); + if (descriptionMatch) listJson.description = descriptionMatch[1].trim(); + if (buttonTextMatch) listJson.buttonText = buttonTextMatch[1].trim(); + if (footerTextMatch) listJson.footerText = footerTextMatch[1].trim(); + + const menuContent = formattedText.match(/\[menu\]([\s\S]*?)\[\/menu\]/)?.[1]; + if (menuContent) { + const sections = menuContent.match(/\[section\]([\s\S]*?)(?=\[section\]|\[\/section\])/g); + if (sections) { + sections.forEach((section) => { + const sectionTitle = section.match(/title: (.*?)(?:\n|$)/)?.[1]?.trim(); + const rows = section.match(/\[row\]([\s\S]*?)(?=\[row\]|\[\/section\]|\[\/menu\])/g); + + const sectionData = { + title: sectionTitle, + rows: + rows?.map((row) => ({ + title: row.match(/title: (.*?)(?:\n|$)/)?.[1]?.trim(), + description: row.match(/description: (.*?)(?:\n|$)/)?.[1]?.trim(), + rowId: row.match(/rowId: (.*?)(?:\n|$)/)?.[1]?.trim(), + })) || [], + }; + + listJson.sections.push(sectionData); + }); + } + } + + await instance.listMessage(listJson); + } else if (formattedText.includes('[buttons]')) { const buttonJson = { number: remoteJid.split('@')[0], thumbnailUrl: undefined, @@ -302,9 +346,9 @@ export class TypebotService { }, false, ); - - sendTelemetry('/message/sendText'); } + + sendTelemetry('/message/sendText'); } if (message.type === 'image') { @@ -371,14 +415,130 @@ export class TypebotService { formattedText = formattedText.replace(/\n$/, ''); - await instance.textMessage( - { + if (formattedText.includes('[list]')) { + const listJson = { number: remoteJid.split('@')[0], - delay: settings?.delayMessage || 1000, - text: formattedText, - }, - false, - ); + title: '', + description: '', + buttonText: '', + footerText: '', + sections: [], + }; + + const titleMatch = formattedText.match(/\[title\]([\s\S]*?)(?=\[description\])/); + const descriptionMatch = formattedText.match(/\[description\]([\s\S]*?)(?=\[buttonText\])/); + const buttonTextMatch = formattedText.match(/\[buttonText\]([\s\S]*?)(?=\[footerText\])/); + const footerTextMatch = formattedText.match(/\[footerText\]([\s\S]*?)(?=\[menu\])/); + + if (titleMatch) listJson.title = titleMatch[1].trim(); + if (descriptionMatch) listJson.description = descriptionMatch[1].trim(); + if (buttonTextMatch) listJson.buttonText = buttonTextMatch[1].trim(); + if (footerTextMatch) listJson.footerText = footerTextMatch[1].trim(); + + const menuContent = formattedText.match(/\[menu\]([\s\S]*?)\[\/menu\]/)?.[1]; + if (menuContent) { + const sections = menuContent.match(/\[section\]([\s\S]*?)(?=\[section\]|\[\/section\])/g); + if (sections) { + sections.forEach((section) => { + const sectionTitle = section.match(/title: (.*?)(?:\n|$)/)?.[1]?.trim(); + const rows = section.match(/\[row\]([\s\S]*?)(?=\[row\]|\[\/section\]|\[\/menu\])/g); + + const sectionData = { + title: sectionTitle, + rows: + rows?.map((row) => ({ + title: row.match(/title: (.*?)(?:\n|$)/)?.[1]?.trim(), + description: row.match(/description: (.*?)(?:\n|$)/)?.[1]?.trim(), + rowId: row.match(/rowId: (.*?)(?:\n|$)/)?.[1]?.trim(), + })) || [], + }; + + listJson.sections.push(sectionData); + }); + } + } + + await instance.listMessage(listJson); + } else if (formattedText.includes('[buttons]')) { + const buttonJson = { + number: remoteJid.split('@')[0], + thumbnailUrl: undefined, + title: '', + description: '', + footer: '', + buttons: [], + }; + + const thumbnailUrlMatch = formattedText.match(/\[thumbnailUrl\]([\s\S]*?)(?=\[title\])/); + const titleMatch = formattedText.match(/\[title\]([\s\S]*?)(?=\[description\])/); + const descriptionMatch = formattedText.match(/\[description\]([\s\S]*?)(?=\[footer\])/); + const footerMatch = formattedText.match(/\[footer\]([\s\S]*?)(?=\[(?:reply|pix|copy|call|url))/); + + if (titleMatch) buttonJson.title = titleMatch[1].trim(); + if (thumbnailUrlMatch) buttonJson.thumbnailUrl = thumbnailUrlMatch[1].trim(); + if (descriptionMatch) buttonJson.description = descriptionMatch[1].trim(); + if (footerMatch) buttonJson.footer = footerMatch[1].trim(); + + const buttonTypes = { + reply: /\[reply\]([\s\S]*?)(?=\[(?:reply|pix|copy|call|url)|$)/g, + pix: /\[pix\]([\s\S]*?)(?=\[(?:reply|pix|copy|call|url)|$)/g, + copy: /\[copy\]([\s\S]*?)(?=\[(?:reply|pix|copy|call|url)|$)/g, + call: /\[call\]([\s\S]*?)(?=\[(?:reply|pix|copy|call|url)|$)/g, + url: /\[url\]([\s\S]*?)(?=\[(?:reply|pix|copy|call|url)|$)/g, + }; + + for (const [type, pattern] of Object.entries(buttonTypes)) { + let match; + while ((match = pattern.exec(formattedText)) !== null) { + const content = match[1].trim(); + const button: any = { type }; + + switch (type) { + case 'pix': + button.currency = content.match(/currency: (.*?)(?:\n|$)/)?.[1]?.trim(); + button.name = content.match(/name: (.*?)(?:\n|$)/)?.[1]?.trim(); + button.keyType = content.match(/keyType: (.*?)(?:\n|$)/)?.[1]?.trim(); + button.key = content.match(/key: (.*?)(?:\n|$)/)?.[1]?.trim(); + break; + + case 'reply': + button.displayText = content.match(/displayText: (.*?)(?:\n|$)/)?.[1]?.trim(); + button.id = content.match(/id: (.*?)(?:\n|$)/)?.[1]?.trim(); + break; + + case 'copy': + button.displayText = content.match(/displayText: (.*?)(?:\n|$)/)?.[1]?.trim(); + button.copyCode = content.match(/copyCode: (.*?)(?:\n|$)/)?.[1]?.trim(); + break; + + case 'call': + button.displayText = content.match(/displayText: (.*?)(?:\n|$)/)?.[1]?.trim(); + button.phoneNumber = content.match(/phone: (.*?)(?:\n|$)/)?.[1]?.trim(); + break; + + case 'url': + button.displayText = content.match(/displayText: (.*?)(?:\n|$)/)?.[1]?.trim(); + button.url = content.match(/url: (.*?)(?:\n|$)/)?.[1]?.trim(); + break; + } + + if (Object.keys(button).length > 1) { + buttonJson.buttons.push(button); + } + } + } + + await instance.buttonMessage(buttonJson); + } else { + await instance.textMessage( + { + number: remoteJid.split('@')[0], + delay: settings?.delayMessage || 1000, + text: formattedText, + }, + false, + ); + } sendTelemetry('/message/sendText'); }