Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"lucide-react": "^0.542.0",
"react": "^19.1.1",
"react-dom": "^19.1.1",
"react-hot-toast": "^2.6.0",
"react-icons": "^5.5.0",
"react-router-dom": "^7.8.2",
"tailwindcss": "^4.1.12"
Expand Down
5 changes: 4 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import AdoptionRegister from "./pages/AdoptionRegister.tsx";
import Login from "./pages/Login.tsx";
import PrivateRoute from "./routes/PrivateRoute";
import { AuthProvider } from "./context/AuthContext";
import type {JSX} from "react";
import { Toaster } from "react-hot-toast"; // <-- import do Toaster
import type { JSX } from "react";

const ProtectedLayout = ({ children }: { children: JSX.Element }) => (
<div className="flex h-screen bg-gray-100">
Expand All @@ -21,6 +22,8 @@ const ProtectedLayout = ({ children }: { children: JSX.Element }) => (
export default function App() {
return (
<AuthProvider>
<Toaster position="top-right" reverseOrder={false} />

<Router>
<Routes>
<Route path="/login" element={<Login />} />
Expand Down
56 changes: 37 additions & 19 deletions src/pages/AnimalList.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { useState, useEffect } from "react";
import { Plus, X, Trash2 } from "lucide-react";
import {useNavigate} from "react-router-dom";
import { getAnimals, deleteAnimalById } from "../services/animalService";
import toast from "react-hot-toast";

type Animal = {
id: number;
export type Animal = {
id: string;
name: string;
age: string;
birthDate?: string;
breed: string;
status: "Disponível" | "Adotado" | "Em tratamento";
image?: string;
Expand All @@ -19,16 +21,18 @@ export default function AnimalList() {
const navigate = useNavigate();

useEffect(() => {
setTimeout(() => {
setAnimals([
{ id: 1, name: "Lilica", age: "2 anos", breed: "Poodle", status: "Disponível" },
{ id: 2, name: "Rex", age: "3 anos", breed: "Vira-lata", status: "Adotado" },
{ id: 3, name: "Bolt", age: "1 ano", breed: "Labrador", status: "Em tratamento" },
{ id: 4, name: "Mia", age: "4 anos", breed: "Siamês", status: "Disponível" },
{ id: 5, name: "Thor", age: "5 anos", breed: "Pastor Alemão", status: "Disponível" },
]);
setLoading(false);
}, 1000);
const fetchData = async () => {
try {
const data = await getAnimals();
setAnimals(data as Animal[]);
} catch (error) {
console.error("Erro ao buscar animais:", error);
} finally {
setLoading(false);
}
};

fetchData();
}, []);

const getStatusStyle = (status: Animal["status"]) => {
Expand All @@ -39,14 +43,27 @@ export default function AnimalList() {
}
};

const confirmDelete = () => {
const confirmDelete = async () => {
if (deleteAnimal) {
setAnimals(prev => prev.filter(a => a.id !== deleteAnimal.id));
if (selectedAnimal?.id === deleteAnimal.id) setSelectedAnimal(null);
await deleteAnimalById(deleteAnimal.id);
setAnimals((prev) => prev.filter((a) => a.id !== deleteAnimal.id));
setDeleteAnimal(null);
toast.success("Animal removido com sucesso!");
}
};

function calcularIdade(birthDate?: string): string {
if (!birthDate) return "Não informado";
const nascimento = new Date(birthDate);
const hoje = new Date();
let idade = hoje.getFullYear() - nascimento.getFullYear();
const m = hoje.getMonth() - nascimento.getMonth();
if (m < 0 || (m === 0 && hoje.getDate() < nascimento.getDate())) {
idade--;
}
return `${idade} ano${idade !== 1 ? "s" : ""}`;
}

return (
<div className="p-6 flex flex-col gap-6">
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4">
Expand Down Expand Up @@ -115,8 +132,9 @@ export default function AnimalList() {
{animal.status}
</span>
</div>
<p className="text-sm text-gray-600">{animal.age} • {animal.breed}</p>
<button
<p className="text-sm text-gray-600">
{calcularIdade(animal.birthDate)} • {animal.breed}
</p> <button
onClick={() => setSelectedAnimal(animal)}
className="w-full mt-2 px-3 py-2 border border-gray-200 rounded-xl hover:bg-gray-100 transition text-sm font-medium"
>
Expand Down Expand Up @@ -162,7 +180,7 @@ export default function AnimalList() {
</div>

<h2 className="text-xl font-bold text-gray-800 mb-2">{selectedAnimal.name}</h2>
<p className="text-gray-600 mb-1"><strong>Idade:</strong> {selectedAnimal.age}</p>
<p className="text-gray-600 mb-1"><strong>Idade:</strong> {calcularIdade(selectedAnimal.birthDate)}</p>
<p className="text-gray-600 mb-1"><strong>Raça:</strong> {selectedAnimal.breed}</p>
<p className="text-gray-600 mb-1">
<strong>Status:</strong>{" "}
Expand Down
Loading