Layout 100%, Notificações, SetupWizard

This commit is contained in:
Leonardo
2026-03-17 21:08:14 -03:00
parent 84d65e49c0
commit 66f67cd40f
77 changed files with 35823 additions and 15023 deletions

View File

@@ -401,39 +401,28 @@ onBeforeUnmount(() => {
<Toast />
<ConfirmDialog />
<!-- Info decorativa (scrolls away naturalmente) -->
<div class="flex items-start gap-4 px-4 pb-3">
<div class="health-hero__icon-wrap">
<i class="pi pi-shield health-hero__icon" />
</div>
<div class="health-hero__sub">
Terapeutas: divergências entre plano (esperado) e entitlements (atual).
Clínicas: exceções comerciais (features liberadas manualmente fora do plano).
</div>
</div>
<!-- Sentinel -->
<div ref="sentinelRef" class="h-px" />
<!-- sentinel -->
<div ref="sentinelRef" style="height: 1px; pointer-events: none;" />
<!-- hero -->
<!-- Hero sticky -->
<div
ref="heroRef"
class="health-hero"
:class="{ 'health-hero--stuck': heroStuck }"
class="sticky mx-3 md:mx-4 mb-4 z-20 overflow-hidden rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-5"
:style="{ top: 'var(--layout-sticky-top, 56px)' }"
>
<div class="health-hero__blobs" aria-hidden="true">
<div class="health-hero__blob health-hero__blob--1" />
<div class="health-hero__blob health-hero__blob--2" />
<div class="absolute inset-0 pointer-events-none overflow-hidden" aria-hidden="true">
<div class="absolute rounded-full blur-[70px] w-72 h-72 -top-16 -right-20 bg-indigo-400/10" />
<div class="absolute rounded-full blur-[70px] w-80 h-80 top-10 -left-24 bg-emerald-400/10" />
<div class="absolute rounded-full blur-[70px] w-72 h-72 -bottom-20 right-24 bg-fuchsia-400/10" />
</div>
<div class="health-hero__inner">
<!-- Título -->
<div class="health-hero__info min-w-0">
<div class="health-hero__title">Saúde das Assinaturas</div>
<div class="relative z-10 flex items-center justify-between gap-3 flex-wrap">
<div class="min-w-0">
<div class="text-[1rem] font-bold tracking-tight text-[var(--text-color)]">Saúde das Assinaturas</div>
<div class="text-[1rem] text-[var(--text-color-secondary)] mt-0.5">Terapeutas: divergências entre plano (esperado) e entitlements (atual). Clínicas: exceções comerciais (features liberadas manualmente fora do plano).</div>
</div>
<!-- Ações desktop ( 1200px) -->
<div class="health-hero__actions health-hero__actions--desktop">
<div class="hidden xl:flex items-center gap-2 shrink-0">
<Button
label="Recarregar"
icon="pi pi-refresh"
@@ -467,7 +456,7 @@ onBeforeUnmount(() => {
</div>
<!-- Ações mobile (< 1200px) -->
<div class="health-hero__actions--mobile">
<div class="flex xl:hidden shrink-0">
<Button
label="Ações"
icon="pi pi-ellipsis-v"
@@ -481,9 +470,9 @@ onBeforeUnmount(() => {
</div>
<!-- content -->
<div class="px-4 pb-4">
<div class="px-3 md:px-4 pb-8 flex flex-col gap-4">
<!-- busca -->
<div class="mb-4">
<div>
<FloatLabel variant="on" class="w-full">
<IconField class="w-full">
<InputIcon class="pi pi-search" />
@@ -505,7 +494,7 @@ onBeforeUnmount(() => {
<!-- Terapeutas (Personal) -->
<!-- ===================================================== -->
<TabPanel header="Terapeutas (Pessoal)">
<div class="surface-100 border-round p-3 mb-4">
<div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-3 mb-4">
<div class="flex flex-wrap gap-2 items-center justify-content-between">
<div class="flex gap-2 items-center flex-wrap">
<Tag :value="`Divergências: ${totalPersonal}`" severity="secondary" />
@@ -514,7 +503,7 @@ onBeforeUnmount(() => {
<Tag v-if="totalPersonalWithoutOwner > 0" :value="`Sem owner: ${totalPersonalWithoutOwner}`" severity="warn" />
</div>
<div class="text-color-secondary text-sm">
<div class="text-[1rem] text-[var(--text-color-secondary)]">
<span class="font-medium">Faltando</span>: o plano exige, mas não está ativo ·
<span class="font-medium">Inesperado</span>: está ativo sem constar no plano
</div>
@@ -545,9 +534,9 @@ onBeforeUnmount(() => {
<template #body="{ data }">
<div class="flex flex-col">
<span class="font-medium">{{ data.feature_key }}</span>
<small class="text-color-secondary">
<div class="text-[1rem] text-[var(--text-color-secondary)]">
{{ helpForMismatch(data.mismatch_type) || '—' }}
</small>
</div>
</div>
</template>
</Column>
@@ -588,12 +577,12 @@ onBeforeUnmount(() => {
<Divider class="my-5" />
<Message severity="info" class="mt-4">
<div class="text-sm line-height-3">
<p class="mb-0">
<div class="text-[1rem] line-height-3">
<div class="mb-0">
<span class="font-semibold">Dica:</span>
Se você alterar o plano e o acesso não refletir imediatamente, esta aba exibirá as divergências entre o plano ativo e os entitlements atuais.
A ação <span class="font-medium">Corrigir</span> reconstrói os entitlements do owner com base no plano vigente e elimina inconsistências.
</p>
</div>
</div>
</Message>
</TabPanel>
@@ -602,13 +591,13 @@ onBeforeUnmount(() => {
<!-- Clínicas (Tenant) -->
<!-- ===================================================== -->
<TabPanel header="Clínicas (Exceções)">
<div class="surface-100 border-round p-3 mb-4">
<div class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-3 mb-4">
<div class="flex flex-wrap gap-2 items-center justify-content-between">
<div class="flex gap-2 items-center flex-wrap">
<Tag :value="`Exceções ativas: ${totalClinic}`" severity="info" />
</div>
<div class="text-color-secondary text-sm">
<div class="text-[1rem] text-[var(--text-color-secondary)]">
Exceções comerciais: features liberadas manualmente fora do plano. Útil para testes, suporte e acordos.
</div>
</div>
@@ -627,7 +616,7 @@ onBeforeUnmount(() => {
<template #body="{ data }">
<div class="flex flex-col">
<span class="font-medium">{{ data.tenant_name || data.tenant_id }}</span>
<small class="text-color-secondary">{{ data.tenant_name ? data.tenant_id : '—' }}</small>
<div class="text-[1rem] text-[var(--text-color-secondary)]">{{ data.tenant_name ? data.tenant_id : '—' }}</div>
</div>
</template>
</Column>
@@ -642,9 +631,9 @@ onBeforeUnmount(() => {
<template #body="{ data }">
<div class="flex flex-col">
<span class="font-medium">{{ data.feature_key }}</span>
<small class="text-color-secondary">
<div class="text-[1rem] text-[var(--text-color-secondary)]">
{{ helpForException() }}
</small>
</div>
</div>
</template>
</Column>
@@ -684,83 +673,22 @@ onBeforeUnmount(() => {
<Divider class="my-5" />
<Message severity="info" class="mt-4">
<div class="text-sm line-height-3">
<p class="mb-2">
<div class="text-[1rem] line-height-3">
<div class="mb-2">
<span class="font-semibold">Observação:</span>
Exceção é uma escolha de negócio. Quando ativa, pode liberar acesso mesmo que o plano não permita.
Utilize <span class="font-medium">Remover exceção</span> quando a liberação deixar de fazer sentido.
</p>
</div>
<p class="mb-0">
<div class="mb-0">
<span class="font-semibold">Dica:</span>
Exceções comerciais liberam recursos fora do plano.
Se o acesso não refletir como esperado, verifique se existe uma exceção ativa para esta clínica.
A ação <span class="font-medium">Remover exceção</span> restaura o comportamento estritamente definido pelo plano.
</p>
</div>
</div>
</Message>
</TabPanel>
</TabView>
</div>
</template>
<style scoped>
/* Hero */
.health-hero {
position: sticky;
top: var(--layout-sticky-top, 56px);
z-index: 20;
overflow: hidden;
border-radius: 1.75rem;
border: 1px solid var(--surface-border);
background: var(--surface-card);
padding: 1.5rem;
margin: 1rem;
}
.health-hero--stuck {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.health-hero__blobs {
position: absolute; inset: 0; pointer-events: none; overflow: hidden;
}
.health-hero__blob {
position: absolute; border-radius: 50%; filter: blur(70px);
}
.health-hero__blob--1 { width: 20rem; height: 20rem; top: -5rem; right: -4rem; background: rgba(248,113,113,0.12); }
.health-hero__blob--2 { width: 18rem; height: 18rem; top: 1rem; left: -5rem; background: rgba(251,113,133,0.09); }
.health-hero__inner {
position: relative; z-index: 1;
display: flex; align-items: center; gap: 1.25rem; flex-wrap: wrap;
}
.health-hero__icon-wrap {
flex-shrink: 0;
width: 4rem; height: 4rem; border-radius: 1.125rem;
border: 2px solid var(--surface-border);
background: var(--surface-ground);
display: grid; place-items: center;
}
.health-hero__icon { font-size: 1.5rem; color: var(--text-color); }
.health-hero__info { flex: 1; min-width: 0; }
.health-hero__title {
font-size: 1.25rem; font-weight: 700; letter-spacing: -0.025em;
color: var(--text-color); line-height: 1.2;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.health-hero__sub {
font-size: 0.78rem; color: var(--text-color-secondary); margin-top: 4px; line-height: 1.5;
}
.health-hero__actions--desktop {
display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap;
}
.health-hero__actions--mobile { display: none; }
@media (max-width: 1199px) {
.health-hero__actions--desktop { display: none; }
.health-hero__actions--mobile { display: flex; }
}
</style>