@adatechnology/conversations-ui 0.1.0-rc.35 → 0.1.0-rc.36

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.
package/dist/index.d.ts CHANGED
@@ -1334,12 +1334,20 @@ interface WhatsAppTemplatesSettingsProps {
1334
1334
  submitting?: boolean;
1335
1335
  result?: WhatsAppCreateTemplateResult | null;
1336
1336
  labels?: Partial<WhatsAppCreateTemplateFormLabels>;
1337
+ /** Nome exibido na prévia do template criado; sem isto o form usa seu próprio fallback. */
1338
+ previewCompanyName?: string;
1339
+ variableExamples?: readonly string[];
1337
1340
  };
1338
1341
  labels?: Partial<WhatsAppTemplatesSettingsLabels>;
1339
1342
  /** Vocabulário do formulário de seleção — separado de `labels`, que nomeia só as abas daqui. */
1340
1343
  settingsLabels?: Partial<WhatsAppTemplateSettingsFormLabels>;
1344
+ /**
1345
+ * Formulários extras de seleção (um por papel adicional de template, ex.: despedida), empilhados
1346
+ * abaixo do principal na mesma sub-aba. Ausente = só o papel principal, comportamento de sempre.
1347
+ */
1348
+ extraRoleForms?: ReactNode;
1341
1349
  }
1342
- declare function WhatsAppTemplatesSettings({ labels: labelsOverride, settingsLabels, create, ...settingsProps }: WhatsAppTemplatesSettingsProps): react.JSX.Element;
1350
+ declare function WhatsAppTemplatesSettings({ labels: labelsOverride, settingsLabels, create, extraRoleForms, ...settingsProps }: WhatsAppTemplatesSettingsProps): react.JSX.Element;
1343
1351
 
