@adatechnology/notification-ui 0.1.0 → 0.2.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.
package/README.md CHANGED
@@ -49,6 +49,14 @@ Tudo por TanStack Query — nunca `useEffect` + `useState` para carregar da API.
49
49
  invalida as queries em vez de escrever no cache na mão: a origem da verdade continua sendo a API,
50
50
  e a tela não diverge se um evento se perder na reconexão.
51
51
 
52
+ ## Modelo padrão de e-mail na tela de modelos
53
+
54
+ O `NotificationSettingsWorkspace` trata `notification.standard-email` à parte: selo "Modelo do
55
+ sistema", **sem "Remover"**, botão "Restaurar padrão" (`useRestoreTemplateDefault`), **sem campo de
56
+ assunto** (é o da conversa) e prévia com as variáveis de exemplo. Variáveis obrigatórias faltando e
57
+ HTML inseguro aparecem listados antes de salvar (`standardEmail.util.ts`, reusa `assess` do contracts).
58
+ Textos em `settings.system*`/`settings.standard*` (pt-BR e en).
59
+
52
60
  ## Licença
53
61
 
54
62
  MIT © Ada Technology
@@ -50,6 +50,16 @@ var pt_BR_default = {
50
50
  "settings.close": "Fechar",
51
51
  "settings.version": "v",
52
52
  "settings.newTemplate": "Nova mensagem",
53
+ "settings.systemTemplate": "Modelo do sistema",
54
+ "settings.restoreDefault": "Restaurar padr\xE3o",
55
+ "settings.restoring": "Restaurando\u2026",
56
+ "settings.standardEmailHint": "Moldura de todo e-mail enviado pelo sistema. O assunto \xE9 o da conversa; use as vari\xE1veis obrigat\xF3rias.",
57
+ "settings.standardMissing": "Vari\xE1veis obrigat\xF3rias que faltam:",
58
+ "settings.standardUnsafe": "HTML n\xE3o permitido neste modelo:",
59
+ "settings.standardUnsafe.event": "atributo de evento (onclick e similares)",
60
+ "settings.standardUnsafe.placeholder_in_tag": "vari\xE1vel dentro de uma tag ou atributo",
61
+ "settings.standardUnsafe.scheme": "endere\xE7o com esquema n\xE3o permitido",
62
+ "settings.standardUnsafe.tag": "tag n\xE3o permitida (script, iframe e similares)",
53
63
  "settings.remove": "Remover",
54
64
  "settings.key": "Chave da notifica\xE7\xE3o",
55
65
  "settings.keyHint": "N\xE3o muda depois de criada \u2014 \xE9 por ela que o envio acha a mensagem.",
@@ -153,6 +163,16 @@ var en_default = {
153
163
  "settings.close": "Close",
154
164
  "settings.version": "v",
155
165
  "settings.newTemplate": "New message",
166
+ "settings.systemTemplate": "System template",
167
+ "settings.restoreDefault": "Restore default",
168
+ "settings.restoring": "Restoring\u2026",
169
+ "settings.standardEmailHint": "The frame of every email the system sends. The subject comes from the conversation; keep the required variables.",
170
+ "settings.standardMissing": "Missing required variables:",
171
+ "settings.standardUnsafe": "HTML not allowed in this template:",
172
+ "settings.standardUnsafe.event": "event attribute (onclick and similar)",
173
+ "settings.standardUnsafe.placeholder_in_tag": "variable inside a tag or attribute",
174
+ "settings.standardUnsafe.scheme": "address with a disallowed scheme",
175
+ "settings.standardUnsafe.tag": "disallowed tag (script, iframe and similar)",
156
176
  "settings.remove": "Remove",
157
177
  "settings.key": "Notification key",
158
178
  "settings.keyHint": "Fixed once created \u2014 sending looks the message up by it.",
@@ -482,6 +502,16 @@ function useDeactivateTemplate() {
482
502
  }
483
503
  });
484
504
  }
505
+ function useRestoreTemplateDefault() {
506
+ const { client } = useNotificationContext();
507
+ const queryClient = useQueryClient4();
508
+ return useMutation3({
509
+ mutationFn: (id) => client.restoreDefault(id),
510
+ onSuccess() {
511
+ void queryClient.invalidateQueries({ queryKey: NOTIFICATION_QUERY_KEYS.templates() });
512
+ }
513
+ });
514
+ }
485
515
 
486
516
  // src/format/notificationTime.ts
487
517
  var SECOND = 1e3;
@@ -544,6 +574,38 @@ import {
544
574
  diffTemplateVariables,
545
575
  renderTemplate
546
576
  } from "@adatechnology/notification-contracts";
577
+
578
+ // src/standardEmail.util.ts
579
+ import {
580
+ STANDARD_EMAIL_TEMPLATE_KEY,
581
+ STANDARD_EMAIL_VARIABLES,
582
+ assessStandardEmailTemplate,
583
+ renderStandardEmail
584
+ } from "@adatechnology/notification-contracts";
585
+ function isStandardEmailKey(key) {
586
+ return key === STANDARD_EMAIL_TEMPLATE_KEY;
587
+ }
588
+ function assessStandardEmailDraft(html) {
589
+ return assessStandardEmailTemplate(html);
590
+ }
591
+ function example(name) {
592
+ return STANDARD_EMAIL_VARIABLES.find((variable) => variable.name === name)?.example ?? "";
593
+ }
594
+ function buildStandardEmailPreviewHtml(templateHtml) {
595
+ return renderStandardEmail({
596
+ template: { html: templateHtml, source: "company", version: 0 },
597
+ input: {
598
+ attachments: [{ name: example("listaAnexos") }],
599
+ bodyText: example("corpoMensagem"),
600
+ footer: { platformNote: example("rodapePlataforma") },
601
+ identity: { displayName: example("nomeEmpresa"), logo: { kind: "initials" } },
602
+ replyHint: example("faixaResposta"),
603
+ signer: { name: example("nomeAssinante"), role: example("cargoAssinante") }
604
+ }
605
+ }).html;
606
+ }
607
+
608
+ // src/hooks/useTemplateEditor.ts
547
609
  var EMPTY_CHANNEL = { subject: "", body: "", whatsappTemplateName: "" };
548
610
  function toDraft(template) {
549
611
  return {
@@ -575,6 +637,7 @@ function useTemplateEditor(params = {}) {
575
637
  const variablesQuery = useTemplateVariables();
576
638
  const upsert = useUpsertTemplate();
577
639
  const deactivateMutation = useDeactivateTemplate();
640
+ const restoreMutation = useRestoreTemplateDefault();
578
641
  const [search, setSearch] = useState2("");
579
642
  const [channelFilter, setChannelFilter] = useState2([]);
580
643
  const [categoryFilter, setCategoryFilter] = useState2([]);
@@ -655,6 +718,16 @@ function useTemplateEditor(params = {}) {
655
718
  return viewports.map((viewport) => ({ ...viewport, channel, rendered }));
656
719
  });
657
720
  }, [draft, variables, params.previewPayload]);
