11package ita .tinybite .domain .party .dto .response ;
2+ import ita .tinybite .domain .party .entity .Party ;
3+ import ita .tinybite .domain .party .enums .ParticipantStatus ;
24import ita .tinybite .domain .party .enums .PartyCategory ;
5+ import ita .tinybite .domain .party .enums .PartyStatus ;
36import lombok .*;
47
8+ import java .time .Duration ;
59import java .time .LocalDateTime ;
10+ import java .time .format .DateTimeFormatter ;
611
712@ Getter
813@ NoArgsConstructor
@@ -20,4 +25,88 @@ public class PartyCardResponse {
2025 private Boolean isClosed ; // 마감 여부
2126 private PartyCategory category ;
2227 private LocalDateTime createdAt ;
28+
29+ public static PartyCardResponse from (Party party , int currentParticipants , boolean isHost , ParticipantStatus status ) {
30+ return PartyCardResponse .builder ()
31+ .partyId (party .getId ())
32+ .thumbnailImage (party .getThumbnailImage ())
33+ .title (party .getTitle ())
34+ .pricePerPerson (calculatePricePerPerson (party , currentParticipants ))
35+ .participantStatus (formatParticipantStatus (currentParticipants , party .getMaxParticipants ()))
36+ .distance (null ) // 거리 계산은 별도 처리 필요
37+ .distanceKm (null ) // 거리 계산은 별도 처리 필요
38+ .timeAgo (calculateTimeAgo (party .getCreatedAt ()))
39+ .isClosed (checkIfClosed (party , currentParticipants ))
40+ .category (party .getCategory ())
41+ .createdAt (party .getCreatedAt ())
42+ .build ();
43+ }
44+ private static String getThumbnailImage (Party party ) {
45+ if (party .getImage () != null && !party .getImage ().isEmpty ()) {
46+ return party .getImage ();
47+ }
48+ return "/images/default-party-thumbnail.jpg" ; // 기본 이미지
49+ }
50+
51+ /**
52+ * 1/N 가격 계산
53+ */
54+ private static Integer calculatePricePerPerson (Party party , int currentParticipants ) {
55+ if (party .getPrice () == null || currentParticipants == 0 ) {
56+ return null ;
57+ }
58+ return party .getPrice () / currentParticipants ;
59+ }
60+
61+ /**
62+ * 참가자 상태 포맷팅 "1/4명"
63+ */
64+ private static String formatParticipantStatus (int current , int max ) {
65+ return String .format ("%d/%d명" , current , max );
66+ }
67+
68+ /**
69+ * 시간 경과 계산 "10분 전", "3시간 전"
70+ */
71+ private static String calculateTimeAgo (LocalDateTime createdAt ) {
72+ if (createdAt == null ) {
73+ return "" ;
74+ }
75+
76+ LocalDateTime now = LocalDateTime .now ();
77+ Duration duration = Duration .between (createdAt , now );
78+
79+ long minutes = duration .toMinutes ();
80+ long hours = duration .toHours ();
81+ long days = duration .toDays ();
82+
83+ if (minutes < 1 ) {
84+ return "방금 전" ;
85+ } else if (minutes < 60 ) {
86+ return minutes + "분 전" ;
87+ } else if (hours < 24 ) {
88+ return hours + "시간 전" ;
89+ } else if (days < 7 ) {
90+ return days + "일 전" ;
91+ } else {
92+ return createdAt .format (DateTimeFormatter .ofPattern ("MM.dd" ));
93+ }
94+ }
95+
96+ /**
97+ * 마감 여부 확인
98+ */
99+ private static Boolean checkIfClosed (Party party , int currentParticipants ) {
100+ // 1. 파티 상태가 CLOSED인 경우
101+ if (party .getStatus () == PartyStatus .CLOSED ) {
102+ return true ;
103+ }
104+
105+ // 2. 정원이 다 찬 경우
106+ if (currentParticipants >= party .getMaxParticipants ()) {
107+ return true ;
108+ }
109+
110+ return false ;
111+ }
23112}
0 commit comments