import React, { useState, useEffect, useRef, useMemo } from 'react';
import {
Users, Heart, Activity, Stethoscope, ChevronLeft, Loader2,
Footprints, ShieldAlert, FileText, Plus, CheckSquare, Square,
Camera, Trash2, X, Scale, Ruler, Droplets,
Printer, ArrowRight, User, Award, CalendarClock, CheckCircle2,
Zap, Image as ImageIcon, FileHeart, Syringe, BarChart3, PieChart, Weight,
Pill, FilePlus, QrCode, List, Search as SearchIcon, AlertTriangle,
Edit, Smartphone, Lock, LogIn, LogOut,
Volume2, PlayCircle, ArrowLeft, Phone, Utensils, CreditCard, Eye, Table2,
Scissors, Sparkles, Smile, Video, ArrowDown, Building, Database,
FileSpreadsheet, Cigarette, TrendingUp, Filter, MapPin, Search, Save, UserPlus, History
} from 'lucide-react';
import { initializeApp } from 'firebase/app';
import {
getFirestore, collection, doc, setDoc, addDoc, updateDoc, onSnapshot,
query, where
} from 'firebase/firestore';
import {
getAuth, signInAnonymously, signInWithCustomToken, onAuthStateChanged
} from 'firebase/auth';
// --- CONFIGURAÇÃO FIREBASE ---
const firebaseConfig = JSON.parse(__firebase_config);
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const db = getFirestore(app);
// ID fixo para persistência dos dados
const appId = typeof __app_id !== 'undefined' ? __app_id : 'esf-patricia-v-master-2';
// --- CONSTANTES GLOBAIS (CORREÇÃO DO ERRO) ---
const DOCTOR_NAME = "Dra. Patrícia Szlachta Senna";
const DOCTOR_CRM = "CRM MS 12795";
const CITY_NAME = "Camapuã - MS"; // Variável restaurada
const PASSWORD_PROFESSIONAL = "esf123"; // Fixed variable name mismatch
const PASS_ADMIN = "admin123";
// --- HELPERS ---
const calculateAge = (birthDate) => {
if (!birthDate) return 0;
const today = new Date();
const birth = new Date(birthDate);
let age = today.getFullYear() - birth.getFullYear();
const m = today.getMonth() - birth.getMonth();
if (m < 0 || (m === 0 && today.getDate() < birth.getDate())) age--;
return age;
};
const formatDate = (dateString) => {
if (!dateString) return '';
const [y, m, d] = dateString.split('-');
return `${d}/${m}/${y}`;
};
// Formatação e Validação
const formatCPF = (v) => v.replace(/\D/g, '').replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, '$1.$2.$3-$4').slice(0, 14);
const formatCNS = (v) => v.replace(/\D/g, '').replace(/(\d{3})(\d{4})(\d{4})(\d{4})/, '$1 $2 $3 $4').slice(0, 18);
const formatPA = (v) => {
const n = v.replace(/\D/g, '').slice(0, 6);
return n.length > 3 ? n.replace(/(\d{3})(\d+)/, '$1/$2') : n;
};
const isValidCPF = (cpf) => cpf.replace(/\D/g, '').length === 11;
// Cálculo CKD-EPI 2021 (Creatinina)
const calculateCKDEPI = (creat, age, sex) => {
if (!creat || !age || !sex) return null;
const cr = parseFloat(creat);
const k = sex === 'Feminino' ? 0.7 : 0.9;
const alpha = sex === 'Feminino' ? -0.329 : -0.411;
const genderFactor = sex === 'Feminino' ? 1.018 : 1;
const minPart = Math.min(cr / k, 1) ** alpha;
const maxPart = Math.max(cr / k, 1) ** -1.200;
const agePart = 0.9938 ** age;
const gfr = 142 * minPart * maxPart * agePart * genderFactor;
return gfr.toFixed(1);
};
// Cálculo Carga Tabágica
const calculateTobaccoLoad = (packsPerDay, years) => {
return (parseFloat(packsPerDay) * parseFloat(years)).toFixed(1);
};
const checkVaccineStatus = (dateString, yearsValid) => {
if (!dateString) return { status: 'missing', msg: 'Pendente' };
const last = new Date(dateString);
const now = new Date();
const diffYears = (now - last) / (1000 * 60 * 60 * 24 * 365);
if (diffYears < yearsValid) return { status: 'ok', msg: 'Em Dia' };
return { status: 'expired', msg: 'Vencida' };
};
const compressImage = (file) => {
return new Promise((resolve) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = (e) => {
const img = new Image();
img.src = e.target.result;
img.onload = () => {
const canvas = document.createElement('canvas');
const MAX_WIDTH = 800;
const scale = MAX_WIDTH / img.width;
canvas.width = MAX_WIDTH;
canvas.height = img.height * scale;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
resolve(canvas.toDataURL('image/jpeg', 0.6));
};
};
});
};
// Helper para calcular a data de retorno sugerida
const getSuggestedReturnDate = (examDate, returnString) => {
if (!examDate || !returnString) return null;
const date = new Date(examDate);
let months = 12;
if (returnString.includes('1 a 3')) months = 3;
else if (returnString.includes('3 a 6')) months = 6;
else if (returnString.includes('12')) months = 12;
date.setMonth(date.getMonth() + months);
return date.toLocaleDateString('pt-BR', { month: 'long', year: 'numeric' });
};
// Ícone personalizado
const RepeatIcon = (props) => (
);
// --- COMPONENTES VISUAIS ---
const SimpleChart = ({ title, data, dataKey, color, limit }) => {
if (!data || data.length < 2) return null;
const chartData = [...data].reverse().slice(0, 5).reverse();
const maxVal = Math.max(...chartData.map(d => parseFloat(d[dataKey]) || 0)) * 1.1;
return (
{title} (Evolução)
{chartData.map((d, i) => {
const val = parseFloat(d[dataKey]) || 0;
const height = (val / maxVal) * 100;
return (
{val}
{new Date(d.timestamp).toLocaleDateString().slice(0,5)}
);
})}
);
};
const NailCutProSVG = () => (
);
const ShoeSVG = () => (
);
const ProFootMap = ({ side, markers, onAddMarker, onRemoveMarker, readOnly = false }) => {
const svgRef = useRef(null);
const isRight = side === 'pd';
const handleClick = (e) => {
if (readOnly) return;
const svg = svgRef.current;
if (!svg) return;
const pt = svg.createSVGPoint();
pt.x = e.clientX; pt.y = e.clientY;
const cursorpt = pt.matrixTransform(svg.getScreenCTM().inverse());
onAddMarker({ x: cursorpt.x, y: cursorpt.y, side });
};
const footColor = "#fff7ed"; const outlineColor = "#94a3b8";
return (
{isRight ? 'Pé Direito' : 'Pé Esquerdo'}
{markers && markers.map((m, i) => (
{ e.stopPropagation(); if(!readOnly) onRemoveMarker(i, side); }} />
))}
);
};
// --- COMPONENTE: ESPAÇO DO PACIENTE ---
const PatientArea = ({ onBack, patients, allExams }) => {
const [section, setSection] = useState('home');
const [videoModal, setVideoModal] = useState({ open: false, title: '' });
const [loginData, setLoginData] = useState({ cpf: '', sus: '' });
const [currentPatient, setCurrentPatient] = useState(null);
const [patientLastExam, setPatientLastExam] = useState(null);
const [loginError, setLoginError] = useState('');
// --- LINKS ---
const LINK_FISIO = "https://www.youtube.com/results?search_query=exercicios+pe+diabetico+alongamento";
const LINK_NUTRI = "https://www.youtube.com/results?search_query=dicas+nutricionais+diabetes";
const LINK_MEDICA = "https://www.youtube.com/results?search_query=cuidados+diabetes+dra+patricia";
const LINK_ENF_LARA = "https://www.youtube.com/results?search_query=cuidados+diabetes+enf+lara";
const handlePatientLogin = (e) => {
e.preventDefault();
const found = patients.find(p => p.cpf === loginData.cpf && p.chartId === loginData.sus);
if (found) {
setCurrentPatient(found);
const exams = allExams.filter(e => e.patientId === found.id).sort((a,b) => b.timestamp - a.timestamp);
setPatientLastExam(exams.length > 0 ? exams[0] : null);
setSection('prontuario');
setLoginError('');
} else {
setLoginError('Ops, identificamos que ainda não possui cadastro nesse sistema. Nos contate para poder ter acesso.');
}
};
const playVideo = (title) => {
setVideoModal({ open: true, title });
};
const videosFisio = [
{ title: "Exercício Sentado", icon: Activity },
{ title: "Alongamento Panturrilha", icon: Footprints },
{ title: "O sapato certo", icon: Footprints },
{ title: "Massagem nos Pés", icon: Smile },
{ title: "Cãibras: Como aliviar", icon: Zap }
];
const videosNutri = [
{ title: "Quais frutas pode?", icon: Utensils },
{ title: "Montar o Prato", icon: PieChart },
{ title: "Água ou Suco?", icon: Droplets },
{ title: "Qual Pão Comer?", icon: Utensils },
{ title: "Lanches Saudáveis", icon: Smile },
{ title: "Receitas Low Carb", icon: Utensils },
{ title: "Doces e Diabetes", icon: AlertTriangle }
];
const videosMedica = [
{ title: "Entender Exames", icon: FileText },
{ title: "Hipoglicemia: O que fazer", icon: AlertTriangle },
{ title: "Diabetes e Visão", icon: Eye },
{ title: "Quando ir ao PS?", icon: ShieldAlert },
{ title: "Sinais de Infarto", icon: Heart },
{ title: "Pé Diabético: Sinais", icon: Footprints }
];
const videosEnf = [
{ title: "Aplicar Insulina", icon: Syringe },
{ title: "Rodízio de Aplicação", icon: RepeatIcon },
{ title: "Medir Certo (HGT)", icon: Droplets },
{ title: "Descarte de Agulhas", icon: Trash2 },
{ title: "Curativo Simples", icon: Scissors }
];
return (
{section === 'home' && (
Toque para entrar: setSection('fisio')} className="bg-orange-100 border-2 border-orange-400 p-4 rounded-2xl cursor-pointer flex flex-col items-center justify-center text-center h-56 shadow-sm active:scale-95 transition-transform">Movimente-se Cuidados Fisioterapeuta
setSection('nutri')} className="bg-green-100 border-2 border-green-500 p-4 rounded-2xl cursor-pointer flex flex-col items-center justify-center text-center h-56 shadow-sm active:scale-95 transition-transform">Alimente-se Bem Cuidados Nutricionista
setSection('medica')} className="bg-blue-100 border-2 border-blue-600 p-4 rounded-2xl cursor-pointer flex flex-col items-center justify-center text-center h-56 shadow-sm active:scale-95 transition-transform">
Cuidados com Dra. Patrícia setSection('enfermeira')} className="bg-pink-100 border-2 border-pink-500 p-4 rounded-2xl cursor-pointer flex flex-col items-center justify-center text-center h-56 shadow-sm active:scale-95 transition-transform">
Cuidados com Enf. Lara setSection('general-orientations')} className="mt-4 bg-emerald-500 hover:bg-emerald-600 text-white p-4 rounded-xl flex items-center justify-center shadow-md w-full mb-2 active:scale-95 transition-transform">Orientações Gerais WhatsApp da Unidade
)}
{section === 'login' && (
Acessar Prontuário Use o seu CPF e o número do Cartão do SUS como senha.
)}
{section === 'prontuario' && currentPatient && (
{ setCurrentPatient(null); setSection('home'); setLoginData({cpf:'', sus:''}); }} className="absolute top-4 right-4 bg-blue-700 hover:bg-blue-800 p-2 rounded-lg text-xs font-bold flex items-center"> Sair
{currentPatient.name} {calculateAge(currentPatient.birthDate)} anos
{patientLastExam && (
<>{patientLastExam.peso} kg {patientLastExam.altura} cm IMC {patientLastExam.imc} >
)}
{patientLastExam && (
HbA1c: {patientLastExam.hba1c}% ({parseFloat(patientLastExam.hba1c) < 7 ? 'DENTRO DO ALVO' : 'FORA DO ALVO'})
)}
setSection('my-orientations')} className="bg-emerald-100 border-2 border-emerald-300 p-5 rounded-2xl mb-6 flex items-center justify-between cursor-pointer active:scale-95 transition-transform shadow-sm">
Minhas Orientações Veja o que o médico recomendou
DiagnósticoDiabetes Mellitus {currentPatient.diabetesType}
{currentPatient.comorbidities && currentPatient.comorbidities.length > 0 && (
Comorbidades Associadas:
{currentPatient.comorbidities.map((c, i) => (
{c}
))}
)}
Medicamentos Atuais
{currentPatient.medications?.length > 0 ? (
currentPatient.medications.map((m, i) => (
))
) : (Nenhum medicamento registrado. )}
setSection('home')} className="w-full mt-6 bg-gray-200 hover:bg-gray-300 text-gray-700 font-bold py-4 rounded-xl shadow-sm">Voltar para o Início
)}
{section === 'my-orientations' && (
setSection('prontuario')} className="w-full bg-gray-200 hover:bg-gray-300 text-gray-800 font-bold py-4 px-6 rounded-xl mb-6 flex items-center shadow-md active:scale-95 transition-transform">Voltar
{patientLastExam ? (
<>
Seu Risco Atual: {patientLastExam.riscoIWGDF} Retorno sugerido em: {patientLastExam.retorno}
{getSuggestedReturnDate(patientLastExam.timestamp, patientLastExam.retorno) && (
Programar para: {getSuggestedReturnDate(patientLastExam.timestamp, patientLastExam.retorno)}
)}
Recomendação Médica {patientLastExam.conduta}
>
) : (
Bem-vindo(a) Ainda não há consultas registradas, mas siga as dicas abaixo!
)}
10 Mandamentos do Pé Diabético 1. Examine os pés diariamente com um espelho. 2. Mantenha os pés limpos e secos entre os dedos. 3. Hidrate a pele (exceto entre os dedos). 4. Corte as unhas retas. Não remova cutículas. 5. Nunca ande descalço. 6. Use calçados confortáveis e fechados. 7. Verifique o interior do sapato antes de calçar. 8. Não use água quente nos pés. 9. Não use calicidas ou lixas metálicas. 10. Em caso de ferida, procure sua unidade de saúde imediatamente.
Aponte a câmera para os códigos abaixo
Fisioterapia
Nutrição
Dra. Patrícia
Enf. Lara
)}
{section === 'general-orientations' && (
setSection('home')} className="w-full bg-gray-200 hover:bg-gray-300 text-gray-800 font-bold py-4 px-6 rounded-xl mb-6 flex items-center shadow-md active:scale-95 transition-transform">Voltar 10 Mandamentos do Pé Diabético 1. Examine os pés diariamente com um espelho. 2. Mantenha os pés limpos e secos entre os dedos. 3. Hidrate a pele (exceto entre os dedos). 4. Corte as unhas retas. Não remova cutículas. 5. Nunca ande descalço. 6. Use calçados confortáveis e fechados. 7. Verifique o interior do sapato antes de calçar. 8. Não use água quente nos pés. 9. Não use calicidas ou lixas metálicas. 10. Em caso de ferida, procure sua unidade de saúde imediatamente.
)}
{['fisio', 'nutri', 'medica', 'enfermeira'].includes(section) && (
setSection('home')} className="w-full bg-gray-200 hover:bg-gray-300 text-gray-800 font-bold py-4 px-6 rounded-xl mb-6 flex items-center shadow-md active:scale-95 transition-transform">Voltar
{section === 'fisio' ? 'Movimente-se' : section === 'nutri' ? 'Alimente-se Bem' : section === 'medica' ? 'Cuidados Médicos' : 'Cuidados Enfermagem'}
{section === 'fisio' ? 'Fisioterapeuta' : section === 'nutri' ? 'Nutricionista' : section === 'medica' ? 'Dra. Patrícia' : 'Enf. Lara'}
{(section === 'fisio' ? videosFisio : section === 'nutri' ? videosNutri : section === 'medica' ? videosMedica : videosEnf).map((v, i) => (
))}
)}
{videoModal.open && (
setVideoModal({open: false, title: ''})} className="bg-white text-black w-12 h-12 rounded-full flex items-center justify-center shadow-lg border-2 border-gray-300 active:scale-90 transition">
)}
);
};
const App = () => {
const [user, setUser] = useState(null);
const [appSection, setAppSection] = useState('welcome');
const [passwordInput, setPasswordInput] = useState('');
const [loginError, setLoginError] = useState('');
const [view, setView] = useState('list');
const [printMode, setPrintMode] = useState('clinical');
const [patients, setPatients] = useState([]);
const [selectedPatient, setSelectedPatient] = useState(null);
const [patientExams, setPatientExams] = useState([]);
const [allExams, setAllExams] = useState([]);
const [activeExam, setActiveExam] = useState(null);
const [searchQuery, setSearchQuery] = useState('');
const [isSaving, setIsSaving] = useState(false);
const [activeMarkerType, setActiveMarkerType] = useState('ulcera');
const [selectedMetric, setSelectedMetric] = useState(null);
const [patientForm, setPatientForm] = useState({
name: '', cpf: '', birthDate: '', chartId: '', diabetesType: 'Tipo 2',
comorbidities: [], medications: []
});
const [medInput, setMedInput] = useState('');
const [otherComorb, setOtherComorb] = useState('');
const initialFootState = {
sensibilidade: 'presente', diapasao: 'presente',
pulsoPedioso: 'presente', pulsoTibial: 'presente',
deformidades: [], pele: [], sintomas: [], markers: [], photo: null,
temUlcera: false, ulceraGrau: '1', sinaisInfeccao: false
};
const initialExamState = {
peso: '', altura: '', imc: '',
hba1c: '', hba1cDate: '', ldl: '', ldlDate: '', idade: '',
pa: '', hgt: '',
ha: false, tabagismo: false, albuminuria: false, loa: false,
historicoUlcera: false, historicoAmputacao: false,
calcadoAdequado: true, unhaCortadaAdequada: true, higieneOk: true,
vacinaInfluenza: '', vacinaPneumo: '',
pd: { ...initialFootState }, pe: { ...initialFootState },
riscoIWGDF: '0', retorno: '12 meses', conduta: '', riscoCV: 'Baixo'
};
const [examForm, setExamForm] = useState(initialExamState);
// --- Auth & Sync ---
useEffect(() => {
const init = async () => {
try {
if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) await signInWithCustomToken(auth, __initial_auth_token);
else await signInAnonymously(auth);
} catch (err) { console.error(err); }
};
init();
onAuthStateChanged(auth, setUser);
}, []);
useEffect(() => {
if (!user) return;
const unsubP = onSnapshot(collection(db, 'artifacts', appId, 'public', 'data', 'patients'), (snap) => {
setPatients(snap.docs.map(d => ({ id: d.id, ...d.data() })).sort((a,b) => (b.createdAt || 0) - (a.createdAt || 0)));
}, (error) => console.error(error));
const unsubE = onSnapshot(collection(db, 'artifacts', appId, 'public', 'data', 'exams'), (snap) => {
setAllExams(snap.docs.map(d => ({ id: d.id, ...d.data() })));
}, (error) => console.error(error));
return () => { unsubP(); unsubE(); };
}, [user]);
useEffect(() => {
if (!user || !selectedPatient) return;
const patExams = allExams.filter(e => e.patientId === selectedPatient.id).sort((a,b) => b.timestamp - a.timestamp);
setPatientExams(patExams);
}, [user, selectedPatient, allExams]);
const handleLogin = (e) => {
e.preventDefault();
if (passwordInput === PASSWORD_PROFESSIONAL) {
setAppSection('professional_dashboard');
setLoginError('');
setPasswordInput('');
} else {
setLoginError('Senha incorreta.');
}
};
const calculated = useMemo(() => {
const age = selectedPatient ? calculateAge(selectedPatient.birthDate) : 0;
let imc = '--.-';
if (examForm.peso && examForm.altura) {
const h = parseFloat(examForm.altura) / 100;
const w = parseFloat(examForm.peso);
if (h > 0) imc = (w / (h * h)).toFixed(1);
}
let rcv = 'Baixo';
const ldl = parseFloat(examForm.ldl) || 0;
if (examForm.loa || examForm.albuminuria) rcv = 'Muito Alto';
else if (examForm.tabagismo || examForm.ha || ldl > 130 || age > 65) rcv = 'Alto';
else if (ldl > 100 || age > 50) rcv = 'Médio';
let riwgdf = '0';
let ret = '12 meses';
const lops = examForm.pd.sensibilidade === 'ausente' || examForm.pe.sensibilidade === 'ausente' ||
examForm.pd.diapasao === 'ausente' || examForm.pe.diapasao === 'ausente';
const pad = examForm.pd.pulsoPedioso === 'ausente' || examForm.pe.pulsoPedioso === 'ausente' ||
examForm.pd.pulsoTibial === 'ausente' || examForm.pe.pulsoTibial === 'ausente';
const def = examForm.pd.deformidades.length > 0 || examForm.pe.deformidades.length > 0;
const hist = examForm.historicoUlcera || examForm.historicoAmputacao;
if (hist) { riwgdf = '3'; ret = '1 a 3 meses'; }
else if ((lops && pad) || (lops && def) || (pad && def)) { riwgdf = '2'; ret = '3 a 6 meses'; }
else if (lops || pad || def) { riwgdf = '1'; ret = '6 a 12 meses'; }
const fluStatus = checkVaccineStatus(examForm.vacinaInfluenza, 1);
const pneumoStatus = checkVaccineStatus(examForm.vacinaPneumo, 5);
return { age, imc, rcv, riwgdf, ret, fluStatus, pneumoStatus };
}, [examForm, selectedPatient]);
const analytics = useMemo(() => {
const patientMap = {};
patients.forEach(p => patientMap[p.id] = p);
const latestMap = {};
allExams.forEach(ex => {
if (!latestMap[ex.patientId] || ex.timestamp > latestMap[ex.patientId].timestamp) {
latestMap[ex.patientId] = ex;
}
});
const getName = (id) => patientMap[id]?.name || 'Desconhecido';
const activeExams = Object.values(latestMap);
const listHbA1cBad = activeExams.filter(e => parseFloat(e.hba1c) > 7).map(e => ({ name: getName(e.patientId), val: `${e.hba1c}%` }));
const listHighRiskFoot = activeExams.filter(e => ['2', '3'].includes(e.riscoIWGDF)).map(e => ({ name: getName(e.patientId), val: `Risco ${e.riscoIWGDF}` }));
const listObese = activeExams.filter(e => parseFloat(e.imc) >= 30).map(e => ({ name: getName(e.patientId), val: `IMC ${e.imc}` }));
const listFluMissing = activeExams.filter(e => checkVaccineStatus(e.vacinaInfluenza, 1).status !== 'ok').map(e => ({ name: getName(e.patientId), val: 'Vencida/ND' }));
const listPneumoMissing = activeExams.filter(e => checkVaccineStatus(e.vacinaPneumo, 5).status !== 'ok').map(e => ({ name: getName(e.patientId), val: 'Vencida/ND' }));
return { total: patients.length, listAllPatients: patients.map(p => ({name: p.name, val: 'Ativo'})), listHbA1cBad, listHighRiskFoot, listObese, listFluMissing, listPneumoMissing };
}, [patients, allExams]);
const latestExam = patientExams.length > 0 ? patientExams[0] : null;
const latestFlu = latestExam ? checkVaccineStatus(latestExam.vacinaInfluenza, 1) : {status:'missing', msg:'--'};
const latestPneumo = latestExam ? checkVaccineStatus(latestExam.vacinaPneumo, 5) : {status:'missing', msg:'--'};
const handlePhotoUpload = async (side, file) => {
if (!file) return;
const compressed = await compressImage(file);
setExamForm(prev => ({ ...prev, [side]: { ...prev[side], photo: compressed } }));
};
const addMarker = (side, x, y, type) => {
setExamForm(prev => {
const newMarkers = [...prev[side].markers, { x, y, type }];
const hasUlcer = newMarkers.some(m => m.type === 'ulcera');
return {
...prev,
[side]: { ...prev[side], markers: newMarkers, temUlcera: hasUlcer }
};
});
};
const removeMarker = (side, index) => {
setExamForm(prev => {
const newMarkers = [...prev[side].markers];
newMarkers.splice(index, 1);
const hasUlcer = newMarkers.some(m => m.type === 'ulcera');
return { ...prev, [side]: { ...prev[side], markers: newMarkers, temUlcera: hasUlcer } };
});
};
const toggleArrayItem = (side, field, value) => {
setExamForm(prev => {
const list = prev[side][field] || [];
const newList = list.includes(value) ? list.filter(i => i !== value) : [...list, value];
return { ...prev, [side]: { ...prev[side], [field]: newList } };
});
};
const toggleComorbidity = (comorb) => {
setPatientForm(prev => {
const list = prev.comorbidities || [];
const newList = list.includes(comorb) ? list.filter(c => c !== comorb) : [...list, comorb];
return { ...prev, comorbidities: newList };
});
};
const addMedication = () => {
if (!medInput) return;
setPatientForm(prev => ({ ...prev, medications: [...(prev.medications || []), medInput] }));
setMedInput('');
};
const removeMedication = (index) => {
setPatientForm(prev => {
const newList = [...(prev.medications || [])];
newList.splice(index, 1);
return { ...prev, medications: newList };
});
};
const savePatient = async (e) => {
e.preventDefault();
if (!patientForm.name) return;
setIsSaving(true);
let finalComorbs = [...(patientForm.comorbidities || [])];
if (otherComorb.trim()) finalComorbs.push(otherComorb.trim());
let finalMedications = [...(patientForm.medications || [])];
if (medInput.trim()) finalMedications.push(medInput.trim());
const dataToSave = { ...patientForm, comorbidities: finalComorbs, medications: finalMedications };
if (view === 'edit-patient' && selectedPatient) {
await updateDoc(doc(db, 'artifacts', appId, 'public', 'data', 'patients', selectedPatient.id), dataToSave);
setSelectedPatient({ ...selectedPatient, ...dataToSave });
setView('detail');
} else {
const finalPatient = { ...dataToSave, createdAt: Date.now() };
const docRef = await addDoc(collection(db, 'artifacts', appId, 'public', 'data', 'patients'), finalPatient);
setSelectedPatient({ id: docRef.id, ...finalPatient });
setView('detail');
}
setPatientForm({ name: '', cpf: '', birthDate: '', chartId: '', diabetesType: 'Tipo 2', comorbidities: [], medications: [] });
setOtherComorb('');
setMedInput('');
setIsSaving(false);
};
const saveExam = async () => {
setIsSaving(true);
const { imc, rcv, riwgdf, ret } = calculated;
const finalExam = { ...examForm, imc, riscoCV: rcv, riscoIWGDF: riwgdf, retorno: ret, patientId: selectedPatient.id, timestamp: Date.now(), doctorName: DOCTOR_NAME, doctorCrm: DOCTOR_CRM };
await addDoc(collection(db, 'artifacts', appId, 'public', 'data', 'exams'), finalExam);
setView('detail');
setExamForm({ ...initialExamState, conduta: '', peso: '', hba1c: '', ldl: '' });
setIsSaving(false);
};
const startNewExam = () => {
const hasHAS = selectedPatient?.comorbidities?.includes('HAS');
const hasTabagismo = selectedPatient?.comorbidities?.includes('Tabagismo');
const highRiskComorbs = ['IAM prévio', 'AVC', 'DAOP', 'IC', 'DRC'];
const hasLOA = selectedPatient?.comorbidities?.some(c => highRiskComorbs.includes(c));
setExamForm({ ...initialExamState, ha: hasHAS || false, tabagismo: hasTabagismo || false, loa: hasLOA || false });
setView('new-exam');
};
const startEditPatient = () => {
setPatientForm({
name: selectedPatient.name,
cpf: selectedPatient.cpf || '',
birthDate: selectedPatient.birthDate,
chartId: selectedPatient.chartId,
diabetesType: selectedPatient.diabetesType,
comorbidities: selectedPatient.comorbidities || [],
medications: selectedPatient.medications || []
});
setView('edit-patient');
};
const conductOptions = [
{ text: "Prescrevo creme hidratante (Ureia 10% / Nivea / Cerave) - aplicar diariamente, exceto entre os dedos.", icon: "🧴", label: "Hidratante" },
{ text: "Encaminho para confecção de palmilha/órtese para alívio de pressão plantar.", icon: "👟", label: "Órtese" },
{ text: "Encaminho à enfermagem para desbridamento de calosidades.", icon: "🩹", label: "Desbridamento" },
{ text: "Encaminho ao cirurgião vascular para avaliação de pulsos.", icon: "🦶", label: "Vascular" },
{ text: "Reforço orientações de corte reto das unhas e uso de calçados adequados.", icon: "✂️", label: "Unhas" }
];
if (!user) return
;
if (appSection === 'welcome') {
return (
Caderno de Saúde do Diabético setAppSection('patient_area')} className="group relative bg-white p-10 rounded-[3rem] shadow-xl border-2 border-transparent hover:border-emerald-400 hover:shadow-2xl transition-all flex flex-col items-center gap-6">
Espaço do Diabético Orientações e Cuidados
setAppSection('login')} className="group relative bg-white p-10 rounded-[3rem] shadow-xl border-2 border-transparent hover:border-indigo-400 hover:shadow-2xl transition-all flex flex-col items-center gap-6">Espaço do Profissional Acesso Restrito
{DOCTOR_NAME} • {DOCTOR_CRM}
);
}
if (appSection === 'login') {
return (
setAppSection('welcome')} className="absolute top-8 left-8 text-slate-400 hover:text-indigo-600">
Área Restrita Digite sua senha de acesso
Dica: A senha é esf123
);
}
if (appSection === 'patient_area') {
return setAppSection('welcome')} patients={patients} allExams={allExams} />;
}
return (
{selectedMetric && (
{selectedMetric.title} setSelectedMetric(null)} className="p-2 bg-slate-100 rounded-full hover:bg-slate-200">
{selectedMetric.list.length > 0 ? (
selectedMetric.list.map((item, i) => (
{item.name} {item.val}
))
) : (
Nenhum paciente nesta categoria.
)}
{selectedMetric.list.length} Registros Encontrados
)}
setView('list')}>
Caderno do Diabético {DOCTOR_NAME}
setAppSection('welcome')} className="bg-indigo-900/50 hover:bg-indigo-900 px-3 py-2 rounded-xl font-bold text-[10px] uppercase transition-all flex items-center gap-2"> Sair
{view === 'list' && (
<> setView('analytics')} className="bg-indigo-700 hover:bg-indigo-600 px-4 py-2 rounded-xl font-bold text-xs uppercase shadow-md transition-all flex items-center gap-2"> Gestão
{
setPatientForm({ name: '', cpf: '', birthDate: '', chartId: '', diabetesType: 'Tipo 2', comorbidities: [], medications: [] });
setView('new-patient');
}} className="bg-white text-indigo-800 px-4 py-2 rounded-xl font-bold text-xs uppercase shadow-md transition-all">
+ Paciente
>
)}
{view === 'analytics' && (
setView('list')} className="text-indigo-600 font-bold text-xs uppercase mb-6 flex items-center gap-1 hover:underline"> Voltar Gestão da Clínica setSelectedMetric({ title: 'Total de Pacientes', list: analytics.listAllPatients || [] })} className="bg-white p-8 rounded-[2rem] shadow-lg border border-slate-100 cursor-pointer hover:border-indigo-300">
Total Pacientes
setSelectedMetric({ title: 'HbA1c > 7%', list: analytics.listHbA1cBad })} className="bg-white p-8 rounded-[2rem] shadow-lg border border-slate-100 cursor-pointer hover:border-rose-300 hover:shadow-xl transition-all group">
{analytics.listHbA1cBad.length} HbA1c Descompensada
setSelectedMetric({ title: 'Pé Diabético Alto Risco', list: analytics.listHighRiskFoot })} className="bg-white p-8 rounded-[2rem] shadow-lg border border-slate-100 cursor-pointer hover:border-amber-300 hover:shadow-xl transition-all group">
{analytics.listHighRiskFoot.length} Pé Risco Alto
setSelectedMetric({ title: 'Pacientes com Obesidade', list: analytics.listObese })} className="bg-white p-8 rounded-[2rem] shadow-lg border border-slate-100 cursor-pointer hover:border-purple-300 hover:shadow-xl transition-all group">
{analytics.listObese.length} Obesidade
setSelectedMetric({ title: 'Atraso Influenza', list: analytics.listFluMissing })} className="bg-white p-8 rounded-[2rem] shadow-lg border border-red-100 cursor-pointer hover:bg-red-50 transition-all group">
{analytics.listFluMissing.length} Influenza Pendente
setSelectedMetric({ title: 'Atraso Pneumo 23', list: analytics.listPneumoMissing })} className="bg-white p-8 rounded-[2rem] shadow-lg border border-red-100 cursor-pointer hover:bg-red-50 transition-all group">
{analytics.listPneumoMissing.length} Pneumo 23 Pendente
)}
{view === 'list' && (
{patients.filter(p => p.name.toLowerCase().includes(searchQuery.toLowerCase())).map(p => (
{ setSelectedPatient(p); setView('detail'); }} className="bg-white p-8 rounded-[3rem] border border-slate-100 shadow-sm hover:shadow-2xl hover:border-indigo-400 cursor-pointer transition-all group overflow-hidden">
{p.name.charAt(0)}
{p.name} {calculateAge(p.birthDate)} anos • {p.diabetesType}
))}
)}
{view === 'detail' && (
setView('list')} className="p-3 bg-slate-50 rounded-2xl text-slate-400 hover:text-indigo-600 transition-colors">
{selectedPatient?.name}
{calculateAge(selectedPatient?.birthDate)} anos • CNS: {selectedPatient?.chartId} • CPF: {selectedPatient?.cpf || '---'}
Nova Consulta
Último IWGDF
{latestExam?.riscoIWGDF || '--'}
Pneumo 23
{latestPneumo.msg}
Risco CV
{latestExam?.riscoCV || '--'}
Histórico de Saúde
{selectedPatient.comorbidities && selectedPatient.comorbidities.length > 0 ? (
selectedPatient.comorbidities.map((c, i) => (
{c}
))
) : Nenhuma comorbidade registrada. }
Uso Contínuo
{selectedPatient.medications && selectedPatient.medications.length > 0 ? (
selectedPatient.medications.map((m, i) => (
{m}
))
) :
Nenhum medicamento registrado. }
Histórico
{patientExams.map(exam => (
{new Date(exam.timestamp).toLocaleDateString()} IWGDF: {exam.riscoIWGDF} { setActiveExam(exam); setPrintMode('clinical'); setView('print'); }} className="text-indigo-600 hover:bg-indigo-50 px-3 py-2 rounded-xl transition-all flex items-center gap-1 font-bold text-[9px] uppercase border border-indigo-100"> Prontuário { setActiveExam(exam); setPrintMode('patient'); setView('print'); }} className="text-emerald-600 hover:bg-emerald-50 px-3 py-2 rounded-xl transition-all flex items-center gap-1 font-bold text-[9px] uppercase border border-emerald-100"> Orientações
{(checkVaccineStatus(exam.vacinaPneumo, 5).status !== 'ok') && (
{ setActiveExam(exam); setPrintMode('crie'); setView('print'); }} className="text-rose-600 hover:bg-rose-50 px-3 py-2 rounded-xl transition-all flex items-center gap-1 font-bold text-[9px] uppercase border border-rose-100"> Laudo CRIE
)}
HbA1c
{exam.hba1c}%
{exam.hba1cDate &&
{formatDate(exam.hba1cDate)}
}
))}
)}
{view === 'new-exam' && (
setView('detail')} className="text-slate-400 font-black text-xs uppercase tracking-widest hover:text-red-500">Descartar Avaliação Integrada 1. Parâmetros Bioquímicos setExamForm({...examForm, ha: !examForm.ha})} className={`p-4 rounded-xl border-2 font-black text-xs flex justify-between items-center transition-all ${examForm.ha ? 'border-rose-600 bg-rose-50 text-rose-700' : 'border-slate-50 bg-slate-50 text-slate-400'}`}>Hipertensão? {examForm.ha ? : } setExamForm({...examForm, tabagismo: !examForm.tabagismo})} className={`p-4 rounded-xl border-2 font-black text-xs flex justify-between items-center transition-all ${examForm.tabagismo ? 'border-rose-600 bg-rose-50 text-rose-700' : 'border-slate-50 bg-slate-50 text-slate-400'}`}>Tabagismo? {examForm.tabagismo ? : } setExamForm({...examForm, albuminuria: !examForm.albuminuria})} className={`p-4 rounded-xl border-2 font-black text-xs flex justify-between items-center transition-all ${examForm.albuminuria ? 'border-red-600 bg-red-50 text-red-800' : 'border-slate-50 bg-slate-50 text-slate-400'}`}>Albuminúria? {examForm.albuminuria ? : } setExamForm({...examForm, loa: !examForm.loa})} className={`p-4 rounded-xl border-2 font-black text-xs flex justify-between items-center transition-all ${examForm.loa ? 'border-red-600 bg-red-50 text-red-800' : 'border-slate-50 bg-slate-50 text-slate-400'}`}>Lesão Órgão Alvo? {examForm.loa ? : } Risco CV: {calculated.rcv}
{/* 2. AUTOCUIDADO */}
2. Higiene e Autocuidado setExamForm({...examForm, calcadoAdequado: !examForm.calcadoAdequado})} className={`p-6 rounded-3xl border-2 font-black text-[10px] uppercase flex flex-col items-center gap-3 transition-all ${examForm.calcadoAdequado ? 'border-emerald-500 bg-emerald-50 text-emerald-700' : 'border-rose-200 bg-rose-50 text-rose-700'}`}>
{examForm.calcadoAdequado ? : } Calçado Adequado
setExamForm({...examForm, unhaCortadaAdequada: !examForm.unhaCortadaAdequada})} className={`p-6 rounded-3xl border-2 font-black text-[10px] uppercase flex flex-col items-center gap-3 transition-all ${examForm.unhaCortadaAdequada ? 'border-emerald-500 bg-emerald-50 text-emerald-700' : 'border-rose-200 bg-rose-50 text-rose-700'}`}>
{examForm.unhaCortadaAdequada ? : } Unhas Adequadas
setExamForm({...examForm, higieneOk: !examForm.higieneOk})} className={`p-6 rounded-3xl border-2 font-black text-[10px] uppercase flex flex-col items-center gap-3 transition-all ${examForm.higieneOk ? 'border-emerald-500 bg-emerald-50 text-emerald-700' : 'border-rose-200 bg-rose-50 text-rose-700'}`}>
{examForm.higieneOk ? : } Autocuidado Preservado
{/* 3. EXAME FÍSICO */}
3. Exame Físico das Extremidades
{/* SINTOMAS */}
{['Queimação', 'Formigamento', 'Cãibras', 'Dormência'].map(s => (
{
const list = examForm.pd.sintomas || [];
const newList = list.includes(s) ? list.filter(i => i !== s) : [...list, s];
setExamForm({...examForm, pd: {...examForm.pd, sintomas: newList}});
}} className={`p-4 rounded-2xl border-2 font-bold text-[10px] uppercase transition-all ${examForm.pd.sintomas?.includes(s) ? 'bg-orange-50 border-orange-400 text-orange-700' : 'bg-slate-50 border-slate-100 text-slate-400'}`}>{s}
))}
{['pd', 'pe'].map(side => (
{
const newMarkers = [...examForm[side].markers, { x: d.x, y: d.y, type: activeMarkerType }];
const hasUlcer = newMarkers.some(m => m.type === 'ulcera');
setExamForm(p => ({
...p,
[side]: {
...p[side],
markers: newMarkers,
temUlcera: hasUlcer
}
}));
}} onRemoveMarker={(i) => {
const upd = [...examForm[side].markers]; upd.splice(i, 1);
const hasUlcer = upd.some(m => m.type === 'ulcera');
setExamForm({...examForm, [side]: {...examForm[side], markers: upd, temUlcera: hasUlcer}});
}} /> setActiveMarkerType('ulcera')} className={`px-4 py-2 rounded-xl text-[10px] font-black ${activeMarkerType === 'ulcera' ? 'bg-red-600 text-white' : 'bg-white text-slate-400 border'}`}>ÚLCERA setActiveMarkerType('calo')} className={`px-4 py-2 rounded-xl text-[10px] font-black ${activeMarkerType === 'calo' ? 'bg-amber-500 text-white' : 'bg-white text-slate-400 border'}`}>CALO
{/* CLASSIFICAÇÃO DA ÚLCERA (SE HOUVER) */}
{examForm[side].temUlcera && (
Caracterização da Lesão
{['1', '2', '3'].map(g => (
setExamForm({...examForm, [side]: {...examForm[side], ulceraGrau: g}})} className={`py-2 rounded-xl border font-bold text-[9px] ${examForm[side].ulceraGrau === g ? 'bg-red-600 text-white border-red-600' : 'bg-white text-red-400 border-red-100'}`}>Grau {g}
))}
1: Superficial | 2: Profunda/Tendão | 3: Osso/Gangrena
setExamForm({...examForm, [side]: {...examForm[side], sinaisInfeccao: !examForm[side].sinaisInfeccao}})} className={`w-full py-2 rounded-xl border font-bold text-[9px] flex justify-between px-3 items-center ${examForm[side].sinaisInfeccao ? 'bg-red-100 border-red-300 text-red-800' : 'bg-white border-red-100 text-red-400'}`}>
Sinais de Infecção? {examForm[side].sinaisInfeccao ? : }
)}
{/* FOTO */}
Foto {side === 'pd' ? 'Direita' : 'Esquerda'}
{examForm[side].photo ? (
<>
setExamForm(p => ({...p, [side]: {...p[side], photo: null}}))} className="absolute top-4 right-4 bg-red-600 text-white p-2 rounded-full shadow-lg"> >
) : (
Tirar Foto handlePhotoUpload(side, e.target.files[0])} />
)}
Monofilamento 10g
{['presente', 'ausente'].map(v => (
setExamForm({...examForm, [side]: {...examForm[side], sensibilidade: v}})} className={`flex-1 py-3 rounded-2xl border-2 font-black text-[9px] uppercase transition-all ${examForm[side].sensibilidade === v ? 'border-indigo-600 bg-indigo-50 text-indigo-800' : 'border-slate-50 bg-white text-slate-300'}`}>{v}
))}
Diapasão 128Hz
{['presente', 'ausente', 'nao_avaliado'].map(v => (
setExamForm({...examForm, [side]: {...examForm[side], diapasao: v}})} className={`flex-1 py-3 rounded-2xl border-2 font-black text-[8px] uppercase transition-all ${examForm[side].diapasao === v ? (v === 'nao_avaliado' ? 'border-slate-400 bg-slate-200 text-slate-600' : 'border-indigo-600 bg-indigo-50 text-indigo-800') : 'border-slate-50 bg-white text-slate-300'}`}>{v.replace('_', ' ')}
))}
Pulsos Arteriais
{['presente', 'ausente'].map(v => (
setExamForm({...examForm, [side]: {...examForm[side], pulsoPedioso: v, pulsoTibial: v}})} className={`flex-1 py-3 rounded-2xl border-2 font-black text-[9px] uppercase transition-all ${examForm[side].pulsoPedioso === v ? 'border-indigo-600 bg-indigo-50 text-indigo-800' : 'border-slate-50 bg-white text-slate-300'}`}>{v}
))}
Deformidades
{['Garra', 'Martelo', 'Charcot', 'Hallux Valgus', 'Amputação'].map(d => (
toggleArrayItem(side, 'deformidades', d)} className={`px-3 py-2 rounded-xl border-2 text-[9px] font-black uppercase ${examForm[side].deformidades?.includes(d) ? 'border-purple-500 bg-purple-50 text-purple-700' : 'border-slate-50 bg-white text-slate-300'}`}>{d}
))}
))}
{/* RESULTADO + CONDUTA */}
setExamForm({...examForm, historicoUlcera: !examForm.historicoUlcera})} className={`p-4 rounded-2xl border-2 font-black text-[10px] uppercase transition-all ${examForm.historicoUlcera ? 'bg-red-50 border-red-500 text-red-700' : 'border-slate-100 text-slate-400'}`}>Histórico de Úlcera {examForm.historicoUlcera && '✓'} setExamForm({...examForm, historicoAmputacao: !examForm.historicoAmputacao})} className={`p-4 rounded-2xl border-2 font-black text-[10px] uppercase transition-all ${examForm.historicoAmputacao ? 'bg-red-50 border-red-500 text-red-700' : 'border-slate-100 text-slate-400'}`}>Histórico de Amputação {examForm.historicoAmputacao && '✓'}
IWGDF 2023
Risco {calculated.riwgdf}
{/* BOTÕES DE INSERÇÃO RÁPIDA DE CONDUTA */}
Inserção Rápida
{conductOptions.map((opt, i) => (
setExamForm(prev => ({
...prev,
conduta: (prev.conduta ? prev.conduta + '\n' : '') + '- ' + opt.text
}))}
className="px-3 py-2 bg-indigo-50 hover:bg-indigo-100 text-indigo-700 rounded-xl text-[10px] font-bold border border-indigo-100 transition-colors flex items-center gap-2"
>{opt.icon} {opt.label}
))}
{isSaving ? : } Finalizar Avaliação
)}
{/* IMPRESSÃO */}
{view === 'print' && activeExam && (
{printMode === 'crie' && (
Identificação do Paciente Nome: {selectedPatient.name}
CPF: {selectedPatient.cpf}
Data de Nascimento: {selectedPatient.birthDate ? new Date(selectedPatient.birthDate).toLocaleDateString() : '--'}
Diagnóstico: Diabetes Mellitus não especificado (CID E14)
Solicitação Ao Centro de Referência para Imunobiológicos Especiais (CRIE),
Solicito a aplicação da vacina Pneumocócica 23-valente (Pneumo 23) para o paciente acima identificado.
Justificativa: Paciente portador de Diabetes Mellitus, grupo de risco para doença pneumocócica invasiva, conforme recomendação do PNI (Programa Nacional de Imunizações) e da SBIm.
)}
{printMode === 'clinical' && (
<>
Paciente {selectedPatient.name}
Nasc: {selectedPatient.birthDate} | CPF: {selectedPatient.cpf}
{selectedPatient.medications?.length > 0 &&
Meds: {selectedPatient.medications.join(', ')}
}
HbA1c: {activeExam.hba1c}% ({formatDate(activeExam.hba1cDate)})
IMC: {activeExam.imc}
LDL: {activeExam.ldl} ({formatDate(activeExam.ldlDate)})
Risco CV: {activeExam.riscoCV}
IWGDF: Categoria {activeExam.riscoIWGDF} (Retorno em {activeExam.retorno})
Exame das Extremidades e Autocuidado Calçado: {activeExam.calcadoAdequado ? 'Adequado' : 'Inadequado'}
Unhas: {activeExam.unhaCortadaAdequada ? 'Corretas' : 'Incorretas'}
Autocuidado: {activeExam.higieneOk ? 'Preservado' : 'Atenção'}
{activeExam.pd?.sintomas?.length > 0 && (
Sintomas Relatados: {activeExam.pd.sintomas.join(', ')}
)}
{['pd', 'pe'].map(side => (
{activeExam[side].photo &&
}
{side === 'pd' ? 'Pé Direito' : 'Pé Esquerdo'}
Monof.: {activeExam[side].sensibilidade}
Diapasão: {activeExam[side].diapasao?.replace('_', ' ')}
Deformidades: {activeExam[side].deformidades?.join(', ') || 'Nenhuma'}
{activeExam[side].temUlcera && (
ÚLCERA GRAU {activeExam[side].ulceraGrau} {activeExam[side].sinaisInfeccao ? '(INFECTADA)' : ''}
)}
))}
>
)}
{printMode === 'patient' && (
Classificação de Risco: {activeExam.riscoIWGDF} Seu retorno deve ocorrer em: {activeExam.retorno}
10 Mandamentos do Pé Diabético 1. Examine os pés diariamente com um espelho. Procure cortes, bolhas ou vermelhidão. 2. Mantenha os pés limpos e secos, especialmente entre os dedos. 3. Hidrate a pele (exceto entre os dedos) para evitar rachaduras. 4. Corte as unhas de forma reta e lixe os cantos. Não remova cutículas. 5. Nunca ande descalço, nem em casa, nem na praia. 6. Use calçados confortáveis, fechados e sem costuras internas ásperas. 7. Verifique o interior do sapato antes de calçar (pedras ou objetos). 8. Não use água quente nos pés (teste a temperatura com o cotovelo). 9. Nunca use calicidas, giletes ou lixas metálicas para remover calos. 10. Em caso de ferida, procure sua unidade de saúde imediatamente.
Técnica de Corte
Calçado Ideal Recomendações Específicas da Consulta "{activeExam.conduta}"
{/* QR CODES */}
Aponte a câmera para os códigos abaixo
Fisioterapia
Nutrição
Dra. Patrícia
Enf. Lara
)}
{CITY_NAME}
{DOCTOR_NAME}
{DOCTOR_CRM}
window.print()} className="bg-indigo-700 text-white px-12 py-5 rounded-2xl font-black shadow-xl flex items-center gap-3 active:scale-95 transition-all text-sm uppercase tracking-widest"> Confirmar Impressão setView('detail')} className="text-slate-400 font-bold px-8 py-5">Voltar
)}
{/* CADASTRO PACIENTE COM MODALIDADE DE EDIÇÃO */}
{(view === 'new-patient' || view === 'edit-patient') && (
setView('list')} className="text-indigo-600 font-black text-xs uppercase mb-8 flex items-center gap-1 hover:underline tracking-widest transition-colors"> Voltar
)}
);
};
export default App;
Our site is still in the works but it's coming soon!
Come back again to see the final version in just:
import React, { useState, useEffect, useRef, useMemo } from 'react';
import {
Users, Heart, Activity, Stethoscope, ChevronLeft, Loader2,
Footprints, ShieldAlert, FileText, Plus, CheckSquare, Square,
Camera, Trash2, X, Scale, Ruler, Droplets,
Printer, ArrowRight, User, Award, CalendarClock, CheckCircle2,
Zap, Image as ImageIcon, FileHeart, Syringe, BarChart3, PieChart, Weight,
Pill, FilePlus, QrCode, List, Search as SearchIcon, AlertTriangle,
Edit, Smartphone, Lock, LogIn, LogOut,
Volume2, PlayCircle, ArrowLeft, Phone, Utensils, CreditCard, Eye, Table2,
Scissors, Sparkles, Smile, Video, ArrowDown, Building, Database,
FileSpreadsheet, Cigarette, TrendingUp, Filter, MapPin, Search, Save, UserPlus, History
} from 'lucide-react';
import { initializeApp } from 'firebase/app';
import {
getFirestore, collection, doc, setDoc, addDoc, updateDoc, onSnapshot,
query, where
} from 'firebase/firestore';
import {
getAuth, signInAnonymously, signInWithCustomToken, onAuthStateChanged
} from 'firebase/auth';
// --- CONFIGURAÇÃO FIREBASE ---
const firebaseConfig = JSON.parse(__firebase_config);
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const db = getFirestore(app);
// ID fixo para persistência dos dados
const appId = typeof __app_id !== 'undefined' ? __app_id : 'esf-patricia-v-master-2';
// --- CONSTANTES GLOBAIS (CORREÇÃO DO ERRO) ---
const DOCTOR_NAME = "Dra. Patrícia Szlachta Senna";
const DOCTOR_CRM = "CRM MS 12795";
const CITY_NAME = "Camapuã - MS"; // Variável restaurada
const PASSWORD_PROFESSIONAL = "esf123"; // Fixed variable name mismatch
const PASS_ADMIN = "admin123";
// --- HELPERS ---
const calculateAge = (birthDate) => {
if (!birthDate) return 0;
const today = new Date();
const birth = new Date(birthDate);
let age = today.getFullYear() - birth.getFullYear();
const m = today.getMonth() - birth.getMonth();
if (m < 0 || (m === 0 && today.getDate() < birth.getDate())) age--;
return age;
};
const formatDate = (dateString) => {
if (!dateString) return '';
const [y, m, d] = dateString.split('-');
return `${d}/${m}/${y}`;
};
// Formatação e Validação
const formatCPF = (v) => v.replace(/\D/g, '').replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, '$1.$2.$3-$4').slice(0, 14);
const formatCNS = (v) => v.replace(/\D/g, '').replace(/(\d{3})(\d{4})(\d{4})(\d{4})/, '$1 $2 $3 $4').slice(0, 18);
const formatPA = (v) => {
const n = v.replace(/\D/g, '').slice(0, 6);
return n.length > 3 ? n.replace(/(\d{3})(\d+)/, '$1/$2') : n;
};
const isValidCPF = (cpf) => cpf.replace(/\D/g, '').length === 11;
// Cálculo CKD-EPI 2021 (Creatinina)
const calculateCKDEPI = (creat, age, sex) => {
if (!creat || !age || !sex) return null;
const cr = parseFloat(creat);
const k = sex === 'Feminino' ? 0.7 : 0.9;
const alpha = sex === 'Feminino' ? -0.329 : -0.411;
const genderFactor = sex === 'Feminino' ? 1.018 : 1;
const minPart = Math.min(cr / k, 1) ** alpha;
const maxPart = Math.max(cr / k, 1) ** -1.200;
const agePart = 0.9938 ** age;
const gfr = 142 * minPart * maxPart * agePart * genderFactor;
return gfr.toFixed(1);
};
// Cálculo Carga Tabágica
const calculateTobaccoLoad = (packsPerDay, years) => {
return (parseFloat(packsPerDay) * parseFloat(years)).toFixed(1);
};
const checkVaccineStatus = (dateString, yearsValid) => {
if (!dateString) return { status: 'missing', msg: 'Pendente' };
const last = new Date(dateString);
const now = new Date();
const diffYears = (now - last) / (1000 * 60 * 60 * 24 * 365);
if (diffYears < yearsValid) return { status: 'ok', msg: 'Em Dia' };
return { status: 'expired', msg: 'Vencida' };
};
const compressImage = (file) => {
return new Promise((resolve) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = (e) => {
const img = new Image();
img.src = e.target.result;
img.onload = () => {
const canvas = document.createElement('canvas');
const MAX_WIDTH = 800;
const scale = MAX_WIDTH / img.width;
canvas.width = MAX_WIDTH;
canvas.height = img.height * scale;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
resolve(canvas.toDataURL('image/jpeg', 0.6));
};
};
});
};
// Helper para calcular a data de retorno sugerida
const getSuggestedReturnDate = (examDate, returnString) => {
if (!examDate || !returnString) return null;
const date = new Date(examDate);
let months = 12;
if (returnString.includes('1 a 3')) months = 3;
else if (returnString.includes('3 a 6')) months = 6;
else if (returnString.includes('12')) months = 12;
date.setMonth(date.getMonth() + months);
return date.toLocaleDateString('pt-BR', { month: 'long', year: 'numeric' });
};
// Ícone personalizado
const RepeatIcon = (props) => (
);
// --- COMPONENTES VISUAIS ---
const SimpleChart = ({ title, data, dataKey, color, limit }) => {
if (!data || data.length < 2) return null;
const chartData = [...data].reverse().slice(0, 5).reverse();
const maxVal = Math.max(...chartData.map(d => parseFloat(d[dataKey]) || 0)) * 1.1;
return (
{title} (Evolução)
{chartData.map((d, i) => {
const val = parseFloat(d[dataKey]) || 0;
const height = (val / maxVal) * 100;
return (
{val}
{new Date(d.timestamp).toLocaleDateString().slice(0,5)}
);
})}
);
};
const NailCutProSVG = () => (
);
const ShoeSVG = () => (
);
const ProFootMap = ({ side, markers, onAddMarker, onRemoveMarker, readOnly = false }) => {
const svgRef = useRef(null);
const isRight = side === 'pd';
const handleClick = (e) => {
if (readOnly) return;
const svg = svgRef.current;
if (!svg) return;
const pt = svg.createSVGPoint();
pt.x = e.clientX; pt.y = e.clientY;
const cursorpt = pt.matrixTransform(svg.getScreenCTM().inverse());
onAddMarker({ x: cursorpt.x, y: cursorpt.y, side });
};
const footColor = "#fff7ed"; const outlineColor = "#94a3b8";
return (
{isRight ? 'Pé Direito' : 'Pé Esquerdo'}
{markers && markers.map((m, i) => (
{ e.stopPropagation(); if(!readOnly) onRemoveMarker(i, side); }} />
))}
);
};
// --- COMPONENTE: ESPAÇO DO PACIENTE ---
const PatientArea = ({ onBack, patients, allExams }) => {
const [section, setSection] = useState('home');
const [videoModal, setVideoModal] = useState({ open: false, title: '' });
const [loginData, setLoginData] = useState({ cpf: '', sus: '' });
const [currentPatient, setCurrentPatient] = useState(null);
const [patientLastExam, setPatientLastExam] = useState(null);
const [loginError, setLoginError] = useState('');
// --- LINKS ---
const LINK_FISIO = "https://www.youtube.com/results?search_query=exercicios+pe+diabetico+alongamento";
const LINK_NUTRI = "https://www.youtube.com/results?search_query=dicas+nutricionais+diabetes";
const LINK_MEDICA = "https://www.youtube.com/results?search_query=cuidados+diabetes+dra+patricia";
const LINK_ENF_LARA = "https://www.youtube.com/results?search_query=cuidados+diabetes+enf+lara";
const handlePatientLogin = (e) => {
e.preventDefault();
const found = patients.find(p => p.cpf === loginData.cpf && p.chartId === loginData.sus);
if (found) {
setCurrentPatient(found);
const exams = allExams.filter(e => e.patientId === found.id).sort((a,b) => b.timestamp - a.timestamp);
setPatientLastExam(exams.length > 0 ? exams[0] : null);
setSection('prontuario');
setLoginError('');
} else {
setLoginError('Ops, identificamos que ainda não possui cadastro nesse sistema. Nos contate para poder ter acesso.');
}
};
const playVideo = (title) => {
setVideoModal({ open: true, title });
};
const videosFisio = [
{ title: "Exercício Sentado", icon: Activity },
{ title: "Alongamento Panturrilha", icon: Footprints },
{ title: "O sapato certo", icon: Footprints },
{ title: "Massagem nos Pés", icon: Smile },
{ title: "Cãibras: Como aliviar", icon: Zap }
];
const videosNutri = [
{ title: "Quais frutas pode?", icon: Utensils },
{ title: "Montar o Prato", icon: PieChart },
{ title: "Água ou Suco?", icon: Droplets },
{ title: "Qual Pão Comer?", icon: Utensils },
{ title: "Lanches Saudáveis", icon: Smile },
{ title: "Receitas Low Carb", icon: Utensils },
{ title: "Doces e Diabetes", icon: AlertTriangle }
];
const videosMedica = [
{ title: "Entender Exames", icon: FileText },
{ title: "Hipoglicemia: O que fazer", icon: AlertTriangle },
{ title: "Diabetes e Visão", icon: Eye },
{ title: "Quando ir ao PS?", icon: ShieldAlert },
{ title: "Sinais de Infarto", icon: Heart },
{ title: "Pé Diabético: Sinais", icon: Footprints }
];
const videosEnf = [
{ title: "Aplicar Insulina", icon: Syringe },
{ title: "Rodízio de Aplicação", icon: RepeatIcon },
{ title: "Medir Certo (HGT)", icon: Droplets },
{ title: "Descarte de Agulhas", icon: Trash2 },
{ title: "Curativo Simples", icon: Scissors }
];
return (
{section === 'home' && (
Toque para entrar: setSection('fisio')} className="bg-orange-100 border-2 border-orange-400 p-4 rounded-2xl cursor-pointer flex flex-col items-center justify-center text-center h-56 shadow-sm active:scale-95 transition-transform">Movimente-se Cuidados Fisioterapeuta
setSection('nutri')} className="bg-green-100 border-2 border-green-500 p-4 rounded-2xl cursor-pointer flex flex-col items-center justify-center text-center h-56 shadow-sm active:scale-95 transition-transform">Alimente-se Bem Cuidados Nutricionista
setSection('medica')} className="bg-blue-100 border-2 border-blue-600 p-4 rounded-2xl cursor-pointer flex flex-col items-center justify-center text-center h-56 shadow-sm active:scale-95 transition-transform">
Cuidados com Dra. Patrícia setSection('enfermeira')} className="bg-pink-100 border-2 border-pink-500 p-4 rounded-2xl cursor-pointer flex flex-col items-center justify-center text-center h-56 shadow-sm active:scale-95 transition-transform">
Cuidados com Enf. Lara setSection('general-orientations')} className="mt-4 bg-emerald-500 hover:bg-emerald-600 text-white p-4 rounded-xl flex items-center justify-center shadow-md w-full mb-2 active:scale-95 transition-transform">Orientações Gerais WhatsApp da Unidade
)}
{section === 'login' && (
Acessar Prontuário Use o seu CPF e o número do Cartão do SUS como senha.
)}
{section === 'prontuario' && currentPatient && (
{ setCurrentPatient(null); setSection('home'); setLoginData({cpf:'', sus:''}); }} className="absolute top-4 right-4 bg-blue-700 hover:bg-blue-800 p-2 rounded-lg text-xs font-bold flex items-center"> Sair
{currentPatient.name} {calculateAge(currentPatient.birthDate)} anos
{patientLastExam && (
<>{patientLastExam.peso} kg {patientLastExam.altura} cm IMC {patientLastExam.imc} >
)}
{patientLastExam && (
HbA1c: {patientLastExam.hba1c}% ({parseFloat(patientLastExam.hba1c) < 7 ? 'DENTRO DO ALVO' : 'FORA DO ALVO'})
)}
setSection('my-orientations')} className="bg-emerald-100 border-2 border-emerald-300 p-5 rounded-2xl mb-6 flex items-center justify-between cursor-pointer active:scale-95 transition-transform shadow-sm">
Minhas Orientações Veja o que o médico recomendou
DiagnósticoDiabetes Mellitus {currentPatient.diabetesType}
{currentPatient.comorbidities && currentPatient.comorbidities.length > 0 && (
Comorbidades Associadas:
{currentPatient.comorbidities.map((c, i) => (
{c}
))}
)}
Medicamentos Atuais
{currentPatient.medications?.length > 0 ? (
currentPatient.medications.map((m, i) => (
))
) : (Nenhum medicamento registrado. )}
setSection('home')} className="w-full mt-6 bg-gray-200 hover:bg-gray-300 text-gray-700 font-bold py-4 rounded-xl shadow-sm">Voltar para o Início
)}
{section === 'my-orientations' && (
setSection('prontuario')} className="w-full bg-gray-200 hover:bg-gray-300 text-gray-800 font-bold py-4 px-6 rounded-xl mb-6 flex items-center shadow-md active:scale-95 transition-transform">Voltar
{patientLastExam ? (
<>
Seu Risco Atual: {patientLastExam.riscoIWGDF} Retorno sugerido em: {patientLastExam.retorno}
{getSuggestedReturnDate(patientLastExam.timestamp, patientLastExam.retorno) && (
Programar para: {getSuggestedReturnDate(patientLastExam.timestamp, patientLastExam.retorno)}
)}
Recomendação Médica {patientLastExam.conduta}
>
) : (
Bem-vindo(a) Ainda não há consultas registradas, mas siga as dicas abaixo!
)}
10 Mandamentos do Pé Diabético 1. Examine os pés diariamente com um espelho. 2. Mantenha os pés limpos e secos entre os dedos. 3. Hidrate a pele (exceto entre os dedos). 4. Corte as unhas retas. Não remova cutículas. 5. Nunca ande descalço. 6. Use calçados confortáveis e fechados. 7. Verifique o interior do sapato antes de calçar. 8. Não use água quente nos pés. 9. Não use calicidas ou lixas metálicas. 10. Em caso de ferida, procure sua unidade de saúde imediatamente.
Aponte a câmera para os códigos abaixo
Fisioterapia
Nutrição
Dra. Patrícia
Enf. Lara
)}
{section === 'general-orientations' && (
setSection('home')} className="w-full bg-gray-200 hover:bg-gray-300 text-gray-800 font-bold py-4 px-6 rounded-xl mb-6 flex items-center shadow-md active:scale-95 transition-transform">Voltar 10 Mandamentos do Pé Diabético 1. Examine os pés diariamente com um espelho. 2. Mantenha os pés limpos e secos entre os dedos. 3. Hidrate a pele (exceto entre os dedos). 4. Corte as unhas retas. Não remova cutículas. 5. Nunca ande descalço. 6. Use calçados confortáveis e fechados. 7. Verifique o interior do sapato antes de calçar. 8. Não use água quente nos pés. 9. Não use calicidas ou lixas metálicas. 10. Em caso de ferida, procure sua unidade de saúde imediatamente.
)}
{['fisio', 'nutri', 'medica', 'enfermeira'].includes(section) && (
setSection('home')} className="w-full bg-gray-200 hover:bg-gray-300 text-gray-800 font-bold py-4 px-6 rounded-xl mb-6 flex items-center shadow-md active:scale-95 transition-transform">Voltar
{section === 'fisio' ? 'Movimente-se' : section === 'nutri' ? 'Alimente-se Bem' : section === 'medica' ? 'Cuidados Médicos' : 'Cuidados Enfermagem'}
{section === 'fisio' ? 'Fisioterapeuta' : section === 'nutri' ? 'Nutricionista' : section === 'medica' ? 'Dra. Patrícia' : 'Enf. Lara'}
{(section === 'fisio' ? videosFisio : section === 'nutri' ? videosNutri : section === 'medica' ? videosMedica : videosEnf).map((v, i) => (
))}
)}
{videoModal.open && (
setVideoModal({open: false, title: ''})} className="bg-white text-black w-12 h-12 rounded-full flex items-center justify-center shadow-lg border-2 border-gray-300 active:scale-90 transition">
)}
);
};
const App = () => {
const [user, setUser] = useState(null);
const [appSection, setAppSection] = useState('welcome');
const [passwordInput, setPasswordInput] = useState('');
const [loginError, setLoginError] = useState('');
const [view, setView] = useState('list');
const [printMode, setPrintMode] = useState('clinical');
const [patients, setPatients] = useState([]);
const [selectedPatient, setSelectedPatient] = useState(null);
const [patientExams, setPatientExams] = useState([]);
const [allExams, setAllExams] = useState([]);
const [activeExam, setActiveExam] = useState(null);
const [searchQuery, setSearchQuery] = useState('');
const [isSaving, setIsSaving] = useState(false);
const [activeMarkerType, setActiveMarkerType] = useState('ulcera');
const [selectedMetric, setSelectedMetric] = useState(null);
const [patientForm, setPatientForm] = useState({
name: '', cpf: '', birthDate: '', chartId: '', diabetesType: 'Tipo 2',
comorbidities: [], medications: []
});
const [medInput, setMedInput] = useState('');
const [otherComorb, setOtherComorb] = useState('');
const initialFootState = {
sensibilidade: 'presente', diapasao: 'presente',
pulsoPedioso: 'presente', pulsoTibial: 'presente',
deformidades: [], pele: [], sintomas: [], markers: [], photo: null,
temUlcera: false, ulceraGrau: '1', sinaisInfeccao: false
};
const initialExamState = {
peso: '', altura: '', imc: '',
hba1c: '', hba1cDate: '', ldl: '', ldlDate: '', idade: '',
pa: '', hgt: '',
ha: false, tabagismo: false, albuminuria: false, loa: false,
historicoUlcera: false, historicoAmputacao: false,
calcadoAdequado: true, unhaCortadaAdequada: true, higieneOk: true,
vacinaInfluenza: '', vacinaPneumo: '',
pd: { ...initialFootState }, pe: { ...initialFootState },
riscoIWGDF: '0', retorno: '12 meses', conduta: '', riscoCV: 'Baixo'
};
const [examForm, setExamForm] = useState(initialExamState);
// --- Auth & Sync ---
useEffect(() => {
const init = async () => {
try {
if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) await signInWithCustomToken(auth, __initial_auth_token);
else await signInAnonymously(auth);
} catch (err) { console.error(err); }
};
init();
onAuthStateChanged(auth, setUser);
}, []);
useEffect(() => {
if (!user) return;
const unsubP = onSnapshot(collection(db, 'artifacts', appId, 'public', 'data', 'patients'), (snap) => {
setPatients(snap.docs.map(d => ({ id: d.id, ...d.data() })).sort((a,b) => (b.createdAt || 0) - (a.createdAt || 0)));
}, (error) => console.error(error));
const unsubE = onSnapshot(collection(db, 'artifacts', appId, 'public', 'data', 'exams'), (snap) => {
setAllExams(snap.docs.map(d => ({ id: d.id, ...d.data() })));
}, (error) => console.error(error));
return () => { unsubP(); unsubE(); };
}, [user]);
useEffect(() => {
if (!user || !selectedPatient) return;
const patExams = allExams.filter(e => e.patientId === selectedPatient.id).sort((a,b) => b.timestamp - a.timestamp);
setPatientExams(patExams);
}, [user, selectedPatient, allExams]);
const handleLogin = (e) => {
e.preventDefault();
if (passwordInput === PASSWORD_PROFESSIONAL) {
setAppSection('professional_dashboard');
setLoginError('');
setPasswordInput('');
} else {
setLoginError('Senha incorreta.');
}
};
const calculated = useMemo(() => {
const age = selectedPatient ? calculateAge(selectedPatient.birthDate) : 0;
let imc = '--.-';
if (examForm.peso && examForm.altura) {
const h = parseFloat(examForm.altura) / 100;
const w = parseFloat(examForm.peso);
if (h > 0) imc = (w / (h * h)).toFixed(1);
}
let rcv = 'Baixo';
const ldl = parseFloat(examForm.ldl) || 0;
if (examForm.loa || examForm.albuminuria) rcv = 'Muito Alto';
else if (examForm.tabagismo || examForm.ha || ldl > 130 || age > 65) rcv = 'Alto';
else if (ldl > 100 || age > 50) rcv = 'Médio';
let riwgdf = '0';
let ret = '12 meses';
const lops = examForm.pd.sensibilidade === 'ausente' || examForm.pe.sensibilidade === 'ausente' ||
examForm.pd.diapasao === 'ausente' || examForm.pe.diapasao === 'ausente';
const pad = examForm.pd.pulsoPedioso === 'ausente' || examForm.pe.pulsoPedioso === 'ausente' ||
examForm.pd.pulsoTibial === 'ausente' || examForm.pe.pulsoTibial === 'ausente';
const def = examForm.pd.deformidades.length > 0 || examForm.pe.deformidades.length > 0;
const hist = examForm.historicoUlcera || examForm.historicoAmputacao;
if (hist) { riwgdf = '3'; ret = '1 a 3 meses'; }
else if ((lops && pad) || (lops && def) || (pad && def)) { riwgdf = '2'; ret = '3 a 6 meses'; }
else if (lops || pad || def) { riwgdf = '1'; ret = '6 a 12 meses'; }
const fluStatus = checkVaccineStatus(examForm.vacinaInfluenza, 1);
const pneumoStatus = checkVaccineStatus(examForm.vacinaPneumo, 5);
return { age, imc, rcv, riwgdf, ret, fluStatus, pneumoStatus };
}, [examForm, selectedPatient]);
const analytics = useMemo(() => {
const patientMap = {};
patients.forEach(p => patientMap[p.id] = p);
const latestMap = {};
allExams.forEach(ex => {
if (!latestMap[ex.patientId] || ex.timestamp > latestMap[ex.patientId].timestamp) {
latestMap[ex.patientId] = ex;
}
});
const getName = (id) => patientMap[id]?.name || 'Desconhecido';
const activeExams = Object.values(latestMap);
const listHbA1cBad = activeExams.filter(e => parseFloat(e.hba1c) > 7).map(e => ({ name: getName(e.patientId), val: `${e.hba1c}%` }));
const listHighRiskFoot = activeExams.filter(e => ['2', '3'].includes(e.riscoIWGDF)).map(e => ({ name: getName(e.patientId), val: `Risco ${e.riscoIWGDF}` }));
const listObese = activeExams.filter(e => parseFloat(e.imc) >= 30).map(e => ({ name: getName(e.patientId), val: `IMC ${e.imc}` }));
const listFluMissing = activeExams.filter(e => checkVaccineStatus(e.vacinaInfluenza, 1).status !== 'ok').map(e => ({ name: getName(e.patientId), val: 'Vencida/ND' }));
const listPneumoMissing = activeExams.filter(e => checkVaccineStatus(e.vacinaPneumo, 5).status !== 'ok').map(e => ({ name: getName(e.patientId), val: 'Vencida/ND' }));
return { total: patients.length, listAllPatients: patients.map(p => ({name: p.name, val: 'Ativo'})), listHbA1cBad, listHighRiskFoot, listObese, listFluMissing, listPneumoMissing };
}, [patients, allExams]);
const latestExam = patientExams.length > 0 ? patientExams[0] : null;
const latestFlu = latestExam ? checkVaccineStatus(latestExam.vacinaInfluenza, 1) : {status:'missing', msg:'--'};
const latestPneumo = latestExam ? checkVaccineStatus(latestExam.vacinaPneumo, 5) : {status:'missing', msg:'--'};
const handlePhotoUpload = async (side, file) => {
if (!file) return;
const compressed = await compressImage(file);
setExamForm(prev => ({ ...prev, [side]: { ...prev[side], photo: compressed } }));
};
const addMarker = (side, x, y, type) => {
setExamForm(prev => {
const newMarkers = [...prev[side].markers, { x, y, type }];
const hasUlcer = newMarkers.some(m => m.type === 'ulcera');
return {
...prev,
[side]: { ...prev[side], markers: newMarkers, temUlcera: hasUlcer }
};
});
};
const removeMarker = (side, index) => {
setExamForm(prev => {
const newMarkers = [...prev[side].markers];
newMarkers.splice(index, 1);
const hasUlcer = newMarkers.some(m => m.type === 'ulcera');
return { ...prev, [side]: { ...prev[side], markers: newMarkers, temUlcera: hasUlcer } };
});
};
const toggleArrayItem = (side, field, value) => {
setExamForm(prev => {
const list = prev[side][field] || [];
const newList = list.includes(value) ? list.filter(i => i !== value) : [...list, value];
return { ...prev, [side]: { ...prev[side], [field]: newList } };
});
};
const toggleComorbidity = (comorb) => {
setPatientForm(prev => {
const list = prev.comorbidities || [];
const newList = list.includes(comorb) ? list.filter(c => c !== comorb) : [...list, comorb];
return { ...prev, comorbidities: newList };
});
};
const addMedication = () => {
if (!medInput) return;
setPatientForm(prev => ({ ...prev, medications: [...(prev.medications || []), medInput] }));
setMedInput('');
};
const removeMedication = (index) => {
setPatientForm(prev => {
const newList = [...(prev.medications || [])];
newList.splice(index, 1);
return { ...prev, medications: newList };
});
};
const savePatient = async (e) => {
e.preventDefault();
if (!patientForm.name) return;
setIsSaving(true);
let finalComorbs = [...(patientForm.comorbidities || [])];
if (otherComorb.trim()) finalComorbs.push(otherComorb.trim());
let finalMedications = [...(patientForm.medications || [])];
if (medInput.trim()) finalMedications.push(medInput.trim());
const dataToSave = { ...patientForm, comorbidities: finalComorbs, medications: finalMedications };
if (view === 'edit-patient' && selectedPatient) {
await updateDoc(doc(db, 'artifacts', appId, 'public', 'data', 'patients', selectedPatient.id), dataToSave);
setSelectedPatient({ ...selectedPatient, ...dataToSave });
setView('detail');
} else {
const finalPatient = { ...dataToSave, createdAt: Date.now() };
const docRef = await addDoc(collection(db, 'artifacts', appId, 'public', 'data', 'patients'), finalPatient);
setSelectedPatient({ id: docRef.id, ...finalPatient });
setView('detail');
}
setPatientForm({ name: '', cpf: '', birthDate: '', chartId: '', diabetesType: 'Tipo 2', comorbidities: [], medications: [] });
setOtherComorb('');
setMedInput('');
setIsSaving(false);
};
const saveExam = async () => {
setIsSaving(true);
const { imc, rcv, riwgdf, ret } = calculated;
const finalExam = { ...examForm, imc, riscoCV: rcv, riscoIWGDF: riwgdf, retorno: ret, patientId: selectedPatient.id, timestamp: Date.now(), doctorName: DOCTOR_NAME, doctorCrm: DOCTOR_CRM };
await addDoc(collection(db, 'artifacts', appId, 'public', 'data', 'exams'), finalExam);
setView('detail');
setExamForm({ ...initialExamState, conduta: '', peso: '', hba1c: '', ldl: '' });
setIsSaving(false);
};
const startNewExam = () => {
const hasHAS = selectedPatient?.comorbidities?.includes('HAS');
const hasTabagismo = selectedPatient?.comorbidities?.includes('Tabagismo');
const highRiskComorbs = ['IAM prévio', 'AVC', 'DAOP', 'IC', 'DRC'];
const hasLOA = selectedPatient?.comorbidities?.some(c => highRiskComorbs.includes(c));
setExamForm({ ...initialExamState, ha: hasHAS || false, tabagismo: hasTabagismo || false, loa: hasLOA || false });
setView('new-exam');
};
const startEditPatient = () => {
setPatientForm({
name: selectedPatient.name,
cpf: selectedPatient.cpf || '',
birthDate: selectedPatient.birthDate,
chartId: selectedPatient.chartId,
diabetesType: selectedPatient.diabetesType,
comorbidities: selectedPatient.comorbidities || [],
medications: selectedPatient.medications || []
});
setView('edit-patient');
};
const conductOptions = [
{ text: "Prescrevo creme hidratante (Ureia 10% / Nivea / Cerave) - aplicar diariamente, exceto entre os dedos.", icon: "🧴", label: "Hidratante" },
{ text: "Encaminho para confecção de palmilha/órtese para alívio de pressão plantar.", icon: "👟", label: "Órtese" },
{ text: "Encaminho à enfermagem para desbridamento de calosidades.", icon: "🩹", label: "Desbridamento" },
{ text: "Encaminho ao cirurgião vascular para avaliação de pulsos.", icon: "🦶", label: "Vascular" },
{ text: "Reforço orientações de corte reto das unhas e uso de calçados adequados.", icon: "✂️", label: "Unhas" }
];
if (!user) return
;
if (appSection === 'welcome') {
return (
Caderno de Saúde do Diabético setAppSection('patient_area')} className="group relative bg-white p-10 rounded-[3rem] shadow-xl border-2 border-transparent hover:border-emerald-400 hover:shadow-2xl transition-all flex flex-col items-center gap-6">
Espaço do Diabético Orientações e Cuidados
setAppSection('login')} className="group relative bg-white p-10 rounded-[3rem] shadow-xl border-2 border-transparent hover:border-indigo-400 hover:shadow-2xl transition-all flex flex-col items-center gap-6">Espaço do Profissional Acesso Restrito
{DOCTOR_NAME} • {DOCTOR_CRM}
);
}
if (appSection === 'login') {
return (
setAppSection('welcome')} className="absolute top-8 left-8 text-slate-400 hover:text-indigo-600">
Área Restrita Digite sua senha de acesso
Dica: A senha é esf123
);
}
if (appSection === 'patient_area') {
return setAppSection('welcome')} patients={patients} allExams={allExams} />;
}
return (
{selectedMetric && (
{selectedMetric.title} setSelectedMetric(null)} className="p-2 bg-slate-100 rounded-full hover:bg-slate-200">
{selectedMetric.list.length > 0 ? (
selectedMetric.list.map((item, i) => (
{item.name} {item.val}
))
) : (
Nenhum paciente nesta categoria.
)}
{selectedMetric.list.length} Registros Encontrados
)}
setView('list')}>
Caderno do Diabético {DOCTOR_NAME}
setAppSection('welcome')} className="bg-indigo-900/50 hover:bg-indigo-900 px-3 py-2 rounded-xl font-bold text-[10px] uppercase transition-all flex items-center gap-2"> Sair
{view === 'list' && (
<> setView('analytics')} className="bg-indigo-700 hover:bg-indigo-600 px-4 py-2 rounded-xl font-bold text-xs uppercase shadow-md transition-all flex items-center gap-2"> Gestão
{
setPatientForm({ name: '', cpf: '', birthDate: '', chartId: '', diabetesType: 'Tipo 2', comorbidities: [], medications: [] });
setView('new-patient');
}} className="bg-white text-indigo-800 px-4 py-2 rounded-xl font-bold text-xs uppercase shadow-md transition-all">
+ Paciente
>
)}
{view === 'analytics' && (
setView('list')} className="text-indigo-600 font-bold text-xs uppercase mb-6 flex items-center gap-1 hover:underline"> Voltar Gestão da Clínica setSelectedMetric({ title: 'Total de Pacientes', list: analytics.listAllPatients || [] })} className="bg-white p-8 rounded-[2rem] shadow-lg border border-slate-100 cursor-pointer hover:border-indigo-300">
Total Pacientes
setSelectedMetric({ title: 'HbA1c > 7%', list: analytics.listHbA1cBad })} className="bg-white p-8 rounded-[2rem] shadow-lg border border-slate-100 cursor-pointer hover:border-rose-300 hover:shadow-xl transition-all group">
{analytics.listHbA1cBad.length} HbA1c Descompensada
setSelectedMetric({ title: 'Pé Diabético Alto Risco', list: analytics.listHighRiskFoot })} className="bg-white p-8 rounded-[2rem] shadow-lg border border-slate-100 cursor-pointer hover:border-amber-300 hover:shadow-xl transition-all group">
{analytics.listHighRiskFoot.length} Pé Risco Alto
setSelectedMetric({ title: 'Pacientes com Obesidade', list: analytics.listObese })} className="bg-white p-8 rounded-[2rem] shadow-lg border border-slate-100 cursor-pointer hover:border-purple-300 hover:shadow-xl transition-all group">
{analytics.listObese.length} Obesidade
setSelectedMetric({ title: 'Atraso Influenza', list: analytics.listFluMissing })} className="bg-white p-8 rounded-[2rem] shadow-lg border border-red-100 cursor-pointer hover:bg-red-50 transition-all group">
{analytics.listFluMissing.length} Influenza Pendente
setSelectedMetric({ title: 'Atraso Pneumo 23', list: analytics.listPneumoMissing })} className="bg-white p-8 rounded-[2rem] shadow-lg border border-red-100 cursor-pointer hover:bg-red-50 transition-all group">
{analytics.listPneumoMissing.length} Pneumo 23 Pendente
)}
{view === 'list' && (
{patients.filter(p => p.name.toLowerCase().includes(searchQuery.toLowerCase())).map(p => (
{ setSelectedPatient(p); setView('detail'); }} className="bg-white p-8 rounded-[3rem] border border-slate-100 shadow-sm hover:shadow-2xl hover:border-indigo-400 cursor-pointer transition-all group overflow-hidden">
{p.name.charAt(0)}
{p.name} {calculateAge(p.birthDate)} anos • {p.diabetesType}
))}
)}
{view === 'detail' && (
setView('list')} className="p-3 bg-slate-50 rounded-2xl text-slate-400 hover:text-indigo-600 transition-colors">
{selectedPatient?.name}
{calculateAge(selectedPatient?.birthDate)} anos • CNS: {selectedPatient?.chartId} • CPF: {selectedPatient?.cpf || '---'}
Nova Consulta
Último IWGDF
{latestExam?.riscoIWGDF || '--'}
Pneumo 23
{latestPneumo.msg}
Risco CV
{latestExam?.riscoCV || '--'}
Histórico de Saúde
{selectedPatient.comorbidities && selectedPatient.comorbidities.length > 0 ? (
selectedPatient.comorbidities.map((c, i) => (
{c}
))
) : Nenhuma comorbidade registrada. }
Uso Contínuo
{selectedPatient.medications && selectedPatient.medications.length > 0 ? (
selectedPatient.medications.map((m, i) => (
{m}
))
) :
Nenhum medicamento registrado. }
Histórico
{patientExams.map(exam => (
{new Date(exam.timestamp).toLocaleDateString()} IWGDF: {exam.riscoIWGDF} { setActiveExam(exam); setPrintMode('clinical'); setView('print'); }} className="text-indigo-600 hover:bg-indigo-50 px-3 py-2 rounded-xl transition-all flex items-center gap-1 font-bold text-[9px] uppercase border border-indigo-100"> Prontuário { setActiveExam(exam); setPrintMode('patient'); setView('print'); }} className="text-emerald-600 hover:bg-emerald-50 px-3 py-2 rounded-xl transition-all flex items-center gap-1 font-bold text-[9px] uppercase border border-emerald-100"> Orientações
{(checkVaccineStatus(exam.vacinaPneumo, 5).status !== 'ok') && (
{ setActiveExam(exam); setPrintMode('crie'); setView('print'); }} className="text-rose-600 hover:bg-rose-50 px-3 py-2 rounded-xl transition-all flex items-center gap-1 font-bold text-[9px] uppercase border border-rose-100"> Laudo CRIE
)}
HbA1c
{exam.hba1c}%
{exam.hba1cDate &&
{formatDate(exam.hba1cDate)}
}
))}
)}
{view === 'new-exam' && (
setView('detail')} className="text-slate-400 font-black text-xs uppercase tracking-widest hover:text-red-500">Descartar Avaliação Integrada 1. Parâmetros Bioquímicos setExamForm({...examForm, ha: !examForm.ha})} className={`p-4 rounded-xl border-2 font-black text-xs flex justify-between items-center transition-all ${examForm.ha ? 'border-rose-600 bg-rose-50 text-rose-700' : 'border-slate-50 bg-slate-50 text-slate-400'}`}>Hipertensão? {examForm.ha ? : } setExamForm({...examForm, tabagismo: !examForm.tabagismo})} className={`p-4 rounded-xl border-2 font-black text-xs flex justify-between items-center transition-all ${examForm.tabagismo ? 'border-rose-600 bg-rose-50 text-rose-700' : 'border-slate-50 bg-slate-50 text-slate-400'}`}>Tabagismo? {examForm.tabagismo ? : } setExamForm({...examForm, albuminuria: !examForm.albuminuria})} className={`p-4 rounded-xl border-2 font-black text-xs flex justify-between items-center transition-all ${examForm.albuminuria ? 'border-red-600 bg-red-50 text-red-800' : 'border-slate-50 bg-slate-50 text-slate-400'}`}>Albuminúria? {examForm.albuminuria ? : } setExamForm({...examForm, loa: !examForm.loa})} className={`p-4 rounded-xl border-2 font-black text-xs flex justify-between items-center transition-all ${examForm.loa ? 'border-red-600 bg-red-50 text-red-800' : 'border-slate-50 bg-slate-50 text-slate-400'}`}>Lesão Órgão Alvo? {examForm.loa ? : } Risco CV: {calculated.rcv}
{/* 2. AUTOCUIDADO */}
2. Higiene e Autocuidado setExamForm({...examForm, calcadoAdequado: !examForm.calcadoAdequado})} className={`p-6 rounded-3xl border-2 font-black text-[10px] uppercase flex flex-col items-center gap-3 transition-all ${examForm.calcadoAdequado ? 'border-emerald-500 bg-emerald-50 text-emerald-700' : 'border-rose-200 bg-rose-50 text-rose-700'}`}>
{examForm.calcadoAdequado ? : } Calçado Adequado
setExamForm({...examForm, unhaCortadaAdequada: !examForm.unhaCortadaAdequada})} className={`p-6 rounded-3xl border-2 font-black text-[10px] uppercase flex flex-col items-center gap-3 transition-all ${examForm.unhaCortadaAdequada ? 'border-emerald-500 bg-emerald-50 text-emerald-700' : 'border-rose-200 bg-rose-50 text-rose-700'}`}>
{examForm.unhaCortadaAdequada ? : } Unhas Adequadas
setExamForm({...examForm, higieneOk: !examForm.higieneOk})} className={`p-6 rounded-3xl border-2 font-black text-[10px] uppercase flex flex-col items-center gap-3 transition-all ${examForm.higieneOk ? 'border-emerald-500 bg-emerald-50 text-emerald-700' : 'border-rose-200 bg-rose-50 text-rose-700'}`}>
{examForm.higieneOk ? : } Autocuidado Preservado
{/* 3. EXAME FÍSICO */}
3. Exame Físico das Extremidades
{/* SINTOMAS */}
{['Queimação', 'Formigamento', 'Cãibras', 'Dormência'].map(s => (
{
const list = examForm.pd.sintomas || [];
const newList = list.includes(s) ? list.filter(i => i !== s) : [...list, s];
setExamForm({...examForm, pd: {...examForm.pd, sintomas: newList}});
}} className={`p-4 rounded-2xl border-2 font-bold text-[10px] uppercase transition-all ${examForm.pd.sintomas?.includes(s) ? 'bg-orange-50 border-orange-400 text-orange-700' : 'bg-slate-50 border-slate-100 text-slate-400'}`}>{s}
))}
{['pd', 'pe'].map(side => (
{
const newMarkers = [...examForm[side].markers, { x: d.x, y: d.y, type: activeMarkerType }];
const hasUlcer = newMarkers.some(m => m.type === 'ulcera');
setExamForm(p => ({
...p,
[side]: {
...p[side],
markers: newMarkers,
temUlcera: hasUlcer
}
}));
}} onRemoveMarker={(i) => {
const upd = [...examForm[side].markers]; upd.splice(i, 1);
const hasUlcer = upd.some(m => m.type === 'ulcera');
setExamForm({...examForm, [side]: {...examForm[side], markers: upd, temUlcera: hasUlcer}});
}} /> setActiveMarkerType('ulcera')} className={`px-4 py-2 rounded-xl text-[10px] font-black ${activeMarkerType === 'ulcera' ? 'bg-red-600 text-white' : 'bg-white text-slate-400 border'}`}>ÚLCERA setActiveMarkerType('calo')} className={`px-4 py-2 rounded-xl text-[10px] font-black ${activeMarkerType === 'calo' ? 'bg-amber-500 text-white' : 'bg-white text-slate-400 border'}`}>CALO
{/* CLASSIFICAÇÃO DA ÚLCERA (SE HOUVER) */}
{examForm[side].temUlcera && (
Caracterização da Lesão
{['1', '2', '3'].map(g => (
setExamForm({...examForm, [side]: {...examForm[side], ulceraGrau: g}})} className={`py-2 rounded-xl border font-bold text-[9px] ${examForm[side].ulceraGrau === g ? 'bg-red-600 text-white border-red-600' : 'bg-white text-red-400 border-red-100'}`}>Grau {g}
))}
1: Superficial | 2: Profunda/Tendão | 3: Osso/Gangrena
setExamForm({...examForm, [side]: {...examForm[side], sinaisInfeccao: !examForm[side].sinaisInfeccao}})} className={`w-full py-2 rounded-xl border font-bold text-[9px] flex justify-between px-3 items-center ${examForm[side].sinaisInfeccao ? 'bg-red-100 border-red-300 text-red-800' : 'bg-white border-red-100 text-red-400'}`}>
Sinais de Infecção? {examForm[side].sinaisInfeccao ? : }
)}
{/* FOTO */}
Foto {side === 'pd' ? 'Direita' : 'Esquerda'}
{examForm[side].photo ? (
<>
setExamForm(p => ({...p, [side]: {...p[side], photo: null}}))} className="absolute top-4 right-4 bg-red-600 text-white p-2 rounded-full shadow-lg"> >
) : (
Tirar Foto handlePhotoUpload(side, e.target.files[0])} />
)}
Monofilamento 10g
{['presente', 'ausente'].map(v => (
setExamForm({...examForm, [side]: {...examForm[side], sensibilidade: v}})} className={`flex-1 py-3 rounded-2xl border-2 font-black text-[9px] uppercase transition-all ${examForm[side].sensibilidade === v ? 'border-indigo-600 bg-indigo-50 text-indigo-800' : 'border-slate-50 bg-white text-slate-300'}`}>{v}
))}
Diapasão 128Hz
{['presente', 'ausente', 'nao_avaliado'].map(v => (
setExamForm({...examForm, [side]: {...examForm[side], diapasao: v}})} className={`flex-1 py-3 rounded-2xl border-2 font-black text-[8px] uppercase transition-all ${examForm[side].diapasao === v ? (v === 'nao_avaliado' ? 'border-slate-400 bg-slate-200 text-slate-600' : 'border-indigo-600 bg-indigo-50 text-indigo-800') : 'border-slate-50 bg-white text-slate-300'}`}>{v.replace('_', ' ')}
))}
Pulsos Arteriais
{['presente', 'ausente'].map(v => (
setExamForm({...examForm, [side]: {...examForm[side], pulsoPedioso: v, pulsoTibial: v}})} className={`flex-1 py-3 rounded-2xl border-2 font-black text-[9px] uppercase transition-all ${examForm[side].pulsoPedioso === v ? 'border-indigo-600 bg-indigo-50 text-indigo-800' : 'border-slate-50 bg-white text-slate-300'}`}>{v}
))}
Deformidades
{['Garra', 'Martelo', 'Charcot', 'Hallux Valgus', 'Amputação'].map(d => (
toggleArrayItem(side, 'deformidades', d)} className={`px-3 py-2 rounded-xl border-2 text-[9px] font-black uppercase ${examForm[side].deformidades?.includes(d) ? 'border-purple-500 bg-purple-50 text-purple-700' : 'border-slate-50 bg-white text-slate-300'}`}>{d}
))}
))}
{/* RESULTADO + CONDUTA */}
setExamForm({...examForm, historicoUlcera: !examForm.historicoUlcera})} className={`p-4 rounded-2xl border-2 font-black text-[10px] uppercase transition-all ${examForm.historicoUlcera ? 'bg-red-50 border-red-500 text-red-700' : 'border-slate-100 text-slate-400'}`}>Histórico de Úlcera {examForm.historicoUlcera && '✓'} setExamForm({...examForm, historicoAmputacao: !examForm.historicoAmputacao})} className={`p-4 rounded-2xl border-2 font-black text-[10px] uppercase transition-all ${examForm.historicoAmputacao ? 'bg-red-50 border-red-500 text-red-700' : 'border-slate-100 text-slate-400'}`}>Histórico de Amputação {examForm.historicoAmputacao && '✓'}
IWGDF 2023
Risco {calculated.riwgdf}
{/* BOTÕES DE INSERÇÃO RÁPIDA DE CONDUTA */}
Inserção Rápida
{conductOptions.map((opt, i) => (
setExamForm(prev => ({
...prev,
conduta: (prev.conduta ? prev.conduta + '\n' : '') + '- ' + opt.text
}))}
className="px-3 py-2 bg-indigo-50 hover:bg-indigo-100 text-indigo-700 rounded-xl text-[10px] font-bold border border-indigo-100 transition-colors flex items-center gap-2"
>{opt.icon} {opt.label}
))}
{isSaving ? : } Finalizar Avaliação
)}
{/* IMPRESSÃO */}
{view === 'print' && activeExam && (
{printMode === 'crie' && (
Identificação do Paciente Nome: {selectedPatient.name}
CPF: {selectedPatient.cpf}
Data de Nascimento: {selectedPatient.birthDate ? new Date(selectedPatient.birthDate).toLocaleDateString() : '--'}
Diagnóstico: Diabetes Mellitus não especificado (CID E14)
Solicitação Ao Centro de Referência para Imunobiológicos Especiais (CRIE),
Solicito a aplicação da vacina Pneumocócica 23-valente (Pneumo 23) para o paciente acima identificado.
Justificativa: Paciente portador de Diabetes Mellitus, grupo de risco para doença pneumocócica invasiva, conforme recomendação do PNI (Programa Nacional de Imunizações) e da SBIm.
)}
{printMode === 'clinical' && (
<>
Paciente {selectedPatient.name}
Nasc: {selectedPatient.birthDate} | CPF: {selectedPatient.cpf}
{selectedPatient.medications?.length > 0 &&
Meds: {selectedPatient.medications.join(', ')}
}
HbA1c: {activeExam.hba1c}% ({formatDate(activeExam.hba1cDate)})
IMC: {activeExam.imc}
LDL: {activeExam.ldl} ({formatDate(activeExam.ldlDate)})
Risco CV: {activeExam.riscoCV}
IWGDF: Categoria {activeExam.riscoIWGDF} (Retorno em {activeExam.retorno})
Exame das Extremidades e Autocuidado Calçado: {activeExam.calcadoAdequado ? 'Adequado' : 'Inadequado'}
Unhas: {activeExam.unhaCortadaAdequada ? 'Corretas' : 'Incorretas'}
Autocuidado: {activeExam.higieneOk ? 'Preservado' : 'Atenção'}
{activeExam.pd?.sintomas?.length > 0 && (
Sintomas Relatados: {activeExam.pd.sintomas.join(', ')}
)}
{['pd', 'pe'].map(side => (
{activeExam[side].photo &&
}
{side === 'pd' ? 'Pé Direito' : 'Pé Esquerdo'}
Monof.: {activeExam[side].sensibilidade}
Diapasão: {activeExam[side].diapasao?.replace('_', ' ')}
Deformidades: {activeExam[side].deformidades?.join(', ') || 'Nenhuma'}
{activeExam[side].temUlcera && (
ÚLCERA GRAU {activeExam[side].ulceraGrau} {activeExam[side].sinaisInfeccao ? '(INFECTADA)' : ''}
)}
))}
>
)}
{printMode === 'patient' && (
Classificação de Risco: {activeExam.riscoIWGDF} Seu retorno deve ocorrer em: {activeExam.retorno}
10 Mandamentos do Pé Diabético 1. Examine os pés diariamente com um espelho. Procure cortes, bolhas ou vermelhidão. 2. Mantenha os pés limpos e secos, especialmente entre os dedos. 3. Hidrate a pele (exceto entre os dedos) para evitar rachaduras. 4. Corte as unhas de forma reta e lixe os cantos. Não remova cutículas. 5. Nunca ande descalço, nem em casa, nem na praia. 6. Use calçados confortáveis, fechados e sem costuras internas ásperas. 7. Verifique o interior do sapato antes de calçar (pedras ou objetos). 8. Não use água quente nos pés (teste a temperatura com o cotovelo). 9. Nunca use calicidas, giletes ou lixas metálicas para remover calos. 10. Em caso de ferida, procure sua unidade de saúde imediatamente.
Técnica de Corte
Calçado Ideal Recomendações Específicas da Consulta "{activeExam.conduta}"
{/* QR CODES */}
Aponte a câmera para os códigos abaixo
Fisioterapia
Nutrição
Dra. Patrícia
Enf. Lara
)}
{CITY_NAME}
{DOCTOR_NAME}
{DOCTOR_CRM}
window.print()} className="bg-indigo-700 text-white px-12 py-5 rounded-2xl font-black shadow-xl flex items-center gap-3 active:scale-95 transition-all text-sm uppercase tracking-widest"> Confirmar Impressão setView('detail')} className="text-slate-400 font-bold px-8 py-5">Voltar
)}
{/* CADASTRO PACIENTE COM MODALIDADE DE EDIÇÃO */}
{(view === 'new-patient' || view === 'edit-patient') && (
setView('list')} className="text-indigo-600 font-black text-xs uppercase mb-8 flex items-center gap-1 hover:underline tracking-widest transition-colors"> Voltar
)}
);
};
export default App;