Skip to content
Merged
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
@@ -0,0 +1,75 @@
package com.classes.controllers;

import com.classes.dtos.reservations.ClassReservationRequest;
import com.classes.dtos.reservations.ClassReservationResponse;
import com.classes.services.AuthorizationService;
import com.classes.services.ClassReservationService;
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.UUID;

@RestController
@RequestMapping("/api/reservations")
@RequiredArgsConstructor
@Slf4j
public class ClassReservationController {

private final ClassReservationService reservationService;
private final AuthorizationService authorizationService; // Para obtener userId desde el token/cookie

// ✅ Reservar una clase
@Operation(summary = "Reservar una clase")
@PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
@PostMapping
public ResponseEntity<ClassReservationResponse> reserveClass(
@RequestBody ClassReservationRequest request,
Authentication authentication) {

UUID memberId = authorizationService.getUserId(authentication);
log.info("🎟️ Usuario {} intentando reservar clase {}", memberId, request.getClassId());

ClassReservationResponse response = reservationService.reserveClass(request, memberId);
return ResponseEntity.ok(response);
}

// ✅ Cancelar una reserva
@Operation(summary = "Cancelar una reserva")
@PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
@DeleteMapping("/{reservationId}")
public ResponseEntity<Void> cancelReservation(
@PathVariable UUID reservationId,
Authentication authentication) {

UUID memberId = authorizationService.getUserId(authentication);
log.info("❌ Usuario {} cancelando reserva {}", memberId, reservationId);

reservationService.cancelReservation(reservationId, memberId);
return ResponseEntity.noContent().build();
}

// ✅ Obtener reservas del usuario (próximas o completadas)
@Operation(summary = "Obtener mis reservas activas o completadas")
@PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
@GetMapping("/my")
public ResponseEntity<List<ClassReservationResponse>> getMyReservations(
Authentication authentication,
@RequestParam(required = false) Boolean completed) {

UUID memberId = authorizationService.getUserId(authentication);
log.info("📋 Usuario {} consultando sus reservas", memberId);

List<ClassReservationResponse> reservations = reservationService.getReservationsByMember(memberId, completed);
if (reservations.isEmpty()) {
return ResponseEntity.noContent().build();
}

return ResponseEntity.ok(reservations);
}
}
36 changes: 36 additions & 0 deletions src/main/java/com/classes/controllers/DashboardController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.classes.controllers;


import com.classes.dtos.Dashboard.MemberDashboardDTO;
import com.classes.services.AuthorizationService;
import com.classes.services.Impl.DashboardServiceImpl;
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;

import java.util.UUID;

@RestController
@RequestMapping("/api/dashboard")
@RequiredArgsConstructor
@Slf4j
public class DashboardController {

private final DashboardServiceImpl dashboardService;
private final AuthorizationService authorizationService;

@Operation(summary = "Obtener dashboard del miembro logueado")
@PreAuthorize("hasRole('USER') or hasRole('ADMIN')")
@GetMapping("/member")
public ResponseEntity<MemberDashboardDTO> getMemberDashboard(Authentication authentication) {
UUID memberId = authorizationService.getUserId(authentication);
log.info("📊 Usuario {} consultando su dashboard", memberId);

MemberDashboardDTO dashboard = dashboardService.getDashboardForMember(memberId);
return ResponseEntity.ok(dashboard);
}
}
18 changes: 18 additions & 0 deletions src/main/java/com/classes/dtos/Dashboard/MemberDashboardDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.classes.dtos.Dashboard;

import lombok.Builder;
import lombok.Data;
import java.util.List;

@Data
@Builder
public class MemberDashboardDTO {

private boolean inClass; // true si está actualmente en una clase activa
private int remainingClasses; // cuántas clases le quedan del plan
private String nextClassName; // nombre de la próxima clase
private String nextClassTime; // hora de la próxima clase
private int consecutiveDays; // días consecutivos asistidos
private List<WeeklyActivityDTO> weeklyActivity; // gráfico semanal
private List<UpcomingClassDTO> upcomingClasses; // próximas clases
}
14 changes: 14 additions & 0 deletions src/main/java/com/classes/dtos/Dashboard/UpcomingClassDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.classes.dtos.Dashboard;


import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class UpcomingClassDTO {
private String className;
private String trainerName;
private String schedule;
private String location;
}
11 changes: 11 additions & 0 deletions src/main/java/com/classes/dtos/Dashboard/WeeklyActivityDTO.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.classes.dtos.Dashboard;

