feat(gto+agenda): busca de paciente por modal + botão ATENDER na agenda

- LancarGTO: substitui <select> de beneficiário por botão que abre modal de busca
  com filtro em tempo real por nome/CPF; avatar com inicial do paciente
- LancarGTO store: adiciona pendingSearch para receber paciente pré-selecionado
  de outra view; auto-seleciona por correspondência exata ou abre modal com
  o nome pré-preenchido
- AgendaView: adiciona botão "ATENDER PACIENTE" no painel de detalhes do
  agendamento (visível para todos os roles exceto paciente); ao clicar define
  o pendingSearch e navega para /lancar-gto com o paciente do horário
- App.tsx: passa onNavigate para AgendaView; adiciona lancar-gto às permissões
  do role dentista

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
VPS 4 Builder
2026-05-14 20:53:48 +02:00
parent a47f225bf9
commit 36c4435787
3 changed files with 133 additions and 16 deletions
+19 -2
View File
@@ -8,6 +8,7 @@ import { AgendaSettingsModal } from '../components/AgendaSettingsModal.tsx';
import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd';
import { HybridBackend } from '../services/backend.ts';
import { Dentista, Agendamento, Paciente, DentistaHorario } from '../types.ts';
import { useGTOStore } from './LancarGTO.tsx';
import { useHybridBackend } from '../hooks/useHybridBackend.ts';
import { useToast } from '../contexts/ToastContext.tsx';
import { PageHeader } from '../components/PageHeader.tsx';
@@ -263,7 +264,7 @@ const AppointmentModal: React.FC<{
);
};
export const AgendaView: React.FC = () => {
export const AgendaView: React.FC<{ onNavigate?: (view: string) => void }> = ({ onNavigate }) => {
const { data: agendamentos, refresh } = useHybridBackend<Agendamento[]>(HybridBackend.getAgendamentos);
const { data: dentists, refresh: refreshDentists } = useHybridBackend<Dentista[]>(HybridBackend.getDentistas);
const { data: googleEvents, refresh: refreshGoogle } = useHybridBackend<any[]>(HybridBackend.getGoogleEvents);
@@ -373,6 +374,14 @@ export const AgendaView: React.FC = () => {
const currentRole = HybridBackend.getCurrentRole();
const currentUserEmail = HybridBackend.getCurrentUser();
const gtoStore = useGTOStore();
const handleAtender = () => {
if (!selectedAppointment || !onNavigate) return;
gtoStore.setPendingSearch(selectedAppointment.pacienteNome);
setShowDetails(false);
onNavigate('lancar-gto');
};
const filteredDentists = dentists?.filter(d => {
if (currentRole === 'admin' || currentRole === 'donoclinica' || currentRole === 'funcionario') return true;
@@ -537,8 +546,16 @@ export const AgendaView: React.FC = () => {
</div>
</div>
{/* Footer: Reagendar */}
{/* Footer: Ações */}
<div className="px-10 py-8 bg-gray-50/50 border-t border-gray-100 flex gap-4">
{onNavigate && currentRole !== 'paciente' && (
<button
onClick={handleAtender}
className="flex-1 py-4 bg-emerald-600 text-white rounded-2xl text-xs font-black uppercase tracking-widest hover:bg-emerald-700 hover:shadow-xl hover:shadow-emerald-200 transition-all shadow-lg shadow-emerald-100"
>
ATENDER PACIENTE
</button>
)}
<button
onClick={() => { setShowDetails(false); setIsModalOpen(true); }}
className="flex-1 py-4 bg-blue-600 text-white rounded-2xl text-xs font-black uppercase tracking-widest hover:bg-blue-700 hover:shadow-xl hover:shadow-blue-200 transition-all shadow-lg shadow-blue-100"