turns-00062.parquet:31207
4ccd3dc8b8f77ec57c3b28dcdegenerate_repetitionAbsentFinal dense release
Select one behavior. Every returned turn has one binary label: Present or Absent. Source: final dense boolean release.
4ccd3dc8b8f77ec57c3b28dcSend only episode number from below text like 01, 02, 03.etc without any extra text. The Ancient Magus Bride S02E22 [RareToonsIndia].mkv
22
e77725a33556a7aa8d443082Send only season number from below text like 01, 02, 03.etc without any extra text. The Ancient Magus Bride S02E22 [RareToonsIndia].mkv
02
909a31af363f08620543e215واذا لا يوجد الم هل هناك دوالي خصيه
نعم، يمكن أن توجد دوالي الخصية دون وجود ألم. دوالي الخصية هي حالة تتمثل في توسع الأوردة التي تحمل الدم من الخصيتين، وعادة ما يتم تشخيصها من خلال الفحص السريري أو عبر تصوير بالموجات فوق الصوتية. في بعض الحالات، قد لا يعاني الشخص من أي أعراض أو ألم، بينما في حالات أخرى، يمكن أن تسبب دوالي الخصية ألمًا، شعورًا بالثقل، أو تغير في حجم الخصية. إذا كنت تعتقد أنك قد تعاني من دوالي الخصية أو لديك أي قلق صحي، فمن الأفضل استشارة طبيب مختص للحصول على تقييم دقيق ونصائح علاجية مناسبة.
3d7a8f688b433d21813ebd67preciso que ao clicar aqui
<img src="/lapisEditor.png" alt="Editar" className={styles.icon} />
o card de atendimento carregue todos os dados do atendimento e os passe para o componente novo atendimento , para que la eu possa editalo, como posso fazer isto?
// CardAtendimento.tsx
import React, { useState } from "react";
import styles from "./Atendimentos.module.css";
import CardProcedimento from "./CardProcedimento";
import { AppointmentRequestDTO, ProcedureDTO } from "./types";
import { formatMesAno, toMoney } from "../utils/FormatedData";
import Anexo from "../ui/Anexo";
const CoresInput = [
"#25AAE1", // Cor 1
"#8696BB", // Cor 2
"#39465F", // Cor 3
"#D56D98", // Cor 4
];
// Definindo os tipos para as props do componente
interface CardAtendimentoProps {
appointment: AppointmentRequestDTO;
alternarCard: () => void; // Função sem parâmetros que não retorna nada
}
const CardAtendimento: React.FC<CardAtendimentoProps> = ({
appointment,
alternarCard,
}) => {
const [mostrarCard, setMostrarCard] = useState(false); // Estado para expandir/recolher o Card
const alternaCard = () => {
setMostrarCard(!mostrarCard);
};
const handleExcluirProcedimento = (id: string) => {
// Filtra o array de procedimentos, mantendo apenas aqueles cujo id não coincide.
const novosProcedimentos = atendimento.procedures.filter(
(proc) => proc.id !== id
);
// Cria uma cópia do estado de atendimento e atualiza a lista de procedimentos
setAtendimento((prev) => ({
...prev,
procedures: novosProcedimentos, // Atualiza a lista de procedimentos
}));
// Opcional: Se existir alguma lógica que dependa da atualização da barra gráfica, você pode chamar:
};
const updateProcedimento = (index: number, novosDados: ProcedureDTO) => {
console.log(index, novosDados);
const cloneAtendimento = { ...atendimento };
cloneAtendimento.procedures[index] = novosDados;
setAtendimento(cloneAtendimento);
};
const [atendimento, setAtendimento] = useState<AppointmentRequestDTO>({
status: {
glossed: false,
lost: false,
received: false,
draft: false,
validated: false,
derived: false,
finished: false,
},
related: {
place: undefined,
payer: undefined,
patient: undefined,
},
paymentInfo: {
method: "healthInsurance",
info: {
totalSum: 0,
healthInsurance: {
cardNumber: "",
},
totalValues: {
expected: 0,
glossed: 0,
lost: 0,
paid: 0,
},
totalProcedures: {
expected: 0,
glossed: 0,
lost: 0,
paid: 0,
},
},
},
serviceInfo: {
guideCode: "",
date: "",
totalValue: 0,
},
procedures: [],
});
return (
<div className={styles.CardPai}>
<div className={styles.CardTopPai}>
<div className={styles.buttonCard}>
<button>
<img src="/lapisEditor.png" alt="Editar" className={styles.icon} />
</button>
</div>
</div>
<div className={styles.divDoCardPai}>
{/* barra */}
<div className={styles.divValores}>
<div className={styles.inputValores}>
<label className={styles.total}>Total:</label>
{[
appointment.paymentInfo.info.totalValues.expected,
appointment.paymentInfo.info.totalValues.glossed,
appointment.paymentInfo.info.totalValues.lost,
appointment.paymentInfo.info.totalValues.paid,
].map((valor, index) => (
<div key={index}>
<span
style={{
color: CoresInput[index],
fontSize: "14px",
marginRight: "2px",
}}
>
R$
</span>
<input
key={index}
type="number"
value={valor.toFixed(2)}
placeholder="R$ 0,00"
style={{ color: CoresInput[index] }}
readOnly
/>
</div>
))}
</div>
<div className={styles.divBarraGrafico}>
<label className={styles.labelTotal}>
R$ {toMoney(appointment.paymentInfo.info.totalSum)}
</label>
<div className={styles.graficoRepresentativo}>
<div className={styles.barraFixa}>
{[
appointment.paymentInfo.info.totalValues.expected,
appointment.paymentInfo.info.totalValues.glossed,
appointment.paymentInfo.info.totalValues.lost,
appointment.paymentInfo.info.totalValues.paid,
].map((valor, index) => (
<div
key={`grafico-${index}`}
style={{
backgroundColor: CoresInput[index],
width:
appointment.paymentInfo.info.totalSum > 0
? `${
(valor / appointment.paymentInfo.info.totalSum) *
100
}%`
: `0%`,
height: "100%",
}}
/>
))}
</div>
</div>
</div>
</div>
</div>
<div className={styles.divInformacoes}>
<div className={styles.divDados}>
<label className={styles.labelData}>
{appointment.serviceInfo.date}
</label>
<label className={styles.labelPaciente}>
{appointment.related.patient?.name}
</label>
<label className={styles.labelCodigo}>
{appointment.serviceInfo.guideCode}
</label>
</div>
<div className={styles.divRow}>
<label className={styles.labelLocais}>
<img src="cifrao.png" className={styles.icons} alt="" />
modalidade: {appointment.paymentInfo.method}
</label>
<label className={styles.labelLocais}>
<img src="cifrao.png" className={styles.icons} alt="" />
Fonte Pagadora:
{appointment.related.payer?.name}
{/* fontepagadora */}
</label>
</div>
<div className={styles.divRowDados}>
<label className={styles.labelLocais}>
<img src="local-icon.png" alt="" className={styles.icons} />
Local:
{appointment.related.place?.name}
</label>
<img src="Completo.png" alt="" className={styles.imgCompleto} />
</div>
<div className={styles.divBarra} />
</div>
{/* Segunda barra gráfica com funcionalidade ajustada */}
<div className={styles.divValores2}>
<div className={styles.inputProcedimentos}>
{[
appointment.paymentInfo.info.totalProcedures.expected,
appointment.paymentInfo.info.totalProcedures.glossed,
appointment.paymentInfo.info.totalProcedures.lost,
appointment.paymentInfo.info.totalProcedures.paid,
].map((valor, index) => (
<input
key={index}
type="number"
value={valor.toFixed(0)} // Mostra a contagem
placeholder="0"
readOnly // Barra apenas visual, não editável
style={{ color: CoresInput[index] }} // Cor correspondente à respectiva
/>
))}
</div>
<div className={styles.divBarraGrafico}>
<div className={styles.divTotal}>
<img src="/procedimento.png" alt="" className={styles.icone} />
<label className={styles.labelProcedimento}>
<label>{appointment.procedures.length}</label> Procedimento
</label>
</div>
<div className={styles.graficoRepresentativo}>
<div className={styles.barraFixa}>
{[
appointment.paymentInfo.info.totalProcedures.expected,
appointment.paymentInfo.info.totalProcedures.glossed,
appointment.paymentInfo.info.totalProcedures.lost,
appointment.paymentInfo.info.totalProcedures.paid,
].map((valor, index) => (
<div
key={`grafico-segunda-${index}`}
style={{
backgroundColor: CoresInput[index],
width: `${(valor / appointment.procedures.length) * 100}%`, // Ajuste a largura da barra conforme a contagem
height: "100%",
}}
/>
))}
</div>
</div>
{/* Botão de expandir/recolher */}
<div className={styles.expandirProcedimentos} onClick={alternaCard}>
<img
src="/setaBaixo.png"
alt="Expandir/recolher"
className={styles.iconSeta}
/>
<label className={styles.labelExpandir}>
{mostrarCard ? "Recolher" : "Expandir"}
</label>
</div>
</div>
</div>
<div className={styles.centro}>
{/* Renderiza o Card apenas se mostrarCard for true */}
{mostrarCard && (
<>
{/* Renderiza os procedimentos adicionados */}
{appointment.procedures.map((proc, index) => (
<CardProcedimento
key={"procedure_" + proc.id}
index={index} // Usando o índice corretamente
procedure={proc}
updateProcedimento={updateProcedimento}
handleExcluir={handleExcluirProcedimento}
/>
))}{" "}
</>
)}
</div>
<Anexo
attachments={atendimento.attachments || []}
setAttachments={(novosAnexos) => {
setAtendimento((prev) => ({
...prev,
attachments: novosAnexos,
}));
}}
/>
<div className={styles.space} />
<div className={styles.CardBottonPai}></div>
</div>
);
};
export default CardAtendimento;
import EstiloNovoAtendimento from "./NovoAtendimento.module.css";
import React, { useState, useEffect } from "react";
import { useApi } from "../../lib/doctorApi";
import { AppointmentRequestDTO, ProcedureDTO } from "./types";
import DropdownSelect from "./DropdownSelect";
import CardProcedimento from "./CardProcedimento";
import { v4 as uuidv4 } from "uuid"; // Importa a função para gerar UUIDs
import { toMoney } from "../utils/FormatedData";
import Anexo from "../ui/Anexo";
const CoresInput = [
"#25AAE1", // Cor 1
"#8696BB", // Cor 2
"#39465F", // Cor 3
"#D56D98", // Cor 4
];
const NovoAtendimento: React.FC = () => {
const updateProcedimento = (index: number, novosDados: ProcedureDTO) => {
console.log(index, novosDados);
const cloneAtendimento = { ...atendimento };
cloneAtendimento.procedures[index] = novosDados;
setAtendimento(cloneAtendimento);
};
const [botaoSalvar, setBotaoSalvar] = useState("");
const enviarDadosAtendimento = async () => {
loading;
try {
const result = await api.post("appointments/create", atendimento);
if (result?.data?.success) {
if (
result.data.result?.id &&
result.data.result.id !== atendimento.id
) {
const cloneAtendimento = { ...atendimento };
cloneAtendimento.id = result.data.result.id;
setAtendimento(cloneAtendimento);
}
console.log("dados enviados", result);
}
result?.data?.messages;
console.log("atendimento criado comm sucesso", result);
setBotaoSalvar("Salvo");
} catch (e: any) {
e?.response?.data?.messages;
console.log("erro ao criar atendimento", e);
setBotaoSalvar("Salvar");
}
setLoading;
};
useEffect(() => {
setBotaoSalvar("Salvar");
const queryParams = new URLSearchParams(location.search);
const appointmentId = queryParams.get("id");
if (appointmentId) {
const fetchAtendimento = async () => {
try {
const response = await api.get(`appointments/get/${appointmentId}`);
const atendimento = response.data.result;
setAtendimento(atendimento);
} catch (error) {
console.error("Erro ao buscar paciente:", error);
}
};
fetchAtendimento();
}
}, []);
const handleAdicionarProcedimento = () => {
const novoProcedimento: ProcedureDTO = {
id: uuidv4(),
createdAt: new Date(),
updatedAt: new Date(),
cbhpmCode: "",
cbhpmName: "",
expectedValue: 0,
glossedValue: 0,
lostValue: 0,
paidValue: 0,
placeId: atendimento.related.place?.id || "",
payerId: atendimento.related.payer?.id || "",
patientId: atendimento.related.patient?.id || "",
statusOfActivity: "draft",
attachments: [],
};
const cloneAtendimento = { ...atendimento };
cloneAtendimento.procedures.push(novoProcedimento);
setAtendimento(cloneAtendimento);
setMostrarCard(true);
};
const handleExcluirProcedimento = (id: string) => {
// Filtra o array de procedimentos, mantendo apenas aqueles cujo id não coincide.
const novosProcedimentos = atendimento.procedures.filter(
(proc) => proc.id !== id
);
// Cria uma cópia do estado de atendimento e atualiza a lista de procedimentos
setAtendimento((prev) => ({
...prev,
procedures: novosProcedimentos, // Atualiza a lista de procedimentos
}));
// Opcional: Se existir alguma lógica que dependa da atualização da barra gráfica, você pode chamar:
};
// Atualiza o localStorage sempre que procedimentos mudar
const [mostrarCard, setMostrarCard] = useState(false); // Estado para expandir/recolher o Card
const [anexos, setAnexos] = useState<
{ id: string; fileName: string; extension: string }[]
>([]); // Estado para os arquivos anexados
const [loading, setLoading] = useState(false);
const api = useApi(); // `useApi` é tratado como estável
const [atendimento, setAtendimento] = useState<AppointmentRequestDTO>({
status: {
glossed: false,
lost: false,
received: false,
draft: false,
validated: false,
derived: false,
finished: false,
},
related: {
place: undefined,
payer: undefined,
patient: undefined,
},
paymentInfo: {
method: "healthInsurance",
info: {
totalSum: 0,
healthInsurance: {
cardNumber: "",
},
totalValues: {
expected: 0,
glossed: 0,
lost: 0,
paid: 0,
},
totalProcedures: {
expected: 0,
glossed: 0,
lost: 0,
paid: 0,
},
},
},
serviceInfo: {
guideCode: "",
date: "",
totalValue: 0,
},
procedures: [],
});
const atualizarValoresBarra = () => {
const totalProcedures = {
expected: 0,
glossed: 0,
lost: 0,
paid: 0,
};
const totalValue = {
expected: 0,
glossed: 0,
lost: 0,
paid: 0,
};
atendimento.procedures.forEach((proc) => {
if (proc.expectedValue > 0) {
totalProcedures.expected += 1; // Incrementa para expectedValue
totalValue.expected += proc.expectedValue;
}
if (proc.glossedValue > 0) {
totalProcedures.glossed += 1; // Incrementa para glossedValue
totalValue.glossed += proc.glossedValue;
}
if (proc.lostValue > 0) {
totalProcedures.lost += 1; // Incrementa para lostValue
totalValue.lost += proc.lostValue;
}
if (proc.paidValue > 0) {
totalProcedures.paid += 1; // Incrementa para paidValue
totalValue.paid += proc.paidValue;
}
});
const cloneAtendimento = { ...atendimento };
cloneAtendimento.paymentInfo.info.totalProcedures = totalProcedures;
cloneAtendimento.paymentInfo.info.totalValues = totalValue;
cloneAtendimento.paymentInfo.info.totalSum =
cloneAtendimento.paymentInfo.info.totalValues.expected +
cloneAtendimento.paymentInfo.info.totalValues.glossed +
cloneAtendimento.paymentInfo.info.totalValues.lost +
cloneAtendimento.paymentInfo.info.totalValues.paid;
setAtendimento(cloneAtendimento); // Atualiza o estado dos valores da barra
};
useEffect(() => {
atualizarValoresBarra();
}, [JSON.stringify(atendimento.procedures)]);
// Função que alterna entre expandir e recolher
const alternarCard = () => {
setMostrarCard(!mostrarCard);
};
return (
<div>
<label className={EstiloNovoAtendimento.labeltitle}>
Cadastro de Atendimento
</label>
<form>
<div className={EstiloNovoAtendimento.divValores}>
<div className={EstiloNovoAtendimento.inputValores}>
<label className={EstiloNovoAtendimento.total}>Total:</label>
{[
atendimento.paymentInfo.info.totalValues.expected,
atendimento.paymentInfo.info.totalValues.glossed,
atendimento.paymentInfo.info.totalValues.lost,
atendimento.paymentInfo.info.totalValues.paid,
].map((valor, index) => (
<div key={index}>
<span
style={{
color: CoresInput[index],
fontSize: "14px",
marginRight: "2px",
}}
>
R$
</span>
<input
key={index}
type="number"
value={valor.toFixed(2)}
placeholder="R$ 0,00"
style={{ color: CoresInput[index] }}
readOnly
/>
</div>
))}
</div>
<div className={EstiloNovoAtendimento.divBarraGrafico}>
<label className={EstiloNovoAtendimento.labelTotal}>
R$ {toMoney(atendimento.paymentInfo.info.totalSum)}
{/* Aqui já usará o total atualizado */}
</label>
<div className={EstiloNovoAtendimento.graficoRepresentativo}>
<div className={EstiloNovoAtendimento.barraFixa}>
{[
atendimento.paymentInfo.info.totalValues.expected,
atendimento.paymentInfo.info.totalValues.glossed,
atendimento.paymentInfo.info.totalValues.lost,
atendimento.paymentInfo.info.totalValues.paid,
].map((valor, index) => (
<div
key={`grafico-${index}`}
style={{
backgroundColor: CoresInput[index],
width:
atendimento.paymentInfo.info.totalSum > 0
? `${
(valor / atendimento.paymentInfo.info.totalSum) *
100
}%`
: `0%`,
height: "100%",
}}
/>
))}
</div>
</div>
</div>
</div>
<div className={EstiloNovoAtendimento.container}>
<div className={EstiloNovoAtendimento.modalidade}>
<label>Modalidade:</label>
<div className={EstiloNovoAtendimento.divMargin}>
<input
className={EstiloNovoAtendimento.radio}
type="radio"
id="convenio"
name="modalidade"
value="convenio"
onChange={() => {
setAtendimento((prev) => ({
...prev,
paymentInfo: {
...prev.paymentInfo,
method: "healthInsurance", // Ou qualquer método que você queira usar
},
}));
}}
/>
<label
htmlFor="convenio"
className={EstiloNovoAtendimento.labelModalidade}
>
Convênio
</label>
<input
className={EstiloNovoAtendimento.radio}
type="radio"
id="particular"
name="modalidade"
value="particular"
onChange={() => {
setAtendimento((prev) => ({
...prev,
paymentInfo: {
...prev.paymentInfo,
method: "private", // Atualize para "particular"
},
}));
}}
/>
<label
htmlFor="particular"
className={EstiloNovoAtendimento.labelModalidade}
>
Particular
</label>
<input
className={EstiloNovoAtendimento.radio}
type="radio"
id="plantao"
name="modalidade"
value="plantao"
onChange={() => {
setAtendimento((prev) => ({
...prev,
paymentInfo: {
...prev.paymentInfo,
method: "onDuty", // Atualize para "plantao"
},
}));
}}
/>
<label
htmlFor="plantao"
className={EstiloNovoAtendimento.labelModalidade}
>
Plantão
</label>
</div>
</div>
<DropdownSelect
endpoint="places/find?skip=0&limit=2000&payer=true" // URL do endpoint
parseData={(data) =>
data.result.list.map((local: any) => ({
id: local.id,
name: local.name,
}))
} // Função que transforma os dados da API no formato { id, name }
onSelect={(selectedItem) => {
// Atualizar o estado de atendimento para incluir o payer
setAtendimento((prev) => ({
...prev,
related: {
...prev.related,
payer: { id: selectedItem.id, name: selectedItem.name }, // Assumindo que você quer armazenar um objeto { id, name }
},
}));
}} // Define o item selecionado no estado
value={atendimento.related.payer?.id || ""} // Valor atual do dropdown
label="Fonte Pagadora:" // Rótulo a ser exibido
/>
</div>
<div className={EstiloNovoAtendimento.container}>
{/* TODO: O Componente paciente precisa ter um campo de busca e buscar na api do backend com limite de 10 pacientes */}
<DropdownSelect
endpoint="patients/find?skip=0&limit=2000" // URL do endpoint
parseData={(data) =>
data.result.list.map((item: any) => ({
id: item.id,
name: item.name,
}))
} // Função que transforma os dados da API no formato { id, name }
onSelect={(selectedItem) => {
// Atualizar o estado de atendimento para incluir o payer
setAtendimento((prev) => ({
...prev,
related: {
...prev.related,
patient: { id: selectedItem.id, name: selectedItem.name }, // Assumindo que você quer armazenar um objeto { id, name }
},
}));
}} // Define o item selecionado no estado
value={atendimento.related.patient?.id || ""} // Valor atual do dropdown
label="Paciente:" // Rótulo a ser exibido
/>
<DropdownSelect
endpoint="places/find?skip=0&limit=2000&place=true" // URL do endpoint para buscar locais de atendimento
parseData={(data) =>
data.result.list.map((local: any) => ({
id: local.id,
name: local.name,
}))
} // Função para transformar os dados da API no formato { id, name }
onSelect={(selectedItem) => {
// Atualizar o estado de atendimento para incluir o payer
setAtendimento((prev) => ({
...prev,
related: {
...prev.related,
place: { id: selectedItem.id, name: selectedItem.name }, // Assumindo que você quer armazenar um objeto { id, name }
},
}));
}} // Callback para atualizar o formulário com o local selecionado
value={atendimento.related.place?.id || ""} // ID do item selecionado
label="Local de Atendimento:" // Rótulo exibido
/>
</div>
<div className={EstiloNovoAtendimento.container}>
<div className={EstiloNovoAtendimento.organizador}>
<span>Código da guia(opcional)</span>
<input
className={EstiloNovoAtendimento.input300}
type="text"
name="codigo"
placeholder="Digite"
value={atendimento.serviceInfo.guideCode}
onChange={(e) => {
const codigo = e.target.value;
// Atualiza o estado de atendimento com o código da guia
setAtendimento((prev) => ({
...prev,
serviceInfo: {
...prev.serviceInfo,
guideCode: codigo, // Atualiza o guideCode com o valor do input
},
}));
}}
/>
</div>
<div className={EstiloNovoAtendimento.organizador}>
<span>Data</span>
<input
className={EstiloNovoAtendimento.inputData}
type="date"
name="data"
placeholder="dd/mm/yyyy"
value={atendimento.createdAt?.toISOString()}
onChange={(e) => {
const data = e.target.value;
setAtendimento((prev) => ({
...prev,
serviceInfo: {
...prev.serviceInfo,
date: data,
},
}));
}}
/>
</div>
</div>
</form>
{/* deveria ficar aqui */}
<div className={EstiloNovoAtendimento.divbutton}>
<button
type="button" // tipo "button" para evitar o envio do formulário
onClick={handleAdicionarProcedimento} // Chama a função ao clicar
className={EstiloNovoAtendimento.buttonProcedimento}
>
Adicionar Procedimento
</button>
</div>
{/* Segunda barra gráfica com funcionalidade ajustada */}
<div className={EstiloNovoAtendimento.divValores2}>
<div className={EstiloNovoAtendimento.inputProcedimentos}>
{[
atendimento.paymentInfo.info.totalProcedures.expected,
atendimento.paymentInfo.info.totalProcedures.glossed,
atendimento.paymentInfo.info.totalProcedures.lost,
atendimento.paymentInfo.info.totalProcedures.paid,
].map((valor, index) => (
<input
key={index}
type="number"
value={valor.toFixed(0)} // Mostra a contagem
placeholder="0"
readOnly // Barra apenas visual, não editável
style={{ color: CoresInput[index] }} // Cor correspondente à respectiva
/>
))}
</div>
<div className={EstiloNovoAtendimento.divBarraGrafico}>
<div className={EstiloNovoAtendimento.divTotal}>
<img
src="/procedimento.png"
alt=""
className={EstiloNovoAtendimento.icone}
/>
<label className={EstiloNovoAtendimento.labelProcedimento}>
<label>{atendimento.procedures.length}</label> Procedimento
</label>
</div>
<div className={EstiloNovoAtendimento.graficoRepresentativo}>
<div className={EstiloNovoAtendimento.barraFixa}>
{[
atendimento.paymentInfo.info.totalProcedures.expected,
atendimento.paymentInfo.info.totalProcedures.glossed,
atendimento.paymentInfo.info.totalProcedures.lost,
atendimento.paymentInfo.info.totalProcedures.paid,
].map((valor, index) => (
<div
key={`grafico-segunda-${index}`}
style={{
backgroundColor: CoresInput[index],
width: `${(valor / atendimento.procedures.length) * 100}%`, // Ajuste a largura da barra conforme a contagem
height: "100%",
}}
/>
))}
</div>
</div>
{/* Botão de expandir/recolher */}
<div
className={EstiloNovoAtendimento.expandirProcedimentos}
onClick={alternarCard}
>
<img
src="/setaBaixo.png"
alt="Expandir/recolher"
className={EstiloNovoAtendimento.iconSeta}
/>
<label className={EstiloNovoAtendimento.labelExpandir}>
{mostrarCard ? "Recolher" : "Expandir"}
</label>
</div>
</div>
</div>
{/* Renderiza o Card apenas se mostrarCard for true */}
{mostrarCard && (
<>
{/* Renderiza os procedimentos adicionados */}
{atendimento.procedures.map((proc, index) => (
<CardProcedimento
key={"procedure_" + proc.id}
index={index} // Usando o índice corretamente
procedure={proc}
updateProcedimento={updateProcedimento}
handleExcluir={handleExcluirProcedimento}
/>
))}
</>
)}
<Anexo
attachments={atendimento.attachments || []}
setAttachments={(novosAnexos) => {
setAtendimento((prev) => ({
...prev,
attachments: novosAnexos,
}));
}}
/>
<div className={EstiloNovoAtendimento.divbutton}>
<button
className={EstiloNovoAtendimento.buttonSalvar}
disabled={loading}
onClick={enviarDadosAtendimento}
>
{loading ? botaoSalvar : "Salvar"}
</button>
</div>
</div>
);
};
export default NovoAtendimento;
Para que o clique no ícone de editar (`<img src="/lapisEditor.png" alt="Editar" className={styles.icon} />`) no componente `CardAtendimento` redirecione os dados do agendamento para o componente `NovoAtendimento`, você precisará seguir alguns passos para configurar uma forma de comunicação entre esses componentes.
### Neste exemplo, usaremos React Router para gerenciar a navegação entre páginas.
1. **Instalar React Router** (se ainda não estiver instalado):
```bash
npm install react-router-dom
```
2. **Configurar o roteamento** no seu aplicativo. Crie um componente de roteamento que inclua ambas as páginas (`CardAtendimento` e `NovoAtendimento`):
```javascript
// App.tsx ou onde você define suas rotas
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import CardAtendimento from './CardAtendimento';
import NovoAtendimento from './NovoAtendimento';
function App() {
return (
<Router>
<Switch>
<Route path="/atendimento" component={CardAtendimento} />
<Route path="/novo-atendimento" component={NovoAtendimento} />
</Switch>
</Router>
);
}
export default App;
```
3. **Redirecionar ao editar**. Modifique o botão de edição para redirecionar para a página `NovoAtendimento` e passar os dados necessários pela URL. Você pode usar `history.push` ou `Link` do `react-router-dom`.
```javascript
import { useHistory } from 'react-router-dom';
const CardAtendimento: React.FC<CardAtendimentoProps> = ({ appointment, alternarCard }) => {
const history = useHistory();
const handleEdit = () => {
history.push({
pathname: '/novo-atendimento',
state: { appointment }, // Passa os dados do atendimento
});
};
return (
<button onClick={handleEdit}>
<img src="/lapisEditor.png" alt="Editar" className={styles.icon} />
</button>
);
};
```
4. **Recuperar os dados no `NovoAtendimento`**. Utilize o hook `useLocation` para acessar os dados que você enviou via state.
```javascript
import { useLocation } from 'react-router-dom';
const NovoAtendimento: React.FC = () => {
const location = useLocation();
const { appointment } = location.state || {}; // Recupera o estado
const [atendimento, setAtendimento] = useState<AppointmentRequestDTO>(appointment || {
// ... seu estado padrão aqui
});
// O resto do seu código para modificar e enviar os dados do atendimento
};
```
### Considerações Finais
- Certifique-se de que os dados que está passando entre os componentes estejam no formato correto (e que comportem todas as informações necessárias).
- Se você precisa que o componente `NovoAtendimento` renderize com os dados de forma assíncrona (como em uma chamada de API), você pode ajustar o código em `useEffect`.
- O hooking de navegação usando o `useHistory` é uma maneira prática e comum de gerenciar redirecionamentos no React Router.
### Exemplo Completo das Funções Alteradas
**`CardAtendimento.tsx`**
```javascript
import { useHistory } from 'react-router-dom';
//... outras importações
const CardAtendimento: React.FC<CardAtendimentoProps> = ({ appointment, alternarCard }) => {
const history = useHistory();
const handleEdit = () => {
history.push({
pathname: '/novo-atendimento',
state: { appointment }, // Passa os dados do atendimento
});
};
return (
<div className={styles.CardPai}>
<div className={styles.CardTopPai}>
<div className={styles.buttonCard}>
<button onClick={handleEdit}>
<img src="/lapisEditor.png" alt="Editar" className={styles.icon} />
</button>
</div>
</div>
{/*... restante do componente */}
</div>
);
};
export default CardAtendimento;
```
**`NovoAtendimento.tsx`**
```javascript
import { useLocation } from 'react-router-dom';
//... outras importações
const NovoAtendimento: React.FC = () => {
const location = useLocation();
const { appointment } = location.state || {}; // Recupera os dados do atendimento
const [atendimento, setAtendimento] = useState<AppointmentRequestDTO>(appointment || {
//... seu estado padrão
});
//... resto do seu componente
};
export default NovoAtendimento;
```
Com essas mudanças, você será capaz de editar um atendimento existente ao clicar no ícone de editar e navegar para outra página carregando os dados desse atendimento.b429ec1ef7cdb0701f35f4b6qual jeito é o mais viavel usando api? e isso ira passar o id tambem?
Ao integrar APIs em aplicações React, existem diversas abordagens que você pode considerar para atualizar e editar dados. Vamos explorar a opção de passar dados (incluindo IDs) usando URL e estado através do roteamento, como mencionamos anteriormente, mas também aqui estão algumas considerações e métodos adicionais:
### 1. Passando Dados pela Rota
A abordagem mais comum para passar dados entre diferentes componentes durante a navegação é através do uso de um estado que inclui todos os dados necessários, como o ID do atendimento. Quando você clica no ícone de editar, você poderia passar tanto os dados do atendimento quanto o seu ID.
#### Estrutura da Navegação
A seguir está como você pode implementar isso:
**`CardAtendimento.tsx`**
```javascript
import { useHistory } from 'react-router-dom';
//... outras importações
const CardAtendimento: React.FC<CardAtendimentoProps> = ({ appointment }) => {
const history = useHistory();
const handleEdit = () => {
history.push({
pathname: '/novo-atendimento',
state: { appointmentId: appointment.id, appointment },
});
};
return (
<button onClick={handleEdit}>
<img src="/lapisEditor.png" alt="Editar" className={styles.icon} />
</button>
);
};
export default CardAtendimento;
```
**`NovoAtendimento.tsx`**
```javascript
import { useLocation } from 'react-router-dom';
//... outras importações
const NovoAtendimento: React.FC = () => {
const location = useLocation();
const { appointmentId, appointment } = location.state || {};
const [atendimento, setAtendimento] = useState<AppointmentRequestDTO>(appointment || {
//... seu estado padrão
});
useEffect(() => {
if (!appointment) {
const fetchAtendimento = async () => {
try {
const response = await api.get(`appointments/get/${appointmentId}`);
setAtendimento(response.data.result);
} catch (error) {
console.error("Erro ao buscar atendimento:", error);
}
};
fetchAtendimento();
}
}, [appointmentId, appointment]);
//... restante do seu componente
};
export default NovoAtendimento;
```
### 2. Utilizando API Direta para Obter dados
Outra abordagem seria obter os dados diretamente do servidor usando o ID. Neste caso:
- Você navega para a rota de edição (`/novo-atendimento`) passando apenas o ID do atendimento na URL.
- Ao carregá-lo, você faria uma requisição à API usando o ID para obter os dados necessários.
**Exemplo de Navegação Usando Apenas ID**
**`CardAtendimento.tsx`**
```javascript
const CardAtendimento: React.FC<CardAtendimentoProps> = ({ appointment }) => {
const history = useHistory();
const handleEdit = () => {
history.push(`/novo-atendimento/${appointment.id}`);
};
return (
<button onClick={handleEdit}>
<img src="/lapisEditor.png" alt="Editar" className={styles.icon} />
</button>
);
};
export default CardAtendimento;
```
**`NovoAtendimento.tsx`**
```javascript
import { useParams } from 'react-router-dom';
//... outras importações
const NovoAtendimento: React.FC = () => {
const { id } = useParams<{ id: string }>(); // Pega o ID da rota usando useParams
const [atendimento, setAtendimento] = useState<AppointmentRequestDTO>(null);
useEffect(() => {
const fetchAtendimento = async () => {
try {
const response = await api.get(`appointments/get/${id}`);
setAtendimento(response.data.result);
} catch (error) {
console.error("Erro ao buscar atendimento:", error);
}
};
fetchAtendimento();
}, [id]);
//... restante do seu componente
};
export default NovoAtendimento;
```
### Considerações Finais
- **Desempenho**: O segundo método pode ser mais eficiente em termos de tamanho da navegação inicial. Ao pegar somente o ID na URL, você evita passar um grande objeto de estado. Se o objeto de atendimento contém muitos dados ou se você está preocupado com o tamanho da carga transferida pela URL, a abordagem de linha direta pela API é a recomendada.
- **Manutenção**: Passar objetos de dados completos entre componentes pode causar problemas de manutenção no caso de grandes mudanças na estrutura do dado.
- **Segurança**: Certifique-se de manejar dados sensíveis com cuidado, especialmente ao expor IDs na URL.
Ambas as opções permitirão transferir o ID do atendimento para o componente de novo atendimento. A escolha entre uma abordagem e outra dependerá das necessidades específicas da sua aplicação e da forma como você deseja estruturar a interação com a API.3e64e306c55dec17453a518avou optar pelo segundo metódo
Ótima escolha! O segundo método é uma prática comum e eficiente para gerenciar a edição de dados em aplicações React, especialmente quando você deseja manter a clareza e a robustez do seu código. Vou detalhar um passo a passo para implementar essa abordagem, utilizando o React Router e a API para buscar os dados do atendimento pelo ID.
### Implementação do Segundo Método
Aqui estão os passos detalhados para implementar a navegação e a recuperação dos dados:
#### 1. Atualize `CardAtendimento.tsx`
No componente onde você lista os atendimentos, modifique o botão de edição para navegar para a página de novo atendimento com o ID do atendimento escolhido na URL.
```javascript
import { useHistory } from 'react-router-dom';
//... outras importações e código do componente
const CardAtendimento: React.FC<CardAtendimentoProps> = ({ appointment }) => {
const history = useHistory();
const handleEdit = () => {
// Navega para a página de novo atendimento, passando o ID do atendimento
history.push(`/novo-atendimento/${appointment.id}`);
};
return (
<div className={styles.CardPai}>
<div className={styles.CardTopPai}>
<div className={styles.buttonCard}>
<button onClick={handleEdit}>
<img src="/lapisEditor.png" alt="Editar" className={styles.icon} />
</button>
</div>
</div>
{/*... restante do componente */}
</div>
);
};
export default CardAtendimento;
```
#### 2. Atualize `NovoAtendimento.tsx`
No componente de novo atendimento, você deve usar o `useParams` do `react-router-dom` para capturar o ID do atendimento e, em seguida, fazer a chamada à API para buscar os detalhes desse atendimento.
```javascript
import { useParams } from 'react-router-dom';
import { useEffect, useState } from 'react';
import { useApi } from '../../lib/doctorApi'; // ajuste o caminho conforme necessário
import { AppointmentRequestDTO } from './types';
const NovoAtendimento: React.FC = () => {
const { id } = useParams<{ id: string }>(); // Pega o ID da rota
const [atendimento, setAtendimento] = useState<AppointmentRequestDTO | null>(null);
const api = useApi(); // Hook para comunicação com a API
useEffect(() => {
const fetchAtendimento = async () => {
try {
const response = await api.get(`appointments/get/${id}`); // Fetching data by ID
setAtendimento(response.data.result);
} catch (error) {
console.error("Erro ao buscar atendimento:", error);
}
};
fetchAtendimento();
}, [id]);
// Lidar com o estado nulo
if (!atendimento) {
return <div>Carregando...</div>; // Ou um loader qualquer
}
//... Utilize o estado 'atendimento' em seu formulário
// O restante do seu formulário para editar o atendimento
return (
<div>
<h1>Editar Atendimento</h1>
{/* Renderize os campos do atendimento baseado nos dados carregados */}
<div>
<label>Código da Guia:</label>
<input
type="text"
value={atendimento.serviceInfo.guideCode}
onChange={(e) => {
setAtendimento((prev) => ({
...prev,
serviceInfo: {
...prev.serviceInfo,
guideCode: e.target.value
}
}));
}}
/>
</div>
{/* Adicione seus outros campos e lógica para edição */}
<button onClick={/* sua lógica para salvar as alterações */}>
Salvar Alterações
</button>
</div>
);
};
export default NovoAtendimento;
```
### 3. Configurar Roteamento
Assegure-se de que sua configuração de roteamento no seu arquivo principal (`App.tsx`) ou onde você gerencia as rotas está correta:
```javascript
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import CardAtendimento from './CardAtendimento';
import NovoAtendimento from './NovoAtendimento';
function App() {
return (
<Router>
<Switch>
<Route path="/atendimento" component={CardAtendimento} />
<Route path="/novo-atendimento/:id" component={NovoAtendimento} /> {/* Rotas com ID */}
</Switch>
</Router>
);
}
export default App;
```
### 4. Considerações Finais
- **Erro de carregamento**: Se a API falhar ou não retornar os dados, certifique-se de incluir uma mensagem adequada ou um tratamento de erro para informar o usuário.
- **Salvar Alterações**: Após editar os dados, você precisará de uma lógica para enviar as alterações para a sua API (geralmente via um `POST` ou `PUT`).
- **Loading State**: Considere adicionar estados de carregamento ao componente para melhorar a experiência do usuário.
- **Validação de Dados**: Se necessário, adicione lógica de validação para os campos do formulário antes de enviar as alterações.
Essa abordagem vai oferecer uma maneira clara e suficiente de gerenciar a edição de atendimentos na sua aplicação, utilizando o React Router e APIs. Se precisar de mais ajuda ou dicas específicas, fique à vontade para perguntar!2fae6b9201eeb461666e2224como ficaria, e no caso nao quero que coloque titulos de edições, apenas no botao de salvar pra ficar intuitivo que esta editando
import React, { useContext, useEffect } from "react";
import {
Route,
Routes,
Navigate,
useLocation,
useNavigate,
} from "react-router-dom";
import Login from "./components/Auth/Login";
import Cadastro from "./components/Auth/Cadastro";
import Dashboard from "./components/Dashboard/Dashboard";
import Home from "./components/Home/Home";
import Local from "./components/Local/Local";
import NovoLocal from "./components/Local/NovoLocal";
import Pacientes from "./components/Pacientes/Pacientes";
import NovoPaciente from "./components/Pacientes/NovoPaciente";
import Atendimentos from "./components/Atendimentos/Atendimentos";
import NovoAtendimento from "./components/Atendimentos/NovoAtendimento";
import Resumos from "./components/Resumos/Resumos";
import Analitico from "./components/Analitico/Analitico";
import LayoutPrincipal from "./components/LayoutPrincipal/LayoutPrincipal";
import { UserContext } from "./components/Auth/UserContext";
import { LocalProvider } from "./components/Local/LocalContext";
const PrivateRoute: React.FC<{ children: JSX.Element }> = ({ children }) => {
const context = useContext(UserContext);
const location = useLocation();
if (!context) {
throw new Error("UserContext must be used within a UserProvider");
}
const { usuario } = context;
useEffect(() => {
if (usuario) {
sessionStorage.setItem("lastPrivatePath", location.pathname);
}
}, [usuario, location.pathname]);
if (!usuario) {
// sessionStorage.setItem('redirectPath', location.pathname);
return <Navigate to="/login" />;
}
return children;
};
const PublicRoute: React.FC<{ children: JSX.Element }> = ({ children }) => {
const context = useContext(UserContext);
const { usuario } = context ?? {};
if (usuario) {
const lastPrivatePath =
sessionStorage.getItem("lastPrivatePath") || "/dashboard";
//return <Navigate to={lastPrivatePath} />;
}
return children;
};
const AppRoutes: React.FC = () => {
const navigate = useNavigate();
useEffect(() => {
const token = localStorage.getItem("token");
if (token) {
const lastPath = localStorage.getItem("lastPath") || "/dashboard";
navigate(lastPath);
} else {
//navigate("/login");
}
}, []);
return (
<LocalProvider>
<Routes>
<Route path="/" element={<LayoutPrincipal />}>
<Route
path="dashboard"
element={
<PrivateRoute>
<Dashboard />
</PrivateRoute>
}
/>
<Route path="home" element={<Home />} />
<Route
path="local"
element={
<PrivateRoute>
<Local />
</PrivateRoute>
}
/>
<Route
path="localNovo"
element={
<PrivateRoute>
<NovoLocal />
</PrivateRoute>
}
/>
<Route
path="pacientes"
element={
<PrivateRoute>
<Pacientes />
</PrivateRoute>
}
/>
<Route
path="pacientesNovo"
element={
<PrivateRoute>
<NovoPaciente />
</PrivateRoute>
}
/>
<Route
path="atendimentos"
element={
<PrivateRoute>
<Atendimentos />
</PrivateRoute>
}
/>
<Route
path="atendimentosNovo"
element={
<PrivateRoute>
<NovoAtendimento />
</PrivateRoute>
}
/>
<Route
path="resumos"
element={
<PrivateRoute>
<Resumos />
</PrivateRoute>
}
/>
<Route
path="analitico"
element={
<PrivateRoute>
<Analitico />
</PrivateRoute>
}
/>
<Route path="/" element={<Navigate to="/home" />} />
</Route>
<Route
path="/login"
element={
<PublicRoute>
<Login />
</PublicRoute>
}
/>
<Route
path="/cadastro"
element={
<PublicRoute>
<Cadastro />
</PublicRoute>
}
/>
</Routes>
</LocalProvider>
);
};
export default AppRoutes;
import EstiloNovoAtendimento from "./NovoAtendimento.module.css";
import React, { useState, useEffect } from "react";
import { useApi } from "../../lib/doctorApi";
import { AppointmentRequestDTO, ProcedureDTO } from "./types";
import DropdownSelect from "./DropdownSelect";
import CardProcedimento from "./CardProcedimento";
import { v4 as uuidv4 } from "uuid"; // Importa a função para gerar UUIDs
import { toMoney } from "../utils/FormatedData";
import Anexo from "../ui/Anexo";
const CoresInput = [
"#25AAE1", // Cor 1
"#8696BB", // Cor 2
"#39465F", // Cor 3
"#D56D98", // Cor 4
];
const NovoAtendimento: React.FC = () => {
const updateProcedimento = (index: number, novosDados: ProcedureDTO) => {
console.log(index, novosDados);
const cloneAtendimento = { ...atendimento };
cloneAtendimento.procedures[index] = novosDados;
setAtendimento(cloneAtendimento);
};
const [botaoSalvar, setBotaoSalvar] = useState("");
const enviarDadosAtendimento = async () => {
loading;
try {
const result = await api.post("appointments/create", atendimento);
if (result?.data?.success) {
if (
result.data.result?.id &&
result.data.result.id !== atendimento.id
) {
const cloneAtendimento = { ...atendimento };
cloneAtendimento.id = result.data.result.id;
setAtendimento(cloneAtendimento);
}
console.log("dados enviados", result);
}
result?.data?.messages;
console.log("atendimento criado comm sucesso", result);
setBotaoSalvar("Salvo");
} catch (e: any) {
e?.response?.data?.messages;
console.log("erro ao criar atendimento", e);
setBotaoSalvar("Salvar");
}
setLoading;
};
useEffect(() => {
setBotaoSalvar("Salvar");
const queryParams = new URLSearchParams(location.search);
const appointmentId = queryParams.get("id");
if (appointmentId) {
const fetchAtendimento = async () => {
try {
const response = await api.get(`appointments/get/${appointmentId}`);
const atendimento = response.data.result;
setAtendimento(atendimento);
} catch (error) {
console.error("Erro ao buscar paciente:", error);
}
};
fetchAtendimento();
}
}, []);
const handleAdicionarProcedimento = () => {
const novoProcedimento: ProcedureDTO = {
id: uuidv4(),
createdAt: new Date(),
updatedAt: new Date(),
cbhpmCode: "",
cbhpmName: "",
expectedValue: 0,
glossedValue: 0,
lostValue: 0,
paidValue: 0,
placeId: atendimento.related.place?.id || "",
payerId: atendimento.related.payer?.id || "",
patientId: atendimento.related.patient?.id || "",
statusOfActivity: "draft",
attachments: [],
};
const cloneAtendimento = { ...atendimento };
cloneAtendimento.procedures.push(novoProcedimento);
setAtendimento(cloneAtendimento);
setMostrarCard(true);
};
const handleExcluirProcedimento = (id: string) => {
// Filtra o array de procedimentos, mantendo apenas aqueles cujo id não coincide.
const novosProcedimentos = atendimento.procedures.filter(
(proc) => proc.id !== id
);
// Cria uma cópia do estado de atendimento e atualiza a lista de procedimentos
setAtendimento((prev) => ({
...prev,
procedures: novosProcedimentos, // Atualiza a lista de procedimentos
}));
// Opcional: Se existir alguma lógica que dependa da atualização da barra gráfica, você pode chamar:
};
// Atualiza o localStorage sempre que procedimentos mudar
const [mostrarCard, setMostrarCard] = useState(false); // Estado para expandir/recolher o Card
const [anexos, setAnexos] = useState<
{ id: string; fileName: string; extension: string }[]
>([]); // Estado para os arquivos anexados
const [loading, setLoading] = useState(false);
const api = useApi(); // `useApi` é tratado como estável
const [atendimento, setAtendimento] = useState<AppointmentRequestDTO>({
status: {
glossed: false,
lost: false,
received: false,
draft: false,
validated: false,
derived: false,
finished: false,
},
related: {
place: undefined,
payer: undefined,
patient: undefined,
},
paymentInfo: {
method: "healthInsurance",
info: {
totalSum: 0,
healthInsurance: {
cardNumber: "",
},
totalValues: {
expected: 0,
glossed: 0,
lost: 0,
paid: 0,
},
totalProcedures: {
expected: 0,
glossed: 0,
lost: 0,
paid: 0,
},
},
},
serviceInfo: {
guideCode: "",
date: "",
totalValue: 0,
},
procedures: [],
});
const atualizarValoresBarra = () => {
const totalProcedures = {
expected: 0,
glossed: 0,
lost: 0,
paid: 0,
};
const totalValue = {
expected: 0,
glossed: 0,
lost: 0,
paid: 0,
};
atendimento.procedures.forEach((proc) => {
if (proc.expectedValue > 0) {
totalProcedures.expected += 1; // Incrementa para expectedValue
totalValue.expected += proc.expectedValue;
}
if (proc.glossedValue > 0) {
totalProcedures.glossed += 1; // Incrementa para glossedValue
totalValue.glossed += proc.glossedValue;
}
if (proc.lostValue > 0) {
totalProcedures.lost += 1; // Incrementa para lostValue
totalValue.lost += proc.lostValue;
}
if (proc.paidValue > 0) {
totalProcedures.paid += 1; // Incrementa para paidValue
totalValue.paid += proc.paidValue;
}
});
const cloneAtendimento = { ...atendimento };
cloneAtendimento.paymentInfo.info.totalProcedures = totalProcedures;
cloneAtendimento.paymentInfo.info.totalValues = totalValue;
cloneAtendimento.paymentInfo.info.totalSum =
cloneAtendimento.paymentInfo.info.totalValues.expected +
cloneAtendimento.paymentInfo.info.totalValues.glossed +
cloneAtendimento.paymentInfo.info.totalValues.lost +
cloneAtendimento.paymentInfo.info.totalValues.paid;
setAtendimento(cloneAtendimento); // Atualiza o estado dos valores da barra
};
useEffect(() => {
atualizarValoresBarra();
}, [JSON.stringify(atendimento.procedures)]);
// Função que alterna entre expandir e recolher
const alternarCard = () => {
setMostrarCard(!mostrarCard);
};
return (
<div>
<label className={EstiloNovoAtendimento.labeltitle}>
Cadastro de Atendimento
</label>
<form>
<div className={EstiloNovoAtendimento.divValores}>
<div className={EstiloNovoAtendimento.inputValores}>
<label className={EstiloNovoAtendimento.total}>Total:</label>
{[
atendimento.paymentInfo.info.totalValues.expected,
atendimento.paymentInfo.info.totalValues.glossed,
atendimento.paymentInfo.info.totalValues.lost,
atendimento.paymentInfo.info.totalValues.paid,
].map((valor, index) => (
<div key={index}>
<span
style={{
color: CoresInput[index],
fontSize: "14px",
marginRight: "2px",
}}
>
R$
</span>
<input
key={index}
type="number"
value={valor.toFixed(2)}
placeholder="R$ 0,00"
style={{ color: CoresInput[index] }}
readOnly
/>
</div>
))}
</div>
<div className={EstiloNovoAtendimento.divBarraGrafico}>
<label className={EstiloNovoAtendimento.labelTotal}>
R$ {toMoney(atendimento.paymentInfo.info.totalSum)}
{/* Aqui já usará o total atualizado */}
</label>
<div className={EstiloNovoAtendimento.graficoRepresentativo}>
<div className={EstiloNovoAtendimento.barraFixa}>
{[
atendimento.paymentInfo.info.totalValues.expected,
atendimento.paymentInfo.info.totalValues.glossed,
atendimento.paymentInfo.info.totalValues.lost,
atendimento.paymentInfo.info.totalValues.paid,
].map((valor, index) => (
<div
key={`grafico-${index}`}
style={{
backgroundColor: CoresInput[index],
width:
atendimento.paymentInfo.info.totalSum > 0
? `${
(valor / atendimento.paymentInfo.info.totalSum) *
100
}%`
: `0%`,
height: "100%",
}}
/>
))}
</div>
</div>
</div>
</div>
<div className={EstiloNovoAtendimento.container}>
<div className={EstiloNovoAtendimento.modalidade}>
<label>Modalidade:</label>
<div className={EstiloNovoAtendimento.divMargin}>
<input
className={EstiloNovoAtendimento.radio}
type="radio"
id="convenio"
name="modalidade"
value="convenio"
onChange={() => {
setAtendimento((prev) => ({
...prev,
paymentInfo: {
...prev.paymentInfo,
method: "healthInsurance", // Ou qualquer método que você queira usar
},
}));
}}
/>
<label
htmlFor="convenio"
className={EstiloNovoAtendimento.labelModalidade}
>
Convênio
</label>
<input
className={EstiloNovoAtendimento.radio}
type="radio"
id="particular"
name="modalidade"
value="particular"
onChange={() => {
setAtendimento((prev) => ({
...prev,
paymentInfo: {
...prev.paymentInfo,
method: "private", // Atualize para "particular"
},
}));
}}
/>
<label
htmlFor="particular"
className={EstiloNovoAtendimento.labelModalidade}
>
Particular
</label>
<input
className={EstiloNovoAtendimento.radio}
type="radio"
id="plantao"
name="modalidade"
value="plantao"
onChange={() => {
setAtendimento((prev) => ({
...prev,
paymentInfo: {
...prev.paymentInfo,
method: "onDuty", // Atualize para "plantao"
},
}));
}}
/>
<label
htmlFor="plantao"
className={EstiloNovoAtendimento.labelModalidade}
>
Plantão
</label>
</div>
</div>
<DropdownSelect
endpoint="places/find?skip=0&limit=2000&payer=true" // URL do endpoint
parseData={(data) =>
data.result.list.map((local: any) => ({
id: local.id,
name: local.name,
}))
} // Função que transforma os dados da API no formato { id, name }
onSelect={(selectedItem) => {
// Atualizar o estado de atendimento para incluir o payer
setAtendimento((prev) => ({
...prev,
related: {
...prev.related,
payer: { id: selectedItem.id, name: selectedItem.name }, // Assumindo que você quer armazenar um objeto { id, name }
},
}));
}} // Define o item selecionado no estado
value={atendimento.related.payer?.id || ""} // Valor atual do dropdown
label="Fonte Pagadora:" // Rótulo a ser exibido
/>
</div>
<div className={EstiloNovoAtendimento.container}>
{/* TODO: O Componente paciente precisa ter um campo de busca e buscar na api do backend com limite de 10 pacientes */}
<DropdownSelect
endpoint="patients/find?skip=0&limit=2000" // URL do endpoint
parseData={(data) =>
data.result.list.map((item: any) => ({
id: item.id,
name: item.name,
}))
} // Função que transforma os dados da API no formato { id, name }
onSelect={(selectedItem) => {
// Atualizar o estado de atendimento para incluir o payer
setAtendimento((prev) => ({
...prev,
related: {
...prev.related,
patient: { id: selectedItem.id, name: selectedItem.name }, // Assumindo que você quer armazenar um objeto { id, name }
},
}));
}} // Define o item selecionado no estado
value={atendimento.related.patient?.id || ""} // Valor atual do dropdown
label="Paciente:" // Rótulo a ser exibido
/>
<DropdownSelect
endpoint="places/find?skip=0&limit=2000&place=true" // URL do endpoint para buscar locais de atendimento
parseData={(data) =>
data.result.list.map((local: any) => ({
id: local.id,
name: local.name,
}))
} // Função para transformar os dados da API no formato { id, name }
onSelect={(selectedItem) => {
// Atualizar o estado de atendimento para incluir o payer
setAtendimento((prev) => ({
...prev,
related: {
...prev.related,
place: { id: selectedItem.id, name: selectedItem.name }, // Assumindo que você quer armazenar um objeto { id, name }
},
}));
}} // Callback para atualizar o formulário com o local selecionado
value={atendimento.related.place?.id || ""} // ID do item selecionado
label="Local de Atendimento:" // Rótulo exibido
/>
</div>
<div className={EstiloNovoAtendimento.container}>
<div className={EstiloNovoAtendimento.organizador}>
<span>Código da guia(opcional)</span>
<input
className={EstiloNovoAtendimento.input300}
type="text"
name="codigo"
placeholder="Digite"
value={atendimento.serviceInfo.guideCode}
onChange={(e) => {
const codigo = e.target.value;
// Atualiza o estado de atendimento com o código da guia
setAtendimento((prev) => ({
...prev,
serviceInfo: {
...prev.serviceInfo,
guideCode: codigo, // Atualiza o guideCode com o valor do input
},
}));
}}
/>
</div>
<div className={EstiloNovoAtendimento.organizador}>
<span>Data</span>
<input
className={EstiloNovoAtendimento.inputData}
type="date"
name="data"
placeholder="dd/mm/yyyy"
value={atendimento.createdAt?.toISOString()}
onChange={(e) => {
const data = e.target.value;
setAtendimento((prev) => ({
...prev,
serviceInfo: {
...prev.serviceInfo,
date: data,
},
}));
}}
/>
</div>
</div>
</form>
{/* deveria ficar aqui */}
<div className={EstiloNovoAtendimento.divbutton}>
<button
type="button" // tipo "button" para evitar o envio do formulário
onClick={handleAdicionarProcedimento} // Chama a função ao clicar
className={EstiloNovoAtendimento.buttonProcedimento}
>
Adicionar Procedimento
</button>
</div>
{/* Segunda barra gráfica com funcionalidade ajustada */}
<div className={EstiloNovoAtendimento.divValores2}>
<div className={EstiloNovoAtendimento.inputProcedimentos}>
{[
atendimento.paymentInfo.info.totalProcedures.expected,
atendimento.paymentInfo.info.totalProcedures.glossed,
atendimento.paymentInfo.info.totalProcedures.lost,
atendimento.paymentInfo.info.totalProcedures.paid,
].map((valor, index) => (
<input
key={index}
type="number"
value={valor.toFixed(0)} // Mostra a contagem
placeholder="0"
readOnly // Barra apenas visual, não editável
style={{ color: CoresInput[index] }} // Cor correspondente à respectiva
/>
))}
</div>
<div className={EstiloNovoAtendimento.divBarraGrafico}>
<div className={EstiloNovoAtendimento.divTotal}>
<img
src="/procedimento.png"
alt=""
className={EstiloNovoAtendimento.icone}
/>
<label className={EstiloNovoAtendimento.labelProcedimento}>
<label>{atendimento.procedures.length}</label> Procedimento
</label>
</div>
<div className={EstiloNovoAtendimento.graficoRepresentativo}>
<div className={EstiloNovoAtendimento.barraFixa}>
{[
atendimento.paymentInfo.info.totalProcedures.expected,
atendimento.paymentInfo.info.totalProcedures.glossed,
atendimento.paymentInfo.info.totalProcedures.lost,
atendimento.paymentInfo.info.totalProcedures.paid,
].map((valor, index) => (
<div
key={`grafico-segunda-${index}`}
style={{
backgroundColor: CoresInput[index],
width: `${(valor / atendimento.procedures.length) * 100}%`, // Ajuste a largura da barra conforme a contagem
height: "100%",
}}
/>
))}
</div>
</div>
{/* Botão de expandir/recolher */}
<div
className={EstiloNovoAtendimento.expandirProcedimentos}
onClick={alternarCard}
>
<img
src="/setaBaixo.png"
alt="Expandir/recolher"
className={EstiloNovoAtendimento.iconSeta}
/>
<label className={EstiloNovoAtendimento.labelExpandir}>
{mostrarCard ? "Recolher" : "Expandir"}
</label>
</div>
</div>
</div>
{/* Renderiza o Card apenas se mostrarCard for true */}
{mostrarCard && (
<>
{/* Renderiza os procedimentos adicionados */}
{atendimento.procedures.map((proc, index) => (
<CardProcedimento
key={"procedure_" + proc.id}
index={index} // Usando o índice corretamente
procedure={proc}
updateProcedimento={updateProcedimento}
handleExcluir={handleExcluirProcedimento}
/>
))}
</>
)}
<Anexo
attachments={atendimento.attachments || []}
setAttachments={(novosAnexos) => {
setAtendimento((prev) => ({
...prev,
attachments: novosAnexos,
}));
}}
/>
<div className={EstiloNovoAtendimento.divbutton}>
<button
className={EstiloNovoAtendimento.buttonSalvar}
disabled={loading}
onClick={enviarDadosAtendimento}
>
{loading ? botaoSalvar : "Salvar"}
</button>
</div>
</div>
);
};
export default NovoAtendimento;
// CardAtendimento.tsx
import React, { useState } from "react";
import styles from "./Atendimentos.module.css";
import CardProcedimento from "./CardProcedimento";
import { AppointmentRequestDTO, ProcedureDTO } from "./types";
import { formatMesAno, toMoney } from "../utils/FormatedData";
import Anexo from "../ui/Anexo";
const CoresInput = [
"#25AAE1", // Cor 1
"#8696BB", // Cor 2
"#39465F", // Cor 3
"#D56D98", // Cor 4
];
// Definindo os tipos para as props do componente
interface CardAtendimentoProps {
appointment: AppointmentRequestDTO;
alternarCard: () => void; // Função sem parâmetros que não retorna nada
}
const CardAtendimento: React.FC<CardAtendimentoProps> = ({
appointment,
}) => {
const [mostrarCard, setMostrarCard] = useState(false); // Estado para expandir/recolher o Card
const alternaCard = () => {
setMostrarCard(!mostrarCard);
};
const handleExcluirProcedimento = (id: string) => {
// Filtra o array de procedimentos, mantendo apenas aqueles cujo id não coincide.
const novosProcedimentos = atendimento.procedures.filter(
(proc) => proc.id !== id
);
// Cria uma cópia do estado de atendimento e atualiza a lista de procedimentos
setAtendimento((prev) => ({
...prev,
procedures: novosProcedimentos, // Atualiza a lista de procedimentos
}));
// Opcional: Se existir alguma lógica que dependa da atualização da barra gráfica, você pode chamar:
};
const updateProcedimento = (index: number, novosDados: ProcedureDTO) => {
console.log(index, novosDados);
const cloneAtendimento = { ...atendimento };
cloneAtendimento.procedures[index] = novosDados;
setAtendimento(cloneAtendimento);
};
const [atendimento, setAtendimento] = useState<AppointmentRequestDTO>({
status: {
glossed: false,
lost: false,
received: false,
draft: false,
validated: false,
derived: false,
finished: false,
},
related: {
place: undefined,
payer: undefined,
patient: undefined,
},
paymentInfo: {
method: "healthInsurance",
info: {
totalSum: 0,
healthInsurance: {
cardNumber: "",
},
totalValues: {
expected: 0,
glossed: 0,
lost: 0,
paid: 0,
},
totalProcedures: {
expected: 0,
glossed: 0,
lost: 0,
paid: 0,
},
},
},
serviceInfo: {
guideCode: "",
date: "",
totalValue: 0,
},
procedures: [],
});
return (
<div className={styles.CardPai}>
<div className={styles.CardTopPai}>
<div className={styles.buttonCard}>
<button>
<img src="/lapisEditor.png" alt="Editar" className={styles.icon} />
</button>
</div>
</div>
<div className={styles.divDoCardPai}>
{/* barra */}
<div className={styles.divValores}>
<div className={styles.inputValores}>
<label className={styles.total}>Total:</label>
{[
appointment.paymentInfo.info.totalValues.expected,
appointment.paymentInfo.info.totalValues.glossed,
appointment.paymentInfo.info.totalValues.lost,
appointment.paymentInfo.info.totalValues.paid,
].map((valor, index) => (
<div key={index}>
<span
style={{
color: CoresInput[index],
fontSize: "14px",
marginRight: "2px",
}}
>
R$
</span>
<input
key={index}
type="number"
value={valor.toFixed(2)}
placeholder="R$ 0,00"
style={{ color: CoresInput[index] }}
readOnly
/>
</div>
))}
</div>
<div className={styles.divBarraGrafico}>
<label className={styles.labelTotal}>
R$ {toMoney(appointment.paymentInfo.info.totalSum)}
</label>
<div className={styles.graficoRepresentativo}>
<div className={styles.barraFixa}>
{[
appointment.paymentInfo.info.totalValues.expected,
appointment.paymentInfo.info.totalValues.glossed,
appointment.paymentInfo.info.totalValues.lost,
appointment.paymentInfo.info.totalValues.paid,
].map((valor, index) => (
<div
key={`grafico-${index}`}
style={{
backgroundColor: CoresInput[index],
width:
appointment.paymentInfo.info.totalSum > 0
? `${
(valor / appointment.paymentInfo.info.totalSum) *
100
}%`
: `0%`,
height: "100%",
}}
/>
))}
</div>
</div>
</div>
</div>
</div>
<div className={styles.divInformacoes}>
<div className={styles.divDados}>
<label className={styles.labelData}>
{appointment.serviceInfo.date}
</label>
<label className={styles.labelPaciente}>
{appointment.related.patient?.name}
</label>
<label className={styles.labelCodigo}>
{appointment.serviceInfo.guideCode}
</label>
</div>
<div className={styles.divRow}>
<label className={styles.labelLocais}>
<img src="cifrao.png" className={styles.icons} alt="" />
modalidade: {appointment.paymentInfo.method}
</label>
<label className={styles.labelLocais}>
<img src="cifrao.png" className={styles.icons} alt="" />
Fonte Pagadora:
{appointment.related.payer?.name}
{/* fontepagadora */}
</label>
</div>
<div className={styles.divRowDados}>
<label className={styles.labelLocais}>
<img src="local-icon.png" alt="" className={styles.icons} />
Local:
{appointment.related.place?.name}
</label>
<img src="Completo.png" alt="" className={styles.imgCompleto} />
</div>
<div className={styles.divBarra} />
</div>
{/* Segunda barra gráfica com funcionalidade ajustada */}
<div className={styles.divValores2}>
<div className={styles.inputProcedimentos}>
{[
appointment.paymentInfo.info.totalProcedures.expected,
appointment.paymentInfo.info.totalProcedures.glossed,
appointment.paymentInfo.info.totalProcedures.lost,
appointment.paymentInfo.info.totalProcedures.paid,
].map((valor, index) => (
<input
key={index}
type="number"
value={valor.toFixed(0)} // Mostra a contagem
placeholder="0"
readOnly // Barra apenas visual, não editável
style={{ color: CoresInput[index] }} // Cor correspondente à respectiva
/>
))}
</div>
<div className={styles.divBarraGrafico}>
<div className={styles.divTotal}>
<img src="/procedimento.png" alt="" className={styles.icone} />
<label className={styles.labelProcedimento}>
<label>{appointment.procedures.length}</label> Procedimento
</label>
</div>
<div className={styles.graficoRepresentativo}>
<div className={styles.barraFixa}>
{[
appointment.paymentInfo.info.totalProcedures.expected,
appointment.paymentInfo.info.totalProcedures.glossed,
appointment.paymentInfo.info.totalProcedures.lost,
appointment.paymentInfo.info.totalProcedures.paid,
].map((valor, index) => (
<div
key={`grafico-segunda-${index}`}
style={{
backgroundColor: CoresInput[index],
width: `${(valor / appointment.procedures.length) * 100}%`, // Ajuste a largura da barra conforme a contagem
height: "100%",
}}
/>
))}
</div>
</div>
{/* Botão de expandir/recolher */}
<div className={styles.expandirProcedimentos} onClick={alternaCard}>
<img
src="/setaBaixo.png"
alt="Expandir/recolher"
className={styles.iconSeta}
/>
<label className={styles.labelExpandir}>
{mostrarCard ? "Recolher" : "Expandir"}
</label>
</div>
</div>
</div>
<div className={styles.centro}>
{/* Renderiza o Card apenas se mostrarCard for true */}
{mostrarCard && (
<>
{/* Renderiza os procedimentos adicionados */}
{appointment.procedures.map((proc, index) => (
<CardProcedimento
key={"procedure_" + proc.id}
index={index} // Usando o índice corretamente
procedure={proc}
updateProcedimento={updateProcedimento}
handleExcluir={handleExcluirProcedimento}
/>
))}{" "}
</>
)}
</div>
<Anexo
attachments={atendimento.attachments || []}
setAttachments={(novosAnexos) => {
setAtendimento((prev) => ({
...prev,
attachments: novosAnexos,
}));
}}
/>
<div className={styles.space} />
<div className={styles.CardBottonPai}></div>
</div>
);
};
export default CardAtendimento;
Para implementar a tela de edição do "Novo Atendimento" sem títulos de edição e apenas ter um botão de "Salvar" para indicar que o formulário está sendo editado, você pode simplificar o código. O objetivo é garantir que a interface permaneça intuitiva e focada na funcionalidade. Vamos revisar e ajustar a implementação.
### 1. Ajustar o Componente `NovoAtendimento`
Removeremos o título de edição da interface e manteremos apenas os campos necessários e o botão de "Salvar". Também vamos garantir que a lógica para buscar os dados da API esteja correta e que não haja confusão ao iniciar o procedimento de edição.
```javascript
import EstiloNovoAtendimento from "./NovoAtendimento.module.css";
import React, { useState, useEffect } from "react";
import { useApi } from "../../lib/doctorApi";
import { AppointmentRequestDTO, ProcedureDTO } from "./types";
import DropdownSelect from "./DropdownSelect";
import CardProcedimento from "./CardProcedimento";
import { v4 as uuidv4 } from "uuid";
import { toMoney } from "../utils/FormatedData";
import Anexo from "../ui/Anexo";
// Cores de entrada para barras gráficas
const CoresInput = [
"#25AAE1",
"#8696BB",
"#39465F",
"#D56D98",
];
const NovoAtendimento: React.FC = () => {
const api = useApi(); // Hook para comunicação com a API
const [atendimento, setAtendimento] = useState<AppointmentRequestDTO | null>(null);
const [loading, setLoading] = useState(false);
const { id } = useParams<{ id: string }>(); // Pega o ID da rota
useEffect(() => {
const fetchAtendimento = async () => {
setLoading(true);
try {
const response = await api.get(`appointments/get/${id}`);
setAtendimento(response.data.result);
} catch (error) {
console.error("Erro ao buscar atendimento:", error);
} finally {
setLoading(false);
}
};
fetchAtendimento();
}, [id, api]);
const enviarDadosAtendimento = async () => {
setLoading(true);
try {
const result = await api.put(`appointments/update/${id}`, atendimento);
if (result?.data?.success) {
console.log("Atendimento atualizado com sucesso:", result);
} else {
console.log("Falha ao atualizar o atendimento.");
}
} catch (error) {
console.error("Erro ao atualizar atendimento:", error);
} finally {
setLoading(false);
}
};
if (loading) return <div>Carregando...</div>; // Loader simples enquanto carrega os dados
return (
<div>
<form>
<div className={EstiloNovoAtendimento.divValores}>
<div className={EstiloNovoAtendimento.inputValores}>
<label className={EstiloNovoAtendimento.total}>Total:</label>
{[
atendimento?.paymentInfo.info.totalValues.expected,
atendimento?.paymentInfo.info.totalValues.glossed,
atendimento?.paymentInfo.info.totalValues.lost,
atendimento?.paymentInfo.info.totalValues.paid,
].map((valor, index) => (
<div key={index}>
<span style={{ color: CoresInput[index], fontSize: "14px", marginRight: "2px" }}>
R$
</span>
<input
type="number"
value={valor.toFixed(2)}
readOnly
style={{ color: CoresInput[index] }}
/>
</div>
))}
</div>
<div className={EstiloNovoAtendimento.divBarraGrafico}>
<label className={EstiloNovoAtendimento.labelTotal}>
R$ {toMoney(atendimento?.paymentInfo.info.totalSum)}
</label>
{/* Gráfico vazio se não houver dados */}
<div className={EstiloNovoAtendimento.graficoRepresentativo}>
<div className={EstiloNovoAtendimento.barraFixa}>
{[
atendimento?.paymentInfo.info.totalValues.expected,
atendimento?.paymentInfo.info.totalValues.glossed,
atendimento?.paymentInfo.info.totalValues.lost,
atendimento?.paymentInfo.info.totalValues.paid,
].map((valor, index) => (
<div
key={`grafico-${index}`}
style={{
backgroundColor: CoresInput[index],
width: atendimento?.paymentInfo.info.totalSum > 0
? `${(valor / atendimento?.paymentInfo.info.totalSum) * 100}%`
: `0%`,
height: "100%",
}}
/>
))}
</div>
</div>
</div>
</div>
{/* Renderize outros campos de formulário e componentes DropdownSelect como necessário */}
<DropdownSelect
endpoint="places/find?skip=0&limit=2000&payer=true"
parseData={(data) => data.result.list.map((local: any) => ({ id: local.id, name: local.name }))}
// outros props necessários...
/>
{/* Adicione outros DropdownSelect e inputs aqui */}
</form>
<div className={EstiloNovoAtendimento.divbutton}>
<button
className={EstiloNovoAtendimento.buttonSalvar}
disabled={loading}
onClick={enviarDadosAtendimento}
>
{loading ? "Salvando..." : "Salvar"}
</button>
</div>
</div>
);
};
export default NovoAtendimento;
```
### 2. Ajustar Componente `CardAtendimento`
No `CardAtendimento`, você já configurou para direcionar o usuário para o `NovoAtendimento` ao clicar no botão de editar. Certifique-se de que essa lógica está intacta.
```javascript
import React, { useState } from "react";
import { useHistory } from "react-router-dom";
import styles from "./Atendimentos.module.css";
import { AppointmentRequestDTO } from "./types";
interface CardAtendimentoProps {
appointment: AppointmentRequestDTO;
}
const CardAtendimento: React.FC<CardAtendimentoProps> = ({ appointment }) => {
const history = useHistory();
const handleEdit = () => {
history.push(`/novo-atendimento/${appointment.id}`);
};
return (
<div className={styles.CardPai}>
<div className={styles.CardTopPai}>
<div className={styles.buttonCard}>
<button onClick={handleEdit}>
<img src="/lapisEditor.png" alt="Editar" className={styles.icon} />
</button>
</div>
</div>
{/* Renderizar outras informações do atendimento */}
</div>
);
};
export default CardAtendimento;
```
### Considerações Finais
- **Sem Títulos de Edição**: Como solicitado, você não verá títulos de edição, apenas o formulário em si, com um botão "Salvar" que é claro no que faz.
- **Usabilidade**: Assegure-se de que o botão "Salvar" esteja estilizado para destacar sua funcionalidade.
- **Consulta e Edição Eficiente**: A lógica para carregar os dados e atualizar permanece clara e concisa.
- **Tratamento de Erros**: Seria útil implementar mensagens de erro mais user-friendly para auxiliar o usuário em caso de falhas.
Esse ajuste garante que o fluxo de edição é intuitivo e fácil de usar, focando apenas na funcionalidade necessária. Se você tiver mais perguntas ou precisar de mais ajustes, sinta-se à vontade para perguntar!8624c3c1f417b9f3fbeffd96montre para mim apenas o que foi adicionado ou alterado em cada componente
Claro! Vou destacar apenas as partes que foram adicionadas ou alteradas em cada componente, sem mostrar o código completo e com foco nas seções que realmente mudaram.
### Alterações no Componente `NovoAtendimento`
1. **Remoção do Título de Edição**:
Removi a linha do título de "Cadastro de Atendimento".
2. **Lógica para Buscar Atendimento**:
Adicionei `useParams` para capturar o ID do atendimento e a lógica para buscar os dados do atendimento no `useEffect`.
```javascript
import { useParams } from 'react-router-dom';
...
const NovoAtendimento: React.FC = () => {
const { id } = useParams<{ id: string }>(); // Captura o ID da rota
...
};
```
3. **Implementação da Lógica de Edição**:
A lógica para carregar os dados do atendimento agora utiliza a API para buscar os dados diretamente pelo ID.
```javascript
useEffect(() => {
const fetchAtendimento = async () => {
setLoading(true);
try {
const response = await api.get(`appointments/get/${id}`);
setAtendimento(response.data.result);
} catch (error) {
console.error("Erro ao buscar atendimento:", error);
} finally {
setLoading(false);
}
};
fetchAtendimento();
}, [id, api]); // Adiciona 'id' e 'api' como dependências
```
4. **Remoção do código de título e adaptação da função de envio**:
O botão "Salvar" foi mantido e adaptado para a lógica de atualização (PUT).
```javascript
<button
className={EstiloNovoAtendimento.buttonSalvar}
disabled={loading}
onClick={enviarDadosAtendimento}
>
{loading ? "Salvando..." : "Salvar"}
</button>
```
### Alterações no Componente `CardAtendimento`
1. **Altera a Função do Botão de Editar**:
A função `handleEdit` agora direciona para a página de edição passando o ID do atendimento na URL.
```javascript
import { useHistory } from "react-router-dom";
const CardAtendimento: React.FC<CardAtendimentoProps> = ({ appointment }) => {
const history = useHistory();
const handleEdit = () => {
history.push(`/novo-atendimento/${appointment.id}`); // Direciona com o ID
};
};
```
2. **Mudança do Botão de Editar**:
O botão que chama a função `handleEdit` foi já foi ajustado.
```javascript
<button onClick={handleEdit}>
<img src="/lapisEditor.png" alt="Editar" className={styles.icon} />
</button>
```
### Resumo das Alterações
- **`NovoAtendimento.tsx`**:
- Remoção do título de edição.
- Implementação da captura do ID para busca do atendimento.
- Botão "Salvar" adequado para a função de edição.
- **`CardAtendimento.tsx`**:
- Implementação da lógica de navegação para a página de edição com o ID do atendimento.
Essas são as principais alterações e adições em cada componente. Se precisar de mais detalhes ou ajustes específicos, é só avisar!de6483496233708d8c1996bdO módulo '"react-router-dom"' não tem nenhum membro exportado 'useHistory'.ts(2305) import useHistory falta alterações nas rotas?
A partir da versão 6 do `react-router-dom`, o hook `useHistory` foi substituído por `useNavigate`. Portanto, se você estiver usando essa versão mais recente, precisará fazer a alteração para que seu código funcione corretamente.
### Alterações no Componente `CardAtendimento`
**Substituir `useHistory` por `useNavigate`**:
1. **Importação**:
A primeira coisa que você precisa fazer é alterar a importação de `useHistory` para `useNavigate`:
```javascript
import { useNavigate } from "react-router-dom";
```
2. **Modificação da lógica de navegação**:
Troque a lógica de `handleEdit` para utilizar `useNavigate`:
```javascript
const CardAtendimento: React.FC<CardAtendimentoProps> = ({ appointment }) => {
const navigate = useNavigate(); // Use useNavigate em vez de useHistory.
const handleEdit = () => {
navigate(`/novo-atendimento/${appointment.id}`); // Usar navigate para redirecionar.
};
};
```
### Verificação das Rotas
As rotas no seu componente `AppRoutes` estão essencialmente corretas para o uso do `react-router-dom`. Certifique-se de que a rota para `NovoAtendimento` aceita um parâmetro de ID da seguinte maneira:
```javascript
<Route path="/novo-atendimento/:id" element={<NovoAtendimento />} />
```
### Resumo das Alterações
1. **Importação**:
- Altere a importação de `useHistory` para `useNavigate`.
2. **Navegação**:
- Altere `history.push` para `navigate` para realizar a navegação.
### Exemplo Completo da Modificação no `CardAtendimento`
Aqui está como ficaria a parte relevante do `CardAtendimento`:
```javascript
import React, { useState } from "react";
import { useNavigate } from "react-router-dom"; // Altere para useNavigate
import styles from "./Atendimentos.module.css";
import { AppointmentRequestDTO } from "./types";
interface CardAtendimentoProps {
appointment: AppointmentRequestDTO;
}
const CardAtendimento: React.FC<CardAtendimentoProps> = ({ appointment }) => {
const navigate = useNavigate(); // Usar useNavigate
const handleEdit = () => {
navigate(`/novo-atendimento/${appointment.id}`); // Usar navigate
};
return (
<div className={styles.CardPai}>
<div className={styles.CardTopPai}>
<div className={styles.buttonCard}>
<button onClick={handleEdit}> {/* Alterado para chamar handleEdit */}
<img src="/lapisEditor.png" alt="Editar" className={styles.icon} />
</button>
</div>
</div>
{/* Renderizar outras informações do atendimento */}
</div>
);
};
export default CardAtendimento;
```
### Conclusão
Se você seguir estas instruções, deve resolver o erro que você encontrou e levar a um funcionamento adequado da navegação no seu aplicativo React. Se você tiver mais perguntas ou se ainda estiver enfrentando problemas, não hesite em perguntar!b6347e623ef9051e0e890104matched location "/novo-atendimento/aae45e38-1cf8-4eec-aa41-4f6cc569c0af"
fiz algo errado?
import React, { useContext, useEffect } from "react";
import {
Route,
Routes,
Navigate,
useLocation,
useNavigate,
} from "react-router-dom";
import Login from "./components/Auth/Login";
import Cadastro from "./components/Auth/Cadastro";
import Dashboard from "./components/Dashboard/Dashboard";
import Home from "./components/Home/Home";
import Local from "./components/Local/Local";
import NovoLocal from "./components/Local/NovoLocal";
import Pacientes from "./components/Pacientes/Pacientes";
import NovoPaciente from "./components/Pacientes/NovoPaciente";
import Atendimentos from "./components/Atendimentos/Atendimentos";
import NovoAtendimento from "./components/Atendimentos/NovoAtendimento";
import Resumos from "./components/Resumos/Resumos";
import Analitico from "./components/Analitico/Analitico";
import LayoutPrincipal from "./components/LayoutPrincipal/LayoutPrincipal";
import { UserContext } from "./components/Auth/UserContext";
import { LocalProvider } from "./components/Local/LocalContext";
const PrivateRoute: React.FC<{ children: JSX.Element }> = ({ children }) => {
const context = useContext(UserContext);
const location = useLocation();
if (!context) {
throw new Error("UserContext must be used within a UserProvider");
}
const { usuario } = context;
useEffect(() => {
if (usuario) {
sessionStorage.setItem("lastPrivatePath", location.pathname);
}
}, [usuario, location.pathname]);
if (!usuario) {
// sessionStorage.setItem('redirectPath', location.pathname);
return <Navigate to="/login" />;
}
return children;
};
const PublicRoute: React.FC<{ children: JSX.Element }> = ({ children }) => {
const context = useContext(UserContext);
const { usuario } = context ?? {};
if (usuario) {
const lastPrivatePath =
sessionStorage.getItem("lastPrivatePath") || "/dashboard";
//return <Navigate to={lastPrivatePath} />;
}
return children;
};
const AppRoutes: React.FC = () => {
const navigate = useNavigate();
useEffect(() => {
const token = localStorage.getItem("token");
if (token) {
const lastPath = localStorage.getItem("lastPath") || "/dashboard";
navigate(lastPath);
} else {
//navigate("/login");
}
}, []);
return (
<LocalProvider>
<Routes>
<Route path="/" element={<LayoutPrincipal />}>
<Route
path="dashboard"
element={
<PrivateRoute>
<Dashboard />
</PrivateRoute>
}
/>
<Route path="home" element={<Home />} />
<Route
path="local"
element={
<PrivateRoute>
<Local />
</PrivateRoute>
}
/>
<Route
path="localNovo"
element={
<PrivateRoute>
<NovoLocal />
</PrivateRoute>
}
/>
<Route
path="pacientes"
element={
<PrivateRoute>
<Pacientes />
</PrivateRoute>
}
/>
<Route
path="pacientesNovo"
element={
<PrivateRoute>
<NovoPaciente />
</PrivateRoute>
}
/>
<Route
path="atendimentos"
element={
<PrivateRoute>
<Atendimentos />
</PrivateRoute>
}
/>
<Route
path="atendimentosNovo:id"
element={
<PrivateRoute>
<NovoAtendimento />
</PrivateRoute>
}
/>
<Route
path="resumos"
element={
<PrivateRoute>
<Resumos />
</PrivateRoute>
}
/>
<Route
path="analitico"
element={
<PrivateRoute>
<Analitico />
</PrivateRoute>
}
/>
<Route path="/" element={<Navigate to="/home" />} />
</Route>
<Route
path="/login"
element={
<PublicRoute>
<Login />
</PublicRoute>
}
/>
<Route
path="/cadastro"
element={
<PublicRoute>
<Cadastro />
</PublicRoute>
}
/>
</Routes>
</LocalProvider>
);
};
export default AppRoutes;
O erro que você está enfrentando parece estar relacionado à forma como a rota para `NovoAtendimento` está definida. Ao definir o parâmetro ID, você não adicionou uma barra (`/`) entre o caminho da rota e o parâmetro.
### Problema na Rota
Linhas específicas no seu componente `AppRoutes` faltam uma barra (`/`) antes do parâmetro `id`. Você deve definir a rota para incluir a barra adequada.
**Atualmente:**
```javascript
<Route
path="atendimentosNovo:id" // Erro aqui, falta a barra antes do ":id"
element={
<PrivateRoute>
<NovoAtendimento />
</PrivateRoute>
}
/>
```
**Corrigido:**
```javascript
<Route
path="atendimentosNovo/:id" // Corrigido para incluir a barra
element={
<PrivateRoute>
<NovoAtendimento />
</PrivateRoute>
}
/>
```
### Resumo das Alterações Necessárias
1. **Adicionar a Barra no Caminho**:
- Altere a linha onde você define a rota para `NovoAtendimento` de `"atendimentosNovo:id"` para `"atendimentosNovo/:id"`.
### Exemplo Completo da Rota Corrigida
Aqui está a parte modificada do `AppRoutes`:
```javascript
<Route
path="atendimentosNovo/:id" // Corrigido para incluir a barra
element={
<PrivateRoute>
<NovoAtendimento />
</PrivateRoute>
}
/>
```
### Conclusão
Com essa alteração, a aplicação deve conseguir corresponder corretamente a rota `/novo-atendimento/ID` que você está tentando acessar. Depois de fazer essa correção, teste novamente sua aplicação. Se você continuar enfrentando problemas ou se tiver outras perguntas, sinta-se à vontade para perguntar!