import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class WeeklyActivityDTO {
private String day; // Lunes, Martes, etc.
private int sessions; // cantidad de clases asistidas ese día
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.classes.dtos.reservations;

import java.util.UUID;
import lombok.*;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ClassReservationRequest {
private UUID classId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.classes.dtos.reservations;

import java.util.UUID;

import lombok.*;
import lombok.Data;



@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ClassReservationResponse {
private UUID reservationId;
private UUID classId;
private String className;
private String trainerName;
private String schedule;
private String locationName;
private String capacity;
private String action;
private boolean alreadyReserved;
private boolean completed;
}
9 changes: 7 additions & 2 deletions src/main/java/com/classes/entities/ClassEntity.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Entity
Expand All @@ -20,8 +22,6 @@ public class ClassEntity {
@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id;
private String name;

private String className;
private int duration;

Expand All @@ -39,6 +39,11 @@ public class ClassEntity {
@JoinColumn(name = "trainer_id")
private TrainerEntity trainer;

@OneToMany(mappedBy = "classEntity", cascade = CascadeType.ALL)
@Builder.Default
private List<ClassReservation> reservations = new ArrayList<>();


@Embedded
private Audit audit;
}
35 changes: 35 additions & 0 deletions src/main/java/com/classes/entities/ClassReservation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.classes.entities;

import com.classes.enums.ReservationStatus;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.util.UUID;

@Entity
@Table(name = "class_reservations")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ClassReservation {

@Id
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id;

@ManyToOne
@JoinColumn(name = "class_id")
private ClassEntity classEntity;

private UUID memberId;

@Enumerated(EnumType.STRING)
private ReservationStatus status; // RESERVADO, LISTA_ESPERA, CANCELADO
private LocalDateTime reservedAt;
@Transient
private boolean attended;

}
7 changes: 7 additions & 0 deletions src/main/java/com/classes/enums/ReservationStatus.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.classes.enums;

public enum ReservationStatus {
RESERVADO,
LISTA_ESPERA,
CANCELADO
}
37 changes: 37 additions & 0 deletions src/main/java/com/classes/mappers/ClassReservationMapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.classes.mappers;


import com.classes.config.MapStructConfig;

import com.classes.dtos.reservations.ClassReservationRequest;
import com.classes.dtos.reservations.ClassReservationResponse;
import com.classes.entities.ClassReservation;
import org.mapstruct.*;

import java.util.List;

@Mapper(config = MapStructConfig.class)
public interface ClassReservationMapper {

@Mapping(target = "id", ignore = true)
@Mapping(target = "classEntity", ignore = true) // Service asigna la clase
@Mapping(target = "memberId", ignore = true) // Service asigna desde token
@Mapping(target = "status", ignore = true)
@Mapping(target = "reservedAt", expression = "java(java.time.LocalDateTime.now())")
@Mapping(target = "attended", constant = "false")
ClassReservation toEntity(ClassReservationRequest request);

@Mapping(target = "reservationId", source = "entity.id")
@Mapping(target = "classId", source = "entity.classEntity.id")
@Mapping(target = "className", source = "entity.classEntity.className")
@Mapping(target = "trainerName", expression = "java(entity.getClassEntity().getTrainer().getFirstName() + \" \" + entity.getClassEntity().getTrainer().getLastName())")
@Mapping(target = "locationName", source = "entity.classEntity.location.name")
@Mapping(target = "schedule", expression = "java(entity.getClassEntity().getStartTime() + \" - \" + entity.getClassEntity().getEndTime())")
@Mapping(target = "capacity", expression = "java(entity.getClassEntity().getReservations().stream().filter(r -> r.getStatus() == com.classes.enums.ReservationStatus.RESERVADO).count() + \"/\" + entity.getClassEntity().getMaxCapacity() + \" inscritos\")")
@Mapping(target = "action", expression = "java(entity.getStatus() == com.classes.enums.ReservationStatus.RESERVADO ? \"Cancelar\" : entity.getStatus() == com.classes.enums.ReservationStatus.LISTA_ESPERA ? \"Esperar\" : \"Reservar\")")
@Mapping(target = "alreadyReserved", expression = "java(entity.getStatus() != com.classes.enums.ReservationStatus.CANCELADO)")
@Mapping(target = "completed", expression = "java(entity.getClassEntity().getStartTime().isBefore(java.time.LocalTime.now()))")
ClassReservationResponse toResponse(ClassReservation entity);

List<ClassReservationResponse> toResponseList(List<ClassReservation> entities);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.classes.repositories;

import com.classes.entities.ClassReservation;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

public interface ClassReservationRepository extends JpaRepository<ClassReservation, UUID> {
List<ClassReservation> findByMemberId(UUID memberId);
List<ClassReservation> findByClassEntityId(UUID classId);
Optional<ClassReservation> findByClassEntityIdAndMemberId(UUID classId, UUID memberId);
}
15 changes: 15 additions & 0 deletions src/main/java/com/classes/services/ClassReservationService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.classes.services;



import com.classes.dtos.reservations.ClassReservationRequest;
import com.classes.dtos.reservations.ClassReservationResponse;
import java.util.List;
import java.util.UUID;

public interface ClassReservationService {
ClassReservationResponse reserveClass(ClassReservationRequest request, UUID memberId);
void cancelReservation(UUID reservationId, UUID memberId);
List<ClassReservationResponse> getReservationsByMember(UUID memberId, Boolean completed);
}

Loading