@dev.smartpricing/message-composer-layer 4.3.1 → 4.3.2-chat.0

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 type {
13
13
  MessageStatus,
14
14
  MessageGroup,
15
15
  } from '@dev.smartpricing/message-composer-utils/types'
16
+ import { useAppContextStore } from '@/stores/appContext'
16
17
 
17
18
  interface TemplateData<T = Message | PostEntity<Message>> {
18
19
  messageGroup: { name: string; category: MessageGroupCategory; brand_id?: string | null }
@@ -27,6 +28,7 @@ interface UseTemplateOperationsOptions {
27
28
  export function useTemplateOperations(options: UseTemplateOperationsOptions = {}) {
28
29
  const saving = ref(false)
29
30
  const saved = ref(false)
31
+ const appContext = useAppContextStore()
30
32
 
31
33
  // Hoist composables to setup scope (they use inject() internally)
32
34
  const { mutateAsync: createMessageGroup } = useCreateMessageGroupMutation()
@@ -39,9 +41,17 @@ export function useTemplateOperations(options: UseTemplateOperationsOptions = {}
39
41
  async function createTemplate(data: TemplateData, status: MessageStatus = 'draft') {
40
42
  saving.value = true
41
43
  try {
42
- const createdMessageGroup = await createMessageGroup(
43
- data.messageGroup as PostEntity<MessageGroup>,
44
- )
44
+ // Every Message Group belongs to the context Product (ADR 0011).
45
+ const product = appContext.product
46
+ if (!product) {
47
+ throw new Error(
48
+ '[message-composer] Cannot create a template: no Product in the composer context',
49
+ )
50
+ }
51
+ const createdMessageGroup = await createMessageGroup({
52
+ ...data.messageGroup,
53
+ product,
54
+ } as PostEntity<MessageGroup>)
45
55
 
46
56
  if (createdMessageGroup?.id) {
47
57
  for (const message of Object.values(data.messages)) {
@@ -1,5 +1,6 @@
1
1
  <template>
2
2
  <SNavigationPage :panel-props="{ ui: { body: 'p-0 sm:p-0 gap-0 sm:gap-0 overflow-hidden' } }">
3
+ <CommonAppContextErrors />
3
4
  <slot />
4
5
  </SNavigationPage>
5
6
  </template>
@@ -1,4 +1,5 @@
1
1
  import { useQuery } from '@pinia/colada'
2
+ import type { DynamicValuesResponse } from '@dev.smartpricing/message-composer-utils/types'
2
3
  import { dynamicValuesApi } from '~/api'
3
4
  import { useAppContextStore } from '~/stores/appContext'
4
5
 
@@ -6,8 +7,13 @@ export function useDynamicValuesQuery() {
6
7
  const { product, mainLanguage } = storeToRefs(useAppContextStore())
7
8
 
8
9
  return useQuery({
9
- key: () => ['dynamic-values', product.value, mainLanguage.value],
10
- query: () => dynamicValuesApi.get(product.value || 'browser', mainLanguage.value || 'en'),
10
+ key: () => ['dynamic-values', product.value ?? '', mainLanguage.value],
11
+ // No Product, no request: the picker stays empty and the store lists the
12
+ // missing Product in `validationErrors`.
13
+ query: () => {
14
+ if (!product.value) return Promise.resolve<DynamicValuesResponse>({})
15
+ return dynamicValuesApi.get(product.value, mainLanguage.value || 'en')
16
+ },
11
17
  staleTime: 30 * 60 * 1000,
12
18
  })
13
19
  }
@@ -4,36 +4,38 @@ import type {
4
4
  MessageGroup,
5
5
  MessageGroupWithMessageSummary,
6
6
  PostEntity,
7
- RenderType,
8
7
  } from '@dev.smartpricing/message-composer-utils/types'
9
8
  import { messageGroupsApi } from '~/api'
9
+ import type { ListMessageGroupsOptions } from '~/api/messageGroups'
10
10
 
11
11
  // QUERIES
12
- export function useMessageGroupsQuery(
13
- options?: MaybeRefOrGetter<{
14
- renderType?: RenderType
15
- tags?: string[]
16
- tagsMode?: 'and' | 'or'
17
- }>,
18
- _queryOptions?: { polling?: boolean },
12
+ /**
13
+ * One page of the server-side filtered list, in the Laravel envelope (ADR 0012).
14
+ * The previous page stays as placeholder data while the next one loads, so
15
+ * paging and filtering never flash an empty table.
16
+ */
17
+ export function useMessageGroupListQuery(
18
+ options: MaybeRefOrGetter<ListMessageGroupsOptions>,
19
+ queryOptions: { enabled?: MaybeRefOrGetter<boolean> } = {},
19
20
  ) {
20
- const query = useQuery({
21
+ return useQuery({
21
22
  key: () => ['message-groups', JSON.stringify(toValue(options))],
22
- query: () => messageGroupsApi.getAll(toValue(options)),
23
+ query: () => messageGroupsApi.list(toValue(options)),
23
24
  staleTime: 0,
25
+ placeholderData: (previousData) => previousData,
26
+ enabled: queryOptions.enabled,
24
27
  })
25
-
26
- // TODO: Implement polling when Pinia Colada supports it
27
- // For now, polling can be done manually in the component using setInterval + refetch
28
-
29
- return query
30
28
  }
31
29
 
32
- export function useMessageGroupQuery(id: MaybeRefOrGetter<string>) {
30
+ export function useMessageGroupQuery(
31
+ id: MaybeRefOrGetter<string>,
32
+ queryOptions: { enabled?: MaybeRefOrGetter<boolean> } = {},
33
+ ) {
33
34
  return useQuery({
34
35
  key: () => ['message-groups', toValue(id)],
35
36
  query: () => messageGroupsApi.getById(toValue(id)),
36
37
  staleTime: 2 * 60 * 1000,
38
+ enabled: queryOptions.enabled,
37
39
  })
38
40
  }
39
41
 
@@ -1,7 +1,8 @@
1
1
  import { ref, computed, watch } from 'vue'
2
- import type {
3
- AppContextConfig,
4
- AppContextState,
2
+ import {
3
+ MESSAGE_GROUP_PRODUCTS,
4
+ type AppContextConfig,
5
+ type AppContextState,
5
6
  } from '@dev.smartpricing/message-composer-utils/types'
6
7
 
7
8
  export const useAppContextStore = defineStore('appContext', () => {
@@ -11,9 +12,10 @@ export const useAppContextStore = defineStore('appContext', () => {
11
12
 
12
13
  // Proxy from injection with defaults (same interface as before)
13
14
  const organization_id = computed(() => ctx.organization_id?.value ?? '')
14
- const product = computed<NonNullable<AppContextConfig['product']>>(
15
- () => ctx.product?.value ?? 'browser',
16
- )
15
+ // The Product is required by the context type (ADR 0011), but a host can
16
+ // still omit it at runtime: read defensively and list it in
17
+ // `validationErrors` rather than crashing or falling back to a fake Product.
18
+ const product = computed<AppContextConfig['product'] | undefined>(() => ctx.product?.value)
17
19
  const strategy = computed<NonNullable<AppContextConfig['strategy']>>(
18
20
  () => ctx.strategy?.value ?? 'native',
19
21
  )
@@ -59,6 +61,10 @@ export const useAppContextStore = defineStore('appContext', () => {
59
61
  const validationErrors = computed<Record<string, string>>(() => {
60
62
  const errors: Record<string, string> = {}
61
63
 
64
+ if (!product.value) {
65
+ errors.product = `Product is required: pass \`product\` (${MESSAGE_GROUP_PRODUCTS.join(' | ')}) in the composer context`
66
+ }
67
+
62
68
  if (channels.value?.includes('whatsapp') && !metaWabaId.value) {
63
69
  errors.metaConfig = 'Meta WABA ID is required for WhatsApp'
64
70
  }
@@ -1,3 +1,5 @@
1
+ import type { MessageGroupProduct } from '@dev.smartpricing/message-composer-utils/types'
2
+
1
3
  export type MessagesKind = 'email' | 'whatsapp'
2
4
 
3
5
  export interface MessageActionProperties {
@@ -83,6 +85,8 @@ export interface TrackingEventMap {
83
85
  search_term: string
84
86
  category: string
85
87
  status: string
88
+ /** The Product filter; `all` when not narrowed. */
89
+ product: MessageGroupProduct | 'all'
86
90
  messages_kind: MessagesKind
87
91
  }
88
92
  change_tab: { messages_kind: MessagesKind }
@@ -513,11 +513,16 @@ export const templateListTableTestIds = {
513
513
  searchInput: 'template-list-table-search-input',
514
514
  categorySelect: 'template-list-table-category-select',
515
515
  statusSelect: 'template-list-table-status-select',
516
+ productSelect: 'template-list-table-product-select',
517
+ visibilitySelect: 'template-list-table-visibility-select',
518
+ pagination: 'template-list-table-pagination',
519
+ paginationSummary: 'template-list-table-pagination-summary',
516
520
  card: 'template-list-table-card',
517
521
  table: 'template-list-table-table',
518
522
  rowName: 'template-list-table-row-name',
519
523
  rowInternalBadge: 'template-list-table-row-internal-badge',
520
524
  rowCategoryBadge: 'template-list-table-row-category-badge',
525
+ rowProductBadge: 'template-list-table-row-product-badge',
521
526
  rowPreview: 'template-list-table-row-preview',
522
527
  rowActions: 'template-list-table-row-actions',
523
528
  rowEditAction: 'template-list-table-row-edit',
@@ -751,6 +756,7 @@ export const previewByIdTestIds = {
751
756
 
752
757
  export const messageGroupSelectTestIds = {
753
758
  root: 'message-group-select-root',
759
+ loadMore: 'message-group-select-load-more',
754
760
  } as const
755
761
 
756
762
  /** @deprecated Use `messageGroupSelectTestIds` instead */
@@ -18,6 +18,7 @@ export default {
18
18
  all: 'Alle',
19
19
  copy: 'Kopieren',
20
20
  copy_of: 'Kopie von {name}',
21
+ context_error_title: 'Konfigurationsfehler des Composers',
21
22
  desktop: 'Desktop',
22
23
  error: 'Fehler',
23
24
  errore: 'Fehler',
@@ -58,6 +59,7 @@ export default {
58
59
  inactive_tooltip:
59
60
  'Diese Nachrichtengruppe enthält nicht genehmigte oder fehlende Nachrichten',
60
61
  hide_inactive: 'Inaktive ausblenden',
62
+ load_more: 'Mehr laden',
61
63
  },
62
64
  view_less: 'Weniger anzeigen',
63
65
  view_more: 'Mehr anzeigen',
@@ -783,20 +785,28 @@ export default {
783
785
  },
784
786
  message_library: {
785
787
  add_message_group: 'Neue Nachricht',
788
+ all_products: 'Alle Produkte',
786
789
  category_placeholder: 'Kategorie auswählen',
787
790
  headers: {
788
791
  category: 'Kategorie',
789
792
  name: 'Name',
790
793
  preview: 'Vorschau',
794
+ product: 'Produkt',
791
795
  status: 'Status',
792
- tags: 'Tags',
793
796
  updated_at: 'Aktualisiert am',
794
797
  },
798
+ pagination_summary: '{from}–{to} von {total}',
799
+ product_placeholder: 'Produkt auswählen',
795
800
  render_type_placeholder: 'Render-Typ auswählen',
796
801
  search_placeholder: 'Suchen',
797
802
  status_placeholder: 'Status auswählen',
798
- tags_placeholder: 'Nach Tags filtern',
799
803
  title: 'Nachrichtenbibliothek',
804
+ visibility: {
805
+ all: 'Alle',
806
+ internal: 'Intern',
807
+ public: 'Öffentlich',
808
+ },
809
+ visibility_placeholder: 'Sichtbarkeit auswählen',
800
810
  },
801
811
  whatsapp: {
802
812
  create_message_group: {
@@ -829,6 +839,12 @@ export default {
829
839
  },
830
840
  },
831
841
  },
842
+ products: {
843
+ chat: 'Smartchat',
844
+ connect: 'Smartconnect',
845
+ pms: 'Smartpms',
846
+ pricing: 'Smartpricing',
847
+ },
832
848
  public: {
833
849
  select_message: {
834
850
  choose_language: 'Sprache auswählen...',
@@ -18,6 +18,7 @@ export default {
18
18
  all: 'All',
19
19
  copy: 'Copy',
20
20
  copy_of: 'Copy of {name}',
21
+ context_error_title: 'Composer configuration error',
21
22
  desktop: 'Desktop',
22
23
  error: 'Error',
23
24
  errore: 'Error',
@@ -56,6 +57,7 @@ export default {
56
57
  messageGroupSelect: {
57
58
  inactive_tooltip: 'This message group has unapproved or missing messages',
58
59
  hide_inactive: 'Hide inactive',
60
+ load_more: 'Load more',
59
61
  },
60
62
  view_less: 'View less',
61
63
  view_more: 'View more',
@@ -772,20 +774,28 @@ export default {
772
774
  },
773
775
  message_library: {
774
776
  add_message_group: 'New message',
777
+ all_products: 'All products',
775
778
  category_placeholder: 'Select category',
776
779
  headers: {
777
780
  category: 'Category',
778
781
  name: 'Name',
779
782
  preview: 'Preview',
783
+ product: 'Product',
780
784
  status: 'Status',
781
- tags: 'Tags',
782
785
  updated_at: 'Updated at',
783
786
  },
787
+ pagination_summary: '{from}–{to} of {total}',
788
+ product_placeholder: 'Select product',
784
789
  render_type_placeholder: 'Select render type',
785
790
  search_placeholder: 'Search',
786
791
  status_placeholder: 'Select status',
787
- tags_placeholder: 'Filter by tags',
788
792
  title: 'Messages',
793
+ visibility: {
794
+ all: 'All',
795
+ internal: 'Internal',
796
+ public: 'Public',
797
+ },
798
+ visibility_placeholder: 'Select visibility',
789
799
  },
790
800
  whatsapp: {
791
801
  create_message_group: {
@@ -818,6 +828,12 @@ export default {
818
828
  },
819
829
  },
820
830
  },
831
+ products: {
832
+ chat: 'Smartchat',
833
+ connect: 'Smartconnect',
834
+ pms: 'Smartpms',
835
+ pricing: 'Smartpricing',
836
+ },
821
837
  public: {
822
838
  select_message: {
823
839
  choose_language: 'Choose a language...',
@@ -18,6 +18,7 @@ export default {
18
18
  all: 'Todos',
19
19
  copy: 'Copiar',
20
20
  copy_of: 'Copia de {name}',
21
+ context_error_title: 'Error de configuración del composer',
21
22
  desktop: 'Escritorio',
22
23
  error: 'Error',
23
24
  errore: 'Error',
@@ -57,6 +58,7 @@ export default {
57
58
  messageGroupSelect: {
58
59
  inactive_tooltip: 'Este grupo de mensajes tiene mensajes no aprobados o faltantes',
59
60
  hide_inactive: 'Ocultar inactivos',
61
+ load_more: 'Cargar más',
60
62
  },
61
63
  view_less: 'Ver menos',
62
64
  view_more: 'Ver más',
@@ -781,20 +783,28 @@ export default {
781
783
  },
782
784
  message_library: {
783
785
  add_message_group: 'Nuevo mensaje',
786
+ all_products: 'Todos los productos',
784
787
  category_placeholder: 'Seleccionar categoría',
785
788
  headers: {
786
789
  category: 'Categoría',
787
790
  name: 'Nombre',
788
791
  preview: 'Vista previa',
792
+ product: 'Producto',
789
793
  status: 'Estado',
790
- tags: 'Etiquetas',
791
794
  updated_at: 'Actualizado el',
792
795
  },
796
+ pagination_summary: '{from}–{to} de {total}',
797
+ product_placeholder: 'Seleccionar producto',
793
798
  render_type_placeholder: 'Seleccionar tipo de renderizado',
794
799
  search_placeholder: 'Buscar',
795
800
  status_placeholder: 'Seleccionar estado',
796
- tags_placeholder: 'Filtrar por etiquetas',
797
801
  title: 'Libreria de mensajes',
802
+ visibility: {
803
+ all: 'Todas',
804
+ internal: 'Internas',
805
+ public: 'Públicas',
806
+ },
807
+ visibility_placeholder: 'Seleccionar visibilidad',
798
808
  },
799
809
  whatsapp: {
800
810
  create_message_group: {
@@ -827,6 +837,12 @@ export default {
827
837
  },
828
838
  },
829
839
  },
840
+ products: {
841
+ chat: 'Smartchat',
842
+ connect: 'Smartconnect',
843
+ pms: 'Smartpms',
844
+ pricing: 'Smartpricing',
845
+ },
830
846
  public: {
831
847
  select_message: {
832
848
  choose_language: 'Elige un idioma...',
@@ -18,6 +18,7 @@ export default {
18
18
  all: 'Tous',
19
19
  copy: 'Copier',
20
20
  copy_of: 'Copie de {name}',
21
+ context_error_title: 'Erreur de configuration du composer',
21
22
  desktop: 'Bureau',
22
23
  error: 'Erreur',
23
24
  errore: 'Erreur',
@@ -57,6 +58,7 @@ export default {
57
58
  messageGroupSelect: {
58
59
  inactive_tooltip: 'Ce groupe de messages contient des messages non approuvés ou manquants',
59
60
  hide_inactive: 'Masquer inactifs',
61
+ load_more: 'Charger plus',
60
62
  },
61
63
  view_less: 'Afficher moins',
62
64
  view_more: 'Afficher plus',
@@ -785,20 +787,28 @@ export default {
785
787
  },
786
788
  message_library: {
787
789
  add_message_group: 'Nouveau message',
790
+ all_products: 'Tous les produits',
788
791
  category_placeholder: 'Sélectionner une catégorie',
789
792
  headers: {
790
793
  category: 'Catégorie',
791
794
  name: 'Nom',
792
795
  preview: 'Aperçu',
796
+ product: 'Produit',
793
797
  status: 'Statut',
794
- tags: 'Tags',
795
798
  updated_at: 'Mis à jour le',
796
799
  },
800
+ pagination_summary: '{from}–{to} sur {total}',
801
+ product_placeholder: 'Sélectionner un produit',
797
802
  render_type_placeholder: 'Sélectionner le type de rendu',
798
803
  search_placeholder: 'Rechercher',
799
804
  status_placeholder: 'Sélectionner un statut',
800
- tags_placeholder: 'Filtrer par tags',
801
805
  title: 'Bibliothèque de messages',
806
+ visibility: {
807
+ all: 'Toutes',
808
+ internal: 'Internes',
809
+ public: 'Publiques',
810
+ },
811
+ visibility_placeholder: 'Sélectionner la visibilité',
802
812
  },
803
813
  whatsapp: {
804
814
  create_message_group: {
@@ -831,6 +841,12 @@ export default {
831
841
  },
832
842
  },
833
843
  },
844
+ products: {
845
+ chat: 'Smartchat',
846
+ connect: 'Smartconnect',
847
+ pms: 'Smartpms',
848
+ pricing: 'Smartpricing',
849
+ },
834
850
  public: {
835
851
  select_message: {
836
852
  choose_language: 'Choisir une langue...',
@@ -18,6 +18,7 @@ export default {
18
18
  all: 'Tutti',
19
19
  copy: 'Copia',
20
20
  copy_of: 'Copia di {name}',
21
+ context_error_title: 'Errore di configurazione del composer',
21
22
  desktop: 'Desktop',
22
23
  error: 'Errore',
23
24
  errore: 'Errore',
@@ -56,6 +57,7 @@ export default {
56
57
  messageGroupSelect: {
57
58
  inactive_tooltip: 'Questo gruppo di messaggi contiene messaggi non approvati o mancanti',
58
59
  hide_inactive: 'Nascondi inattivi',
60
+ load_more: 'Carica altri',
59
61
  },
60
62
  view_less: 'Mostra meno',
61
63
  view_more: 'Mostra di più',
@@ -778,20 +780,28 @@ export default {
778
780
  },
779
781
  message_library: {
780
782
  add_message_group: 'Nuovo messaggio',
783
+ all_products: 'Tutti i prodotti',
781
784
  category_placeholder: 'Seleziona categoria',
782
785
  headers: {
783
786
  category: 'Categoria',
784
787
  name: 'Nome',
785
788
  preview: 'Anteprima',
789
+ product: 'Prodotto',
786
790
  status: 'Stato',
787
- tags: 'Tag',
788
791
  updated_at: 'Aggiornato il',
789
792
  },
793
+ pagination_summary: '{from}–{to} di {total}',
794
+ product_placeholder: 'Seleziona prodotto',
790
795
  render_type_placeholder: 'Seleziona tipo di rendering',
791
796
  search_placeholder: 'Cerca',
792
797
  status_placeholder: 'Seleziona stato',
793
- tags_placeholder: 'Filtra per tag',
794
798
  title: 'Libreria messaggi',
799
+ visibility: {
800
+ all: 'Tutte',
801
+ internal: 'Interne',
802
+ public: 'Pubbliche',
803
+ },
804
+ visibility_placeholder: 'Seleziona visibilità',
795
805
  },
796
806
  whatsapp: {
797
807
  create_message_group: {
@@ -824,6 +834,12 @@ export default {
824
834
  },
825
835
  },
826
836
  },
837
+ products: {
838
+ chat: 'Smartchat',
839
+ connect: 'Smartconnect',
840
+ pms: 'Smartpms',
841
+ pricing: 'Smartpricing',
842
+ },
827
843
  public: {
828
844
  select_message: {
829
845
  choose_language: 'Scegli una lingua...',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dev.smartpricing/message-composer-layer",
3
- "version": "4.3.1",
3
+ "version": "4.3.2-chat.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./nuxt.config.ts",
@@ -36,7 +36,7 @@
36
36
  "vue-router": "^5.0.7",
37
37
  "vue3-emoji-picker": "^1.1.8",
38
38
  "zod": "^4.4.3",
39
- "@dev.smartpricing/message-composer-utils": "4.3.1"
39
+ "@dev.smartpricing/message-composer-utils": "4.3.2-chat.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@nuxt/eslint": "^1.15.2",