} />
diff --git a/src/pages/AnimalList.tsx b/src/pages/AnimalList.tsx
index a3e893d..f43bd4b 100644
--- a/src/pages/AnimalList.tsx
+++ b/src/pages/AnimalList.tsx
@@ -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;
@@ -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"]) => {
@@ -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 (
@@ -115,8 +132,9 @@ export default function AnimalList() {
{animal.status}
-
{animal.age} • {animal.breed}
-
{selectedAnimal.name}
- Idade: {selectedAnimal.age}
+ Idade: {calcularIdade(selectedAnimal.birthDate)}
Raça: {selectedAnimal.breed}
Status:{" "}
diff --git a/src/pages/AnimalRegister.tsx b/src/pages/AnimalRegister.tsx
index 2443477..e7ed4d4 100644
--- a/src/pages/AnimalRegister.tsx
+++ b/src/pages/AnimalRegister.tsx
@@ -1,14 +1,14 @@
-import { useState } from "react";
+import React, { useState } from "react";
import { motion } from "framer-motion";
import { PawPrint, Save, Upload } from "lucide-react";
import { useNavigate } from "react-router-dom";
import { registerAnimal } from "../services/animalService";
+import toast from "react-hot-toast";
export default function AnimalRegister() {
const [preview, setPreview] = useState(null);
const [imageFile, setImageFile] = useState(null);
const [loading, setLoading] = useState(false);
-
const navigate = useNavigate();
const [formData, setFormData] = useState({
@@ -24,11 +24,14 @@ export default function AnimalRegister() {
notes: "",
});
+ const [errors, setErrors] = useState<{ [key: string]: string }>({});
+
const handleChange = (
e: React.ChangeEvent
) => {
const { name, value } = e.target;
setFormData({ ...formData, [name]: value });
+ setErrors({ ...errors, [name]: "" });
};
const handleImageChange = (e: React.ChangeEvent) => {
@@ -36,26 +39,57 @@ export default function AnimalRegister() {
if (file) {
setPreview(URL.createObjectURL(file));
setImageFile(file);
+ setErrors({ ...errors, image: "" });
}
};
+ const validate = () => {
+ const newErrors: { [key: string]: string } = {};
+ Object.entries(formData).forEach(([key, value]) => {
+ if (!value) newErrors[key] = "Campo obrigatório";
+ });
+ setErrors(newErrors);
+ return Object.keys(newErrors).length === 0;
+ };
+
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
- setLoading(true);
+ if (!validate()) return;
+ setLoading(true);
try {
await registerAnimal(formData, imageFile || undefined);
+ setFormData({
+ name: "",
+ birthDate: "",
+ sex: "",
+ color: "",
+ species: "",
+ breed: "",
+ rescueDate: "",
+ size: "",
+ status: "",
+ notes: "",
+ });
+ setImageFile(null);
+ setPreview(null);
+ setErrors({});
+ toast.success("Animal cadastrado com sucesso!");
} catch (err) {
- alert("Erro ao cadastrar animal.");
+ console.error(err);
+ toast.error("Erro ao cadastrar animal.");
} finally {
setLoading(false);
}
};
- const inputModern =
- "w-full px-4 py-3 rounded-xl bg-gray-100/70 shadow-sm " +
- "focus:ring-2 focus:ring-blue-500 focus:outline-none " +
- "transition placeholder-gray-400 text-gray-800";
+ const inputModern = (error?: boolean) =>
+ `w-full px-4 py-3 rounded-xl shadow-sm focus:ring-2 focus:outline-none transition placeholder-gray-400 text-gray-800 ` +
+ (error
+ ? "border-2 border-red-500 focus:ring-red-500 bg-red-50"
+ : "bg-gray-100/70 focus:ring-blue-500");
+
+ const errorStyle = "text-sm text-red-500 mt-1";
return (
@@ -78,15 +112,27 @@ export default function AnimalRegister() {
Informações do Animal
-
-
-
@@ -94,48 +140,74 @@ export default function AnimalRegister() {
Características
-
-
-
+
+
+
+ {errors.rescueDate && {errors.rescueDate}}
+
+
+
+
+ {errors.size && {errors.size}}
+
+
+
+
+ {errors.status && {errors.status}}
+
- Observações
-
+
+
+
+ {errors.notes && {errors.notes}}
+
-
+