1344
1352
  interface TopicItem {
1345
1353
  key: string;
@@ -1374,6 +1382,22 @@ interface TemplateSettings {
1374
1382
  templateLanguage: string;
1375
1383
  variables: string[];
1376
1384
  }
1385
+ /**
1386
+ * Papel adicional de template (ex.: despedida) além do principal (`getTemplateSettings`/
1387
+ * `saveTemplateSettings`). Cada papel ganha seu próprio formulário empilhado na mesma aba, com
1388
+ * carregamento e salvamento independentes — é o que permite hosts com mais de um papel (o
1389
+ * financiamento tem boas-vindas + despedida) convergirem para este componente em vez de remontar
1390
+ * a tela à parte.
1391
+ */
1392
+ interface MessagesWorkspaceTemplateRole {
1393
+ readonly key: string;
1394
+ readonly labels: {
1395
+ sectionTitle: string;
1396
+ sectionDescription: string;
1397
+ };
1398
+ getSettings(): Promise<TemplateSettings>;
1399
+ saveSettings(settings: TemplateSettings): Promise<void>;
1400
+ }
1377
1401
  interface TranscriptionSettings {
1378
1402
  enabled: boolean;
1379
1403
  mode: TranscriptionMode;
@@ -1388,6 +1412,8 @@ interface MessagesWorkspaceApi {
1388
1412
  /** Sem este par, a aba de templates não é desenhada. */
1389
1413
  getTemplateSettings?(): Promise<TemplateSettings>;
1390
1414
  saveTemplateSettings?(settings: TemplateSettings): Promise<void>;
1415
+ /** Papéis adicionais de template (ex.: despedida) além do principal acima. */
1416
+ templateRoles?: MessagesWorkspaceTemplateRole[];
1391
1417
  /**
1392
1418
  * Lista de templates aprovados na Meta. Ausente, a aba ainda existe (dá para salvar o nome
1393
1419
  * escolhido), mas nasce sem opções e sem botão de recarregar.
@@ -1422,9 +1448,12 @@ interface MessagesWorkspaceProps {
1422
1448
  readonly availableVariables?: WhatsAppTemplateVariableSuggestion[];
1423
1449
  /** Aviso do produto acima da aba de templates (ex.: rota da Graph API ainda não implementada). */
1424
1450
  readonly renderTemplatesNotice?: () => ReactNode;
1451
+ /** Repassados ao formulário de criação — mesma prévia que `WhatsAppCreateTemplateForm` já suporta. */
1452
+ readonly createTemplatePreviewCompanyName?: string;
1453
+ readonly createTemplateVariableExamples?: readonly string[];
1425
1454
  readonly className?: string;
1426
1455
  }
1427
- declare function MessagesWorkspace({ api, labels: labelsOverride, welcomePlaceholders, farewellPlaceholders, availableVariables, renderTemplatesNotice, className, }: MessagesWorkspaceProps): react.JSX.Element;
1456
+ declare function MessagesWorkspace({ api, labels: labelsOverride, welcomePlaceholders, farewellPlaceholders, availableVariables, renderTemplatesNotice, createTemplatePreviewCompanyName, createTemplateVariableExamples, className, }: MessagesWorkspaceProps): react.JSX.Element;
1428
1457
 
1429
1458
  interface UseConversationMessagesResult {
1430
1459
  messages: MessagePayload[];
package/dist/index.js CHANGED
@@ -3267,6 +3267,7 @@ function WhatsAppTemplatesSettings({
3267
3267
  labels: labelsOverride,
3268
3268
  settingsLabels,
3269
3269
  create,
3270
+ extraRoleForms,
3270
3271
  ...settingsProps
3271
3272
  }) {
3272
3273
  const labels = { ...DEFAULT_TEMPLATES_SETTINGS_LABELS, ...labelsOverride };
@@ -3300,7 +3301,10 @@ function WhatsAppTemplatesSettings({
3300
3301
  }
3301
3302
  ) : null
3302
3303
  ] }),
3303
- tab === TEMPLATE_SETTINGS_TAB.SELECT ? /* @__PURE__ */ jsx22(WhatsAppTemplateSettingsForm, { ...settingsProps, ...settingsLabels ? { labels: settingsLabels } : {} }) : create ? /* @__PURE__ */ jsx22(WhatsAppCreateTemplateForm, { ...create }) : null
3304
+ tab === TEMPLATE_SETTINGS_TAB.SELECT ? /* @__PURE__ */ jsxs20("div", { className: "space-y-6", children: [
3305
+ /* @__PURE__ */ jsx22(WhatsAppTemplateSettingsForm, { ...settingsProps, ...settingsLabels ? { labels: settingsLabels } : {} }),
3306
+ extraRoleForms
3307
+ ] }) : create ? /* @__PURE__ */ jsx22(WhatsAppCreateTemplateForm, { ...create }) : null
3304
3308
  ] });
3305
3309
  }
3306
3310
 
