From 35535b37798630a239f3c0800c22701ad3a40060 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gustavo?= <166467972+JoaoGustavo-dev@users.noreply.github.com> Date: Thu, 30 Oct 2025 17:51:45 -0300 Subject: [PATCH 1/8] fix-timezone --- .../app/(main-routes)/calendar/page.tsx | 1 + .../components/agendamento/AgendaCalendar.tsx | 31 ++++++++++++------- susconecta/components/ui/calendar.tsx | 8 ++--- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/susconecta/app/(main-routes)/calendar/page.tsx b/susconecta/app/(main-routes)/calendar/page.tsx index f1ce1b3..869ccc4 100644 --- a/susconecta/app/(main-routes)/calendar/page.tsx +++ b/susconecta/app/(main-routes)/calendar/page.tsx @@ -170,6 +170,7 @@ export default function AgendamentoPage() { plugins={[dayGridPlugin, timeGridPlugin, interactionPlugin]} initialView="dayGridMonth" locale={pt_br_locale} + timeZone={"America/Sao_Paulo"} events={requestsList} headerToolbar={{ left: "prev,next today", diff --git a/susconecta/components/agendamento/AgendaCalendar.tsx b/susconecta/components/agendamento/AgendaCalendar.tsx index da0abe1..983e49d 100644 --- a/susconecta/components/agendamento/AgendaCalendar.tsx +++ b/susconecta/components/agendamento/AgendaCalendar.tsx @@ -66,7 +66,8 @@ export default function AgendaCalendar({ weekday: 'long', day: 'numeric', month: 'long', - year: 'numeric' + year: 'numeric', + timeZone: 'America/Sao_Paulo' }); }; @@ -205,18 +206,22 @@ export default function AgendaCalendar({
- {currentDate.toLocaleDateString('pt-BR', { weekday: 'long' })} -
+ {currentDate.toLocaleDateString('pt-BR', { weekday: 'long', timeZone: 'America/Sao_Paulo' })} +
{timeSlots.map(time => (
))} {filteredAppointments.map(app => { - const [date, timeStr] = app.time.split('T'); - const [hours, minutes] = timeStr.split(':'); - const hour = parseInt(hours); - const minute = parseInt(minutes); + // parse appointment time in Brazil timezone + const d = new Date(app.time); + // extract hour/minute in America/Sao_Paulo using Intl.DateTimeFormat + const parts = new Intl.DateTimeFormat('en-US', { hour12: false, hour: '2-digit', minute: '2-digit', timeZone: 'America/Sao_Paulo' }).formatToParts(d); + const hourPart = parts.find(p => p.type === 'hour')?.value ?? '00'; + const minutePart = parts.find(p => p.type === 'minute')?.value ?? '00'; + const hour = parseInt(hourPart, 10); + const minute = parseInt(minutePart, 10); return (
- {hours}:{minutes} - {app.type} {getTypeIcon(app.type)} + {String(hour).padStart(2,'0')}:{String(minute).padStart(2,'0')} - {app.type} {getTypeIcon(app.type)}
{professionals.find(p => p.id === app.professional)?.name} @@ -260,9 +265,13 @@ export default function AgendaCalendar({ {view === 'month' && (
- {filteredAppointments.map(app => { - const [date, timeStr] = app.time.split('T'); - const [hours, minutes] = timeStr.split(':'); + {filteredAppointments.map(app => { + const d = new Date(app.time); + const parts = new Intl.DateTimeFormat('en-US', { hour12: false, hour: '2-digit', minute: '2-digit', timeZone: 'America/Sao_Paulo' }).formatToParts(d); + const hourPart = parts.find(p => p.type === 'hour')?.value ?? '00'; + const minutePart = parts.find(p => p.type === 'minute')?.value ?? '00'; + const hours = String(hourPart).padStart(2,'0'); + const minutes = String(minutePart).padStart(2,'0'); return (
diff --git a/susconecta/components/ui/calendar.tsx b/susconecta/components/ui/calendar.tsx index 4d7c46a..5479c11 100644 --- a/susconecta/components/ui/calendar.tsx +++ b/susconecta/components/ui/calendar.tsx @@ -35,9 +35,9 @@ function Calendar({ className )} captionLayout={captionLayout} - formatters={{ + formatters={{ formatMonthDropdown: (date) => - date.toLocaleString("default", { month: "short" }), + date.toLocaleString("default", { month: "short", timeZone: 'America/Sao_Paulo' }), ...formatters, }} classNames={{ @@ -155,7 +155,7 @@ function Calendar({ ) }, - DayButton: CalendarDayButton, + DayButton: CalendarDayButton, WeekNumber: ({ children, ...props }) => { return ( @@ -190,7 +190,7 @@ function CalendarDayButton({ ref={ref} variant="ghost" size="icon" - data-day={day.date.toLocaleDateString()} + data-day={day.date.toLocaleDateString(undefined, { timeZone: 'America/Sao_Paulo' })} data-selected-single={ modifiers.selected && !modifiers.range_start && -- 2.47.2 From a2d90bf68f6c4f0c51d280d24ef03e115e23cb67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gustavo?= <166467972+JoaoGustavo-dev@users.noreply.github.com> Date: Thu, 30 Oct 2025 18:21:30 -0300 Subject: [PATCH 2/8] fix-report-page --- susconecta/app/paciente/page.tsx | 60 ++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/susconecta/app/paciente/page.tsx b/susconecta/app/paciente/page.tsx index eb631df..6822431 100644 --- a/susconecta/app/paciente/page.tsx +++ b/susconecta/app/paciente/page.tsx @@ -730,6 +730,60 @@ export default function PacientePage() { const [loadingReports, setLoadingReports] = useState(false) const [reportsError, setReportsError] = useState(null) const [reportDoctorName, setReportDoctorName] = useState(null) + const [doctorsMap, setDoctorsMap] = useState>({}) + + // Helper to derive a human-friendly title for a report/laudo + const reportTitle = (rep: any, preferDoctorName?: string | null) => { + if (!rep) return 'Laudo' + // prefer a resolved doctor name when we have a map + try { + const maybeId = rep?.doctor_id ?? rep?.created_by ?? rep?.doctor ?? null + if (maybeId) { + const doc = doctorsMap[String(maybeId)] + if (doc) { + const name = doc.full_name || doc.name || doc.fullName || doc.doctor_name || null + if (name) return String(name) + } + } + } catch (e) { + // ignore + } + // Try common fields that may contain the doctor's/author name first + const tryKeys = [ + 'doctor_name', 'doctor_full_name', 'doctorFullName', 'doctorName', + 'requested_by_name', 'requested_by', 'requester_name', 'requester', + 'created_by_name', 'created_by', 'executante', 'executante_name', + 'title', 'name', 'report_name', 'report_title' + ] + for (const k of tryKeys) { + const v = rep[k] + if (v !== undefined && v !== null && String(v).trim() !== '') return String(v) + } + if (preferDoctorName) return preferDoctorName + return 'Laudo' + } + + // When reports are loaded, try to resolve doctor records for display + useEffect(() => { + let mounted = true + if (!reports || !Array.isArray(reports) || reports.length === 0) return + ;(async () => { + try { + const ids = Array.from(new Set(reports.map((r: any) => r.doctor_id || r.created_by || r.doctor).filter(Boolean).map(String))) + if (ids.length === 0) return + const docs = await buscarMedicosPorIds(ids).catch(() => []) + if (!mounted) return + const map: Record = {} + for (const d of docs || []) { + if (d && d.id !== undefined && d.id !== null) map[String(d.id)] = d + } + setDoctorsMap(map) + } catch (e) { + // ignore resolution errors + } + })() + return () => { mounted = false } + }, [reports]) useEffect(() => { let mounted = true @@ -789,11 +843,11 @@ export default function PacientePage() {
{reportsError}
) : (!reports || reports.length === 0) ? (
Nenhum laudo encontrado para este paciente.
- ) : ( + ) : ( reports.map((r) => (
-
{r.title || r.name || r.report_name || 'Laudo'}
+
{reportTitle(r)}
Data: {new Date(r.report_date || r.created_at || Date.now()).toLocaleDateString('pt-BR')}
@@ -813,7 +867,7 @@ export default function PacientePage() { {selectedReport && ( <>
-
{selectedReport.title || selectedReport.name || 'Laudo'}
+
{reportTitle(selectedReport, reportDoctorName)}
Data: {new Date(selectedReport.report_date || selectedReport.created_at || Date.now()).toLocaleDateString('pt-BR')}
{reportDoctorName &&
Profissional: {reportDoctorName}
}
-- 2.47.2 From c1471ea4faa899645f1aaa543d62161cbb7e5510 Mon Sep 17 00:00:00 2001 From: M-Gabrielly Date: Thu, 30 Oct 2025 18:26:01 -0300 Subject: [PATCH 3/8] fix: fix of hovers --- .../app/(main-routes)/dashboard/page.tsx | 6 +-- susconecta/app/paciente/page.tsx | 20 +++++++--- susconecta/app/profissional/page.tsx | 38 +++++++++---------- susconecta/components/dashboard/header.tsx | 2 +- susconecta/components/simple-theme-toggle.tsx | 2 +- susconecta/components/ui/sidebar.tsx | 2 +- 6 files changed, 39 insertions(+), 31 deletions(-) diff --git a/susconecta/app/(main-routes)/dashboard/page.tsx b/susconecta/app/(main-routes)/dashboard/page.tsx index 1ec2c13..5d6bf2d 100644 --- a/susconecta/app/(main-routes)/dashboard/page.tsx +++ b/susconecta/app/(main-routes)/dashboard/page.tsx @@ -283,15 +283,15 @@ export default function DashboardPage() { Novo Paciente - - - diff --git a/susconecta/app/paciente/page.tsx b/susconecta/app/paciente/page.tsx index eb631df..18ca84e 100644 --- a/susconecta/app/paciente/page.tsx +++ b/susconecta/app/paciente/page.tsx @@ -982,7 +982,7 @@ export default function PacientePage() {
Portal do Paciente -
- +
@@ -1001,7 +1009,7 @@ export default function PacientePage() { variant={tab==='dashboard'?'secondary':'ghost'} aria-current={tab==='dashboard'} onClick={()=>setTab('dashboard')} - className={`justify-start ${tab==='dashboard' ? 'bg-primary/10 text-primary' : ''}`} + className={`justify-start hover:!bg-primary hover:!text-white transition-colors ${tab==='dashboard' ? 'bg-primary/10 text-primary' : ''}`} > {strings.dashboard} @@ -1009,7 +1017,7 @@ export default function PacientePage() { variant={tab==='consultas'?'secondary':'ghost'} aria-current={tab==='consultas'} onClick={()=>setTab('consultas')} - className={`justify-start ${tab==='consultas' ? 'bg-primary/10 text-primary' : ''}`} + className={`justify-start hover:!bg-primary hover:!text-white transition-colors ${tab==='consultas' ? 'bg-primary/10 text-primary' : ''}`} > {strings.consultas} @@ -1017,7 +1025,7 @@ export default function PacientePage() { variant={tab==='exames'?'secondary':'ghost'} aria-current={tab==='exames'} onClick={()=>setTab('exames')} - className={`justify-start ${tab==='exames' ? 'bg-primary/10 text-primary' : ''}`} + className={`justify-start hover:!bg-primary hover:!text-white transition-colors ${tab==='exames' ? 'bg-primary/10 text-primary' : ''}`} > {strings.exames} @@ -1026,7 +1034,7 @@ export default function PacientePage() { variant={tab==='perfil'?'secondary':'ghost'} aria-current={tab==='perfil'} onClick={()=>setTab('perfil')} - className={`justify-start ${tab==='perfil' ? 'bg-primary/10 text-primary' : ''}`} + className={`justify-start hover:!bg-primary hover:!text-white transition-colors ${tab==='perfil' ? 'bg-primary/10 text-primary' : ''}`} > {strings.perfil} diff --git a/susconecta/app/profissional/page.tsx b/susconecta/app/profissional/page.tsx index 5efa5be..74794b5 100644 --- a/susconecta/app/profissional/page.tsx +++ b/susconecta/app/profissional/page.tsx @@ -690,9 +690,9 @@ const ProfissionalPage = () => { variant="outline" size="sm" onClick={() => navigateDate('prev')} - className="p-2 hover:bg-blue-50 cursor-pointer dark:hover:bg-primary dark:hover:text-primary-foreground" + className="p-2 hover:!bg-primary hover:!text-white cursor-pointer transition-colors" > - +

{formatDate(currentCalendarDate)} @@ -701,9 +701,9 @@ const ProfissionalPage = () => { variant="outline" size="sm" onClick={() => navigateDate('next')} - className="p-2 hover:bg-blue-50 cursor-pointer dark:hover:bg-primary dark:hover:text-primary-foreground" + className="p-2 hover:!bg-primary hover:!text-white cursor-pointer transition-colors" > - +

@@ -900,7 +900,7 @@ const ProfissionalPage = () => { variant={selectedRange === 'todos' ? 'default' : 'outline'} size="sm" onClick={() => setSelectedRange('todos')} - className="hover:bg-primary/10 hover:text-primary" + className="hover:!bg-primary hover:!text-white transition-colors" > Todos @@ -908,7 +908,7 @@ const ProfissionalPage = () => { variant={selectedRange === 'semana' ? 'default' : 'outline'} size="sm" onClick={() => setSelectedRange('semana')} - className="hover:bg-primary/10 hover:text-primary" + className="hover:!bg-primary hover:!text-white transition-colors" > Semana @@ -916,7 +916,7 @@ const ProfissionalPage = () => { variant={selectedRange === 'mes' ? 'default' : 'outline'} size="sm" onClick={() => setSelectedRange('mes')} - className="hover:bg-primary/10 hover:text-primary" + className="hover:!bg-primary hover:!text-white transition-colors" > Mês @@ -1077,7 +1077,7 @@ const ProfissionalPage = () => { -
@@ -1383,7 +1383,7 @@ const ProfissionalPage = () => { setIsViewing(true); } }} - className="flex items-center gap-1 hover:bg-blue-50 dark:hover:bg-accent dark:hover:text-accent-foreground" + className="flex items-center gap-1 hover:!bg-primary hover:!text-white transition-colors" > Ver Laudo @@ -2457,7 +2457,7 @@ const ProfissionalPage = () => { Este editor permite escrever relatórios de forma livre, com formatação de texto rica.
- {/* botão 'Salvar Rascunho' removido por não ser utilizado */} @@ -2656,7 +2656,7 @@ const ProfissionalPage = () => { -
@@ -2779,7 +2779,7 @@ const ProfissionalPage = () => { {isEditingProfile && (
-

@@ -2875,7 +2875,7 @@ const ProfissionalPage = () => {

- diff --git a/susconecta/components/simple-theme-toggle.tsx b/susconecta/components/simple-theme-toggle.tsx index c322131..3f96dcd 100644 --- a/susconecta/components/simple-theme-toggle.tsx +++ b/susconecta/components/simple-theme-toggle.tsx @@ -17,7 +17,7 @@ export function SimpleThemeToggle() { variant="outline" size="icon" onClick={toggleTheme} - className="hover:text-muted-foreground cursor-pointer !shadow-sm !shadow-black/10 !border-2 !border-black dark:!shadow-none dark:!border-border" + className="hover:!bg-primary hover:!text-white hover:!border-primary cursor-pointer !shadow-sm !shadow-black/10 !border-2 !border-black dark:!shadow-none dark:!border-border transition-colors" > diff --git a/susconecta/components/ui/sidebar.tsx b/susconecta/components/ui/sidebar.tsx index 116d4d3..4409ae3 100644 --- a/susconecta/components/ui/sidebar.tsx +++ b/susconecta/components/ui/sidebar.tsx @@ -266,7 +266,7 @@ function SidebarTrigger({ data-slot="sidebar-trigger" variant="ghost" size="icon" - className={cn("size-7", className)} + className={cn("size-7 hover:!bg-primary hover:!text-white transition-colors", className)} onClick={(event) => { onClick?.(event) toggleSidebar() -- 2.47.2 From d2bb921b69d589cca9fd0535e37235e4b2a42233 Mon Sep 17 00:00:00 2001 From: Jonas Francisco Date: Thu, 30 Oct 2025 18:47:41 -0300 Subject: [PATCH 4/8] feat(paciente): padronizar tipografia e ajustar estilo dos cards do dashboard --- susconecta/app/paciente/page.tsx | 37 ++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/susconecta/app/paciente/page.tsx b/susconecta/app/paciente/page.tsx index eb631df..75211ca 100644 --- a/susconecta/app/paciente/page.tsx +++ b/susconecta/app/paciente/page.tsx @@ -341,16 +341,35 @@ export default function PacientePage() { }, [patientId]) return ( -
- - - {strings.proximaConsulta} - {loading ? '...' : (nextAppt ?? '-')} +
+ +
+
+ +
+ + {strings.proximaConsulta} + + {/* mesmo tamanho e fonte do rótulo */} + + {loading ? '—' : (nextAppt ?? '-')} + +
- - - {strings.ultimosExames} - {loading ? '...' : (examsCount !== null ? String(examsCount) : '-')} + + +
+
+ +
+ + {strings.ultimosExames} + + {/* mesmo tamanho e fonte do rótulo */} + + {loading ? '—' : (examsCount !== null ? String(examsCount) : '-')} + +
) -- 2.47.2 From 3ff349905d119ebf31149d3d0fa65d43300f843e Mon Sep 17 00:00:00 2001 From: Jonas Francisco Date: Thu, 30 Oct 2025 18:59:24 -0300 Subject: [PATCH 5/8] =?UTF-8?q?style(paciente):=20padronizar=20fonte=20e?= =?UTF-8?q?=20tamanho=20dos=20r=C3=B3tulos=20e=20n=C3=BAmeros=20nos=20card?= =?UTF-8?q?s=20do=20dashboard?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- susconecta/app/paciente/page.tsx | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/susconecta/app/paciente/page.tsx b/susconecta/app/paciente/page.tsx index a1b52ee..0b79647 100644 --- a/susconecta/app/paciente/page.tsx +++ b/susconecta/app/paciente/page.tsx @@ -347,11 +347,11 @@ export default function PacientePage() {
- + {/* rótulo e número com mesma fonte e mesmo tamanho (harmônico) */} + {strings.proximaConsulta} - {/* mesmo tamanho e fonte do rótulo */} - + {loading ? '—' : (nextAppt ?? '-')}
@@ -362,11 +362,10 @@ export default function PacientePage() {
- + {strings.ultimosExames} - {/* mesmo tamanho e fonte do rótulo */} - + {loading ? '—' : (examsCount !== null ? String(examsCount) : '-')}
@@ -864,20 +863,20 @@ export default function PacientePage() {
Nenhum laudo encontrado para este paciente.
) : ( reports.map((r) => ( -
+
-
{reportTitle(r)}
-
Data: {new Date(r.report_date || r.created_at || Date.now()).toLocaleDateString('pt-BR')}
+
{reportTitle(r)}
+
Data: {new Date(r.report_date || r.created_at || Date.now()).toLocaleDateString('pt-BR')}
-
- - +
+ +
)) )}
- + !open && setSelectedReport(null)}> @@ -886,7 +885,7 @@ export default function PacientePage() { {selectedReport && ( <>
-
{reportTitle(selectedReport, reportDoctorName)}
+
{reportTitle(selectedReport, reportDoctorName)}
Data: {new Date(selectedReport.report_date || selectedReport.created_at || Date.now()).toLocaleDateString('pt-BR')}
{reportDoctorName &&
Profissional: {reportDoctorName}
}
-- 2.47.2 From d3c897d95ad3fa802382f7aefdfaf30854db7566 Mon Sep 17 00:00:00 2001 From: M-Gabrielly Date: Thu, 30 Oct 2025 22:57:26 -0300 Subject: [PATCH 6/8] fix: Redesign of the patient portal and add hovers - placed hovers on the medical and administrator/manager/secretary pages - Transformed "Scheduled Appointments" modal into a normal page section - Reorganized flex layout for responsive grid [220px_1fr] - Redesigned header with avatar, patient info, and rounded edges, now sticky - Side menu revamped with rounded edges, sticky and responsive - Appointment cards with gradients, smooth hovers, and responsive grid layout - Unified visual standard with professional/doctor page - Improvements: reduced icons, consistent spacing, smooth transitions - Content remains centered without forced margins - Responsiveness guaranteed for mobile, tablet, and desktop --- .../app/(main-routes)/calendar/page.tsx | 4 +- .../app/(main-routes)/consultas/page.tsx | 20 +- .../app/(main-routes)/dashboard/page.tsx | 2 +- .../dashboard/relatorios/page.tsx | 17 +- .../app/(main-routes)/doutores/page.tsx | 20 +- .../app/(main-routes)/pacientes/page.tsx | 22 +- susconecta/app/paciente/page.tsx | 303 +++++++++--------- .../app/resultados/ResultadosClient.tsx | 35 +- susconecta/components/ui/dropdown-menu.tsx | 2 +- 9 files changed, 223 insertions(+), 202 deletions(-) diff --git a/susconecta/app/(main-routes)/calendar/page.tsx b/susconecta/app/(main-routes)/calendar/page.tsx index f1ce1b3..148bf33 100644 --- a/susconecta/app/(main-routes)/calendar/page.tsx +++ b/susconecta/app/(main-routes)/calendar/page.tsx @@ -147,7 +147,7 @@ export default function AgendamentoPage() {