MelissaPerfil: pagina nativa 2-col com gamificacao no aside

Tira "Meu Perfil" do MelissaConfiguracoes (era embed cfg-perfil ->
ProfilePage.vue) e cria a /melissa/perfil como pagina nativa Melissa
no padrao das outras 2-col (sidebar + main).

Sidebar (mpr-side):
- Card "Sua evolucao" — gamificacao: nivel atual + barra de progresso
  + XP-to-next + 7 badges (earned/locked) + dicas do que falta
- Card "Avatar" — preview + upload (5MB max) + remover
- Footer: botao "Sair da conta" (com Confirm dialog)

Main:
- Card Identidade: full_name + nickname + work_description (+ outro)
- Card Contato: phone (mask BR) + email read-only
- Card Bio: textarea
- Card Sites e Redes: site/IG/YT/FB/X + customSocials (add/remove)

O que ficou de fora (vs ProfilePage.vue):
- Aparencia (tema/cores) — vive no MelissaConfiguracoes Layout Melissa
- Layout Variant (Rail/Classic/Melissa) — irrelevante dentro do Melissa
- Trocar senha — empurrado pro cfg-seguranca
- Preferencias (idioma/timezone/notifs) — fora de escopo do MVP

Wire-up:
- MelissaLayout: import + render `<MelissaPerfil v-if=secaoAberta=='perfil'>`
- 'perfil' sai de MELISSA_CONFIG_ALIASES, entra em MELISSA_NON_CONFIG_SLUGS
- SECOES.perfil descricao atualizada
- MelissaConfiguracoes: cfg-perfil removido de COMPONENT_MAP, ROUTE_ALIASES
  e do grupo "Conta" (continua com Plano + Negocio + Seguranca)

