first commit

This commit is contained in:
Leonardo
2026-02-18 22:36:45 -03:00
parent ec6b6ef53a
commit 676042268b
122 changed files with 26354 additions and 1615 deletions
+293
View File
@@ -0,0 +1,293 @@
<script setup>
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { supabase } from '../../lib/supabase/client' // ajuste se o caminho for outro
const router = useRouter()
const checking = ref(true)
const userEmail = ref('')
const role = ref(null)
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@' }
}
function roleToPath(r) {
if (r === 'admin') return '/admin'
if (r === 'therapist') return '/therapist'
if (r === 'patient') return '/patient'
return '/'
}
async function fetchMyRole() {
const { data: userData, error: userErr } = await supabase.auth.getUser()
if (userErr) return null
const user = userData?.user
if (!user) return null
userEmail.value = user.email || ''
const { data, error } = await supabase
.from('profiles')
.select('role')
.eq('id', user.id)
.single()
if (error) return null
return data?.role || null
}
async function go(area) {
// Se já estiver logado, respeita role real (não o card)
const { data: sessionData } = await supabase.auth.getSession()
const session = sessionData?.session
if (session) {
const r = role.value || (await fetchMyRole())
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
// ✅ 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)
sessionStorage.setItem('login_prefill_password', acc.password)
} else {
sessionStorage.removeItem('login_prefill_email')
sessionStorage.removeItem('login_prefill_password')
}
}
router.push('/auth/login')
}
async function goMyPanel() {
if (!role.value) return
router.push(roleToPath(role.value))
}
async function logout() {
await supabase.auth.signOut()
role.value = null
userEmail.value = ''
}
onMounted(async () => {
try {
const { data: sessionData } = await supabase.auth.getSession()
const session = sessionData?.session
if (session) {
role.value = await fetchMyRole()
// Se está logado e tem role, manda direto pro painel
if (role.value) {
router.replace(roleToPath(role.value))
return
}
}
} finally {
checking.value = false
}
})
</script>
<template>
<!-- Estado carregando sessão -->
<div
v-if="checking"
class="relative min-h-screen flex items-center justify-center bg-[var(--surface-ground)]"
>
<div class="text-[var(--text-color-secondary)] text-sm animate-pulse">
Verificando sessão
</div>
</div>
<!-- Página -->
<div
v-else
class="relative min-h-screen overflow-hidden bg-[var(--surface-ground)]"
>
<!-- fundo conceitual -->
<div class="pointer-events-none absolute inset-0">
<!-- grid sutil -->
<div
class="absolute inset-0 opacity-70"
style="
background-image:
linear-gradient(to right, rgba(255,255,255,.05) 1px, transparent 1px),
linear-gradient(to bottom, rgba(255,255,255,.05) 1px, transparent 1px);
background-size: 40px 40px;
mask-image: radial-gradient(ellipse at 50% 15%, rgba(0,0,0,.95), transparent 70%);
"
/>
<!-- halos -->
<div class="absolute -top-32 -right-32 h-[28rem] w-[28rem] rounded-full blur-3xl bg-indigo-400/10" />
<div class="absolute top-20 -left-32 h-[32rem] w-[32rem] rounded-full blur-3xl bg-emerald-400/10" />
<div class="absolute -bottom-36 right-24 h-[28rem] w-[28rem] rounded-full blur-3xl bg-fuchsia-400/10" />
</div>
<div class="relative flex items-center justify-center min-h-screen p-6">
<div class="w-full max-w-6xl">
<div class="overflow-hidden rounded-[2.75rem] border border-[var(--surface-border)] bg-[var(--surface-card)] shadow-2xl">
<!-- HEADER -->
<div class="px-8 pt-10 pb-8">
<div class="flex items-start justify-between gap-6">
<div>
<div class="text-3xl md:text-4xl font-semibold text-[var(--text-color)]">
Agência PSI
</div>
<div class="mt-2 text-[var(--text-color-secondary)] text-sm md:text-base">
Ambiente de acesso e testes de perfis
</div>
</div>
<div class="hidden md:flex items-center gap-2 text-xs text-[var(--text-color-secondary)]">
<span class="inline-block h-1.5 w-1.5 rounded-full bg-primary/60" />
Dev Mode
</div>
</div>
<div class="mt-8 h-px w-full bg-[var(--surface-border)] opacity-70" />
</div>
<!-- SE ESTIVER LOGADO -->
<div
v-if="role"
class="mx-8 mb-6 rounded-2xl border border-[var(--surface-border)] bg-[var(--surface-ground)] p-5 flex flex-col md:flex-row md:items-center md:justify-between gap-4"
>
<div>
<div class="font-semibold text-[var(--text-color)]">
Sessão ativa
</div>
<div class="text-sm text-[var(--text-color-secondary)] mt-1">
{{ userEmail }} perfil: <span class="font-medium">{{ role }}</span>
</div>
</div>
<div class="flex gap-3">
<Button
label="Ir para meu painel"
icon="pi pi-arrow-right"
@click="goMyPanel"
/>
<Button
label="Sair"
severity="secondary"
outlined
@click="logout"
/>
</div>
</div>
<!-- CARDS -->
<div class="px-8 pb-10">
<div class="grid grid-cols-12 gap-6">
<!-- ADMIN -->
<div class="col-span-12 md:col-span-4">
<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')"
>
<div class="flex items-center justify-between mb-4">
<div class="text-xl font-semibold text-[var(--text-color)]">
Admin
</div>
<i class="pi pi-building text-sm opacity-70" />
</div>
<div class="text-sm text-[var(--text-color-secondary)] leading-relaxed">
Gestão da clínica, controle de usuários, permissões, planos e configurações globais.
</div>
<div class="mt-6 text-sm font-medium text-primary opacity-80 group-hover:opacity-100 transition">
Acessar painel
</div>
</div>
</div>
<!-- TERAPEUTA -->
<div class="col-span-12 md:col-span-4">
<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')"
>
<div class="flex items-center justify-between mb-4">
<div class="text-xl font-semibold text-[var(--text-color)]">
Terapeuta
</div>
<i class="pi pi-calendar text-sm opacity-70" />
</div>
<div class="text-sm text-[var(--text-color-secondary)] leading-relaxed">
Agenda, prontuários, evolução clínica, gestão de pacientes e atendimentos.
</div>
<div class="mt-6 text-sm font-medium text-primary opacity-80 group-hover:opacity-100 transition">
Acessar painel
</div>
</div>
</div>
<!-- PACIENTE -->
<div class="col-span-12 md:col-span-4">
<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')"
>
<div class="flex items-center justify-between mb-4">
<div class="text-xl font-semibold text-[var(--text-color)]">
Paciente
</div>
<i class="pi pi-user text-sm opacity-70" />
</div>
<div class="text-sm text-[var(--text-color-secondary)] leading-relaxed">
Visualização de informações pessoais, documentos e interações com a clínica.
</div>
<div class="mt-6 text-sm font-medium text-primary opacity-80 group-hover:opacity-100 transition">
Acessar painel
</div>
</div>
</div>
</div>
<!-- Rodapé explicativo -->
<div class="mt-10 text-center text-xs text-[var(--text-color-secondary)] opacity-80">
Você será redirecionado para o login (se necessário) e, após autenticação,
encaminhado automaticamente ao painel correspondente.
</div>
</div>
</div>
<!-- assinatura visual -->
<div class="mt-6 flex items-center justify-center gap-2 text-xs text-[var(--text-color-secondary)] opacity-70">
<span class="inline-block h-1.5 w-1.5 rounded-full bg-primary/60" />
<span>Ambiente de desenvolvimento</span>
<span class="inline-block h-1.5 w-1.5 rounded-full bg-primary/60" />
</div>
</div>
</div>
</div>
</template>