Skip to content

Commit

Permalink
BE: [feat] 메인 화면 구성 CSID-DGU#153
Browse files Browse the repository at this point in the history
  • Loading branch information
Seoyoung2222 committed Dec 2, 2024
1 parent 82933ac commit 944c8b0
Show file tree
Hide file tree
Showing 6 changed files with 220 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@

import RunningMachines.R2R.domain.course.entity.UserCourse;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.time.LocalDateTime;
import java.util.List;

public interface UserCourseRepository extends JpaRepository<UserCourse, Long> {
@Query("SELECT uc FROM UserCourse uc WHERE uc.user.id = :userId AND uc.createdAt BETWEEN :startDateTime AND :endDateTime")
List<UserCourse> findByUserIdAndDateRange(
@Param("userId") Long userId,
@Param("startDateTime") LocalDateTime startDateTime,
@Param("endDateTime") LocalDateTime endDateTime
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package RunningMachines.R2R.domain.home.controller;

import RunningMachines.R2R.domain.home.service.HomeService;
import RunningMachines.R2R.domain.user.service.AuthCommandService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
@RequestMapping("/home")
@RequiredArgsConstructor
public class HomeController {
private final HomeService homeService;
private final AuthCommandService authCommandService;

@GetMapping("/user")
public ResponseEntity<Map<String, Object>> getDailyUserRecords() {
// 현재 로그인한 사용자 ID 가져오기
Long userId = authCommandService.getCurrentUser().getId();
// 일일 기록 데이터 가져오기
Map<String, Object> response = homeService.getDailyUserRecord(userId);
return ResponseEntity.ok(response);
}

/**
* 주간 크루 기록 조회
* @return 주간 거리 랭킹 및 페이스 랭킹
*/
@GetMapping("/crews")
public ResponseEntity<Map<String, Object>> getWeeklyCrewRecords() {
// 주간 크루 기록 데이터 가져오기
Map<String, Object> response = homeService.getWeeklyCrewRecords();
return ResponseEntity.ok(response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package RunningMachines.R2R.domain.home.dto;

import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
public class CrewRankResponseDto {
private Long crewId;
private String crewName;
private String crewProfileUrl;
private String value;
private double totalDistance;
private double averagePace;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package RunningMachines.R2R.domain.home.dto;

import lombok.Builder;
import lombok.Getter;

import java.util.List;

@Getter
@Builder
public class HomePageResponseDto {
private TodayRunResponseDto todayRun;
private List<CrewRankResponseDto> topDistanseCrews;
private List<CrewRankResponseDto> topPaceCrews;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package RunningMachines.R2R.domain.home.dto;

import lombok.Builder;
import lombok.Getter;

@Getter
@Builder
public class TodayRunResponseDto {
private double totalDistance;
private String averagePace;
private int totalDuration;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package RunningMachines.R2R.domain.home.service;

import RunningMachines.R2R.domain.course.entity.UserCourse;
import RunningMachines.R2R.domain.course.repository.UserCourseRepository;
import RunningMachines.R2R.domain.crew.common.entity.Crew;
import RunningMachines.R2R.domain.crew.common.entity.CrewUser;
import RunningMachines.R2R.domain.crew.common.repository.CrewRepository;
import RunningMachines.R2R.domain.user.entity.User;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoField;
import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class HomeService {
private final UserCourseRepository userCourseRepository;
private final CrewRepository crewRepository;

public Map<String, Object> getWeeklyCrewRecords() {
// Define start and end of the current week
LocalDateTime startOfWeek = LocalDate.now().with(ChronoField.DAY_OF_WEEK, 1).atStartOfDay();
LocalDateTime endOfWeek = startOfWeek.plusDays(6).with(LocalTime.MAX);

// Fetch all crews
List<Crew> crews = crewRepository.findAll();

// Calculate rankings for distance and pace
List<Map<String, Object>> distanceRankings = new ArrayList<>();
List<Map<String, Object>> paceRankings = new ArrayList<>();

for (Crew crew : crews) {
// Get all users in the crew
List<User> crewUsers = crew.getCrewUsers().stream()
.map(cu -> cu.getUser())
.collect(Collectors.toList());

// Calculate total distance and total duration
double totalDistance = crewUsers.stream()
.flatMap(user -> userCourseRepository.findByUserIdAndDateRange(user.getId(), startOfWeek, endOfWeek).stream())
.mapToDouble(UserCourse::getDistance)
.sum();

int totalDuration = crewUsers.stream()
.flatMap(user -> userCourseRepository.findByUserIdAndDateRange(user.getId(), startOfWeek, endOfWeek).stream())
.mapToInt(UserCourse::getDuration)
.sum();

String averagePace = formatPace(totalDistance, totalDuration);

// Add to distance ranking
Map<String, Object> distanceRanking = new HashMap<>();
distanceRanking.put("crewId", crew.getId());
distanceRanking.put("title", crew.getTitle());
distanceRanking.put("image", crew.getImages() != null ? crew.getImages().getImageUrl() : null);
distanceRanking.put("distance", String.format("%.2fKM", totalDistance));
distanceRankings.add(distanceRanking);

// Add to pace ranking
Map<String, Object> paceRanking = new HashMap<>();
paceRanking.put("crewId", crew.getId());
paceRanking.put("title", crew.getTitle());
paceRanking.put("image", crew.getImages() != null ? crew.getImages().getImageUrl() : null);
paceRanking.put("averagePace", averagePace);
paceRankings.add(paceRanking);
}

// Sort rankings
distanceRankings.sort(Comparator.comparing((Map<String, Object> m) -> Double.parseDouble(m.get("distance").toString().replace("KM", ""))).reversed());
paceRankings.sort(Comparator.comparing((Map<String, Object> m) -> parsePaceToSeconds(m.get("averagePace").toString())));

// Prepare the response
Map<String, Object> response = new HashMap<>();
response.put("distanceRankings", distanceRankings.stream().limit(3).collect(Collectors.toList()));
response.put("paceRankings", paceRankings.stream().limit(3).collect(Collectors.toList()));

return response;
}

public Map<String, Object> getDailyUserRecord(Long userId) {
// Define start and end of the current day
LocalDateTime startOfDay = LocalDate.now().atStartOfDay();
LocalDateTime endOfDay = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);

// Fetch the user's daily records
List<UserCourse> userCourses = userCourseRepository.findByUserIdAndDateRange(userId, startOfDay, endOfDay);

// Calculate total distance, total duration, and average pace
double totalDistance = userCourses.stream().mapToDouble(UserCourse::getDistance).sum();
int totalDuration = userCourses.stream().mapToInt(UserCourse::getDuration).sum(); // duration in minutes
String averagePace = formatPace(totalDistance, totalDuration);

// Prepare the response
Map<String, Object> response = new HashMap<>();
response.put("totalDistance", String.format("%.2fKM", totalDistance));
response.put("totalDuration", formatDuration(totalDuration));
response.put("averagePace", averagePace);

return response;
}

private String formatPace(double totalDistance, int totalDuration) {
if (totalDistance <= 0) return "0'00''";
int totalSeconds = (int) (totalDuration * 60 / totalDistance);
int minutes = totalSeconds / 60;
int seconds = totalSeconds % 60;
return String.format("%d'%02d''", minutes, seconds);
}

private int parsePaceToSeconds(String pace) {
String[] parts = pace.split("[']");
int minutes = Integer.parseInt(parts[0]);
int seconds = Integer.parseInt(parts[1].replace("''", ""));
return minutes * 60 + seconds;
}

private String formatDuration(int totalMinutes) {
int hours = totalMinutes / 60;
int minutes = totalMinutes % 60;
return String.format("%dh %02dm", hours, minutes);
}
}

0 comments on commit 944c8b0

Please sign in to comment.