From 43d72773bccec5b69a6cc3181c82be358d189cf7 Mon Sep 17 00:00:00 2001 From: Alicelspires Date: Sun, 10 May 2026 18:35:40 -0300 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20Layout=20de=20listagem=20de=20clien?= =?UTF-8?q?tes,=20area=20de=20anota=C3=A7=C3=A3o=20e=20prontuario=20de=20p?= =?UTF-8?q?acientes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/App.jsx | 18 ++ .../src/assets/styles/home/filtros-home.css | 81 ++++-- .../styles/listaclientes/listaclientes.css | 112 +++++++++ frontend/src/assets/styles/perfil/section.css | 3 - .../prontuario/historico-atendimento.css | 205 +++++++++++++++ .../assets/styles/prontuario/prontuario.css | 166 ++++++++++++ frontend/src/assets/styles/ui/buttons.css | 2 +- .../styles}/videochamada/streaming.css | 162 +++++++++--- frontend/src/components/Editor.jsx | 0 .../src/components/addartigos/FormArticle.jsx | 2 +- .../src/components/cards/CardClientes.jsx | 32 +++ .../src/components/cards/CardProntuario.jsx | 38 +++ .../src/components/homepage/ActiveFilters.jsx | 14 -- frontend/src/components/homepage/Filtro.jsx | 2 +- .../src/components/homepage/SearchSection.jsx | 13 +- .../components/perfilpage/InfoPsicologo.jsx | 3 + .../components/prontuario/AreaProntuario.jsx | 110 ++++++++ .../prontuario/HistoricoAtendimentos.jsx | 121 +++++++++ frontend/src/pages/Home.jsx | 54 ++-- frontend/src/pages/ListaClientes.jsx | 142 +++++++++++ frontend/src/pages/Prontuario.jsx | 238 ++++++++++++++++++ frontend/src/pages/VideoChamada.jsx | 81 ++++-- 22 files changed, 1472 insertions(+), 127 deletions(-) create mode 100644 frontend/src/assets/styles/listaclientes/listaclientes.css create mode 100644 frontend/src/assets/styles/prontuario/historico-atendimento.css create mode 100644 frontend/src/assets/styles/prontuario/prontuario.css rename frontend/src/{components => assets/styles}/videochamada/streaming.css (58%) create mode 100644 frontend/src/components/Editor.jsx create mode 100644 frontend/src/components/cards/CardClientes.jsx create mode 100644 frontend/src/components/cards/CardProntuario.jsx create mode 100644 frontend/src/components/prontuario/AreaProntuario.jsx create mode 100644 frontend/src/components/prontuario/HistoricoAtendimentos.jsx create mode 100644 frontend/src/pages/ListaClientes.jsx create mode 100644 frontend/src/pages/Prontuario.jsx diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 99f20a1..d9a2d9c 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -16,6 +16,8 @@ import SobreNos from "./pages/SobreNos"; import AddArtigos from "./pages/AddArtigos"; import Configuracoes from "./pages/Configuracoes"; + import ListaClientes from "./pages/ListaClientes"; + import Prontuario from "./pages/Prontuario"; import TermosCondicoes from "./pages/TermosCondicoes"; import VideoChamada from "./pages/VideoChamada"; import Cadastro from "./pages/Cadastro"; @@ -73,6 +75,22 @@ } + /> + + + + } + /> + + + + } />
- +

Visibilidade do artigo

