"use client"; import React, { useEffect, useState, useCallback, useMemo } from "react"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { Button } from "@/components/ui/button" import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { Edit, Trash2, Eye, Calendar, Filter, Loader2, MoreVertical } from "lucide-react" import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from "@/components/ui/alert-dialog" import { doctorsService } from "services/doctorsApi.mjs"; import Sidebar from "@/components/Sidebar"; // --- NOVOS IMPORTS (Certifique-se que criou os arquivos no passo anterior) --- import { FilterBar } from "@/components/ui/filter-bar"; import { normalizeSpecialty, getUniqueSpecialties } from "@/lib/normalization"; interface Doctor { id: number; full_name: string; specialty: string; crm: string; phone_mobile: string | null; city: string | null; state: string | null; status?: string; } interface DoctorDetails { nome: string; crm: string; especialidade: string; contato: { celular?: string; telefone1?: string; }; endereco: { cidade?: string; estado?: string; }; convenio?: string; vip?: boolean; status?: string; ultimo_atendimento?: string; proximo_atendimento?: string; error?: string; } export default function DoctorsPage() { const router = useRouter(); // --- Estados de Dados --- const [doctors, setDoctors] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); // --- Estados de Modais --- const [detailsDialogOpen, setDetailsDialogOpen] = useState(false); const [doctorDetails, setDoctorDetails] = useState(null); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [doctorToDeleteId, setDoctorToDeleteId] = useState(null); // --- Estados de Filtro e Busca --- const [searchTerm, setSearchTerm] = useState(""); const [filters, setFilters] = useState({ specialty: "all", status: "all" }); // --- Estados de Paginação --- const [itemsPerPage, setItemsPerPage] = useState(10); const [currentPage, setCurrentPage] = useState(1); // 1. Buscar Médicos na API const fetchDoctors = useCallback(async () => { setLoading(true); setError(null); try { const data: Doctor[] = await doctorsService.list(); // Mockando status para visualização (conforme original) const dataWithStatus = data.map((doc, index) => ({ ...doc, status: index % 3 === 0 ? "Inativo" : index % 2 === 0 ? "Férias" : "Ativo", })); setDoctors(dataWithStatus || []); // Não resetamos a página aqui para manter a navegação fluida se apenas recarregar dados } catch (e: any) { console.error("Erro ao carregar lista de médicos:", e); setError("Não foi possível carregar a lista de médicos. Verifique a conexão com a API."); setDoctors([]); } finally { setLoading(false); } }, []); useEffect(() => { fetchDoctors(); }, [fetchDoctors]); // 2. Gerar lista única de especialidades (Normalizada) const uniqueSpecialties = useMemo(() => { return getUniqueSpecialties(doctors); }, [doctors]); // 3. Lógica de Filtragem Centralizada const filteredDoctors = useMemo(() => { return doctors.filter((doctor) => { // Normaliza a especialidade do médico atual para comparar const normalizedDocSpecialty = normalizeSpecialty(doctor.specialty); // Filtros exatos const specialtyMatch = filters.specialty === "all" || normalizedDocSpecialty === filters.specialty; const statusMatch = filters.status === "all" || doctor.status === filters.status; // Busca textual (Nome, Telefone, CRM) const searchLower = searchTerm.toLowerCase(); const nameMatch = doctor.full_name?.toLowerCase().includes(searchLower); const phoneMatch = doctor.phone_mobile?.includes(searchLower); const crmMatch = doctor.crm?.toLowerCase().includes(searchLower); return specialtyMatch && statusMatch && (searchTerm === "" || nameMatch || phoneMatch || crmMatch); }); }, [doctors, filters, searchTerm]); // --- Handlers de Controle (Com Reset de Paginação) --- const handleSearch = (term: string) => { setSearchTerm(term); setCurrentPage(1); // Correção: Reseta para página 1 ao buscar }; const handleFilterChange = (key: string, value: string) => { setFilters(prev => ({ ...prev, [key]: value })); setCurrentPage(1); // Correção: Reseta para página 1 ao filtrar }; const handleClearFilters = () => { setSearchTerm(""); setFilters({ specialty: "all", status: "all" }); setCurrentPage(1); // Correção: Reseta para página 1 ao limpar }; const handleItemsPerPageChange = (value: string) => { setItemsPerPage(Number(value)); setCurrentPage(1); }; // --- Lógica de Paginação --- const totalPages = Math.ceil(filteredDoctors.length / itemsPerPage); const indexOfLastItem = currentPage * itemsPerPage; const indexOfFirstItem = indexOfLastItem - itemsPerPage; const currentItems = filteredDoctors.slice(indexOfFirstItem, indexOfLastItem); const paginate = (pageNumber: number) => setCurrentPage(pageNumber); const goToPrevPage = () => setCurrentPage((prev) => Math.max(1, prev - 1)); const goToNextPage = () => setCurrentPage((prev) => Math.min(totalPages, prev + 1)); const getVisiblePageNumbers = (totalPages: number, currentPage: number) => { const pages: number[] = []; const maxVisiblePages = 5; const halfRange = Math.floor(maxVisiblePages / 2); let startPage = Math.max(1, currentPage - halfRange); let endPage = Math.min(totalPages, currentPage + halfRange); if (endPage - startPage + 1 < maxVisiblePages) { if (endPage === totalPages) { startPage = Math.max(1, totalPages - maxVisiblePages + 1); } if (startPage === 1) { endPage = Math.min(totalPages, maxVisiblePages); } } for (let i = startPage; i <= endPage; i++) { pages.push(i); } return pages; }; const visiblePageNumbers = getVisiblePageNumbers(totalPages, currentPage); // --- Handlers de Ações (Detalhes e Delete) --- const openDetailsDialog = (doctor: Doctor) => { setDetailsDialogOpen(true); setDoctorDetails({ nome: doctor.full_name, crm: doctor.crm, especialidade: normalizeSpecialty(doctor.specialty), // Exibe normalizado contato: { celular: doctor.phone_mobile ?? undefined }, endereco: { cidade: doctor.city ?? undefined, estado: doctor.state ?? undefined }, status: doctor.status || "Ativo", convenio: "Particular", vip: false, ultimo_atendimento: "N/A", proximo_atendimento: "N/A", }); }; const openDeleteDialog = (doctorId: number) => { setDoctorToDeleteId(doctorId); setDeleteDialogOpen(true); }; const handleDelete = async () => { if (doctorToDeleteId === null) return; setLoading(true); try { await doctorsService.delete(doctorToDeleteId); setDeleteDialogOpen(false); setDoctorToDeleteId(null); await fetchDoctors(); } catch (e) { console.error("Erro ao excluir:", e); alert("Erro ao excluir médico."); } finally { setLoading(false); } }; return (
{/* Cabeçalho */}