@@ -3390,7 +3394,7 @@ function TopicsForm({
3390
3394
 
3391
3395
  // src/settings/MessagesWorkspace.tsx
3392
3396
  import { useCallback as useCallback6, useEffect as useEffect9, useState as useState14 } from "react";
3393
- import { jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
3397
+ import { Fragment as Fragment6, jsx as jsx24, jsxs as jsxs22 } from "react/jsx-runtime";
3394
3398
  var DEFAULT_LABELS7 = {
3395
3399
  title: "Mensagens",
3396
3400
  subtitle: "Mensagens do bot e templates do WhatsApp.",
@@ -3439,9 +3443,12 @@ function MessagesWorkspace({
3439
3443
  farewellPlaceholders,
3440
3444
  availableVariables,
3441
3445
  renderTemplatesNotice,
3446
+ createTemplatePreviewCompanyName,
3447
+ createTemplateVariableExamples,
3442
3448
  className
3443
3449
  }) {
3444
3450
  const labels = { ...DEFAULT_LABELS7, ...labelsOverride };
3451
+ const templateRoles = api.templateRoles ?? [];
3445
3452
  const hasTopics = Boolean(api.getTopics && api.saveTopics);
3446
3453
  const hasTemplates = Boolean(api.getTemplateSettings && api.saveTemplateSettings);
3447
3454
  const hasTranscription = Boolean(api.getTranscription && api.saveTranscription);
@@ -3459,6 +3466,9 @@ function MessagesWorkspace({
3459
3466
  const [templatesError, setTemplatesError] = useState14(false);
3460
3467
  const [savingTemplate, setSavingTemplate] = useState14(false);
3461
3468
  const [templateSaved, setTemplateSaved] = useState14(false);
3469
+ const [roleSettings, setRoleSettings] = useState14({});
3470
+ const [savingRole, setSavingRole] = useState14({});
3471
+ const [roleSaved, setRoleSaved] = useState14({});
3462
3472
  const [createTemplate, setCreateTemplate] = useState14(EMPTY_CREATE_TEMPLATE);
3463
3473
  const [creatingTemplate, setCreatingTemplate] = useState14(false);
3464
3474
  const [createResult, setCreateResult] = useState14(null);
@@ -3481,17 +3491,20 @@ function MessagesWorkspace({
3481
3491
  let active = true;
3482
3492
  async function load() {
3483
3493
  try {
3484
- const [loadedMessages, loadedTopics, loadedTemplateSettings, loadedTranscription] = await Promise.all([
3494
+ const roles = api.templateRoles ?? [];
3495
+ const [loadedMessages, loadedTopics, loadedTemplateSettings, loadedTranscription, loadedRoleSettings] = await Promise.all([
3485
3496
  api.getMessages(),
3486
3497
  api.getTopics?.(),
3487
3498
  api.getTemplateSettings?.(),
3488
- api.getTranscription?.()
3499
+ api.getTranscription?.(),
3500
+ Promise.all(roles.map((role) => role.getSettings()))
3489
3501
  ]);
3490
3502
  if (!active) return;
3491
3503
  setMessages(loadedMessages);
3492
3504
  if (loadedTopics) setTopics(loadedTopics);
3493
3505
  if (loadedTemplateSettings) setTemplateSettings(loadedTemplateSettings);
3494
3506
  if (loadedTranscription) setTranscription(loadedTranscription);
3507
+ setRoleSettings(Object.fromEntries(roles.map((role, index) => [role.key, loadedRoleSettings[index]])));
3495
3508
  setLoadState("ready");
3496
3509
  } catch {
3497
3510
  if (active) setLoadState("error");
@@ -3541,6 +3554,36 @@ function MessagesWorkspace({
3541
3554
  setSavingTemplate(false);
3542
3555
  }
3543
3556
  }
3557
+ function handleSaveRole(role) {
3558
+ return async (event) => {
3559
+ event.preventDefault();
3560
+ const settings = roleSettings[role.key];
3561
+ if (!settings) return;
3562
+ setSavingRole((previous) => ({ ...previous, [role.key]: true }));
3563
+ try {
3564
+ await role.saveSettings(settings);
3565
+ setRoleSaved((previous) => ({ ...previous, [role.key]: true }));
3566
+ setTimeout(() => setRoleSaved((previous) => ({ ...previous, [role.key]: false })), SAVE_FEEDBACK_MS);
3567
+ } finally {
3568
+ setSavingRole((previous) => ({ ...previous, [role.key]: false }));
3569
+ }
3570
+ };
3571
+ }
3572
+ function handleSelectRoleTemplate(role, name, template) {
3573
+ setRoleSettings((previous) => {
3574
+ const current = previous[role.key] ?? EMPTY_TEMPLATE_SETTINGS;
3575
+ if (!template) return { ...previous, [role.key]: { ...current, templateName: name } };
3576
+ const shouldSeedVariables = template.variableCount > 0 && current.variables.length === 0;
3577
+ return {
3578
+ ...previous,
3579
+ [role.key]: {
3580
+ templateName: name,
3581
+ templateLanguage: template.language,
3582
+ variables: shouldSeedVariables ? Array.from({ length: template.variableCount }, () => "") : current.variables
3583
+ }
3584
+ };
3585
+ });
3586
+ }
3544
3587
  async function handleCreateTemplate(event) {
3545
3588
  event.preventDefault();
3546
3589
  if (!api.createTemplate) return;
@@ -3671,8 +3714,37 @@ function MessagesWorkspace({
3671
3714
  onSubmit: handleCreateTemplate,
3672
3715
  submitting: creatingTemplate,
3673
3716
  result: createResult,
3674
- labels: labels.createTemplate
3717
+ labels: labels.createTemplate,
3718
+ ...createTemplatePreviewCompanyName ? { previewCompanyName: createTemplatePreviewCompanyName } : {},
3719
+ ...createTemplateVariableExamples ? { variableExamples: createTemplateVariableExamples } : {}
3675
3720
  }
3721
+ } : {},
3722
+ ...templateRoles.length > 0 ? {
3723
+ extraRoleForms: /* @__PURE__ */ jsx24(Fragment6, { children: templateRoles.map((role) => {
3724
+ const settings = roleSettings[role.key] ?? EMPTY_TEMPLATE_SETTINGS;
3725
+ return /* @__PURE__ */ jsx24(
3726
+ WhatsAppTemplateSettingsForm,
3727
+ {
3728
+ templates,
3729
+ loadingTemplates,
3730
+ templatesError,
3731
+ selectedTemplateName: settings.templateName,
3732
+ onSelectTemplate: (name, template) => handleSelectRoleTemplate(role, name, template),
3733
+ variables: settings.variables,
3734
+ onVariablesChange: (variables) => setRoleSettings((previous) => ({
3735
+ ...previous,
3736
+ [role.key]: { ...previous[role.key] ?? EMPTY_TEMPLATE_SETTINGS, variables }
3737
+ })),
3738
+ onSave: handleSaveRole(role),
3739
+ saving: Boolean(savingRole[role.key]),
3740
+ saveSuccess: Boolean(roleSaved[role.key]),
3741
+ labels: { ...labels.templateSettings, ...role.labels },
3742
+ ...api.listTemplates ? { onRefreshTemplates: () => void reloadTemplates() } : {},
3743
+ ...availableVariables ? { availableVariables } : {}
3744
+ },
3745
+ role.key
3746
+ );
3747
+ }) })
3676
3748
  } : {}
3677
3749
  }
3678
3750
  )
@@ -4591,7 +4663,7 @@ function useConversationsInbox(params = {}) {
4591
4663
  }
4592
4664
 
4593
4665
  // src/workspace/ConversationsWorkspace.tsx
4594
- import { Fragment as Fragment6, jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
4666
+ import { Fragment as Fragment7, jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
4595
4667
  function ConversationsWorkspace({
4596
4668
  labels: labelsOverride,
4597
4669
  filters,
@@ -4764,7 +4836,7 @@ function ConversationsWorkspace({
4764
4836
  ] }),
4765
4837
  inbox.loadFailure ? /* @__PURE__ */ jsxs26("p", { role: "alert", className: "cv-workspace-failure", children: [
4766
4838
  inbox.loadFailure,
4767
- signInHref ? /* @__PURE__ */ jsxs26(Fragment6, { children: [
4839
+ signInHref ? /* @__PURE__ */ jsxs26(Fragment7, { children: [
4768
4840
  " ",
4769
4841
  /* @__PURE__ */ jsx28("a", { href: signInHref, className: "cv-workspace-failure__link", children: labels.signIn })
4770
4842
  ] }) : null
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adatechnology/conversations-ui",
3
- "version": "0.1.0-rc.35",
3
+ "version": "0.1.0-rc.36",
4
4
  "description": "WhatsApp conversation UI components — parametrizável por endpoint, tema e feature flags",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -18,10 +18,11 @@ import {
18
18
  WhatsAppTemplatesSettings,
19
19
  type WhatsAppTemplatesSettingsLabels,
20
20
  } from './WhatsAppTemplatesSettings'
21
- import type {
22
- WhatsAppTemplateSummary,
23
- WhatsAppTemplateVariableSuggestion,
24
- WhatsAppTemplateSettingsFormLabels,
21
+ import {
22
+ WhatsAppTemplateSettingsForm,
23
+ type WhatsAppTemplateSummary,
24
+ type WhatsAppTemplateVariableSuggestion,
25
+ type WhatsAppTemplateSettingsFormLabels,
25
26
  } from './WhatsAppTemplateSettingsForm'
26
27
  import type {
27
28
  WhatsAppCreateTemplateFormLabels,
@@ -46,6 +47,20 @@ export interface TemplateSettings {
46
47
  variables: string[]
47
48
  }
48
49
 
50
+ /**
51
+ * Papel adicional de template (ex.: despedida) além do principal (`getTemplateSettings`/
52
+ * `saveTemplateSettings`). Cada papel ganha seu próprio formulário empilhado na mesma aba, com
53
+ * carregamento e salvamento independentes — é o que permite hosts com mais de um papel (o
54
+ * financiamento tem boas-vindas + despedida) convergirem para este componente em vez de remontar
55
+ * a tela à parte.
56
+ */
57
+ export interface MessagesWorkspaceTemplateRole {
58
+ readonly key: string
59
+ readonly labels: { sectionTitle: string; sectionDescription: string }
60
+ getSettings(): Promise<TemplateSettings>
61
+ saveSettings(settings: TemplateSettings): Promise<void>
62
+ }
63
+
49
64
  export interface TranscriptionSettings {
50
65
  enabled: boolean
51
66
  mode: TranscriptionMode
@@ -61,6 +76,8 @@ export interface MessagesWorkspaceApi {
61
76
  /** Sem este par, a aba de templates não é desenhada. */
62
77
  getTemplateSettings?(): Promise<TemplateSettings>
63
78
  saveTemplateSettings?(settings: TemplateSettings): Promise<void>
79
+ /** Papéis adicionais de template (ex.: despedida) além do principal acima. */
80
+ templateRoles?: MessagesWorkspaceTemplateRole[]
64
81
  /**
65
82
  * Lista de templates aprovados na Meta. Ausente, a aba ainda existe (dá para salvar o nome
66
83
  * escolhido), mas nasce sem opções e sem botão de recarregar.
@@ -150,6 +167,9 @@ export interface MessagesWorkspaceProps {
150
167
  readonly availableVariables?: WhatsAppTemplateVariableSuggestion[]
151
168
  /** Aviso do produto acima da aba de templates (ex.: rota da Graph API ainda não implementada). */
152
169
  readonly renderTemplatesNotice?: () => ReactNode
170
+ /** Repassados ao formulário de criação — mesma prévia que `WhatsAppCreateTemplateForm` já suporta. */
171
+ readonly createTemplatePreviewCompanyName?: string
172
+ readonly createTemplateVariableExamples?: readonly string[]
153
173
  readonly className?: string
154
174
  }
155
175
 
@@ -160,9 +180,12 @@ export function MessagesWorkspace({
160
180
  farewellPlaceholders,
161
181
  availableVariables,
162
182
  renderTemplatesNotice,
183
+ createTemplatePreviewCompanyName,
184
+ createTemplateVariableExamples,
163
185
  className,
164
186
  }: MessagesWorkspaceProps) {
165
187
  const labels = { ...DEFAULT_LABELS, ...labelsOverride }
188
+ const templateRoles = api.templateRoles ?? []
166
189
 
167
190
  const hasTopics = Boolean(api.getTopics && api.saveTopics)
168
191
  const hasTemplates = Boolean(api.getTemplateSettings && api.saveTemplateSettings)
@@ -186,6 +209,10 @@ export function MessagesWorkspace({
186
209
  const [savingTemplate, setSavingTemplate] = useState(false)
187
210
  const [templateSaved, setTemplateSaved] = useState(false)
188
211
 
212
+ const [roleSettings, setRoleSettings] = useState<Record<string, TemplateSettings>>({})
213
+ const [savingRole, setSavingRole] = useState<Record<string, boolean>>({})
214
+ const [roleSaved, setRoleSaved] = useState<Record<string, boolean>>({})
215
+
189
216
  const [createTemplate, setCreateTemplate] = useState<WhatsAppCreateTemplateState>(EMPTY_CREATE_TEMPLATE)
190
217
  const [creatingTemplate, setCreatingTemplate] = useState(false)
191
218
  const [createResult, setCreateResult] = useState<WhatsAppCreateTemplateResult | null>(null)
@@ -211,17 +238,21 @@ export function MessagesWorkspace({
211
238
  let active = true
212
239
  async function load(): Promise<void> {
213
240
  try {
214
- const [loadedMessages, loadedTopics, loadedTemplateSettings, loadedTranscription] = await Promise.all([
215
- api.getMessages(),
216
- api.getTopics?.(),
217
- api.getTemplateSettings?.(),
218
- api.getTranscription?.(),
219
- ])
241
+ const roles = api.templateRoles ?? []
242
+ const [loadedMessages, loadedTopics, loadedTemplateSettings, loadedTranscription, loadedRoleSettings] =
243
+ await Promise.all([
244
+ api.getMessages(),
245
+ api.getTopics?.(),
246
+ api.getTemplateSettings?.(),
247
+ api.getTranscription?.(),
248
+ Promise.all(roles.map((role) => role.getSettings())),
249
+ ])
220
250
  if (!active) return
221
251
  setMessages(loadedMessages)
222
252
  if (loadedTopics) setTopics(loadedTopics)
223
253
  if (loadedTemplateSettings) setTemplateSettings(loadedTemplateSettings)
224
254
  if (loadedTranscription) setTranscription(loadedTranscription)
255
+ setRoleSettings(Object.fromEntries(roles.map((role, index) => [role.key, loadedRoleSettings[index]])))
225
256
  setLoadState('ready')
226
257
  } catch {
227
258
  if (active) setLoadState('error')
@@ -279,6 +310,42 @@ export function MessagesWorkspace({
279
310
  }
280
311
  }
281
312
 
313
+ function handleSaveRole(role: MessagesWorkspaceTemplateRole): (event: FormEvent) => Promise<void> {
314
+ return async (event: FormEvent) => {
315
+ event.preventDefault()
316
+ const settings = roleSettings[role.key]
317
+ if (!settings) return
318
+ setSavingRole((previous) => ({ ...previous, [role.key]: true }))
319
+ try {
320
+ await role.saveSettings(settings)
321
+ setRoleSaved((previous) => ({ ...previous, [role.key]: true }))
322
+ setTimeout(() => setRoleSaved((previous) => ({ ...previous, [role.key]: false })), SAVE_FEEDBACK_MS)
323
+ } finally {
324
+ setSavingRole((previous) => ({ ...previous, [role.key]: false }))
325
+ }
326
+ }
327
+ }
328
+
329
+ function handleSelectRoleTemplate(
330
+ role: MessagesWorkspaceTemplateRole,
331
+ name: string,
332
+ template: WhatsAppTemplateSummary | undefined,
333
+ ): void {
334
+ setRoleSettings((previous) => {
335
+ const current = previous[role.key] ?? EMPTY_TEMPLATE_SETTINGS
336
+ if (!template) return { ...previous, [role.key]: { ...current, templateName: name } }
337
+ const shouldSeedVariables = template.variableCount > 0 && current.variables.length === 0
338
+ return {
339
+ ...previous,
340
+ [role.key]: {
341
+ templateName: name,
342
+ templateLanguage: template.language,
343
+ variables: shouldSeedVariables ? Array.from({ length: template.variableCount }, () => '') : current.variables,
344
+ },
345
+ }
346
+ })
347
+ }
348
+
282
349
  async function handleCreateTemplate(event: FormEvent): Promise<void> {
283
350
  event.preventDefault()
284
351
  if (!api.createTemplate) return
@@ -443,9 +510,45 @@ export function MessagesWorkspace({
443
510
  submitting: creatingTemplate,
444
511
  result: createResult,
445
512
  labels: labels.createTemplate,
513
+ ...(createTemplatePreviewCompanyName ? { previewCompanyName: createTemplatePreviewCompanyName } : {}),
514
+ ...(createTemplateVariableExamples ? { variableExamples: createTemplateVariableExamples } : {}),
446
515
  },
447
516
  }
448
517
  : {})}
518
+ {...(templateRoles.length > 0
519
+ ? {
520
+ extraRoleForms: (
521
+ <>
522
+ {templateRoles.map((role) => {
523
+ const settings = roleSettings[role.key] ?? EMPTY_TEMPLATE_SETTINGS
524
+ return (
525
+ <WhatsAppTemplateSettingsForm
526
+ key={role.key}
527
+ templates={templates}
528
+ loadingTemplates={loadingTemplates}
529
+ templatesError={templatesError}
530
+ selectedTemplateName={settings.templateName}
531
+ onSelectTemplate={(name, template) => handleSelectRoleTemplate(role, name, template)}
532
+ variables={settings.variables}
533
+ onVariablesChange={(variables) =>
534
+ setRoleSettings((previous) => ({
535
+ ...previous,
536
+ [role.key]: { ...(previous[role.key] ?? EMPTY_TEMPLATE_SETTINGS), variables },
537
+ }))
538
+ }
539
+ onSave={handleSaveRole(role)}
540
+ saving={Boolean(savingRole[role.key])}
541
+ saveSuccess={Boolean(roleSaved[role.key])}
542
+ labels={{ ...labels.templateSettings, ...role.labels }}
543
+ {...(api.listTemplates ? { onRefreshTemplates: () => void reloadTemplates() } : {})}
544
+ {...(availableVariables ? { availableVariables } : {})}
545
+ />
546
+ )
547
+ })}
548
+ </>
549
+ ),
550
+ }
551
+ : {})}
449
552
  />
450
553
  </div>
451
554
  ) : null}
@@ -0,0 +1,61 @@
1
+ import { describe, expect, it } from 'bun:test'
2
+ import { renderToStaticMarkup } from 'react-dom/server'
3
+
4
+ import { WhatsAppTemplatesSettings } from './WhatsAppTemplatesSettings'
5
+ import type { WhatsAppTemplatesSettingsProps } from './WhatsAppTemplatesSettings'
6
+
7
+ function render(overrides: Partial<WhatsAppTemplatesSettingsProps> = {}): string {
8
+ return renderToStaticMarkup(
9
+ <WhatsAppTemplatesSettings
10
+ templates={[]}
11
+ selectedTemplateName=""
12
+ onSelectTemplate={() => {}}
13
+ variables={[]}
14
+ onVariablesChange={() => {}}
15
+ onSave={() => {}}
16
+ {...overrides}
17
+ />,
18
+ )
19
+ }
20
+
21
+ describe('WhatsAppTemplatesSettings', () => {
22
+ it('renderiza os formulários extras de papel na aba de seleção', () => {
23
+ const markup = render({ extraRoleForms: <div>MARCADOR_PAPEL_EXTRA</div> })
24
+
25
+ expect(markup).toContain('MARCADOR_PAPEL_EXTRA')
26
+ })
27
+
28
+ it('sem extraRoleForms, o comportamento é idêntico ao de antes', () => {
29
+ const markup = render()
30
+
31
+ expect(markup).not.toContain('MARCADOR_PAPEL_EXTRA')
32
+ })
33
+
34
+ it('aceita previewCompanyName e variableExamples em create sem quebrar a tipagem', () => {
35
+ const markup = render({
36
+ create: {
37
+ value: {
38
+ name: '',
39
+ category: 'UTILITY',
40
+ language: 'pt_BR',
41
+ headerType: 'NONE',
42
+ headerText: '',
43
+ bodyText: '',
44
+ footerText: '',
45
+ },
46
+ onChange: () => {},
47
+ onSubmit: () => {},
48
+ previewCompanyName: 'Empresa Teste',
49
+ variableExamples: ['João', '123'],
50
+ },
51
+ })
52
+
53
+ expect(markup).toContain('Criar template')
54
+ })
55
+
56
+ it('sem create, a aba de criação não aparece', () => {
57
+ const markup = render()
58
+
59
+ expect(markup).not.toContain('Criar template')
60
+ })
61
+ })
@@ -8,7 +8,7 @@
8
8
  * Segue presentacional: nenhuma chamada de rede aqui. Templates, estado e handlers vêm por props.
9
9
  */
10
10
 
11
- import { useState, type FormEvent } from 'react'
11
+ import { useState, type FormEvent, type ReactNode } from 'react'
12
12
  import {
13
13
  WhatsAppTemplateSettingsForm,
14
14
  type WhatsAppTemplateSummary,
@@ -59,16 +59,25 @@ export interface WhatsAppTemplatesSettingsProps {
59
59
  submitting?: boolean
60
60
  result?: WhatsAppCreateTemplateResult | null
61
61
  labels?: Partial<WhatsAppCreateTemplateFormLabels>
62
+ /** Nome exibido na prévia do template criado; sem isto o form usa seu próprio fallback. */
63
+ previewCompanyName?: string
64
+ variableExamples?: readonly string[]
62
65
  }
63
66
  labels?: Partial<WhatsAppTemplatesSettingsLabels>
64
67
  /** Vocabulário do formulário de seleção — separado de `labels`, que nomeia só as abas daqui. */
65
68
  settingsLabels?: Partial<WhatsAppTemplateSettingsFormLabels>
69
+ /**
70
+ * Formulários extras de seleção (um por papel adicional de template, ex.: despedida), empilhados
71
+ * abaixo do principal na mesma sub-aba. Ausente = só o papel principal, comportamento de sempre.
72
+ */
73
+ extraRoleForms?: ReactNode
66
74
  }
67
75
 
68
76
  export function WhatsAppTemplatesSettings({
69
77
  labels: labelsOverride,
70
78
  settingsLabels,
71
79
  create,
80
+ extraRoleForms,
72
81
  ...settingsProps
73
82
  }: WhatsAppTemplatesSettingsProps) {
74
83
  const labels = { ...DEFAULT_TEMPLATES_SETTINGS_LABELS, ...labelsOverride }
@@ -105,7 +114,10 @@ export function WhatsAppTemplatesSettings({
105
114
  </nav>
106
115
 
107
116
  {tab === TEMPLATE_SETTINGS_TAB.SELECT ? (
108
- <WhatsAppTemplateSettingsForm {...settingsProps} {...(settingsLabels ? { labels: settingsLabels } : {})} />
117
+ <div className="space-y-6">
118
+ <WhatsAppTemplateSettingsForm {...settingsProps} {...(settingsLabels ? { labels: settingsLabels } : {})} />
119
+ {extraRoleForms}
120
+ </div>
109
121
  ) : create ? (
110
122
  <WhatsAppCreateTemplateForm {...create} />
111
123
  ) : null}