import { useEffect, useMemo, useState } from 'react' import { FeatureBadge, FeatureCallout } from '../components/FeatureState.jsx' import { featurePanelClass } from '../components/featureStateStyles.js' import { availabilityRepository } from '../repositories/availabilityRepository.js' import { professionalRepository } from '../repositories/professionalRepository.js' const cardClass = 'rounded-2xl border border-[#404040] bg-[#262626] shadow-sm' const weekdays = [ { label: 'Seg', value: 1 }, { label: 'Ter', value: 2 }, { label: 'Qua', value: 3 }, { label: 'Qui', value: 4 }, { label: 'Sex', value: 5 }, ] export function TeamPage({ navigate }) { const [professionals, setProfessionals] = useState([]) const [availability, setAvailability] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState('') useEffect(() => { let active = true async function loadTeam() { try { setError('') const [professionalsData, availabilityData] = await Promise.all([ professionalRepository.getAll(), availabilityRepository.getAll({ active: true }), ]) if (!active) return setProfessionals(professionalsData) setAvailability(availabilityData) } catch (loadError) { if (!active) return setError(loadError.message || 'Erro ao carregar profissionais e disponibilidade.') } finally { if (active) setLoading(false) } } loadTeam() return () => { active = false } }, []) const availabilityByDoctor = useMemo(() => groupAvailabilityByDoctor(availability), [availability]) return (
{error ? ( ) : null}

Profissionais

Equipe, agenda e cobertura operacional da clínica.

{loading ? (

Carregando profissionais...

) : null}
{professionals.map((professional) => (
{initials(professional.name)}

{professional.name}

{professional.role}

))}

Mapa de cobertura

Disponibilidades ativas cadastradas em /rest/v1/doctor_availability.

{['Profissional', ...weekdays.map((weekday) => weekday.label)].map((label) => (
{label}
))}
{professionals.map((professional) => (
{professional.name}
{weekdays.map((weekday) => (
{formatCoverage(availabilityByDoctor.get(String(professional.id))?.[weekday.value])}
))}
))}
) } function Info({ label, value }) { return (
{label}
{value}
) } function StatusPill({ status }) { const className = status === 'Disponivel' ? 'bg-emerald-500/20 text-emerald-400' : status === 'Em atendimento' ? 'bg-amber-500/20 text-amber-400' : 'bg-blue-500/20 text-blue-400' return {status} } function initials(name) { return String(name || '') .replace(/^(Dr\.|Dra\.|Nutri\.|Enf\.)\s+/i, '') .split(' ') .slice(0, 2) .map((part) => part[0]) .join('') .toUpperCase() } function groupAvailabilityByDoctor(items) { const grouped = new Map() for (const item of items) { const doctorId = String(item.doctorId) const current = grouped.get(doctorId) || {} current[item.weekday] = [...(current[item.weekday] || []), item] grouped.set(doctorId, current) } return grouped } function formatCoverage(items = []) { const activeItems = items.filter((item) => item.active !== false) if (!activeItems.length) return 'Sem regra' return activeItems .map((item) => `${formatTime(item.startTime)}-${formatTime(item.endTime)}`) .join(', ') } function formatTime(value) { return String(value || '').slice(0, 5) }