315 lines
11 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
// Imports mantidos
import { useEffect, useState } from "react";
import dynamic from "next/dynamic";
import Link from "next/link";
// --- Imports do FullCalendar (restaurados) ---
import pt_br_locale from "@fullcalendar/core/locales/pt-br";
import FullCalendar from "@fullcalendar/react";
import dayGridPlugin from "@fullcalendar/daygrid";
import interactionPlugin from "@fullcalendar/interaction";
import timeGridPlugin from "@fullcalendar/timegrid";
import { EventInput } from "@fullcalendar/core/index.js";
// --- Imports do EventManager (NOVO) - ADICIONADOS ---
import { EventManager, type Event } from "@/components/event-manager";
import { v4 as uuidv4 } from 'uuid';
// Imports mantidos
import { Sidebar } from "@/components/dashboard/sidebar";
import { PagesHeader } from "@/components/dashboard/header";
import { Button } from "@/components/ui/button";
import { mockWaitingList } from "@/lib/mocks/appointment-mocks";
import "./index.css";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { ThreeDWallCalendar, CalendarEvent } from "@/components/ui/three-dwall-calendar"; // Calendário 3D mantido
const ListaEspera = dynamic(
  () => import("@/components/agendamento/ListaEspera"),
  { ssr: false }
);
export default function AgendamentoPage() {
  const [appointments, setAppointments] = useState<any[]>([]);
  const [waitingList, setWaitingList] = useState(mockWaitingList);
  const [activeTab, setActiveTab] = useState<"calendar" | "espera" | "3d">("calendar");
 
// Estado para alimentar o FullCalendar (restaurado)
const [requestsList, setRequestsList] = useState<EventInput[]>([]);
 
const [threeDEvents, setThreeDEvents] = useState<CalendarEvent[]>([]);
// --- Dados de Exemplo para o NOVO Calendário ---
// (Colado do exemplo do 21st.dev)
const demoEvents: Event[] = [
{
id: uuidv4(),
title: "Team Standup",
description: "Daily sync with the engineering team.",
startTime: new Date(2025, 9, 20, 9, 0, 0), // Mês 9 = Outubro
endTime: new Date(2025, 9, 20, 9, 30, 0),
color: "blue",
},
{
id: uuidv4(),
title: "Code Review",
description: "Review PRs for the new feature.",
startTime: new Date(2025, 9, 21, 14, 0, 0),
endTime: new Date(2025, 9, 21, 15, 0, 0),
color: "green",
},
{
id: uuidv4(),
title: "Client Presentation",
description: "Present the new designs to the client.",
startTime: new Date(2025, 9, 22, 11, 0, 0),
endTime: new Date(2025, 9, 22, 12, 0, 0),
color: "orange",
},
{
id: uuidv4(),
title: "Sprint Planning",
description: "Plan the next sprint tasks.",
startTime: new Date(2025, 9, 23, 10, 0, 0),
endTime: new Date(2025, 9, 23, 11, 30, 0),
color: "purple",
},
{
id: uuidv4(),
title: "Doctor Appointment",
description: "Annual check-up.",
startTime: new Date(2025, 9, 24, 16, 0, 0),
endTime: new Date(2025, 9, 24, 17, 0, 0),
color: "red",
},
{
id: uuidv4(),
title: "Deploy to Production",
description: "Deploy the new release.",
startTime: new Date(2025, 9, 25, 15, 0, 0),
endTime: new Date(2025, 9, 25, 16, 0, 0),
color: "teal",
},
{
id: uuidv4(),
title: "Product Design Review",
description: "Review the new product design mockups.",
startTime: new Date(2025, 9, 20, 13, 0, 0),
endTime: new Date(2025, 9, 20, 14, 30, 0),
color: "pink",
},
{
id: uuidv4(),
title: "Gym Session",
description: "Leg day.",
startTime: new Date(2025, 9, 20, 18, 0, 0),
endTime: new Date(2025, 9, 20, 19, 0, 0),
color: "gray",
},
];
// --- Fim dos Dados de Exemplo ---
  useEffect(() => {
    document.addEventListener("keydown", (event) => {
      if (event.key === "c") {
        setActiveTab("calendar");
      }
      if (event.key === "f") {
        setActiveTab("espera");
      }
      if (event.key === "3") {
        setActiveTab("3d");
      }
    });
  }, []);
  useEffect(() => {
// Este useEffect foi mantido, pois ele busca dados para o Calendário 3D
    let mounted = true;
    (async () => {
      try {
        const api = await import('@/lib/api');
        const arr = await api.listarAgendamentos('select=*&order=scheduled_at.desc&limit=500').catch(() => []);
        if (!mounted) return;
        if (!arr || !arr.length) {
          setAppointments([]);
          // setRequestsList([]); // Removido
          setThreeDEvents([]);
          return;
        }
        const patientIds = Array.from(new Set(arr.map((a: any) => a.patient_id).filter(Boolean)));
        const patients = (patientIds && patientIds.length) ? await api.buscarPacientesPorIds(patientIds) : [];
        const patientsById: Record<string, any> = {};
        (patients || []).forEach((p: any) => { if (p && p.id) patientsById[String(p.id)] = p; });
        setAppointments(arr || []);
// --- Mapeamento para o FullCalendar (ANTIGO) - REMOVIDO ---
        // const events: EventInput[] = (arr || []).map((obj: any) => {
        //   ...
        // });
        // setRequestsList(events || []);
// Convert to 3D calendar events
const threeDEvents: CalendarEvent[] = (arr || []).map((obj: any) => {
const scheduled = obj.scheduled_at || obj.scheduledAt || obj.time || null;
const patient = (patientsById[String(obj.patient_id)]?.full_name) || obj.patient_name || obj.patient_full_name || obj.patient || 'Paciente';
const appointmentType = obj.appointment_type ?? obj.type ?? 'Consulta';
const title = `${patient}: ${appointmentType}`.trim();
return {
id: obj.id || String(Date.now()),
title,
date: scheduled ? new Date(scheduled).toISOString() : new Date().toISOString(),
status: obj.status || 'pending',
patient,
type: appointmentType,
};
});
setThreeDEvents(threeDEvents);
} catch (err) {
console.warn('[AgendamentoPage] falha ao carregar agendamentos', err);
setAppointments([]);
setRequestsList([]);
setThreeDEvents([]);
}
})();
return () => { mounted = false; };
}, []);
  // Handlers mantidos
  const handleSaveAppointment = (appointment: any) => {
    if (appointment.id) {
      setAppointments((prev) =>
        prev.map((a) => (a.id === appointment.id ? appointment : a))
      );
    } else {
      const newAppointment = {
        ...appointment,
        id: Date.now().toString(),
      };
      setAppointments((prev) => [...prev, newAppointment]);
    }
  };
  const handleNotifyPatient = (patientId: string) => {
    console.log(`Notificando paciente ${patientId}`);
  };
  const handleAddEvent = (event: CalendarEvent) => {
    setThreeDEvents((prev) => [...prev, event]);
  };
  const handleRemoveEvent = (id: string) => {
    setThreeDEvents((prev) => prev.filter((e) => e.id !== id));
  };
  return (
    <div className="flex flex-row bg-background">
      <div className="flex w-full flex-col">
        <div className="flex w-full flex-col gap-10 p-6">
          <div className="flex flex-row justify-between items-center">
{/* Todo o cabeçalho foi mantido */}
            <div>
              <h1 className="text-2xl font-bold text-foreground">
                {activeTab === "calendar" ? "Calendário" : activeTab === "3d" ? "Calendário 3D" : "Lista de Espera"}
              </h1>
              <p className="text-muted-foreground">
                Navegue através dos atalhos: Calendário (C), Fila de espera (F) ou 3D (3).
              </p>
            </div>
            <div className="flex space-x-2">
              <DropdownMenu>
                <DropdownMenuTrigger className="bg-primary hover:bg-primary/90 px-5 py-1 text-primary-foreground rounded-sm">
                  Opções &#187;
                </DropdownMenuTrigger>
                <DropdownMenuContent>
                  <Link href={"/agenda"}>
                    <DropdownMenuItem>Agendamento</DropdownMenuItem>
                  </Link>
                  <Link href={"/procedimento"}>
                    <DropdownMenuItem>Procedimento</DropdownMenuItem>
                  </Link>
                  <Link href={"/financeiro"}>
                    <DropdownMenuItem>Financeiro</DropdownMenuItem>
                  </Link>
                </DropdownMenuContent>
              </DropdownMenu>
              <div className="flex flex-row">
                <Button
                  variant={"outline"}
                  className="bg-muted hover:!bg-primary hover:!text-white transition-colors rounded-l-[100px] rounded-r-[0px]"
                  onClick={() => setActiveTab("calendar")}
                >
                  Calendário
                </Button>
                <Button
                  variant={"outline"}
                  className="bg-muted hover:!bg-primary hover:!text-white transition-colors rounded-none"
                  onClick={() => setActiveTab("3d")}
                >
                  3D
                </Button>
                <Button
                  variant={"outline"}
                  className="bg-muted hover:!bg-primary hover:!text-white transition-colors rounded-r-[100px] rounded-l-[0px]"
                  onClick={() => setActiveTab("espera")}
                >
                  Lista de espera
                </Button>
              </div>
            </div>
          </div>
{activeTab === "calendar" ? (
<div className="flex w-full">
<FullCalendar
plugins={[dayGridPlugin, timeGridPlugin, interactionPlugin]}
initialView="dayGridMonth"
locale={pt_br_locale}
timeZone={"America/Sao_Paulo"}
events={requestsList}
headerToolbar={{
left: "prev,next today",
center: "title",
right: "dayGridMonth,timeGridWeek,timeGridDay",
}}
dateClick={(info) => {
info.view.calendar.changeView("timeGridDay", info.dateStr);
}}
selectable={true}
selectMirror={true}
dayMaxEvents={true}
dayMaxEventRows={3}
/>
</div>
) : activeTab === "3d" ? (
<div className="flex w-full justify-center">
<ThreeDWallCalendar
events={threeDEvents}
onAddEvent={handleAddEvent}
onRemoveEvent={handleRemoveEvent}
/>
</div>
) : (
<ListaEspera
patients={waitingList}
onNotify={handleNotifyPatient}
onAddToWaitlist={() => {}}
/>
)}
</div>
</div>
</div>
);
}