Ajuste rotas, Menus, Layout, Permissãoes UserRoleGuard

This commit is contained in:
Leonardo
2026-02-24 12:04:59 -03:00
parent b1c0cb47c0
commit d58dc21297
15 changed files with 1925 additions and 259 deletions

View File

@@ -5,13 +5,19 @@ import { useRouter } from 'vue-router'
import { sessionUser, sessionRole } from '@/app/session'
import { supabase } from '@/lib/supabase/client'
import { useRoleGuard } from '@/composables/useRoleGuard'
const router = useRouter()
const pop = ref(null)
function isAdminRole (r) {
return r === 'admin' || r === 'tenant_admin'
}
// ------------------------------------------------------
// RBAC (Tenant): fonte da verdade para permissões por papel
// ------------------------------------------------------
const { role, canSee, isPatient } = useRoleGuard()
// ------------------------------------------------------
// UI labels (nome/iniciais)
// ------------------------------------------------------
const initials = computed(() => {
const name = sessionUser.value?.user_metadata?.full_name || sessionUser.value?.email || ''
const parts = String(name).trim().split(/\s+/).filter(Boolean)
@@ -25,15 +31,30 @@ const label = computed(() => {
return name || sessionUser.value?.email || 'Conta'
})
/**
* 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.
*/
const sublabel = computed(() => {
const r = sessionRole.value
const r = role.value || sessionRole.value
if (!r) return 'Sessão'
if (isAdminRole(r)) return 'Administrador'
// tenant roles (confirmados no banco): tenant_admin | therapist | patient
if (r === 'tenant_admin') return 'Administrador'
if (r === 'therapist') return 'Terapeuta'
if (r === 'patient') return 'Paciente'
// fallback (caso venha algo diferente)
return r
})
// ------------------------------------------------------
// Popover helpers
// ------------------------------------------------------
function toggle (e) {
pop.value?.toggle(e)
}
@@ -44,35 +65,9 @@ function close () {
} catch {}
}
function goMyProfile() {
close()
// Navegação segura para Account → Profile
safePush(
{ name: 'account-profile' },
'/account/profile'
)
}
function goSettings () {
close()
const r = sessionRole.value
if (isAdminRole(r) || r === 'therapist') {
// rota por name (como você já usa)
router.push({ name: 'ConfiguracoesAgenda' })
return
}
if (r === 'patient') {
router.push('/patient/portal')
return
}
router.push('/')
}
// ------------------------------------------------------
// Navegação segura (NAME com fallback)
// ------------------------------------------------------
async function safePush (target, fallback) {
try {
await router.push(target)
@@ -90,6 +85,35 @@ async function safePush (target, fallback) {
}
}
function goMyProfile () {
close()
// Navegação segura para Account → Profile
safePush(
{ name: 'account-profile' },
'/account/profile'
)
}
function goSettings () {
close()
// ✅ Decide por RBAC (tenant role), não por sessionRole
if (canSee('settings.view')) {
router.push({ name: 'ConfiguracoesAgenda' })
return
}
// 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('/')
}
function goSecurity () {
close()
@@ -150,6 +174,7 @@ async function signOut () {
<Popover ref="pop" appendTo="body">
<div class="min-w-[220px] p-1">
<Button
v-if="canSee('settings.view')"
label="Configurações"
icon="pi pi-cog"
text
@@ -164,14 +189,14 @@ async function signOut () {
class="w-full justify-start"
@click="goSecurity"
/>
<Button
label="Meu Perfil"
icon="pi pi-user"
text
class="w-full justify-start"
@click="goMyProfile"
/>
<Button
label="Meu Perfil"
icon="pi pi-user"
text
class="w-full justify-start"
@click="goMyProfile"
/>
<div class="my-1 border-t border-[var(--surface-border)]" />
@@ -186,4 +211,4 @@ async function signOut () {
</div>
</Popover>
</div>
</template>
</template>