+ Menu Hover no Layout Rail, Twilio, Sms, Email, Templates, LNovo Layout Configurações
This commit is contained in:
@@ -2326,10 +2326,10 @@ onMounted(async () => {
|
||||
<div class="absolute w-64 h-64 -top-16 -right-8 rounded-full blur-[60px] bg-indigo-500/10" />
|
||||
<div class="absolute w-72 h-72 top-0 -left-16 rounded-full blur-[60px] bg-emerald-400/[0.07]" />
|
||||
</div>
|
||||
<div class="relative z-[1] flex items-center gap-3">
|
||||
<div class="relative z-1 flex items-center gap-3">
|
||||
<!-- Brand -->
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<div class="grid place-items-center w-9 h-9 rounded-md flex-shrink-0 bg-indigo-500/10 text-indigo-500"><i class="pi pi-calendar text-base" /></div>
|
||||
<div class="flex items-center gap-2 shrink-0">
|
||||
<div class="grid place-items-center w-9 h-9 rounded-md shrink-0 bg-indigo-500/10 text-indigo-500"><i class="pi pi-calendar text-base" /></div>
|
||||
<div class="min-w-0 hidden lg:block">
|
||||
<div class="text-base font-bold tracking-tight text-[var(--text-color)]">Agenda</div>
|
||||
<div class="text-xs text-[var(--text-color-secondary)]">{{ subtitleText }}</div>
|
||||
@@ -2523,7 +2523,7 @@ onMounted(async () => {
|
||||
agPanelOpen = false;
|
||||
"
|
||||
>
|
||||
<div class="flex flex-col items-end min-w-[36px] flex-shrink-0">
|
||||
<div class="flex flex-col items-end min-w-[36px] shrink-0">
|
||||
<span class="text-xs font-bold text-[var(--text-color)]">{{ fmtHoraEvento(ev.inicio_em) }}</span>
|
||||
<span class="text-[0.65rem] text-[var(--text-color-secondary)]">{{ fmtDuracao(ev.inicio_em, ev.fim_em) }}</span>
|
||||
</div>
|
||||
@@ -2539,13 +2539,13 @@ onMounted(async () => {
|
||||
</div>
|
||||
<button
|
||||
v-if="ev.patient_id || ev.paciente_id"
|
||||
class="w-6 h-6 rounded-full flex items-center justify-center border-none bg-transparent text-[var(--text-color-secondary)] hover:bg-[var(--surface-border)] hover:text-[var(--primary-color,#6366f1)] transition-colors duration-100 cursor-pointer flex-shrink-0"
|
||||
class="w-6 h-6 rounded-full flex items-center justify-center border-none bg-transparent text-[var(--text-color-secondary)] hover:bg-[var(--surface-border)] hover:text-[var(--primary-color,#6366f1)] transition-colors duration-100 cursor-pointer shrink-0"
|
||||
title="Opções"
|
||||
@click.stop="openTodayEvMenu($event, ev)"
|
||||
>
|
||||
<i class="pi pi-ellipsis-v text-[0.7rem]" />
|
||||
</button>
|
||||
<i v-else class="text-xs text-[var(--text-color-secondary)] flex-shrink-0" :class="statusIcon(ev.status)" />
|
||||
<i v-else class="text-xs text-[var(--text-color-secondary)] shrink-0" :class="statusIcon(ev.status)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -2587,23 +2587,23 @@ onMounted(async () => {
|
||||
class="flex items-center gap-2.5 px-2.5 py-2 rounded-md border-none bg-transparent cursor-pointer w-full text-left transition-colors duration-100 hover:bg-[var(--surface-hover)]"
|
||||
@click="router.push('/therapist/patients')"
|
||||
>
|
||||
<div class="w-[30px] h-[30px] rounded-md grid place-items-center text-[0.8rem] flex-shrink-0 bg-indigo-500/10 text-indigo-500"><i class="pi pi-list" /></div>
|
||||
<div class="w-[30px] h-[30px] rounded-md grid place-items-center text-[0.8rem] shrink-0 bg-indigo-500/10 text-indigo-500"><i class="pi pi-list" /></div>
|
||||
<div class="flex-1 min-w-0 flex flex-col gap-px">
|
||||
<span class="text-[1rem] font-semibold text-[var(--text-color)] truncate">Lista de pacientes</span>
|
||||
<span class="text-[0.68rem] text-[var(--text-color-secondary)] truncate">Todos os cadastros ativos</span>
|
||||
</div>
|
||||
<i class="pi pi-chevron-right text-[0.6rem] text-[var(--text-color-secondary)] opacity-40 flex-shrink-0" />
|
||||
<i class="pi pi-chevron-right text-[0.6rem] text-[var(--text-color-secondary)] opacity-40 shrink-0" />
|
||||
</button>
|
||||
<button
|
||||
class="flex items-center gap-2.5 px-2.5 py-2 rounded-md border-none bg-transparent cursor-pointer w-full text-left transition-colors duration-100 hover:bg-[var(--surface-hover)]"
|
||||
@click="router.push('/therapist/patients/cadastro')"
|
||||
>
|
||||
<div class="w-[30px] h-[30px] rounded-md grid place-items-center text-[0.8rem] flex-shrink-0 bg-green-500/10 text-green-600"><i class="pi pi-user-plus" /></div>
|
||||
<div class="w-[30px] h-[30px] rounded-md grid place-items-center text-[0.8rem] shrink-0 bg-green-500/10 text-green-600"><i class="pi pi-user-plus" /></div>
|
||||
<div class="flex-1 min-w-0 flex flex-col gap-px">
|
||||
<span class="text-[1rem] font-semibold text-[var(--text-color)] truncate">Novo paciente</span>
|
||||
<span class="text-[0.68rem] text-[var(--text-color-secondary)] truncate">Cadastrar manualmente</span>
|
||||
</div>
|
||||
<i class="pi pi-chevron-right text-[0.6rem] text-[var(--text-color-secondary)] opacity-40 flex-shrink-0" />
|
||||
<i class="pi pi-chevron-right text-[0.6rem] text-[var(--text-color-secondary)] opacity-40 shrink-0" />
|
||||
</button>
|
||||
<!-- Link de cadastro externo -->
|
||||
<div v-if="cadastroExternoLink" class="flex flex-col gap-1 px-2.5 py-2 rounded-md bg-[var(--surface-ground)] border border-[var(--surface-border)] mt-1">
|
||||
@@ -2616,7 +2616,7 @@ onMounted(async () => {
|
||||
@click="$event.target.select()"
|
||||
/>
|
||||
<button
|
||||
class="grid place-items-center w-[26px] h-[26px] rounded border border-[var(--surface-border)] bg-[var(--surface-card)] text-[var(--text-color-secondary)] cursor-pointer text-xs flex-shrink-0 transition-colors duration-100 hover:bg-[var(--primary-color,#6366f1)] hover:text-white hover:border-[var(--primary-color)]"
|
||||
class="grid place-items-center w-[26px] h-[26px] rounded border border-[var(--surface-border)] bg-[var(--surface-card)] text-[var(--text-color-secondary)] cursor-pointer text-xs shrink-0 transition-colors duration-100 hover:bg-[var(--primary-color,#6366f1)] hover:text-white hover:border-[var(--primary-color)]"
|
||||
@click="copyLink(cadastroExternoLink)"
|
||||
v-tooltip.top="'Copiar link'"
|
||||
>
|
||||
@@ -2637,12 +2637,12 @@ onMounted(async () => {
|
||||
class="flex items-center gap-2.5 px-2.5 py-2 rounded-md border-none bg-transparent cursor-pointer w-full text-left transition-colors duration-100 hover:bg-[var(--surface-hover)]"
|
||||
@click="router.push('/therapist/agendador/solicitacoes')"
|
||||
>
|
||||
<div class="w-[30px] h-[30px] rounded-md grid place-items-center text-[0.8rem] flex-shrink-0 bg-indigo-500/10 text-indigo-500"><i class="pi pi-inbox" /></div>
|
||||
<div class="w-[30px] h-[30px] rounded-md grid place-items-center text-[0.8rem] shrink-0 bg-indigo-500/10 text-indigo-500"><i class="pi pi-inbox" /></div>
|
||||
<div class="flex-1 min-w-0 flex flex-col gap-px">
|
||||
<span class="text-[1rem] font-semibold text-[var(--text-color)] truncate">Solicitações</span>
|
||||
<span class="text-[0.68rem] text-[var(--text-color-secondary)] truncate">Pedidos de agendamento</span>
|
||||
</div>
|
||||
<i class="pi pi-chevron-right text-[0.6rem] text-[var(--text-color-secondary)] opacity-40 flex-shrink-0" />
|
||||
<i class="pi pi-chevron-right text-[0.6rem] text-[var(--text-color-secondary)] opacity-40 shrink-0" />
|
||||
</button>
|
||||
<!-- Link do agendador -->
|
||||
<div v-if="agendadorLink" class="flex flex-col gap-1 px-2.5 py-2 rounded-md bg-[var(--surface-ground)] border border-[var(--surface-border)] mt-1">
|
||||
@@ -2650,7 +2650,7 @@ onMounted(async () => {
|
||||
<div class="flex items-center gap-1.5">
|
||||
<input readonly :value="agendadorLink" class="flex-1 min-w-0 text-[0.72rem] text-[var(--primary-color,#6366f1)] bg-transparent border-none outline-none truncate cursor-text font-mono" @click="$event.target.select()" />
|
||||
<button
|
||||
class="grid place-items-center w-[26px] h-[26px] rounded border border-[var(--surface-border)] bg-[var(--surface-card)] text-[var(--text-color-secondary)] cursor-pointer text-xs flex-shrink-0 transition-colors duration-100 hover:bg-[var(--primary-color,#6366f1)] hover:text-white hover:border-[var(--primary-color)]"
|
||||
class="grid place-items-center w-[26px] h-[26px] rounded border border-[var(--surface-border)] bg-[var(--surface-card)] text-[var(--text-color-secondary)] cursor-pointer text-xs shrink-0 transition-colors duration-100 hover:bg-[var(--primary-color,#6366f1)] hover:text-white hover:border-[var(--primary-color)]"
|
||||
@click="copyLink(agendadorLink)"
|
||||
v-tooltip.top="'Copiar link'"
|
||||
>
|
||||
@@ -2714,7 +2714,7 @@ onMounted(async () => {
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<i class="pi pi-calendar-clock text-[var(--primary-color,#6366f1)]" />
|
||||
<span class="truncate">Calendário · Sessões de hoje</span>
|
||||
<span v-if="todayEvents.length" class="inline-flex items-center justify-center min-w-[18px] h-[18px] px-1 rounded-full bg-[var(--primary-color,#6366f1)] text-white text-[0.68rem] font-bold flex-shrink-0">{{
|
||||
<span v-if="todayEvents.length" class="inline-flex items-center justify-center min-w-[18px] h-[18px] px-1 rounded-full bg-[var(--primary-color,#6366f1)] text-white text-[0.68rem] font-bold shrink-0">{{
|
||||
todayEvents.length
|
||||
}}</span>
|
||||
</div>
|
||||
@@ -2804,7 +2804,7 @@ onMounted(async () => {
|
||||
}"
|
||||
@click="onEventRowClick(ev)"
|
||||
>
|
||||
<div class="flex flex-col items-end min-w-[36px] flex-shrink-0">
|
||||
<div class="flex flex-col items-end min-w-[36px] shrink-0">
|
||||
<span class="text-xs font-bold text-[var(--text-color)]">{{ fmtHoraEvento(ev.inicio_em) }}</span>
|
||||
<span class="text-[0.65rem] text-[var(--text-color-secondary)]">{{ fmtDuracao(ev.inicio_em, ev.fim_em) }}</span>
|
||||
</div>
|
||||
@@ -2820,13 +2820,13 @@ onMounted(async () => {
|
||||
</div>
|
||||
<button
|
||||
v-if="ev.patient_id || ev.paciente_id"
|
||||
class="w-6 h-6 rounded-full flex items-center justify-center border-none bg-transparent text-[var(--text-color-secondary)] hover:bg-[var(--surface-border)] hover:text-[var(--primary-color,#6366f1)] transition-colors duration-100 cursor-pointer flex-shrink-0"
|
||||
class="w-6 h-6 rounded-full flex items-center justify-center border-none bg-transparent text-[var(--text-color-secondary)] hover:bg-[var(--surface-border)] hover:text-[var(--primary-color,#6366f1)] transition-colors duration-100 cursor-pointer shrink-0"
|
||||
title="Opções"
|
||||
@click.stop="openTodayEvMenu($event, ev)"
|
||||
>
|
||||
<i class="pi pi-ellipsis-v text-[0.7rem]" />
|
||||
</button>
|
||||
<i v-else class="text-xs text-[var(--text-color-secondary)] flex-shrink-0" :class="statusIcon(ev.status)" />
|
||||
<i v-else class="text-xs text-[var(--text-color-secondary)] shrink-0" :class="statusIcon(ev.status)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -2860,23 +2860,23 @@ onMounted(async () => {
|
||||
class="flex items-center gap-2.5 px-2.5 py-2 rounded-md border-none bg-transparent cursor-pointer w-full text-left transition-colors duration-100 hover:bg-[var(--surface-hover)]"
|
||||
@click="router.push('/therapist/patients')"
|
||||
>
|
||||
<div class="w-[30px] h-[30px] rounded-md grid place-items-center text-[0.8rem] flex-shrink-0 bg-indigo-500/10 text-indigo-500"><i class="pi pi-list" /></div>
|
||||
<div class="w-[30px] h-[30px] rounded-md grid place-items-center text-[0.8rem] shrink-0 bg-indigo-500/10 text-indigo-500"><i class="pi pi-list" /></div>
|
||||
<div class="flex-1 min-w-0 flex flex-col gap-px">
|
||||
<span class="text-[1rem] font-semibold text-[var(--text-color)] truncate">Lista de pacientes</span>
|
||||
<span class="text-[0.68rem] text-[var(--text-color-secondary)] truncate">Todos os cadastros ativos</span>
|
||||
</div>
|
||||
<i class="pi pi-chevron-right text-[0.6rem] text-[var(--text-color-secondary)] opacity-40 flex-shrink-0" />
|
||||
<i class="pi pi-chevron-right text-[0.6rem] text-[var(--text-color-secondary)] opacity-40 shrink-0" />
|
||||
</button>
|
||||
<button
|
||||
class="flex items-center gap-2.5 px-2.5 py-2 rounded-md border-none bg-transparent cursor-pointer w-full text-left transition-colors duration-100 hover:bg-[var(--surface-hover)]"
|
||||
@click="router.push('/therapist/patients/cadastro')"
|
||||
>
|
||||
<div class="w-[30px] h-[30px] rounded-md grid place-items-center text-[0.8rem] flex-shrink-0 bg-green-500/10 text-green-600"><i class="pi pi-user-plus" /></div>
|
||||
<div class="w-[30px] h-[30px] rounded-md grid place-items-center text-[0.8rem] shrink-0 bg-green-500/10 text-green-600"><i class="pi pi-user-plus" /></div>
|
||||
<div class="flex-1 min-w-0 flex flex-col gap-px">
|
||||
<span class="text-[1rem] font-semibold text-[var(--text-color)] truncate">Novo paciente</span>
|
||||
<span class="text-[0.68rem] text-[var(--text-color-secondary)] truncate">Cadastrar manualmente</span>
|
||||
</div>
|
||||
<i class="pi pi-chevron-right text-[0.6rem] text-[var(--text-color-secondary)] opacity-40 flex-shrink-0" />
|
||||
<i class="pi pi-chevron-right text-[0.6rem] text-[var(--text-color-secondary)] opacity-40 shrink-0" />
|
||||
</button>
|
||||
<!-- Link de cadastro externo -->
|
||||
<div v-if="cadastroExternoLink" class="flex flex-col gap-1 px-2.5 py-2 rounded-md bg-[var(--surface-ground)] border border-[var(--surface-border)] mt-1">
|
||||
@@ -2889,7 +2889,7 @@ onMounted(async () => {
|
||||
@click="$event.target.select()"
|
||||
/>
|
||||
<button
|
||||
class="grid place-items-center w-[26px] h-[26px] rounded border border-[var(--surface-border)] bg-[var(--surface-card)] text-[var(--text-color-secondary)] cursor-pointer text-xs flex-shrink-0 transition-colors duration-100 hover:bg-[var(--primary-color,#6366f1)] hover:text-white hover:border-[var(--primary-color)]"
|
||||
class="grid place-items-center w-[26px] h-[26px] rounded border border-[var(--surface-border)] bg-[var(--surface-card)] text-[var(--text-color-secondary)] cursor-pointer text-xs shrink-0 transition-colors duration-100 hover:bg-[var(--primary-color,#6366f1)] hover:text-white hover:border-[var(--primary-color)]"
|
||||
@click="copyLink(cadastroExternoLink)"
|
||||
v-tooltip.top="'Copiar link'"
|
||||
>
|
||||
@@ -2910,12 +2910,12 @@ onMounted(async () => {
|
||||
class="flex items-center gap-2.5 px-2.5 py-2 rounded-md border-none bg-transparent cursor-pointer w-full text-left transition-colors duration-100 hover:bg-[var(--surface-hover)]"
|
||||
@click="router.push('/therapist/agendador/solicitacoes')"
|
||||
>
|
||||
<div class="w-[30px] h-[30px] rounded-md grid place-items-center text-[0.8rem] flex-shrink-0 bg-indigo-500/10 text-indigo-500"><i class="pi pi-inbox" /></div>
|
||||
<div class="w-[30px] h-[30px] rounded-md grid place-items-center text-[0.8rem] shrink-0 bg-indigo-500/10 text-indigo-500"><i class="pi pi-inbox" /></div>
|
||||
<div class="flex-1 min-w-0 flex flex-col gap-px">
|
||||
<span class="text-[1rem] font-semibold text-[var(--text-color)] truncate">Solicitações</span>
|
||||
<span class="text-[0.68rem] text-[var(--text-color-secondary)] truncate">Pedidos de agendamento</span>
|
||||
</div>
|
||||
<i class="pi pi-chevron-right text-[0.6rem] text-[var(--text-color-secondary)] opacity-40 flex-shrink-0" />
|
||||
<i class="pi pi-chevron-right text-[0.6rem] text-[var(--text-color-secondary)] opacity-40 shrink-0" />
|
||||
</button>
|
||||
<!-- Link do agendador -->
|
||||
<div v-if="agendadorLink" class="flex flex-col gap-1 px-2.5 py-2 rounded-md bg-[var(--surface-ground)] border border-[var(--surface-border)] mt-1">
|
||||
@@ -2923,7 +2923,7 @@ onMounted(async () => {
|
||||
<div class="flex items-center gap-1.5">
|
||||
<input readonly :value="agendadorLink" class="flex-1 min-w-0 text-[0.72rem] text-[var(--primary-color,#6366f1)] bg-transparent border-none outline-none truncate cursor-text font-mono" @click="$event.target.select()" />
|
||||
<button
|
||||
class="grid place-items-center w-[26px] h-[26px] rounded border border-[var(--surface-border)] bg-[var(--surface-card)] text-[var(--text-color-secondary)] cursor-pointer text-xs flex-shrink-0 transition-colors duration-100 hover:bg-[var(--primary-color,#6366f1)] hover:text-white hover:border-[var(--primary-color)]"
|
||||
class="grid place-items-center w-[26px] h-[26px] rounded border border-[var(--surface-border)] bg-[var(--surface-card)] text-[var(--text-color-secondary)] cursor-pointer text-xs shrink-0 transition-colors duration-100 hover:bg-[var(--primary-color,#6366f1)] hover:text-white hover:border-[var(--primary-color)]"
|
||||
@click="copyLink(agendadorLink)"
|
||||
v-tooltip.top="'Copiar link'"
|
||||
>
|
||||
@@ -3144,11 +3144,11 @@ onMounted(async () => {
|
||||
<!-- Body: split panel -->
|
||||
<div v-if="desativadoSelected" class="flex flex-col lg:flex-row flex-1 min-h-0 overflow-hidden">
|
||||
<!-- Sidebar esquerda: lista de sessões -->
|
||||
<div class="w-full lg:w-[340px] lg:flex-shrink-0 flex flex-col border-b lg:border-b-0 lg:border-r border-[var(--surface-border)]">
|
||||
<div class="w-full lg:w-[340px] lg:shrink-0 flex flex-col border-b lg:border-b-0 lg:border-r border-[var(--surface-border)]">
|
||||
<!-- Patient info -->
|
||||
<div class="px-4 py-3 border-b border-[var(--surface-border)] bg-orange-500/5">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-10 h-10 rounded-full flex items-center justify-center text-white font-bold text-sm flex-shrink-0" style="background: #f97316">
|
||||
<div class="w-10 h-10 rounded-full flex items-center justify-center text-white font-bold text-sm shrink-0" style="background: #f97316">
|
||||
{{ (desativadoSelected.nome_completo || '?').charAt(0).toUpperCase() }}
|
||||
</div>
|
||||
<div class="min-w-0">
|
||||
@@ -3157,7 +3157,7 @@ onMounted(async () => {
|
||||
{{ desativadoSelected.status === 'Arquivado' ? 'arquivado' : 'desativado' }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="ml-auto text-right flex-shrink-0">
|
||||
<div class="ml-auto text-right shrink-0">
|
||||
<div class="text-lg font-bold text-orange-500">{{ desativadoSelected.sessions.length }}</div>
|
||||
<div class="text-[0.65rem] text-[var(--text-color-secondary)]">sessão(ões)</div>
|
||||
</div>
|
||||
|
||||
@@ -360,12 +360,12 @@ const emptySub = computed(() => {
|
||||
<div class="absolute w-56 h-56 -bottom-8 right-1/4 rounded-full blur-[55px] bg-orange-400/[0.07]" />
|
||||
</div>
|
||||
|
||||
<div class="relative z-[1] flex flex-col gap-2.5">
|
||||
<div class="relative z-1 flex flex-col gap-2.5">
|
||||
<!-- Linha 1: brand + busca + refresh -->
|
||||
<div class="flex items-center gap-3 flex-wrap">
|
||||
<!-- Brand -->
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<div class="grid place-items-center w-9 h-9 rounded-md flex-shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<div class="flex items-center gap-2 shrink-0">
|
||||
<div class="grid place-items-center w-9 h-9 rounded-md shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<i class="pi pi-inbox text-base" />
|
||||
</div>
|
||||
<div class="min-w-0 hidden sm:block">
|
||||
@@ -386,7 +386,7 @@ const emptySub = computed(() => {
|
||||
</div>
|
||||
|
||||
<!-- Refresh -->
|
||||
<Button icon="pi pi-refresh" severity="secondary" outlined class="h-9 w-9 rounded-full flex-shrink-0" :loading="loading" title="Atualizar" @click="load" />
|
||||
<Button icon="pi pi-refresh" severity="secondary" outlined class="h-9 w-9 rounded-full shrink-0" :loading="loading" title="Atualizar" @click="load" />
|
||||
</div>
|
||||
|
||||
<!-- Linha 2: chips de status -->
|
||||
@@ -425,7 +425,7 @@ const emptySub = computed(() => {
|
||||
@click="filtroStatus = 'autorizado'"
|
||||
>
|
||||
<!-- Ícone pulsante -->
|
||||
<div class="relative flex-shrink-0">
|
||||
<div class="relative shrink-0">
|
||||
<div class="grid place-items-center w-8 h-8 rounded-md bg-amber-400/20 text-amber-600">
|
||||
<i class="pi pi-calendar-plus text-[0.95rem]" />
|
||||
</div>
|
||||
@@ -444,7 +444,7 @@ const emptySub = computed(() => {
|
||||
</div>
|
||||
|
||||
<!-- Badge + seta -->
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<div class="flex items-center gap-2 shrink-0">
|
||||
<span class="inline-flex items-center justify-center min-w-[22px] h-[22px] px-1.5 rounded-full bg-amber-500 text-white text-[1rem] font-bold">
|
||||
{{ totalAutorizados }}
|
||||
</span>
|
||||
@@ -460,7 +460,7 @@ const emptySub = computed(() => {
|
||||
<!-- Loading skeleton -->
|
||||
<div v-if="loading" class="flex flex-col gap-3">
|
||||
<div v-for="n in 4" :key="n" class="flex items-center gap-4 p-4 rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)]">
|
||||
<div class="w-10 h-10 rounded-full flex-shrink-0 bg-[var(--surface-border,#e2e8f0)] animate-pulse" />
|
||||
<div class="w-10 h-10 rounded-full shrink-0 bg-[var(--surface-border,#e2e8f0)] animate-pulse" />
|
||||
<div class="flex flex-col gap-2 flex-1">
|
||||
<div class="h-3.5 w-3/5 rounded-md bg-[var(--surface-border,#e2e8f0)] animate-pulse" />
|
||||
<div class="h-2.5 w-2/5 rounded-md bg-[var(--surface-border,#e2e8f0)] animate-pulse" />
|
||||
@@ -512,7 +512,7 @@ const emptySub = computed(() => {
|
||||
<!-- Linha principal clicável -->
|
||||
<div class="flex items-center gap-3 px-4 py-3.5 cursor-pointer hover:bg-[var(--surface-ground,#f8fafc)] transition-colors duration-100" @click="toggleExpand(s.id)">
|
||||
<!-- Avatar inicial -->
|
||||
<div class="grid place-items-center w-10 h-10 rounded-full flex-shrink-0 font-bold text-[0.95rem] bg-indigo-500/10 text-indigo-600">
|
||||
<div class="grid place-items-center w-10 h-10 rounded-full shrink-0 font-bold text-[0.95rem] bg-indigo-500/10 text-indigo-600">
|
||||
{{ initials(s) }}
|
||||
</div>
|
||||
|
||||
@@ -532,24 +532,24 @@ const emptySub = computed(() => {
|
||||
</div>
|
||||
|
||||
<!-- Ações rápidas — pendente -->
|
||||
<div v-if="s.status === 'pendente'" class="hidden sm:flex items-center gap-1.5 flex-shrink-0" @click.stop>
|
||||
<div v-if="s.status === 'pendente'" class="hidden sm:flex items-center gap-1.5 shrink-0" @click.stop>
|
||||
<Button label="Aprovar" icon="pi pi-check" size="small" severity="success" class="rounded-full" :loading="aprovando === s.id" @click="aprovar(s)" />
|
||||
<Button label="Recusar" icon="pi pi-times" size="small" severity="danger" outlined class="rounded-full" @click="abrirRecusa(s)" />
|
||||
<Button label="Converter" icon="pi pi-calendar-plus" size="small" severity="info" outlined class="rounded-full" :loading="convertendoId === s.id" @click="converterEmSessao(s)" />
|
||||
</div>
|
||||
|
||||
<!-- Ações — autorizado -->
|
||||
<div v-else-if="s.status === 'autorizado'" class="hidden sm:flex items-center flex-shrink-0" @click.stop>
|
||||
<div v-else-if="s.status === 'autorizado'" class="hidden sm:flex items-center shrink-0" @click.stop>
|
||||
<Button label="Converter em sessão" icon="pi pi-calendar-plus" size="small" severity="info" outlined class="rounded-full" :loading="convertendoId === s.id" @click="converterEmSessao(s)" />
|
||||
</div>
|
||||
|
||||
<!-- Ações — convertido -->
|
||||
<div v-else-if="s.status === 'convertido'" class="hidden sm:flex items-center flex-shrink-0" @click.stop>
|
||||
<div v-else-if="s.status === 'convertido'" class="hidden sm:flex items-center shrink-0" @click.stop>
|
||||
<Button label="Ver na agenda" icon="pi pi-calendar" size="small" severity="secondary" outlined class="rounded-full" @click="irParaAgenda(s)" />
|
||||
</div>
|
||||
|
||||
<!-- Chevron -->
|
||||
<i class="pi flex-shrink-0 text-[1rem] text-[var(--text-color-secondary)] transition-transform duration-200" :class="expandedId === s.id ? 'pi-chevron-up' : 'pi-chevron-down'" />
|
||||
<i class="pi shrink-0 text-[1rem] text-[var(--text-color-secondary)] transition-transform duration-200" :class="expandedId === s.id ? 'pi-chevron-up' : 'pi-chevron-down'" />
|
||||
</div>
|
||||
|
||||
<!-- Ações mobile (visíveis só quando expandido, em telas pequenas) -->
|
||||
|
||||
@@ -382,25 +382,25 @@ function isRecent(row) {
|
||||
═══════════════════════════════════════ -->
|
||||
<div
|
||||
ref="headerEl"
|
||||
class="sticky mx-3 md:mx-4 mb-3 z-20 overflow-hidden rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)] px-3 py-2.5 transition-[border-radius] duration-200"
|
||||
class="sticky mx-3 md:mx-4 mb-3 z-20 overflow-hidden rounded-md border border-(--surface-border,#e2e8f0) bg-(--surface-card,#fff) px-3 py-2.5 transition-[border-radius] duration-200"
|
||||
:class="{ 'rounded-tl-none rounded-tr-none': headerStuck }"
|
||||
:style="{ top: 'var(--layout-sticky-top, 56px)' }"
|
||||
>
|
||||
<!-- Blobs decorativos -->
|
||||
<div class="absolute inset-0 pointer-events-none overflow-hidden" aria-hidden="true">
|
||||
<div class="absolute w-64 h-64 -top-16 -right-8 rounded-full blur-[60px] bg-emerald-400/10" />
|
||||
<div class="absolute w-72 h-72 top-0 -left-16 rounded-full blur-[60px] bg-indigo-500/[0.09]" />
|
||||
<div class="absolute w-72 h-72 top-0 -left-16 rounded-full blur-[60px] bg-indigo-500/9" />
|
||||
</div>
|
||||
|
||||
<div class="relative z-[1] flex items-center gap-3">
|
||||
<div class="relative z-1 flex items-center gap-3">
|
||||
<!-- Brand -->
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<div class="grid place-items-center w-9 h-9 rounded-md flex-shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<div class="flex items-center gap-2 shrink-0">
|
||||
<div class="grid place-items-center w-9 h-9 rounded-md shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<i class="pi pi-list text-base" />
|
||||
</div>
|
||||
<div class="min-w-0 hidden lg:block">
|
||||
<div class="text-[1rem] font-bold tracking-tight text-[var(--text-color)]">Compromissos</div>
|
||||
<div class="text-[0.75rem] text-[var(--text-color-secondary)]">Configure tipos de compromissos e campos adicionais</div>
|
||||
<div class="text-[1rem] font-bold tracking-tight text-(--text-color)">Compromissos</div>
|
||||
<div class="text-[0.75rem] text-(--text-color-secondary)">Configure tipos de compromissos e campos adicionais</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -419,13 +419,13 @@ function isRecent(row) {
|
||||
</div>
|
||||
|
||||
<!-- Ações desktop -->
|
||||
<div class="hidden xl:flex items-center gap-1 flex-shrink-0">
|
||||
<div class="hidden xl:flex items-center gap-1 shrink-0">
|
||||
<Button label="Novo" icon="pi pi-plus" class="rounded-full" :disabled="loading" @click="openCreate()" />
|
||||
<Button icon="pi pi-refresh" severity="secondary" outlined class="h-9 w-9 rounded-full" :loading="loading" @click="fetchAll()" />
|
||||
</div>
|
||||
|
||||
<!-- Mobile -->
|
||||
<div class="flex xl:hidden items-center gap-1 flex-shrink-0 ml-auto">
|
||||
<div class="flex xl:hidden items-center gap-1 shrink-0 ml-auto">
|
||||
<Button icon="pi pi-search" severity="secondary" outlined class="h-9 w-9 rounded-full" @click="searchDlgOpen = true" />
|
||||
<Button icon="pi pi-plus" class="h-9 w-9 rounded-full" @click="openCreate()" />
|
||||
<Button label="Ações" icon="pi pi-ellipsis-v" severity="secondary" size="small" class="rounded-full" @click="(e) => mobileMenuRef.toggle(e)" />
|
||||
@@ -506,7 +506,7 @@ function isRecent(row) {
|
||||
<Column field="name" header="Nome" sortable style="min-width: 14rem">
|
||||
<template #body="{ data }">
|
||||
<div class="flex items-center gap-2">
|
||||
<div v-if="data.bg_color" class="w-3 h-3 rounded-full flex-shrink-0" :style="{ background: `#${data.bg_color}` }" />
|
||||
<div v-if="data.bg_color" class="w-3 h-3 rounded-full shrink-0" :style="{ background: `#${data.bg_color}` }" />
|
||||
<span class="font-semibold text-sm">{{ data.name }}</span>
|
||||
<Tag v-if="data.is_native" value="Nativo" severity="info" class="text-xs" />
|
||||
</div>
|
||||
@@ -561,11 +561,11 @@ function isRecent(row) {
|
||||
<!-- fim coluna principal -->
|
||||
|
||||
<!-- ── PAINEL LATERAL: tipos de compromisso ─────────── -->
|
||||
<div class="w-full xl:w-[272px] xl:flex-shrink-0">
|
||||
<div class="w-full xl:w-[272px] xl:shrink-0">
|
||||
<div class="rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)] overflow-hidden">
|
||||
<!-- Header do painel -->
|
||||
<div class="flex items-center gap-2.5 px-3.5 pt-3 pb-2.5 border-b border-[var(--surface-border,#f1f5f9)]">
|
||||
<div class="w-8 h-8 rounded-md flex items-center justify-center flex-shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<div class="w-8 h-8 rounded-md flex items-center justify-center shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<i class="pi pi-chart-bar text-[0.9rem]" />
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
@@ -596,14 +596,14 @@ function isRecent(row) {
|
||||
@click="openStatsInfo(c)"
|
||||
>
|
||||
<!-- Dot cor -->
|
||||
<div class="w-2.5 h-2.5 rounded-full flex-shrink-0" :style="c.bg_color ? { background: `#${c.bg_color}` } : { background: 'var(--surface-border)' }" />
|
||||
<div class="w-2.5 h-2.5 rounded-full shrink-0" :style="c.bg_color ? { background: `#${c.bg_color}` } : { background: 'var(--surface-border)' }" />
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="font-semibold text-[0.8rem] truncate text-[var(--text-color)]">{{ c.name }}</div>
|
||||
<div class="text-[0.72rem] text-[var(--text-color-secondary)]">
|
||||
{{ formatMinutes(getTotalMinutes(c.id)) }}
|
||||
</div>
|
||||
</div>
|
||||
<i class="pi pi-chevron-right text-[0.6rem] text-[var(--text-color-secondary)] opacity-30 group-hover:opacity-100 group-hover:text-[var(--primary-color,#6366f1)] transition-all duration-150 flex-shrink-0" />
|
||||
<i class="pi pi-chevron-right text-[0.6rem] text-[var(--text-color-secondary)] opacity-30 group-hover:opacity-100 group-hover:text-[var(--primary-color,#6366f1)] transition-all duration-150 shrink-0" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -208,9 +208,9 @@ onMounted(async () => {
|
||||
</div>
|
||||
|
||||
<!-- Linha 1: icon + título + botão -->
|
||||
<div class="relative z-[1] flex items-center gap-3">
|
||||
<div class="relative z-1 flex items-center gap-3">
|
||||
<div class="flex items-center gap-2.5 flex-1 min-w-0">
|
||||
<div class="cfg-subheader__icon grid place-items-center w-10 h-10 rounded-md flex-shrink-0" style="background: color-mix(in srgb, #10b981 15%, transparent); color: #059669">
|
||||
<div class="cfg-subheader__icon grid place-items-center w-10 h-10 rounded-md shrink-0" style="background: color-mix(in srgb, #10b981 15%, transparent); color: #059669">
|
||||
<i class="pi pi-wallet text-lg" />
|
||||
</div>
|
||||
<div class="min-w-0">
|
||||
@@ -218,13 +218,13 @@ onMounted(async () => {
|
||||
<div class="text-[0.78rem] text-[var(--text-color-secondary)] mt-0.5">Resumo e visão geral do período</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<div class="flex items-center gap-2 shrink-0">
|
||||
<Button label="Ver lançamentos" icon="pi pi-list" severity="secondary" outlined class="rounded-full hidden sm:flex" @click="goToLancamentos" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Linha 2: quick stats -->
|
||||
<div class="relative z-[1] mt-2.5">
|
||||
<div class="relative z-1 mt-2.5">
|
||||
<template v-if="summaryLoading">
|
||||
<div class="grid grid-cols-2 lg:grid-cols-4 gap-2.5">
|
||||
<div v-for="n in 4" :key="n" class="flex flex-col gap-1.5 px-4 py-2.5 rounded-md border border-[var(--surface-border)]">
|
||||
@@ -249,7 +249,7 @@ onMounted(async () => {
|
||||
<div class="flex flex-col gap-0.5 px-4 py-2.5 rounded-md border border-amber-500/25 bg-amber-500/5">
|
||||
<div class="text-[1.35rem] font-bold leading-none text-amber-500">{{ fmtBRL(totalPendente) }}</div>
|
||||
<div class="flex items-center gap-1.5 text-[0.7rem] text-amber-600/80 font-semibold">
|
||||
<span class="h-1.5 w-1.5 rounded-full bg-amber-400 animate-pulse flex-shrink-0" />
|
||||
<span class="h-1.5 w-1.5 rounded-full bg-amber-400 animate-pulse shrink-0" />
|
||||
Pendente
|
||||
</div>
|
||||
</div>
|
||||
@@ -281,7 +281,7 @@ onMounted(async () => {
|
||||
═══════════════════════════════════════ -->
|
||||
<section class="dash-card rounded-md">
|
||||
<div class="dash-card__head gap-2.5 p-2.5">
|
||||
<i class="pi pi-chart-bar cfg-subheader__icon w-10 h-10 rounded-md flex-shrink-0" />
|
||||
<i class="pi pi-chart-bar cfg-subheader__icon w-10 h-10 rounded-md shrink-0" />
|
||||
<div>
|
||||
<div class="font-bold tracking-tight text-[var(--text-color-secondary)]">Receita × Despesa</div>
|
||||
<div class="dash-card__sub">Comparativo dos últimos 6 meses</div>
|
||||
@@ -303,7 +303,7 @@ onMounted(async () => {
|
||||
═══════════════════════════════════════ -->
|
||||
<section class="dash-card rounded-md">
|
||||
<div class="dash-card__head gap-2.5 p-2.5">
|
||||
<i class="pi pi-calendar cfg-subheader__icon w-10 h-10 rounded-md flex-shrink-0" />
|
||||
<i class="pi pi-calendar cfg-subheader__icon w-10 h-10 rounded-md shrink-0" />
|
||||
<div>
|
||||
<div class="font-bold tracking-tight text-[var(--text-color-secondary)]">Projeção de Caixa</div>
|
||||
<div class="dash-card__sub">Cobranças em aberto — próximos 6 meses</div>
|
||||
@@ -320,7 +320,7 @@ onMounted(async () => {
|
||||
|
||||
<div v-else class="flex flex-col gap-1.5 pt-1">
|
||||
<div v-for="row in cashflowRows" :key="row.mes_label" class="flex items-center gap-3 px-3 py-2.5 rounded-md bg-[var(--surface-ground,#f8fafc)] hover:bg-[var(--surface-hover,#f1f5f9)] transition-colors duration-100">
|
||||
<span class="font-bold text-[0.8rem] uppercase tracking-wide text-[var(--text-color)] min-w-[3.5rem] flex-shrink-0">{{ row.mes_label }}</span>
|
||||
<span class="font-bold text-[0.8rem] uppercase tracking-wide text-[var(--text-color)] min-w-[3.5rem] shrink-0">{{ row.mes_label }}</span>
|
||||
<div class="flex items-center gap-2 flex-1 flex-wrap text-[0.8rem]">
|
||||
<span class="flex items-center gap-1 text-emerald-600 font-semibold">
|
||||
<i class="pi pi-arrow-up-right text-xs" />
|
||||
@@ -334,7 +334,7 @@ onMounted(async () => {
|
||||
<span class="text-[var(--text-color-secondary)] opacity-30">·</span>
|
||||
<span class="font-bold" :class="Number(row.saldo_projetado) >= 0 ? 'text-emerald-600' : 'text-red-500'"> saldo {{ fmtBRL(row.saldo_projetado) }} </span>
|
||||
</div>
|
||||
<Tag :value="row.count_registros + ' cobranças'" severity="secondary" class="ml-auto text-xs flex-shrink-0" />
|
||||
<Tag :value="row.count_registros + ' cobranças'" severity="secondary" class="ml-auto text-xs shrink-0" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -345,12 +345,12 @@ onMounted(async () => {
|
||||
═══════════════════════════════════════ -->
|
||||
<section class="dash-card rounded-md shadow-[0_0_0_3px_color-mix(in_srgb,var(--primary-color)_7%,transparent)]">
|
||||
<div class="dash-card__head gap-2.5 p-2.5">
|
||||
<i class="pi pi-list cfg-subheader__icon w-10 h-10 rounded-md flex-shrink-0" />
|
||||
<i class="pi pi-list cfg-subheader__icon w-10 h-10 rounded-md shrink-0" />
|
||||
<div class="flex-1">
|
||||
<div class="font-bold tracking-tight text-[var(--text-color-secondary)]">Últimos lançamentos</div>
|
||||
<div class="dash-card__sub">Cobranças e receitas recentes</div>
|
||||
</div>
|
||||
<button class="flex items-center gap-1 bg-transparent border-none cursor-pointer text-xs font-semibold text-[var(--primary-color,#6366f1)] p-0 flex-shrink-0" @click="goToLancamentos">
|
||||
<button class="flex items-center gap-1 bg-transparent border-none cursor-pointer text-xs font-semibold text-[var(--primary-color,#6366f1)] p-0 shrink-0" @click="goToLancamentos">
|
||||
Ver todos <i class="pi pi-arrow-right text-xs" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -302,11 +302,11 @@ onBeforeUnmount(() => {
|
||||
<div class="absolute w-72 h-72 top-0 -left-16 rounded-full blur-[60px] bg-indigo-500/[0.09]" />
|
||||
</div>
|
||||
|
||||
<div class="relative z-[1] px-3 pt-2.5 pb-2">
|
||||
<div class="relative z-1 px-3 pt-2.5 pb-2">
|
||||
<!-- Linha 1: brand + actions -->
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="flex items-center gap-2.5 flex-1 min-w-0">
|
||||
<div class="cfg-subheader__icon grid place-items-center w-10 h-10 rounded-md flex-shrink-0" style="background: color-mix(in srgb, #10b981 15%, transparent); color: #059669">
|
||||
<div class="cfg-subheader__icon grid place-items-center w-10 h-10 rounded-md shrink-0" style="background: color-mix(in srgb, #10b981 15%, transparent); color: #059669">
|
||||
<i class="pi pi-wallet text-base" />
|
||||
</div>
|
||||
<div class="min-w-0">
|
||||
@@ -316,13 +316,13 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
|
||||
<!-- Ações desktop -->
|
||||
<div class="hidden sm:flex items-center gap-2 flex-shrink-0">
|
||||
<div class="hidden sm:flex items-center gap-2 shrink-0">
|
||||
<Button icon="pi pi-refresh" severity="secondary" outlined class="h-9 w-9 rounded-full" :loading="loading" v-tooltip.top="'Recarregar'" @click="applyFilters" />
|
||||
<Button label="Lançamento manual" icon="pi pi-plus" class="rounded-full" @click="openManualDlg" />
|
||||
</div>
|
||||
|
||||
<!-- Mobile -->
|
||||
<div class="flex sm:hidden items-center gap-1 flex-shrink-0">
|
||||
<div class="flex sm:hidden items-center gap-1 shrink-0">
|
||||
<Button icon="pi pi-refresh" severity="secondary" outlined class="h-9 w-9 rounded-full" :loading="loading" @click="applyFilters" />
|
||||
<Button icon="pi pi-plus" class="h-9 w-9 rounded-full" @click="openManualDlg" />
|
||||
</div>
|
||||
@@ -349,7 +349,7 @@ onBeforeUnmount(() => {
|
||||
>
|
||||
<div class="text-[1.25rem] font-bold leading-none text-amber-500">{{ fmtBRL(summary.totalPending) }}</div>
|
||||
<div class="flex items-center gap-1.5 text-[0.7rem] text-amber-600/80 font-semibold">
|
||||
<span class="h-1.5 w-1.5 rounded-full bg-amber-400 animate-pulse flex-shrink-0" />
|
||||
<span class="h-1.5 w-1.5 rounded-full bg-amber-400 animate-pulse shrink-0" />
|
||||
Pendente
|
||||
<span class="ml-auto font-bold bg-amber-500/10 rounded-full px-1.5">{{ summary.countByStatus.pending ?? 0 }}</span>
|
||||
</div>
|
||||
@@ -397,12 +397,12 @@ onBeforeUnmount(() => {
|
||||
═══════════════════════════════════════ -->
|
||||
<section class="dash-card rounded-md">
|
||||
<div class="dash-card__head gap-2.5 p-2.5">
|
||||
<i class="pi pi-filter cfg-subheader__icon w-10 h-10 rounded-md flex-shrink-0" />
|
||||
<i class="pi pi-filter cfg-subheader__icon w-10 h-10 rounded-md shrink-0" />
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="font-bold tracking-tight text-[var(--text-color-secondary)]">Filtros</div>
|
||||
<div class="dash-card__sub">Refine por status, tipo, paciente ou período</div>
|
||||
</div>
|
||||
<Button v-if="hasActiveFilters" label="Limpar" icon="pi pi-filter-slash" severity="danger" outlined size="small" class="rounded-full ml-auto flex-shrink-0" @click="clearFilters" />
|
||||
<Button v-if="hasActiveFilters" label="Limpar" icon="pi pi-filter-slash" severity="danger" outlined size="small" class="rounded-full ml-auto shrink-0" @click="clearFilters" />
|
||||
</div>
|
||||
<div class="px-4 py-3">
|
||||
<div class="flex flex-col sm:flex-row sm:flex-wrap items-start sm:items-end gap-3">
|
||||
@@ -428,7 +428,7 @@ onBeforeUnmount(() => {
|
||||
<Select id="fin-filter-patient" v-model="filterPatient" :options="patients" optionLabel="nome_completo" filter :filterFields="['nome_completo']" showClear class="w-full">
|
||||
<template #option="{ option }">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="h-2 w-2 rounded-full flex-shrink-0" :style="option.identification_color ? { background: option.identification_color } : { background: 'var(--surface-border)' }" />
|
||||
<span class="h-2 w-2 rounded-full shrink-0" :style="option.identification_color ? { background: option.identification_color } : { background: 'var(--surface-border)' }" />
|
||||
<span>{{ option.nome_completo }}</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -452,7 +452,7 @@ onBeforeUnmount(() => {
|
||||
Erro de carregamento
|
||||
═══════════════════════════════════════ -->
|
||||
<div v-if="error" class="rounded-md border border-red-500/30 bg-red-500/5 px-4 py-3 flex items-center gap-3 text-red-600">
|
||||
<i class="pi pi-exclamation-triangle flex-shrink-0" />
|
||||
<i class="pi pi-exclamation-triangle shrink-0" />
|
||||
<span class="text-[1rem]">{{ error }}</span>
|
||||
<Button icon="pi pi-refresh" severity="danger" text size="small" class="ml-auto" @click="applyFilters" />
|
||||
</div>
|
||||
@@ -497,7 +497,7 @@ onBeforeUnmount(() => {
|
||||
<!-- Linha 1: paciente + valor + status -->
|
||||
<div class="flex items-start gap-2.5">
|
||||
<div
|
||||
class="h-8 w-8 rounded-full flex-shrink-0 grid place-items-center text-white text-xs font-bold mt-0.5"
|
||||
class="h-8 w-8 rounded-full shrink-0 grid place-items-center text-white text-xs font-bold mt-0.5"
|
||||
:style="rec.patients?.identification_color ? { background: rec.patients.identification_color } : { background: 'var(--primary-color, #6366f1)' }"
|
||||
>
|
||||
{{ rec.patients?.nome_completo?.[0]?.toUpperCase() ?? '?' }}
|
||||
@@ -510,7 +510,7 @@ onBeforeUnmount(() => {
|
||||
{{ rec.agenda_eventos ? fmtDateTime(rec.agenda_eventos.inicio_em) : 'Lançamento manual' }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col items-end gap-1 flex-shrink-0">
|
||||
<div class="flex flex-col items-end gap-1 shrink-0">
|
||||
<span class="font-bold text-[var(--text-color)]">{{ fmtBRL(rec.final_amount) }}</span>
|
||||
<Tag :value="STATUS_CFG[rec.status]?.label ?? rec.status" :severity="STATUS_CFG[rec.status]?.severity" class="text-xs" />
|
||||
</div>
|
||||
@@ -547,7 +547,7 @@ onBeforeUnmount(() => {
|
||||
<section class="hidden md:block dash-card rounded-md shadow-[0_0_0_3px_color-mix(in_srgb,var(--primary-color)_7%,transparent)]">
|
||||
<!-- Header -->
|
||||
<div class="dash-card__head gap-2.5 p-2.5">
|
||||
<i class="pi pi-table cfg-subheader__icon w-10 h-10 rounded-md flex-shrink-0" />
|
||||
<i class="pi pi-table cfg-subheader__icon w-10 h-10 rounded-md shrink-0" />
|
||||
<div class="flex-1">
|
||||
<div class="font-bold tracking-tight text-[var(--text-color-secondary)]">Registros</div>
|
||||
<div class="dash-card__sub">Lista completa de cobranças e lançamentos</div>
|
||||
@@ -584,7 +584,7 @@ onBeforeUnmount(() => {
|
||||
<template #body="{ data }">
|
||||
<div class="flex items-center gap-2">
|
||||
<div
|
||||
class="h-6 w-6 rounded-full flex-shrink-0 grid place-items-center text-white text-[0.6rem] font-bold"
|
||||
class="h-6 w-6 rounded-full shrink-0 grid place-items-center text-white text-[0.6rem] font-bold"
|
||||
:style="data.patients?.identification_color ? { background: data.patients.identification_color } : { background: 'var(--primary-color, #6366f1)' }"
|
||||
>
|
||||
{{ data.patients?.nome_completo?.[0]?.toUpperCase() ?? '?' }}
|
||||
@@ -688,7 +688,7 @@ onBeforeUnmount(() => {
|
||||
<div class="font-semibold text-sm text-[var(--text-color)] truncate">{{ payDlgRecord.patients?.nome_completo ?? '—' }}</div>
|
||||
<div class="text-[0.75rem] text-[var(--text-color-secondary)] mt-0.5">Vencimento: {{ fmtDate(payDlgRecord.due_date) }}</div>
|
||||
</div>
|
||||
<div class="text-right flex-shrink-0">
|
||||
<div class="text-right shrink-0">
|
||||
<div class="text-lg font-bold text-[var(--text-color)]">{{ fmtBRL(payDlgRecord.final_amount) }}</div>
|
||||
<div v-if="payDlgRecord.discount_amount > 0" class="text-[0.7rem] text-[var(--text-color-secondary)] line-through">
|
||||
{{ fmtBRL(payDlgRecord.amount) }}
|
||||
@@ -745,7 +745,7 @@ onBeforeUnmount(() => {
|
||||
<Select v-model="manualForm.patient" :options="patients" optionLabel="nome_completo" filter :filterFields="['nome_completo']" showClear placeholder="Selecionar paciente..." class="w-full">
|
||||
<template #option="{ option }">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="h-2 w-2 rounded-full flex-shrink-0" :style="option.identification_color ? { background: option.identification_color } : { background: 'var(--surface-border)' }" />
|
||||
<span class="h-2 w-2 rounded-full shrink-0" :style="option.identification_color ? { background: option.identification_color } : { background: 'var(--surface-border)' }" />
|
||||
<span>{{ option.nome_completo }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -741,10 +741,10 @@ function isRecent(row) {
|
||||
<div class="absolute w-72 h-72 top-0 -left-16 rounded-full blur-[60px] bg-indigo-500/[0.09]" />
|
||||
</div>
|
||||
|
||||
<div class="relative z-[1] flex items-center gap-3">
|
||||
<div class="relative z-1 flex items-center gap-3">
|
||||
<!-- Brand -->
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<div class="grid place-items-center w-9 h-9 rounded-md flex-shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<div class="flex items-center gap-2 shrink-0">
|
||||
<div class="grid place-items-center w-9 h-9 rounded-md shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<i class="pi pi-users text-base" />
|
||||
</div>
|
||||
<div class="min-w-0 hidden lg:block">
|
||||
@@ -767,7 +767,7 @@ function isRecent(row) {
|
||||
</div>
|
||||
|
||||
<!-- Ações desktop -->
|
||||
<div class="hidden xl:flex items-center gap-1 flex-shrink-0">
|
||||
<div class="hidden xl:flex items-center gap-1 shrink-0">
|
||||
<Button icon="pi pi-refresh" severity="secondary" outlined class="h-9 w-9 rounded-full" :loading="loading" @click="fetchAll" />
|
||||
<Button icon="pi pi-percentage" severity="secondary" outlined class="h-9 w-9 rounded-full" v-tooltip.top="'Descontos'" @click="router.push('/configuracoes/descontos')" />
|
||||
<Button label="Novo" icon="pi pi-user-plus" class="rounded-full" @click="(e) => createPopoverRef?.toggle(e)" />
|
||||
@@ -776,7 +776,7 @@ function isRecent(row) {
|
||||
</div>
|
||||
|
||||
<!-- Mobile -->
|
||||
<div class="flex xl:hidden items-center gap-1 flex-shrink-0 ml-auto">
|
||||
<div class="flex xl:hidden items-center gap-1 shrink-0 ml-auto">
|
||||
<Button icon="pi pi-search" severity="secondary" outlined class="h-9 w-9 rounded-full" @click="searchMobileDlg = true" />
|
||||
<Button icon="pi pi-user-plus" class="h-9 w-9 rounded-full" @click="(e) => createPopoverRef?.toggle(e)" />
|
||||
<Button label="Ações" icon="pi pi-ellipsis-v" severity="secondary" size="small" class="rounded-full" @click="(e) => patMobileMenuRef.toggle(e)" />
|
||||
@@ -1225,14 +1225,14 @@ function isRecent(row) {
|
||||
:style="{ borderBottomColor: `${grp.color || 'var(--surface-border)'}30` }"
|
||||
@click="openGrpDialog(grp)"
|
||||
>
|
||||
<div class="w-9 h-9 rounded-lg flex items-center justify-center text-white font-bold text-sm flex-shrink-0 shadow-sm" :style="grpColorStyle(grp)">
|
||||
<div class="w-9 h-9 rounded-lg flex items-center justify-center text-white font-bold text-sm shrink-0 shadow-sm" :style="grpColorStyle(grp)">
|
||||
{{ (grp.name || '?')[0].toUpperCase() }}
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="font-semibold truncate text-sm" :style="{ color: grp.color || 'var(--text-color)' }">{{ grp.name }}</div>
|
||||
<div class="text-[0.72rem] text-[var(--text-color-secondary)] opacity-70">{{ grp.patients.length }} paciente{{ grp.patients.length !== 1 ? 's' : '' }} · clique para ver</div>
|
||||
</div>
|
||||
<span class="inline-flex items-center justify-center min-w-[26px] h-6 px-1.5 rounded-full text-white text-xs font-bold flex-shrink-0" :style="grpColorStyle(grp)">{{ grp.patients.length }}</span>
|
||||
<span class="inline-flex items-center justify-center min-w-[26px] h-6 px-1.5 rounded-full text-white text-xs font-bold shrink-0" :style="grpColorStyle(grp)">{{ grp.patients.length }}</span>
|
||||
</button>
|
||||
|
||||
<!-- Chips de pacientes -->
|
||||
@@ -1258,7 +1258,7 @@ function isRecent(row) {
|
||||
}
|
||||
"
|
||||
>
|
||||
<span class="w-5 h-5 rounded-full flex items-center justify-center text-[9px] font-bold flex-shrink-0 transition-colors group-hover:bg-white/20 group-hover:text-white" :style="grpChipAvatarStyle(grp)">
|
||||
<span class="w-5 h-5 rounded-full flex items-center justify-center text-[9px] font-bold shrink-0 transition-colors group-hover:bg-white/20 group-hover:text-white" :style="grpChipAvatarStyle(grp)">
|
||||
{{ (p.nome_completo || '?').charAt(0).toUpperCase() }}
|
||||
</span>
|
||||
<span class="max-w-[120px] truncate">{{ (p.nome_completo || '—').split(' ').slice(0, 2).join(' ') }}</span>
|
||||
@@ -1293,7 +1293,7 @@ function isRecent(row) {
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-9 h-9 rounded-lg flex items-center justify-center text-white font-bold text-base flex-shrink-0" :style="grpColorStyle(grpDialog.group)">
|
||||
<div class="w-9 h-9 rounded-lg flex items-center justify-center text-white font-bold text-base shrink-0" :style="grpColorStyle(grpDialog.group)">
|
||||
{{ (grpDialog.group?.name || '?')[0].toUpperCase() }}
|
||||
</div>
|
||||
<div>
|
||||
|
||||
@@ -564,11 +564,11 @@ defineExpose({ fillRandomPatient, onSubmit, confirmDelete, saving, deleting, can
|
||||
<div class="absolute w-72 h-72 top-0 -left-16 rounded-full blur-[60px] bg-emerald-400/[0.08]" />
|
||||
</div>
|
||||
|
||||
<div class="relative z-[1] flex items-center gap-3">
|
||||
<div class="relative z-1 flex items-center gap-3">
|
||||
|
||||
<!-- Brand -->
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<div class="grid place-items-center w-9 h-9 rounded-md flex-shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<div class="flex items-center gap-2 shrink-0">
|
||||
<div class="grid place-items-center w-9 h-9 rounded-md shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<i class="pi pi-user-plus text-base" />
|
||||
</div>
|
||||
<div class="min-w-0 hidden lg:block">
|
||||
@@ -586,7 +586,7 @@ defineExpose({ fillRandomPatient, onSubmit, confirmDelete, saving, deleting, can
|
||||
<div class="flex-1" />
|
||||
|
||||
<!-- Ações (ocultas no modo dialog — o Dialog tem seu próprio footer) -->
|
||||
<div v-if="!dialogMode" class="flex items-center gap-1.5 flex-shrink-0">
|
||||
<div v-if="!dialogMode" class="flex items-center gap-1.5 shrink-0">
|
||||
<Button
|
||||
v-if="canSee('testMODE')"
|
||||
label="Preencher tudo"
|
||||
@@ -634,7 +634,7 @@ defineExpose({ fillRandomPatient, onSubmit, confirmDelete, saving, deleting, can
|
||||
<!-- Avatar -->
|
||||
<div class="flex items-center gap-3 pb-3.5 mb-3.5 border-b border-[var(--surface-border,#e2e8f0)] xl:flex-col xl:items-center xl:gap-2">
|
||||
<!-- Foto -->
|
||||
<div class="w-16 h-16 xl:w-20 xl:h-20 rounded-full overflow-hidden border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-ground,#f8fafc)] flex-shrink-0">
|
||||
<div class="w-16 h-16 xl:w-20 xl:h-20 rounded-full overflow-hidden border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-ground,#f8fafc)] shrink-0">
|
||||
<img
|
||||
v-if="avatarPreviewUrl || form.avatar_url"
|
||||
:src="avatarPreviewUrl || form.avatar_url"
|
||||
@@ -676,7 +676,7 @@ defineExpose({ fillRandomPatient, onSubmit, confirmDelete, saving, deleting, can
|
||||
: 'border-transparent text-[var(--text-color)] hover:bg-[var(--surface-ground,#f8fafc)] font-medium'"
|
||||
@click="openPanel(Number(item.value))"
|
||||
>
|
||||
<i :class="item.icon" class="text-[1rem] opacity-70 flex-shrink-0" />
|
||||
<i :class="item.icon" class="text-[1rem] opacity-70 shrink-0" />
|
||||
<span>{{ item.label }}</span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -705,7 +705,7 @@ defineExpose({ fillRandomPatient, onSubmit, confirmDelete, saving, deleting, can
|
||||
:class="activeValue === item.value ? 'bg-indigo-500/8 border-indigo-300/40 text-indigo-700 font-semibold' : 'text-[var(--text-color)] hover:bg-[var(--surface-ground,#f8fafc)] font-medium'"
|
||||
@click="selectNav(item)"
|
||||
>
|
||||
<i :class="item.icon" class="text-[1rem] opacity-70 flex-shrink-0" />
|
||||
<i :class="item.icon" class="text-[1rem] opacity-70 shrink-0" />
|
||||
<span>{{ item.label }}</span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -802,7 +802,7 @@ defineExpose({ fillRandomPatient, onSubmit, confirmDelete, saving, deleting, can
|
||||
</FloatLabel>
|
||||
<div class="mt-1 text-[0.72rem] text-[var(--text-color-secondary)] opacity-70">Usado para puxar um modelo de anamnese.</div>
|
||||
</div>
|
||||
<Button icon="pi pi-plus" severity="secondary" outlined class="flex-shrink-0" @click="openGroupDlg" />
|
||||
<Button icon="pi pi-plus" severity="secondary" outlined class="shrink-0" @click="openGroupDlg" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- Tags -->
|
||||
@@ -814,7 +814,7 @@ defineExpose({ fillRandomPatient, onSubmit, confirmDelete, saving, deleting, can
|
||||
<label for="f_tags">Tags</label>
|
||||
</FloatLabel>
|
||||
</div>
|
||||
<Button icon="pi pi-plus" severity="secondary" outlined class="flex-shrink-0" @click="openTagDlg" />
|
||||
<Button icon="pi pi-plus" severity="secondary" outlined class="shrink-0" @click="openTagDlg" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
@@ -928,11 +928,11 @@ defineExpose({ fillRandomPatient, onSubmit, confirmDelete, saving, deleting, can
|
||||
<div class="flex flex-col gap-4 pt-1">
|
||||
<span class="text-[1rem] text-[var(--text-color-secondary)]">Crie um grupo para organizar seus pacientes.</span>
|
||||
<div class="flex items-center gap-3">
|
||||
<label for="group-name" class="w-20 text-[1rem] font-semibold flex-shrink-0">Nome</label>
|
||||
<label for="group-name" class="w-20 text-[1rem] font-semibold shrink-0">Nome</label>
|
||||
<InputText id="group-name" v-model="newGroup.name" class="flex-1" autocomplete="off" placeholder="Ex: Crianças" />
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<label class="w-20 text-[1rem] font-semibold flex-shrink-0">Cor</label>
|
||||
<label class="w-20 text-[1rem] font-semibold shrink-0">Cor</label>
|
||||
<div class="flex flex-1 items-center gap-2.5">
|
||||
<input v-model="newGroup.color" type="color" class="h-9 w-12 cursor-pointer rounded-md border border-[var(--surface-border,#e2e8f0)] bg-transparent" />
|
||||
<Chip :label="newGroup.color || '#—'" class="font-semibold" :style="{ backgroundColor: newGroup.color, color: '#fff' }" />
|
||||
@@ -963,11 +963,11 @@ defineExpose({ fillRandomPatient, onSubmit, confirmDelete, saving, deleting, can
|
||||
<div class="flex flex-col gap-4 pt-1">
|
||||
<span class="text-[1rem] text-[var(--text-color-secondary)]">Crie uma tag para facilitar filtros e organização.</span>
|
||||
<div class="flex items-center gap-3">
|
||||
<label for="tag-name" class="w-20 text-[1rem] font-semibold flex-shrink-0">Nome</label>
|
||||
<label for="tag-name" class="w-20 text-[1rem] font-semibold shrink-0">Nome</label>
|
||||
<InputText id="tag-name" v-model="newTag.name" class="flex-1" autocomplete="off" placeholder="Ex: Ansiedade" />
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<label class="w-20 text-[1rem] font-semibold flex-shrink-0">Cor</label>
|
||||
<label class="w-20 text-[1rem] font-semibold shrink-0">Cor</label>
|
||||
<div class="flex flex-1 items-center gap-2.5">
|
||||
<input v-model="newTag.color" type="color" class="h-9 w-12 cursor-pointer rounded-md border border-[var(--surface-border,#e2e8f0)] bg-transparent" />
|
||||
<Chip :label="newTag.color || '#—'" class="font-semibold" :style="{ backgroundColor: newTag.color, color: '#fff' }" />
|
||||
|
||||
@@ -190,10 +190,10 @@ onBeforeUnmount(() => {
|
||||
<div class="absolute w-72 h-72 top-0 -left-16 rounded-full blur-[60px] bg-emerald-400/[0.08]" />
|
||||
</div>
|
||||
|
||||
<div class="relative z-[1] flex items-center gap-3">
|
||||
<div class="relative z-1 flex items-center gap-3">
|
||||
<!-- Brand -->
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<div class="grid place-items-center w-9 h-9 rounded-md flex-shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<div class="flex items-center gap-2 shrink-0">
|
||||
<div class="grid place-items-center w-9 h-9 rounded-md shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<i class="pi pi-link text-base" />
|
||||
</div>
|
||||
<div class="min-w-0 hidden lg:block">
|
||||
@@ -206,7 +206,7 @@ onBeforeUnmount(() => {
|
||||
<div class="hidden xl:flex flex-1 min-w-0 mx-2 items-center gap-3">
|
||||
<!-- Badge de status -->
|
||||
<span
|
||||
class="inline-flex items-center gap-1.5 text-[0.75rem] px-2.5 py-1 rounded-full border flex-shrink-0 transition-colors"
|
||||
class="inline-flex items-center gap-1.5 text-[0.75rem] px-2.5 py-1 rounded-full border shrink-0 transition-colors"
|
||||
:class="inviteToken ? 'border-emerald-200 text-emerald-700 bg-emerald-50' : 'border-[var(--surface-border)] text-[var(--text-color-secondary)] bg-[var(--surface-ground)]'"
|
||||
>
|
||||
<span class="h-1.5 w-1.5 rounded-full" :class="inviteToken ? 'bg-emerald-500 animate-pulse' : 'bg-[var(--text-color-secondary)]'" />
|
||||
@@ -224,12 +224,12 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
|
||||
<!-- Ações desktop -->
|
||||
<div class="hidden xl:flex items-center gap-1 flex-shrink-0">
|
||||
<div class="hidden xl:flex items-center gap-1 shrink-0">
|
||||
<Button label="Gerar novo link" icon="pi pi-refresh" severity="secondary" outlined class="rounded-full" :loading="rotating" @click="rotateLink" />
|
||||
</div>
|
||||
|
||||
<!-- Mobile -->
|
||||
<div class="flex xl:hidden items-center gap-1 flex-shrink-0 ml-auto">
|
||||
<div class="flex xl:hidden items-center gap-1 shrink-0 ml-auto">
|
||||
<Button label="Ações" icon="pi pi-ellipsis-v" severity="secondary" size="small" class="rounded-full" @click="(e) => mobileMenuRef.toggle(e)" />
|
||||
<Menu ref="mobileMenuRef" :model="mobileMenuItems" :popup="true" />
|
||||
</div>
|
||||
@@ -251,7 +251,7 @@ onBeforeUnmount(() => {
|
||||
<div class="text-[1rem] text-[var(--text-color-secondary)] mt-0.5">Envie ao paciente por WhatsApp, e-mail ou mensagem direta</div>
|
||||
</div>
|
||||
<span
|
||||
class="inline-flex items-center gap-1.5 text-[0.75rem] px-2.5 py-1 rounded-full border flex-shrink-0"
|
||||
class="inline-flex items-center gap-1.5 text-[0.75rem] px-2.5 py-1 rounded-full border shrink-0"
|
||||
:class="inviteToken ? 'border-emerald-200 text-emerald-700 bg-emerald-50' : 'border-[var(--surface-border)] text-[var(--text-color-secondary)] bg-[var(--surface-ground)]'"
|
||||
>
|
||||
<span class="h-1.5 w-1.5 rounded-full" :class="inviteToken ? 'bg-emerald-500 animate-pulse' : 'bg-[var(--text-color-secondary)]'" />
|
||||
@@ -286,7 +286,7 @@ onBeforeUnmount(() => {
|
||||
class="flex items-center gap-3 px-3.5 py-3 rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-ground,#f8fafc)] cursor-pointer text-left transition-[background,box-shadow,transform] duration-150 hover:bg-[var(--surface-hover,#f1f5f9)] hover:shadow-[0_2px_12px_rgba(0,0,0,0.06)] hover:-translate-y-px active:translate-y-0"
|
||||
@click="copyLink"
|
||||
>
|
||||
<div class="grid place-items-center w-9 h-9 rounded-md flex-shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<div class="grid place-items-center w-9 h-9 rounded-md shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<i class="pi pi-copy" />
|
||||
</div>
|
||||
<div class="min-w-0">
|
||||
@@ -300,7 +300,7 @@ onBeforeUnmount(() => {
|
||||
class="flex items-center gap-3 px-3.5 py-3 rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-ground,#f8fafc)] cursor-pointer text-left transition-[background,box-shadow,transform] duration-150 hover:bg-[var(--surface-hover,#f1f5f9)] hover:shadow-[0_2px_12px_rgba(0,0,0,0.06)] hover:-translate-y-px active:translate-y-0"
|
||||
@click="copyInviteMessage"
|
||||
>
|
||||
<div class="grid place-items-center w-9 h-9 rounded-md flex-shrink-0 bg-emerald-500/10 text-emerald-600">
|
||||
<div class="grid place-items-center w-9 h-9 rounded-md shrink-0 bg-emerald-500/10 text-emerald-600">
|
||||
<i class="pi pi-comment" />
|
||||
</div>
|
||||
<div class="min-w-0">
|
||||
@@ -336,11 +336,11 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
|
||||
<!-- ── DIREITA: instruções ────────────────────────── -->
|
||||
<div class="w-full lg:w-[272px] lg:flex-shrink-0 flex flex-col gap-3">
|
||||
<div class="w-full lg:w-[272px] lg:shrink-0 flex flex-col gap-3">
|
||||
<!-- Como funciona -->
|
||||
<div class="rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)] overflow-hidden">
|
||||
<div class="flex items-center gap-2.5 px-3.5 pt-3 pb-2.5 border-b border-[var(--surface-border,#f1f5f9)]">
|
||||
<div class="w-8 h-8 rounded-md flex items-center justify-center flex-shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<div class="w-8 h-8 rounded-md flex items-center justify-center shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<i class="pi pi-list-check text-[0.9rem]" />
|
||||
</div>
|
||||
<div class="min-w-0">
|
||||
@@ -351,7 +351,7 @@ onBeforeUnmount(() => {
|
||||
|
||||
<ol class="flex flex-col divide-y divide-[var(--surface-border,#f1f5f9)]">
|
||||
<li v-for="step in howItWorks" :key="step.n" class="flex items-start gap-3 px-3.5 py-3">
|
||||
<div class="grid place-items-center w-7 h-7 rounded-md flex-shrink-0 bg-indigo-500/10 text-indigo-500 text-[0.75rem] font-bold mt-px">
|
||||
<div class="grid place-items-center w-7 h-7 rounded-md shrink-0 bg-indigo-500/10 text-indigo-500 text-[0.75rem] font-bold mt-px">
|
||||
{{ step.n }}
|
||||
</div>
|
||||
<div class="min-w-0">
|
||||
@@ -365,7 +365,7 @@ onBeforeUnmount(() => {
|
||||
<!-- Boas práticas -->
|
||||
<div class="rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)] overflow-hidden">
|
||||
<div class="flex items-center gap-2.5 px-3.5 pt-3 pb-2.5 border-b border-[var(--surface-border,#f1f5f9)]">
|
||||
<div class="w-8 h-8 rounded-md flex items-center justify-center flex-shrink-0 bg-emerald-500/10 text-emerald-600">
|
||||
<div class="w-8 h-8 rounded-md flex items-center justify-center shrink-0 bg-emerald-500/10 text-emerald-600">
|
||||
<i class="pi pi-shield text-[0.9rem]" />
|
||||
</div>
|
||||
<div class="min-w-0">
|
||||
@@ -376,7 +376,7 @@ onBeforeUnmount(() => {
|
||||
|
||||
<ul class="flex flex-col divide-y divide-[var(--surface-border,#f1f5f9)]">
|
||||
<li v-for="tip in goodPractices" :key="tip" class="flex items-start gap-2.5 px-3.5 py-2.5">
|
||||
<i class="pi pi-check text-emerald-500 mt-0.5 flex-shrink-0 text-[1rem]" />
|
||||
<i class="pi pi-check text-emerald-500 mt-0.5 shrink-0 text-[1rem]" />
|
||||
<span class="text-[1rem] text-[var(--text-color-secondary)] leading-relaxed">{{ tip }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -495,10 +495,10 @@ onBeforeUnmount(() => {
|
||||
<div class="absolute w-72 h-72 top-0 -left-16 rounded-full blur-[60px] bg-indigo-500/[0.09]" />
|
||||
</div>
|
||||
|
||||
<div class="relative z-[1] flex items-center gap-3">
|
||||
<div class="relative z-1 flex items-center gap-3">
|
||||
<!-- Brand -->
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<div class="grid place-items-center w-9 h-9 rounded-md flex-shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<div class="flex items-center gap-2 shrink-0">
|
||||
<div class="grid place-items-center w-9 h-9 rounded-md shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<i class="pi pi-inbox text-base" />
|
||||
</div>
|
||||
<div class="min-w-0 hidden lg:block">
|
||||
@@ -537,12 +537,12 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
|
||||
<!-- Ações desktop -->
|
||||
<div class="hidden xl:flex items-center gap-1 flex-shrink-0">
|
||||
<div class="hidden xl:flex items-center gap-1 shrink-0">
|
||||
<Button icon="pi pi-refresh" severity="secondary" outlined class="h-9 w-9 rounded-full" :loading="loading" title="Atualizar" @click="fetchIntakes" />
|
||||
</div>
|
||||
|
||||
<!-- Mobile -->
|
||||
<div class="flex xl:hidden items-center gap-1 flex-shrink-0 ml-auto">
|
||||
<div class="flex xl:hidden items-center gap-1 shrink-0 ml-auto">
|
||||
<Button icon="pi pi-search" severity="secondary" outlined class="h-9 w-9 rounded-full" @click="recSearchDlgOpen = true" />
|
||||
<Button label="Ações" icon="pi pi-ellipsis-v" severity="secondary" size="small" class="rounded-full" @click="(e) => recMobileMenuRef.toggle(e)" />
|
||||
<Menu ref="recMobileMenuRef" :model="recMobileMenuItems" :popup="true" />
|
||||
|
||||
@@ -431,10 +431,10 @@ function isRecent(row) {
|
||||
<div class="absolute w-72 h-72 top-0 -left-16 rounded-full blur-[60px] bg-indigo-500/[0.09]" />
|
||||
</div>
|
||||
|
||||
<div class="relative z-[1] flex items-center gap-3">
|
||||
<div class="relative z-1 flex items-center gap-3">
|
||||
<!-- Brand -->
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<div class="grid place-items-center w-9 h-9 rounded-md flex-shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<div class="flex items-center gap-2 shrink-0">
|
||||
<div class="grid place-items-center w-9 h-9 rounded-md shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<i class="pi pi-sitemap text-base" />
|
||||
</div>
|
||||
<div class="min-w-0 hidden lg:block">
|
||||
@@ -457,14 +457,14 @@ function isRecent(row) {
|
||||
</div>
|
||||
|
||||
<!-- Ações desktop -->
|
||||
<div class="hidden xl:flex items-center gap-1 flex-shrink-0">
|
||||
<div class="hidden xl:flex items-center gap-1 shrink-0">
|
||||
<Button v-if="selectedGroups?.length" label="Excluir selecionados" icon="pi pi-trash" severity="danger" outlined class="rounded-full" @click="confirmDeleteSelected" />
|
||||
<Button label="Novo grupo" icon="pi pi-plus" class="rounded-full" @click="openCreate" />
|
||||
<Button icon="pi pi-refresh" severity="secondary" outlined class="h-9 w-9 rounded-full" :loading="loading" @click="fetchAll" />
|
||||
</div>
|
||||
|
||||
<!-- Mobile -->
|
||||
<div class="flex xl:hidden items-center gap-1 flex-shrink-0 ml-auto">
|
||||
<div class="flex xl:hidden items-center gap-1 shrink-0 ml-auto">
|
||||
<Button icon="pi pi-search" severity="secondary" outlined class="h-9 w-9 rounded-full" @click="grpSearchDlgOpen = true" />
|
||||
<Button icon="pi pi-plus" class="h-9 w-9 rounded-full" @click="openCreate" />
|
||||
<Button label="Ações" icon="pi pi-ellipsis-v" severity="secondary" size="small" class="rounded-full" @click="(e) => grpMobileMenuRef.toggle(e)" />
|
||||
@@ -564,7 +564,7 @@ function isRecent(row) {
|
||||
<Column field="nome" header="Nome" sortable style="min-width: 16rem">
|
||||
<template #body="{ data }">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="w-[3px] h-5 rounded-sm flex-shrink-0" :style="effectiveCor(data) ? colorStyle(effectiveCor(data)) : { background: 'var(--surface-border)' }" />
|
||||
<span class="w-[3px] h-5 rounded-sm shrink-0" :style="effectiveCor(data) ? colorStyle(effectiveCor(data)) : { background: 'var(--surface-border)' }" />
|
||||
<span class="font-medium">{{ data.nome }}</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -616,18 +616,18 @@ function isRecent(row) {
|
||||
</div>
|
||||
|
||||
<!-- ── PAINEL LATERAL: grupos com pacientes ─────────── -->
|
||||
<div class="w-full lg:w-[272px] lg:flex-shrink-0">
|
||||
<div class="w-full lg:w-[272px] lg:shrink-0">
|
||||
<div class="rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)] overflow-hidden">
|
||||
<!-- Header do painel -->
|
||||
<div class="flex items-center gap-2.5 px-3.5 pt-3 pb-2.5 border-b border-[var(--surface-border,#f1f5f9)]">
|
||||
<div class="w-8 h-8 rounded-md flex items-center justify-center flex-shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<div class="w-8 h-8 rounded-md flex items-center justify-center shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<i class="pi pi-users text-[0.9rem]" />
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<span class="block text-[1rem] font-bold text-[var(--text-color)]">Pacientes por grupo</span>
|
||||
<span class="block text-[0.72rem] text-[var(--text-color-secondary)]">Grupos com associações ativas</span>
|
||||
</div>
|
||||
<span v-if="cards.length" class="inline-flex items-center justify-center min-w-[20px] h-5 px-1 rounded-full bg-[var(--primary-color,#6366f1)] text-white text-[0.65rem] font-bold flex-shrink-0">{{ cards.length }}</span>
|
||||
<span v-if="cards.length" class="inline-flex items-center justify-center min-w-[20px] h-5 px-1 rounded-full bg-[var(--primary-color,#6366f1)] text-white text-[0.65rem] font-bold shrink-0">{{ cards.length }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Skeleton -->
|
||||
@@ -651,7 +651,7 @@ function isRecent(row) {
|
||||
@click="openGroupPatientsModal(g)"
|
||||
>
|
||||
<!-- Dot cor -->
|
||||
<div class="w-2.5 h-2.5 rounded-full flex-shrink-0" :style="effectiveCor(g) ? colorStyle(effectiveCor(g)) : { background: 'var(--surface-border)' }" />
|
||||
<div class="w-2.5 h-2.5 rounded-full shrink-0" :style="effectiveCor(g) ? colorStyle(effectiveCor(g)) : { background: 'var(--surface-border)' }" />
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="font-semibold text-[0.8rem] truncate text-[var(--text-color)]">{{ g.nome }}</div>
|
||||
<div class="text-[1rem] text-[var(--text-color-secondary)]">
|
||||
@@ -659,10 +659,10 @@ function isRecent(row) {
|
||||
</div>
|
||||
</div>
|
||||
<!-- Badge contagem -->
|
||||
<span class="inline-flex items-center justify-center min-w-[22px] h-[22px] px-1 rounded-full font-bold text-[0.68rem] flex-shrink-0" :class="g.is_system ? 'bg-sky-500/10 text-sky-600' : 'bg-indigo-500/10 text-indigo-600'">{{
|
||||
<span class="inline-flex items-center justify-center min-w-[22px] h-[22px] px-1 rounded-full font-bold text-[0.68rem] shrink-0" :class="g.is_system ? 'bg-sky-500/10 text-sky-600' : 'bg-indigo-500/10 text-indigo-600'">{{
|
||||
Number(g.patients_count ?? g.patient_count ?? 0)
|
||||
}}</span>
|
||||
<i class="pi pi-chevron-right text-[0.6rem] text-[var(--text-color-secondary)] opacity-30 group-hover:opacity-100 group-hover:text-[var(--primary-color,#6366f1)] transition-all duration-150 flex-shrink-0" />
|
||||
<i class="pi pi-chevron-right text-[0.6rem] text-[var(--text-color-secondary)] opacity-30 group-hover:opacity-100 group-hover:text-[var(--primary-color,#6366f1)] transition-all duration-150 shrink-0" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -791,7 +791,7 @@ function isRecent(row) {
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-9 h-9 rounded-lg flex items-center justify-center text-white font-bold text-base flex-shrink-0" :style="{ background: patientsGroupHex }">
|
||||
<div class="w-9 h-9 rounded-lg flex items-center justify-center text-white font-bold text-base shrink-0" :style="{ background: patientsGroupHex }">
|
||||
{{ (patientsDialog.group?.nome || '?')[0].toUpperCase() }}
|
||||
</div>
|
||||
<div>
|
||||
|
||||
@@ -601,7 +601,7 @@ Tags: ${
|
||||
<aside class="rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)] p-3.5 xl:sticky xl:top-2 xl:self-start">
|
||||
<!-- Avatar + info rápida -->
|
||||
<div class="flex items-center gap-3 pb-3.5 mb-3.5 border-b border-[var(--surface-border,#e2e8f0)] xl:flex-col xl:items-center xl:gap-2 xl:text-center">
|
||||
<div class="w-16 h-16 xl:w-20 xl:h-20 rounded-full overflow-hidden border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-ground,#f8fafc)] flex-shrink-0">
|
||||
<div class="w-16 h-16 xl:w-20 xl:h-20 rounded-full overflow-hidden border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-ground,#f8fafc)] shrink-0">
|
||||
<img :src="avatarUrl" alt="avatar" class="w-full h-full object-cover" />
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
@@ -636,7 +636,7 @@ Tags: ${
|
||||
:class="activeValue === item.value ? 'bg-indigo-500/8 border-indigo-300/40 text-indigo-700 font-semibold' : 'border-transparent text-[var(--text-color)] hover:bg-[var(--surface-ground,#f8fafc)] font-medium'"
|
||||
@click="openPanel(Number(item.value))"
|
||||
>
|
||||
<i :class="item.icon" class="text-sm opacity-70 flex-shrink-0" />
|
||||
<i :class="item.icon" class="text-sm opacity-70 shrink-0" />
|
||||
<span>{{ item.label }}</span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -657,7 +657,7 @@ Tags: ${
|
||||
:class="activeValue === item.value ? 'bg-indigo-500/8 border-indigo-300/40 text-indigo-700 font-semibold' : 'text-[var(--text-color)] hover:bg-[var(--surface-ground,#f8fafc)] font-medium'"
|
||||
@click="selectNav(item)"
|
||||
>
|
||||
<i :class="item.icon" class="text-sm opacity-70 flex-shrink-0" />
|
||||
<i :class="item.icon" class="text-sm opacity-70 shrink-0" />
|
||||
<span>{{ item.label }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -426,10 +426,10 @@ function isRecent(row) {
|
||||
<div class="absolute w-72 h-72 top-0 -left-16 rounded-full blur-[60px] bg-indigo-500/[0.09]" />
|
||||
</div>
|
||||
|
||||
<div class="relative z-[1] flex items-center gap-3">
|
||||
<div class="relative z-1 flex items-center gap-3">
|
||||
<!-- Brand -->
|
||||
<div class="flex items-center gap-2 flex-shrink-0">
|
||||
<div class="grid place-items-center w-9 h-9 rounded-md flex-shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<div class="flex items-center gap-2 shrink-0">
|
||||
<div class="grid place-items-center w-9 h-9 rounded-md shrink-0 bg-indigo-500/10 text-indigo-500">
|
||||
<i class="pi pi-tags text-base" />
|
||||
</div>
|
||||
<div class="min-w-0 hidden lg:block">
|
||||
@@ -452,14 +452,14 @@ function isRecent(row) {
|
||||
</div>
|
||||
|
||||
<!-- Ações desktop -->
|
||||
<div class="hidden xl:flex items-center gap-1 flex-shrink-0">
|
||||
<div class="hidden xl:flex items-center gap-1 shrink-0">
|
||||
<Button v-if="etiquetasSelecionadas?.length" label="Excluir selecionados" icon="pi pi-trash" severity="danger" outlined class="rounded-full" @click="confirmarExclusaoSelecionadas" />
|
||||
<Button label="Nova tag" icon="pi pi-plus" class="rounded-full" @click="abrirCriar" />
|
||||
<Button icon="pi pi-refresh" severity="secondary" outlined class="h-9 w-9 rounded-full" :loading="carregando" @click="buscarEtiquetas" />
|
||||
</div>
|
||||
|
||||
<!-- Mobile -->
|
||||
<div class="flex xl:hidden items-center gap-1 flex-shrink-0 ml-auto">
|
||||
<div class="flex xl:hidden items-center gap-1 shrink-0 ml-auto">
|
||||
<Button icon="pi pi-search" severity="secondary" outlined class="h-9 w-9 rounded-full" @click="searchDlgOpen = true" />
|
||||
<Button icon="pi pi-plus" class="h-9 w-9 rounded-full" @click="abrirCriar" />
|
||||
<Button label="Ações" icon="pi pi-ellipsis-v" severity="secondary" size="small" class="rounded-full" @click="(e) => mobileMenuRef.toggle(e)" />
|
||||
@@ -551,9 +551,9 @@ function isRecent(row) {
|
||||
<template #body="{ data }">
|
||||
<div class="flex items-center gap-2 min-w-0">
|
||||
<!-- Barra lateral colorida -->
|
||||
<span class="w-[3px] h-5 rounded-sm flex-shrink-0" :style="{ background: data.cor || '#94a3b8' }" />
|
||||
<span class="w-[3px] h-5 rounded-sm shrink-0" :style="{ background: data.cor || '#94a3b8' }" />
|
||||
<span class="font-medium truncate">{{ data.nome }}</span>
|
||||
<span v-if="data.is_padrao" class="inline-flex items-center px-1.5 py-px rounded text-[0.65rem] font-semibold bg-[var(--surface-border,#e2e8f0)] text-[var(--text-color-secondary)] flex-shrink-0">padrão</span>
|
||||
<span v-if="data.is_padrao" class="inline-flex items-center px-1.5 py-px rounded text-[0.65rem] font-semibold bg-[var(--surface-border,#e2e8f0)] text-[var(--text-color-secondary)] shrink-0">padrão</span>
|
||||
</div>
|
||||
</template>
|
||||
</Column>
|
||||
@@ -610,18 +610,18 @@ function isRecent(row) {
|
||||
</div>
|
||||
|
||||
<!-- ── PAINEL LATERAL: tags mais usadas ─────────────── -->
|
||||
<div class="w-full lg:w-[272px] lg:flex-shrink-0">
|
||||
<div class="w-full lg:w-[272px] lg:shrink-0">
|
||||
<div class="rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)] overflow-hidden">
|
||||
<!-- Header do painel -->
|
||||
<div class="flex items-center gap-2.5 px-3.5 pt-3 pb-2.5 border-b border-[var(--surface-border,#f1f5f9)]">
|
||||
<div class="w-8 h-8 rounded-md flex items-center justify-center flex-shrink-0 bg-pink-500/10 text-pink-500">
|
||||
<div class="w-8 h-8 rounded-md flex items-center justify-center shrink-0 bg-pink-500/10 text-pink-500">
|
||||
<i class="pi pi-tags text-[0.9rem]" />
|
||||
</div>
|
||||
<div class="flex-1 min-w-0">
|
||||
<span class="block text-[1rem] font-bold text-[var(--text-color)]">Mais usadas</span>
|
||||
<span class="block text-[0.72rem] text-[var(--text-color-secondary)]">Tags com pacientes associados</span>
|
||||
</div>
|
||||
<span v-if="cards.length" class="inline-flex items-center justify-center min-w-[20px] h-5 px-1 rounded-full bg-[var(--primary-color,#6366f1)] text-white text-[0.65rem] font-bold flex-shrink-0">{{ cards.length }}</span>
|
||||
<span v-if="cards.length" class="inline-flex items-center justify-center min-w-[20px] h-5 px-1 rounded-full bg-[var(--primary-color,#6366f1)] text-white text-[0.65rem] font-bold shrink-0">{{ cards.length }}</span>
|
||||
</div>
|
||||
|
||||
<!-- Skeleton -->
|
||||
@@ -645,7 +645,7 @@ function isRecent(row) {
|
||||
@click="abrirModalPacientesDaTag(t)"
|
||||
>
|
||||
<!-- Barra de cor -->
|
||||
<div class="w-[3px] h-5 rounded-sm flex-shrink-0" :style="{ background: t.cor || '#94a3b8' }" />
|
||||
<div class="w-[3px] h-5 rounded-sm shrink-0" :style="{ background: t.cor || '#94a3b8' }" />
|
||||
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="font-semibold text-[0.8rem] truncate text-[var(--text-color)] flex items-center gap-1.5">
|
||||
@@ -657,11 +657,11 @@ function isRecent(row) {
|
||||
|
||||
<!-- Badge contagem com cor da tag -->
|
||||
<span
|
||||
class="inline-flex items-center justify-center min-w-[22px] h-[22px] px-1 rounded-full font-bold text-[0.68rem] flex-shrink-0"
|
||||
class="inline-flex items-center justify-center min-w-[22px] h-[22px] px-1 rounded-full font-bold text-[0.68rem] shrink-0"
|
||||
:style="{ background: `${t.cor ? (t.cor.startsWith('#') ? t.cor : '#' + t.cor) : '#6366f1'}18`, color: t.cor ? (t.cor.startsWith('#') ? t.cor : '#' + t.cor) : '#6366f1' }"
|
||||
>{{ Number(t.pacientes_count ?? 0) }}</span
|
||||
>
|
||||
<i class="pi pi-chevron-right text-[0.6rem] opacity-30 group-hover:opacity-100 transition-all duration-150 flex-shrink-0" :style="{ color: 'var(--text-color-secondary)' }" />
|
||||
<i class="pi pi-chevron-right text-[0.6rem] opacity-30 group-hover:opacity-100 transition-all duration-150 shrink-0" :style="{ color: 'var(--text-color-secondary)' }" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -787,7 +787,7 @@ function isRecent(row) {
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-9 h-9 rounded-lg flex items-center justify-center text-white font-bold text-base flex-shrink-0" :style="{ background: modalTagHex }">
|
||||
<div class="w-9 h-9 rounded-lg flex items-center justify-center text-white font-bold text-base shrink-0" :style="{ background: modalTagHex }">
|
||||
{{ (modalPacientes.tag?.nome || '?')[0].toUpperCase() }}
|
||||
</div>
|
||||
<div>
|
||||
@@ -806,7 +806,7 @@ function isRecent(row) {
|
||||
</IconField>
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-semibold" :style="{ background: `${modalTagHex}18`, color: modalTagHex }">{{ modalPacientes.items.length }} paciente(s)</span>
|
||||
<Button icon="pi pi-refresh" outlined class="h-8 w-8 rounded-full flex-shrink-0" :style="{ borderColor: modalTagHex, color: modalTagHex }" @click="recarregarModalPacientes" />
|
||||
<Button icon="pi pi-refresh" outlined class="h-8 w-8 rounded-full shrink-0" :style="{ borderColor: modalTagHex, color: modalTagHex }" @click="recarregarModalPacientes" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user