"use client" import React, { useEffect, useMemo, useState } from 'react' import { useSearchParams, useRouter } from 'next/navigation' import { Button } from '@/components/ui/button' import { Card } from '@/components/ui/card' import { Toggle } from '@/components/ui/toggle' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' import { Badge } from '@/components/ui/badge' import { Avatar, AvatarFallback } from '@/components/ui/avatar' import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' import { Building2, Filter, Globe, HeartPulse, Languages, MapPin, ShieldCheck, Star, Stethoscope, ChevronRight, UserRound } from 'lucide-react' import { cn } from '@/lib/utils' import { buscarMedicos, getAvailableSlots, criarAgendamento, getUserInfo, buscarPacientes, type Medico, } from '@/lib/api' // ...existing code (tipagens locais de UI)... type TipoConsulta = 'teleconsulta' | 'local' // Utilidades de formatação/agenda const shortWeek = ['DOM.', 'SEG.', 'TER.', 'QUA.', 'QUI.', 'SEX.', 'SÁB.'] const monthPt = ['Jan','Fev','Mar','Abr','Mai','Jun','Jul','Ago','Set','Out','Nov','Dez'] const fmtDay = (d: Date) => `${d.getDate()} ${monthPt[d.getMonth()]}` type DayAgenda = { label: string; data: string; dateKey: string; horarios: Array<{ iso: string; label: string }> } const especialidadesHero = ['Psicólogo', 'Médico clínico geral', 'Pediatra', 'Dentista', 'Ginecologista', 'Veja mais'] export default function ResultadosClient() { const params = useSearchParams() const router = useRouter() // Filtros/controles da UI const [tipoConsulta, setTipoConsulta] = useState( params?.get('tipo') === 'presencial' ? 'local' : 'teleconsulta' ) const [especialidadeHero, setEspecialidadeHero] = useState(params?.get('especialidade') || 'Psicólogo') const [convenio, setConvenio] = useState('Todos') const [bairro, setBairro] = useState('Todos') // Estado dinâmico const [patientId, setPatientId] = useState(null) const [medicos, setMedicos] = useState([]) const [loadingMedicos, setLoadingMedicos] = useState(false) // agenda por médico e loading por médico const [agendaByDoctor, setAgendaByDoctor] = useState>({}) const [agendaLoading, setAgendaLoading] = useState>({}) const [agendasExpandida, setAgendasExpandida] = useState>({}) // Seleção para o Dialog de perfil completo const [medicoSelecionado, setMedicoSelecionado] = useState(null) const [abaDetalhe, setAbaDetalhe] = useState('experiencia') // Toast simples const [toast, setToast] = useState<{ type: 'success' | 'error', msg: string } | null>(null) const showToast = (type: 'success' | 'error', msg: string) => { setToast({ type, msg }) setTimeout(() => setToast(null), 3000) } // 1) Obter patientId a partir do usuário autenticado (email -> patients) useEffect(() => { let mounted = true ;(async () => { try { const info = await getUserInfo().catch(() => null) const uid = info?.user?.id ?? null const email = info?.user?.email ?? null if (!email) return const results = await buscarPacientes(email).catch(() => []) // preferir linha com user_id igual ao auth id const row = (results || []).find((p: any) => String(p.user_id) === String(uid)) || results?.[0] if (row && mounted) setPatientId(String(row.id)) } catch { // silencioso } })() return () => { mounted = false } }, []) // 2) Buscar médicos conforme especialidade selecionada useEffect(() => { let mounted = true ;(async () => { try { setLoadingMedicos(true) setMedicos([]) setAgendaByDoctor({}) setAgendasExpandida({}) // termo de busca: usar a especialidade escolhida (fallback para string genérica) const termo = (especialidadeHero && especialidadeHero !== 'Veja mais') ? especialidadeHero : (params?.get('q') || 'medico') const list = await buscarMedicos(termo).catch(() => []) if (!mounted) return setMedicos(Array.isArray(list) ? list : []) } catch (e: any) { showToast('error', e?.message || 'Falha ao buscar profissionais') } finally { if (mounted) setLoadingMedicos(false) } })() // eslint-disable-next-line react-hooks/exhaustive-deps }, [especialidadeHero]) // 3) Carregar horários disponíveis para um médico (próximos 7 dias) e agrupar por dia async function loadAgenda(doctorId: string) { if (!doctorId) return if (agendaLoading[doctorId]) return setAgendaLoading((s) => ({ ...s, [doctorId]: true })) try { // janela de 7 dias const start = new Date(); start.setHours(0,0,0,0) const end = new Date(); end.setDate(end.getDate() + 7); end.setHours(23,59,59,999) const res = await getAvailableSlots({ doctor_id: doctorId, start_date: start.toISOString(), end_date: end.toISOString(), appointment_type: tipoConsulta === 'local' ? 'presencial' : 'telemedicina', }) // construir colunas: hoje, amanhã, +2 dias (4 colunas visíveis) const days: DayAgenda[] = [] for (let i = 0; i < 4; i++) { const d = new Date(start); d.setDate(start.getDate() + i) const dateKey = d.toISOString().split('T')[0] const label = i === 0 ? 'HOJE' : i === 1 ? 'AMANHÃ' : shortWeek[d.getDay()] days.push({ label, data: fmtDay(d), dateKey, horarios: [] }) } const onlyAvail = (res?.slots || []).filter(s => s.available) for (const s of onlyAvail) { const dt = new Date(s.datetime) const key = dt.toISOString().split('T')[0] const bucket = days.find(d => d.dateKey === key) if (!bucket) continue const label = dt.toLocaleTimeString('pt-BR', { hour: '2-digit', minute: '2-digit' }) bucket.horarios.push({ iso: s.datetime, label }) } // ordenar horários em cada dia for (const d of days) { d.horarios.sort((a, b) => new Date(a.iso).getTime() - new Date(b.iso).getTime()) } setAgendaByDoctor((prev) => ({ ...prev, [doctorId]: days })) } catch (e: any) { showToast('error', e?.message || 'Falha ao buscar horários') } finally { setAgendaLoading((s) => ({ ...s, [doctorId]: false })) } } // 4) Agendar ao clicar em um horário async function agendar(doctorId: string, iso: string) { if (!patientId) { showToast('error', 'Paciente não identificado. Faça login novamente.') return } try { await criarAgendamento({ patient_id: String(patientId), doctor_id: String(doctorId), scheduled_at: String(iso), duration_minutes: 30, appointment_type: (tipoConsulta === 'local' ? 'presencial' : 'telemedicina'), }) showToast('success', 'Consulta agendada com sucesso!') // remover horário da lista local setAgendaByDoctor((prev) => { const days = prev[doctorId] if (!days) return prev const updated = days.map(d => ({ ...d, horarios: d.horarios.filter(h => h.iso !== iso) })) return { ...prev, [doctorId]: updated } }) } catch (e: any) { showToast('error', e?.message || 'Falha ao agendar') } } // Filtro visual (convenio/bairro são cosméticos; quando sem dado, mantemos tudo) const profissionais = useMemo(() => { return (medicos || []).filter((m: any) => { if (convenio !== 'Todos' && m.convenios && !m.convenios.includes(convenio)) return false if (bairro !== 'Todos' && m.neighborhood && String(m.neighborhood).toLowerCase() !== String(bairro).toLowerCase()) return false return true }) }, [medicos, convenio, bairro]) // Render return (
{/* Toast */} {toast && (
{toast.msg}
)} {/* Hero de filtros (mantido) */}

