Files
riseup_squad_03/src/repositories/repositoryUtils.js
letvb20-dot db7a2fe8f5 modo-claro
modified:   src/hooks/useAgenda.js
modified:   src/index.css
modified:   src/main.jsx
modified:   src/mappers/reportMapper.js
modified:   src/pages/AgendaPage.jsx
modified:   src/pages/AuthPages.jsx
modified:   src/pages/MedicalRecordsPage.jsx
modified:   src/pages/PatientsPage.jsx
modified:   src/pages/ReportsPage.jsx
modified:   src/pages/SettingsPage.jsx
modified:   src/repositories/analyticsRepository.js
modified:   src/repositories/authRepository.js
modified:   src/repositories/patientRepository.js
modified:   src/repositories/reportRepository.js
modified:   src/repositories/repositoryUtils.js
new file:   src/utils/theme.js
new file:   vercel.json
2026-05-07 05:51:07 -03:00

135 lines
4.2 KiB
JavaScript

export async function fetchJsonWithFallback(requests, fallbackMessage) {
let lastResponse = null
let lastError = null
for (const request of requests) {
let response
try {
response = await fetch(request.url, request.options)
lastResponse = response
} catch (error) {
lastError = error
continue
}
if (response.ok) {
return parseJsonResponse(response)
}
if (!shouldFallback(response)) {
throw new Error(await getResponseError(response, fallbackMessage))
}
}
if (lastError && !lastResponse) {
throw new Error(translateErrorMessage(lastError.message || fallbackMessage))
}
throw new Error(await getResponseError(lastResponse, fallbackMessage))
}
export function normalizeCollection(data, keys = []) {
if (Array.isArray(data)) return data
for (const key of keys) {
if (Array.isArray(data?.[key])) return data[key]
}
return []
}
export function normalizeItem(data, keys = []) {
if (Array.isArray(data)) return data[0] || null
for (const key of keys) {
if (data?.[key]) return data[key]
}
return data || null
}
export async function getResponseError(response, fallbackMessage) {
if (!response) return fallbackMessage
const text = await response.text().catch(() => '')
const error = parseErrorBody(text)
const message = translateErrorMessage(
error.error_description ||
error.msg ||
error.message ||
error.error ||
error.details ||
error.hint ||
text ||
fallbackMessage,
)
return response.status ? `${fallbackMessage} (${response.status}): ${message}` : message
}
export function translateErrorMessage(message) {
const rawMessage = String(message || '').trim()
const normalized = rawMessage.toLowerCase()
if (!rawMessage) return 'Erro inesperado.'
if (isPortugueseMessage(rawMessage)) return rawMessage
const translations = [
[/failed to fetch|networkerror|load failed|network request failed/, 'Não foi possível conectar ao servidor. Verifique sua conexão e tente novamente.'],
[/invalid login credentials|invalid credentials/, 'E-mail ou senha inválidos.'],
[/email not confirmed/, 'E-mail ainda não confirmado. Verifique sua caixa de entrada.'],
[/user already registered|already registered/, 'Este e-mail já está cadastrado.'],
[/user not found/, 'Usuário não encontrado.'],
[/jwt expired|invalid jwt|jwt malformed|invalid token|token is expired/, 'Sessão expirada. Faça login novamente.'],
[/missing required parameters?/, 'Parâmetros obrigatórios não foram enviados.'],
[/duplicate key value violates unique constraint/, 'Já existe um registro com essas informações.'],
[/new row violates row-level security policy|row-level security policy|permission denied/, 'Você não tem permissão para realizar esta ação.'],
[/violates foreign key constraint/, 'Não foi possível salvar porque há um vínculo obrigatório ausente ou inválido.'],
[/null value in column "([^"]+)".*violates not-null constraint/, 'Campo obrigatório não preenchido.'],
[/invalid input value for enum ([^:]+): "([^"]+)"/, 'Valor inválido para uma opção do sistema.'],
[/invalid input syntax for type uuid/, 'Identificador inválido enviado para a API.'],
[/relation .* does not exist/, 'Recurso da API não encontrado.'],
[/function .* does not exist/, 'Endpoint da API não encontrado.'],
[/cors|preflight/, 'A API bloqueou a requisição por configuração de CORS.'],
]
for (const [pattern, translation] of translations) {
if (pattern.test(normalized)) return translation
}
return rawMessage
}
function isPortugueseMessage(message) {
return /[ãõáéíóúâêôç]/i.test(message) ||
/\b(erro|falha|não|nao|usuário|usuario|senha|campo|obrigatório|obrigatorio|sessão|sessao)\b/i.test(message)
}
function shouldFallback(response) {
return [404, 405].includes(response.status)
}
async function parseJsonResponse(response) {
if (response.status === 204) return null
const text = await response.text()
if (!text) return null
try {
return JSON.parse(text)
} catch {
return { message: text }
}
}
function parseErrorBody(text) {
if (!text) return {}
try {
return JSON.parse(text)
} catch {
return { message: text }
}
}