From 5334afc7611ba885dc24677edcd67b4c8e554aa4 Mon Sep 17 00:00:00 2001 From: pedrogomes5913 Date: Wed, 8 Oct 2025 21:47:57 -0300 Subject: [PATCH 1/4] feat(ui): formatar datas para dd/MM/yyyy e controlar forma de pagamento --- susconecta/app/financeiro/page.tsx | 4 +- .../forms/doctor-registration-form.tsx | 30 +++++++++++++- .../forms/patient-registration-form.tsx | 40 +++++++++++++++++-- 3 files changed, 67 insertions(+), 7 deletions(-) diff --git a/susconecta/app/financeiro/page.tsx b/susconecta/app/financeiro/page.tsx index 7981f4b..3861848 100644 --- a/susconecta/app/financeiro/page.tsx +++ b/susconecta/app/financeiro/page.tsx @@ -16,6 +16,8 @@ export default function FinanceiroPage() { const pathname = usePathname(); const router = useRouter(); const [bloqueio, setBloqueio] = useState(false); + const [formaTipo, setFormaTipo] = useState(""); + const [parcelas, setParcelas] = useState("1"); const isAg = pathname?.startsWith("/agendamento"); const isPr = pathname?.startsWith("/procedimento"); @@ -90,7 +92,7 @@ export default function FinanceiroPage() {
- setFormaTipo(e.target.value)} className="h-10 w-full rounded-md border border-gray-300 dark:border-input bg-background text-foreground pr-8 pl-3 text-[13px] appearance-none transition-colors hover:bg-muted/30 hover:border-gray-400"> diff --git a/susconecta/components/forms/doctor-registration-form.tsx b/susconecta/components/forms/doctor-registration-form.tsx index 13251e7..f5437f0 100644 --- a/susconecta/components/forms/doctor-registration-form.tsx +++ b/susconecta/components/forms/doctor-registration-form.tsx @@ -368,7 +368,18 @@ const payload: MedicoInput = { neighborhood: form.bairro || undefined, city: form.cidade || "", state: form.estado || "", - birth_date: form.data_nascimento || null, + // converte dd/MM/yyyy para ISO + birth_date: (() => { + try { + const parts = String(form.data_nascimento).split(/\D+/).filter(Boolean); + if (parts.length === 3) { + const [d, m, y] = parts; + const date = new Date(Number(y), Number(m) - 1, Number(d)); + if (!isNaN(date.getTime())) return date.toISOString().slice(0, 10); + } + } catch {} + return null; + })(), rg: form.rg || null, active: true, created_by: null, @@ -653,7 +664,22 @@ if (missingFields.length > 0) {
- setField("data_nascimento", e.target.value)} /> + { + const v = e.target.value.replace(/[^0-9\/]/g, "").slice(0, 10); + setField("data_nascimento", v); + }} + onBlur={() => { + const raw = form.data_nascimento; + const parts = raw.split(/\D+/).filter(Boolean); + if (parts.length === 3) { + const d = `${parts[0].padStart(2,'0')}/${parts[1].padStart(2,'0')}/${parts[2].padStart(4,'0')}`; + setField("data_nascimento", d); + } + }} + />
diff --git a/susconecta/components/forms/patient-registration-form.tsx b/susconecta/components/forms/patient-registration-form.tsx index 1abade4..303bb50 100644 --- a/susconecta/components/forms/patient-registration-form.tsx +++ b/susconecta/components/forms/patient-registration-form.tsx @@ -2,6 +2,7 @@ "use client"; import { useEffect, useMemo, useState } from "react"; +import { format, parse, isValid, parseISO } from "date-fns"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; @@ -130,7 +131,9 @@ export function PatientRegistrationForm({ cpf: p.cpf || "", rg: p.rg || "", sexo: p.sex || "", - birth_date: p.birth_date || "", // 👈 trocar data_nascimento → birth_date + birth_date: p.birth_date ? (() => { + try { return format(parseISO(String(p.birth_date)), 'dd/MM/yyyy'); } catch { return String(p.birth_date); } + })() : "", telefone: p.phone_mobile || "", email: p.email || "", cep: p.cep || "", @@ -199,13 +202,26 @@ export function PatientRegistrationForm({ } function toPayload(): PacienteInput { + // converte dd/MM/yyyy para ISO (yyyy-MM-dd) se possível + let isoDate: string | null = null; + try { + const parts = String(form.birth_date).split(/\D+/).filter(Boolean); + if (parts.length === 3) { + const [d, m, y] = parts; + const date = new Date(Number(y), Number(m) - 1, Number(d)); + if (!isNaN(date.getTime())) { + isoDate = date.toISOString().slice(0, 10); + } + } + } catch {} + return { full_name: form.nome, // 👈 troca 'nome' por 'full_name' social_name: form.nome_social || null, cpf: form.cpf, rg: form.rg || null, sex: form.sexo || null, - birth_date: form.birth_date || null, // 👈 troca data_nascimento → birth_date + birth_date: isoDate, // enviar ISO ou null phone_mobile: form.telefone || null, email: form.email || null, cep: form.cep || null, @@ -504,8 +520,24 @@ export function PatientRegistrationForm({
- setField("birth_date", e.target.value)} /> - + { + // permita apenas números e '/' + const v = e.target.value.replace(/[^0-9\/]/g, "").slice(0, 10); + setField("birth_date", v); + }} + onBlur={() => { + // tenta formatar automaticamente se for uma data válida + const raw = form.birth_date; + const parts = raw.split(/\D+/).filter(Boolean); + if (parts.length === 3) { + const d = `${parts[0].padStart(2,'0')}/${parts[1].padStart(2,'0')}/${parts[2].padStart(4,'0')}`; + setField("birth_date", d); + } + }} + />
From b6c160bffd003df3f66e01c7c3c2b490569a04ba Mon Sep 17 00:00:00 2001 From: Jonas Francisco Date: Thu, 9 Oct 2025 11:52:42 -0300 Subject: [PATCH 2/4] =?UTF-8?q?fix:=20hover=20azul=20no=20bot=C3=A3o=20Ver?= =?UTF-8?q?=20consultas=20agendadas?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- susconecta/app/paciente/page.tsx | 265 ++++++++++++++++++++++++------- susconecta/next-env.d.ts | 3 +- 2 files changed, 212 insertions(+), 56 deletions(-) diff --git a/susconecta/app/paciente/page.tsx b/susconecta/app/paciente/page.tsx index f76067b..0d23ec2 100644 --- a/susconecta/app/paciente/page.tsx +++ b/susconecta/app/paciente/page.tsx @@ -14,6 +14,7 @@ import { SimpleThemeToggle } from '@/components/simple-theme-toggle' import Link from 'next/link' import ProtectedRoute from '@/components/ProtectedRoute' import { useAuth } from '@/hooks/useAuth' +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' // Simulação de internacionalização básica const strings = { dashboard: 'Dashboard', @@ -145,8 +146,7 @@ export default function PacientePage() { }, ]; - function formatDatePt(dateStr: string) { - const date = new Date(dateStr); + function formatDatePt(date: Date) { return date.toLocaleDateString('pt-BR', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' }); } @@ -163,65 +163,222 @@ export default function PacientePage() { const consultasDoDia = consultasFicticias.filter(c => c.data === todayStr); function Consultas() { + const [tipoConsulta, setTipoConsulta] = useState<'teleconsulta' | 'presencial'>('teleconsulta') + const [especialidade, setEspecialidade] = useState('cardiologia') + const [localizacao, setLocalizacao] = useState('') + const [mostrarAgendadas, setMostrarAgendadas] = useState(false) + const hoverPrimaryClass = "transition duration-200 hover:bg-[#2563eb] hover:text-white focus-visible:ring-2 focus-visible:ring-[#2563eb]/60 active:scale-[0.97]" + const activeToggleClass = "w-full transition duration-200 focus-visible:ring-2 focus-visible:ring-[#2563eb]/60 active:scale-[0.97] bg-[#2563eb] text-white hover:bg-[#2563eb] hover:text-white" + const inactiveToggleClass = "w-full transition duration-200 bg-slate-50 text-[#2563eb] border border-[#2563eb]/30 hover:bg-slate-100 hover:text-[#2563eb] dark:bg-white/5 dark:text-white dark:hover:bg-white/10 dark:border-white/20" + const hoverPrimaryIconClass = "rounded-xl bg-white text-[#1e293b] border border-black/10 shadow-[0_2px_8px_rgba(0,0,0,0.03)] transition duration-200 hover:bg-[#2563eb] hover:text-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#2563eb] dark:bg-slate-800 dark:text-slate-100 dark:border-white/10 dark:shadow-none dark:hover:bg-[#2563eb] dark:hover:text-white" + const today = new Date(); today.setHours(0, 0, 0, 0); + const selectedDate = new Date(currentDate); selectedDate.setHours(0, 0, 0, 0); + const isSelectedDateToday = selectedDate.getTime() === today.getTime() + return (
-
-

Minhas Consultas

-
- {/* Navegação de Data */} -
-
- -

{formatDatePt(todayStr)}

- - -
-
- {consultasDoDia.length} consulta{consultasDoDia.length !== 1 ? 's' : ''} agendada{consultasDoDia.length !== 1 ? 's' : ''} -
-
- {/* Lista de Consultas do Dia */} -
- {consultasDoDia.length === 0 ? ( -
- -

Nenhuma consulta agendada para este dia

-

Você pode agendar uma nova consulta

- +
+
+

Agende sua próxima consulta

+

Escolha o formato ideal, selecione a especialidade e encontre o profissional perfeito para você.

+
+ +
+
+ +
+ + +
- ) : ( - consultasDoDia.map(consulta => ( -
-
-
-
-
-
- - {consulta.medico} + +
+
+ + +
+ +
+ +
+ + setLocalizacao(event.target.value)} + placeholder="Cidade ou estado" + className="pl-9" + /> +
+
+
+ + +
+ +
+ +
+
+ + setMostrarAgendadas(open)}> + + + Consultas agendadas + Gerencie suas consultas confirmadas, pendentes ou canceladas. + + +
+
+ + {formatDatePt(currentDate)} + + {isSelectedDateToday && ( + + )} +
+
+ {consultasDoDia.length} consulta{consultasDoDia.length !== 1 ? 's' : ''} agendada{consultasDoDia.length !== 1 ? 's' : ''} +
+
+ +
+ {consultasDoDia.length === 0 ? ( +
+ +

Nenhuma consulta agendada para este dia

+

Use a busca para marcar uma nova consulta.

+
+ ) : ( + consultasDoDia.map(consulta => ( +
+
+
+ +
+
+ + {consulta.medico} +
+

+ {consulta.especialidade} • {consulta.local} +

+
-
- {consulta.especialidade} • {consulta.local} + +
+ + {consulta.hora} +
+ +
+ + {consulta.status} + +
+ +
+ + {consulta.status !== 'Cancelada' && ( + + )} + {consulta.status !== 'Cancelada' && ( + + )}
-
- - {consulta.hora} -
-
-
{consulta.status}
-
-
- - {consulta.status !== 'Cancelada' && } - {consulta.status !== 'Cancelada' && } -
-
-
- )) - )} -
+ )) + )} +
+ + + + + +
) } diff --git a/susconecta/next-env.d.ts b/susconecta/next-env.d.ts index 830fb59..40c3d68 100644 --- a/susconecta/next-env.d.ts +++ b/susconecta/next-env.d.ts @@ -1,6 +1,5 @@ /// /// -/// // NOTE: This file should not be edited -// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. +// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information. From 1de9176e94118b5eaeca6a2857e8ddc3be5f2569 Mon Sep 17 00:00:00 2001 From: Jonas Francisco Date: Thu, 9 Oct 2025 14:15:08 -0300 Subject: [PATCH 3/4] =?UTF-8?q?feat:=20adicionar=20p=C3=A1gina=20de=20resu?= =?UTF-8?q?ltados=20de=20busca=20ao=20clicar=20em=20pesquisar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- susconecta/app/paciente/page.tsx | 18 +- susconecta/app/resultados/page.tsx | 304 +++++++++++++++++++++++++++++ 2 files changed, 321 insertions(+), 1 deletion(-) create mode 100644 susconecta/app/resultados/page.tsx diff --git a/susconecta/app/paciente/page.tsx b/susconecta/app/paciente/page.tsx index 0d23ec2..8bd8e24 100644 --- a/susconecta/app/paciente/page.tsx +++ b/susconecta/app/paciente/page.tsx @@ -2,6 +2,7 @@ // import { useAuth } from '@/hooks/useAuth' // removido duplicado import { useState } from 'react' +import { useRouter } from 'next/navigation' import { Button } from '@/components/ui/button' import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from '@/components/ui/dialog' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' @@ -163,6 +164,7 @@ export default function PacientePage() { const consultasDoDia = consultasFicticias.filter(c => c.data === todayStr); function Consultas() { + const router = useRouter() const [tipoConsulta, setTipoConsulta] = useState<'teleconsulta' | 'presencial'>('teleconsulta') const [especialidade, setEspecialidade] = useState('cardiologia') const [localizacao, setLocalizacao] = useState('') @@ -175,6 +177,15 @@ export default function PacientePage() { const selectedDate = new Date(currentDate); selectedDate.setHours(0, 0, 0, 0); const isSelectedDateToday = selectedDate.getTime() === today.getTime() + const handlePesquisar = () => { + const params = new URLSearchParams({ + tipo: tipoConsulta, + especialidade, + local: localizacao + }) + router.push(`/resultados?${params.toString()}`) + } + return (
@@ -237,7 +248,12 @@ export default function PacientePage() {
- +
diff --git a/susconecta/app/resultados/page.tsx b/susconecta/app/resultados/page.tsx new file mode 100644 index 0000000..5a966c3 --- /dev/null +++ b/susconecta/app/resultados/page.tsx @@ -0,0 +1,304 @@ +'use client' + +import { 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 { + Building2, + Filter, + Globe, + HeartPulse, + Languages, + MapPin, + ShieldCheck, + Star, + Stethoscope, + ChevronRight +} from 'lucide-react' +import { cn } from '@/lib/utils' + +type TipoConsulta = 'teleconsulta' | 'local' + +type Medico = { + id: number + nome: string + especialidade: string + avaliacao: number + avaliacaoQtd: number + convenios: string[] + endereco?: string + bairro?: string + cidade?: string + precoLocal?: string + precoTeleconsulta?: string + atendeLocal: boolean + atendeTele: boolean +} + +const especialidadesHero = ['Psicólogo', 'Médico clínico geral', 'Pediatra', 'Dentista', 'Ginecologista', 'Veja mais'] + +const medicosMock: Medico[] = [ + { + id: 1, + nome: 'Paula Pontes', + especialidade: 'Psicóloga', + avaliacao: 4.9, + avaliacaoQtd: 23, + convenios: ['Amil', 'Unimed'], + endereco: 'Av. Doutor José Machado de Souza, 200 - Jardins', + bairro: 'Jardins', + cidade: 'Aracaju • SE', + precoLocal: 'R$ 180', + precoTeleconsulta: 'R$ 160', + atendeLocal: true, + atendeTele: true + }, + { + id: 2, + nome: 'Dr. Carlos Andrade', + especialidade: 'Cardiologista', + avaliacao: 4.8, + avaliacaoQtd: 128, + convenios: ['SulAmérica', 'Bradesco Saúde'], + endereco: 'Rua Sergipe, 88 - Centro Médico Jardins', + bairro: 'Centro', + cidade: 'Aracaju • SE', + precoLocal: 'R$ 320', + precoTeleconsulta: 'R$ 290', + atendeLocal: true, + atendeTele: true + }, + { + id: 3, + nome: 'Dra. Fernanda Lima', + especialidade: 'Dermatologista', + avaliacao: 5, + avaliacaoQtd: 210, + convenios: ['Amil', 'Particular'], + precoTeleconsulta: 'R$ 250', + atendeLocal: false, + atendeTele: true + }, + { + id: 4, + nome: 'Dr. João Silva', + especialidade: 'Ortopedista', + avaliacao: 4.7, + avaliacaoQtd: 96, + convenios: ['Unimed', 'Bradesco Saúde'], + endereco: 'Av. Beira Mar, 1450 - Farolândia', + bairro: 'Farolândia', + cidade: 'Aracaju • SE', + precoLocal: 'R$ 310', + atendeLocal: true, + atendeTele: false + } +] + +export default function ResultadosPage() { + const params = useSearchParams() + const router = useRouter() + 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') + + const profissionais = useMemo(() => { + return medicosMock.filter(medico => { + if (tipoConsulta === 'local' && !medico.atendeLocal) return false + if (tipoConsulta === 'teleconsulta' && !medico.atendeTele) return false + if (convenio !== 'Todos' && !medico.convenios.includes(convenio)) return false + if (bairro !== 'Todos' && medico.bairro !== bairro) return false + if (especialidadeHero !== 'Veja mais' && medico.especialidade !== especialidadeHero) return false + return true + }) + }, [bairro, convenio, especialidadeHero, tipoConsulta]) + + const toggleBase = + '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]' + + return ( +
+
+
+
+
+

Resultados da procura

+

Qual especialização você deseja?

+
+ +
+
+ {especialidadesHero.map(item => ( + + ))} +
+
+ +
+ setTipoConsulta('teleconsulta')} + className={cn(toggleBase, tipoConsulta === 'teleconsulta' ? 'bg-primary text-primary-foreground' : 'border border-primary/40 text-primary')} + > + + Teleconsulta + + setTipoConsulta('local')} + className={cn(toggleBase, tipoConsulta === 'local' ? 'bg-primary text-primary-foreground' : 'border border-primary/40 text-primary')} + > + + Consulta no local + + + + + + + + + +
+ +
+ {profissionais.map(medico => ( + +
+
+

{medico.nome}

+ {medico.especialidade} +
+
+ + + {medico.avaliacao.toFixed(1)} • {medico.avaliacaoQtd} avaliações + + {medico.convenios.join(', ')} +
+
+ + {tipoConsulta === 'local' && medico.atendeLocal && ( +
+ + + {medico.endereco} + +
+ {medico.cidade} + {medico.precoLocal} +
+
+ )} + + {tipoConsulta === 'teleconsulta' && medico.atendeTele && ( +
+ + + Teleconsulta + + {medico.precoTeleconsulta} +
+ )} + +
+ + + Idiomas: Português, Inglês + + + + Acolhimento em cada consulta + + + + Pagamento seguro + + + + Especialista recomendado + +
+ +
+ + + +
+
+ ))} + + {!profissionais.length && ( + + Nenhum profissional encontrado. Ajuste os filtros para ver outras opções. + + )} +
+
+
+ ) +} From 429c5c2eeb424a9e76d336ff199413e87ddb256a Mon Sep 17 00:00:00 2001 From: Jonas Francisco Date: Thu, 9 Oct 2025 14:42:04 -0300 Subject: [PATCH 4/4] =?UTF-8?q?feat:=20adicionar=20listagem=20e=20rolagem?= =?UTF-8?q?=20de=20m=C3=A9dicos=20por=20especializa=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- susconecta/app/resultados/page.tsx | 743 +++++++++++++++++++++++++++-- 1 file changed, 708 insertions(+), 35 deletions(-) diff --git a/susconecta/app/resultados/page.tsx b/susconecta/app/resultados/page.tsx index 5a966c3..2933e39 100644 --- a/susconecta/app/resultados/page.tsx +++ b/susconecta/app/resultados/page.tsx @@ -7,6 +7,9 @@ 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, @@ -17,7 +20,8 @@ import { ShieldCheck, Star, Stethoscope, - ChevronRight + ChevronRight, + UserRound } from 'lucide-react' import { cn } from '@/lib/utils' @@ -27,6 +31,8 @@ type Medico = { id: number nome: string especialidade: string + crm: string + categoriaHero: string avaliacao: number avaliacaoQtd: number convenios: string[] @@ -37,15 +43,27 @@ type Medico = { precoTeleconsulta?: string atendeLocal: boolean atendeTele: boolean + agenda: { + label: string + data: string + horarios: string[] + }[] + experiencia: string[] + planosSaude: string[] + consultorios: { nome: string; endereco: string; telefone: string }[] + servicos: { nome: string; preco: string }[] + opinioes: { id: number; paciente: string; data: string; nota: number; comentario: string }[] } const especialidadesHero = ['Psicólogo', 'Médico clínico geral', 'Pediatra', 'Dentista', 'Ginecologista', 'Veja mais'] -const medicosMock: Medico[] = [ +const medicosBase: Medico[] = [ { id: 1, nome: 'Paula Pontes', - especialidade: 'Psicóloga', + especialidade: 'Psicóloga clínica', + crm: 'CRP SE 19/4244', + categoriaHero: 'Psicólogo', avaliacao: 4.9, avaliacaoQtd: 23, convenios: ['Amil', 'Unimed'], @@ -55,38 +73,106 @@ const medicosMock: Medico[] = [ precoLocal: 'R$ 180', precoTeleconsulta: 'R$ 160', atendeLocal: true, - atendeTele: true + atendeTele: true, + agenda: [ + { label: 'Hoje', data: '9 Out', horarios: [] }, + { label: 'Amanhã', data: '10 Out', horarios: ['09:00', '10:00', '11:00', '12:00', '13:00'] }, + { label: 'Sáb.', data: '11 Out', horarios: ['11:00', '12:00', '13:00', '14:00'] }, + { label: 'Dom.', data: '12 Out', horarios: [] } + ] }, { id: 2, - nome: 'Dr. Carlos Andrade', - especialidade: 'Cardiologista', - avaliacao: 4.8, - avaliacaoQtd: 128, + nome: 'Marcos Vieira', + especialidade: 'Psicólogo comportamental', + crm: 'CRP SE 24/1198', + categoriaHero: 'Psicólogo', + avaliacao: 4.7, + avaliacaoQtd: 31, convenios: ['SulAmérica', 'Bradesco Saúde'], - endereco: 'Rua Sergipe, 88 - Centro Médico Jardins', - bairro: 'Centro', + endereco: 'Rua Juarez Távora, 155 - São José', + bairro: 'São José', cidade: 'Aracaju • SE', - precoLocal: 'R$ 320', - precoTeleconsulta: 'R$ 290', + precoLocal: 'R$ 190', + precoTeleconsulta: 'R$ 150', atendeLocal: true, - atendeTele: true + atendeTele: true, + agenda: [ + { label: 'Hoje', data: '9 Out', horarios: ['14:00', '16:00'] }, + { label: 'Amanhã', data: '10 Out', horarios: ['10:00', '11:00', '12:00'] }, + { label: 'Sáb.', data: '11 Out', horarios: ['09:00', '10:30'] }, + { label: 'Dom.', data: '12 Out', horarios: [] } + ] }, { id: 3, - nome: 'Dra. Fernanda Lima', - especialidade: 'Dermatologista', - avaliacao: 5, - avaliacaoQtd: 210, - convenios: ['Amil', 'Particular'], - precoTeleconsulta: 'R$ 250', + nome: 'Julia Azevedo', + especialidade: 'Psicóloga infantil', + crm: 'CRP SE 23/4476', + categoriaHero: 'Psicólogo', + avaliacao: 4.95, + avaliacaoQtd: 45, + convenios: ['NotreDame Intermédica', 'Particular'], + precoTeleconsulta: 'R$ 140', atendeLocal: false, - atendeTele: true + atendeTele: true, + agenda: [ + { label: 'Hoje', data: '9 Out', horarios: ['09:00'] }, + { label: 'Amanhã', data: '10 Out', horarios: ['09:30', '11:30'] }, + { label: 'Sáb.', data: '11 Out', horarios: ['08:30', '10:00', '11:00'] }, + { label: 'Dom.', data: '12 Out', horarios: [] } + ] }, { id: 4, + nome: 'Rafael Sousa', + especialidade: 'Neuropsicólogo', + crm: 'CRP BA 03/8874', + categoriaHero: 'Psicólogo', + avaliacao: 4.82, + avaliacaoQtd: 52, + convenios: ['Amil', 'Particular'], + endereco: 'Rua Riachão, 77 - Centro', + bairro: 'Centro', + cidade: 'Aracaju • SE', + precoLocal: 'R$ 210', + atendeLocal: true, + atendeTele: false, + agenda: [ + { label: 'Hoje', data: '9 Out', horarios: [] }, + { label: 'Amanhã', data: '10 Out', horarios: ['09:00', '13:00'] }, + { label: 'Sáb.', data: '11 Out', horarios: ['10:00', '12:00'] }, + { label: 'Dom.', data: '12 Out', horarios: ['09:30'] } + ] + }, + { + id: 5, + nome: 'Lucas Amorim', + especialidade: 'Clínico geral', + crm: 'CRM SE 5122', + categoriaHero: 'Médico clínico geral', + avaliacao: 4.88, + avaliacaoQtd: 98, + convenios: ['Amil', 'Bradesco Saúde'], + endereco: 'Av. Beira Mar, 402 - Coroa do Meio', + bairro: 'Coroa do Meio', + cidade: 'Aracaju • SE', + precoLocal: 'R$ 220', + atendeLocal: true, + atendeTele: true, + agenda: [ + { label: 'Hoje', data: '9 Out', horarios: ['09:00', '11:00'] }, + { label: 'Amanhã', data: '10 Out', horarios: ['08:00', '09:30', '14:00'] }, + { label: 'Sáb.', data: '11 Out', horarios: ['10:30', '12:00'] }, + { label: 'Dom.', data: '12 Out', horarios: [] } + ] + }, + { + id: 6, nome: 'Dr. João Silva', especialidade: 'Ortopedista', + crm: 'CRM RJ 90876', + categoriaHero: 'Veja mais', avaliacao: 4.7, avaliacaoQtd: 96, convenios: ['Unimed', 'Bradesco Saúde'], @@ -95,10 +181,394 @@ const medicosMock: Medico[] = [ cidade: 'Aracaju • SE', precoLocal: 'R$ 310', atendeLocal: true, - atendeTele: false + atendeTele: false, + agenda: [ + { label: 'Hoje', data: '9 Out', horarios: [] }, + { label: 'Amanhã', data: '10 Out', horarios: ['08:00', '09:00'] }, + { label: 'Sáb.', data: '11 Out', horarios: ['10:00'] }, + { label: 'Dom.', data: '12 Out', horarios: [] } + ] + }, + { + id: 7, + nome: 'Dra. Beatriz Moura', + especialidade: 'Ginecologista', + crm: 'CRM BA 52110', + categoriaHero: 'Veja mais', + avaliacao: 4.95, + avaliacaoQtd: 186, + convenios: ['NotreDame Intermédica', 'Particular', 'Amil'], + endereco: 'Rua Tobias Barreto, 512 - Bairro São José', + bairro: 'São José', + cidade: 'Aracaju • SE', + precoLocal: 'R$ 280', + precoTeleconsulta: 'R$ 240', + atendeLocal: true, + atendeTele: true, + agenda: [ + { label: 'Hoje', data: '9 Out', horarios: ['14:00', '15:00'] }, + { label: 'Amanhã', data: '10 Out', horarios: ['09:00', '11:00', '16:00'] }, + { label: 'Sáb.', data: '11 Out', horarios: ['10:30', '12:30'] }, + { label: 'Dom.', data: '12 Out', horarios: ['11:30'] } + ] + }, + { + id: 8, + nome: 'Dr. André Lemos', + especialidade: 'Gastroenterologista', + crm: 'CRM SE 9033', + categoriaHero: 'Veja mais', + avaliacao: 4.75, + avaliacaoQtd: 105, + convenios: ['SulAmérica', 'Unimed'], + endereco: 'Rua Arauá, 22 - Centro', + bairro: 'Centro', + cidade: 'Aracaju • SE', + precoLocal: 'R$ 340', + atendeLocal: true, + atendeTele: true, + agenda: [ + { label: 'Hoje', data: '9 Out', horarios: ['13:00'] }, + { label: 'Amanhã', data: '10 Out', horarios: ['08:00', '09:00', '11:00', '15:00'] }, + { label: 'Sáb.', data: '11 Out', horarios: ['09:30', '10:15'] }, + { label: 'Dom.', data: '12 Out', horarios: [] } + ] + }, + { + id: 9, + nome: 'Dra. Fernanda Lima', + especialidade: 'Médico clínico geral', + crm: 'CRM SE 7890', + categoriaHero: 'Médico clínico geral', + avaliacao: 4.9, + avaliacaoQtd: 110, + convenios: ['Amil', 'Unimed', 'Bradesco Saúde'], + endereco: 'Av. Rio de Janeiro, 300 - São José', + bairro: 'São José', + cidade: 'Aracaju • SE', + precoLocal: 'R$ 250', + atendeLocal: true, + atendeTele: true, + agenda: [ + { label: 'Hoje', data: '9 Out', horarios: ['09:00', '11:00'] }, + { label: 'Amanhã', data: '10 Out', horarios: ['08:00', '09:30', '14:00'] }, + { label: 'Sáb.', data: '11 Out', horarios: ['10:30', '12:00'] }, + { label: 'Dom.', data: '12 Out', horarios: [] } + ] + }, + { + id: 10, + nome: 'Dra. Helena Castro', + especialidade: 'Pediatra geral', + crm: 'CRM SE 7812', + categoriaHero: 'Pediatra', + avaliacao: 4.92, + avaliacaoQtd: 134, + convenios: ['Amil', 'Unimed', 'SulAmérica'], + endereco: 'Rua José Hipólito, 98 - Suíssa', + bairro: 'Suíssa', + cidade: 'Aracaju • SE', + precoLocal: 'R$ 260', + precoTeleconsulta: 'R$ 220', + atendeLocal: true, + atendeTele: true, + agenda: [ + { label: 'Hoje', data: '9 Out', horarios: ['09:00', '11:30'] }, + { label: 'Amanhã', data: '10 Out', horarios: ['08:30', '10:00', '14:00'] }, + { label: 'Sáb.', data: '11 Out', horarios: ['09:30', '11:00'] }, + { label: 'Dom.', data: '12 Out', horarios: [] } + ] + }, + { + id: 11, + nome: 'Dr. Vinícius Prado', + especialidade: 'Pediatra neonatologista', + crm: 'CRM SE 6331', + categoriaHero: 'Pediatra', + avaliacao: 4.85, + avaliacaoQtd: 89, + convenios: ['Bradesco Saúde', 'NotreDame Intermédica'], + endereco: 'Av. Augusto Franco, 2220 - Siqueira Campos', + bairro: 'Siqueira Campos', + cidade: 'Aracaju • SE', + precoLocal: 'R$ 280', + atendeLocal: true, + atendeTele: false, + agenda: [ + { label: 'Hoje', data: '9 Out', horarios: [] }, + { label: 'Amanhã', data: '10 Out', horarios: ['08:00', '09:00', '11:30'] }, + { label: 'Sáb.', data: '11 Out', horarios: ['10:00'] }, + { label: 'Dom.', data: '12 Out', horarios: ['09:30'] } + ] + }, + { + id: 12, + nome: 'Dra. Marina Salles', + especialidade: 'Pediatra emergencista', + crm: 'CRM BA 85660', + categoriaHero: 'Pediatra', + avaliacao: 4.78, + avaliacaoQtd: 57, + convenios: ['Particular', 'Amil'], + precoTeleconsulta: 'R$ 210', + atendeLocal: false, + atendeTele: true, + agenda: [ + { label: 'Hoje', data: '9 Out', horarios: ['13:00', '15:00'] }, + { label: 'Amanhã', data: '10 Out', horarios: ['09:30', '12:30'] }, + { label: 'Sáb.', data: '11 Out', horarios: ['09:00'] }, + { label: 'Dom.', data: '12 Out', horarios: [] } + ] + }, + { + id: 13, + nome: 'Dr. Caio Moura', + especialidade: 'Pediatra pneumologista', + crm: 'CRM SE 7345', + categoriaHero: 'Pediatra', + avaliacao: 4.91, + avaliacaoQtd: 102, + convenios: ['SulAmérica', 'Unimed'], + endereco: 'Av. Hermes Fontes, 445 - Salgado Filho', + bairro: 'Salgado Filho', + cidade: 'Aracaju • SE', + precoLocal: 'R$ 270', + precoTeleconsulta: 'R$ 230', + atendeLocal: true, + atendeTele: true, + agenda: [ + { label: 'Hoje', data: '9 Out', horarios: ['10:00'] }, + { label: 'Amanhã', data: '10 Out', horarios: ['09:00', '11:00', '16:00'] }, + { label: 'Sáb.', data: '11 Out', horarios: ['09:30', '11:30'] }, + { label: 'Dom.', data: '12 Out', horarios: [] } + ] + }, + { + id: 14, + nome: 'Dra. Patrícia Freire', + especialidade: 'Cirurgiã-dentista', + crm: 'CRO SE 2133', + categoriaHero: 'Dentista', + avaliacao: 4.9, + avaliacaoQtd: 176, + convenios: ['OdontoPrev', 'Amil Dental'], + endereco: 'Rua Itabaiana, 410 - Centro', + bairro: 'Centro', + cidade: 'Aracaju • SE', + precoLocal: 'R$ 200', + precoTeleconsulta: 'R$ 160', + atendeLocal: true, + atendeTele: true, + agenda: [ + { label: 'Hoje', data: '9 Out', horarios: ['09:00', '13:30'] }, + { label: 'Amanhã', data: '10 Out', horarios: ['08:30', '10:00', '14:30'] }, + { label: 'Sáb.', data: '11 Out', horarios: ['09:30', '11:00'] }, + { label: 'Dom.', data: '12 Out', horarios: [] } + ] + }, + { + id: 15, + nome: 'Dr. Henrique Assis', + especialidade: 'Implantodontista', + crm: 'CRO SE 1450', + categoriaHero: 'Dentista', + avaliacao: 4.83, + avaliacaoQtd: 94, + convenios: ['SulAmérica Odonto', 'Particular'], + endereco: 'Av. Jorge Amado, 321 - Atalaia', + bairro: 'Atalaia', + cidade: 'Aracaju • SE', + precoLocal: 'R$ 350', + atendeLocal: true, + atendeTele: false, + agenda: [ + { label: 'Hoje', data: '9 Out', horarios: [] }, + { label: 'Amanhã', data: '10 Out', horarios: ['09:00', '11:00'] }, + { label: 'Sáb.', data: '11 Out', horarios: ['10:30'] }, + { label: 'Dom.', data: '12 Out', horarios: [] } + ] + }, + { + id: 16, + nome: 'Dra. Lívia Teles', + especialidade: 'Ortodontista', + crm: 'CRO BA 11567', + categoriaHero: 'Dentista', + avaliacao: 4.88, + avaliacaoQtd: 140, + convenios: ['Uniodonto', 'Amil Dental', 'Particular'], + precoTeleconsulta: 'R$ 120', + atendeLocal: false, + atendeTele: true, + agenda: [ + { label: 'Hoje', data: '9 Out', horarios: ['17:00'] }, + { label: 'Amanhã', data: '10 Out', horarios: ['09:00', '10:30', '15:00'] }, + { label: 'Sáb.', data: '11 Out', horarios: ['08:30', '09:30'] }, + { label: 'Dom.', data: '12 Out', horarios: [] } + ] + }, + { + id: 17, + nome: 'Dr. Pablo Menezes', + especialidade: 'Endodontista', + crm: 'CRO SE 2099', + categoriaHero: 'Dentista', + avaliacao: 4.76, + avaliacaoQtd: 83, + convenios: ['OdontoPrev', 'SulAmérica Odonto'], + endereco: 'Rua Cedro, 70 - Grageru', + bairro: 'Grageru', + cidade: 'Aracaju • SE', + precoLocal: 'R$ 230', + precoTeleconsulta: 'R$ 190', + atendeLocal: true, + atendeTele: true, + agenda: [ + { label: 'Hoje', data: '9 Out', horarios: ['09:00'] }, + { label: 'Amanhã', data: '10 Out', horarios: ['08:00', '09:00', '13:00'] }, + { label: 'Sáb.', data: '11 Out', horarios: ['09:30'] }, + { label: 'Dom.', data: '12 Out', horarios: [] } + ] + }, + { + id: 18, + nome: 'Dra. Beatriz Moura', + especialidade: 'Ginecologista obstetra', + crm: 'CRM BA 52110', + categoriaHero: 'Ginecologista', + avaliacao: 4.95, + avaliacaoQtd: 186, + convenios: ['NotreDame Intermédica', 'Particular', 'Amil'], + endereco: 'Rua Tobias Barreto, 512 - São José', + bairro: 'São José', + cidade: 'Aracaju • SE', + precoLocal: 'R$ 280', + precoTeleconsulta: 'R$ 240', + atendeLocal: true, + atendeTele: true, + agenda: [ + { label: 'Hoje', data: '9 Out', horarios: ['14:00', '15:00'] }, + { label: 'Amanhã', data: '10 Out', horarios: ['09:00', '11:00', '16:00'] }, + { label: 'Sáb.', data: '11 Out', horarios: ['10:30', '12:30'] }, + { label: 'Dom.', data: '12 Out', horarios: ['11:30'] } + ] + }, + { + id: 19, + nome: 'Dra. Camila Albuquerque', + especialidade: 'Ginecologista endocrinologista', + crm: 'CRM SE 6774', + categoriaHero: 'Ginecologista', + avaliacao: 4.89, + avaliacaoQtd: 122, + convenios: ['SulAmérica', 'Unimed'], + endereco: 'Av. Gonçalo Prado Rollemberg, 167 - São José', + bairro: 'São José', + cidade: 'Aracaju • SE', + precoLocal: 'R$ 300', + atendeLocal: true, + atendeTele: false, + agenda: [ + { label: 'Hoje', data: '9 Out', horarios: [] }, + { label: 'Amanhã', data: '10 Out', horarios: ['08:00', '09:30', '15:00'] }, + { label: 'Sáb.', data: '11 Out', horarios: ['09:00'] }, + { label: 'Dom.', data: '12 Out', horarios: [] } + ] + }, + { + id: 20, + nome: 'Dra. Renata Figueiredo', + especialidade: 'Ginecologista minimamente invasiva', + crm: 'CRM PE 112233', + categoriaHero: 'Ginecologista', + avaliacao: 4.94, + avaliacaoQtd: 208, + convenios: ['Amil', 'Bradesco Saúde', 'Particular'], + precoTeleconsulta: 'R$ 260', + atendeLocal: false, + atendeTele: true, + agenda: [ + { label: 'Hoje', data: '9 Out', horarios: ['09:00', '10:30'] }, + { label: 'Amanhã', data: '10 Out', horarios: ['08:30', '11:00', '14:30'] }, + { label: 'Sáb.', data: '11 Out', horarios: ['09:45'] }, + { label: 'Dom.', data: '12 Out', horarios: [] } + ] + }, + { + id: 21, + nome: 'Dr. Eduardo Fontes', + especialidade: 'Ginecologista mastologista', + crm: 'CRM SE 7012', + categoriaHero: 'Ginecologista', + avaliacao: 4.8, + avaliacaoQtd: 95, + convenios: ['NotreDame Intermédica', 'SulAmérica'], + endereco: 'Rua Teófilo Dantas, 55 - Centro', + bairro: 'Centro', + cidade: 'Aracaju • SE', + precoLocal: 'R$ 310', + atendeLocal: true, + atendeTele: true, + agenda: [ + { label: 'Hoje', data: '9 Out', horarios: ['08:30'] }, + { label: 'Amanhã', data: '10 Out', horarios: ['09:00', '11:00', '16:30'] }, + { label: 'Sáb.', data: '11 Out', horarios: ['10:00', '12:00'] }, + { label: 'Dom.', data: '12 Out', horarios: [] } + ] } ] +const medicosMock: Medico[] = medicosBase.map((medico, index) => ({ + ...medico, + experiencia: + medico.experiencia ?? + [ + 'Especialista com atuação reconhecida pelo respectivo conselho profissional.', + 'Formação continuada em instituições nacionais e internacionais.', + 'Atendimento humanizado com foco em resultados sustentáveis.' + ], + planosSaude: + medico.planosSaude ?? medico.convenios ?? ['Amil', 'Unimed', 'SulAmérica'], + consultorios: + medico.consultorios ?? + (medico.endereco + ? [ + { + nome: 'Clínica principal', + endereco: `${medico.endereco}${medico.cidade ? ` — ${medico.cidade}` : ''}`, + telefone: '(79) 4002-8922' + } + ] + : []), + servicos: + medico.servicos ?? + [ + { + nome: 'Consulta inicial', + preco: medico.precoLocal ?? medico.precoTeleconsulta ?? 'Sob consulta' + }, + { nome: 'Retorno em até 30 dias', preco: 'R$ 150' } + ], + opinioes: + medico.opinioes ?? + [ + { + id: index * 2 + 1, + paciente: 'Ana P.', + data: '01/09/2025', + nota: 5, + comentario: 'Profissional muito atencioso e detalhista.' + }, + { + id: index * 2 + 2, + paciente: 'Marcos L.', + data: '18/08/2025', + nota: 4, + comentario: 'Explicações claras e ambiente acolhedor.' + } + ] +})) + export default function ResultadosPage() { const params = useSearchParams() const router = useRouter() @@ -108,6 +578,10 @@ export default function ResultadosPage() { const [especialidadeHero, setEspecialidadeHero] = useState(params.get('especialidade') || 'Psicólogo') const [convenio, setConvenio] = useState('Todos') const [bairro, setBairro] = useState('Todos') + const [modalFiltrosAberto, setModalFiltrosAberto] = useState(false) + const [agendasExpandida, setAgendasExpandida] = useState>({}) + const [medicoSelecionado, setMedicoSelecionado] = useState(null) + const [abaDetalhe, setAbaDetalhe] = useState('experiencia') const profissionais = useMemo(() => { return medicosMock.filter(medico => { @@ -115,7 +589,8 @@ export default function ResultadosPage() { if (tipoConsulta === 'teleconsulta' && !medico.atendeTele) return false if (convenio !== 'Todos' && !medico.convenios.includes(convenio)) return false if (bairro !== 'Todos' && medico.bairro !== bairro) return false - if (especialidadeHero !== 'Veja mais' && medico.especialidade !== especialidadeHero) return false + if (especialidadeHero !== 'Veja mais' && medico.categoriaHero !== especialidadeHero) return false + if (especialidadeHero === 'Veja mais' && medico.categoriaHero !== 'Veja mais') return false return true }) }, [bairro, convenio, especialidadeHero, tipoConsulta]) @@ -224,18 +699,36 @@ export default function ResultadosPage() { key={medico.id} className="flex flex-col gap-4 border border-border bg-card/80 p-6 shadow-sm transition hover:-translate-y-1 hover:shadow-lg" > -
-
-

{medico.nome}

- {medico.especialidade} -
-
- - - {medico.avaliacao.toFixed(1)} • {medico.avaliacaoQtd} avaliações - - {medico.convenios.join(', ')} +
+ + + + + +
+
+

{medico.nome}

+ {medico.especialidade} +
+
+ + + {medico.avaliacao.toFixed(1)} • {medico.avaliacaoQtd} avaliações + + {medico.crm} + {medico.convenios.join(', ')} +
+
{tipoConsulta === 'local' && medico.atendeLocal && ( @@ -285,10 +778,53 @@ export default function ResultadosPage() { -
+ +
+
+ {medico.agenda.map(coluna => { + const horarios = agendasExpandida[medico.id] ? coluna.horarios : coluna.horarios.slice(0, 3) + return ( +
+

{coluna.label}

+

{coluna.data}

+
+ {horarios.length ? ( + horarios.map(horario => ( + + )) + ) : ( + + Sem horários + + )} + {!agendasExpandida[medico.id] && coluna.horarios.length > 3 && ( + +{coluna.horarios.length - 3} horários + )} +
+
+ ) + })} +
+
))} @@ -298,6 +834,143 @@ export default function ResultadosPage() { )}
+ + !open && setMedicoSelecionado(null)}> + + {medicoSelecionado && ( + <> + + + {medicoSelecionado.nome} + +

+ {medicoSelecionado.especialidade} • {medicoSelecionado.crm} +

+
+ +
+
+ + + {medicoSelecionado.avaliacao.toFixed(1)} ({medicoSelecionado.avaliacaoQtd} avaliações) + + {medicoSelecionado.planosSaude.join(' • ')} +
+ + + + + Experiência + + + Planos de saúde + + + Consultórios + + + Serviços + + + Opiniões ({medicoSelecionado.opinioes.length}) + + + Agenda + + + + + {medicoSelecionado.experiencia.map((linha, index) => ( +

{linha}

+ ))} +
+ + + {medicoSelecionado.planosSaude.map(plano => ( + + {plano} + + ))} + + + + {medicoSelecionado.consultorios.length ? ( + medicoSelecionado.consultorios.map((consultorio, index) => ( +
+

{consultorio.nome}

+

{consultorio.endereco}

+

Telefone: {consultorio.telefone}

+
+ )) + ) : ( +

Atendimento exclusivamente por teleconsulta.

+ )} +
+ + + {medicoSelecionado.servicos.map(servico => ( +
+ {servico.nome} + {servico.preco} +
+ ))} +
+ + + {medicoSelecionado.opinioes.map(opiniao => ( +
+
+ {opiniao.paciente} + {opiniao.data} +
+
+ {Array.from({ length: opiniao.nota }).map((_, index) => ( + + ))} +
+

{opiniao.comentario}

+
+ ))} +
+ + +

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

+
+
+ {medicoSelecionado.agenda.map(coluna => ( +
+

{coluna.label}

+

{coluna.data}

+
+ {coluna.horarios.length ? ( + coluna.horarios.map(horario => ( + + )) + ) : ( + + Sem horários + + )} +
+
+ ))} +
+
+
+
+
+ + )} +
+
)