diff --git a/backend/src/main/java/com/itestra/eep/mappers/EventMapper.java b/backend/src/main/java/com/itestra/eep/mappers/EventMapper.java index 4642ba0..0aaf4ca 100644 --- a/backend/src/main/java/com/itestra/eep/mappers/EventMapper.java +++ b/backend/src/main/java/com/itestra/eep/mappers/EventMapper.java @@ -6,7 +6,6 @@ import com.itestra.eep.dtos.FileDetailsDTO; import com.itestra.eep.models.Event; import com.itestra.eep.models.FileEntity; -import com.itestra.eep.models.Participation; import org.mapstruct.*; import java.time.LocalDateTime; @@ -28,20 +27,12 @@ public interface EventMapper { List toDetailsDto(List events); @Mappings({ - @Mapping(source = "participations", target = "participantCount", qualifiedByName = "countConfirmed"), @Mapping(source = "date", target = "status", qualifiedByName = "status") }) EventDetailsDTO toDetailsDto(Event event); FileDetailsDTO toFileDetailsDto(FileEntity file); - @Named("countConfirmed") - default int map(List participations) { - return participations.stream().filter(Participation::isConfirmed) - .mapToInt(p -> p.getGuestCount() + 1) - .sum(); - } - @Named("status") default String status(LocalDateTime eventDate) { return eventDate.isAfter(LocalDateTime.now()) ? "upcoming" : "completed"; diff --git a/backend/src/main/java/com/itestra/eep/models/Employee.java b/backend/src/main/java/com/itestra/eep/models/Employee.java index 3d14653..cf0d083 100644 --- a/backend/src/main/java/com/itestra/eep/models/Employee.java +++ b/backend/src/main/java/com/itestra/eep/models/Employee.java @@ -21,7 +21,7 @@ public class Employee { private UUID id; @MapsId - @OneToOne(fetch = FetchType.LAZY, optional = false) + @OneToOne(fetch = FetchType.LAZY, optional = false, orphanRemoval = true) @JoinColumn(name = "profile_id", nullable = false) private Profile profile; @@ -35,7 +35,7 @@ public class Employee { @Column(name = "employment_type") private EmploymentType employmentType; - @OneToMany(mappedBy = "employee") + @OneToMany(mappedBy = "employee", orphanRemoval = true) private List participations = new LinkedList<>(); @ManyToMany diff --git a/backend/src/main/java/com/itestra/eep/models/Event.java b/backend/src/main/java/com/itestra/eep/models/Event.java index 07b3157..d9a983f 100644 --- a/backend/src/main/java/com/itestra/eep/models/Event.java +++ b/backend/src/main/java/com/itestra/eep/models/Event.java @@ -50,5 +50,18 @@ public class Event { @OneToOne(mappedBy = "event", orphanRemoval = true) private Schematics schematics; + @Transient + public int getParticipantCount() { + return getParticipantCount(null); + } + + @Transient + public int getParticipantCount(Participation excludeParticipation) { + return participations.stream() + .filter(p -> excludeParticipation == null || !p.getId().equals(excludeParticipation.getId())) + .mapToInt(p -> p.getGuestCount() + 1) + .sum(); + } + } diff --git a/backend/src/main/java/com/itestra/eep/services/impl/EventServiceImpl.java b/backend/src/main/java/com/itestra/eep/services/impl/EventServiceImpl.java index dc3bff6..456b5a1 100644 --- a/backend/src/main/java/com/itestra/eep/services/impl/EventServiceImpl.java +++ b/backend/src/main/java/com/itestra/eep/services/impl/EventServiceImpl.java @@ -58,11 +58,9 @@ public Event create(EventCreateDTO dto) { public Event update(UUID id, EventUpdateDTO dto) { Event event = eventRepository.findById(id).orElseThrow(EventNotFoundException::new); eventMapper.updateEventFromDto(dto, event); - - if (event.getCapacity() < participationRepository.sumGuestCounts(event, null)) { + if (dto.getCapacity() != null && event.getParticipantCount(null) > dto.getCapacity()) { throw new EventCapacityExceededException(); } - return eventRepository.save(event); } @@ -107,9 +105,7 @@ public void deleteParticipant(UUID participationId) { private void validateCapacity(Event event, int guestCount, Participation excludeParticipation) { - Integer total = participationRepository.sumGuestCounts(event, excludeParticipation == null ? null : excludeParticipation.getId()); - - int currentTotal = total != null ? total : 0; + int currentTotal = event.getParticipantCount(excludeParticipation); int newTotal = currentTotal + guestCount + 1; diff --git a/backend/src/main/java/com/itestra/eep/webcontroller/SchematicsController.java b/backend/src/main/java/com/itestra/eep/webcontroller/SchematicsController.java index d8f34a2..22057b9 100644 --- a/backend/src/main/java/com/itestra/eep/webcontroller/SchematicsController.java +++ b/backend/src/main/java/com/itestra/eep/webcontroller/SchematicsController.java @@ -28,7 +28,7 @@ public class SchematicsController { private final SchematicsMapper schematicsMapper; @GetMapping("/{id}") - @PreAuthorize("hasAnyAuthority('ADMIN', 'EMPLOYEE', 'VISITOR')") + @PreAuthorize("hasAnyAuthority('ADMIN', 'EMPLOYEE')") public ResponseEntity getSchematics(@PathVariable UUID id) { Schematics schematics = schematicsService.findById(id); return new ResponseEntity<>(schematicsMapper.toSchematicsCreateDTO(schematics), HttpStatus.OK); diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index a50cddb..cf69c5d 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,8 +1,8 @@ -import { RouterProvider } from "react-router-dom"; -import { ConfigProvider } from "antd"; -import { AuthProvider } from "./contexts/AuthContext"; -import { router } from "./routes/routes"; -import { Toaster } from "react-hot-toast"; +import {RouterProvider} from "react-router-dom"; +import {ConfigProvider} from "antd"; +import {AuthProvider} from "./contexts/AuthContext"; +import {router} from "./routes/routes"; +import {Toaster} from "react-hot-toast"; function App() { return ( diff --git a/frontend/src/components/AppContainer.tsx b/frontend/src/components/AppContainer.tsx index 3be6171..7223173 100644 --- a/frontend/src/components/AppContainer.tsx +++ b/frontend/src/components/AppContainer.tsx @@ -1,15 +1,9 @@ -import { Avatar, Dropdown, Layout, Menu } from "antd"; -import { Outlet, useLocation, useNavigate } from "react-router-dom"; -import { - CalendarOutlined, - DashboardOutlined, - LogoutOutlined, - TeamOutlined, - UserOutlined, -} from "@ant-design/icons"; -import { useAuth } from "../contexts/AuthContext"; +import {Avatar, Dropdown, Layout, Menu} from "antd"; +import {Outlet, useLocation, useNavigate} from "react-router-dom"; +import {CalendarOutlined, DashboardOutlined, LogoutOutlined, TeamOutlined, UserOutlined,} from "@ant-design/icons"; +import {useAuth} from "../contexts/AuthContext"; import useApiService from "../services/apiService.ts"; -import { useState } from "react"; +import {useState} from "react"; import itestraEventLogo from "../assets/itestra_event_logo.png"; const { Sider, Content, Footer } = Layout; @@ -70,27 +64,27 @@ export const AppContainer = () => { return ( setCollapsed(value)} - onBreakpoint={broken => setCollapsed(broken)} + theme="dark" + className="fixed h-full z-10" + breakpoint="lg" + collapsedWidth="0" + onCollapse={value => setCollapsed(value)} + onBreakpoint={broken => setCollapsed(broken)} >
itestra event planning logo
{ /> {/* User profile at the bottom */}
{
-