Melissa: paginas nativas cfg-* + temas + textos com fundo + drawer WA

CHROME COMPARTILHADO + 18 PAGINAS NATIVAS
- MelissaConfigPage: chrome unico (header, drawer mobile, sidebar com Configuracoes
  + FAQ slot, main com Suspense). Replica fake-dialog right rule e fica flush
  com o config-aside global.
- 18 wrappers finos (~25 linhas cada): cfg-precificacao, cfg-descontos,
  cfg-excecoes, cfg-convenios, cfg-wa, cfg-wa-pessoal, cfg-wa-oficial,
  cfg-wa-templates, cfg-conversas-tags/autoreply/optouts/sla/bots,
  cfg-lembretes, cfg-creditos-wa, cfg-sms, cfg-email-templates,
  cfg-recursos-extras, cfg-recursos-extras-extrato, cfg-auditoria.
- Cada wrapper usa defineAsyncComponent + Suspense pra evitar race com
  tenantStore no boot (loading travado em alguns chooser-style pages).
- MelissaLayout: imports + SECOES + MELISSA_NON_CONFIG_SLUGS + render
  conditions atualizados pra cobrir os 18 slugs.

PAGINAS LEGADAS DETECTAM CONTEXTO MELISSA
- ConfiguracoesWhatsappChooserPage, WhatsappPage, TwilioWhatsappPage,
  SmsPage, RecursosExtrasPage, EmailTemplatesPage, AddonsExtratoPage,
  AgendadorPage, ConversasAutoreplyPage: route.startsWith('/melissa')
  decide se router.push vai pro slug Melissa ou /configuracoes legado.
- Anchors <a href="/configuracoes/..."> (que recarregavam pagina e
  vazavam o usuario do Melissa) trocados por RouterLink context-aware.
- MelissaAgenda.goSettings agora vai pra /melissa/agenda-config.

PERSONALIZAR > TEMAS
- melissaThemes.js: catalogo Freud/Klein/Jung (wallpaper + cor primaria
  + preset Lara/Nora + surface).
- Toggle de tema aplica tudo de uma vez; persistido em melissa_prefs.themeName.
- Boot resolve themeName -> imagem via fetch + data URL (sem guardar
  data URL gigante no DB).
- onCustomFileChange/onClearBg invalidam themeName quando user mexe no bg.

PERSONALIZAR > FUNDO NOS TEXTOS
- Pref textBgEnabled em melissa_prefs.
- MelissaHeroClock: prop textBg envolve relogio/data/saudacao/resumo
  em <span class="hero-text"> que ganha bg branco/preto 60% + borda
  + padding + radius quando o toggle esta on.
- Vars --m-hero-text-bg / --m-hero-text-border flipam com light/dark.

TOP + DOCK COM GRADIENT HORIZONTAL
- Var --m-band: preto 80% (dark) / branco 80% (light).
- .melissa-topbar-band: gradiente cor->transparente (right->left) atras
  dos botoes do topo.
- .melissa-dock: gradiente cor->transparente (left->right) atras dos pins.

MELISSANEGOCIO ABSORVE MINHA EMPRESA
- Adiciona logo upload + preview "cartao de visita" (computeds
  enderecoLinhas/redesValidas/temDados/logoDisplay + redeIcon helper).
- Normaliza dados legados do cfg-empresa: redes_sociais.{rede} virou {name}.
- Preview teleporta entre 3 destinos baseado no viewport:
  mobile -> drawer; mid-desktop -> sidebar; wide-desktop (>=1340px) ->
  painel flutuante FORA do fake dialog (ancora no right edge + 14px gap,
  altura segue conteudo, header alinhado com header do dialog).
- Remove cfg-empresa de melissaConfigGrupos.js + COMPONENT_MAP do
  MelissaConfiguracoes; grupo "Empresa & Plataforma" -> "Plataforma".

CRONOMETRO -> SESSAO AGENDADA
- MelissaCronometro emite session-end ao parar com paciente selecionado
  (threshold 5s pra ignorar start/stop acidental).
- MelissaLayout.onCronometroSessionEnd busca agenda_eventos do paciente
  no dia (tipo='sessao'), pega o mais recente e grava em
  extra_fields.cronometro_duracao_seg + cronometro_parado_em.
- Toast: sucesso ("X min salvos") ou warn ("sessao nao encontrada").

CONVERSATIONDRAWER WHATSAPP-LIKE
- Nova imagem whatsapp-bg.jpg (renomeada de hash random) usada como
  tile (380px) no .cd-msgs.
- Light: bege #efeae2 + multiply blend.
- Dark: #0b141a + camada 78% sobre o doodle.
- Bubbles WA-style (verde out / branco-dark in com tails) ja existiam.

EXTRATO RECURSOS EXTRAS
- Filtros 2-por-linha em Melissa (vs 1/4 no /configuracoes).
- Cards de Resumo teleportam pro #cfg-page-side em Melissa
  (1-col empilhado no drawer; 4-col inline no /configuracoes).
- Botoes de exportar com flex-1 distribuidos em uma unica linha em
  desktop, wrap no mobile.
- DataTable scrollable em ambos os layouts.

