Ajuste em Massa - Paciente, Terapeuta, Clinica e Admin - Inicio agenda
This commit is contained in:
+166
-40
@@ -2,68 +2,76 @@
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { supabase } from '../../lib/supabase/client' // ajuste se o caminho for outro
|
||||
import { useTenantStore } from '@/stores/tenantStore'
|
||||
|
||||
const router = useRouter()
|
||||
const tenant = useTenantStore()
|
||||
|
||||
const checking = ref(true)
|
||||
const userEmail = ref('')
|
||||
const role = ref(null)
|
||||
const role = ref(null) // aqui vai guardar o role REAL do tenant: clinic_admin/therapist/patient
|
||||
|
||||
const TEST_ACCOUNTS = {
|
||||
admin: { email: 'admin@agenciapsi.com.br', password: '123Mudar@' },
|
||||
clinic_admin: { email: 'clinic@agenciapsi.com.br', password: '123Mudar@' },
|
||||
therapist: { email: 'therapist@agenciapsi.com.br', password: '123Mudar@' },
|
||||
patient: { email: 'patient@agenciapsi.com.br', password: '123Mudar@' }
|
||||
patient: { email: 'patient@agenciapsi.com.br', password: '123Mudar@' },
|
||||
saas: { email: 'saas@agenciapsi.com.br', password: '123Mudar@' }
|
||||
}
|
||||
|
||||
|
||||
function roleToPath(r) {
|
||||
if (r === 'admin') return '/admin'
|
||||
function roleToPath (r) {
|
||||
// ✅ role REAL (tenant_members via my_tenants)
|
||||
if (r === 'clinic_admin' || r === 'tenant_admin' || r === 'admin') return '/admin'
|
||||
if (r === 'therapist') return '/therapist'
|
||||
if (r === 'patient') return '/patient'
|
||||
if (r === 'patient') return '/portal'
|
||||
return '/'
|
||||
}
|
||||
|
||||
async function fetchMyRole() {
|
||||
async function isSaasAdmin () {
|
||||
const { data: userData, error: userErr } = await supabase.auth.getUser()
|
||||
if (userErr) return null
|
||||
if (userErr) return false
|
||||
const user = userData?.user
|
||||
if (!user) return null
|
||||
|
||||
userEmail.value = user.email || ''
|
||||
if (!user?.id) return false
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('profiles')
|
||||
.select('role')
|
||||
.eq('id', user.id)
|
||||
.single()
|
||||
.from('saas_admins')
|
||||
.select('user_id')
|
||||
.eq('user_id', user.id)
|
||||
.maybeSingle()
|
||||
|
||||
if (error) return null
|
||||
return data?.role || null
|
||||
if (error) return false
|
||||
return !!data
|
||||
}
|
||||
|
||||
async function go(area) {
|
||||
// Se já estiver logado, respeita role real (não o card)
|
||||
// ✅ carrega tenant/role real (my_tenants) e atualiza UI
|
||||
async function syncTenantRole () {
|
||||
await tenant.loadSessionAndTenant()
|
||||
role.value = tenant.activeRole || null
|
||||
return role.value
|
||||
}
|
||||
|
||||
async function go (area) {
|
||||
// Se já estiver logado:
|
||||
const { data: sessionData } = await supabase.auth.getSession()
|
||||
const session = sessionData?.session
|
||||
|
||||
if (session) {
|
||||
const r = role.value || (await fetchMyRole())
|
||||
userEmail.value = session.user?.email || userEmail.value || ''
|
||||
|
||||
// ✅ se for SaaS master, SEMPRE manda pra /saas (independente do card clicado)
|
||||
const saas = await isSaasAdmin()
|
||||
if (saas) return router.push('/saas')
|
||||
|
||||
const r = role.value || (await syncTenantRole())
|
||||
if (!r) return router.push('/auth/login')
|
||||
return router.push(roleToPath(r))
|
||||
}
|
||||
|
||||
// Se não estiver logado, manda pro login guardando a intenção
|
||||
sessionStorage.setItem('intended_area', area) // admin/therapist/patient
|
||||
sessionStorage.setItem('intended_area', area) // clinic_admin/therapist/patient/saas
|
||||
|
||||
// ✅ Prefill de login (apenas DEV)
|
||||
const DEV_PREFILL = import.meta.env.DEV
|
||||
if (DEV_PREFILL) {
|
||||
const TEST_ACCOUNTS = {
|
||||
admin: { email: 'admin@agenciapsi.com.br', password: '123Mudar@' },
|
||||
therapist: { email: 'therapist@agenciapsi.com.br', password: '123Mudar@' },
|
||||
patient: { email: 'patient@agenciapsi.com.br', password: '123Mudar@' }
|
||||
}
|
||||
|
||||
const acc = TEST_ACCOUNTS[area]
|
||||
if (acc) {
|
||||
sessionStorage.setItem('login_prefill_email', acc.email)
|
||||
@@ -77,15 +85,32 @@ async function go(area) {
|
||||
router.push('/auth/login')
|
||||
}
|
||||
|
||||
async function goMyPanel() {
|
||||
async function goMyPanel () {
|
||||
if (!role.value) return
|
||||
|
||||
// ✅ se for SaaS master, sempre /saas
|
||||
const saas = await isSaasAdmin()
|
||||
if (saas) return router.push('/saas')
|
||||
|
||||
router.push(roleToPath(role.value))
|
||||
}
|
||||
|
||||
async function logout() {
|
||||
await supabase.auth.signOut()
|
||||
role.value = null
|
||||
userEmail.value = ''
|
||||
async function logout () {
|
||||
try {
|
||||
await supabase.auth.signOut()
|
||||
} finally {
|
||||
role.value = null
|
||||
userEmail.value = ''
|
||||
|
||||
// limpa qualquer intenção pendente
|
||||
sessionStorage.removeItem('redirect_after_login')
|
||||
sessionStorage.removeItem('intended_area')
|
||||
|
||||
// ✅ força redirecionamento para HomeCards (/)
|
||||
router.replace('/')
|
||||
// Use router.replace('/') e não push,
|
||||
// assim o usuário não consegue voltar com o botão "voltar" para uma rota protegida.
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
@@ -94,7 +119,17 @@ onMounted(async () => {
|
||||
const session = sessionData?.session
|
||||
|
||||
if (session) {
|
||||
role.value = await fetchMyRole()
|
||||
userEmail.value = session.user?.email || ''
|
||||
|
||||
// ✅ se for SaaS master, manda direto pro SaaS
|
||||
const saas = await isSaasAdmin()
|
||||
if (saas) {
|
||||
router.replace('/saas')
|
||||
return
|
||||
}
|
||||
|
||||
// ✅ role REAL vem do tenantStore (my_tenants)
|
||||
role.value = await syncTenantRole()
|
||||
|
||||
// Se está logado e tem role, manda direto pro painel
|
||||
if (role.value) {
|
||||
@@ -201,15 +236,15 @@ onMounted(async () => {
|
||||
<div class="px-8 pb-10">
|
||||
<div class="grid grid-cols-12 gap-6">
|
||||
|
||||
<!-- ADMIN -->
|
||||
<div class="col-span-12 md:col-span-4">
|
||||
<!-- CLÍNICA (antigo ADMIN) -->
|
||||
<div class="col-span-12 md:col-span-3">
|
||||
<div
|
||||
class="group h-full cursor-pointer rounded-2xl border border-[var(--surface-border)] bg-[var(--surface-ground)] p-6 transition-all hover:shadow-xl hover:-translate-y-1"
|
||||
@click="go('admin')"
|
||||
@click="go('clinic_admin')"
|
||||
>
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="text-xl font-semibold text-[var(--text-color)]">
|
||||
Admin
|
||||
Clínica
|
||||
</div>
|
||||
<i class="pi pi-building text-sm opacity-70" />
|
||||
</div>
|
||||
@@ -225,7 +260,7 @@ onMounted(async () => {
|
||||
</div>
|
||||
|
||||
<!-- TERAPEUTA -->
|
||||
<div class="col-span-12 md:col-span-4">
|
||||
<div class="col-span-12 md:col-span-3">
|
||||
<div
|
||||
class="group h-full cursor-pointer rounded-2xl border border-[var(--surface-border)] bg-[var(--surface-ground)] p-6 transition-all hover:shadow-xl hover:-translate-y-1"
|
||||
@click="go('therapist')"
|
||||
@@ -248,7 +283,7 @@ onMounted(async () => {
|
||||
</div>
|
||||
|
||||
<!-- PACIENTE -->
|
||||
<div class="col-span-12 md:col-span-4">
|
||||
<div class="col-span-12 md:col-span-3">
|
||||
<div
|
||||
class="group h-full cursor-pointer rounded-2xl border border-[var(--surface-border)] bg-[var(--surface-ground)] p-6 transition-all hover:shadow-xl hover:-translate-y-1"
|
||||
@click="go('patient')"
|
||||
@@ -270,7 +305,98 @@ onMounted(async () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- SAAS MASTER -->
|
||||
<div class="col-span-12 md:col-span-3">
|
||||
<div
|
||||
class="group h-full cursor-pointer rounded-2xl border border-[var(--surface-border)] bg-[var(--surface-ground)] p-6 transition-all hover:shadow-xl hover:-translate-y-1"
|
||||
@click="go('saas')"
|
||||
>
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="text-xl font-semibold text-[var(--text-color)]">
|
||||
SaaS (Master)
|
||||
</div>
|
||||
<i class="pi pi-shield text-sm opacity-70" />
|
||||
</div>
|
||||
|
||||
<div class="text-sm text-[var(--text-color-secondary)] leading-relaxed">
|
||||
Acesso global: planos, assinaturas, tenants e saúde da plataforma.
|
||||
</div>
|
||||
|
||||
<div class="mt-6 text-sm font-medium text-primary opacity-80 group-hover:opacity-100 transition">
|
||||
Acessar painel →
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- DEV – Usuários cadastrados -->
|
||||
<div class="mt-10 w-full rounded-2xl border border-[var(--surface-border)] bg-[var(--surface-ground)] p-6">
|
||||
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="text-sm font-semibold text-[var(--text-color)]">
|
||||
Usuários do ambiente (Desenvolvimento)
|
||||
</div>
|
||||
<span class="text-xs text-[var(--text-color-secondary)] opacity-70">
|
||||
Identificadores internos
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full text-xs md:text-sm">
|
||||
<thead>
|
||||
<tr class="text-left border-b border-[var(--surface-border)]">
|
||||
<th class="py-2 pr-4 font-medium text-[var(--text-color-secondary)]">ID</th>
|
||||
<th class="py-2 font-medium text-[var(--text-color-secondary)]">E-mail</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-[var(--text-color)]">
|
||||
|
||||
<tr class="border-b border-[var(--surface-border)]/60">
|
||||
<td class="py-2 pr-4 font-mono opacity-80">
|
||||
40a4b683-a0c9-4890-a201-20faf41fca06
|
||||
</td>
|
||||
<td class="py-2">
|
||||
saas@agenciapsi.com.br
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="border-b border-[var(--surface-border)]/60">
|
||||
<td class="py-2 pr-4 font-mono opacity-80">
|
||||
523003e7-17ab-4375-b912-040027a75c22
|
||||
</td>
|
||||
<td class="py-2">
|
||||
patient@agenciapsi.com.br
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="border-b border-[var(--surface-border)]/60">
|
||||
<td class="py-2 pr-4 font-mono opacity-80">
|
||||
816b24fe-a0c3-4409-b79b-c6c0a6935d03
|
||||
</td>
|
||||
<td class="py-2">
|
||||
clinic@agenciapsi.com.br
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td class="py-2 pr-4 font-mono opacity-80">
|
||||
824f125c-55bb-40f5-a8c4-7a33618b91c7
|
||||
</td>
|
||||
<td class="py-2">
|
||||
therapist@agenciapsi.com.br
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 text-[11px] text-[var(--text-color-secondary)] opacity-70">
|
||||
Estes usuários existem apenas para fins de teste no ambiente de desenvolvimento.
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Rodapé explicativo -->
|
||||
<div class="mt-10 text-center text-xs text-[var(--text-color-secondary)] opacity-80">
|
||||
|
||||
Reference in New Issue
Block a user