Loading pet details...
} + {error &&{error}
} + + {!loading && !error && pet && ( +diff --git a/backend/src/main/java/com/petshop/backend/security/SecurityConfig.java b/backend/src/main/java/com/petshop/backend/security/SecurityConfig.java
index 00ce63f8..d26e3e84 100644
--- a/backend/src/main/java/com/petshop/backend/security/SecurityConfig.java
+++ b/backend/src/main/java/com/petshop/backend/security/SecurityConfig.java
@@ -17,6 +17,11 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.CorsConfigurationSource;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+
+import java.util.List;
@Configuration
@EnableWebSecurity
@@ -28,12 +33,10 @@ public class SecurityConfig {
private final RestAuthenticationEntryPoint restAuthenticationEntryPoint;
private final RestAccessDeniedHandler restAccessDeniedHandler;
- public SecurityConfig(
- JwtAuthenticationFilter jwtAuthFilter,
+ public SecurityConfig(JwtAuthenticationFilter jwtAuthFilter,
UserDetailsService userDetailsService,
RestAuthenticationEntryPoint restAuthenticationEntryPoint,
- RestAccessDeniedHandler restAccessDeniedHandler
- ) {
+ RestAccessDeniedHandler restAccessDeniedHandler) {
this.jwtAuthFilter = jwtAuthFilter;
this.userDetailsService = userDetailsService;
this.restAuthenticationEntryPoint = restAuthenticationEntryPoint;
@@ -42,7 +45,7 @@ public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
- http
+ http.cors(cors -> cors.configurationSource(corsConfigurationSource()))
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/v1/auth/login", "/api/v1/auth/register").permitAll()
@@ -56,8 +59,7 @@ public class SecurityConfig {
.requestMatchers(HttpMethod.GET, "/api/v1/appointments/availability").permitAll()
.anyRequest().authenticated()
)
- .exceptionHandling(ex -> ex
- .authenticationEntryPoint(restAuthenticationEntryPoint)
+ .exceptionHandling(ex -> ex.authenticationEntryPoint(restAuthenticationEntryPoint)
.accessDeniedHandler(restAccessDeniedHandler)
)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
@@ -70,16 +72,32 @@ public class SecurityConfig {
private DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider(userDetailsService);
authProvider.setPasswordEncoder(passwordEncoder());
+
return authProvider;
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
+
return new ProviderManager(daoAuthenticationProvider());
}
+ @Bean
+ public CorsConfigurationSource corsConfigurationSource() {
+ CorsConfiguration config = new CorsConfiguration();
+ config.setAllowedOriginPatterns(List.of("http://localhost:*", "http://127.0.0.1:*"));
+ config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
+ config.setAllowedHeaders(List.of("*"));
+ config.setAllowCredentials(true);
+ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+ source.registerCorsConfiguration("/**", config);
+
+ return source;
+ }
+
@Bean
public PasswordEncoder passwordEncoder() {
+
return new BCryptPasswordEncoder();
}
}
diff --git a/web/app/adopt/[id]/page.js b/web/app/adopt/[id]/page.js
new file mode 100644
index 00000000..21a24aa4
--- /dev/null
+++ b/web/app/adopt/[id]/page.js
@@ -0,0 +1,52 @@
+"use client";
+
+import Link from "next/link";
+import { useState, useEffect } from "react";
+import { useParams } from "next/navigation";
+import PetProfile from "@/components/PetProfile";
+
+const API_BASE = "";
+
+export default function PetDetailPage() {
+ const { id } = useParams();
+ const [pet, setPet] = useState(null);
+ const [loading, setLoading] = useState(true);
+ const [error, setError] = useState(null);
+
+ useEffect(() => {
+ if (!id) return;
+ setLoading(true);
+ setError(null);
+
+ fetch(`${API_BASE}/api/v1/pets/${id}`)
+ .then((res) => {
+ if (!res.ok) throw new Error(`HTTP ${res.status} – ${res.statusText}`);
+ return res.json();
+ })
+ .then((data) => setPet(data))
+ .catch((err) => setError(err.message))
+ .finally(() => setLoading(false));
+ }, [id]);
+
+ return (
+ Loading pet details... {error} Give a loving pet their forever home Loading pets... Failed to load pets
+ {health === "offline"
+ ? "The Spring Boot backend is not reachable. Make sure it is running in IntelliJ on port 8080."
+ : health === "error"
+ ? "The backend responded with an error. Check the IntelliJ Run console for stack traces."
+ : "The backend is reachable but the /pets endpoint failed. Check the IntelliJ Run console."}
+ No pets found.Find Your Perfect Companion
+ {error}
+
Your One-Stop Shop for All Things Pets
Loading…
{petSpecies}
+ + {petStatus} + ++ Interested in adopting {petName}? Visit us in store or schedule an appointment. +
+ + Schedule an Appointment + +