diff --git a/src/pages/Adopter/AdopterList.tsx b/src/pages/Adopter/AdopterList.tsx index 403d584..f47d925 100644 --- a/src/pages/Adopter/AdopterList.tsx +++ b/src/pages/Adopter/AdopterList.tsx @@ -48,6 +48,9 @@ export default function AdopterList() { const [errors, setErrors] = useState({}); const navigate = useNavigate(); + const [currentPage, setCurrentPage] = useState(1); + const itemsPerPage = 8; + useEffect(() => { const fetchData = async () => { try { @@ -69,6 +72,18 @@ export default function AdopterList() { ) ); + const totalPages = Math.max(1, Math.ceil(filteredAdopters.length / itemsPerPage)); + const paginatedAdopters = filteredAdopters.slice((currentPage - 1) * itemsPerPage, currentPage * itemsPerPage); + + useEffect(() => { + const tp = Math.max(1, Math.ceil(filteredAdopters.length / itemsPerPage)); + if (currentPage > tp) setCurrentPage(tp); + }, [currentPage, filteredAdopters.length]); + + useEffect(() => { + setCurrentPage(1); + }, [searchTerm]); + const inputStyle = (hasError?: boolean) => `w-full px-4 py-3 rounded-xl shadow-sm focus:ring-2 focus:outline-none transition placeholder-gray-400 text-gray-800 bg-gray-100/70 ${hasError ? "ring-red-500 focus:ring-red-500" : "focus:ring-blue-500"}`; @@ -165,10 +180,35 @@ export default function AdopterList() { error: "Erro ao excluir adotante." } ); - setAdopters(prev => prev.filter(a => a.id !== deleteAdopter.id)); + + setAdopters(prev => { + const newList = prev.filter(a => a.id !== deleteAdopter.id); + const newFilteredLength = newList.filter(a => + [a.name, a.email, a.phone, a.cpf, a.rg].some(field => + field?.toLowerCase().includes(searchTerm.toLowerCase()) + ) + ).length; + const newTotalPages = Math.max(1, Math.ceil(newFilteredLength / itemsPerPage)); + if (currentPage > newTotalPages) setCurrentPage(newTotalPages); + return newList; + }); + setDeleteAdopter(null); }; + const startIndex = (currentPage - 1) * itemsPerPage; + const endIndex = Math.min(filteredAdopters.length, currentPage * itemsPerPage); + + const getPageNumbers = () => { + return Array.from({ length: totalPages }).map((_, i) => i + 1); + }; + + const goToPage = (page: number) => { + if (page < 1 || page > totalPages) return; + setCurrentPage(page); + window.scrollTo({ top: 0, behavior: "smooth" }); + }; + return (
@@ -191,47 +231,86 @@ export default function AdopterList() { {loading ? (
- {[...Array(6)].map((_, i) => ( + {Array.from({ length: itemsPerPage }).map((_, i) => (
))}
) : filteredAdopters.length === 0 ? (
Nenhum adotante encontrado.
) : ( -
- {filteredAdopters.map(a => ( -
-
- {a.sex === "Feminino" ? ( - Avatar feminino - ) : a.sex === "Masculino" ? ( - Avatar masculino - ) : ( - Avatar outros - )} + <> +
+ {paginatedAdopters.map(a => ( +
+
+ {a.sex === "Feminino" ? ( + Avatar feminino + ) : a.sex === "Masculino" ? ( + Avatar masculino + ) : ( + Avatar outros + )} - + +
+
+

{a.name}

+

{a.email}

+

{a.phone}

+

{a.sex || "Não informado"}

+ +
-
-

{a.name}

-

{a.email}

-

{a.phone}

-

{a.sex || "Não informado"}

+ ))} +
+ +
+
+ + + {getPageNumbers().map(n => ( -
+ ))} + +
- ))} -
+ +
+ Mostrando {startIndex + 1}–{endIndex} de {filteredAdopters.length} +
+
+ )} @@ -337,11 +416,7 @@ export default function AdopterList() {
@@ -349,9 +424,7 @@ export default function AdopterList() {
@@ -370,51 +443,27 @@ export default function AdopterList() { {/* Rua */}
- +
{/* Número */}
- +
{/* Complemento */}
- +
- +
@@ -424,12 +473,9 @@ export default function AdopterList() { name="sex" value={editing.sex || ""} onChange={handleEditChange} - className={inputStyle(!!errors.cep)} + className={inputStyle(!!errors.sex)} > - - - - + {/* opções */}
@@ -437,27 +483,7 @@ export default function AdopterList() {
- - - + {/* radio/checkbox */}
@@ -468,7 +494,6 @@ export default function AdopterList() { value={editing.notes || ""} onChange={handleEditChange} className={inputStyle(!!errors.notes)} - rows={3} />
diff --git a/src/pages/Adoption/AdoptionList.tsx b/src/pages/Adoption/AdoptionList.tsx index bb3a659..7405549 100644 --- a/src/pages/Adoption/AdoptionList.tsx +++ b/src/pages/Adoption/AdoptionList.tsx @@ -6,8 +6,8 @@ import { motion, AnimatePresence } from "framer-motion"; import { useAnimals } from "../../context/AnimalsContext"; import { deleteAdoptionById, getAdoptions, updateAdoption } from "../../services/adoptionService.ts"; import EditAdoptionForm from "../../Components/EditAdoptionForm/EditAdoptionForm.tsx"; -import {getAdopters} from "../../services/adopterService.ts"; -import {getStaff} from "../../services/staffService.ts"; +import { getAdopters } from "../../services/adopterService.ts"; +import { getStaff } from "../../services/staffService.ts"; export type Adoption = { id: string; @@ -37,6 +37,9 @@ export default function AdoptionList() { const [searchTerm, setSearchTerm] = useState(""); const navigate = useNavigate(); + const [currentPage, setCurrentPage] = useState(1); + const itemsPerPage = 8; + useEffect(() => { const fetchAdoptions = async () => { setLoading(true); @@ -140,9 +143,32 @@ export default function AdoptionList() { .some(field => field.toLowerCase().includes(searchTerm.toLowerCase())) ); + const totalPages = Math.max(1, Math.ceil(filteredAdoptions.length / itemsPerPage)); + const startIndex = (currentPage - 1) * itemsPerPage; + const endIndex = Math.min(filteredAdoptions.length, currentPage * itemsPerPage); + const paginatedAdoptions = filteredAdoptions.slice(startIndex, endIndex); + + const getPageNumbers = () => Array.from({ length: totalPages }).map((_, i) => i + 1); + + const goToPage = (page: number) => { + if (page < 1 || page > totalPages) return; + setCurrentPage(page); + window.scrollTo({ top: 0, behavior: "smooth" }); + }; + const prevPage = () => goToPage(currentPage - 1); + const nextPage = () => goToPage(currentPage + 1); + + useEffect(() => { + const tp = Math.max(1, Math.ceil(filteredAdoptions.length / itemsPerPage)); + if (currentPage > tp) setCurrentPage(tp); + }, [currentPage, filteredAdoptions.length]); + + useEffect(() => { + setCurrentPage(1); + }, [searchTerm]); + return (
- {/* Header */}

Adoções

@@ -161,67 +187,104 @@ export default function AdoptionList() {
- {/* Lista */} {loading ? (
- {[...Array(6)].map((_, i) => ( + {[...Array(itemsPerPage)].map((_, i) => (
))}
) : filteredAdoptions.length === 0 ? (
Nenhuma adoção encontrada.
) : ( -
- {filteredAdoptions.map(a => { - const animalData = animals.find(an => an.id === a.animalId); - return ( -
-
- {animalData?.image ? ( - {a.animalName} - ) : ( - Animal - )} -
+ <> +
+ {paginatedAdoptions.map(a => { + const animalData = animals.find(an => an.id === a.animalId); + return ( +
+
+ {animalData?.image ? ( + {a.animalName} + ) : ( + Animal + )} +
+ +
+
+
+
+

{a.animalName}

+ + {a.status} + +
+

Adotante: {a.adopterName}

+

Responsável: {a.employeeName}

-
-
-

{a.animalName}

- - {a.status} - -
-

Adotante: {a.adopterName}

-

Responsável: {a.employeeName}

- -
-
- ); - })} -
+ ); + })} +
+ +
+
+ + + {getPageNumbers().map(n => ( + + ))} + + +
+ +
+ Mostrando {startIndex + 1}–{endIndex} de {filteredAdoptions.length} +
+
+ )} - {/* Modais */} {selectedAdoption && ( navigate("/health-card")} + onClick={() => navigate("/HealthCardList")} className="w-full sm:w-auto px-6 py-3 rounded-2xl bg-gray-600 text-white shadow hover:bg-gray-700 transition font-medium" > Carteiras de Saúde diff --git a/src/pages/Health/DewormingRegister/DewormingRegister.tsx b/src/pages/Health/DewormingRegister/DewormingRegister.tsx index 2277b14..f7c6fbd 100644 --- a/src/pages/Health/DewormingRegister/DewormingRegister.tsx +++ b/src/pages/Health/DewormingRegister/DewormingRegister.tsx @@ -323,7 +323,7 @@ export default function DewormingRegister() { navigate("/health-card")} + onClick={() => navigate("/HealthCardList")} className="w-full sm:w-auto px-6 py-3 rounded-2xl bg-gray-600 text-white shadow hover:bg-gray-700 transition font-medium" > Carteiras de Saúde diff --git a/src/pages/Health/HealthCardList/HealthCardList.tsx b/src/pages/Health/HealthCardList/HealthCardList.tsx index fa87ef2..9aa111a 100644 --- a/src/pages/Health/HealthCardList/HealthCardList.tsx +++ b/src/pages/Health/HealthCardList/HealthCardList.tsx @@ -1,3 +1,5 @@ +// typescript +// src/pages/Health/HealthCardList/HealthCardList.tsx import { useEffect, useState } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { Syringe, Shield, Pill, X, Trash2 } from "lucide-react"; @@ -8,10 +10,20 @@ import { getDewormings, deleteDewormingRecord } from "../../../services/dewormin import toast from "react-hot-toast"; import type {HealthRecord} from "../types/healthRecord.ts"; +type AnimalShort = { + id: string; + name: string; + image?: string; + birthDate?: string; + breed?: string; +}; + +type TimestampLike = Date | { toDate?: () => Date } | string | number | null | undefined; + export default function HealthCardList() { const { animals } = useAnimals(); const [searchTerm, setSearchTerm] = useState(""); - const [selectedAnimal, setSelectedAnimal] = useState(null); + const [selectedAnimal, setSelectedAnimal] = useState(null); const [animalHealth, setAnimalHealth] = useState<{ vaccines: HealthRecord[]; antiparasitics: HealthRecord[]; @@ -22,6 +34,10 @@ export default function HealthCardList() { dewormings: [], }); + const [loading, setLoading] = useState(true); + const [currentPage, setCurrentPage] = useState(1); + const itemsPerPage = 8; + useEffect(() => { const fetchHealthData = async () => { try { @@ -38,6 +54,8 @@ export default function HealthCardList() { } catch (err) { console.error(err); toast.error("Erro ao carregar dados de saúde."); + } finally { + setLoading(false); } }; fetchHealthData(); @@ -49,6 +67,18 @@ export default function HealthCardList() { a.breed?.toLowerCase().includes(searchTerm.toLowerCase()) ); + const totalPages = Math.max(1, Math.ceil(filteredAnimals.length / itemsPerPage)); + const paginatedAnimals = filteredAnimals.slice((currentPage - 1) * itemsPerPage, currentPage * itemsPerPage); + + useEffect(() => { + const tp = Math.max(1, Math.ceil(filteredAnimals.length / itemsPerPage)); + if (currentPage > tp) setCurrentPage(tp); + }, [currentPage, filteredAnimals.length]); + + useEffect(() => { + setCurrentPage(1); + }, [searchTerm]); + const calcularIdade = (birthDate?: string) => { if (!birthDate) return "Não informado"; const nascimento = new Date(birthDate); @@ -62,12 +92,17 @@ export default function HealthCardList() { return anos > 0 ? `${anos} ano${anos !== 1 ? "s" : ""}` : `${meses} mês${meses !== 1 ? "es" : ""}`; }; - const formatDate = (timestamp?: any) => { + const isWithToDate = (t: unknown): t is { toDate: () => Date } => + typeof t === "object" && t !== null && typeof (t as { toDate?: unknown }).toDate === "function"; + + const formatDate = (timestamp?: TimestampLike) => { if (!timestamp) return "-"; - const date = - timestamp.toDate?.() instanceof Date - ? timestamp.toDate() - : new Date(timestamp); + let date: Date; + if (isWithToDate(timestamp)) { + date = timestamp.toDate(); + } else { + date = new Date(timestamp as string | number | Date); + } return date.toLocaleDateString("pt-BR"); }; @@ -80,7 +115,6 @@ export default function HealthCardList() { const getAnimalDewormings = (id: string) => animalHealth.dewormings.filter((d) => d.animalId === id); - // Funções de remoção const handleDelete = async (type: "vaccine" | "antiparasitic" | "deworming", id: string) => { if (!window.confirm("Tem certeza que deseja remover este registro?")) return; @@ -111,6 +145,14 @@ export default function HealthCardList() { } }; + const startIndex = (currentPage - 1) * itemsPerPage; + const endIndex = Math.min(filteredAnimals.length, currentPage * itemsPerPage); + + const getPageNumbers = () => { + return Array.from({ length: totalPages }).map((_, i) => i + 1); + }; + + return (
@@ -123,68 +165,113 @@ export default function HealthCardList() { />
- {filteredAnimals.length === 0 ? ( + {loading ? ( +
+ {Array.from({ length: itemsPerPage }).map((_, i) => ( +
+ ))} +
+ ) : filteredAnimals.length === 0 ? (
Nenhum animal encontrado.
) : ( -
- {filteredAnimals.map((animal) => { - const vaccines = getAnimalVaccines(animal.id); - const antiparasitics = getAnimalAntiparasitics(animal.id); - const dewormings = getAnimalDewormings(animal.id); - - return ( -
-
- {animal.image ? ( - {animal.name} - ) : ( - Sem imagem - )} -
-
-

- {animal.name} -

-

- {calcularIdade(animal.birthDate)} •{" "} - {animal.breed || "-"} -

- -
-
- - {vaccines.length} vacinas -
-
- - {antiparasitics.length} antiparasitários -
-
- - {dewormings.length} vermífugos -
+ <> +
+ {paginatedAnimals.map((animal) => { + const vaccines = getAnimalVaccines(animal.id); + const antiparasitics = getAnimalAntiparasitics(animal.id); + const dewormings = getAnimalDewormings(animal.id); + + return ( +
+
+ {animal.image ? ( + {animal.name} + ) : ( + Sem imagem + )}
+
+

+ {animal.name} +

+

+ {calcularIdade(animal.birthDate)} •{" "} + {animal.breed || "-"} +

+ +
+
+ + {vaccines.length} vacinas +
+
+ + {antiparasitics.length} antiparasitários +
+
+ + {dewormings.length} vermífugos +
+
- + +
-
- ); - })} -
+ ); + })} +
+ +
+
+ + + {getPageNumbers().map(n => ( + + ))} + + +
+ +
+ Mostrando {startIndex + 1}–{endIndex} de {filteredAnimals.length} +
+
+ )} @@ -212,7 +299,6 @@ export default function HealthCardList() { {selectedAnimal.name} — Carteira de Saúde - {/* Vacinas */}

Vacinas @@ -244,7 +330,6 @@ export default function HealthCardList() {

- {/* Antiparasitários */}

Antiparasitários @@ -276,7 +361,6 @@ export default function HealthCardList() {

- {/* Vermífugos */}

Vermífugos @@ -322,4 +406,4 @@ export default function HealthCardList() {

); -} +} \ No newline at end of file diff --git a/src/pages/Health/Vaccine/VaccineRegister.tsx b/src/pages/Health/Vaccine/VaccineRegister.tsx index e896190..5c1e4c5 100644 --- a/src/pages/Health/Vaccine/VaccineRegister.tsx +++ b/src/pages/Health/Vaccine/VaccineRegister.tsx @@ -310,7 +310,7 @@ export default function VaccineRegister() { navigate("/health-card")} + onClick={() => navigate("/HealthCardList")} className="w-full sm:w-auto px-6 py-3 rounded-2xl bg-gray-600 text-white shadow hover:bg-gray-700 transition font-medium" > Carteiras de Saúde