721
+ const isStandardEmail = draft !== void 0 && isStandardEmailKey(draft.key);
722
+ const standardHtml = isStandardEmail ? draft?.byChannel[draft.channels[0] ?? ""]?.body ?? "" : void 0;
723
+ const standardAssessment = useMemo3(
724
+ () => standardHtml === void 0 ? void 0 : assessStandardEmailDraft(standardHtml),
725
+ [standardHtml]
726
+ );
727
+ const standardPreviewHtml = useMemo3(
728
+ () => standardHtml === void 0 || !standardAssessment?.usable ? void 0 : buildStandardEmailPreviewHtml(standardHtml),
729
+ [standardHtml, standardAssessment]
730
+ );
658
731
  const isDirty = useMemo3(() => {
659
732
  if (!draft) return false;
660
733
  const temTexto = draft.channels.some((channel) => (draft.byChannel[channel]?.body ?? "").length > 0);
@@ -679,7 +752,11 @@ function useTemplateEditor(params = {}) {
679
752
  isLoading: templatesQuery.isLoading,
680
753
  isSaving: upsert.isPending,
681
754
  isDeactivating: deactivateMutation.isPending,
682
- error: upsert.error?.message ?? deactivateMutation.error?.message,
755
+ isRestoring: restoreMutation.isPending,
756
+ isStandardEmail,
757
+ standardAssessment,
758
+ standardPreviewHtml,
759
+ error: upsert.error?.message ?? deactivateMutation.error?.message ?? restoreMutation.error?.message,
683
760
  selected,
684
761
  draft,
685
762
  isNew,
@@ -691,7 +768,8 @@ function useTemplateEditor(params = {}) {
691
768
  // A variável desconhecida é recusada pelo servidor com 400; bloquear o botão evita a ida
692
769
  // perdida, sem virar a única defesa — a validação continua sendo a da rota.
693
770
  /** Todo canal marcado precisa do proprio texto — senao a gravacao criaria template vazio. */
694
- canSave: Boolean(draft?.key) && (draft?.channels.length ?? 0) > 0 && (draft?.channels.every((channel) => (draft.byChannel[channel]?.body ?? "").length > 0) ?? false) && variableDiff.unknown.length === 0,
771
+ canSave: Boolean(draft?.key) && (draft?.channels.length ?? 0) > 0 && (draft?.channels.every((channel) => (draft.byChannel[channel]?.body ?? "").length > 0) ?? false) && variableDiff.unknown.length === 0 && // O modelo padrão inutilizável nunca é gravado: o servidor recusa (400) e o envio o ignoraria.
772
+ (standardAssessment?.usable ?? true),
695
773
  setSearch,
696
774
  toggleChannelFilter(channel) {
697
775
  setChannelFilter(
@@ -775,7 +853,8 @@ function useTemplateEditor(params = {}) {
775
853
  locale: draft.locale,
776
854
  active: true,
777
855
  body: content.body,
778
- ...content.subject ? { subject: content.subject } : {},
856
+ // Modelo padrão não tem assunto: ele é dado do envio, e um assunto aqui se acumularia.
857
+ ...content.subject && !isStandardEmail ? { subject: content.subject } : {},
779
858
  ...content.whatsappTemplateName ? { whatsappTemplateName: content.whatsappTemplateName } : {}
780
859
  };
781
860
  });
@@ -797,6 +876,15 @@ function useTemplateEditor(params = {}) {
797
876
  }
798
877
  });
799
878
  },
879
+ restoreDefault(id) {
880
+ restoreMutation.mutate(id, {
881
+ onSuccess: () => {
882
+ if (selectedId !== id) return;
883
+ setSelectedId(void 0);
884
+ setDraft(void 0);
885
+ }
886
+ });
887
+ },
800
888
  clear() {
801
889
  setSelectedId(void 0);
802
890
  setDraft(void 0);
@@ -825,12 +913,14 @@ export {
825
913
  useUpsertTemplate,
826
914
  useTemplateVariables,
827
915
  useDeactivateTemplate,
916
+ useRestoreTemplateDefault,
828
917
  formatNotificationTime,
829
918
  formatNotificationTimestamp,
830
919
  TEMPLATE_VIEWS,
831
920
  TEMPLATE_SORT_FIELDS,
832
921
  SORT_DIRECTIONS,
833
922
  TEMPLATE_COLUMNS,
923
+ isStandardEmailKey,
834
924
  useTemplateEditor
835
925
  };
836
- //# sourceMappingURL=chunk-7XDQ76IV.js.map
926
+ //# sourceMappingURL=chunk-SFMOFCHV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/NotificationProvider.tsx","../src/locales/pt-BR.json","../src/locales/en.json","../src/locales/index.ts","../src/hooks/useNotifications.ts","../src/hooks/queryKeys.ts","../src/hooks/useNotificationStream.ts","../src/hooks/useCategoryPolicies.ts","../src/hooks/usePreferences.ts","../src/format/notificationTime.ts","../src/hooks/useTemplateEditor.ts","../src/templateList.constant.ts","../src/standardEmail.util.ts"],"sourcesContent":["/**\n * Copyright (c) 2026 Ada Technology. MIT License.\n *\n * Provider do pacote. **Não instancia `QueryClient`** — usa o do host (regra de módulos\n * plugáveis §4.2). Instanciar o próprio criaria dois caches na mesma página: a inbox invalidaria\n * um, e a tela do produto continuaria lendo o outro.\n */\n\nimport { createContext, useContext, useMemo, type ReactNode } from 'react'\nimport type { NotificationClient } from '@adatechnology/notification-client'\n\nimport { DEFAULT_LOCALE, resolveMessages, type NotificationLocale, type NotificationMessages } from './locales'\n\nexport type NotificationTheme = {\n /** Classe aplicada na raiz de cada componente — é por onde o host injeta os tokens dele. */\n readonly rootClassName?: string\n readonly components?: Partial<Record<string, string>>\n}\n\nexport type NotificationContextValue = {\n readonly client: NotificationClient\n /**\n * O idioma resolvido, e não só os textos dele: data e número não vivem no arquivo de locale —\n * quem os formata é `Intl`, e `Intl` precisa da tag do idioma. Sem isto o item da lista teria de\n * chutar um locale fixo, e a inbox mostraria \"5 minutes ago\" numa tela em português.\n */\n readonly locale: NotificationLocale\n readonly messages: NotificationMessages\n readonly theme: NotificationTheme\n /** Polling de fallback quando o SSE não está disponível (segundos); `0` desliga. */\n readonly pollIntervalSeconds: number\n}\n\nconst NotificationContext = createContext<NotificationContextValue | null>(null)\n\nexport type NotificationProviderProps = {\n readonly client: NotificationClient\n readonly locale?: NotificationLocale\n /** Sobrescreve textos pontuais sem trocar o locale inteiro. */\n readonly messageOverrides?: Partial<NotificationMessages>\n readonly theme?: NotificationTheme\n readonly pollIntervalSeconds?: number\n readonly children: ReactNode\n}\n\nexport function NotificationProvider({\n client,\n locale = DEFAULT_LOCALE,\n messageOverrides,\n theme = {},\n pollIntervalSeconds = 60,\n children,\n}: NotificationProviderProps) {\n const value = useMemo<NotificationContextValue>(\n () => ({\n client,\n locale,\n messages: { ...resolveMessages(locale), ...messageOverrides },\n theme,\n pollIntervalSeconds,\n }),\n [client, locale, messageOverrides, theme, pollIntervalSeconds],\n )\n\n return <NotificationContext.Provider value={value}>{children}</NotificationContext.Provider>\n}\n\nexport function useNotificationContext(): NotificationContextValue {\n const context = useContext(NotificationContext)\n if (!context) throw new Error('notification-ui: componente usado fora de <NotificationProvider>')\n return context\n}\n","{\n \"bell.label\": \"Notificações\",\n \"bell.unreadSuffix\": \"não lidas\",\n \"list.title\": \"Caixa de entrada\",\n \"list.unread\": \"não lidas\",\n \"list.empty\": \"Nenhuma notificação por aqui.\",\n \"list.loading\": \"Carregando…\",\n \"list.error\": \"Não foi possível carregar suas notificações.\",\n \"list.retry\": \"Tentar de novo\",\n \"list.loadMore\": \"Carregar mais\",\n \"list.markAllAsRead\": \"Marcar todas como lidas\",\n \"item.markAsRead\": \"Marcar como lida\",\n \"item.delete\": \"Excluir\",\n \"item.unread\": \"Não lida\",\n \"preferences.title\": \"Preferências de notificação\",\n \"preferences.description\": \"Escolha por onde você quer ser avisado em cada assunto.\",\n \"preferences.save\": \"Salvar preferências\",\n \"preferences.saved\": \"Preferências salvas.\",\n \"preferences.error\": \"Não foi possível salvar. Tente de novo.\",\n \"preferences.empty\": \"Nenhuma preferência configurada ainda.\",\n \"preferences.quietHours\": \"Silêncio entre\",\n \"preferences.quietHoursTo\": \"e\",\n \"channel.inbox\": \"No app\",\n \"channel.push\": \"Push\",\n \"channel.email\": \"E-mail\",\n \"channel.whatsapp\": \"WhatsApp\",\n \"channel.sms\": \"SMS\",\n \"workspace.title\": \"Notificações\",\n \"workspace.description\": \"O que foi avisado, e por quais canais.\",\n \"workspace.settingsLink\": \"Configurações\",\n \"settings.title\": \"Configurações de notificação\",\n \"settings.description\": \"Por onde avisar, e o texto exato que chega.\",\n \"settings.channelsTitle\": \"Canais\",\n \"settings.channelsHint\": \"Desligar um canal não apaga o histórico — o aviso deixa de sair por ali daqui em diante.\",\n \"settings.templatesTitle\": \"Mensagens\",\n \"settings.templatesHint\": \"Uma versão nova é criada a cada gravação; a anterior fica no histórico.\",\n \"settings.templatesEmpty\": \"Nenhuma mensagem cadastrada.\",\n \"settings.pickTemplate\": \"Escolha uma mensagem para editar.\",\n \"settings.subject\": \"Título\",\n \"settings.subjectHint\": \"O que aparece na lista. Vazio, o título é derivado da primeira linha do texto.\",\n \"settings.body\": \"Texto\",\n \"settings.previewTitle\": \"Como o destinatário vê\",\n \"settings.save\": \"Salvar nova versão\",\n \"settings.saving\": \"Salvando…\",\n \"settings.unchanged\": \"Nada mudou ainda.\",\n \"settings.close\": \"Fechar\",\n \"settings.version\": \"v\",\n \"settings.newTemplate\": \"Nova mensagem\",\n \"settings.systemTemplate\": \"Modelo do sistema\",\n \"settings.restoreDefault\": \"Restaurar padrão\",\n \"settings.restoring\": \"Restaurando…\",\n \"settings.standardEmailHint\": \"Moldura de todo e-mail enviado pelo sistema. O assunto é o da conversa; use as variáveis obrigatórias.\",\n \"settings.standardMissing\": \"Variáveis obrigatórias que faltam:\",\n \"settings.standardUnsafe\": \"HTML não permitido neste modelo:\",\n \"settings.standardUnsafe.event\": \"atributo de evento (onclick e similares)\",\n \"settings.standardUnsafe.placeholder_in_tag\": \"variável dentro de uma tag ou atributo\",\n \"settings.standardUnsafe.scheme\": \"endereço com esquema não permitido\",\n \"settings.standardUnsafe.tag\": \"tag não permitida (script, iframe e similares)\",\n \"settings.remove\": \"Remover\",\n \"settings.key\": \"Chave da notificação\",\n \"settings.keyHint\": \"Não muda depois de criada — é por ela que o envio acha a mensagem.\",\n \"settings.channel\": \"Canal\",\n \"settings.locale\": \"Idioma\",\n \"settings.variablesTitle\": \"Variáveis\",\n \"settings.variablesHint\": \"Clique para inserir no ponto onde o cursor estava.\",\n \"settings.unknownVariables\": \"Variáveis que não existem nesta notificação:\",\n \"settings.constraint.title\": \"Assunto passa do limite do canal:\",\n \"settings.constraint.body\": \"Texto passa do limite do canal:\",\n \"settings.tab.messages\": \"Mensagens\",\n \"settings.tab.routing\": \"Roteamento\",\n \"settings.policiesTitle\": \"Canais permitidos por assunto\",\n \"settings.policiesHint\": \"Decisão da empresa. Canal desligado aqui não sai, mesmo que o destinatário tenha pedido.\",\n \"settings.savePolicies\": \"Salvar roteamento\",\n \"settings.discard\": \"Descartar\",\n \"preview.to\": \"para você\",\n \"preview.now\": \"agora\",\n \"preview.mailbox\": \"Buscar no e-mail\",\n \"settings.viewport.browser\": \"Navegador\",\n \"settings.viewport.ios\": \"iPhone\",\n \"settings.viewport.android\": \"Android\",\n \"settings.channelHint\": \"Pode marcar mais de um — o mesmo texto é gravado para cada canal.\",\n \"preview.time\": \"9:41\",\n \"preview.address\": \"caixa de entrada\",\n \"preview.counter\": \"1 de 1.248\",\n \"preview.folder\": \"Caixa de entrada\",\n \"preview.senderAddress\": \"<nao-responda@exemplo.com>\",\n \"preview.unsubscribe\": \"Cancelar inscrição\",\n \"preview.online\": \"online\",\n \"preview.today\": \"hoje\",\n \"preview.compose\": \"Mensagem\",\n \"preview.reply\": \"Responder\",\n \"preview.forward\": \"Encaminhar\",\n \"preview.replyAll\": \"Responder a todos\",\n \"settings.searchLabel\": \"Buscar mensagem\",\n \"settings.searchPlaceholder\": \"Buscar por chave ou texto…\",\n \"settings.clearFilters\": \"Limpar filtros\",\n \"settings.noResults\": \"Nenhuma mensagem para esse filtro.\",\n \"settings.viewLabel\": \"Modo de exibição\",\n \"settings.view.table\": \"Tabela\",\n \"settings.view.list\": \"Lista\",\n \"settings.column.key\": \"Mensagem\",\n \"settings.column.body\": \"Texto\",\n \"settings.column.channel\": \"Canal\",\n \"settings.column.version\": \"Versão\",\n \"settings.column.actions\": \"Ações\",\n \"toolbar.bold\": \"Negrito\",\n \"toolbar.italic\": \"Italico\",\n \"toolbar.strikethrough\": \"Tachado\",\n \"toolbar.monospace\": \"Monoespacado\",\n \"toolbar.emoji\": \"Emoji\"\n}\n","{\n \"bell.label\": \"Notifications\",\n \"bell.unreadSuffix\": \"unread\",\n \"list.title\": \"Inbox\",\n \"list.unread\": \"unread\",\n \"list.empty\": \"Nothing here yet.\",\n \"list.loading\": \"Loading…\",\n \"list.error\": \"We couldn't load your notifications.\",\n \"list.retry\": \"Try again\",\n \"list.loadMore\": \"Load more\",\n \"list.markAllAsRead\": \"Mark all as read\",\n \"item.markAsRead\": \"Mark as read\",\n \"item.delete\": \"Delete\",\n \"item.unread\": \"Unread\",\n \"preferences.title\": \"Notification preferences\",\n \"preferences.description\": \"Choose how you want to be notified about each topic.\",\n \"preferences.save\": \"Save preferences\",\n \"preferences.saved\": \"Preferences saved.\",\n \"preferences.error\": \"Couldn't save. Try again.\",\n \"preferences.empty\": \"No preferences configured yet.\",\n \"preferences.quietHours\": \"Quiet between\",\n \"preferences.quietHoursTo\": \"and\",\n \"channel.inbox\": \"In app\",\n \"channel.push\": \"Push\",\n \"channel.email\": \"Email\",\n \"channel.whatsapp\": \"WhatsApp\",\n \"channel.sms\": \"SMS\",\n \"workspace.title\": \"Notifications\",\n \"workspace.description\": \"What was sent, and through which channels.\",\n \"workspace.settingsLink\": \"Settings\",\n \"settings.title\": \"Notification settings\",\n \"settings.description\": \"Where to notify, and the exact text that arrives.\",\n \"settings.channelsTitle\": \"Channels\",\n \"settings.channelsHint\": \"Turning a channel off does not erase history — notices stop going out through it from now on.\",\n \"settings.templatesTitle\": \"Messages\",\n \"settings.templatesHint\": \"Each save creates a new version; the previous one stays in history.\",\n \"settings.templatesEmpty\": \"No messages registered.\",\n \"settings.pickTemplate\": \"Pick a message to edit.\",\n \"settings.subject\": \"Title\",\n \"settings.subjectHint\": \"Shown in the list. Empty, the title is derived from the first line of the body.\",\n \"settings.body\": \"Body\",\n \"settings.previewTitle\": \"How the recipient sees it\",\n \"settings.save\": \"Save new version\",\n \"settings.saving\": \"Saving…\",\n \"settings.unchanged\": \"Nothing changed yet.\",\n \"settings.close\": \"Close\",\n \"settings.version\": \"v\",\n \"settings.newTemplate\": \"New message\",\n \"settings.systemTemplate\": \"System template\",\n \"settings.restoreDefault\": \"Restore default\",\n \"settings.restoring\": \"Restoring…\",\n \"settings.standardEmailHint\": \"The frame of every email the system sends. The subject comes from the conversation; keep the required variables.\",\n \"settings.standardMissing\": \"Missing required variables:\",\n \"settings.standardUnsafe\": \"HTML not allowed in this template:\",\n \"settings.standardUnsafe.event\": \"event attribute (onclick and similar)\",\n \"settings.standardUnsafe.placeholder_in_tag\": \"variable inside a tag or attribute\",\n \"settings.standardUnsafe.scheme\": \"address with a disallowed scheme\",\n \"settings.standardUnsafe.tag\": \"disallowed tag (script, iframe and similar)\",\n \"settings.remove\": \"Remove\",\n \"settings.key\": \"Notification key\",\n \"settings.keyHint\": \"Fixed once created — sending looks the message up by it.\",\n \"settings.channel\": \"Channel\",\n \"settings.locale\": \"Language\",\n \"settings.variablesTitle\": \"Variables\",\n \"settings.variablesHint\": \"Click to insert where the cursor was.\",\n \"settings.unknownVariables\": \"Variables this notification does not have:\",\n \"settings.constraint.title\": \"Subject exceeds the channel limit:\",\n \"settings.constraint.body\": \"Body exceeds the channel limit:\",\n \"settings.tab.messages\": \"Messages\",\n \"settings.tab.routing\": \"Routing\",\n \"settings.policiesTitle\": \"Allowed channels per topic\",\n \"settings.policiesHint\": \"Company decision. A channel turned off here never sends, even if the recipient opted in.\",\n \"settings.savePolicies\": \"Save routing\",\n \"settings.discard\": \"Discard\",\n \"preview.to\": \"to you\",\n \"preview.now\": \"now\",\n \"preview.mailbox\": \"Search mail\",\n \"settings.viewport.browser\": \"Browser\",\n \"settings.viewport.ios\": \"iPhone\",\n \"settings.viewport.android\": \"Android\",\n \"settings.channelHint\": \"Pick more than one — the same text is saved for each channel.\",\n \"preview.time\": \"9:41\",\n \"preview.address\": \"inbox\",\n \"preview.counter\": \"1 of 1,248\",\n \"preview.folder\": \"Inbox\",\n \"preview.senderAddress\": \"<no-reply@example.com>\",\n \"preview.unsubscribe\": \"Unsubscribe\",\n \"preview.online\": \"online\",\n \"preview.today\": \"today\",\n \"preview.compose\": \"Message\",\n \"preview.reply\": \"Reply\",\n \"preview.forward\": \"Forward\",\n \"preview.replyAll\": \"Reply all\",\n \"settings.searchLabel\": \"Search message\",\n \"settings.searchPlaceholder\": \"Search by key or text…\",\n \"settings.clearFilters\": \"Clear filters\",\n \"settings.noResults\": \"No message matches this filter.\",\n \"settings.viewLabel\": \"View mode\",\n \"settings.view.table\": \"Table\",\n \"settings.view.list\": \"List\",\n \"settings.column.key\": \"Message\",\n \"settings.column.body\": \"Text\",\n \"settings.column.channel\": \"Channel\",\n \"settings.column.version\": \"Version\",\n \"settings.column.actions\": \"Actions\",\n \"toolbar.bold\": \"Bold\",\n \"toolbar.italic\": \"Italic\",\n \"toolbar.strikethrough\": \"Strikethrough\",\n \"toolbar.monospace\": \"Monospace\",\n \"toolbar.emoji\": \"Emoji\"\n}\n","/**\n * Copyright (c) 2026 Ada Technology. MIT License.\n *\n * Nenhum texto visível vive em tag ou prop (`web.md` §6). O host sobrescreve chaves pontuais via\n * `messageOverrides` sem precisar fornecer um locale inteiro.\n */\n\nimport ptBR from './pt-BR.json'\nimport en from './en.json'\n\nexport type NotificationMessages = typeof ptBR\nexport type NotificationLocale = 'pt-BR' | 'en'\n\nexport const DEFAULT_LOCALE: NotificationLocale = 'pt-BR'\n\nconst MESSAGES_BY_LOCALE: Record<NotificationLocale, NotificationMessages> = {\n 'pt-BR': ptBR,\n en: en as NotificationMessages,\n}\n\nexport function resolveMessages(locale: NotificationLocale): NotificationMessages {\n return MESSAGES_BY_LOCALE[locale] ?? MESSAGES_BY_LOCALE[DEFAULT_LOCALE]\n}\n","/**\n * Copyright (c) 2026 Ada Technology. MIT License.\n *\n * Camada headless — a válvula de escape do item 4 da §4 da regra de módulos plugáveis: quando a\n * tela default não serve, o produto monta a própria sobre estes mesmos hooks e continua herdando\n * upgrades de lógica.\n */\n\nimport { useInfiniteQuery, useMutation, useQuery, useQueryClient } from '@tanstack/react-query'\nimport type { NotificationSummary } from '@adatechnology/notification-contracts'\n\nimport { useNotificationContext } from '../NotificationProvider'\nimport { NOTIFICATION_QUERY_KEYS } from './queryKeys'\n\nexport type UseNotificationsOptions = {\n readonly category?: string\n readonly read?: boolean\n readonly perPage?: number\n}\n\nexport function useNotifications(options: UseNotificationsOptions = {}) {\n const { client } = useNotificationContext()\n\n return useInfiniteQuery({\n queryKey: NOTIFICATION_QUERY_KEYS.list({ category: options.category, read: options.read }),\n initialPageParam: undefined as string | undefined,\n queryFn: ({ pageParam }) =>\n client.listNotifications({\n category: options.category,\n read: options.read,\n cursor: pageParam,\n perPage: options.perPage,\n }),\n getNextPageParam: (lastPage) => lastPage.nextCursor,\n })\n}\n\nexport function useUnreadCount() {\n const { client, pollIntervalSeconds } = useNotificationContext()\n\n return useQuery({\n queryKey: NOTIFICATION_QUERY_KEYS.unreadCount(),\n queryFn: () => client.countUnread(),\n // Polling é o fallback de quem não ligou o SSE. Com o stream ativo,\n // `useNotificationStream` invalida esta chave e o refetch acontece na hora.\n refetchInterval: pollIntervalSeconds > 0 ? pollIntervalSeconds * 1000 : false,\n })\n}\n\nexport function useMarkAsRead() {\n const { client } = useNotificationContext()\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: (id: string) => client.markAsRead(id),\n async onMutate(id: string) {\n // Atualização otimista: marcar como lida é ação de um clique, e esperar o round-trip para\n // o badge cair faz a interface parecer travada.\n await queryClient.cancelQueries({ queryKey: NOTIFICATION_QUERY_KEYS.all })\n const previousCount = queryClient.getQueryData<number>(NOTIFICATION_QUERY_KEYS.unreadCount())\n\n queryClient.setQueryData<number>(NOTIFICATION_QUERY_KEYS.unreadCount(), (current) =>\n current === undefined ? current : Math.max(0, current - 1),\n )\n return { previousCount, id }\n },\n onError(_error, _id, context) {\n // Rollback: sem isto o badge ficaria mentindo até o próximo refetch.\n if (context?.previousCount !== undefined) {\n queryClient.setQueryData(NOTIFICATION_QUERY_KEYS.unreadCount(), context.previousCount)\n }\n },\n onSettled() {\n void queryClient.invalidateQueries({ queryKey: NOTIFICATION_QUERY_KEYS.all })\n },\n })\n}\n\nexport function useMarkAllAsRead() {\n const { client } = useNotificationContext()\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: () => client.markAllAsRead(),\n onSettled() {\n void queryClient.invalidateQueries({ queryKey: NOTIFICATION_QUERY_KEYS.all })\n },\n })\n}\n\nexport function useDeleteNotification() {\n const { client } = useNotificationContext()\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: (id: string) => client.deleteNotification(id),\n onSettled() {\n void queryClient.invalidateQueries({ queryKey: NOTIFICATION_QUERY_KEYS.all })\n },\n })\n}\n\n/** Achata as páginas do infinite query — a lista quase sempre quer o array direto. */\nexport function flattenNotificationPages(\n pages: readonly { data: readonly NotificationSummary[] }[] | undefined,\n): readonly NotificationSummary[] {\n return pages?.flatMap((page) => page.data) ?? []\n}\n","/**\n * Copyright (c) 2026 Ada Technology. MIT License.\n *\n * Chaves centralizadas: o sino e a lista leem o mesmo `unreadCount`, e uma invalidação precisa\n * atingir os dois. Chave montada inline em cada hook é como badge e lista passam a mostrar\n * números diferentes.\n */\n\nexport const NOTIFICATION_QUERY_KEYS = {\n all: ['notifications'] as const,\n list: (filters: { category?: string; read?: boolean }) => ['notifications', 'list', filters] as const,\n unreadCount: () => ['notifications', 'unread-count'] as const,\n preferences: () => ['notifications', 'preferences'] as const,\n templates: () => ['notifications', 'templates'] as const,\n templateVariables: () => ['notifications', 'template-variables'] as const,\n categoryPolicies: () => ['notifications', 'category-policies'] as const,\n} as const\n","/**\n * Copyright (c) 2026 Ada Technology. MIT License.\n */\n\nimport { useEffect } from 'react'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { subscribeToNotificationStream } from '@adatechnology/notification-client'\n\nimport { useNotificationContext } from '../NotificationProvider'\nimport { NOTIFICATION_QUERY_KEYS } from './queryKeys'\n\nexport type UseNotificationStreamOptions = {\n /** Desligado por omissão: abrir SSE é decisão do host, que sabe se o backend expõe a rota. */\n readonly enabled?: boolean\n readonly onEvent?: (event: { event: string; data: unknown }) => void\n}\n\n/**\n * Liga o SSE do inbox ao cache do TanStack: cada evento invalida as chaves, e o badge e a lista\n * atualizam juntos. `useEffect` aqui é o uso correto do hook — sincronizar com um sistema externo\n * (`react.md`, \"useEffect só para sincronizar com sistemas externos\"), não transformar dado.\n */\nexport function useNotificationStream(options: UseNotificationStreamOptions = {}): void {\n const { client } = useNotificationContext()\n const queryClient = useQueryClient()\n const enabled = options.enabled ?? false\n const onEvent = options.onEvent\n\n useEffect(() => {\n if (!enabled) return\n\n let subscription: { close(): void } | undefined\n let cancelled = false\n\n void client.resolveStreamRequest().then(({ url, headers }) => {\n // A resolução do token é assíncrona; se o componente desmontou nesse meio-tempo, não abre\n // conexão nenhuma — senão sobraria um stream órfão a cada navegação rápida.\n if (cancelled) return\n\n subscription = subscribeToNotificationStream({\n url,\n headers,\n onEvent: (event) => {\n onEvent?.(event)\n void queryClient.invalidateQueries({ queryKey: NOTIFICATION_QUERY_KEYS.all })\n },\n })\n })\n\n return () => {\n cancelled = true\n subscription?.close()\n }\n }, [client, queryClient, enabled, onEvent])\n}\n","/**\n * Copyright (c) 2026 Ada Technology. MIT License.\n *\n * O roteamento: por quais canais cada categoria PODE sair, decidido pela empresa.\n *\n * É a camada que faltava. O chamador já podia enumerar canais em cada `sendNotification`, e quem\n * recebe já tinha preferência — mas \"cobrança nunca sai por SMS\" não cabia em nenhum dos dois:\n * o primeiro espalha a decisão por todo o código, o segundo deixa ela na mão do destinatário.\n *\n * O modelo aqui é de teto, não de piso: desligar barra o canal para todo mundo; ligar apenas\n * permite, e a preferência de quem recebe continua valendo por cima.\n */\n\nimport { useMemo, useState } from 'react'\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'\nimport type { NotificationCategoryPolicy } from '@adatechnology/notification-contracts'\n\nimport { useNotificationContext } from '../NotificationProvider'\nimport { NOTIFICATION_QUERY_KEYS } from './queryKeys'\n\nexport type UseCategoryPoliciesResult = {\n readonly isLoading: boolean\n readonly isSaving: boolean\n readonly error: string | undefined\n readonly isDirty: boolean\n /** Linha ausente é permitido — o mesmo default do servidor, para a tela não mentir. */\n isAllowed: (params: { category: string; channel: string }) => boolean\n toggle: (params: { category: string; channel: string }) => void\n save: () => void\n reset: () => void\n}\n\nfunction identityOf(params: { category: string; channel: string }): string {\n return `${params.category}:${params.channel}`\n}\n\nexport function useCategoryPolicies(): UseCategoryPoliciesResult {\n const { client } = useNotificationContext()\n const queryClient = useQueryClient()\n\n const policiesQuery = useQuery({\n queryKey: NOTIFICATION_QUERY_KEYS.categoryPolicies(),\n queryFn: () => client.getCategoryPolicies(),\n })\n\n const mutation = useMutation({\n mutationFn: (policies: readonly NotificationCategoryPolicy[]) => client.updateCategoryPolicies(policies),\n onSuccess() {\n void queryClient.invalidateQueries({ queryKey: NOTIFICATION_QUERY_KEYS.categoryPolicies() })\n },\n })\n\n /**\n * O rascunho guarda só o que foi TOCADO, não uma cópia do conjunto inteiro. Com a cópia, salvar\n * gravaria linha para toda combinação exibida na tela — e a ausência de linha, que é o default\n * \"permitido\", viraria centenas de registros de `enabled: true` sem significado.\n */\n const [touched, setTouched] = useState<Record<string, boolean>>({})\n\n const saved = useMemo(() => {\n const byIdentity = new Map<string, boolean>()\n for (const policy of policiesQuery.data ?? []) byIdentity.set(identityOf(policy), policy.enabled)\n return byIdentity\n }, [policiesQuery.data])\n\n function isAllowed(params: { category: string; channel: string }): boolean {\n const identity = identityOf(params)\n return touched[identity] ?? saved.get(identity) ?? true\n }\n\n return {\n isLoading: policiesQuery.isLoading,\n isSaving: mutation.isPending,\n error: mutation.error?.message,\n isDirty: Object.keys(touched).length > 0,\n isAllowed,\n\n toggle(params) {\n const identity = identityOf(params)\n setTouched((current) => ({ ...current, [identity]: !isAllowed(params) }))\n },\n\n save() {\n // Só as categorias tocadas vão no corpo: o servidor substitui categoria a categoria, e\n // mandar o conjunto inteiro apagaria e reescreveria política que ninguém editou.\n const categories = new Set(Object.keys(touched).map((identity) => identity.split(':')[0] ?? ''))\n const policies: NotificationCategoryPolicy[] = []\n for (const category of categories) {\n const channels = new Set([\n ...[...saved.keys()].filter((identity) => identity.startsWith(`${category}:`)),\n ...Object.keys(touched).filter((identity) => identity.startsWith(`${category}:`)),\n ])\n for (const identity of channels) {\n const channel = identity.slice(category.length + 1)\n policies.push({\n category,\n channel: channel as NotificationCategoryPolicy['channel'],\n enabled: isAllowed({ category, channel }),\n })\n }\n }\n mutation.mutate(policies, { onSuccess: () => setTouched({}) })\n },\n\n reset() {\n setTouched({})\n },\n }\n}\n","/**\n * Copyright (c) 2026 Ada Technology. MIT License.\n */\n\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'\nimport type { NotificationPreference, UpsertTemplateBody } from '@adatechnology/notification-contracts'\n\nimport { useNotificationContext } from '../NotificationProvider'\nimport { NOTIFICATION_QUERY_KEYS } from './queryKeys'\n\nexport function usePreferences() {\n const { client } = useNotificationContext()\n\n return useQuery({\n queryKey: NOTIFICATION_QUERY_KEYS.preferences(),\n queryFn: () => client.getPreferences(),\n })\n}\n\nexport function useUpdatePreferences() {\n const { client } = useNotificationContext()\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: (preferences: readonly NotificationPreference[]) => client.updatePreferences(preferences),\n onSuccess(saved) {\n // A resposta já é o estado persistido — usar direto evita um refetch e o piscar do painel\n // entre o valor otimista e o confirmado.\n queryClient.setQueryData(NOTIFICATION_QUERY_KEYS.preferences(), saved)\n },\n })\n}\n\nexport function useTemplates() {\n const { client } = useNotificationContext()\n\n return useQuery({\n queryKey: NOTIFICATION_QUERY_KEYS.templates(),\n queryFn: () => client.listTemplates(),\n })\n}\n\n/**\n * Salva uma VERSÃO nova do template. É o que a tela de configuração usa para o lojista mudar a copy\n * sem deploy.\n *\n * Invalida em vez de escrever no cache: o servidor decide o número da versão, então o objeto salvo\n * traz um campo que o otimista não teria como prever — e mostrar \"versão 3\" quando o banco gravou 4\n * confunde exatamente quem está tentando conferir o que salvou.\n */\nexport function useUpsertTemplate() {\n const { client } = useNotificationContext()\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: (input: UpsertTemplateBody) => client.upsertTemplate(input),\n onSuccess() {\n void queryClient.invalidateQueries({ queryKey: NOTIFICATION_QUERY_KEYS.templates() })\n },\n })\n}\n\n/**\n * O catálogo é config do host: muda com deploy, não com uso. `staleTime: Infinity` evita refetch a\n * cada foco de janela por um dado que não muda durante a sessão.\n */\nexport function useTemplateVariables() {\n const { client } = useNotificationContext()\n\n return useQuery({\n queryKey: NOTIFICATION_QUERY_KEYS.templateVariables(),\n queryFn: () => client.listTemplateVariables(),\n staleTime: Number.POSITIVE_INFINITY,\n })\n}\n\n/**\n * Desativa o template. Invalida a lista pelo mesmo motivo do upsert: o servidor derruba TODAS as\n * versões ativas da identidade, e um cache otimista que removesse só a linha clicada mostraria a\n * versão anterior de volta na tela.\n */\nexport function useDeactivateTemplate() {\n const { client } = useNotificationContext()\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: (id: string) => client.deactivateTemplate(id),\n onSuccess() {\n void queryClient.invalidateQueries({ queryKey: NOTIFICATION_QUERY_KEYS.templates() })\n },\n })\n}\n\nexport function useRestoreTemplateDefault() {\n const { client } = useNotificationContext()\n const queryClient = useQueryClient()\n\n return useMutation({\n mutationFn: (id: string) => client.restoreDefault(id),\n onSuccess() {\n void queryClient.invalidateQueries({ queryKey: NOTIFICATION_QUERY_KEYS.templates() })\n },\n })\n}\n","/**\n * Copyright (c) 2026 Ada Technology. MIT License.\n *\n * Quando o aviso chegou, dito do jeito que se diz em voz alta.\n *\n * `Intl` faz o trabalho de idioma — o pacote não guarda \"há\", \"ago\" nem nome de mês em lugar nenhum,\n * o que manteria `web.md` §6 de pé e ainda assim quebraria no primeiro locale novo. O que é decisão\n * nossa são as faixas: segundo, minuto, hora, dia, e a virada para data absoluta.\n */\n\nconst SECOND = 1_000\nconst MINUTE = 60 * SECOND\nconst HOUR = 60 * MINUTE\nconst DAY = 24 * HOUR\n\n/**\n * Passada uma semana, o relativo para de informar e passa a exigir conta: \"há 43 dias\" é um convite\n * a abrir o calendário. A data, o leitor lê.\n */\nconst RELATIVE_HORIZON = 7 * DAY\n\nfunction parseInstant(isoTimestamp: string): Date | undefined {\n const instant = new Date(isoTimestamp)\n return Number.isNaN(instant.getTime()) ? undefined : instant\n}\n\nexport function formatNotificationTime(isoTimestamp: string, locale: string, now: Date): string {\n const instant = parseInstant(isoTimestamp)\n if (!instant) return ''\n\n // Relógio do navegador adiantado é rotina; anunciar \"daqui a 2 minutos\" para algo que já chegou\n // não é. O piso em zero transforma o desvio em \"agora\", que é o que de fato aconteceu.\n const elapsed = Math.max(0, now.getTime() - instant.getTime())\n\n if (elapsed >= RELATIVE_HORIZON) {\n return new Intl.DateTimeFormat(locale, { day: '2-digit', month: '2-digit', year: 'numeric' }).format(instant)\n }\n\n // `numeric: 'auto'` é o que troca \"há 1 dia\" por \"ontem\" e \"há 0 segundos\" por \"agora\".\n const relative = new Intl.RelativeTimeFormat(locale, { numeric: 'auto' })\n\n if (elapsed < MINUTE) return relative.format(0, 'second')\n if (elapsed < HOUR) return relative.format(-Math.floor(elapsed / MINUTE), 'minute')\n if (elapsed < DAY) return relative.format(-Math.floor(elapsed / HOUR), 'hour')\n return relative.format(-Math.floor(elapsed / DAY), 'day')\n}\n\n/** O instante inteiro, para o `title` — é a hora que o texto relativo esconde. */\nexport function formatNotificationTimestamp(isoTimestamp: string, locale: string): string {\n const instant = parseInstant(isoTimestamp)\n if (!instant) return ''\n\n return new Intl.DateTimeFormat(locale, { dateStyle: 'short', timeStyle: 'short' }).format(instant)\n}\n","/**\n * Copyright (c) 2026 Ada Technology. MIT License.\n *\n * A lógica do editor de template, que estava reimplementada no host.\n *\n * Ela veio de `quickcart/modules/notifications/hooks/useNotificationSettings.hook.ts` — 207 linhas\n * que o segundo produto reescreveria, com as mesmas quatro decisões sutis para redescobrir. Elas\n * são o motivo de isto ser pacote e não exemplo:\n *\n * 1. **Versão ativa mais alta.** A rota devolve o histórico inteiro, correto para auditoria; na tela\n * isso faz a mesma mensagem aparecer três vezes e ninguém sabe qual está no ar.\n * 2. **Seleção pelo id, não pelo objeto.** Salvar cria versão nova no servidor; segurando o objeto,\n * o editor mostra a versão que já não é a ativa e a gravação seguinte parte de um texto velho.\n * 3. **Campo vazio é ausência.** Gravar `subject: ''` faz o renderer tratar como subject existente e\n * derivar título vazio, em vez de cair no fallback que usa o corpo.\n * 4. **Preview pelo `renderTemplate` do contracts**, o mesmo do envio. Reimplementar a interpolação\n * dá um preview que confere hoje e mente quando o renderer mudar.\n *\n * A criação de template novo trouxe uma quinta: **a identidade é imutável depois de criada**.\n * `key`+`channel`+`locale` é o que o `sendNotification` procura; deixar editar num template\n * existente não seria edição, seria criar outro e deixar o antigo órfão no ar.\n */\n\nimport { useMemo, useState } from 'react'\n\nimport {\n SORT_DIRECTIONS,\n TEMPLATE_SORT_FIELDS,\n TEMPLATE_VIEWS,\n type TemplateSort,\n type TemplateSortField,\n type TemplateView,\n} from '../templateList.constant'\nimport {\n PREVIEW_VIEWPORT_BY_CHANNEL,\n buildPreviewPayload,\n diffTemplateVariables,\n renderTemplate,\n} from '@adatechnology/notification-contracts'\nimport type {\n NotificationChannel,\n StandardEmailAssessment,\n NotificationTemplate,\n PreviewViewportSpec,\n RenderedTemplatePreview,\n TemplateVariableDefinition,\n TemplateVariableDiff,\n UpsertTemplateBody,\n} from '@adatechnology/notification-contracts'\n\nimport { assessStandardEmailDraft, buildStandardEmailPreviewHtml, isStandardEmailKey } from '../standardEmail.util'\nimport {\n useDeactivateTemplate,\n useRestoreTemplateDefault,\n useTemplateVariables,\n useTemplates,\n useUpsertTemplate,\n} from './usePreferences'\n\nexport type TemplateDraft = {\n readonly key: string\n /**\n * Canais, no plural: um aviso costuma sair por mais de um.\n *\n * No banco a identidade continua sendo `key`+`channel`+`locale` — uma linha por canal. Escolher\n * varios aqui grava um template por canal com o MESMO texto, que e o comportamento certo para\n * criar: escrever a mensagem uma vez e mandar por onde precisar. Depois, cada canal e editado\n * sozinho pela lista, porque o texto tende a divergir (o SMS encurta, o WhatsApp perde o titulo).\n */\n readonly channels: readonly string[]\n readonly locale: string\n /**\n * Texto POR CANAL, e não um só copiado para todos.\n *\n * Os canais não são o mesmo recado em molduras diferentes: o WhatsApp ignora o assunto, o SMS\n * cobra por segmento de 160 e encurta, o push corta em duas linhas. Um texto único obrigaria a\n * escrever para o pior canal e mandar isso a todos. No banco cada canal já é uma linha própria\n * (`key`+`channel`+`locale`) — aqui a tela passa a refletir isso.\n */\n readonly byChannel: Readonly<Record<string, ChannelDraft>>\n}\n\nexport type ChannelDraft = {\n readonly subject: string\n readonly body: string\n readonly whatsappTemplateName: string\n}\n\nconst EMPTY_CHANNEL: ChannelDraft = { subject: '', body: '', whatsappTemplateName: '' }\n\nexport type TemplateDraftField = 'subject' | 'body'\n\nexport type TemplatePreviewFrame = PreviewViewportSpec & {\n /** O canal viaja com o quadro: a moldura do preview depende dele, e ler do rascunho dentro do\n * `map` perde a garantia de que o rascunho existe. */\n readonly channel: string\n readonly rendered: RenderedTemplatePreview\n}\n\nfunction toDraft(template: NotificationTemplate): TemplateDraft {\n return {\n key: template.key,\n channels: [template.channel],\n locale: template.locale,\n byChannel: {\n [template.channel]: {\n subject: template.subject ?? '',\n body: template.body,\n whatsappTemplateName: template.whatsappTemplateName ?? '',\n },\n },\n }\n}\n\n/** `auth` em `auth.password_reset`. Chave sem ponto é a própria categoria. */\nfunction categoryOf(key: string): string {\n return key.split('.')[0] ?? key\n}\n\nfunction buildEmptyDraft(params: { channel: string; locale: string }): TemplateDraft {\n return {\n key: '',\n channels: [params.channel],\n locale: params.locale,\n byChannel: { [params.channel]: EMPTY_CHANNEL },\n }\n}\n\nexport type UseTemplateEditorParams = {\n /**\n * Valores de exemplo do preview. Hoje o padrão vem do catálogo de variáveis do servidor; isto\n * continua existindo para o produto sobrescrever um exemplo pontual sem mexer no catálogo.\n */\n readonly previewPayload?: Readonly<Record<string, unknown>>\n /** Canal e locale de um template novo, antes de o operador escolher. */\n readonly defaultChannel?: string\n readonly defaultLocale?: string\n}\n\n/**\n * Um grupo da lista.\n *\n * O prefixo da chave (`auth` em `auth.password_reset`) já é a categoria que o produto escreveu — o\n * módulo não precisa de um campo novo no banco para agrupar, e um campo novo divergiria da chave\n * na primeira vez que alguém renomeasse um sem o outro.\n */\nexport type TemplateGroup = {\n readonly category: string\n readonly templates: readonly NotificationTemplate[]\n}\n\nexport type UseTemplateEditorResult = {\n readonly templates: readonly NotificationTemplate[]\n /** Já filtrados e agrupados por categoria, na ordem em que a tela desenha. */\n readonly groups: readonly TemplateGroup[]\n /** Todas as categorias existentes, inclusive as que o filtro escondeu. */\n readonly categories: readonly string[]\n readonly search: string\n readonly channelFilter: readonly string[]\n readonly categoryFilter: readonly string[]\n readonly hasFilters: boolean\n /** Quantos templates existem antes de filtrar — separa \"nada cadastrado\" de \"nada encontrado\". */\n readonly totalCount: number\n /** Tabela para comparar, lista para reconhecer. */\n readonly view: TemplateView\n /** Ausente = ordem natural (categoria, depois chave) — o terceiro estado do cabeçalho. */\n readonly sort: TemplateSort | undefined\n setView: (view: TemplateView) => void\n /** Cicla `asc` → `desc` → neutro na mesma coluna; outra coluna recomeça em `asc`. */\n toggleSort: (field: TemplateSortField) => void\n setSearch: (value: string) => void\n toggleChannelFilter: (channel: string) => void\n toggleCategoryFilter: (category: string) => void\n clearFilters: () => void\n readonly isLoading: boolean\n readonly isSaving: boolean\n readonly isDeactivating: boolean\n readonly isRestoring: boolean\n /** `true` quando o rascunho é o modelo padrão do sistema: sem assunto, sem remover, validado à parte. */\n readonly isStandardEmail: boolean\n /** O laudo do modelo padrão (faltantes e inseguros); `undefined` nos demais modelos. */\n readonly standardAssessment: StandardEmailAssessment | undefined\n /** O modelo padrão renderizado com os exemplos do catálogo; `undefined` nos demais. */\n readonly standardPreviewHtml: string | undefined\n readonly error: string | undefined\n readonly selected: NotificationTemplate | undefined\n readonly draft: TemplateDraft | undefined\n /** `true` enquanto o rascunho é um template que ainda não existe no servidor. */\n readonly isNew: boolean\n /** Identidade travada — `false` só durante a criação. */\n readonly isIdentityLocked: boolean\n /** Os dois quadros do preview, na ordem em que a tela desenha. */\n readonly previews: readonly TemplatePreviewFrame[]\n /** As variáveis que esta `key` declara. Vazio quando o catálogo não conhece a chave. */\n readonly variables: readonly TemplateVariableDefinition[]\n readonly variableDiff: TemplateVariableDiff\n readonly isDirty: boolean\n readonly canSave: boolean\n select: (template: NotificationTemplate) => void\n startNew: () => void\n update: (patch: Partial<TemplateDraft>) => void\n /** Edita o texto de UM canal. */\n updateChannel: (channel: string, patch: Partial<ChannelDraft>) => void\n /** Liga ou desliga um canal do rascunho. Nunca esvazia para nada: sem canal nao ha o que gravar. */\n toggleChannel: (channel: string) => void\n /** Insere `{{nome}}` na posição do cursor. O operador nunca digita o nome à mão. */\n insertVariable: (params: { name: string; field: TemplateDraftField; cursorIndex: number; channel: string }) => void\n save: () => void\n deactivate: (id: string) => void\n /** \"Restaurar padrão\": versão nova com o modelo embutido no SDK. */\n restoreDefault: (id: string) => void\n clear: () => void\n}\n\nexport function useTemplateEditor(params: UseTemplateEditorParams = {}): UseTemplateEditorResult {\n const templatesQuery = useTemplates()\n const variablesQuery = useTemplateVariables()\n const upsert = useUpsertTemplate()\n const deactivateMutation = useDeactivateTemplate()\n const restoreMutation = useRestoreTemplateDefault()\n\n const [search, setSearch] = useState('')\n const [channelFilter, setChannelFilter] = useState<readonly string[]>([])\n const [categoryFilter, setCategoryFilter] = useState<readonly string[]>([])\n const [view, setView] = useState<TemplateView>(TEMPLATE_VIEWS.TABLE)\n const [sort, setSort] = useState<TemplateSort | undefined>(undefined)\n const [selectedId, setSelectedId] = useState<string | undefined>(undefined)\n const [draft, setDraft] = useState<TemplateDraft | undefined>(undefined)\n const [isNew, setIsNew] = useState(false)\n\n /** Decisão 1: só a ativa mais alta por `key`+`channel`+`locale` — a mesma que o envio faz. */\n const templates = useMemo(() => {\n const activeByIdentity = new Map<string, NotificationTemplate>()\n for (const template of templatesQuery.data ?? []) {\n if (!template.active) continue\n const identity = `${template.key}:${template.channel}:${template.locale}`\n const current = activeByIdentity.get(identity)\n if (!current || template.version > current.version) activeByIdentity.set(identity, template)\n }\n return [...activeByIdentity.values()].sort(\n (left, right) => left.key.localeCompare(right.key) || left.channel.localeCompare(right.channel),\n )\n }, [templatesQuery.data])\n\n const categories = useMemo(\n () => [...new Set(templates.map((template) => categoryOf(template.key)))].sort(),\n [templates],\n )\n\n /**\n * Busca sobre chave E texto: quem procura \"senha\" costuma lembrar do que a mensagem diz, não da\n * chave técnica que alguém escolheu meses atrás.\n */\n const filtered = useMemo(() => {\n const termo = search.trim().toLowerCase()\n\n return templates.filter((template) => {\n if (channelFilter.length > 0 && !channelFilter.includes(template.channel)) return false\n if (categoryFilter.length > 0 && !categoryFilter.includes(categoryOf(template.key))) return false\n if (!termo) return true\n return `${template.key} ${template.subject ?? ''} ${template.body}`.toLowerCase().includes(termo)\n })\n }, [templates, search, channelFilter, categoryFilter])\n\n /**\n * Ordenação só existe quando alguém pediu: sem `sort`, a ordem é a natural (categoria e chave),\n * que é a que o agrupamento desenha. Reordenar por padrão esconderia essa estrutura.\n */\n const sorted = useMemo(() => {\n if (!sort) return filtered\n const sinal = sort.direction === SORT_DIRECTIONS.ASC ? 1 : -1\n\n return [...filtered].sort((left, right) => {\n if (sort.field === TEMPLATE_SORT_FIELDS.VERSION) return (left.version - right.version) * sinal\n const campo = sort.field === TEMPLATE_SORT_FIELDS.CHANNEL ? 'channel' : 'key'\n return left[campo].localeCompare(right[campo]) * sinal\n })\n }, [filtered, sort])\n\n const groups = useMemo<readonly TemplateGroup[]>(() => {\n const porCategoria = new Map<string, NotificationTemplate[]>()\n for (const template of sorted) {\n const categoria = categoryOf(template.key)\n const atual = porCategoria.get(categoria)\n if (atual) atual.push(template)\n else porCategoria.set(categoria, [template])\n }\n return [...porCategoria.entries()]\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([category, list]) => ({ category, templates: list }))\n }, [sorted])\n\n /** Decisão 2: derivado do id. */\n const selected = useMemo(() => templates.find((template) => template.id === selectedId), [templates, selectedId])\n\n const variables = useMemo(() => (draft ? (variablesQuery.data?.[draft.key] ?? []) : []), [variablesQuery.data, draft])\n\n const variableDiff = useMemo(\n () =>\n diffTemplateVariables({\n /** Junta o texto de todos os canais: variavel errada em qualquer um recusa a gravacao. */\n body: draft ? draft.channels.map((c) => draft.byChannel[c]?.body ?? '').join('\\n') : '',\n subject: draft ? draft.channels.map((c) => draft.byChannel[c]?.subject ?? '').join('\\n') : undefined,\n // Chave sem entrada no catálogo é catálogo não declarado, não catálogo vazio — o servidor\n // aceita qualquer variável nesse caso, e a tela não pode acusar o que a rota vai gravar.\n variables: draft && variablesQuery.data?.[draft.key] ? variables : undefined,\n }),\n [draft, variables, variablesQuery.data],\n )\n\n /** Decisão 4: o mesmo render do envio, uma vez por viewport do canal. */\n const previews = useMemo<readonly TemplatePreviewFrame[]>(() => {\n if (!draft) return []\n const payload = { ...buildPreviewPayload(variables), ...(params.previewPayload ?? {}) }\n /** Um conjunto de quadros por canal escolhido: e o que permite comparar como o mesmo texto\n * chega no e-mail e no WhatsApp sem salvar antes. */\n return draft.channels.flatMap((channel) => {\n const content = draft.byChannel[channel] ?? EMPTY_CHANNEL\n const rendered = renderTemplate({\n channel,\n subject: content.subject || undefined,\n body: content.body,\n payload,\n })\n const viewports = PREVIEW_VIEWPORT_BY_CHANNEL[channel as NotificationChannel] ?? []\n return viewports.map((viewport) => ({ ...viewport, channel, rendered }))\n })\n }, [draft, variables, params.previewPayload])\n\n const isStandardEmail = draft !== undefined && isStandardEmailKey(draft.key)\n const standardHtml = isStandardEmail ? (draft?.byChannel[draft.channels[0] ?? '']?.body ?? '') : undefined\n const standardAssessment = useMemo(\n () => (standardHtml === undefined ? undefined : assessStandardEmailDraft(standardHtml)),\n [standardHtml],\n )\n const standardPreviewHtml = useMemo(\n () =>\n standardHtml === undefined || !standardAssessment?.usable\n ? undefined\n : buildStandardEmailPreviewHtml(standardHtml),\n [standardHtml, standardAssessment],\n )\n\n const isDirty = useMemo(() => {\n if (!draft) return false\n const temTexto = draft.channels.some((channel) => (draft.byChannel[channel]?.body ?? '').length > 0)\n if (isNew) return draft.key.length > 0 || temTexto\n if (!selected) return false\n const original = toDraft(selected).byChannel[selected.channel] ?? EMPTY_CHANNEL\n const atual = draft.byChannel[selected.channel] ?? EMPTY_CHANNEL\n return (Object.keys(original) as (keyof ChannelDraft)[]).some((field) => original[field] !== atual[field])\n }, [draft, selected, isNew])\n\n return {\n templates: sorted,\n groups,\n view,\n sort,\n categories,\n search,\n channelFilter,\n categoryFilter,\n // Ordenação conta: o botão de limpar existe para desfazer QUALQUER recorte aplicado (web.md §7).\n hasFilters: search.trim().length > 0 || channelFilter.length > 0 || categoryFilter.length > 0 || sort !== undefined,\n totalCount: templates.length,\n isLoading: templatesQuery.isLoading,\n isSaving: upsert.isPending,\n isDeactivating: deactivateMutation.isPending,\n isRestoring: restoreMutation.isPending,\n isStandardEmail,\n standardAssessment,\n standardPreviewHtml,\n error: upsert.error?.message ?? deactivateMutation.error?.message ?? restoreMutation.error?.message,\n selected,\n draft,\n isNew,\n isIdentityLocked: !isNew,\n previews,\n variables,\n variableDiff,\n isDirty,\n // A variável desconhecida é recusada pelo servidor com 400; bloquear o botão evita a ida\n // perdida, sem virar a única defesa — a validação continua sendo a da rota.\n /** Todo canal marcado precisa do proprio texto — senao a gravacao criaria template vazio. */\n canSave:\n Boolean(draft?.key) &&\n (draft?.channels.length ?? 0) > 0 &&\n (draft?.channels.every((channel) => (draft.byChannel[channel]?.body ?? '').length > 0) ?? false) &&\n variableDiff.unknown.length === 0 &&\n // O modelo padrão inutilizável nunca é gravado: o servidor recusa (400) e o envio o ignoraria.\n (standardAssessment?.usable ?? true),\n\n setSearch,\n\n toggleChannelFilter(channel) {\n setChannelFilter((current) =>\n current.includes(channel) ? current.filter((each) => each !== channel) : [...current, channel],\n )\n },\n\n toggleCategoryFilter(category) {\n setCategoryFilter((current) =>\n current.includes(category) ? current.filter((each) => each !== category) : [...current, category],\n )\n },\n\n setView,\n toggleSort(field) {\n setSort((current) => {\n if (current?.field !== field) return { field, direction: SORT_DIRECTIONS.ASC }\n if (current.direction === SORT_DIRECTIONS.ASC) return { field, direction: SORT_DIRECTIONS.DESC }\n return undefined\n })\n },\n clearFilters() {\n setSearch('')\n setChannelFilter([])\n setCategoryFilter([])\n setSort(undefined)\n },\n\n select(template) {\n setSelectedId(template.id)\n setDraft(toDraft(template))\n setIsNew(false)\n },\n\n startNew() {\n setSelectedId(undefined)\n setIsNew(true)\n setDraft(buildEmptyDraft({ channel: params.defaultChannel ?? 'email', locale: params.defaultLocale ?? 'pt-BR' }))\n },\n\n update(patch) {\n setDraft((current) => (current ? { ...current, ...patch } : current))\n },\n\n updateChannel(channel, patch) {\n setDraft((current) => {\n if (!current) return current\n const atual = current.byChannel[channel] ?? EMPTY_CHANNEL\n return { ...current, byChannel: { ...current.byChannel, [channel]: { ...atual, ...patch } } }\n })\n },\n\n toggleChannel(channel) {\n setDraft((current) => {\n if (!current) return current\n if (current.channels.includes(channel)) {\n /** O texto do canal desmarcado fica guardado: remarcar nao pode apagar o que foi escrito. */\n return { ...current, channels: current.channels.filter((each) => each !== channel) }\n }\n return {\n ...current,\n channels: [...current.channels, channel],\n byChannel: { ...current.byChannel, [channel]: current.byChannel[channel] ?? EMPTY_CHANNEL },\n }\n })\n },\n\n insertVariable({ name, field, cursorIndex, channel }) {\n setDraft((current) => {\n if (!current) return current\n const atual = current.byChannel[channel] ?? EMPTY_CHANNEL\n const text = atual[field]\n const at = Math.min(Math.max(cursorIndex, 0), text.length)\n return {\n ...current,\n byChannel: {\n ...current.byChannel,\n [channel]: { ...atual, [field]: `${text.slice(0, at)}{{${name}}}${text.slice(at)}` },\n },\n }\n })\n },\n\n save() {\n if (!draft) return\n\n /** Um `upsert` por canal, em serie: o servidor versiona por identidade, e o numero da versao\n * de um canal nao pode depender da ordem de chegada do outro. */\n const bodies: UpsertTemplateBody[] = draft.channels.map((channel) => {\n const content = draft.byChannel[channel] ?? EMPTY_CHANNEL\n return {\n key: draft.key,\n channel: channel as UpsertTemplateBody['channel'],\n locale: draft.locale,\n active: true,\n body: content.body,\n // Modelo padrão não tem assunto: ele é dado do envio, e um assunto aqui se acumularia.\n ...(content.subject && !isStandardEmail ? { subject: content.subject } : {}),\n ...(content.whatsappTemplateName ? { whatsappTemplateName: content.whatsappTemplateName } : {}),\n }\n })\n\n void bodies\n .reduce(\n (queue, body) => queue.then(() => upsert.mutateAsync(body).then(() => undefined)),\n Promise.resolve<void>(undefined),\n )\n .then(() => {\n setSelectedId(undefined)\n setDraft(undefined)\n setIsNew(false)\n })\n .catch(() => undefined)\n },\n\n deactivate(id) {\n deactivateMutation.mutate(id, {\n onSuccess: () => {\n if (selectedId !== id) return\n setSelectedId(undefined)\n setDraft(undefined)\n },\n })\n },\n\n restoreDefault(id) {\n restoreMutation.mutate(id, {\n onSuccess: () => {\n if (selectedId !== id) return\n setSelectedId(undefined)\n setDraft(undefined)\n },\n })\n },\n\n clear() {\n setSelectedId(undefined)\n setDraft(undefined)\n setIsNew(false)\n },\n }\n}\n","/**\n * Copyright (c) 2026 Ada Technology. MIT License.\n *\n * Modos de exibição e ordenação da lista de mensagens.\n *\n * Duas leituras da mesma coleção: a TABELA compara (canal e versão alinhados em coluna, varredura\n * vertical) e a LISTA reconhece (o texto da mensagem visível em duas linhas). Quem administra trinta\n * templates quer a tabela; quem procura \"aquela que fala de senha\" quer a lista.\n */\n\nexport const TEMPLATE_VIEWS = {\n TABLE: 'table',\n LIST: 'list',\n} as const\nexport type TemplateView = (typeof TEMPLATE_VIEWS)[keyof typeof TEMPLATE_VIEWS]\n\n/** As colunas ordenáveis da tabela — e só elas: cabeçalho clicável que não ordena é mentira. */\nexport const TEMPLATE_SORT_FIELDS = {\n KEY: 'key',\n CHANNEL: 'channel',\n VERSION: 'version',\n} as const\nexport type TemplateSortField = (typeof TEMPLATE_SORT_FIELDS)[keyof typeof TEMPLATE_SORT_FIELDS]\n\nexport const SORT_DIRECTIONS = {\n ASC: 'asc',\n DESC: 'desc',\n} as const\nexport type SortDirection = (typeof SORT_DIRECTIONS)[keyof typeof SORT_DIRECTIONS]\n\nexport type TemplateSort = {\n readonly field: TemplateSortField\n readonly direction: SortDirection\n}\n\n/**\n * As colunas da tabela, na ordem. `field` ausente = coluna que não ordena (texto livre e ações):\n * cabeçalho clicável que não reordena nada é promessa quebrada.\n */\nexport type TemplateColumn = {\n readonly labelKey: string\n readonly field?: TemplateSortField\n /** Cabeçalho só para leitor de tela — a coluna de ação não precisa de título visível. */\n readonly headerHidden?: boolean\n}\n\nexport const TEMPLATE_COLUMNS: readonly TemplateColumn[] = [\n { labelKey: 'settings.column.key', field: TEMPLATE_SORT_FIELDS.KEY },\n { labelKey: 'settings.column.body' },\n { labelKey: 'settings.column.channel', field: TEMPLATE_SORT_FIELDS.CHANNEL },\n { labelKey: 'settings.column.version', field: TEMPLATE_SORT_FIELDS.VERSION },\n { labelKey: 'settings.column.actions', headerHidden: true },\n]\n","/**\n * Copyright (c) 2026 Ada Technology. MIT License.\n *\n * O modelo padrão de e-mail (`notification.standard-email`) na tela: quem é, se está utilizável e\n * como fica com os exemplos do catálogo. A regra mora no `notification-contracts` — aqui só se\n * chama, para a tela e o servidor nunca discordarem do que é \"utilizável\".\n */\n\nimport {\n STANDARD_EMAIL_TEMPLATE_KEY,\n STANDARD_EMAIL_VARIABLES,\n assessStandardEmailTemplate,\n renderStandardEmail,\n type StandardEmailAssessment,\n} from '@adatechnology/notification-contracts'\n\nexport function isStandardEmailKey(key: string): boolean {\n return key === STANDARD_EMAIL_TEMPLATE_KEY\n}\n\n/** Vale para o HTML inteiro do modelo; não depende da área de mensagem. */\nexport function assessStandardEmailDraft(html: string): StandardEmailAssessment {\n return assessStandardEmailTemplate(html)\n}\n\nfunction example(name: string): string {\n return STANDARD_EMAIL_VARIABLES.find((variable) => variable.name === name)?.example ?? ''\n}\n\n/** O modelo renderizado pelo mesmo `renderStandardEmail` do envio, com os exemplos do catálogo. */\nexport function buildStandardEmailPreviewHtml(templateHtml: string): string {\n return renderStandardEmail({\n template: { html: templateHtml, source: 'company', version: 0 },\n input: {\n attachments: [{ name: example('listaAnexos') }],\n bodyText: example('corpoMensagem'),\n footer: { platformNote: example('rodapePlataforma') },\n identity: { displayName: example('nomeEmpresa'), logo: { kind: 'initials' } },\n replyHint: example('faixaResposta'),\n signer: { name: example('nomeAssinante'), role: example('cargoAssinante') },\n },\n }).html\n}\n"],"mappings":"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","names":["useQueryClient","useQueryClient","useMemo","useMutation","useQuery","useQueryClient","useQueryClient","useQuery","useMutation","useMemo","useMutation","useQuery","useQueryClient","useQuery","useQueryClient","useMutation","useMemo","useState","useState","useMemo"]}
@@ -4,7 +4,7 @@ import * as _adatechnology_notification_client from '@adatechnology/notification
4
4
  import { NotificationClient } from '@adatechnology/notification-client';
5
5
  import * as _tanstack_react_query from '@tanstack/react-query';
6
6
  import * as _adatechnology_notification_contracts from '@adatechnology/notification-contracts';
7
- import { NotificationSummary, NotificationPreference, PreviewViewportSpec, RenderedTemplatePreview, NotificationTemplate, TemplateVariableDefinition, TemplateVariableDiff } from '@adatechnology/notification-contracts';
7
+ import { NotificationSummary, NotificationPreference, PreviewViewportSpec, RenderedTemplatePreview, NotificationTemplate, StandardEmailAssessment, TemplateVariableDefinition, TemplateVariableDiff } from '@adatechnology/notification-contracts';
8
8
 
9
9
  var ptBR = {
10
10
  "bell.label": "Notificações",
@@ -54,6 +54,16 @@ var ptBR = {
54
54
  "settings.close": "Fechar",
55
55
  "settings.version": "v",
56
56
  "settings.newTemplate": "Nova mensagem",
57
+ "settings.systemTemplate": "Modelo do sistema",
58
+ "settings.restoreDefault": "Restaurar padrão",
59
+ "settings.restoring": "Restaurando…",
60
+ "settings.standardEmailHint": "Moldura de todo e-mail enviado pelo sistema. O assunto é o da conversa; use as variáveis obrigatórias.",
61
+ "settings.standardMissing": "Variáveis obrigatórias que faltam:",
62
+ "settings.standardUnsafe": "HTML não permitido neste modelo:",
63
+ "settings.standardUnsafe.event": "atributo de evento (onclick e similares)",
64
+ "settings.standardUnsafe.placeholder_in_tag": "variável dentro de uma tag ou atributo",
65
+ "settings.standardUnsafe.scheme": "endereço com esquema não permitido",
66
+ "settings.standardUnsafe.tag": "tag não permitida (script, iframe e similares)",
57
67
  "settings.remove": "Remover",
58
68
  "settings.key": "Chave da notificação",
59
69
  "settings.keyHint": "Não muda depois de criada — é por ela que o envio acha a mensagem.",
@@ -217,9 +227,9 @@ type UseCategoryPoliciesResult = {
217
227
  };
218
228
  declare function useCategoryPolicies(): UseCategoryPoliciesResult;
219
229
 
220
- declare function usePreferences(): _tanstack_react_query.UseQueryResult<NoInfer<readonly NotificationPreference[]>, Error>;
230
+ declare function usePreferences(): _tanstack_react_query.UseQueryResult<readonly NotificationPreference[], Error>;
221
231
  declare function useUpdatePreferences(): _tanstack_react_query.UseMutationResult<readonly NotificationPreference[], Error, readonly NotificationPreference[], unknown>;
222
- declare function useTemplates(): _tanstack_react_query.UseQueryResult<NoInfer<readonly _adatechnology_notification_contracts.NotificationTemplate[]>, Error>;
232
+ declare function useTemplates(): _tanstack_react_query.UseQueryResult<readonly _adatechnology_notification_contracts.NotificationTemplate[], Error>;
223
233
  /**
224
234
  * Salva uma VERSÃO nova do template. É o que a tela de configuração usa para o lojista mudar a copy
225
235
  * sem deploy.
@@ -241,13 +251,14 @@ declare function useUpsertTemplate(): _tanstack_react_query.UseMutationResult<_a
241
251
  * O catálogo é config do host: muda com deploy, não com uso. `staleTime: Infinity` evita refetch a
242
252
  * cada foco de janela por um dado que não muda durante a sessão.
243
253
  */
244
- declare function useTemplateVariables(): _tanstack_react_query.UseQueryResult<NoInfer<Readonly<Record<string, readonly _adatechnology_notification_contracts.TemplateVariableDefinition[]>>>, Error>;
254
+ declare function useTemplateVariables(): _tanstack_react_query.UseQueryResult<Readonly<Record<string, readonly _adatechnology_notification_contracts.TemplateVariableDefinition[]>>, Error>;
245
255
  /**
246
256
  * Desativa o template. Invalida a lista pelo mesmo motivo do upsert: o servidor derruba TODAS as
247
257
  * versões ativas da identidade, e um cache otimista que removesse só a linha clicada mostraria a
248
258
  * versão anterior de volta na tela.
249
259
  */
250
260
  declare function useDeactivateTemplate(): _tanstack_react_query.UseMutationResult<void, Error, string, unknown>;
261
+ declare function useRestoreTemplateDefault(): _tanstack_react_query.UseMutationResult<_adatechnology_notification_contracts.NotificationTemplate, Error, string, unknown>;
251
262
 
252
263
  /**
253
264
  * Copyright (c) 2026 Ada Technology. MIT License.
@@ -431,6 +442,13 @@ type UseTemplateEditorResult = {
431
442
  readonly isLoading: boolean;
432
443
  readonly isSaving: boolean;
433
444
  readonly isDeactivating: boolean;
445
+ readonly isRestoring: boolean;
446
+ /** `true` quando o rascunho é o modelo padrão do sistema: sem assunto, sem remover, validado à parte. */
447
+ readonly isStandardEmail: boolean;
448
+ /** O laudo do modelo padrão (faltantes e inseguros); `undefined` nos demais modelos. */
449
+ readonly standardAssessment: StandardEmailAssessment | undefined;
450
+ /** O modelo padrão renderizado com os exemplos do catálogo; `undefined` nos demais. */
451
+ readonly standardPreviewHtml: string | undefined;
434
452
  readonly error: string | undefined;
435
453
  readonly selected: NotificationTemplate | undefined;
436
454
  readonly draft: TemplateDraft | undefined;
@@ -461,8 +479,10 @@ type UseTemplateEditorResult = {
461
479
  }) => void;
462
480
  save: () => void;
463
481
  deactivate: (id: string) => void;
482
+ /** "Restaurar padrão": versão nova com o modelo embutido no SDK. */
483
+ restoreDefault: (id: string) => void;
464
484
  clear: () => void;
465
485
  };
466
486
  declare function useTemplateEditor(params?: UseTemplateEditorParams): UseTemplateEditorResult;
467
487
 
468
- export { useDeleteNotification as A, useMarkAllAsRead as B, useMarkAsRead as C, DEFAULT_LOCALE as D, useNotificationContext as E, useNotificationStream as F, useNotifications as G, usePreferences as H, useTemplateEditor as I, useTemplateVariables as J, useTemplates as K, useUnreadCount as L, useUpdatePreferences as M, NOTIFICATION_QUERY_KEYS as N, useUpsertTemplate as O, SORT_DIRECTIONS as S, TEMPLATE_COLUMNS as T, type UseCategoryPoliciesResult as U, type NotificationContextValue as a, type NotificationLocale as b, type NotificationMessages as c, NotificationProvider as d, type NotificationProviderProps as e, type NotificationTheme as f, type SortDirection as g, TEMPLATE_SORT_FIELDS as h, TEMPLATE_VIEWS as i, type TemplateColumn as j, type TemplateDraft as k, type TemplateDraftField as l, type TemplatePreviewFrame as m, type TemplateSort as n, type TemplateSortField as o, type TemplateView as p, type UseNotificationStreamOptions as q, type UseNotificationsOptions as r, type UseTemplateEditorParams as s, type UseTemplateEditorResult as t, flattenNotificationPages as u, formatNotificationTime as v, formatNotificationTimestamp as w, resolveMessages as x, useCategoryPolicies as y, useDeactivateTemplate as z };
488
+ export { useDeleteNotification as A, useMarkAllAsRead as B, useMarkAsRead as C, DEFAULT_LOCALE as D, useNotificationContext as E, useNotificationStream as F, useNotifications as G, usePreferences as H, useRestoreTemplateDefault as I, useTemplateEditor as J, useTemplateVariables as K, useTemplates as L, useUnreadCount as M, NOTIFICATION_QUERY_KEYS as N, useUpdatePreferences as O, useUpsertTemplate as P, SORT_DIRECTIONS as S, TEMPLATE_COLUMNS as T, type UseCategoryPoliciesResult as U, type NotificationContextValue as a, type NotificationLocale as b, type NotificationMessages as c, NotificationProvider as d, type NotificationProviderProps as e, type NotificationTheme as f, type SortDirection as g, TEMPLATE_SORT_FIELDS as h, TEMPLATE_VIEWS as i, type TemplateColumn as j, type TemplateDraft as k, type TemplateDraftField as l, type TemplatePreviewFrame as m, type TemplateSort as n, type TemplateSortField as o, type TemplateView as p, type UseNotificationStreamOptions as q, type UseNotificationsOptions as r, type UseTemplateEditorParams as s, type UseTemplateEditorResult as t, flattenNotificationPages as u, formatNotificationTime as v, formatNotificationTimestamp as w, resolveMessages as x, useCategoryPolicies as y, useDeactivateTemplate as z };
@@ -1,4 +1,4 @@
1
- export { D as DEFAULT_LOCALE, N as NOTIFICATION_QUERY_KEYS, a as NotificationContextValue, b as NotificationLocale, c as NotificationMessages, d as NotificationProvider, e as NotificationProviderProps, f as NotificationTheme, k as TemplateDraft, l as TemplateDraftField, m as TemplatePreviewFrame, U as UseCategoryPoliciesResult, q as UseNotificationStreamOptions, r as UseNotificationsOptions, s as UseTemplateEditorParams, t as UseTemplateEditorResult, u as flattenNotificationPages, v as formatNotificationTime, w as formatNotificationTimestamp, x as resolveMessages, y as useCategoryPolicies, z as useDeactivateTemplate, A as useDeleteNotification, B as useMarkAllAsRead, C as useMarkAsRead, E as useNotificationContext, F as useNotificationStream, G as useNotifications, H as usePreferences, I as useTemplateEditor, J as useTemplateVariables, K as useTemplates, L as useUnreadCount, M as useUpdatePreferences, O as useUpsertTemplate } from './headless--T3Ry0h4.js';
1
+ export { D as DEFAULT_LOCALE, N as NOTIFICATION_QUERY_KEYS, a as NotificationContextValue, b as NotificationLocale, c as NotificationMessages, d as NotificationProvider, e as NotificationProviderProps, f as NotificationTheme, k as TemplateDraft, l as TemplateDraftField, m as TemplatePreviewFrame, U as UseCategoryPoliciesResult, q as UseNotificationStreamOptions, r as UseNotificationsOptions, s as UseTemplateEditorParams, t as UseTemplateEditorResult, u as flattenNotificationPages, v as formatNotificationTime, w as formatNotificationTimestamp, x as resolveMessages, y as useCategoryPolicies, z as useDeactivateTemplate, A as useDeleteNotification, B as useMarkAllAsRead, C as useMarkAsRead, E as useNotificationContext, F as useNotificationStream, G as useNotifications, H as usePreferences, I as useRestoreTemplateDefault, J as useTemplateEditor, K as useTemplateVariables, L as useTemplates, M as useUnreadCount, O as useUpdatePreferences, P as useUpsertTemplate } from './headless-03_gfBEI.js';
2
2
  import 'react';
3
3
  import '@adatechnology/notification-client';
4
4
  import '@tanstack/react-query';
package/dist/headless.js CHANGED
@@ -15,13 +15,14 @@ import {
15
15
  useNotificationStream,
16
16
  useNotifications,
17
17
  usePreferences,
18
+ useRestoreTemplateDefault,
18
19
  useTemplateEditor,
19
20
  useTemplateVariables,
20
21
  useTemplates,
21
22
  useUnreadCount,
22
23
  useUpdatePreferences,
23
24
  useUpsertTemplate
24
- } from "./chunk-7XDQ76IV.js";
25
+ } from "./chunk-SFMOFCHV.js";
25
26
  export {
26
27
  DEFAULT_LOCALE,
27
28
  NOTIFICATION_QUERY_KEYS,
@@ -39,6 +40,7 @@ export {
39
40
  useNotificationStream,
40
41
  useNotifications,
41
42
  usePreferences,
43
+ useRestoreTemplateDefault,
42
44
  useTemplateEditor,
43
45
  useTemplateVariables,
44
46
  useTemplates,
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { D as DEFAULT_LOCALE, N as NOTIFICATION_QUERY_KEYS, a as NotificationContextValue, b as NotificationLocale, c as NotificationMessages, d as NotificationProvider, e as NotificationProviderProps, f as NotificationTheme, S as SORT_DIRECTIONS, g as SortDirection, T as TEMPLATE_COLUMNS, h as TEMPLATE_SORT_FIELDS, i as TEMPLATE_VIEWS, j as TemplateColumn, k as TemplateDraft, l as TemplateDraftField, m as TemplatePreviewFrame, n as TemplateSort, o as TemplateSortField, p as TemplateView, U as UseCategoryPoliciesResult, q as UseNotificationStreamOptions, r as UseNotificationsOptions, s as UseTemplateEditorParams, t as UseTemplateEditorResult, u as flattenNotificationPages, v as formatNotificationTime, w as formatNotificationTimestamp, x as resolveMessages, y as useCategoryPolicies, z as useDeactivateTemplate, A as useDeleteNotification, B as useMarkAllAsRead, C as useMarkAsRead, E as useNotificationContext, F as useNotificationStream, G as useNotifications, H as usePreferences, I as useTemplateEditor, J as useTemplateVariables, K as useTemplates, L as useUnreadCount, M as useUpdatePreferences, O as useUpsertTemplate } from './headless--T3Ry0h4.js';
1
+ export { D as DEFAULT_LOCALE, N as NOTIFICATION_QUERY_KEYS, a as NotificationContextValue, b as NotificationLocale, c as NotificationMessages, d as NotificationProvider, e as NotificationProviderProps, f as NotificationTheme, S as SORT_DIRECTIONS, g as SortDirection, T as TEMPLATE_COLUMNS, h as TEMPLATE_SORT_FIELDS, i as TEMPLATE_VIEWS, j as TemplateColumn, k as TemplateDraft, l as TemplateDraftField, m as TemplatePreviewFrame, n as TemplateSort, o as TemplateSortField, p as TemplateView, U as UseCategoryPoliciesResult, q as UseNotificationStreamOptions, r as UseNotificationsOptions, s as UseTemplateEditorParams, t as UseTemplateEditorResult, u as flattenNotificationPages, v as formatNotificationTime, w as formatNotificationTimestamp, x as resolveMessages, y as useCategoryPolicies, z as useDeactivateTemplate, A as useDeleteNotification, B as useMarkAllAsRead, C as useMarkAsRead, E as useNotificationContext, F as useNotificationStream, G as useNotifications, H as usePreferences, I as useRestoreTemplateDefault, J as useTemplateEditor, K as useTemplateVariables, L as useTemplates, M as useUnreadCount, O as useUpdatePreferences, P as useUpsertTemplate } from './headless-03_gfBEI.js';
2
2
  import * as react from 'react';
3
3
  import { ReactNode } from 'react';
4
4
  import { NotificationSummary, NotificationTemplate } from '@adatechnology/notification-contracts';