OUTROS AJUSTES MENORES
- Cfg-conversas-autoreply: dias semana 4-cols em Melissa (vs 7-cols
  no /configuracoes).
- Cfg-creditos-wa: 1/2 por linha (vs 1/2/4) em Melissa.
- Cfg-recursos-extras: pacotes 1/2 (vs 1/2/4); "Em breve" 1-col.
- WhatsAppPage aba Templates: guia de formatacao teleporta pro side
  drawer em Melissa, deixando textareas full-width.
- ConfigPage chrome agora tem #cfg-page-actions target pros Teleport
  de acoes (refresh button etc).
- Imagens renomeadas em src/assets/themes/ (freudwebp/melainewebp/
  jungwebp.webp) e src/assets/whatsapp-bg.jpg.
- JoditTextEditor.vue novo (wrapper Jodit generico, sem features de email).
- MelissaConfigList.vue novo (lista compartilhada de configs pro drawer).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Leonardo
2026-05-07 23:48:18 -03:00
parent cc7841bd1f
commit 9966b5f175
60 changed files with 4785 additions and 713 deletions
@@ -8,14 +8,25 @@
-->
<script setup>
import { ref, computed, onMounted, watch } from 'vue';
import { useRoute } from 'vue-router';
import { useToast } from 'primevue/usetoast';
import { useTenantStore } from '@/stores/tenantStore';
import { useAutoReplySettings } from '@/composables/useAutoReplySettings';
const route = useRoute();
const toast = useToast();
const tenantStore = useTenantStore();
const api = useAutoReplySettings();
// Em /melissa o card vive numa coluna mais estreita — quebra os 7 dias
// em 4+3 em vez de espremer 7 colunas. /configuracoes mantem 7 colunas.
const inMelissa = computed(() => String(route.path || '').startsWith('/melissa'));
// Links pra outras paginas de config preservam o layout em que estao
// (Melissa vs /configuracoes), evitando "vazar" o usuario do Melissa.
const agendaPath = computed(() => (inMelissa.value ? '/melissa/agenda-config' : '/configuracoes/agenda'));
const whatsappPath = computed(() => (inMelissa.value ? '/melissa/cfg-wa' : '/configuracoes/whatsapp'));
const DIAS = [
{ dow: 0, label: 'Dom' },
{ dow: 1, label: 'Seg' },
@@ -298,9 +309,9 @@ onBeforeUnmount(() => { if (_tick) clearInterval(_tick); });
<!-- Preview das janelas do modo 'agenda' (read-only) -->
<div v-if="api.settings.value.schedule_mode === 'agenda'" class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-ground)] p-3">
<div v-if="!agendaWindows.length" class="text-xs text-[var(--text-color-secondary)] italic">
Nenhuma regra semanal ativa encontrada na agenda. Configure em <a href="/configuracoes/agenda" class="text-[var(--primary-color)] underline">Configurações Agenda</a>.
Nenhuma regra semanal ativa encontrada na agenda. Configure em <RouterLink :to="agendaPath" class="text-[var(--primary-color)] underline">{{ inMelissa ? 'Agenda' : 'Configurações → Agenda' }}</RouterLink>.
</div>
<div v-else class="grid grid-cols-7 gap-1">
<div v-else class="grid gap-1" :class="inMelissa ? 'grid-cols-4' : 'grid-cols-7'">
<div v-for="d in DIAS" :key="d.dow" class="flex flex-col items-center gap-1">
<div class="text-[0.7rem] font-semibold text-[var(--text-color-secondary)] uppercase">{{ d.label }}</div>
<div class="flex flex-col gap-0.5 w-full">
@@ -341,7 +352,10 @@ onBeforeUnmount(() => { if (_tick) clearInterval(_tick); });
/>
</div>
<div class="grid grid-cols-7 gap-1.5 border border-[var(--surface-border)] rounded-md bg-[var(--surface-ground)] p-2">
<div
class="grid gap-1.5 border border-[var(--surface-border)] rounded-md bg-[var(--surface-ground)] p-2"
:class="inMelissa ? 'grid-cols-4' : 'grid-cols-7'"
>
<div v-for="d in DIAS" :key="d.dow" class="flex flex-col gap-1 min-h-[80px]">
<div class="text-[0.7rem] font-bold text-[var(--text-color-secondary)] uppercase text-center">{{ d.label }}</div>
<div class="flex flex-col gap-1">
@@ -390,7 +404,7 @@ onBeforeUnmount(() => { if (_tick) clearInterval(_tick); });
<i class="pi pi-info-circle text-sky-500 mt-0.5" />
<div>
<strong>Pré-requisito:</strong> o WhatsApp do tenant precisa estar conectado em
<a href="/configuracoes/whatsapp" class="text-[var(--primary-color)] underline">Configurações WhatsApp</a>.
<RouterLink :to="whatsappPath" class="text-[var(--primary-color)] underline">{{ inMelissa ? 'Canal WhatsApp' : 'Configurações → WhatsApp' }}</RouterLink>.
O auto-reply é enviado via o mesmo canal.
<br/>
Todas as datas/horas são tratadas no fuso <strong>America/Sao_Paulo</strong>.