Resultados da procura

Qual especialização você deseja?

{especialidadesHero.map(item => ( ))}
{/* Barra de filtros secundários (mantida) */}
setTipoConsulta('teleconsulta')} className={cn('rounded-full px-4 py-[10px] text-sm font-medium transition hover:bg-primary hover:text-primary-foreground focus-visible:ring-2 focus-visible:ring-primary/60 active:scale-[0.97]', tipoConsulta === 'teleconsulta' ? 'bg-primary text-primary-foreground' : 'border border-primary/40 text-primary')} > Teleconsulta setTipoConsulta('local')} className={cn('rounded-full px-4 py-[10px] text-sm font-medium transition hover:bg-primary hover:text-primary-foreground focus-visible:ring-2 focus-visible:ring-primary/60 active:scale-[0.97]', tipoConsulta === 'local' ? 'bg-primary text-primary-foreground' : 'border border-primary/40 text-primary')} > Consulta no local
{/* Lista de profissionais */}
{loadingMedicos && ( Buscando profissionais... )} {!loadingMedicos && profissionais.map((medico) => { const id = String(medico.id) const agenda = agendaByDoctor[id] const isLoadingAgenda = !!agendaLoading[id] const atendeLocal = true // dados ausentes → manter visual const atendeTele = true const nome = medico.full_name || 'Profissional' const esp = (medico as any).specialty || medico.especialidade || '—' const crm = [medico.crm, (medico as any).crm_uf].filter(Boolean).join(' / ') const convenios = '—' const endereco = [medico.street, medico.number].filter(Boolean).join(', ') || medico.street || '—' const cidade = [medico.city, medico.state].filter(Boolean).join(' • ') const precoLocal = '—' const precoTeleconsulta = '—' return (

{nome}

{esp}
{/* sem avaliação → travar layout */} {'4.9'} • {'23'} avaliações {crm || '—'} {convenios}
{tipoConsulta === 'local' && atendeLocal && (
{endereco}
{cidade || '—'} {precoLocal}
)} {tipoConsulta === 'teleconsulta' && atendeTele && (
Teleconsulta {precoTeleconsulta}
)}
Idiomas: Português, Inglês Acolhimento em cada consulta Pagamento seguro Especialista recomendado
{/* Agenda: 4 colunas como no layout. Se ainda não carregou, mostra placeholders. */}
{(agenda || [ { label: 'HOJE', data: fmtDay(new Date()), horarios: [] }, { label: 'AMANHÃ', data: fmtDay(new Date(Date.now()+86400000)), horarios: [] }, { label: shortWeek[new Date(Date.now()+2*86400000).getDay()], data: fmtDay(new Date(Date.now()+2*86400000)), horarios: [] }, { label: shortWeek[new Date(Date.now()+3*86400000).getDay()], data: fmtDay(new Date(Date.now()+3*86400000)), horarios: [] }, ]).map((col, idx) => { const horarios = agendasExpandida[id] ? col.horarios : col.horarios.slice(0, 3) return (

{col.label}

{col.data}

{isLoadingAgenda && !agenda ? ( Carregando... ) : horarios.length ? ( horarios.map(h => ( )) ) : ( Sem horários )} {!agendasExpandida[id] && (col.horarios.length > 3) && ( +{col.horarios.length - 3} horários )}
) })}
) })} {!loadingMedicos && !profissionais.length && ( Nenhum profissional encontrado. Ajuste os filtros para ver outras opções. )}
{/* Dialog de perfil completo (mantido e adaptado) */} !open && setMedicoSelecionado(null)}> {medicoSelecionado && ( <> {medicoSelecionado.full_name || 'Profissional'}

{((medicoSelecionado as any).specialty || medicoSelecionado.especialidade || '—')} { ' • ' } {[medicoSelecionado.crm, (medicoSelecionado as any).crm_uf].filter(Boolean).join(' / ') || '—'}

4.9 (23 avaliações) Planos de saúde: —
Experiência Planos de saúde Consultórios Serviços Opiniões (0) loadAgenda(String(medicoSelecionado.id))}> Agenda

Informações fornecidas pelo profissional.

Atendimento por teleconsulta ou endereço informado no card.

Consulta

Nenhuma opinião disponível.

Escolha o melhor horário disponível para sua consulta.

{(agendaByDoctor[String(medicoSelecionado.id)] || []).map((col, idx) => (

{col.label}

{col.data}

{col.horarios.length ? ( col.horarios.map(h => ( )) ) : ( Sem horários )}
))} {!(agendaByDoctor[String(medicoSelecionado.id)] || []).length && (
Carregando horários...
)}
)}
) }