Médicos Cadastrados

Gerencie todos os profissionais de saúde.

{/* --- NOVO COMPONENTE DE FILTRO --- */} {/* Seletor de Itens por Página (Filho do FilterBar) */}
{/* Tabela de Médicos */}
{loading ? (
Carregando médicos...
) : error ? (
{error}
) : filteredDoctors.length === 0 ? (
{doctors.length === 0 ? <>Nenhum médico cadastrado. Adicione um novo. : "Nenhum médico encontrado com os filtros aplicados." }
) : (
{currentItems.map((doctor) => ( ))}
Nome CRM Especialidade Status Cidade/Estado Ações
{doctor.full_name} {doctor.crm} {/* Exibe Especialidade Normalizada */} {normalizeSpecialty(doctor.specialty)} {doctor.status || "N/A"} {(doctor.city || doctor.state) ? `${doctor.city || ""}${doctor.city && doctor.state ? '/' : ''}${doctor.state || ""}` : "N/A"} openDetailsDialog(doctor)}> Ver detalhes Editar Marcar consulta openDeleteDialog(doctor.id)}> Excluir
)}
{/* Cards de Médicos (Mobile) */}
{loading ? (
Carregando médicos...
) : error ? (
{error}
) : filteredDoctors.length === 0 ? (
{doctors.length === 0 ? <>Nenhum médico cadastrado. Adicione um novo. : "Nenhum médico encontrado com os filtros aplicados." }
) : (
{currentItems.map((doctor) => (
{doctor.full_name}
{doctor.phone_mobile}
{normalizeSpecialty(doctor.specialty)}
{doctor.status || "N/A"}
openDetailsDialog(doctor)}> Ver detalhes Editar openDeleteDialog(doctor.id)}> Excluir
))}
)}
{/* Paginação */} {totalPages > 1 && (
{visiblePageNumbers.map((number) => ( ))}
)} {/* Dialogs (Exclusão e Detalhes) */} Confirma a exclusão? Esta ação é irreversível e excluirá permanentemente o registro deste médico. Cancelar {loading ? : null} Excluir {doctorDetails?.nome} {doctorDetails && (

Informações Principais

CRM: {doctorDetails.crm}
Especialidade:{" "} {doctorDetails.especialidade}
Celular:{" "} {doctorDetails.contato.celular || "N/A"}
Localização:{" "} {`${doctorDetails.endereco.cidade || "N/A"}/${ doctorDetails.endereco.estado || "N/A" }`}

Atendimento e Convênio

Convênio:{" "} {doctorDetails.convenio || "N/A"}
VIP:{" "} {doctorDetails.vip ? "Sim" : "Não"}
Status: {doctorDetails.status || "N/A"}
Último atendimento:{" "} {doctorDetails.ultimo_atendimento || "N/A"}
Próximo atendimento:{" "} {doctorDetails.proximo_atendimento || "N/A"}
)} {doctorDetails === null && !loading && (
Detalhes não disponíveis.
)}
Fechar
); }