-
Hello Rigo!!
diff --git a/src/front/pages/MedicalAppointmentDetail.jsx b/src/front/pages/MedicalAppointmentDetail.jsx
new file mode 100644
index 0000000000..c4e8813f2c
--- /dev/null
+++ b/src/front/pages/MedicalAppointmentDetail.jsx
@@ -0,0 +1,216 @@
+import React, { useState, useEffect } from "react";
+import { useParams, Link, useNavigate } from "react-router-dom";
+
+export const MedicalAppointmentDetail = () => {
+ const { id } = useParams();
+ const navigate = useNavigate();
+ const backendUrl = import.meta.env.VITE_BACKEND_URL;
+
+ const [loading, setLoading] = useState(true);
+ const [users, setUsers] = useState([]);
+ const [pets, setPets] = useState([]);
+ const [veterinarians, setVeterinarians] = useState([]);
+
+ const [appointment, setAppointment] = useState({
+ user_id: "",
+ pet_id: "",
+ veterinarian_id: "",
+ date: "",
+ hour: "",
+ comments: ""
+ });
+
+ useEffect(() => {
+ const fetchData = async () => {
+ try {
+ const [resAppt, resUsers, resPets, resVets] = await Promise.all([
+ fetch(`${backendUrl}/api/medical-appointments/${id}`),
+ fetch(`${backendUrl}/api/user`),
+ fetch(`${backendUrl}/api/pets`),
+ fetch(`${backendUrl}/api/veterinarians`)
+ ]);
+
+ if (resUsers.ok) setUsers(await resUsers.json());
+ if (resPets.ok) setPets(await resPets.json());
+ if (resVets.ok) setVeterinarians(await resVets.json());
+
+ if (resAppt.ok) {
+ const data = await resAppt.json();
+ setAppointment({
+ user_id: data.user_id || data.idUser || "",
+ pet_id: data.pet_id || data.idPet || "",
+ veterinarian_id: data.veterinarian_id || data.idVeterinarian || "",
+ date: data.date || "",
+ hour: data.hour || "",
+ comments: data.comments || ""
+ });
+ }
+ } catch (error) {
+ console.error("Error fetching data:", error);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchData();
+ }, [id, backendUrl]);
+
+ const handleChange = (e) => {
+ const { name, value } = e.target;
+ setAppointment({
+ ...appointment,
+ [name]: value
+ });
+ };
+
+ const handleSave = async (e) => {
+ e.preventDefault();
+
+ const payload = {
+ user_id: appointment.user_id ? Number(appointment.user_id) : null,
+ idUser: appointment.user_id ? Number(appointment.user_id) : null,
+ pet_id: appointment.pet_id ? Number(appointment.pet_id) : null,
+ idPet: appointment.pet_id ? Number(appointment.pet_id) : null,
+ veterinarian_id: appointment.veterinarian_id ? Number(appointment.veterinarian_id) : null,
+ idVeterinarian: appointment.veterinarian_id ? Number(appointment.veterinarian_id) : null,
+ date: appointment.date,
+ hour: appointment.hour,
+ comments: appointment.comments
+ };
+
+ try {
+ const response = await fetch(`${backendUrl}/api/medical-appointments/${id}`, {
+ method: "PUT",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify(payload)
+ });
+
+ if (response.ok) {
+ alert("Medical appointment updated successfully!");
+ navigate("/medapps");
+ } else {
+ const errorData = await response.json();
+ console.error("Error del servidor:", errorData);
+ alert("Failed to update medical appointment");
+ }
+ } catch (error) {
+ console.error("Error updating medical appointment:", error);
+ }
+ };
+
+ if (loading) {
+ return (
+
+
Loading medical appointment details...
+
+ );
+ }
+
+ return (
+
+
+ ← Back to Medical Appointments List
+
+
+
+
Edit Medical Appointment
+
+
+
+
+ );
+};
\ No newline at end of file
diff --git a/src/front/pages/MedicalAppointmentView.jsx b/src/front/pages/MedicalAppointmentView.jsx
new file mode 100644
index 0000000000..da202e7d67
--- /dev/null
+++ b/src/front/pages/MedicalAppointmentView.jsx
@@ -0,0 +1,158 @@
+import React, { useState, useEffect } from "react";
+import { useParams, Link } from "react-router-dom";
+
+export const MedicalAppointmentView = () => {
+ const { id } = useParams();
+ const backendUrl = import.meta.env.VITE_BACKEND_URL;
+
+ const [loading, setLoading] = useState(true);
+ const [users, setUsers] = useState([]);
+ const [pets, setPets] = useState([]);
+ const [veterinarians, setVeterinarians] = useState([]);
+
+ const [appointment, setAppointment] = useState({
+ user_id: "",
+ pet_id: "",
+ veterinarian_id: "",
+ date: "",
+ hour: "",
+ comments: ""
+ });
+
+ useEffect(() => {
+ const fetchData = async () => {
+ try {
+ const [resAppt, resUsers, resPets, resVets] = await Promise.all([
+ fetch(`${backendUrl}/api/medical-appointments/${id}`),
+ fetch(`${backendUrl}/api/user`),
+ fetch(`${backendUrl}/api/pets`),
+ fetch(`${backendUrl}/api/veterinarians`)
+ ]);
+
+ if (resUsers.ok) setUsers(await resUsers.json());
+ if (resPets.ok) setPets(await resPets.json());
+ if (resVets.ok) setVeterinarians(await resVets.json());
+
+ if (resAppt.ok) {
+ const data = await resAppt.json();
+ setAppointment({
+ user_id: data.user_id || data.idUser || "",
+ pet_id: data.pet_id || data.idPet || "",
+ veterinarian_id: data.veterinarian_id || data.idVeterinarian || "",
+ date: data.date || "",
+ hour: data.hour || "",
+ comments: data.comments || ""
+ });
+ }
+ } catch (error) {
+ console.error("Error fetching data:", error);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchData();
+ }, [id, backendUrl]);
+
+ if (loading) {
+ return (
+
+
Loading medical appointment details...
+
+ );
+ }
+
+ return (
+
+
+ ← Back to Medical Appointments List
+
+
+
+
View Medical Appointment
+
+
+
+
+ );
+};
\ No newline at end of file
diff --git a/src/front/pages/MedicalAppointmentsList.jsx b/src/front/pages/MedicalAppointmentsList.jsx
new file mode 100644
index 0000000000..0a0c6f4693
--- /dev/null
+++ b/src/front/pages/MedicalAppointmentsList.jsx
@@ -0,0 +1,89 @@
+import React, { useState, useEffect } from "react";
+import { Link } from "react-router-dom";
+import { MedicalAppointmentCard } from "../components/MedicalAppointmentCard";
+
+export const MedicalAppointmentsList = () => {
+ const [appointments, setAppointments] = useState([]);
+ const [users, setUsers] = useState([]);
+ const [pets, setPets] = useState([]);
+ const [veterinarians, setVeterinarians] = useState([]);
+
+ const backendUrl = import.meta.env.VITE_BACKEND_URL;
+
+ const fetchAppointments = async () => {
+ try {
+ const response = await fetch(`${backendUrl}/api/medical-appointments`);
+ if (response.ok) {
+ const data = await response.json();
+ setAppointments(data);
+ }
+ } catch (error) {
+ console.error("Error fetching medical appointments:", error);
+ }
+ };
+
+ const fetchRelatedData = async () => {
+ try {
+ const [resUsers, resPets, resVeterinarians] = await Promise.all([
+ fetch(`${backendUrl}/api/user`),
+ fetch(`${backendUrl}/api/pets`),
+ fetch(`${backendUrl}/api/veterinarians`)
+ ]);
+
+ if (resUsers.ok) setUsers(await resUsers.json());
+ if (resPets.ok) setPets(await resPets.json());
+ if (resVeterinarians.ok) setVeterinarians(await resVeterinarians.json());
+ } catch (error) {
+ console.error("Error fetching related data:", error);
+ }
+ };
+
+ useEffect(() => {
+ fetchAppointments();
+ fetchRelatedData();
+ }, []);
+
+ const handleDelete = async (id) => {
+ if (!window.confirm("Are you sure you want to delete this medical appointment?")) return;
+
+ try {
+ const response = await fetch(`${backendUrl}/api/medical-appointments/${id}`, {
+ method: "DELETE"
+ });
+
+ if (response.ok) {
+ fetchAppointments();
+ }
+ } catch (error) {
+ console.error("Error deleting medical appointment:", error);
+ }
+ };
+
+ return (
+
+
+
Medical Appointments List
+
+ + Create Medical Appointment
+
+
+
+ {appointments.length === 0 ? (
+
No medical appointments registered yet.
+ ) : (
+
+ {appointments.map((appointment) => (
+
+ ))}
+
+ )}
+
+ );
+};
\ No newline at end of file
diff --git a/src/front/pages/PetDetail.jsx b/src/front/pages/PetDetail.jsx
new file mode 100644
index 0000000000..e6f6df6c77
--- /dev/null
+++ b/src/front/pages/PetDetail.jsx
@@ -0,0 +1,197 @@
+import React, { useState, useEffect } from "react";
+import { useParams, Link, useNavigate } from "react-router-dom";
+
+export const PetDetail = () => {
+ const { id } = useParams();
+ const navigate = useNavigate();
+ const backendUrl = import.meta.env.VITE_BACKEND_URL;
+
+ const [loading, setLoading] = useState(true);
+ const [pet, setPet] = useState({
+ name: "",
+ genre: "male",
+ birthDate: "",
+ castrated: false,
+ chipNumber: "",
+ color: "",
+ photoUrl: "",
+ size: "medium",
+ idUser: "",
+ idShelter: "",
+ idBreed: ""
+ });
+
+ useEffect(() => {
+ const fetchPetDetail = async () => {
+ try {
+ const response = await fetch(`${backendUrl}/api/pets/${id}`);
+ if (response.ok) {
+ const data = await response.json();
+ setPet({
+ ...data,
+ birthDate: data.birthDate || "",
+ chipNumber: data.chipNumber || "",
+ photoUrl: data.photoUrl || ""
+ });
+ }
+ } catch (error) {
+ console.error("Error fetching pet details:", error);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchPetDetail();
+ }, [id, backendUrl]);
+
+ const handleChange = (e) => {
+ const { name, value, type, checked } = e.target;
+ setPet({
+ ...pet,
+ [name]: type === "checkbox" ? checked : value
+ });
+ };
+
+ const handleSave = async (e) => {
+ e.preventDefault();
+ try {
+ const response = await fetch(`${backendUrl}/api/pets/${id}`, {
+ method: "PUT",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify(pet)
+ });
+
+ if (response.ok) {
+ alert("Pet updated successfully!");
+ navigate("/pets");
+ } else {
+ alert("Failed to update pet");
+ }
+ } catch (error) {
+ console.error("Error updating pet:", error);
+ }
+ };
+
+ if (loading) {
+ return (
+
+
Loading pet details...
+
+ );
+ }
+
+ return (
+
+
+ ← Back to Pets List
+
+
+
+
Edit Pet
+
+
+
+
+ );
+};
\ No newline at end of file
diff --git a/src/front/pages/PetView.jsx b/src/front/pages/PetView.jsx
new file mode 100644
index 0000000000..cba2678114
--- /dev/null
+++ b/src/front/pages/PetView.jsx
@@ -0,0 +1,82 @@
+import React, { useState, useEffect } from "react";
+import { useParams, Link } from "react-router-dom";
+
+export const PetView = () => {
+ const { id } = useParams();
+ const backendUrl = import.meta.env.VITE_BACKEND_URL;
+
+ const [loading, setLoading] = useState(true);
+ const [pet, setPet] = useState(null);
+
+ useEffect(() => {
+ const fetchPetDetail = async () => {
+ try {
+ const response = await fetch(`${backendUrl}/api/pets/${id}`);
+ if (response.ok) {
+ const data = await response.json();
+ setPet(data);
+ }
+ } catch (error) {
+ console.error("Error fetching pet details:", error);
+ } finally {
+ setLoading(false);
+ }
+ };
+
+ fetchPetDetail();
+ }, [id, backendUrl]);
+
+ if (loading) {
+ return (
+
+
Loading pet details...
+
+ );
+ }
+
+ if (!pet) {
+ return (
+
+
Pet not found.
+
+ ← Back to Pets List
+
+
+ );
+ }
+
+ return (
+
+
+ ← Back to Pets List
+
+
+
+
+ {pet.photoUrl && (
+
+

+
+ )}
+
+
+
{pet.name}
+
+
Gender: {pet.genre}
+
Size: {pet.size}
+
Color: {pet.color}
+
Birth Date: {pet.birthDate || "Not provided"}
+
Chip Number: {pet.chipNumber || "No chip"}
+
Castrated: {pet.castrated ? "Yes" : "No"}
+
+
+
+
+
+ );
+};
\ No newline at end of file
diff --git a/src/front/pages/PetsList.jsx b/src/front/pages/PetsList.jsx
new file mode 100644
index 0000000000..12982a3a64
--- /dev/null
+++ b/src/front/pages/PetsList.jsx
@@ -0,0 +1,61 @@
+import React, { useState, useEffect } from "react";
+import { Link } from "react-router-dom";
+import { PetCard } from "../components/PetCard";
+
+export const PetsList = () => {
+ const [pets, setPets] = useState([]);
+ const backendUrl = import.meta.env.VITE_BACKEND_URL;
+
+ const fetchPets = async () => {
+ try {
+ const response = await fetch(`${backendUrl}/api/pets`);
+ if (response.ok) {
+ const data = await response.json();
+ setPets(data);
+ }
+ } catch (error) {
+ console.error("Error fetching pets:", error);
+ }
+ };
+
+ useEffect(() => {
+ fetchPets();
+ }, []);
+
+ const handleDelete = async (id) => {
+ if (!window.confirm("Are you sure you want to delete this pet?")) return;
+
+ try {
+ const response = await fetch(`${backendUrl}/api/pets/${id}`, {
+ method: "DELETE"
+ });
+
+ if (response.ok) {
+ fetchPets();
+ }
+ } catch (error) {
+ console.error("Error deleting pet:", error);
+ }
+ };
+
+ return (
+
+
+
Pets List
+
+ + Create Pet
+
+
+
+ {pets.length === 0 ? (
+
No pets registered yet.
+ ) : (
+
+ {pets.map((pet) => (
+
+ ))}
+
+ )}
+
+ );
+};
\ No newline at end of file
diff --git a/src/front/pages/Shelter.jsx b/src/front/pages/Shelter.jsx
new file mode 100644
index 0000000000..5dc7bf556d
--- /dev/null
+++ b/src/front/pages/Shelter.jsx
@@ -0,0 +1,71 @@
+import { Link, useActionData } from "react-router-dom";
+import { useEffect, useState } from "react";
+import rigoImageUrl from "../assets/img/rigo-baby.jpg";
+import useGlobalReducer from "../hooks/useGlobalReducer.jsx";
+import { CardShelter } from "../components/CardShelter.jsx";
+
+
+export const Shelter = () => {
+
+const [shelter, setShelter] = useState([]);
+ const backendUrl = import.meta.env.VITE_BACKEND_URL;
+
+ const fetchShelter = async () => {
+ try {
+ const response = await fetch(`${backendUrl}/api/shelter`);
+ if (response.ok) {
+ const data = await response.json();
+ setShelter(data);
+ }
+ } catch (error) {
+ console.error("Error fetching shelters:", error);
+ }
+ };
+
+const handleDeleteShelter = (id) => {
+ setShelter(prev => prev.filter(item => item.id !== id));
+};
+
+
+ useEffect(() => {
+ fetchShelter();
+ }, []);
+
+
+
+ return (
+ <>
+
+
+
+
Refugios
+
+ {shelter.map((shelter, index) => (
+
+
+
+
+ ))}
+
+
+
+
+
+
+ Back home
+
+
+ >
+ );
+};
\ No newline at end of file
diff --git a/src/front/pages/User.jsx b/src/front/pages/User.jsx
new file mode 100644
index 0000000000..c67873014d
--- /dev/null
+++ b/src/front/pages/User.jsx
@@ -0,0 +1,72 @@
+import { Link, useActionData } from "react-router-dom";
+import { useEffect, useState } from "react";
+import rigoImageUrl from "../assets/img/rigo-baby.jpg";
+import useGlobalReducer from "../hooks/useGlobalReducer.jsx";
+//import { Link } from "react-router-dom";
+import { CardUser } from "../components/CardUser.jsx";
+
+
+export const User = () => {
+
+const [user, setUser] = useState([]);
+ const backendUrl = import.meta.env.VITE_BACKEND_URL;
+
+ const fetchUser = async () => {
+ try {
+ const response = await fetch(`${backendUrl}/api/user`);
+ if (response.ok) {
+ const data = await response.json();
+ setUser(data);
+ }
+ } catch (error) {
+ console.error("Error fetching user:", error);
+ }
+ };
+
+const handleDeleteUser = (id) => {
+ setUser(prev => prev.filter(item => item.id !== id));
+};
+
+
+ useEffect(() => {
+ fetchUser();
+ }, []);
+
+
+
+ return (
+ <>
+
+
+
+
Usuarios
+
+ {user.map((user, index) => (
+
+
+
+
+ ))}
+
+
+
+
+
+
+ Back home
+
+
+ >
+ );
+};
\ No newline at end of file
diff --git a/src/front/routes.jsx b/src/front/routes.jsx
index 0557df6141..2ac8df3f88 100644
--- a/src/front/routes.jsx
+++ b/src/front/routes.jsx
@@ -1,30 +1,67 @@
// Import necessary components and functions from react-router-dom.
import {
- createBrowserRouter,
- createRoutesFromElements,
- Route,
+ createBrowserRouter,
+ createRoutesFromElements,
+ Route,
} from "react-router-dom";
+
import { Layout } from "./pages/Layout";
-import { Home } from "./pages/Home";
+import Breed from "./pages/Breed";
+import CreateBreed from "./pages/CreateBreed";
+import EditBreed from "./pages/EditBreed";
import { Single } from "./pages/Single";
import { Demo } from "./pages/Demo";
+import { Form } from "./pages/Form";
+import { Shelter } from "./pages/Shelter";
+import { User } from "./pages/User";
+import { PetsList } from "./pages/PetsList";
+import { CreatePet } from "./pages/CreatePet";
+import { PetDetail } from "./pages/PetDetail";
+import { PetView } from "./pages/PetView";
+import { Home } from "./pages/Home";
+import { AdoptionsList } from "./pages/AdoptionsList";
+import { CreateAdoption } from "./pages/CreateAdoption";
+import { AdoptionDetail } from "./pages/AdoptionDetail";
+import { MedicalAppointmentsList } from "./pages/MedicalAppointmentsList";
+import { CreateMedicalAppointment } from "./pages/CreateMedicalAppointment";
+import { MedicalAppointmentDetail } from "./pages/MedicalAppointmentDetail";
+import { MedicalAppointmentView } from "./pages/MedicalAppointmentView";
+import { AdoptionView } from "./pages/AdoptionView";
export const router = createBrowserRouter(
- createRoutesFromElements(
+ createRoutesFromElements(
// CreateRoutesFromElements function allows you to build route elements declaratively.
// Create your routes here, if you want to keep the Navbar and Footer in all views, add your new routes inside the containing Route.
// Root, on the contrary, create a sister Route, if you have doubts, try it!
// Note: keep in mind that errorElement will be the default page when you don't get a route, customize that page to make your project more attractive.
// Note: The child paths of the Layout element replace the Outlet component with the elements contained in the "element" attribute of these child paths.
- // Root Route: All navigation will start from here.
-
} errorElement={
Not found!
} >
-
- {/* Nested Routes: Defines sub-routes within the BaseHome component. */}
-
} />
-
} /> {/* Dynamic route for single items */}
-
} />
-
- )
+ // Root Route: All navigation will start from here.
+
} errorElement={
Not found!
} >
+
} />
+
} />
+
} />
+
} />
+
} />
+
} />
+
} />
+
} />
+
} />
+
} />
+
} />
+
} />
+
} />
+
} />
+
} />
+
} />
+
} />
+
} />
+
} />
+
} />
+
} />
+
} />
+
} />
+
+ )
);
\ No newline at end of file
diff --git a/src/front/store.js b/src/front/store.js
index 3062cd222d..5a562dab8f 100644
--- a/src/front/store.js
+++ b/src/front/store.js
@@ -1,4 +1,4 @@
-export const initialStore=()=>{
+/* export const initialStore=()=>{
return{
message: null,
todos: [
@@ -14,7 +14,16 @@ export const initialStore=()=>{
}
]
}
-}
+} */
+
+
+export const initialStore = () => {
+ return {
+ shelters: [],
+
+ };
+};
+
export default function storeReducer(store, action = {}) {
switch(action.type){
@@ -32,7 +41,15 @@ export default function storeReducer(store, action = {}) {
...store,
todos: store.todos.map((todo) => (todo.id === id ? { ...todo, background: color } : todo))
};
+
+ case "load_data": {
+ const { nuevosShelters } = action.payload; //es la informacion que tu das para que se haga lo que haya en el case, por ejemplo un ID, que te permitirá hacer "algo"
+ return {
+ ...store,
+ shelters: nuevosShelters
+ };
+ }
default:
throw Error('Unknown action.');
}
-}
+}
\ No newline at end of file
diff --git a/vite.config.js b/vite.config.js
index a93495e81e..e925c421df 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -1,14 +1,19 @@
-import {
- defineConfig
-} from 'vite'
-import react from '@vitejs/plugin-react'
+import { defineConfig } from "vite";
+import react from "@vitejs/plugin-react";
export default defineConfig({
- plugins: [react()],
- server: {
- port: 3000
+ plugins: [react()],
+ server: {
+ host: "0.0.0.0",
+ port: 3000,
+ proxy: {
+ "/api": {
+ target: "http://127.0.0.1:3001",
+ changeOrigin: true,
+ },
},
- build: {
- outDir: 'dist'
- }
-})
\ No newline at end of file
+ },
+ build: {
+ outDir: "dist",
+ },
+});