diff --git a/src/main/java/com/soptie/server/api/controller/dto/response/member/GetHomeInfoResponse.java b/src/main/java/com/soptie/server/api/controller/dto/response/member/GetHomeInfoResponse.java index d8fb66c8..75d8c070 100644 --- a/src/main/java/com/soptie/server/api/controller/dto/response/member/GetHomeInfoResponse.java +++ b/src/main/java/com/soptie/server/api/controller/dto/response/member/GetHomeInfoResponse.java @@ -22,7 +22,8 @@ public record GetHomeInfoResponse( @Schema(description = "무지개 솜뭉치 개수", example = "10") int happinessCottonCount, @Schema(description = "대화 내용 목록", example = "[\"안녕?\", \"반가워~\"]") - @NotNull List conversations + @NotNull List conversations, + String frameImageUrl //TODO: delete ) { public static GetHomeInfoResponse of(Member member, MemberDoll memberDoll, List conversations) { @@ -32,6 +33,17 @@ public static GetHomeInfoResponse of(Member member, MemberDoll memberDoll, List< .dailyCottonCount(member.getCottonInfo().getBasicCottonCount()) .happinessCottonCount(member.getCottonInfo().getRainbowCottonCount()) .conversations(conversations) + .frameImageUrl(getFrameImageUrl(memberDoll.getDollId())) .build(); } + + private static String getFrameImageUrl(long dollId) { + return switch ((int)dollId) { + case 1 -> "https://github.com/Team-Sopetit/sopetit-image/blob/main/character/brown/background.png?raw=true"; + case 2 -> "https://github.com/Team-Sopetit/sopetit-image/blob/main/character/gray/background.png?raw=true"; + case 3 -> "https://github.com/Team-Sopetit/sopetit-image/blob/main/character/red/background.png?raw=true"; + default -> + "https://github.com/Team-Sopetit/sopetit-image/blob/main/character/white/background.png?raw=true"; + }; + } } diff --git a/src/main/java/com/soptie/server/temporary/TemporaryApi.java b/src/main/java/com/soptie/server/temporary/TemporaryApi.java new file mode 100644 index 00000000..a039fefb --- /dev/null +++ b/src/main/java/com/soptie/server/temporary/TemporaryApi.java @@ -0,0 +1,125 @@ +package com.soptie.server.temporary; + +import java.security.Principal; +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +import org.springframework.http.HttpStatus; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +import com.soptie.server.api.controller.dto.response.SuccessResponse; +import com.soptie.server.domain.memberroutine.MemberRoutine; +import com.soptie.server.domain.routine.Routine; +import com.soptie.server.persistence.adapter.ChallengeAdapter; +import com.soptie.server.persistence.adapter.MemberAdapter; +import com.soptie.server.persistence.adapter.MemberRoutineAdapter; +import com.soptie.server.persistence.adapter.MissionAdapter; +import com.soptie.server.persistence.adapter.RoutineAdapter; +import com.soptie.server.persistence.adapter.ThemeAdapter; +import com.soptie.server.persistence.entity.ChallengeEntity; +import com.soptie.server.persistence.entity.ThemeEntity; +import com.soptie.server.persistence.repository.ChallengeRepository; +import com.soptie.server.persistence.repository.ThemeRepository; +import com.soptie.server.temporary.dto.CreateMemberDailyRoutine; +import com.soptie.server.temporary.dto.GetHappinessRoutinesResponse; +import com.soptie.server.temporary.dto.GetHappinessSubRoutinesResponse; +import com.soptie.server.temporary.dto.GetMemberDailyRoutinesResponse; + +import lombok.RequiredArgsConstructor; +import lombok.val; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1") +public class TemporaryApi { + private final ThemeAdapter themeAdapter; + private final ChallengeAdapter challengeAdapter; + private final MissionAdapter missionAdapter; + private final ThemeRepository themeRepository; + private final ChallengeRepository challengeRepository; + private final RoutineAdapter routineAdapter; + private final MemberRoutineAdapter memberRoutineAdapter; + private final MemberAdapter memberAdapter; + + @ResponseStatus(HttpStatus.OK) + @GetMapping("/routines/happiness/routine/{routineId}") + public SuccessResponse getHappinessRoutinesByRoutine( + @PathVariable long routineId + ) { + val challenge = challengeAdapter.findById(routineId); + val theme = themeAdapter.findById(challenge.getThemeId()); + val missions = missionAdapter.findByChallengeIds(List.of(challenge.getId())); + return SuccessResponse.success( + "루틴별 행복 서브 루틴 내용 조회 성공", + GetHappinessSubRoutinesResponse.of(theme, challenge, missions)); + } + + @ResponseStatus(HttpStatus.OK) + @GetMapping("/routines/happiness") + public SuccessResponse getHappinessRoutinesByTheme( + @RequestParam(required = false) Long themeId + ) { + val themes = themeId == null + ? themeRepository.findAll().stream().map(ThemeEntity::toDomain).toList() + : List.of(themeAdapter.findById(themeId)); + val challenges = challengeRepository.findAll().stream().map(ChallengeEntity::toDomain).toList(); + + val map = themes.stream() + .collect(Collectors.toMap( + theme -> theme, + theme -> challenges.stream() + .filter(challenge -> challenge.getThemeId() == theme.getId()) + .toList() + )); + + return SuccessResponse.success( + "테마 목록별 행복 루틴 목록 조회 성공", + GetHappinessRoutinesResponse.of(map)); + } + + @ResponseStatus(HttpStatus.CREATED) + @PostMapping("/routines/daily/member") + @Transactional + public SuccessResponse createMemberDailyRoutine( + Principal principal, + @RequestBody CreateMemberDailyRoutine request + ) { + val memberId = Long.parseLong(principal.getName()); + val member = memberAdapter.findById(memberId); + val routine = routineAdapter.findById(request.routineId()); + val memberRoutine = memberRoutineAdapter.saveAll(member, List.of(routine)); + return SuccessResponse.success( + "데일리 루틴 추가 성공", + new CreateMemberDailyRoutine(!memberRoutine.isEmpty() ? memberRoutine.get(0).getId() : 0L)); + } + + @ResponseStatus(HttpStatus.OK) + @GetMapping("/routines/daily/member") + public SuccessResponse getMemberDailyRoutines(Principal principal) { + val memberId = Long.parseLong(principal.getName()); + val memberRoutines = memberRoutineAdapter.findByMemberId(memberId); + val routines = routineAdapter.findByIds(memberRoutines.stream().map(MemberRoutine::getRoutineId).toList()); + + val routineMap = routines.stream() + .collect(Collectors.toMap(Routine::getId, Function.identity())); + + val memberRoutineMap = memberRoutines.stream() + .collect(Collectors.toMap( + Function.identity(), // Key: MemberRoutine 자체 + memberRoutine -> routineMap.get(memberRoutine.getRoutineId()) // Value: 해당 MemberRoutine의 Routine + )); + + return SuccessResponse.success( + "회원의 데일리 루틴 목록 조회 성공", + GetMemberDailyRoutinesResponse.of(memberRoutineMap)); + } +} diff --git a/src/main/java/com/soptie/server/temporary/data/ThemeData.java b/src/main/java/com/soptie/server/temporary/data/ThemeData.java new file mode 100644 index 00000000..1b4daaeb --- /dev/null +++ b/src/main/java/com/soptie/server/temporary/data/ThemeData.java @@ -0,0 +1,54 @@ +package com.soptie.server.temporary.data; + +public class ThemeData { + + public static String getColor(long id) { + return switch ((int)id) { + case 1 -> "#E19098"; + case 2 -> "#38B662"; + case 3 -> "#6392D8"; + case 4 -> "#EF596F"; + case 5 -> "#52A1DA"; + case 6 -> "#EDBF4F"; + default -> "#EB9D07"; + }; + } + + public static String getBackgroundImageUrl(long id) { + return switch ((int)id) { + case 1 -> + "https://softie-data-image.s3.ap-northeast-2.amazonaws.com/background/%E1%84%80%E1%85%AA%E1%86%AB%E1%84%80%E1%85%A8_%E1%84%8A%E1%85%A1%E1%87%82%E1%84%80%E1%85%B5.png"; + case 2 -> + "https://softie-data-image.s3.ap-northeast-2.amazonaws.com/background/%E1%84%92%E1%85%A1%E1%86%AB_%E1%84%80%E1%85%A5%E1%86%AF%E1%84%8B%E1%85%B3%E1%86%B7_%E1%84%89%E1%85%A5%E1%86%BC%E1%84%8C%E1%85%A1%E1%86%BC.png"; + case 3 -> + "https://softie-data-image.s3.ap-northeast-2.amazonaws.com/background/%E1%84%82%E1%85%A1%E1%84%8B%E1%85%AA_%E1%84%8E%E1%85%B5%E1%86%AB%E1%84%92%E1%85%A2%E1%84%8C%E1%85%B5%E1%84%80%E1%85%B5.png"; + case 4 -> + "https://softie-data-image.s3.ap-northeast-2.amazonaws.com/background/%E1%84%86%E1%85%A1%E1%84%8B%E1%85%B3%E1%86%B7_%E1%84%8E%E1%85%A2%E1%86%BC%E1%84%80%E1%85%B5%E1%86%B7.png"; + case 5 -> + "https://softie-data-image.s3.ap-northeast-2.amazonaws.com/background/%E1%84%80%E1%85%A5%E1%86%AB%E1%84%80%E1%85%A1%E1%86%BC%E1%84%92%E1%85%A1%E1%86%AB_%E1%84%86%E1%85%A9%E1%86%B7.png"; + case 6 -> + "https://softie-data-image.s3.ap-northeast-2.amazonaws.com/background/%E1%84%90%E1%85%A9%E1%86%BC%E1%84%90%E1%85%A9%E1%86%BC%E1%84%92%E1%85%A1%E1%86%AB_%E1%84%90%E1%85%A9%E1%86%BC%E1%84%8C%E1%85%A1%E1%86%BC.png"; + default -> + "https://softie-data-image.s3.ap-northeast-2.amazonaws.com/background/%E1%84%89%E1%85%A1%E1%86%AB%E1%84%84%E1%85%B3%E1%86%BA%E1%84%92%E1%85%A1%E1%86%AB_%E1%84%8B%E1%85%B5%E1%86%AF%E1%84%89%E1%85%A1%E1%86%BC.png"; + }; + } + + public static String getIconImageUrl(long id) { + return switch ((int)id) { + case 1 -> + "https://softie-data-image.s3.ap-northeast-2.amazonaws.com/icon/%E1%84%80%E1%85%AA%E1%86%AB%E1%84%80%E1%85%A8_%E1%84%8A%E1%85%A1%E1%87%82%E1%84%80%E1%85%B5.png"; + case 2 -> + "https://softie-data-image.s3.ap-northeast-2.amazonaws.com/icon/%E1%84%92%E1%85%A1%E1%86%AB_%E1%84%80%E1%85%A5%E1%86%AF%E1%84%8B%E1%85%B3%E1%86%B7_%E1%84%89%E1%85%A5%E1%86%BC%E1%84%8C%E1%85%A1%E1%86%BC.png"; + case 3 -> + "https://softie-data-image.s3.ap-northeast-2.amazonaws.com/icon/%E1%84%82%E1%85%A1%E1%84%8B%E1%85%AA_%E1%84%8E%E1%85%B5%E1%86%AB%E1%84%92%E1%85%A2%E1%84%8C%E1%85%B5%E1%84%80%E1%85%B5.png"; + case 4 -> + "https://softie-data-image.s3.ap-northeast-2.amazonaws.com/icon/%E1%84%86%E1%85%A1%E1%84%8B%E1%85%B3%E1%86%B7_%E1%84%8E%E1%85%A2%E1%86%BC%E1%84%80%E1%85%B5%E1%86%B7.png"; + case 5 -> + "https://softie-data-image.s3.ap-northeast-2.amazonaws.com/icon/%E1%84%80%E1%85%A5%E1%86%AB%E1%84%80%E1%85%A1%E1%86%BC%E1%84%92%E1%85%A1%E1%86%AB_%E1%84%86%E1%85%A9%E1%86%B7.png"; + case 6 -> + "https://softie-data-image.s3.ap-northeast-2.amazonaws.com/icon/%E1%84%90%E1%85%A9%E1%86%BC%E1%84%90%E1%85%A9%E1%86%BC%E1%84%92%E1%85%A1%E1%86%AB_%E1%84%90%E1%85%A9%E1%86%BC%E1%84%8C%E1%85%A1%E1%86%BC.png"; + default -> + "https://softie-data-image.s3.ap-northeast-2.amazonaws.com/icon/%E1%84%89%E1%85%A1%E1%86%AB%E1%84%84%E1%85%B3%E1%86%BA%E1%84%92%E1%85%A1%E1%86%AB_%E1%84%8B%E1%85%B5%E1%86%AF%E1%84%89%E1%85%A1%E1%86%BC.png"; + }; + } +} diff --git a/src/main/java/com/soptie/server/temporary/dto/CreateMemberDailyRoutine.java b/src/main/java/com/soptie/server/temporary/dto/CreateMemberDailyRoutine.java new file mode 100644 index 00000000..762a961e --- /dev/null +++ b/src/main/java/com/soptie/server/temporary/dto/CreateMemberDailyRoutine.java @@ -0,0 +1,6 @@ +package com.soptie.server.temporary.dto; + +public record CreateMemberDailyRoutine( + long routineId +) { +} diff --git a/src/main/java/com/soptie/server/temporary/dto/GetHappinessRoutinesResponse.java b/src/main/java/com/soptie/server/temporary/dto/GetHappinessRoutinesResponse.java new file mode 100644 index 00000000..b1788277 --- /dev/null +++ b/src/main/java/com/soptie/server/temporary/dto/GetHappinessRoutinesResponse.java @@ -0,0 +1,47 @@ +package com.soptie.server.temporary.dto; + +import java.util.List; +import java.util.Map; + +import com.soptie.server.domain.challenge.Challenge; +import com.soptie.server.domain.theme.Theme; +import com.soptie.server.temporary.data.ThemeData; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.NonNull; + +@Builder(access = AccessLevel.PRIVATE) +public record GetHappinessRoutinesResponse( + List routines +) { + + public static GetHappinessRoutinesResponse of(Map> map) { + return GetHappinessRoutinesResponse.builder() + .routines(map.entrySet().stream() + .flatMap(entry -> entry.getValue().stream() + .map(challenge -> HappinessRoutineResponse.of(entry.getKey(), challenge))) + .toList()) + .build(); + } + + @Builder(access = AccessLevel.PRIVATE) + public record HappinessRoutineResponse( + long routineId, + @NonNull String name, + @NonNull String nameColor, + @NonNull String title, + @NonNull String iconImageUrl + ) { + + public static HappinessRoutineResponse of(Theme theme, Challenge challenge) { + return HappinessRoutineResponse.builder() + .routineId(challenge.getId()) + .name(theme.getName()) + .nameColor(ThemeData.getColor(theme.getId())) + .title(challenge.getName()) + .iconImageUrl(ThemeData.getIconImageUrl(theme.getId())) + .build(); + } + } +} diff --git a/src/main/java/com/soptie/server/temporary/dto/GetHappinessSubRoutinesResponse.java b/src/main/java/com/soptie/server/temporary/dto/GetHappinessSubRoutinesResponse.java new file mode 100644 index 00000000..829646e0 --- /dev/null +++ b/src/main/java/com/soptie/server/temporary/dto/GetHappinessSubRoutinesResponse.java @@ -0,0 +1,54 @@ +package com.soptie.server.temporary.dto; + +import java.util.List; + +import com.soptie.server.domain.challenge.Challenge; +import com.soptie.server.domain.challenge.Mission; +import com.soptie.server.domain.theme.Theme; +import com.soptie.server.temporary.data.ThemeData; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.NonNull; + +@Builder(access = AccessLevel.PRIVATE) +public record GetHappinessSubRoutinesResponse( + @NonNull String title, + @NonNull String name, + @NonNull String nameColor, + @NonNull String iconImageUrl, + @NonNull String contentImageUrl, + @NonNull List subRoutines +) { + + public static GetHappinessSubRoutinesResponse of(Theme theme, Challenge challenge, List missions) { + return GetHappinessSubRoutinesResponse.builder() + .title(challenge.getName()) + .name(theme.getName()) + .nameColor(ThemeData.getColor(theme.getId())) + .iconImageUrl(ThemeData.getIconImageUrl(theme.getId())) + .contentImageUrl(ThemeData.getBackgroundImageUrl(theme.getId())) + .subRoutines(missions.stream().map(HappinessSubRoutineResponse::of).toList()) + .build(); + } + + @Builder(access = AccessLevel.PRIVATE) + public record HappinessSubRoutineResponse( + long subRoutineId, + @NonNull String content, + @NonNull String detailContent, + @NonNull String timeTaken, + @NonNull String place + ) { + + public static HappinessSubRoutineResponse of(Mission mission) { + return HappinessSubRoutineResponse.builder() + .subRoutineId(mission.getId()) + .content(mission.getContent()) + .detailContent(mission.getDescription()) + .timeTaken(mission.getRequiredTime()) + .place(mission.getPlace()) + .build(); + } + } +} diff --git a/src/main/java/com/soptie/server/temporary/dto/GetMemberDailyRoutinesResponse.java b/src/main/java/com/soptie/server/temporary/dto/GetMemberDailyRoutinesResponse.java new file mode 100644 index 00000000..9acefd59 --- /dev/null +++ b/src/main/java/com/soptie/server/temporary/dto/GetMemberDailyRoutinesResponse.java @@ -0,0 +1,45 @@ +package com.soptie.server.temporary.dto; + +import java.util.List; +import java.util.Map; + +import com.soptie.server.domain.memberroutine.MemberRoutine; +import com.soptie.server.domain.routine.Routine; +import com.soptie.server.temporary.data.ThemeData; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.NonNull; + +@Builder(access = AccessLevel.PRIVATE) +public record GetMemberDailyRoutinesResponse( + List routines +) { + + public static GetMemberDailyRoutinesResponse of(Map map) { + return GetMemberDailyRoutinesResponse.builder() + .routines(map.entrySet().stream() + .map(it -> MemberDailyRoutineResponse.of(it.getKey(), it.getValue())).toList()) + .build(); + } + + @Builder(access = AccessLevel.PRIVATE) + private record MemberDailyRoutineResponse( + long routineId, + @NonNull String content, + @NonNull String iconImageUrl, + int achieveCount, + boolean isAchieve + ) { + + private static MemberDailyRoutineResponse of(MemberRoutine memberRoutine, Routine routine) { + return MemberDailyRoutineResponse.builder() + .routineId(memberRoutine.getId()) + .content(routine.getContent()) + .iconImageUrl(ThemeData.getIconImageUrl(routine.getThemeId())) + .achieveCount(memberRoutine.getAchievementCount()) + .isAchieve(memberRoutine.isAchieved()) + .build(); + } + } +}