@dev.smartpricing/message-composer-layer 4.5.1-next.0 → 4.5.1-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,6 +13,7 @@ import {
13
13
  convertToWhatsappHeaderText,
14
14
  convertToWhatsappMarkdown,
15
15
  getTipTapExtensions,
16
+ isWhatsappHeaderMultiline,
16
17
  sanitizeContent,
17
18
  } from '@dev.smartpricing/message-composer-utils/utils'
18
19
  import EmojiPickerButton from '../Common/EmojiPickerButton.vue'
@@ -278,14 +279,21 @@ const toolbarItems = computed(() => {
278
279
  // WhatsApp markdown-aware character count
279
280
  // Meta counts the final markdown output (with *bold*, _italic_ marks),
280
281
  // so we must display that count instead of TipTap's document-model count.
281
- const isWhatsapp = computed(() => props.preset === 'whatsapp' || props.preset === 'whatsapp-header')
282
+ const isWhatsappHeader = computed(() => props.preset === 'whatsapp-header')
283
+ const isWhatsapp = computed(() => props.preset === 'whatsapp' || isWhatsappHeader.value)
282
284
  const whatsappCharCount = computed(() => {
283
285
  if (!isWhatsapp.value || !props.characterLimit || !text.value) return 0
284
- return props.preset === 'whatsapp-header'
286
+ return isWhatsappHeader.value
285
287
  ? convertToWhatsappHeaderText(text.value).length
286
288
  : convertToWhatsappMarkdown(text.value).length
287
289
  })
288
290
 
291
+ // A multi-line header is still saved (its lines are joined into one when
292
+ // sent to Meta), so the editor warns instead of raising a validation error.
293
+ const hasHeaderLineBreaks = computed(
294
+ () => isWhatsappHeader.value && isWhatsappHeaderMultiline(text.value),
295
+ )
296
+
289
297
  // Handlers
290
298
  function onSelectEmoji(emoji: EmojiExt) {
291
299
  editor.value?.commands.insertContent(emoji.i)
@@ -491,6 +499,10 @@ defineExpose({
491
499
  </span>
492
500
  </p>
493
501
 
502
+ <p v-if="hasHeaderLineBreaks" class="paragraph-xs text-warning-700 pt-1.5 px-1">
503
+ {{ $t('editor.validation.header_line_breaks') }}
504
+ </p>
505
+
494
506
  <!-- AI Generate slideover -->
495
507
  </div>
496
508
  </template>
@@ -4,12 +4,10 @@ import type {
4
4
  WaButtonTypeV1,
5
5
  WhatsappMessage,
6
6
  } from '@dev.smartpricing/message-composer-utils/types'
7
- import { generateHTML } from '@tiptap/vue-3'
8
7
  import { computed } from 'vue'
9
8
  import {
9
+ convertToWhatsappHeaderText,
10
10
  generateWhatsappHtml,
11
- getTipTapExtensions,
12
- sanitizeContent,
13
11
  } from '@dev.smartpricing/message-composer-utils/utils'
14
12
  import { useResolvedParametersQuery } from '~/queries/compilation'
15
13
 
@@ -57,15 +55,10 @@ const bodyHtml = computed(() => {
57
55
  return replaceMentionsWithValues(html)
58
56
  })
59
57
 
60
- const headerHtml = computed(() => {
58
+ // Plain text, exactly as Meta receives it
59
+ const headerText = computed(() => {
61
60
  if (props.message.body.header.type !== 'text') return ''
62
- if (!props.message.body.header.content) return ''
63
- const extensions = getTipTapExtensions({ preset: 'whatsapp-header' })
64
- const html = generateHTML(
65
- sanitizeContent(props.message.body.header.content, extensions),
66
- extensions,
67
- ).replaceAll('<p></p>', '<p>&nbsp;</p>')
68
- return replaceMentionsWithValues(html)
61
+ return replaceMentionsWithValues(convertToWhatsappHeaderText(props.message.body.header.content))
69
62
  })
70
63
 
71
64
  const currentTime = computed(() => {
@@ -131,7 +124,7 @@ const getIcon = (type: WaButtonTypeV1) => {
131
124
  v-if="message.body.header.type === 'text'"
132
125
  class="text-sm text-primary-950 break-all"
133
126
  >
134
- <p v-html="headerHtml" />
127
+ <p>{{ headerText }}</p>
135
128
  </div>
136
129
  <div v-else-if="message.body.header.type === 'image'" class="mb-2">
137
130
  <img
@@ -1,10 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { JSONContent } from '@tiptap/vue-3'
3
- import { generateHTML } from '@tiptap/vue-3'
4
- import {
5
- getTipTapExtensions,
6
- sanitizeContent,
7
- } from '@dev.smartpricing/message-composer-utils/utils'
3
+ import { convertToWhatsappHeaderText } from '@dev.smartpricing/message-composer-utils/utils'
8
4
  import RichTextEditor from '@/components/Editor/RichTextEditor.vue'
9
5
  import { useAppContextStore } from '@/stores/appContext'
10
6
  import { WA_HEADER_TEXT_MAX_LENGTH } from '@dev.smartpricing/message-composer-utils/types'
@@ -22,26 +18,15 @@ const targetContent = defineModel<JSONContent | undefined>({
22
18
  })
23
19
 
24
20
  const appContext = useAppContextStore()
25
-
26
- // Generate HTML for preview of base language with rich text support
27
- function generatePreviewHtml(content: JSONContent | undefined): string {
28
- if (!content) return ''
29
- const extensions = getTipTapExtensions({ preset: 'whatsapp-header' })
30
- return generateHTML(sanitizeContent(content, extensions), extensions).replaceAll(
31
- '<p></p>',
32
- '<p>&nbsp;</p>',
33
- )
34
- }
35
21
  </script>
36
22
 
37
23
  <template>
38
24
  <div class="flex gap-8 items-start" :data-testid="whatsappTranslatorHeaderTestIds.container">
39
25
  <!-- Base language preview (read-only) -->
40
26
  <div class="flex-1 min-w-0" :data-testid="whatsappTranslatorHeaderTestIds.basePreview">
41
- <div
42
- class="paragraph-sm text-primary-700 break-words"
43
- v-html="generatePreviewHtml(baseContent)"
44
- />
27
+ <div class="paragraph-sm text-primary-700 break-words">
28
+ {{ convertToWhatsappHeaderText(baseContent) }}
29
+ </div>
45
30
  </div>
46
31
 
47
32
  <!-- Translation editor (editable) -->
@@ -512,6 +512,8 @@ export default {
512
512
  },
513
513
  validation: {
514
514
  character_limit: 'Dieses Feld hat eine Zeichenbegrenzung.',
515
+ header_line_breaks:
516
+ 'Zeilenumbrüche werden in der Kopfzeile nicht unterstützt: Die Zeilen werden zu einer zusammengefügt.',
515
517
  error: {
516
518
  atLeastOneBlockRequired: 'Mindestens ein Inhaltsblock ist erforderlich',
517
519
  bodyEmpty: 'Nachrichtentext darf nicht leer sein',
@@ -506,6 +506,8 @@ export default {
506
506
  },
507
507
  validation: {
508
508
  character_limit: 'This field has a character limit.',
509
+ header_line_breaks:
510
+ "Line breaks aren't supported in the header: the lines will be joined into one.",
509
511
  error: {
510
512
  atLeastOneBlockRequired: 'At least one content block is required',
511
513
  bodyEmpty: 'Message body cannot be empty',
@@ -508,6 +508,8 @@ export default {
508
508
  },
509
509
  validation: {
510
510
  character_limit: 'Este campo tiene un límite de caracteres.',
511
+ header_line_breaks:
512
+ 'Los saltos de línea no se admiten en el encabezado: las líneas se unirán en una sola.',
511
513
  error: {
512
514
  atLeastOneBlockRequired: 'Se requiere al menos un bloque de contenido',
513
515
  bodyEmpty: 'El cuerpo del mensaje no puede estar vacío',
@@ -509,6 +509,8 @@ export default {
509
509
  },
510
510
  validation: {
511
511
  character_limit: 'Ce champ a une limite de caractères.',
512
+ header_line_breaks:
513
+ "Les sauts de ligne ne sont pas pris en charge dans l'en-tête : les lignes seront fusionnées en une seule.",
512
514
  error: {
513
515
  atLeastOneBlockRequired: 'Au moins un bloc de contenu est requis',
514
516
  bodyEmpty: 'Le corps du message ne peut pas être vide',
@@ -507,6 +507,8 @@ export default {
507
507
  },
508
508
  validation: {
509
509
  character_limit: 'Questo campo ha un limite di caratteri.',
510
+ header_line_breaks:
511
+ "Gli a capo non sono supportati nell'intestazione: le righe verranno unite in una sola.",
510
512
  error: {
511
513
  atLeastOneBlockRequired: 'È obbligatorio almeno un blocco di contenuto',
512
514
  bodyEmpty: 'Il corpo del messaggio non può essere vuoto',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dev.smartpricing/message-composer-layer",
3
- "version": "4.5.1-next.0",
3
+ "version": "4.5.1-next.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./nuxt.config.ts",
@@ -35,7 +35,7 @@
35
35
  "vue-router": "^5.0.7",
36
36
  "vue3-emoji-picker": "^1.1.8",
37
37
  "zod": "^4.4.3",
38
- "@dev.smartpricing/message-composer-utils": "4.5.1-next.0"
38
+ "@dev.smartpricing/message-composer-utils": "4.5.1-next.1"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@dev.smartpricing/platform-layer": "^0.0.23",