Replace hardcoded user with live profile data

This commit is contained in:
EdilbertoC
2026-04-28 12:46:39 -03:00
parent d496494b3e
commit 000abb39ac
15 changed files with 993 additions and 358 deletions

View File

@@ -1,5 +1,6 @@
import { useMemo, useState } from 'react'
import { useEffect, useMemo, useState } from 'react'
import { profileRepository } from '../repositories/profileRepository.js'
import { BrandLogo } from './Brand.jsx'
import { FeatureLegend } from './FeatureState.jsx'
@@ -7,16 +8,16 @@ const navItems = [
{ href: '/inicio', label: 'Painel', icon: 'pulse', activePaths: ['/inicio', '/home', '/dashboard'] },
{ href: '/agenda', label: 'Agenda', icon: 'calendar' },
{ href: '/pacientes', label: 'Pacientes', icon: 'users', exact: true },
{ href: '/prontuario', label: 'Prontuário', icon: 'file' },
{ href: '/prontuario', label: 'Prontuario', icon: 'file' },
{ href: '/laudos', label: 'Laudos', icon: 'clipboard' },
{
href: '/camunicacao',
label: 'Comunicação',
label: 'Comunicacao',
icon: 'message',
activePaths: ['/camunicacao', '/comunicacao', '/mensagens'],
},
{ href: '/relatorios', label: 'Relatórios', icon: 'chart' },
{ href: '/configuracoes', label: 'Configurações', icon: 'settings', activePaths: ['/configuracoes', '/config'] },
{ href: '/relatorios', label: 'Relatorios', icon: 'chart' },
{ href: '/configuracoes', label: 'Configuracoes', icon: 'settings', activePaths: ['/configuracoes', '/config'] },
]
const titles = {
@@ -27,20 +28,21 @@ const titles = {
'/consultas': 'Consultas',
'/laudos': 'Laudos',
'/pacientes': 'Pacientes',
'/prontuario': 'Prontuário',
'/camunicacao': 'Comunicação',
'/comunicacao': 'Comunicação',
'/mensagens': 'Comunicação',
'/relatorios': 'Relatórios',
'/prontuario': 'Prontuario',
'/camunicacao': 'Comunicacao',
'/comunicacao': 'Comunicacao',
'/mensagens': 'Comunicacao',
'/relatorios': 'Relatorios',
'/profissionais': 'Profissionais',
'/perfil': 'Perfil',
'/configuracoes': 'Configurações',
'/config': 'Configurações',
'/configuracoes': 'Configuracoes',
'/config': 'Configuracoes',
}
export function AppShell({ children, currentPath, navigate, routeTitle }) {
const [menuOpen, setMenuOpen] = useState(false)
const [quickSearch, setQuickSearch] = useState('')
const [viewerProfile, setViewerProfile] = useState({ name: 'Usuario', role: 'Usuario do Sistema' })
const pageTitle = useMemo(() => {
if (currentPath.startsWith('/pacientes/') && routeTitle) {
@@ -50,6 +52,25 @@ export function AppShell({ children, currentPath, navigate, routeTitle }) {
return routeTitle || titles[currentPath] || 'MediConnect'
}, [currentPath, routeTitle])
useEffect(() => {
let active = true
profileRepository.getCurrentUserProfile()
.then((profile) => {
if (!active || !profile) return
setViewerProfile({
name: profile.name || 'Usuario',
role: profile.role || 'Usuario do Sistema',
})
})
.catch(() => {})
return () => {
active = false
}
}, [])
function goTo(path) {
setMenuOpen(false)
navigate(path)
@@ -96,8 +117,8 @@ export function AppShell({ children, currentPath, navigate, routeTitle }) {
onClick={() => goTo('/perfil')}
type="button"
>
<p className="truncate text-xs font-semibold text-[#e5e5e5]">Dr. Henrique Cardoso</p>
<p className="mt-0.5 truncate text-[11px] leading-4 text-[#a3a3a3]">Médico Clínico Geral</p>
<p className="truncate text-xs font-semibold text-[#e5e5e5]">{viewerProfile.name}</p>
<p className="mt-0.5 truncate text-[11px] leading-4 text-[#a3a3a3]">{viewerProfile.role}</p>
</button>
</div>
</aside>
@@ -129,7 +150,7 @@ export function AppShell({ children, currentPath, navigate, routeTitle }) {
aria-label="Busca rapida"
className="h-[38px] w-full rounded-sm border border-[#404040] bg-[#303030] py-2 pl-10 pr-4 text-sm text-[#e5e5e5] outline-none transition placeholder:text-[#a3a3a3] focus:border-[#3b82f6] focus:ring-2 focus:ring-[#3b82f6]/20"
onChange={(event) => setQuickSearch(event.target.value)}
placeholder="Buscar paciente, prontuário..."
placeholder="Buscar paciente, prontuario..."
value={quickSearch}
/>
</div>
@@ -155,14 +176,14 @@ export function AppShell({ children, currentPath, navigate, routeTitle }) {
type="button"
>
<span className="grid size-8 shrink-0 place-items-center rounded-full border border-[#3b82f6]/30 bg-[#3b82f6]/15 text-xs font-bold text-[#3b82f6]">
HC
{getInitials(viewerProfile.name)}
</span>
<span className="hidden min-w-0 sm:block">
<span className="block truncate text-sm font-semibold leading-4 text-[#e5e5e5]">
Dr. Henrique Cardoso
{viewerProfile.name}
</span>
<span className="mt-0.5 block truncate text-[11px] font-medium leading-4 text-[#51a2ff]">
Médico(a)
{viewerProfile.role}
</span>
</span>
<ChevronDownIcon className="hidden size-4 text-[#a3a3a3] sm:block" />
@@ -335,3 +356,13 @@ function SearchIcon({ className = 'size-4' }) {
</svg>
)
}
function getInitials(name) {
return String(name || 'US')
.split(' ')
.filter(Boolean)
.slice(0, 2)
.map((part) => part[0])
.join('')
.toUpperCase()
}