@@ -223,7 +223,51 @@ export class TypebotService {
223223
224224 formattedText = formattedText . replace ( / \n $ / , '' ) ;
225225
226- if ( formattedText . includes ( '[buttons]' ) ) {
226+ if ( formattedText . includes ( '[list]' ) ) {
227+ const listJson = {
228+ number : remoteJid . split ( '@' ) [ 0 ] ,
229+ title : '' ,
230+ description : '' ,
231+ buttonText : '' ,
232+ footerText : '' ,
233+ sections : [ ] ,
234+ } ;
235+
236+ const titleMatch = formattedText . match ( / \[ t i t l e \] ( [ \s \S ] * ?) (? = \[ d e s c r i p t i o n \] ) / ) ;
237+ const descriptionMatch = formattedText . match ( / \[ d e s c r i p t i o n \] ( [ \s \S ] * ?) (? = \[ b u t t o n T e x t \] ) / ) ;
238+ const buttonTextMatch = formattedText . match ( / \[ b u t t o n T e x t \] ( [ \s \S ] * ?) (? = \[ f o o t e r T e x t \] ) / ) ;
239+ const footerTextMatch = formattedText . match ( / \[ f o o t e r T e x t \] ( [ \s \S ] * ?) (? = \[ m e n u \] ) / ) ;
240+
241+ if ( titleMatch ) listJson . title = titleMatch [ 1 ] . trim ( ) ;
242+ if ( descriptionMatch ) listJson . description = descriptionMatch [ 1 ] . trim ( ) ;
243+ if ( buttonTextMatch ) listJson . buttonText = buttonTextMatch [ 1 ] . trim ( ) ;
244+ if ( footerTextMatch ) listJson . footerText = footerTextMatch [ 1 ] . trim ( ) ;
245+
246+ const menuContent = formattedText . match ( / \[ m e n u \] ( [ \s \S ] * ?) \[ \/ m e n u \] / ) ?. [ 1 ] ;
247+ if ( menuContent ) {
248+ const sections = menuContent . match ( / \[ s e c t i o n \] ( [ \s \S ] * ?) (? = \[ s e c t i o n \] | \[ \/ s e c t i o n \] ) / g) ;
249+ if ( sections ) {
250+ sections . forEach ( ( section ) => {
251+ const sectionTitle = section . match ( / t i t l e : ( .* ?) (?: \n | $ ) / ) ?. [ 1 ] ?. trim ( ) ;
252+ const rows = section . match ( / \[ r o w \] ( [ \s \S ] * ?) (? = \[ r o w \] | \[ \/ s e c t i o n \] | \[ \/ m e n u \] ) / g) ;
253+
254+ const sectionData = {
255+ title : sectionTitle ,
256+ rows :
257+ rows ?. map ( ( row ) => ( {
258+ title : row . match ( / t i t l e : ( .* ?) (?: \n | $ ) / ) ?. [ 1 ] ?. trim ( ) ,
259+ description : row . match ( / d e s c r i p t i o n : ( .* ?) (?: \n | $ ) / ) ?. [ 1 ] ?. trim ( ) ,
260+ rowId : row . match ( / r o w I d : ( .* ?) (?: \n | $ ) / ) ?. [ 1 ] ?. trim ( ) ,
261+ } ) ) || [ ] ,
262+ } ;
263+
264+ listJson . sections . push ( sectionData ) ;
265+ } ) ;
266+ }
267+ }
268+
269+ await instance . listMessage ( listJson ) ;
270+ } else if ( formattedText . includes ( '[buttons]' ) ) {
227271 const buttonJson = {
228272 number : remoteJid . split ( '@' ) [ 0 ] ,
229273 thumbnailUrl : undefined ,
@@ -302,9 +346,9 @@ export class TypebotService {
302346 } ,
303347 false ,
304348 ) ;
305-
306- sendTelemetry ( '/message/sendText' ) ;
307349 }
350+
351+ sendTelemetry ( '/message/sendText' ) ;
308352 }
309353
310354 if ( message . type === 'image' ) {
@@ -371,14 +415,130 @@ export class TypebotService {
371415
372416 formattedText = formattedText . replace ( / \n $ / , '' ) ;
373417
374- await instance . textMessage (
375- {
418+ if ( formattedText . includes ( '[list]' ) ) {
419+ const listJson = {
376420 number : remoteJid . split ( '@' ) [ 0 ] ,
377- delay : settings ?. delayMessage || 1000 ,
378- text : formattedText ,
379- } ,
380- false ,
381- ) ;
421+ title : '' ,
422+ description : '' ,
423+ buttonText : '' ,
424+ footerText : '' ,
425+ sections : [ ] ,
426+ } ;
427+
428+ const titleMatch = formattedText . match ( / \[ t i t l e \] ( [ \s \S ] * ?) (? = \[ d e s c r i p t i o n \] ) / ) ;
429+ const descriptionMatch = formattedText . match ( / \[ d e s c r i p t i o n \] ( [ \s \S ] * ?) (? = \[ b u t t o n T e x t \] ) / ) ;
430+ const buttonTextMatch = formattedText . match ( / \[ b u t t o n T e x t \] ( [ \s \S ] * ?) (? = \[ f o o t e r T e x t \] ) / ) ;
431+ const footerTextMatch = formattedText . match ( / \[ f o o t e r T e x t \] ( [ \s \S ] * ?) (? = \[ m e n u \] ) / ) ;
432+
433+ if ( titleMatch ) listJson . title = titleMatch [ 1 ] . trim ( ) ;
434+ if ( descriptionMatch ) listJson . description = descriptionMatch [ 1 ] . trim ( ) ;
435+ if ( buttonTextMatch ) listJson . buttonText = buttonTextMatch [ 1 ] . trim ( ) ;
436+ if ( footerTextMatch ) listJson . footerText = footerTextMatch [ 1 ] . trim ( ) ;
437+
438+ const menuContent = formattedText . match ( / \[ m e n u \] ( [ \s \S ] * ?) \[ \/ m e n u \] / ) ?. [ 1 ] ;
439+ if ( menuContent ) {
440+ const sections = menuContent . match ( / \[ s e c t i o n \] ( [ \s \S ] * ?) (? = \[ s e c t i o n \] | \[ \/ s e c t i o n \] ) / g) ;
441+ if ( sections ) {
442+ sections . forEach ( ( section ) => {
443+ const sectionTitle = section . match ( / t i t l e : ( .* ?) (?: \n | $ ) / ) ?. [ 1 ] ?. trim ( ) ;
444+ const rows = section . match ( / \[ r o w \] ( [ \s \S ] * ?) (? = \[ r o w \] | \[ \/ s e c t i o n \] | \[ \/ m e n u \] ) / g) ;
445+
446+ const sectionData = {
447+ title : sectionTitle ,
448+ rows :
449+ rows ?. map ( ( row ) => ( {
450+ title : row . match ( / t i t l e : ( .* ?) (?: \n | $ ) / ) ?. [ 1 ] ?. trim ( ) ,
451+ description : row . match ( / d e s c r i p t i o n : ( .* ?) (?: \n | $ ) / ) ?. [ 1 ] ?. trim ( ) ,
452+ rowId : row . match ( / r o w I d : ( .* ?) (?: \n | $ ) / ) ?. [ 1 ] ?. trim ( ) ,
453+ } ) ) || [ ] ,
454+ } ;
455+
456+ listJson . sections . push ( sectionData ) ;
457+ } ) ;
458+ }
459+ }
460+
461+ await instance . listMessage ( listJson ) ;
462+ } else if ( formattedText . includes ( '[buttons]' ) ) {
463+ const buttonJson = {
464+ number : remoteJid . split ( '@' ) [ 0 ] ,
465+ thumbnailUrl : undefined ,
466+ title : '' ,
467+ description : '' ,
468+ footer : '' ,
469+ buttons : [ ] ,
470+ } ;
471+
472+ const thumbnailUrlMatch = formattedText . match ( / \[ t h u m b n a i l U r l \] ( [ \s \S ] * ?) (? = \[ t i t l e \] ) / ) ;
473+ const titleMatch = formattedText . match ( / \[ t i t l e \] ( [ \s \S ] * ?) (? = \[ d e s c r i p t i o n \] ) / ) ;
474+ const descriptionMatch = formattedText . match ( / \[ d e s c r i p t i o n \] ( [ \s \S ] * ?) (? = \[ f o o t e r \] ) / ) ;
475+ const footerMatch = formattedText . match ( / \[ f o o t e r \] ( [ \s \S ] * ?) (? = \[ (?: r e p l y | p i x | c o p y | c a l l | u r l ) ) / ) ;
476+
477+ if ( titleMatch ) buttonJson . title = titleMatch [ 1 ] . trim ( ) ;
478+ if ( thumbnailUrlMatch ) buttonJson . thumbnailUrl = thumbnailUrlMatch [ 1 ] . trim ( ) ;
479+ if ( descriptionMatch ) buttonJson . description = descriptionMatch [ 1 ] . trim ( ) ;
480+ if ( footerMatch ) buttonJson . footer = footerMatch [ 1 ] . trim ( ) ;
481+
482+ const buttonTypes = {
483+ reply : / \[ r e p l y \] ( [ \s \S ] * ?) (? = \[ (?: r e p l y | p i x | c o p y | c a l l | u r l ) | $ ) / g,
484+ pix : / \[ p i x \] ( [ \s \S ] * ?) (? = \[ (?: r e p l y | p i x | c o p y | c a l l | u r l ) | $ ) / g,
485+ copy : / \[ c o p y \] ( [ \s \S ] * ?) (? = \[ (?: r e p l y | p i x | c o p y | c a l l | u r l ) | $ ) / g,
486+ call : / \[ c a l l \] ( [ \s \S ] * ?) (? = \[ (?: r e p l y | p i x | c o p y | c a l l | u r l ) | $ ) / g,
487+ url : / \[ u r l \] ( [ \s \S ] * ?) (? = \[ (?: r e p l y | p i x | c o p y | c a l l | u r l ) | $ ) / g,
488+ } ;
489+
490+ for ( const [ type , pattern ] of Object . entries ( buttonTypes ) ) {
491+ let match ;
492+ while ( ( match = pattern . exec ( formattedText ) ) !== null ) {
493+ const content = match [ 1 ] . trim ( ) ;
494+ const button : any = { type } ;
495+
496+ switch ( type ) {
497+ case 'pix' :
498+ button . currency = content . match ( / c u r r e n c y : ( .* ?) (?: \n | $ ) / ) ?. [ 1 ] ?. trim ( ) ;
499+ button . name = content . match ( / n a m e : ( .* ?) (?: \n | $ ) / ) ?. [ 1 ] ?. trim ( ) ;
500+ button . keyType = content . match ( / k e y T y p e : ( .* ?) (?: \n | $ ) / ) ?. [ 1 ] ?. trim ( ) ;
501+ button . key = content . match ( / k e y : ( .* ?) (?: \n | $ ) / ) ?. [ 1 ] ?. trim ( ) ;
502+ break ;
503+
504+ case 'reply' :
505+ button . displayText = content . match ( / d i s p l a y T e x t : ( .* ?) (?: \n | $ ) / ) ?. [ 1 ] ?. trim ( ) ;
506+ button . id = content . match ( / i d : ( .* ?) (?: \n | $ ) / ) ?. [ 1 ] ?. trim ( ) ;
507+ break ;
508+
509+ case 'copy' :
510+ button . displayText = content . match ( / d i s p l a y T e x t : ( .* ?) (?: \n | $ ) / ) ?. [ 1 ] ?. trim ( ) ;
511+ button . copyCode = content . match ( / c o p y C o d e : ( .* ?) (?: \n | $ ) / ) ?. [ 1 ] ?. trim ( ) ;
512+ break ;
513+
514+ case 'call' :
515+ button . displayText = content . match ( / d i s p l a y T e x t : ( .* ?) (?: \n | $ ) / ) ?. [ 1 ] ?. trim ( ) ;
516+ button . phoneNumber = content . match ( / p h o n e : ( .* ?) (?: \n | $ ) / ) ?. [ 1 ] ?. trim ( ) ;
517+ break ;
518+
519+ case 'url' :
520+ button . displayText = content . match ( / d i s p l a y T e x t : ( .* ?) (?: \n | $ ) / ) ?. [ 1 ] ?. trim ( ) ;
521+ button . url = content . match ( / u r l : ( .* ?) (?: \n | $ ) / ) ?. [ 1 ] ?. trim ( ) ;
522+ break ;
523+ }
524+
525+ if ( Object . keys ( button ) . length > 1 ) {
526+ buttonJson . buttons . push ( button ) ;
527+ }
528+ }
529+ }
530+
531+ await instance . buttonMessage ( buttonJson ) ;
532+ } else {
533+ await instance . textMessage (
534+ {
535+ number : remoteJid . split ( '@' ) [ 0 ] ,
536+ delay : settings ?. delayMessage || 1000 ,
537+ text : formattedText ,
538+ } ,
539+ false ,
540+ ) ;
541+ }
382542
383543 sendTelemetry ( '/message/sendText' ) ;
384544 }
0 commit comments