diff --git a/frontend/src/components/perfilpage/InfoPsicologo.jsx b/frontend/src/components/perfilpage/InfoPsicologo.jsx index 2104fe8..f02c850 100644 --- a/frontend/src/components/perfilpage/InfoPsicologo.jsx +++ b/frontend/src/components/perfilpage/InfoPsicologo.jsx @@ -69,6 +69,9 @@ export default function InfoPsicologo({ profileData }) {
+ + Clientes + Criar Artigos diff --git a/frontend/src/components/prontuario/AreaProntuario.jsx b/frontend/src/components/prontuario/AreaProntuario.jsx new file mode 100644 index 0000000..1e1c01e --- /dev/null +++ b/frontend/src/components/prontuario/AreaProntuario.jsx @@ -0,0 +1,110 @@ +import { useEffect, useState } from "react"; +import { HiOutlineClipboardList } from "react-icons/hi"; +import CardProntuario from "../cards/CardProntuario"; + +export default function AreaProntuario({ + formatarData, + prontuarioAtual, +}) { + const [openCard, setOpenCard] = useState(null); + const [loadingTransition, setLoadingTransition] = useState(false); + + useEffect(() => { + if (!prontuarioAtual) return; + setLoadingTransition(true); + + const timer = setTimeout(() => { + setLoadingTransition(false); + }, 250); + + return () => clearTimeout(timer); + }, [prontuarioAtual]); + + if (!prontuarioAtual) { + return ( +
+ +

Selecione um prontuário

+
+ ); + } + + if (loadingTransition) { + return ( +
+ +

Carregando prontuário...

+
+ ); + } + + const sessoesProntuario = [ + { + id: 1, + titulo: "Identificação do usuário/instituição", + descricao: "Descrição da queixa inicial, motivos da busca pelo atendimento e hipótese diagnóstica inicial, se houver.", + informacoes: "" + }, + { + id: 2, + titulo: "Avaliação da demanda e definição de objetivos", + descricao: "Descrição das razões que motivaram a busca pelo serviço ou assistência psicológica, juntamente a aparesentção da modalidade de assistência prestada.", + informacoes: "" + }, + { + id: 3, + titulo: "Registro de evolução e Procedimentos técnico-científicos", + descricao: "Descrição das atividades realizadas, bem como intervenções, técnicas e abordagens teóricas utilizadas.", + informacoes: "" + }, + { + id: 4, + titulo: "Registro de encaminhamento ou encerramento", + descricao: "Registro sobre encaminhamentos para outros profissionais ou o motivo do encerramento do caso.", + informacoes: "" + } + ] + + return ( + <> +
+ {} +

Prontuario: {formatarData(prontuarioAtual.data, "longa")}

+

Informações requeridas pelo CFP

+
+
+ {sessoesProntuario.map((sessao, index) => ( + p.sessaoId === sessao.id + ) || null + } + /> + ))} +
+

Informações adicionais

+
+ +
+
+ +

Manual Orientativo

+
+
+
+ + +
+ +
+
+ + ) +} diff --git a/frontend/src/components/prontuario/HistoricoAtendimentos.jsx b/frontend/src/components/prontuario/HistoricoAtendimentos.jsx new file mode 100644 index 0000000..8c684e4 --- /dev/null +++ b/frontend/src/components/prontuario/HistoricoAtendimentos.jsx @@ -0,0 +1,121 @@ +import "../../assets/styles/prontuario/historico-atendimento.css" +import "../../assets/styles/home/filtros-home.css"; +import { + HiOutlineDocumentText, + HiChevronDown, + HiPlus, + HiOutlineSearch +} from "react-icons/hi"; +import { useState } from "react"; + +export default function HistoricoAtendimentos({ + abrirProntuario, + criarProntuario, + formatarData, + atendimentos, + setAtendimento +}) { + const [openId, setOpenId] = useState(1); + const [searchText, setSearchText] = useState(""); + + const toggleAccordion = (id) => { + setOpenId(openId === id ? null : id); + }; + + const handleTextoChange = (id, value) => { + setAtendimento((prev) => + prev.map((at) => + at.id === id + ? { ...at, relatorioTecnico: value } + : at + ) + ); + }; + + const handleSearch = (e) => { + setSearchText(e.target.value); + } + + const atendimentosFiltrados = atendimentos.filter((at) => { + return ( + searchText.trim() === "" || + at.relatorioTecnico + .toLowerCase() + .includes(searchText.toLowerCase()) + ); + }); + + return ( + <> +
+
+
+ + +
+
+ +
+ + {atendimentosFiltrados.map((item) => ( +
+ +
+ {formatarData(item.data, "curta")} +
+ +
+
toggleAccordion(item.id)}> +
+ {item.hasProntuario ? ( + <> + + Visualizar prontuário do dia + + ) : ( + <> + + Adicionar prontuário do dia + + )} + + {item.titulo} +
+ + +
+ +
+
+ +
+
+ +
+
+ ))} +
+ + ) +} diff --git a/frontend/src/pages/Home.jsx b/frontend/src/pages/Home.jsx index d265276..b8e2fe0 100644 --- a/frontend/src/pages/Home.jsx +++ b/frontend/src/pages/Home.jsx @@ -27,7 +27,6 @@ export default function Home() { const [selectedLocals, setSelectedLocals] = useState([]); const [visualizacao, setVisualizacao] = useState("col"); const [selectedDays, setSelectedDays] = useState([]); - const [selectedRatings, setSelectedRatings] = useState([]); const [searchText, setSearchText] = useState(""); // Texto de busca // Cards const [openPsi, setOpenPsi] = useState(false); @@ -65,21 +64,42 @@ export default function Home() { // Aplicar filtros const perfisFiltrados = perfis.filter(perfil => { - // Filtro de texto (busca por nome, especialidade, local) - const matchTexto = searchText.trim() === "" || + + // Pesquisa + const matchTexto = + searchText.trim() === "" || perfil.nome.toLowerCase().includes(searchText.toLowerCase()) || perfil.local.toLowerCase().includes(searchText.toLowerCase()) || - perfil.tags.some(tag => tag.toLowerCase().includes(searchText.toLowerCase())) || - (perfil.sobreMim && perfil.sobreMim.toLowerCase().includes(searchText.toLowerCase())) || - (perfil.crp && perfil.crp.toLowerCase().includes(searchText.toLowerCase())); - - const matchEspecialidade = selectedSpecialities.length === 0 - || perfil.tags.some(tag => selectedSpecialities.includes(tag)); - const matchLocal = selectedLocals.length === 0 - || selectedLocals.includes(perfil.local); - - return matchTexto && matchEspecialidade && matchLocal; - }); + perfil.tags.some(tag => + tag.toLowerCase().includes(searchText.toLowerCase()) + ); + + // Especialidade + const matchEspecialidade = + selectedSpecialities.length === 0 || + perfil.tags.some(tag => + selectedSpecialities.includes(tag) + ); + + // Local + const matchLocal = + selectedLocals.length === 0 || + selectedLocals.includes(perfil.local); + + // Semana + const matchDias = + selectedDays.length === 0 || + selectedDays.some(dia => + Object.keys(perfil.horarios || {}).includes(dia) + ); + + return ( + matchTexto && + matchEspecialidade && + matchLocal && + matchDias + ); +}); const handleAgendamento = async (dados) => { // Guardar agendamento feito try{ @@ -105,8 +125,6 @@ export default function Home() { selectedLocals={selectedLocals} setSelectedLocals={setSelectedLocals} locais={locais} - selectedRatings={selectedRatings} - setSelectedRatings={setSelectedRatings} selectedDays={selectedDays} setSelectedDays={setSelectedDays} visualizacao={visualizacao} @@ -137,8 +155,6 @@ export default function Home() { selectedLocals={selectedLocals} setSelectedLocals={setSelectedLocals} locais={locais} - selectedRatings={selectedRatings} - setSelectedRatings={setSelectedRatings} selectedDays={selectedDays} setSelectedDays={setSelectedDays} visualizacao={visualizacao} @@ -167,8 +183,6 @@ export default function Home() { selectedLocals={selectedLocals} setSelectedLocals={setSelectedLocals} locais={locais} - selectedRatings={selectedRatings} - setSelectedRatings={setSelectedRatings} selectedDays={selectedDays} setSelectedDays={setSelectedDays} visualizacao={visualizacao} diff --git a/frontend/src/pages/ListaClientes.jsx b/frontend/src/pages/ListaClientes.jsx new file mode 100644 index 0000000..0d0fc88 --- /dev/null +++ b/frontend/src/pages/ListaClientes.jsx @@ -0,0 +1,142 @@ +import "../assets/styles/listaclientes/listaclientes.css"; +import "../assets/styles/home/filtros-home.css"; +import { useState } from "react"; +import { HiOutlineSearch } from "react-icons/hi"; +import CardClientes from "../components/cards/CardClientes"; +import Filtro from "../components/homepage/Filtro"; + +export default function ListaClientes() { + const [searchText, setSearchText] = useState(""); + const [statusSelecionados, setStatusSelecionados] = useState([]); + + // Mock de dados de clientes + const clientes = [ + { + idProntuario: 1, + foto: "/path/to/foto.jpg", + nome: "Amara Silva", + status: "Ativo", + email: "amara.silva@example.com", + dataInicio: "2023-01-01" + }, + { + idProntuario: 2, + foto: "/path/to/foto.jpg", + nome: "Lira Costa", + status: "Inativo", + email: "lira.costa@example.com", + dataInicio: "2023-01-01" + }, + { + idProntuario: 3, + foto: "/path/to/foto.jpg", + nome: "Snoopy", + status: "Ativo", + email: "snoopy@example.com", + dataInicio: "2023-01-01" + }, + { + idProntuario: 4, + foto: "/path/to/foto.jpg", + nome: "Marcos Silva", + status: "Pendente", + email: "marcos.silva@example.com", + dataInicio: "2023-01-01" + }, + { + idProntuario: 5, + foto: "/path/to/foto.jpg", + nome: "Carlos Matheus", + status: "Ativo", + email: "carlos.matheus@example.com", + dataInicio: "2023-01-01" + }, + { + idProntuario: 6, + foto: "/path/to/foto.jpg", + nome: "Luis Alcantara", + status: "Inativo", + email: "luis.alcantara@example.com", + dataInicio: "2023-01-01" + }, + { + idProntuario: 7, + foto: "/path/to/foto.jpg", + nome: "Heugenia Silva", + status: "Ativo", + email: "heugenia.silva@example.com", + dataInicio: "2023-01-01" + }, + { + idProntuario: 8, + foto: "/path/to/foto.jpg", + nome: "Marcos Santos", + status: "Inativo", + email: "marcos.santos@example.com", + dataInicio: "2023-01-01" + }, + ]; + const statusOptions = ["Ativo", "Pendente", "Inativo"]; + + const handleSearch = (e) => { + setSearchText(e.target.value); + } + + const clientesFiltrados = clientes.filter(cliente => { + const matchTexto = + searchText.trim() === "" || + cliente.nome.toLowerCase().includes(searchText.toLowerCase()); + + const matchStatus = + statusSelecionados.length === 0 || + statusSelecionados.includes(cliente.status); + + return matchTexto && matchStatus; + }); + + return ( + <> +
+
+
+ + +
+ +
+ +
+
+

Cliente

+

Status

+

Email

+

Data de Inicio

+

Prontuários

+
+ +
+ {clientesFiltrados.map((cliente, index) => ( + + ))} +
+
+
+ + ) +} diff --git a/frontend/src/pages/Prontuario.jsx b/frontend/src/pages/Prontuario.jsx new file mode 100644 index 0000000..2f42ddd --- /dev/null +++ b/frontend/src/pages/Prontuario.jsx @@ -0,0 +1,238 @@ +import "../assets/styles/prontuario/prontuario.css"; +import "../assets/styles/listaclientes/listaclientes.css"; +import perfil from "../assets/img/perfil-default.png"; +import AreaProntuario from "../components/prontuario/AreaProntuario"; +import HistoricoAtendimentos from "../components/prontuario/HistoricoAtendimentos"; +import { useState } from "react"; + +export default function Prontuario() { + // Mock de dados + const cliente = { + idProntuario: 1, + foto: "/path/to/foto.jpg", + nome: "Amara Silva", + idade: 25, + local: "São Paulo, SP", + status: "Ativo", + email: "amara.silva@example.com", + dataInicio: "2023-01-01", + qtd_atendimentos: 3 + } + const atendimentoMock = [ + { + id: 1, + data: "15/05/2026", + hasProntuario: true, + relatorioTecnico: "Notas do dia 15 de Maio, Lembrete da sessão:", + prontuario: [ + { + sessaoId: 1, + informacoes: "Paciente relata episódios recentes de ansiedade relacionados ao ambiente de trabalho." + }, + { + sessaoId: 2, + informacoes: "Definido acompanhamento semanal para manejo emocional." + }, + { + sessaoId: 3, + informacoes: "" + }, + { + sessaoId: 4, + informacoes: "" + } + ], + informacoesAdicionais: "Paciente demonstrou boa adesão às orientações." + }, + { + id: 2, + data: "08/05/2026", + hasProntuario: true, + relatorioTecnico: "", + prontuario: [ + { + sessaoId: 1, + informacoes: "Queixa principal relacionada à dificuldade de concentração." + }, + { + sessaoId: 2, + informacoes: "Objetivo inicial focado em organização de rotina." + }, + { + sessaoId: 3, + informacoes: "Realizada escuta ativa e levantamento de hábitos." + }, + { + sessaoId: 4, + informacoes: "" + } + ], + informacoesAdicionais: "" + }, + { + id: 3, + data: "01/05/2026", + hasProntuario: false, + relatorioTecnico: "", + prontuario: [], + informacoesAdicionais: "" + }, + { + id: 4, + data: "25/04/2026", + hasProntuario: true, + relatorioTecnico: "", + prontuario: [ + { + sessaoId: 1, + informacoes: "Paciente relata conflitos familiares recorrentes." + }, + { + sessaoId: 2, + informacoes: "Definido fortalecimento de habilidades comunicativas." + }, + { + sessaoId: 3, + informacoes: "Trabalhada identificação de gatilhos emocionais." + }, + { + sessaoId: 4, + informacoes: "" + } + ], + informacoesAdicionais: "Paciente apresentou melhora na comunicação." + }, + ]; + + const [prontuarioAtual, setProntuarioAtual] = useState(null); + const [atendimentos, setAtendimento] = useState(atendimentoMock); + + const criarProntuario = (data) => { + const prontuarioVazio = [ + { + sessaoId: 1, + informacoes: "" + }, + { + sessaoId: 2, + informacoes: "" + }, + { + sessaoId: 3, + informacoes: "" + }, + { + sessaoId: 4, + informacoes: "" + } + ]; + + setAtendimento((prev) => prev.map((at) => + at.data === data ? { + ...at, + hasProntuario: true, + prontuario: prontuarioVazio, + informacoesAdicionais: "" + } + : at + ) + ); + + const atendimentoAtualizado = atendimentos.find( + (at) => at.data === data + ); + + setProntuarioAtual({ + ...atendimentoAtualizado, + hasProntuario: true, + prontuario: prontuarioVazio, + informacoesAdicionais: "" + }); + }; + + const abrirProntuario = (atendimentoData) => { + const prontuarioSelecionado = atendimentos.find((at) => at.data === atendimentoData); + setProntuarioAtual(prontuarioSelecionado); + }; + + const formatarData = (data, tipo = "curta") => { + if (!data) return ""; + const meses = [ + "Janeiro", + "Fevereiro", + "Março", + "Abril", + "Maio", + "Junho", + "Julho", + "Agosto", + "Setembro", + "Outubro", + "Novembro", + "Dezembro" + ]; + + const [dia, mes, ano] = data.split("/"); + if (!dia || !mes || !ano) return data; + + const nomeMes = meses[Number(mes) - 1]; + + if (tipo === "curta") { + return `${nomeMes.length > 5 ? nomeMes.substring(0, 3) : nomeMes} ${dia}`; + } + + return `${dia} de ${nomeMes} de ${ano}`; + } + + // Salvar no backend as informações + const salvarProntuario = async () => { + if (!prontuarioAtual) return; + + const dados = { + clienteId: cliente.idProntuario, + atendimentoId: prontuarioAtual.id, + prontuario: prontuarioAtual.prontuario, + informacoesAdicionais: + prontuarioAtual.informacoesAdicionais, + relatorioTecnico: + prontuarioAtual.relatorioTecnico + }; + }; + + return ( + <> +
+
+
+ {`Foto { + e.target.src = perfil; + }}/> +
+

{cliente.nome}

+

Idade: {cliente.idade} anos

+

Local: {cliente.local}

+

Primeira consulta: {cliente.dataInicio}

+

Atendimentos: {cliente.qtd_atendimentos}

+
+

{cliente.status}

+
+ +
+ + +
+ + ) +} diff --git a/frontend/src/pages/VideoChamada.jsx b/frontend/src/pages/VideoChamada.jsx index 76beb08..a2dd669 100644 --- a/frontend/src/pages/VideoChamada.jsx +++ b/frontend/src/pages/VideoChamada.jsx @@ -1,10 +1,13 @@ import { useAuth } from '../context/AuthContext'; import { useParams, Navigate, useNavigate } from 'react-router-dom'; import { useEffect, useRef, useState } from 'react'; +import { HiChevronLeft, HiChevronRight} from "react-icons/hi"; import { Video, VideoOff, Mic, MicOff, PhoneOff } from 'lucide-react'; -import '../components/videochamada/streaming.css'; +import '../assets/styles/videochamada/streaming.css'; export default function VideoChamada() { + const [open, setOpen] = useState(true); + const [openInfoNote, setOpenInfoNote] = useState(false); const { user, loading } = useAuth(); const { agendamentoId } = useParams(); const navigate = useNavigate(); @@ -14,6 +17,12 @@ export default function VideoChamada() { const [isVideoOn, setIsVideoOn] = useState(true); const [roomName, setRoomName] = useState(''); const [isInCall, setIsInCall] = useState(false); + const [notes, setNotes] = useState(""); + + const notesPsicologo = (e) => { + setNotes(e.target.value); + // Implementar a lógica para salvar as anotações + } useEffect(() => { if (agendamentoId) { @@ -187,8 +196,10 @@ export default function VideoChamada() { return (
+
{!isInCall ? ( + // Tela de entrada - escolher sala
@@ -258,7 +269,9 @@ export default function VideoChamada() { )}
+ ) : ( + // Container do Jitsi Meet <>
{/* Área lateral */} -
-
-

Informações

-

Usuário: {user.nome}

-

Tipo: {user.tipo}

- {isInCall && ( - <> -

Sala:

-

{roomName}

-
- Compartilhe este nome de sala com a outra pessoa para entrarem juntos! -
- - )} - {!isInCall && ( -
- Modo Debug Ativo
- Você pode entrar em qualquer sala sem restrições. +
+
+
+

Usuário: {user.nome}

+

Tipo: {user.tipo}

+ {isInCall && ( + <> +

Sala:

+

{roomName}

+
+ Compartilhe este nome de sala com a outra pessoa para entrarem juntos! +
+ + )} + {!isInCall && ( +
+ Modo Debug Ativo
+ Você pode entrar em qualquer sala sem restrições. +
+ )} +
+
+
+

Anotações são salvas automaticamente

+