Logica de load/save espelhada do ProfilePage (auth.user_metadata +
profiles + storage avatars), compativel com a /account/perfil legacy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Leonardo
2026-05-06 15:06:22 -03:00
parent 44135a961f
commit abd4f8f34c
3 changed files with 1466 additions and 10 deletions
+6 -7
View File
@@ -39,7 +39,6 @@ const emit = defineEmits(['close']);
// existir, senão a key como-é.
const ROUTE_ALIASES = {
aparencia: 'aparencia',
perfil: 'cfg-perfil',
plano: 'cfg-plano',
negocio: 'cfg-negocio',
seguranca: 'cfg-seguranca',
@@ -99,7 +98,7 @@ const COMPONENT_MAP = {
'cfg-recursos-extras': defineAsyncComponent(() => import('@/layout/configuracoes/ConfiguracoesRecursosExtrasPage.vue')),
'cfg-auditoria': defineAsyncComponent(() => import('@/layout/configuracoes/AuditoriaPage.vue')),
// Conta (páginas pessoais que vivem em /account/*)
'cfg-perfil': defineAsyncComponent(() => import('@/views/pages/account/ProfilePage.vue')),
// 'cfg-perfil' removido — virou pagina nativa MelissaPerfil em /melissa/perfil
'cfg-plano': defineAsyncComponent(() => import('@/views/pages/billing/TherapistMeuPlanoPage.vue')),
'cfg-negocio': defineAsyncComponent(() => import('@/views/pages/account/Negociopage.vue')),
'cfg-seguranca': defineAsyncComponent(() => import('@/views/pages/auth/SecurityPage.vue'))
@@ -151,13 +150,13 @@ const grupos = [
{
key: 'conta',
label: 'Conta',
desc: 'Perfil pessoal, plano contratado, dados do negócio e segurança.',
desc: 'Plano contratado, dados do negócio e segurança.',
icon: 'pi pi-user',
items: [
{ key: 'cfg-perfil', label: 'Meu Perfil', desc: 'Nome, avatar, redes sociais e preferências de aparência.', icon: 'pi pi-user' },
{ key: 'cfg-plano', label: 'Meu Plano', desc: 'Plano contratado, limites de uso e fatura.', icon: 'pi pi-credit-card' },
{ key: 'cfg-negocio', label: 'Meu Negócio', desc: 'Dados do negócio, faturamento e branding.', icon: 'pi pi-briefcase' },
{ key: 'cfg-seguranca', label: 'Segurança', desc: 'Senha, dispositivos confiáveis e sessões ativas.', icon: 'pi pi-shield' }
// "Meu Perfil" virou pagina nativa em /melissa/perfil (MelissaPerfil)
{ key: 'cfg-plano', label: 'Meu Plano', desc: 'Plano contratado, limites de uso e fatura.', icon: 'pi pi-credit-card' },
{ key: 'cfg-negocio', label: 'Meu Negócio', desc: 'Dados do negócio, faturamento e branding.', icon: 'pi pi-briefcase' },
{ key: 'cfg-seguranca', label: 'Segurança', desc: 'Senha, dispositivos confiáveis e sessões ativas.', icon: 'pi pi-shield' }
]
},
{
+11 -3
View File
@@ -33,6 +33,7 @@ import MelissaConversas from './MelissaConversas.vue';
import MelissaTags from './MelissaTags.vue';
import MelissaGrupos from './MelissaGrupos.vue';
import MelissaConfiguracoes from './MelissaConfiguracoes.vue';
import MelissaPerfil from './MelissaPerfil.vue';
import MelissaEmbed from './MelissaEmbed.vue';
import MelissaCadastrosRecebidos from './MelissaCadastrosRecebidos.vue';
import MelissaAgendamentosRecebidos from './MelissaAgendamentosRecebidos.vue';
@@ -163,8 +164,9 @@ const SECOES = {
medicos: { label: 'Médicos e referências', icon: 'pi pi-user-edit', descricao: 'Profissionais que encaminham ou recebem pacientes.' },
// Pagina unificada do Layout Melissa (Aparencia + Fundo + Relogio + Cronometro)
aparencia: { label: 'Layout Melissa', icon: 'pi pi-palette', descricao: 'Aparência, plano de fundo, relógio e cronômetro do resumo.' },
// Atalhos de Conta — todas montam o MelissaConfiguracoes com a seção embed pré-selecionada
perfil: { label: 'Meu Perfil', icon: 'pi pi-user', descricao: 'Dados pessoais, avatar e preferências.' },
// Pagina nativa do perfil (MelissaPerfil) — saiu do MelissaConfiguracoes
perfil: { label: 'Meu Perfil', icon: 'pi pi-user', descricao: 'Identidade, contato, bio, redes — gamificacao no aside.' },
// Atalhos de Conta restantes — todos montam o MelissaConfiguracoes com a seção embed pré-selecionada
plano: { label: 'Meu Plano', icon: 'pi pi-credit-card', descricao: 'Plano contratado, limites e fatura.' },
negocio: { label: 'Meu Negócio', icon: 'pi pi-briefcase', descricao: 'Dados do negócio, faturamento e branding.' },
seguranca: { label: 'Segurança', icon: 'pi pi-shield', descricao: 'Senha, dispositivos confiáveis e sessões.' },
@@ -193,12 +195,13 @@ const MELISSA_NON_CONFIG_SLUGS = new Set([
'tags', 'grupos', 'cadastros-recebidos', 'medicos', 'agendamentos-recebidos',
'link-externo', 'notificacoes', 'financeiro', 'financeiro-lancamentos',
'documentos', 'documentos-templates', 'relatorios',
'perfil',
...MELISSA_EMBED_KEYS
]);
// Aliases "bonitos" + INLINE_KEYS reconhecidos pelo MelissaConfiguracoes.
// Mantidos sincronizados com o ROUTE_ALIASES/INLINE_KEYS de lá.
const MELISSA_CONFIG_ALIASES = new Set([
'aparencia', 'perfil', 'plano', 'negocio', 'seguranca', 'bloqueios',
'aparencia', 'plano', 'negocio', 'seguranca', 'bloqueios',
'fundo', 'relogio', 'cronometro'
]);
function isMelissaConfigRoute(slug) {
@@ -2207,6 +2210,11 @@ function onKeydown(e) {
@close="fecharSecao"
/>
<MelissaPerfil
v-if="layoutReady && secaoAberta === 'perfil'"
@close="fecharSecao"
/>
<MelissaConfiguracoes
v-if="layoutReady && isMelissaConfigRoute(secaoAberta)"
:secao-rota="secaoAberta"
File diff suppressed because it is too large Load Diff