This commit is contained in:
Leonardo
2026-03-06 06:37:13 -03:00
parent d58dc21297
commit f733db8436
146 changed files with 43436 additions and 12779 deletions

View File

@@ -2,6 +2,8 @@
import { computed, ref } from 'vue'
import { useRouter } from 'vue-router'
import Popover from 'primevue/popover'
import { sessionUser, sessionRole } from '@/app/session'
import { supabase } from '@/lib/supabase/client'
@@ -13,7 +15,7 @@ const pop = ref(null)
// ------------------------------------------------------
// RBAC (Tenant): fonte da verdade para permissões por papel
// ------------------------------------------------------
const { role, canSee, isPatient } = useRoleGuard()
const { role, canSee } = useRoleGuard()
// ------------------------------------------------------
// UI labels (nome/iniciais)
@@ -33,22 +35,21 @@ const label = computed(() => {
/**
* sublabel:
* Aqui eu recomendo exibir o papel do TENANT (role do useRoleGuard),
* porque é ele que realmente governa a UI dentro da clínica.
*
* Se você preferir manter sessionRole como rótulo "global", ok,
* mas isso pode confundir quando o usuário estiver em contextos diferentes.
* Prefere exibir o papel do TENANT (role do useRoleGuard),
* porque governa a UI dentro da clínica.
*/
const sublabel = computed(() => {
const r = role.value || sessionRole.value
if (!r) return 'Sessão'
// tenant roles (confirmados no banco): tenant_admin | therapist | patient
if (r === 'tenant_admin') return 'Administrador'
// tenant roles
if (r === 'clinic_admin' || r === 'tenant_admin' || r === 'admin') return 'Administrador'
if (r === 'therapist') return 'Terapeuta'
if (r === 'patient') return 'Paciente'
// fallback (caso venha algo diferente)
// portal/global roles
if (r === 'portal_user') return 'Portal'
if (r === 'patient') return 'Portal' // legado (caso ainda exista em algum lugar)
return r
})
@@ -60,69 +61,52 @@ function toggle (e) {
}
function close () {
try {
pop.value?.hide()
} catch {}
try { pop.value?.hide() } catch {}
}
// ------------------------------------------------------
// Navegação segura (NAME com fallback)
// Navegação segura (resolve antes; fallback se não existir)
// ------------------------------------------------------
async function safePush (target, fallback) {
try {
await router.push(target)
} catch (e) {
// fallback quando o "name" não existe no router
if (fallback) {
try {
await router.push(fallback)
} catch {
await router.push('/')
}
} else {
await router.push('/')
}
const r = router.resolve(target)
if (r?.matched?.length) return await router.push(target)
} catch {}
if (fallback) {
try { return await router.push(fallback) } catch {}
}
return router.push('/')
}
// ------------------------------------------------------
// Actions
// ------------------------------------------------------
function goMyProfile () {
close()
// Navegação segura para Account → Profile
safePush(
{ name: 'account-profile' },
'/account/profile'
)
safePush({ name: 'account-profile' }, '/account/profile')
}
function goSettings () {
close()
// ✅ Decide por RBAC (tenant role), não por sessionRole
// ✅ Configurações é RBAC (quem pode ver, vê)
if (canSee('settings.view')) {
router.push({ name: 'ConfiguracoesAgenda' })
return
return safePush({ name: 'ConfiguracoesAgenda' }, '/admin/settings') // fallback genérico
}
// Se não pode ver configurações, manda paciente pro portal.
// (Se amanhã você criar outro papel, esta regra continua segura.)
if (isPatient.value) {
router.push('/patient/portal')
return
}
router.push('/')
// ✅ quem não pode (ex.: paciente), manda pro portal correto
return safePush({ name: 'portal-sessoes' }, '/portal')
}
function goSecurity () {
close()
// ✅ 1) tenta por NAME (recomendado)
// ✅ 2) fallback: caminhos mais prováveis do teu projeto
// Ajuste/defina a rota no router como name: 'AdminSecurity' para ficar perfeito
safePush(
{ name: 'AdminSecurity' },
'/admin/settings/security'
// ✅ Segurança é "Account": todos podem acessar
return safePush(
{ name: 'account-security' },
'/account/security'
)
}
@@ -147,9 +131,10 @@ async function signOut () {
>
<!-- avatar -->
<img
v-if="sessionUser.value?.user_metadata?.avatar_url"
:src="sessionUser.value.user_metadata.avatar_url"
v-if="sessionUser?.user_metadata?.avatar_url"
:src="sessionUser.user_metadata.avatar_url"
class="h-9 w-9 rounded-xl object-cover border border-[var(--surface-border)]"
alt="avatar"
/>
<div
v-else