Melissa: hub Configuracoes + Embed + 9 Pages novas + dialog blueprint dark

Sprints 04-29 + 04-30 acumuladas.

- MelissaConfiguracoes: hub 2-col com 6 grupos (Layout/Conta/Agenda/
  Financeiro/WhatsApp/Sistema), tudo embedado via MelissaEmbed.
- MelissaEmbed: wrapper generico que injeta layout-variant=melissa
  e remove cromos pra reaproveitar Pages tradicionais.
- 9 Melissa Pages novas: CadastrosRecebidos, Compromissos, Configuracoes,
  Conversas, Embed, Grupos, Medicos, Recorrencias, Tags.
- Dialog blueprint atualizado: bg-gray-100 (hardcoded light) ->
  bg-[var(--surface-ground)] (tema-aware). 22 dialogs migrados em
  9 arquivos. Anti-pattern documentado.
- PatientsCadastroPage: bug fix dropdown Grupo (optionLabel nome->name),
  toggle vertical/abas com persist localStorage, sticky margin-top.
- Surface picker no popover do MelissaLayout (8 swatches).
- useTopbarPlanMenu, useMelissaWhatsapp, useMelissaPacientesAside novos.
- Migration: status agenda remarcado/confirmado.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Leonardo
2026-05-04 11:41:19 -03:00
parent 269c380d9c
commit 86311ef305
52 changed files with 16214 additions and 1027 deletions
@@ -21,6 +21,7 @@ import { supabase } from '@/lib/supabase/client';
import { useTenantStore } from '@/stores/tenantStore';
import { useToast } from 'primevue/usetoast';
import { useFeriados } from '@/composables/useFeriados';
import { useLayout } from '@/layout/composables/layout';
import DatePicker from 'primevue/datepicker';
defineOptions({ inheritAttrs: false });
@@ -37,6 +38,14 @@ const emit = defineEmits(['bloqueado']);
const router = useRouter();
const tenantStore = useTenantStore();
const toast = useToast();
const { layoutConfig } = useLayout();
// Quando o layout ativo é Melissa, "Ver todos os feriados" leva pra rota
// interna /melissa/bloqueios (abre MelissaConfiguracoes na seção embed
// de Bloqueios). Caso contrário usa a rota tradicional de configurações.
const verTodosFeriadosRoute = computed(() =>
layoutConfig.variant === 'melissa' ? '/melissa/bloqueios' : '/configuracoes/bloqueios'
);
const { nacionais, municipais, todos, loading, load, criar, remover, isDuplicata, doMes } = useFeriados();
@@ -236,7 +245,7 @@ function fmtDate(iso) {
<i class="pi pi-star text-amber-500 text-sm" />
<span class="font-semibold text-sm">Próximos feriados</span>
</div>
<span class="text-xs text-[var(--text-color-secondary)]">{{ nomeMes }}</span>
<span class="pfc-month-badge">{{ nomeMes }}</span>
</div>
<!-- Lista -->
@@ -282,12 +291,12 @@ function fmtDate(iso) {
<!-- Confirmação inline (expande abaixo do item) -->
<Transition name="pfc-expand">
<div v-if="confirmandoIso === f.data" class="pfc-confirm">
<i class="pi pi-exclamation-triangle pfc-confirm__icon" />
<div class="flex-1 min-w-0">
<p class="text-xs font-semibold mb-0.5">Bloquear {{ f.nome }}?</p>
<p class="text-xs opacity-70 leading-snug">O dia inteiro ficará indisponível. Sessões existentes serão marcadas para reagendamento.</p>
</div>
<div class="flex gap-1.5 shrink-0">
<p class="text-xs font-semibold mb-0.5">
<i class="pi pi-exclamation-triangle pfc-confirm__icon" />
Bloquear {{ f.nome }}?
</p>
<p class="text-xs opacity-70 leading-snug">O dia inteiro ficará indisponível. Sessões existentes serão marcadas para reagendamento.</p>
<div class="pfc-confirm__actions flex gap-1.5">
<Button label="Não" size="small" severity="secondary" outlined class="rounded-full h-7 text-xs px-3" @click="cancelarConfirmacao" />
<Button label="Bloquear" size="small" severity="danger" icon="pi pi-lock" class="rounded-full h-7 text-xs px-3" @click="confirmarBloqueio(f)" />
</div>
@@ -300,7 +309,7 @@ function fmtDate(iso) {
<!-- Ações -->
<div class="flex flex-col gap-1.5 px-4 pb-4">
<Button icon="pi pi-plus" label="Cadastrar feriado municipal" severity="secondary" outlined size="small" class="w-full rounded-full" @click="abrirDialog" />
<Button icon="pi pi-list" label="Ver todos os feriados" text size="small" class="w-full rounded-full" @click="router.push('/configuracoes/bloqueios')" />
<Button icon="pi pi-list" label="Ver todos os feriados" text size="small" class="w-full rounded-full" @click="router.push(verTodosFeriadosRoute)" />
</div>
</div>
@@ -370,20 +379,38 @@ function fmtDate(iso) {
/* ── Confirmação inline ───────────────────────────────────── */
.pfc-confirm {
display: flex;
align-items: flex-start;
gap: 0.625rem;
/* sem display:flex — texto flui em bloco; botões ganham margin-top
pra distanciar do parágrafo. */
padding: 0.625rem 0.75rem;
border-radius: 0.875rem;
background: color-mix(in srgb, var(--red-400, #f87171) 10%, var(--surface-card));
border: 1px solid color-mix(in srgb, var(--red-400, #f87171) 30%, transparent);
margin-left: 2.75rem; /* alinha com o nome, após a data */
}
.pfc-confirm__icon {
color: var(--red-500, #ef4444);
flex-shrink: 0;
margin-top: 2px;
margin-right: 0.375rem;
font-size: 0.8rem;
vertical-align: middle;
}
/* Espaço entre os botões "Não/Bloquear" e o texto acima. */
.pfc-confirm__actions {
margin-top: 10px;
}
/* ── Mês atual no header (badge primary) ─────────────────── */
.pfc-month-badge {
display: inline-flex;
align-items: center;
padding: 2px 10px;
border-radius: 999px;
background: var(--p-primary-color);
color: var(--p-primary-contrast-color, white);
border: 1px solid var(--p-primary-color);
font-size: 0.7rem;
font-weight: 600;
letter-spacing: 0.02em;
text-transform: capitalize;
line-height: 1.4;
}
/* ── Transição expand ─────────────────────────────────────── */