Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -116,4 +117,10 @@ public ResponseEntity<UserDTO> loginUser(@RequestBody LoginRequest loginRequest)

return ResponseEntity.ok(userDTO);
}

@GetMapping("/{id}/invites")
public ResponseEntity<List<UserInviteDTO>> getUserInvites(@PathVariable Long id) {
List<UserInviteDTO> userInvites = userService.getAllInvitedEvents(id);
return ResponseEntity.ok(userInvites);
}
}
Original file line number Diff line number Diff line change
@@ -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<UserDTO> guests = new HashSet<>();
EventDTO model =
Expand All @@ -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());
Expand All @@ -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<EventDTO> mapListToDTO(List<UserInviteDTO> list) {
return list.stream().map(DTOConverter::mapToDTO).toList();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.api.demo.dtos;

import java.time.LocalDateTime;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
Expand All @@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ public interface UserRepository extends JpaRepository<User, Long> {

@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<UserInviteDTO> findAllUserInvitedEvents(Long userId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -230,22 +230,8 @@ public void getUserInvitedEvents() {
Long userId = 1L;
List<UserInviteDTO> expectedInvites =
List.of(
UserInviteDTO.builder()
.email("[email protected]")
.description("Description 1")
.title("Event 1")
.is_public(true)
.start_time(LocalDateTime.now().plusDays(1))
.name("John Doe")
.build(),
UserInviteDTO.builder()
.email("[email protected]")
.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);

Expand All @@ -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("[email protected]");
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ type InvitationsListProps = {
const InvitationsList: React.FC<InvitationsListProps> = ({ events, onSelect }) => (
<ul className="invitations-list">
{/* Render a button for each event; clicking sets the selected event in the parent */}
{events.map((event, idx) => (
{
events.map((event, idx) => (
<li key={idx}>
<button onClick={() => onSelect(idx)}>{event.title}</button>
</li>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ const Navigation: React.FC = () => {
<ul className="navigation-top-menu">
<li><Link to="/">Discover</Link></li>
<li><Link to="/about">About Us</Link></li>
<li><Link to="/invitations">Invites</Link></li>
</ul>
)}

Expand Down
47 changes: 45 additions & 2 deletions event-planner/frontend/src/pages/invitations/Invitations.tsx
Original file line number Diff line number Diff line change
@@ -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<number | null>(null);
const [events, setEvents] = useState<PrivateEventDetails[]>(invitedEvents);
const { isSignedIn, user } = useUser();
const apiUrl = import.meta.env.VITE_API_URL;
const [backendUser,setBackendUser] = useState<any>();
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") => {
Expand All @@ -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;
Expand All @@ -41,3 +82,5 @@ const Invitations: React.FC = () => {
};

export default Invitations;


16 changes: 16 additions & 0 deletions event-planner/frontend/src/service/apicalls.ts
Original file line number Diff line number Diff line change
@@ -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);
}
}