diff --git a/event-planner/api/demo/src/main/java/com/api/demo/controllers/UserController.java b/event-planner/api/demo/src/main/java/com/api/demo/controllers/UserController.java index adc6219..7483f96 100644 --- a/event-planner/api/demo/src/main/java/com/api/demo/controllers/UserController.java +++ b/event-planner/api/demo/src/main/java/com/api/demo/controllers/UserController.java @@ -5,6 +5,7 @@ import com.api.demo.dtos.EventDTO; import com.api.demo.dtos.LoginRequest; import com.api.demo.dtos.UserDTO; +import com.api.demo.dtos.UserInviteDTO; import com.api.demo.models.EventModel; import com.api.demo.models.User; import com.api.demo.services.UserService; @@ -116,4 +117,10 @@ public ResponseEntity loginUser(@RequestBody LoginRequest loginRequest) return ResponseEntity.ok(userDTO); } + + @GetMapping("/{id}/invites") + public ResponseEntity> getUserInvites(@PathVariable Long id) { + List userInvites = userService.getAllInvitedEvents(id); + return ResponseEntity.ok(userInvites); + } } diff --git a/event-planner/api/demo/src/main/java/com/api/demo/dtos/DTOConverter.java b/event-planner/api/demo/src/main/java/com/api/demo/dtos/DTOConverter.java index 3168d3e..ec81c4a 100644 --- a/event-planner/api/demo/src/main/java/com/api/demo/dtos/DTOConverter.java +++ b/event-planner/api/demo/src/main/java/com/api/demo/dtos/DTOConverter.java @@ -1,22 +1,16 @@ package com.api.demo.dtos; import com.api.demo.models.EventModel; +import com.api.demo.models.User; import java.util.HashSet; +import java.util.List; import java.util.Set; public class DTOConverter { public static EventDTO mapToDTO(EventModel event) { // Handle null organizer case - UserDTO organizerDTO = null; - if (event.getOrganizer() != null) { - organizerDTO = - UserDTO.builder() - .id(event.getOrganizer().getId()) - .name(event.getOrganizer().getName()) - .email(event.getOrganizer().getEmail()) - .build(); - } + UserDTO organizerDTO = mapToDTO(event.getOrganizer()); Set guests = new HashSet<>(); EventDTO model = @@ -34,6 +28,15 @@ public static EventDTO mapToDTO(EventModel event) { return model; } + public static UserDTO mapToDTO(User user) { + UserDTO userDTO = null; + if (user != null) { + userDTO = + UserDTO.builder().id(user.getId()).name(user.getName()).email(user.getEmail()).build(); + } + return userDTO; + } + public static EventModel mapToModel(CreateEventWithGuestsRequest request) { EventModel createdEvent = new EventModel(); createdEvent.setDescription(request.getDescription()); @@ -43,4 +46,12 @@ public static EventModel mapToModel(CreateEventWithGuestsRequest request) { createdEvent.setLocation(request.getAddress()); return createdEvent; } + + public static EventDTO mapToDTO(UserInviteDTO userInvite) { + return EventDTO.builder().title(userInvite.getTitle()).id(userInvite.getEventId()).build(); + } + + public static List mapListToDTO(List list) { + return list.stream().map(DTOConverter::mapToDTO).toList(); + } } diff --git a/event-planner/api/demo/src/main/java/com/api/demo/dtos/UserInviteDTO.java b/event-planner/api/demo/src/main/java/com/api/demo/dtos/UserInviteDTO.java index 9fdc982..932df4c 100644 --- a/event-planner/api/demo/src/main/java/com/api/demo/dtos/UserInviteDTO.java +++ b/event-planner/api/demo/src/main/java/com/api/demo/dtos/UserInviteDTO.java @@ -1,6 +1,5 @@ package com.api.demo.dtos; -import java.time.LocalDateTime; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,10 +8,6 @@ @Builder @Data public class UserInviteDTO { - private String email; - private String name; - private String description; - private Boolean is_public; - private LocalDateTime start_time; private String title; + private Long eventId; } diff --git a/event-planner/api/demo/src/main/java/com/api/demo/repos/UserRepository.java b/event-planner/api/demo/src/main/java/com/api/demo/repos/UserRepository.java index e8e7d0f..d17ad3d 100644 --- a/event-planner/api/demo/src/main/java/com/api/demo/repos/UserRepository.java +++ b/event-planner/api/demo/src/main/java/com/api/demo/repos/UserRepository.java @@ -20,12 +20,13 @@ public interface UserRepository extends JpaRepository { @Query( """ - SELECT - u.email, u.name, e.title, e.description, e.isPublic, e.startTime - FROM EventGuest eg - JOIN eg.guest u - JOIN eg.event e - WHERE u.id = :userId - """) + SELECT new com.api.demo.dtos.UserInviteDTO( + e.title,e.id + ) + FROM EventGuest eg + JOIN eg.guest u + JOIN eg.event e + WHERE u.id = :userId +""") List findAllUserInvitedEvents(Long userId); } diff --git a/event-planner/api/demo/src/test/java/com/api/demo/services/UserServiceTest.java b/event-planner/api/demo/src/test/java/com/api/demo/services/UserServiceTest.java index 96b3fcf..aabe27d 100644 --- a/event-planner/api/demo/src/test/java/com/api/demo/services/UserServiceTest.java +++ b/event-planner/api/demo/src/test/java/com/api/demo/services/UserServiceTest.java @@ -230,22 +230,8 @@ public void getUserInvitedEvents() { Long userId = 1L; List expectedInvites = List.of( - UserInviteDTO.builder() - .email("john.doe@example.com") - .description("Description 1") - .title("Event 1") - .is_public(true) - .start_time(LocalDateTime.now().plusDays(1)) - .name("John Doe") - .build(), - UserInviteDTO.builder() - .email("john.doe@example.com") - .description("Description 2") - .title("Event 2") - .is_public(false) - .start_time(LocalDateTime.now().plusDays(2)) - .name("John Doe") - .build()); + UserInviteDTO.builder().title("Event 1").eventId(1L).build(), + UserInviteDTO.builder().title("Event 2").eventId(2L).build()); when(userRepository.findAllUserInvitedEvents(userId)).thenReturn(expectedInvites); @@ -256,8 +242,10 @@ public void getUserInvitedEvents() { verify(userRepository, times(1)).findAllUserInvitedEvents(userId); assertThat(result).hasSize(2); assertThat(result).isEqualTo(expectedInvites); - assertThat(result.get(0).getEmail()).isEqualTo("john.doe@example.com"); + assertThat(result.get(0).getTitle()).isEqualTo("Event 1"); assertThat(result.get(1).getTitle()).isEqualTo("Event 2"); + assertThat(result.get(0).getEventId()).isEqualTo(1L); + assertThat(result.get(1).getEventId()).isEqualTo(2L); } @Test diff --git a/event-planner/frontend/src/components/invitations/InvitationsList.tsx b/event-planner/frontend/src/components/invitations/InvitationsList.tsx index 7007714..dec9da3 100644 --- a/event-planner/frontend/src/components/invitations/InvitationsList.tsx +++ b/event-planner/frontend/src/components/invitations/InvitationsList.tsx @@ -12,7 +12,8 @@ type InvitationsListProps = { const InvitationsList: React.FC = ({ events, onSelect }) => (
    {/* Render a button for each event; clicking sets the selected event in the parent */} - {events.map((event, idx) => ( + { + events.map((event, idx) => (
  • diff --git a/event-planner/frontend/src/components/navigation/Navigation.tsx b/event-planner/frontend/src/components/navigation/Navigation.tsx index d3901a0..0effd27 100644 --- a/event-planner/frontend/src/components/navigation/Navigation.tsx +++ b/event-planner/frontend/src/components/navigation/Navigation.tsx @@ -51,6 +51,7 @@ const Navigation: React.FC = () => {
    • Discover
    • About Us
    • +
    • Invites
    )} diff --git a/event-planner/frontend/src/pages/invitations/Invitations.tsx b/event-planner/frontend/src/pages/invitations/Invitations.tsx index b8b0981..5bc7ebb 100644 --- a/event-planner/frontend/src/pages/invitations/Invitations.tsx +++ b/event-planner/frontend/src/pages/invitations/Invitations.tsx @@ -1,16 +1,54 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import './Invitations.css'; import { type PrivateEventDetails, invitedEvents } from "../../types/types"; import InvitationsList from "../../components/invitations/InvitationsList"; import InvitationDetails from "../../components/invitations/InvitationDetails"; - +import { useUser } from "@clerk/clerk-react"; +import { fetchUser } from "../../service/apicalls"; // Main Invitations page component // Manages the list of invited events, selected event, and RSVP state const Invitations: React.FC = () => { // Index of the currently selected event in the events array (null if none selected) const [selectedEventIdx, setSelectedEventIdx] = useState(null); const [events, setEvents] = useState(invitedEvents); + const { isSignedIn, user } = useUser(); + const apiUrl = import.meta.env.VITE_API_URL; + const [backendUser,setBackendUser] = useState(); + if (!isSignedIn) { + alert("You must be signed in to view your invitations."); + window.location.href = "/login"; + } + const fetchUserData = async () => { + if (user) { + const userData = await fetchUser(user.id); + console.log("Fetched user data:", userData); + setBackendUser(userData); + } + }; + useEffect(() => { + fetchUserData(); + }, [user]); + + useEffect(() => { + const fetchInvitedEvents = async () => { + + try { + const response = await fetch(`${apiUrl}/users/${backendUser.id}/invites`); + if (response.ok) { + const data = await response.json(); + console.log("Fetched invited events:", data); + setEvents(data); + } else { + console.error("Failed to fetch invited events", response.status); + } + } catch (err) { + console.error("Error fetching invited events:", err); + } + }; + fetchInvitedEvents(); + }, [backendUser, apiUrl]); + // Updates RSVP status for the selected event // Only updates if an event is selected const handleRSVP = (status: "accepted" | "declined") => { @@ -22,6 +60,9 @@ const Invitations: React.FC = () => { }; setEvents(updatedEvents); }; + useEffect(() => { + fetch(`${apiUrl}/users//invites`) + }, []) // Get the currently selected event object, or null if none selected const selectedEvent = selectedEventIdx !== null ? events[selectedEventIdx] : null; @@ -41,3 +82,5 @@ const Invitations: React.FC = () => { }; export default Invitations; + + diff --git a/event-planner/frontend/src/service/apicalls.ts b/event-planner/frontend/src/service/apicalls.ts new file mode 100644 index 0000000..89c3941 --- /dev/null +++ b/event-planner/frontend/src/service/apicalls.ts @@ -0,0 +1,16 @@ +const BASE_API_URL = import.meta.env.VITE_API_URL +export const fetchUser = async(clerkId: string)=> { + try { + const response = await fetch(`${BASE_API_URL}/users/clerk/${clerkId}`) + if (response.ok) { + const json = await response.json(); + return json; + + + } else { + console.error("Failed to fetch user", response.status); + } + } catch (err) { + console.error("Error fetching user:", err); + } + } \ No newline at end of file