modified: index.html

modified:   src/App.jsx
modified:   src/components/AppShell.jsx
modified:   src/components/featureStateStyles.js
modified:   src/config/permissions.js
modified:   src/hooks/useAgenda.js
modified:   src/mappers/reportMapper.js
modified:   src/pages/AgendaPage.jsx
modified:   src/pages/AnalyticsPage.jsx
modified:   src/pages/AuthPages.jsx
modified:   src/pages/HomePage.jsx
modified:   src/pages/MedicalRecordsPage.jsx
modified:   src/pages/MessagesPage.jsx
modified:   src/pages/PatientsPage.jsx
modified:   src/pages/ReportsPage.jsx
modified:   src/pages/SettingsPage.jsx
deleted:    src/pages/TeamPage.jsx
modified:   src/pages/UsersPage.jsx
modified:   src/repositories/availabilityRepository.js
modified:   src/repositories/patientRepository.js
modified:   src/repositories/professionalRepository.js
modified:   src/repositories/reportRepository.js
modified:   src/repositories/settingsRepository.js
This commit is contained in:
2026-05-07 01:11:10 -03:00
parent 9335e974eb
commit efb942d5aa
23 changed files with 1461 additions and 591 deletions

View File

@@ -9,14 +9,25 @@ export const patientRepository = {
},
async getById(patientId) {
const patients = await this.getAll()
const [patients, appointments] = await Promise.all([
this.getAll(),
getAppointments().catch(() => []),
])
const patient = patients.find((p) => String(p.id) === String(patientId)) || null
return patient ? mapPatientToDetail(patient) : null
return patient ? mapPatientToDetail(patient, appointments) : null
},
async getDirectoryRows() {
const patients = await this.getAll()
return patients.map(mapPatientToDirectory)
async getDirectoryRows({ doctorId } = {}) {
const [patients, appointments] = await Promise.all([
this.getAll().catch(() => []),
getAppointments({ doctorId }).catch(() => []),
])
const visiblePatients = doctorId
? getPatientsFromDoctorAppointments(patients, appointments)
: patients
return visiblePatients.map((patient) => mapPatientToDirectory(patient, appointments))
},
// 2. Criar paciente (direto)
@@ -26,7 +37,7 @@ export const patientRepository = {
cpf: data.cpf,
email: data.email,
phone_mobile: data.phone,
birth_date: data.birthDate || null,
birth_date: data.birthDate || data.birth_date || null,
created_by: data.createdBy || '00000000-0000-0000-0000-000000000000',
}
@@ -52,7 +63,7 @@ export const patientRepository = {
cpf: data.cpf,
email: data.email,
phone_mobile: data.phone,
birth_date: data.birthDate || null,
birth_date: data.birthDate || data.birth_date || null,
created_by: data.createdBy || '00000000-0000-0000-0000-000000000000',
}
@@ -77,7 +88,7 @@ export const patientRepository = {
cpf: data.cpf,
email: data.email,
phone_mobile: data.phone,
birth_date: data.birthDate || null,
birth_date: data.birthDate || data.birth_date || null,
}
const response = await fetch(`${apiConfig.restUrl}/patients?id=eq.${patientId}`, {
@@ -102,41 +113,200 @@ export const patientRepository = {
},
}
function mapPatientToDirectory(patient) {
function mapPatientToDirectory(patient, appointments = []) {
const appointmentSummary = summarizeAppointments(patient.id, appointments)
const city = getFirstValue(patient, ['city', 'cidade', 'address_city', 'municipio'], patient.address?.city)
const state = getFirstValue(patient, ['state', 'uf', 'address_state', 'estado'], patient.address?.state)
const insurance = getFirstValue(patient, ['insurance', 'convenio', 'health_insurance', 'insurance_name'])
return {
...patient,
name: patient.name || patient.full_name || patient.nome || 'Paciente',
phone: patient.phone || patient.phone_mobile || patient.telefone || '',
detailId: patient.id,
insurance: patient.insurance || patient.convenio || 'Particular',
city: patient.city || patient.cidade || 'Recife',
state: patient.state || patient.uf || 'PE',
insurance: normalizeInsurance(insurance),
city,
state,
vip: Boolean(patient.vip),
lastVisitIso: patient.lastVisitIso || patient.last_visit_iso || null,
lastVisit: patient.lastVisit || patient.last_visit || 'Ainda não houve atendimento',
nextVisit: patient.nextVisit || patient.next_visit || 'Nenhum atendimento agendado',
birthDate: patient.birthDate || patient.birth_date || '',
motherName: patient.motherName || patient.mother_name || patient.nome_mae || '',
fatherName: patient.fatherName || patient.father_name || patient.nome_pai || '',
ethnicity: patient.ethnicity || patient.etnia || '',
maritalStatus: patient.maritalStatus || patient.marital_status || patient.estado_civil || '',
phoneSecondary: patient.phoneSecondary || patient.phone_secondary || patient.phone_home || '',
zipCode: patient.zipCode || patient.zip_code || patient.cep || '',
addressStreet: patient.addressStreet || patient.address_street || patient.street || patient.logradouro || patient.address || '',
addressNumber: patient.addressNumber || patient.address_number || patient.numero || '',
addressComplement: patient.addressComplement || patient.address_complement || patient.complemento || '',
plan: patient.plan || patient.plano || patient.insurance_plan || '',
notesText: patient.notesText || patient.notes_text || patient.observations || patient.observacoes || '',
lastVisitIso: patient.lastVisitIso || patient.last_visit_iso || appointmentSummary.lastVisitIso || null,
lastVisit: patient.lastVisit || patient.last_visit || appointmentSummary.lastVisit || '',
nextVisit: patient.nextVisit || patient.next_visit || appointmentSummary.nextVisit || '',
}
}
function mapPatientToDetail(patient) {
const directory = mapPatientToDirectory(patient)
function mapPatientToDetail(patient, appointments = []) {
const directory = mapPatientToDirectory(patient, appointments)
return {
...directory,
age: patient.age || patient.idade || calculateAge(patient.birth_date),
document: patient.document || patient.cpf || 'CPF não informado',
plan: directory.insurance,
plan: directory.plan || directory.insurance,
condition: patient.condition || patient.condicao || 'Sem condicao principal',
status: patient.status || 'Acompanhamento',
risk: patient.risk || patient.risco || 'Baixo',
email: patient.email || '',
address: patient.address || patient.endereco || 'Endereço não informado',
address: formatAddress(directory) || patient.address || patient.endereco || 'Endereço não informado',
team: patient.team || patient.equipe || [],
notes: patient.notes || patient.observacoes || [],
notes: normalizeNotes(patient.notes || patient.observacoes || directory.notesText),
exams: patient.exams || patient.exames || [],
}
}
async function getAppointments({ doctorId } = {}) {
const query = new URLSearchParams()
query.set('select', '*,patients(*)')
if (doctorId) {
query.set('doctor_id', `eq.${doctorId}`)
}
const response = await fetch(`${apiConfig.restUrl}/appointments?${query.toString()}`, {
headers: getAuthenticatedHeaders(),
})
if (!response.ok) return []
return response.json()
}
function getPatientsFromDoctorAppointments(patients, appointments) {
const patientById = new Map(
patients
.map((patient) => [normalizeId(patient.id), patient])
.filter(([id]) => id),
)
const visibleIds = new Set()
for (const appointment of appointments) {
const patientId = normalizeId(
appointment.patient_id ||
appointment.patientId ||
appointment.paciente_id ||
appointment.patients?.id ||
appointment.patient?.id ||
appointment.paciente?.id,
)
if (!patientId) continue
visibleIds.add(patientId)
if (!patientById.has(patientId)) {
const embeddedPatient = appointment.patients || appointment.patient || appointment.paciente
if (embeddedPatient) {
patientById.set(patientId, { ...embeddedPatient, id: embeddedPatient.id || patientId })
}
}
}
return [...visibleIds]
.map((patientId) => patientById.get(patientId))
.filter(Boolean)
}
function summarizeAppointments(patientId, appointments) {
const now = new Date()
const normalizedPatientId = String(patientId)
const patientAppointments = appointments
.filter((appointment) => String(appointment.patient_id || appointment.patientId || appointment.paciente_id || '') === normalizedPatientId)
.map((appointment) => ({
...appointment,
date: getAppointmentDate(appointment),
}))
.filter((appointment) => appointment.date)
.sort((a, b) => a.date - b.date)
const past = patientAppointments.filter((appointment) => appointment.date < now)
const future = patientAppointments.filter((appointment) => appointment.date >= now)
const last = past.at(-1)
const next = future[0]
return {
lastVisitIso: last ? formatDateInput(last.date) : null,
lastVisit: last ? formatAppointmentLabel(last.date) : '',
nextVisit: next ? formatAppointmentLabel(next.date) : '',
}
}
function getAppointmentDate(appointment) {
if (appointment.scheduled_at) {
const date = new Date(appointment.scheduled_at)
return Number.isNaN(date.getTime()) ? null : date
}
const dateValue = appointment.date || appointment.appointment_date || appointment.data
const timeValue = appointment.time || appointment.appointment_time || appointment.hora || '00:00'
if (!dateValue) return null
const date = new Date(`${dateValue}T${timeValue}`)
return Number.isNaN(date.getTime()) ? null : date
}
function formatAppointmentLabel(date) {
return new Intl.DateTimeFormat('pt-BR', {
day: '2-digit',
month: '2-digit',
year: 'numeric',
hour: '2-digit',
minute: '2-digit',
}).format(date)
}
function formatDateInput(date) {
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}
function getFirstValue(source, keys, fallback = '') {
for (const key of keys) {
if (source?.[key]) return source[key]
}
return fallback || ''
}
function normalizeId(value) {
return String(value || '').trim()
}
function formatAddress(patient) {
return [
patient.addressStreet,
patient.addressNumber,
patient.addressComplement,
patient.city,
patient.state,
patient.zipCode,
]
.filter(Boolean)
.join(', ')
}
function normalizeNotes(notes) {
if (Array.isArray(notes)) return notes
if (!notes) return []
return [String(notes)]
}
function normalizeInsurance(value) {
const normalized = String(value || '').trim()
if (normalized.toLowerCase() === 'bradesco saude') return 'Bradesco Saúde'
return normalized
}
function calculateAge(birthDate) {
if (!birthDate) return 0