-| 팀 캘린더 | 팀 피드 |
+| 팀 캘린더 | 팀 채팅 |
| :---------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------: |
-| | |
+| | |
| 팀 링크 | 팀 생성 및 팀 참가 |
-| | |
+| | |
팀바팀을 더 자세히 알고 싶다면, 여기로!
diff --git a/backend/src/main/java/team/teamby/teambyteam/global/presentation/GlobalExceptionHandler.java b/backend/src/main/java/team/teamby/teambyteam/global/presentation/GlobalExceptionHandler.java
index 6f3dbf76d..4e75bc844 100644
--- a/backend/src/main/java/team/teamby/teambyteam/global/presentation/GlobalExceptionHandler.java
+++ b/backend/src/main/java/team/teamby/teambyteam/global/presentation/GlobalExceptionHandler.java
@@ -123,6 +123,7 @@ public ResponseEntity handleCustomForbiddenException(final Runtim
@ExceptionHandler(value = {
ScheduleException.SpanWrongOrderException.class,
+ ScheduleException.dateFormatException.class,
TeamPlaceInviteCodeException.LengthException.class,
TeamPlaceException.NameLengthException.class,
TeamPlaceException.NameBlankException.class,
diff --git a/backend/src/main/java/team/teamby/teambyteam/schedule/application/MyCalendarScheduleService.java b/backend/src/main/java/team/teamby/teambyteam/schedule/application/MyCalendarScheduleService.java
index 6ec6c8253..f3e36b309 100644
--- a/backend/src/main/java/team/teamby/teambyteam/schedule/application/MyCalendarScheduleService.java
+++ b/backend/src/main/java/team/teamby/teambyteam/schedule/application/MyCalendarScheduleService.java
@@ -9,11 +9,13 @@
import team.teamby.teambyteam.member.domain.vo.Email;
import team.teamby.teambyteam.member.exception.MemberException;
import team.teamby.teambyteam.schedule.application.dto.SchedulesWithTeamPlaceIdResponse;
+import team.teamby.teambyteam.schedule.application.parser.LocalDateParser;
import team.teamby.teambyteam.schedule.domain.CalendarPeriod;
import team.teamby.teambyteam.schedule.domain.Schedule;
import team.teamby.teambyteam.schedule.domain.ScheduleRepository;
import team.teamby.teambyteam.teamplace.domain.TeamPlace;
+import java.time.LocalDate;
import java.util.List;
@Service
@@ -23,6 +25,7 @@ public class MyCalendarScheduleService {
private final MemberRepository memberRepository;
private final ScheduleRepository scheduleRepository;
+ private final LocalDateParser localDateParser;
@Transactional(readOnly = true)
public SchedulesWithTeamPlaceIdResponse findScheduleInPeriod(
@@ -66,4 +69,29 @@ public SchedulesWithTeamPlaceIdResponse findScheduleInPeriod(
return SchedulesWithTeamPlaceIdResponse.of(dailySchedules);
}
+
+ @Transactional(readOnly = true)
+ public SchedulesWithTeamPlaceIdResponse findScheduleInPeriod(
+ final MemberEmailDto memberEmailDto,
+ final String startDateString,
+ final String endDateString
+ ) {
+ final Member member = memberRepository.findByEmail(new Email(memberEmailDto.email()))
+ .orElseThrow(() -> new MemberException.MemberNotFoundException(memberEmailDto.email()));
+
+ final List participatedTeamPlaceIds = member.getTeamPlaces()
+ .stream()
+ .map(TeamPlace::getId)
+ .toList();
+
+ final LocalDate startDate = localDateParser.parse(startDateString);
+ final LocalDate endDate = localDateParser.parse(endDateString);
+
+ final CalendarPeriod period = CalendarPeriod.of(startDate, endDate);
+
+ final List dailySchedules = scheduleRepository.findAllByTeamPlaceIdAndPeriod(
+ participatedTeamPlaceIds, period.startDateTime(), period.endDatetime());
+
+ return SchedulesWithTeamPlaceIdResponse.of(dailySchedules);
+ }
}
diff --git a/backend/src/main/java/team/teamby/teambyteam/schedule/application/TeamCalendarScheduleService.java b/backend/src/main/java/team/teamby/teambyteam/schedule/application/TeamCalendarScheduleService.java
index 83fd90d06..2bb969263 100644
--- a/backend/src/main/java/team/teamby/teambyteam/schedule/application/TeamCalendarScheduleService.java
+++ b/backend/src/main/java/team/teamby/teambyteam/schedule/application/TeamCalendarScheduleService.java
@@ -13,6 +13,7 @@
import team.teamby.teambyteam.schedule.application.event.ScheduleDeleteEvent;
import team.teamby.teambyteam.schedule.application.event.ScheduleUpdateEvent;
import team.teamby.teambyteam.schedule.application.event.ScheduleUpdateEventDto;
+import team.teamby.teambyteam.schedule.application.parser.LocalDateParser;
import team.teamby.teambyteam.schedule.domain.CalendarPeriod;
import team.teamby.teambyteam.schedule.domain.Schedule;
import team.teamby.teambyteam.schedule.domain.ScheduleRepository;
@@ -22,6 +23,7 @@
import team.teamby.teambyteam.teamplace.domain.TeamPlaceRepository;
import team.teamby.teambyteam.teamplace.exception.TeamPlaceException;
+import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
@@ -34,6 +36,7 @@ public class TeamCalendarScheduleService {
private final ScheduleRepository scheduleRepository;
private final TeamPlaceRepository teamPlaceRepository;
private final ApplicationEventPublisher applicationEventPublisher;
+ private final LocalDateParser localDateParser;
public Long register(final ScheduleRegisterRequest scheduleRegisterRequest, final Long teamPlaceId) {
checkTeamPlaceExist(teamPlaceId);
@@ -87,7 +90,7 @@ private boolean isNotScheduleOfTeam(final Long teamPlaceId, final Schedule sched
}
@Transactional(readOnly = true)
- public SchedulesResponse findScheduleInPeriod(final Long teamPlaceId, final int targetYear, final int targetMonth) {
+ public SchedulesResponse findScheduleInMonth(final Long teamPlaceId, final int targetYear, final int targetMonth) {
checkTeamPlaceExist(teamPlaceId);
final CalendarPeriod period = CalendarPeriod.of(targetYear, targetMonth);
@@ -98,7 +101,7 @@ public SchedulesResponse findScheduleInPeriod(final Long teamPlaceId, final int
}
@Transactional(readOnly = true)
- public SchedulesResponse findScheduleInPeriod(
+ public SchedulesResponse findScheduleInDay(
final Long teamPlaceId,
final int targetYear,
final int targetMonth,
@@ -113,6 +116,24 @@ public SchedulesResponse findScheduleInPeriod(
return SchedulesResponse.of(dailySchedules);
}
+ @Transactional(readOnly = true)
+ public SchedulesResponse findScheduleInPeriod(
+ final Long teaPlaceId,
+ final String startDateString,
+ final String endDateString
+ ) {
+ checkTeamPlaceExist(teaPlaceId);
+
+ final LocalDate startDate = localDateParser.parse(startDateString);
+ final LocalDate endDate = localDateParser.parse(endDateString);
+ final CalendarPeriod period = CalendarPeriod.of(startDate, endDate);
+
+ final List schedules = scheduleRepository.
+ findAllByTeamPlaceIdAndPeriod(teaPlaceId, period.startDateTime(), period.endDatetime());
+
+ return SchedulesResponse.of(schedules);
+ }
+
public void update(final ScheduleUpdateRequest scheduleUpdateRequest, final Long teamPlaceId, final Long scheduleId) {
checkTeamPlaceExist(teamPlaceId);
diff --git a/backend/src/main/java/team/teamby/teambyteam/schedule/application/parser/LocalDateParser.java b/backend/src/main/java/team/teamby/teambyteam/schedule/application/parser/LocalDateParser.java
new file mode 100644
index 000000000..ab470bb02
--- /dev/null
+++ b/backend/src/main/java/team/teamby/teambyteam/schedule/application/parser/LocalDateParser.java
@@ -0,0 +1,22 @@
+package team.teamby.teambyteam.schedule.application.parser;
+
+import org.springframework.stereotype.Component;
+import team.teamby.teambyteam.schedule.exception.ScheduleException;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+
+@Component
+public class LocalDateParser {
+
+ private static final DateTimeFormatter DATE_PARAM_FORMAT = DateTimeFormatter.ofPattern("yyyyMMdd");
+
+ public LocalDate parse(final String yearMonthDay) {
+ try {
+ return LocalDate.parse(yearMonthDay, DATE_PARAM_FORMAT);
+ } catch (final DateTimeParseException e) {
+ throw new ScheduleException.dateFormatException(e);
+ }
+ }
+}
diff --git a/backend/src/main/java/team/teamby/teambyteam/schedule/domain/CalendarPeriod.java b/backend/src/main/java/team/teamby/teambyteam/schedule/domain/CalendarPeriod.java
index 5af8c105e..a268cd957 100644
--- a/backend/src/main/java/team/teamby/teambyteam/schedule/domain/CalendarPeriod.java
+++ b/backend/src/main/java/team/teamby/teambyteam/schedule/domain/CalendarPeriod.java
@@ -1,9 +1,18 @@
package team.teamby.teambyteam.schedule.domain;
+import team.teamby.teambyteam.schedule.exception.ScheduleException;
+
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
+/**
+ * 캘린더 일정
+ * 일정에 해당하려면 startDateTime <= PERIOD < endDateTime
+ *
+ * @param startDateTime inclusive DateTime
+ * @param endDatetime exclusive DateTime
+ */
public record CalendarPeriod(
LocalDateTime startDateTime,
LocalDateTime endDatetime
@@ -26,4 +35,21 @@ public static CalendarPeriod of(final int year, final int month, final int day)
return new CalendarPeriod(LocalDateTime.of(dailyDate, START_TIME_OF_DAY), LocalDateTime.of(nextDay, START_TIME_OF_DAY));
}
+
+ public static CalendarPeriod of(final LocalDate startDate, final LocalDate endDate) {
+ validateOrder(startDate, endDate);
+ return new CalendarPeriod(
+ LocalDateTime.of(startDate, START_TIME_OF_DAY),
+ LocalDateTime.of(endDate.plusDays(NEXT_DAY_OFFSET), START_TIME_OF_DAY)
+ );
+ }
+
+ private static void validateOrder(final LocalDate startDate, final LocalDate endDate) {
+ if (endDate.isBefore(startDate)) {
+ throw new ScheduleException.SpanWrongOrderException(
+ LocalDateTime.of(startDate, START_TIME_OF_DAY),
+ LocalDateTime.of(endDate, START_TIME_OF_DAY)
+ );
+ }
+ }
}
diff --git a/backend/src/main/java/team/teamby/teambyteam/schedule/exception/ScheduleException.java b/backend/src/main/java/team/teamby/teambyteam/schedule/exception/ScheduleException.java
index e6082c286..11d5af703 100644
--- a/backend/src/main/java/team/teamby/teambyteam/schedule/exception/ScheduleException.java
+++ b/backend/src/main/java/team/teamby/teambyteam/schedule/exception/ScheduleException.java
@@ -8,6 +8,10 @@ public ScheduleException(final String message) {
super(message);
}
+ public ScheduleException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
public static class ScheduleNotFoundException extends ScheduleException {
public ScheduleNotFoundException(final Long scheduleId) {
super(String.format("조회한 일정이 존재하지 않습니다. - request info { schedule_id : %d }", scheduleId));
@@ -31,9 +35,14 @@ public SpanWrongOrderException(final LocalDateTime startDateTime, final LocalDat
}
public static class TitleBlankException extends ScheduleException {
-
public TitleBlankException() {
super("일정의 제목은 빈 칸일 수 없습니다.");
}
}
+
+ public static class dateFormatException extends ScheduleException {
+ public dateFormatException(final Exception e) {
+ super("잘못된 날짜 입력 형식입니다.", e);
+ }
+ }
}
diff --git a/backend/src/main/java/team/teamby/teambyteam/schedule/presentation/MyCalendarScheduleController.java b/backend/src/main/java/team/teamby/teambyteam/schedule/presentation/MyCalendarScheduleController.java
index 16b7f9705..63edcbc6d 100644
--- a/backend/src/main/java/team/teamby/teambyteam/schedule/presentation/MyCalendarScheduleController.java
+++ b/backend/src/main/java/team/teamby/teambyteam/schedule/presentation/MyCalendarScheduleController.java
@@ -40,4 +40,15 @@ public ResponseEntity findDailySchedule(
return ResponseEntity.ok(responseBody);
}
+
+ @GetMapping(value = "/schedules", params = {"startDate", "endDate"})
+ public ResponseEntity findDailySchedule(
+ @AuthPrincipal final MemberEmailDto memberEmailDto,
+ @RequestParam(value = "startDate") final String startDate,
+ @RequestParam(value = "endDate") final String endDate
+ ) {
+ final SchedulesWithTeamPlaceIdResponse responseBody = myCalendarScheduleService.findScheduleInPeriod(memberEmailDto, startDate, endDate);
+
+ return ResponseEntity.ok(responseBody);
+ }
}
diff --git a/backend/src/main/java/team/teamby/teambyteam/schedule/presentation/TeamCalendarScheduleController.java b/backend/src/main/java/team/teamby/teambyteam/schedule/presentation/TeamCalendarScheduleController.java
index fa758f81b..f5f5694c7 100644
--- a/backend/src/main/java/team/teamby/teambyteam/schedule/presentation/TeamCalendarScheduleController.java
+++ b/backend/src/main/java/team/teamby/teambyteam/schedule/presentation/TeamCalendarScheduleController.java
@@ -38,12 +38,12 @@ public ResponseEntity findSpecificSchedule(
}
@GetMapping(value = "/{teamPlaceId}/calendar/schedules", params = {"year", "month"})
- public ResponseEntity findSchedulesInPeriod(
+ public ResponseEntity findScheduleInMonth(
@PathVariable final Long teamPlaceId,
@RequestParam final Integer year,
@RequestParam final Integer month
) {
- final SchedulesResponse responseBody = teamCalendarScheduleService.findScheduleInPeriod(teamPlaceId, year, month);
+ final SchedulesResponse responseBody = teamCalendarScheduleService.findScheduleInMonth(teamPlaceId, year, month);
return ResponseEntity.ok(responseBody);
}
@@ -55,7 +55,18 @@ public ResponseEntity findDailySchedule(
@RequestParam final Integer month,
@RequestParam final Integer day
) {
- final SchedulesResponse response = teamCalendarScheduleService.findScheduleInPeriod(teamPlaceId, year, month, day);
+ final SchedulesResponse response = teamCalendarScheduleService.findScheduleInDay(teamPlaceId, year, month, day);
+
+ return ResponseEntity.ok(response);
+ }
+
+ @GetMapping(value = "/{teamPlaceId}/calendar/schedules", params = {"startDate", "endDate"})
+ public ResponseEntity findDailySchedule(
+ @PathVariable final Long teamPlaceId,
+ @RequestParam(value = "startDate") final String startDate,
+ @RequestParam(value = "endDate") final String endDate
+ ) {
+ final SchedulesResponse response = teamCalendarScheduleService.findScheduleInPeriod(teamPlaceId, startDate, endDate);
return ResponseEntity.ok(response);
}
diff --git a/backend/src/test/java/team/teamby/teambyteam/common/fixtures/acceptance/MyCalendarScheduleAcceptanceFixtures.java b/backend/src/test/java/team/teamby/teambyteam/common/fixtures/acceptance/MyCalendarScheduleAcceptanceFixtures.java
index e489570d0..1bedc1a59 100644
--- a/backend/src/test/java/team/teamby/teambyteam/common/fixtures/acceptance/MyCalendarScheduleAcceptanceFixtures.java
+++ b/backend/src/test/java/team/teamby/teambyteam/common/fixtures/acceptance/MyCalendarScheduleAcceptanceFixtures.java
@@ -21,6 +21,21 @@ public static ExtractableResponse FIND_PERIOD_SCHEDULE_REQUEST(final S
.extract();
}
+ public static ExtractableResponse FIND_PERIOD_SCHEDULE_REQUEST(
+ final String token,
+ final String startDate,
+ final String endDate
+ ) {
+ return RestAssured.given().log().all()
+ .header(new Header(HttpHeaders.AUTHORIZATION, JWT_PREFIX + token))
+ .queryParam("startDate", startDate)
+ .queryParam("endDate", endDate)
+ .when().log().all()
+ .get("/api/my-calendar/schedules")
+ .then().log().all()
+ .extract();
+ }
+
public static ExtractableResponse FIND_DAILY_SCHEDULE_REQUEST(final String token, final Integer year, final Integer month, final Integer day) {
return RestAssured.given().log().all()
.header(new Header(HttpHeaders.AUTHORIZATION, JWT_PREFIX + token))
diff --git a/backend/src/test/java/team/teamby/teambyteam/common/fixtures/acceptance/TeamCalendarScheduleAcceptanceFixtures.java b/backend/src/test/java/team/teamby/teambyteam/common/fixtures/acceptance/TeamCalendarScheduleAcceptanceFixtures.java
index 3c6b9f615..4c868b1ff 100644
--- a/backend/src/test/java/team/teamby/teambyteam/common/fixtures/acceptance/TeamCalendarScheduleAcceptanceFixtures.java
+++ b/backend/src/test/java/team/teamby/teambyteam/common/fixtures/acceptance/TeamCalendarScheduleAcceptanceFixtures.java
@@ -44,6 +44,18 @@ public static ExtractableResponse FIND_PERIOD_SCHEDULE_REQUEST(final S
.extract();
}
+ public static ExtractableResponse FIND_PERIOD_SCHEDULE_REQUEST(final String token, final Long teamPlaceId, final String startDate, final String endDate) {
+ return RestAssured.given().log().all()
+ .header(new Header(HttpHeaders.AUTHORIZATION, JWT_PREFIX + token))
+ .pathParam("teamPlaceId", teamPlaceId)
+ .queryParam("startDate", startDate)
+ .queryParam("endDate", endDate)
+ .when().log().all()
+ .get("/api/team-place/{teamPlaceId}/calendar/schedules")
+ .then().log().all()
+ .extract();
+ }
+
public static ExtractableResponse FIND_DAILY_SCHEDULE_REQUEST(final String token, final Long teamPlaceId, final int year, final int month, final int day) {
return RestAssured.given().log().all()
.header(new Header(HttpHeaders.AUTHORIZATION, JWT_PREFIX + token))
diff --git a/backend/src/test/java/team/teamby/teambyteam/schedule/acceptance/MyCalendarScheduleAcceptanceTest.java b/backend/src/test/java/team/teamby/teambyteam/schedule/acceptance/MyCalendarScheduleAcceptanceTest.java
index 8e9c16600..331426037 100644
--- a/backend/src/test/java/team/teamby/teambyteam/schedule/acceptance/MyCalendarScheduleAcceptanceTest.java
+++ b/backend/src/test/java/team/teamby/teambyteam/schedule/acceptance/MyCalendarScheduleAcceptanceTest.java
@@ -100,4 +100,107 @@ void success() {
});
}
}
+
+
+
+ @Nested
+ @DisplayName("내 캘린더 일정을 특정 기간 사이에서 조회를 한다")
+ class MyCalendarFindScheduleInSpecificPeriod {
+
+ @Test
+ @DisplayName("기간으로 조회 성공한다.")
+ void success() {
+ // given
+ final Member PHILIP = testFixtureBuilder.buildMember(PHILIP());
+
+ final TeamPlace ENGLISH_TEAM_PLACE = testFixtureBuilder.buildTeamPlace(ENGLISH_TEAM_PLACE());
+ final TeamPlace JAPANESE_TEAM_PLACE = testFixtureBuilder.buildTeamPlace(JAPANESE_TEAM_PLACE());
+
+ testFixtureBuilder.buildMemberTeamPlace(PHILIP, ENGLISH_TEAM_PLACE);
+ testFixtureBuilder.buildMemberTeamPlace(PHILIP, JAPANESE_TEAM_PLACE);
+
+ final Schedule MONTH_6_AND_MONTH_7_DAY_12_ENGLISH_SCHEDULE = testFixtureBuilder.buildSchedule(MONTH_6_AND_MONTH_7_DAY_12_SCHEDULE(ENGLISH_TEAM_PLACE.getId()));
+ final Schedule MONTH_7_AND_DAY_12_ALL_DAY_ENGLISH_SCHEDULE = testFixtureBuilder.buildSchedule(MONTH_7_AND_DAY_12_ALL_DAY_SCHEDULE(ENGLISH_TEAM_PLACE.getId()));
+ final Schedule MONTH_7_AND_DAY_12_N_HOUR_JAPANESE_SCHEDULE = testFixtureBuilder.buildSchedule(MONTH_7_AND_DAY_12_N_HOUR_SCHEDULE(JAPANESE_TEAM_PLACE.getId()));
+ final Schedule MONTH_7_DAY_28_AND_MONTH_8_SCHEDULE_JAPANESE_SCHEDULE = testFixtureBuilder.buildSchedule(MONTH_7_DAY_28_AND_MONTH_8_SCHEDULE(JAPANESE_TEAM_PLACE.getId()));
+
+ final String startDate = "20230711";
+ final String endDate = "20230712";
+
+ // when
+ final ExtractableResponse response = FIND_PERIOD_SCHEDULE_REQUEST(jwtTokenProvider.generateAccessToken(PHILIP.getEmail().getValue()), startDate, endDate);
+ final List schedules = response.jsonPath().getList("schedules", ScheduleWithTeamPlaceIdResponse.class);
+
+ //then
+ assertSoftly(softly -> {
+ softly.assertThat(response.statusCode()).isEqualTo(HttpStatus.OK.value());
+ softly.assertThat(schedules).hasSize(3);
+ softly.assertThat(schedules.get(0).title()).isEqualTo(MONTH_6_AND_MONTH_7_DAY_12_ENGLISH_SCHEDULE.getTitle().getValue());
+ softly.assertThat(schedules.get(1).title()).isEqualTo(MONTH_7_AND_DAY_12_ALL_DAY_ENGLISH_SCHEDULE.getTitle().getValue());
+ softly.assertThat(schedules.get(2).title()).isEqualTo(MONTH_7_AND_DAY_12_N_HOUR_JAPANESE_SCHEDULE.getTitle().getValue());
+ });
+ }
+
+ @Test
+ @DisplayName("날짜의 순서가 잘못되면 실패한다.")
+ void failWithWrongPeriodDateOrder() {
+ // given
+ final Member PHILIP = testFixtureBuilder.buildMember(PHILIP());
+
+ final TeamPlace ENGLISH_TEAM_PLACE = testFixtureBuilder.buildTeamPlace(ENGLISH_TEAM_PLACE());
+ final TeamPlace JAPANESE_TEAM_PLACE = testFixtureBuilder.buildTeamPlace(JAPANESE_TEAM_PLACE());
+
+ testFixtureBuilder.buildMemberTeamPlace(PHILIP, ENGLISH_TEAM_PLACE);
+ testFixtureBuilder.buildMemberTeamPlace(PHILIP, JAPANESE_TEAM_PLACE);
+
+ testFixtureBuilder.buildSchedule(MONTH_6_AND_MONTH_7_DAY_12_SCHEDULE(ENGLISH_TEAM_PLACE.getId()));
+ testFixtureBuilder.buildSchedule(MONTH_7_AND_DAY_12_ALL_DAY_SCHEDULE(ENGLISH_TEAM_PLACE.getId()));
+ testFixtureBuilder.buildSchedule(MONTH_7_AND_DAY_12_N_HOUR_SCHEDULE(JAPANESE_TEAM_PLACE.getId()));
+ testFixtureBuilder.buildSchedule(MONTH_7_DAY_28_AND_MONTH_8_SCHEDULE(JAPANESE_TEAM_PLACE.getId()));
+
+ final String startDate = "20230711";
+ final String endDate = "20230710";
+
+ // when
+ final ExtractableResponse response = FIND_PERIOD_SCHEDULE_REQUEST(jwtTokenProvider.generateAccessToken(PHILIP.getEmail().getValue()), startDate, endDate);
+ final String errorMessage = response.jsonPath().get("error");
+
+ //then
+ assertSoftly(softly -> {
+ softly.assertThat(response.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value());
+ softly.assertThat(errorMessage).contains("시작 일자가 종료 일자보다 이후일 수 없습니다.");
+ });
+ }
+
+ @Test
+ @DisplayName("잘못된 형식으로 조회요청시 실패한다")
+ void failWithWrongDateFormant() {
+ // given
+ final Member PHILIP = testFixtureBuilder.buildMember(PHILIP());
+
+ final TeamPlace ENGLISH_TEAM_PLACE = testFixtureBuilder.buildTeamPlace(ENGLISH_TEAM_PLACE());
+ final TeamPlace JAPANESE_TEAM_PLACE = testFixtureBuilder.buildTeamPlace(JAPANESE_TEAM_PLACE());
+
+ testFixtureBuilder.buildMemberTeamPlace(PHILIP, ENGLISH_TEAM_PLACE);
+ testFixtureBuilder.buildMemberTeamPlace(PHILIP, JAPANESE_TEAM_PLACE);
+
+ testFixtureBuilder.buildSchedule(MONTH_6_AND_MONTH_7_DAY_12_SCHEDULE(ENGLISH_TEAM_PLACE.getId()));
+ testFixtureBuilder.buildSchedule(MONTH_7_AND_DAY_12_ALL_DAY_SCHEDULE(ENGLISH_TEAM_PLACE.getId()));
+ testFixtureBuilder.buildSchedule(MONTH_7_AND_DAY_12_N_HOUR_SCHEDULE(JAPANESE_TEAM_PLACE.getId()));
+ testFixtureBuilder.buildSchedule(MONTH_7_DAY_28_AND_MONTH_8_SCHEDULE(JAPANESE_TEAM_PLACE.getId()));
+
+ final String startDate = "2023-07-11";
+ final String endDate = "20230712";
+
+ // when
+ final ExtractableResponse response = FIND_PERIOD_SCHEDULE_REQUEST(jwtTokenProvider.generateAccessToken(PHILIP.getEmail().getValue()), startDate, endDate);
+ final String errorMessage = response.jsonPath().get("error");
+
+ //then
+ assertSoftly(softly -> {
+ softly.assertThat(response.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value());
+ softly.assertThat(errorMessage).isEqualTo("잘못된 날짜 입력 형식입니다.");
+ });
+ }
+ }
}
diff --git a/backend/src/test/java/team/teamby/teambyteam/schedule/acceptance/TeamCalendarScheduleAcceptanceTest.java b/backend/src/test/java/team/teamby/teambyteam/schedule/acceptance/TeamCalendarScheduleAcceptanceTest.java
index 2db8d5719..23a65d5fe 100644
--- a/backend/src/test/java/team/teamby/teambyteam/schedule/acceptance/TeamCalendarScheduleAcceptanceTest.java
+++ b/backend/src/test/java/team/teamby/teambyteam/schedule/acceptance/TeamCalendarScheduleAcceptanceTest.java
@@ -34,10 +34,22 @@
import static org.assertj.core.api.SoftAssertions.assertSoftly;
import static team.teamby.teambyteam.common.fixtures.MemberFixtures.PHILIP;
import static team.teamby.teambyteam.common.fixtures.MemberTeamPlaceFixtures.PHILIP_ENGLISH_TEAM_PLACE;
-import static team.teamby.teambyteam.common.fixtures.ScheduleFixtures.*;
+import static team.teamby.teambyteam.common.fixtures.ScheduleFixtures.MONTH_6_AND_MONTH_7_DAY_12_SCHEDULE;
+import static team.teamby.teambyteam.common.fixtures.ScheduleFixtures.MONTH_7_AND_DAY_12_ALL_DAY_SCHEDULE;
+import static team.teamby.teambyteam.common.fixtures.ScheduleFixtures.MONTH_7_AND_DAY_12_N_HOUR_SCHEDULE;
+import static team.teamby.teambyteam.common.fixtures.ScheduleFixtures.MONTH_7_AND_DAY_12_N_HOUR_SCHEDULE_REGISTER_REQUEST;
+import static team.teamby.teambyteam.common.fixtures.ScheduleFixtures.MONTH_7_AND_DAY_12_N_HOUR_SCHEDULE_TITLE;
+import static team.teamby.teambyteam.common.fixtures.ScheduleFixtures.MONTH_7_AND_DAY_12_N_HOUR_SCHEDULE_UPDATE_REQUEST;
+import static team.teamby.teambyteam.common.fixtures.ScheduleFixtures.MONTH_7_DAY_28_AND_MONTH_8_SCHEDULE;
+import static team.teamby.teambyteam.common.fixtures.ScheduleFixtures.MONTH_7_DAY_29_AND_MONTH_8_SCHEDULE;
import static team.teamby.teambyteam.common.fixtures.TeamPlaceFixtures.ENGLISH_TEAM_PLACE;
import static team.teamby.teambyteam.common.fixtures.TeamPlaceFixtures.JAPANESE_TEAM_PLACE;
-import static team.teamby.teambyteam.common.fixtures.acceptance.TeamCalendarScheduleAcceptanceFixtures.*;
+import static team.teamby.teambyteam.common.fixtures.acceptance.TeamCalendarScheduleAcceptanceFixtures.DELETE_SCHEDULE_REQUEST;
+import static team.teamby.teambyteam.common.fixtures.acceptance.TeamCalendarScheduleAcceptanceFixtures.FIND_DAILY_SCHEDULE_REQUEST;
+import static team.teamby.teambyteam.common.fixtures.acceptance.TeamCalendarScheduleAcceptanceFixtures.FIND_PERIOD_SCHEDULE_REQUEST;
+import static team.teamby.teambyteam.common.fixtures.acceptance.TeamCalendarScheduleAcceptanceFixtures.FIND_SPECIFIC_SCHEDULE_REQUEST;
+import static team.teamby.teambyteam.common.fixtures.acceptance.TeamCalendarScheduleAcceptanceFixtures.REGISTER_SCHEDULE_REQUEST;
+import static team.teamby.teambyteam.common.fixtures.acceptance.TeamCalendarScheduleAcceptanceFixtures.UPDATE_SCHEDULE_REQUEST;
public class TeamCalendarScheduleAcceptanceTest extends AcceptanceTest {
@@ -129,7 +141,7 @@ void failMemberHasNotTeamPlaceSchedule() {
@Nested
@DisplayName("팀 캘린더 내 기간 일정 조회 시")
- class FindTeamCalendarScheduleInPeriod {
+ class FindTeamCalendarScheduleInMonthlyPeriod {
@Test
@DisplayName("기간으로 조회 성공한다.")
@@ -211,6 +223,79 @@ void failWithWrongQuery() {
}
}
+ @Nested
+ @DisplayName("팀 캘린더 기간 지정 일정 조회 시")
+ class FindTeamCalendarScheduleInSpecificPeriod {
+
+ @Test
+ @DisplayName("기간으로 조회 성공한다.")
+ void success() {
+ // given
+ final Member PHILIP = testFixtureBuilder.buildMember(PHILIP());
+ final TeamPlace ENGLISH_TEAM_PLACE = testFixtureBuilder.buildTeamPlace(ENGLISH_TEAM_PLACE());
+ final MemberTeamPlace PHILIP_ENGLISH_TEAM_PLACE = PHILIP_ENGLISH_TEAM_PLACE();
+ PHILIP_ENGLISH_TEAM_PLACE.setMemberAndTeamPlace(PHILIP, ENGLISH_TEAM_PLACE);
+ testFixtureBuilder.buildMemberTeamPlace(PHILIP_ENGLISH_TEAM_PLACE);
+
+ final List schedulesToSave = List.of(
+ MONTH_6_AND_MONTH_7_DAY_12_SCHEDULE(ENGLISH_TEAM_PLACE.getId()),
+ MONTH_7_AND_DAY_12_ALL_DAY_SCHEDULE(ENGLISH_TEAM_PLACE.getId()),
+ MONTH_7_AND_DAY_12_N_HOUR_SCHEDULE(ENGLISH_TEAM_PLACE.getId()),
+ MONTH_7_DAY_28_AND_MONTH_8_SCHEDULE(ENGLISH_TEAM_PLACE.getId()),
+ MONTH_7_DAY_29_AND_MONTH_8_SCHEDULE(ENGLISH_TEAM_PLACE.getId())
+ );
+ final List expectedSchedules = testFixtureBuilder.buildSchedules(schedulesToSave);
+ final String startDate = "20230712";
+ final String endDate = "20230728";
+
+ // when
+ final ExtractableResponse response = FIND_PERIOD_SCHEDULE_REQUEST(jwtTokenProvider.generateAccessToken(PHILIP.getEmail().getValue()), ENGLISH_TEAM_PLACE.getId(), startDate, endDate);
+ final List actualSchedules = response.jsonPath().getList("schedules", ScheduleResponse.class);
+
+ //then
+ assertSoftly(softly -> {
+ softly.assertThat(response.statusCode()).isEqualTo(HttpStatus.OK.value());
+ softly.assertThat(actualSchedules.size()).isEqualTo(4);
+ softly.assertThat(actualSchedules.get(0).title()).isEqualTo(expectedSchedules.get(0).getTitle().getValue());
+ softly.assertThat(actualSchedules.get(1).title()).isEqualTo(expectedSchedules.get(1).getTitle().getValue());
+ softly.assertThat(actualSchedules.get(2).title()).isEqualTo(expectedSchedules.get(2).getTitle().getValue());
+ softly.assertThat(actualSchedules.get(3).title()).isEqualTo(expectedSchedules.get(3).getTitle().getValue());
+ });
+ }
+
+ @Test
+ @DisplayName("잘못된 날짜 형식으로 요청시 실패한다.")
+ void failWithWrongFormat() {
+ // given
+ final Member PHILIP = testFixtureBuilder.buildMember(PHILIP());
+ final TeamPlace ENGLISH_TEAM_PLACE = testFixtureBuilder.buildTeamPlace(ENGLISH_TEAM_PLACE());
+ final MemberTeamPlace PHILIP_ENGLISH_TEAM_PLACE = PHILIP_ENGLISH_TEAM_PLACE();
+ PHILIP_ENGLISH_TEAM_PLACE.setMemberAndTeamPlace(PHILIP, ENGLISH_TEAM_PLACE);
+ testFixtureBuilder.buildMemberTeamPlace(PHILIP_ENGLISH_TEAM_PLACE);
+
+ final List schedulesToSave = List.of(
+ MONTH_6_AND_MONTH_7_DAY_12_SCHEDULE(ENGLISH_TEAM_PLACE.getId()),
+ MONTH_7_AND_DAY_12_ALL_DAY_SCHEDULE(ENGLISH_TEAM_PLACE.getId()),
+ MONTH_7_AND_DAY_12_N_HOUR_SCHEDULE(ENGLISH_TEAM_PLACE.getId()),
+ MONTH_7_DAY_28_AND_MONTH_8_SCHEDULE(ENGLISH_TEAM_PLACE.getId()),
+ MONTH_7_DAY_29_AND_MONTH_8_SCHEDULE(ENGLISH_TEAM_PLACE.getId())
+ );
+ testFixtureBuilder.buildSchedules(schedulesToSave);
+ final String startDate = "2023-07-12";
+ final String endDate = "2023-07-28";
+
+ // when
+ final ExtractableResponse response = FIND_PERIOD_SCHEDULE_REQUEST(jwtTokenProvider.generateAccessToken(PHILIP.getEmail().getValue()), ENGLISH_TEAM_PLACE.getId(), startDate, endDate);
+ final String errorMessage = response.jsonPath().get("error");
+
+ //then
+ assertSoftly(softly -> {
+ softly.assertThat(response.statusCode()).isEqualTo(HttpStatus.BAD_REQUEST.value());
+ softly.assertThat(errorMessage).isEqualTo("잘못된 날짜 입력 형식입니다.");
+ });
+ }
+ }
+
@Nested
@DisplayName("팀 캘린더 하루 일정 조회 시")
class FindTeamCalendarDailySchedule {
@@ -499,7 +584,6 @@ private ExtractableResponse wrongDateTimeTypeRegisterScheduleRequest(f
}
}
-
@Nested
@DisplayName("일정 수정 시")
class UpdateSchedule {
diff --git a/backend/src/test/java/team/teamby/teambyteam/schedule/application/LocalDateParserTest.java b/backend/src/test/java/team/teamby/teambyteam/schedule/application/LocalDateParserTest.java
new file mode 100644
index 000000000..47b9bcdd4
--- /dev/null
+++ b/backend/src/test/java/team/teamby/teambyteam/schedule/application/LocalDateParserTest.java
@@ -0,0 +1,46 @@
+package team.teamby.teambyteam.schedule.application;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
+import team.teamby.teambyteam.schedule.application.parser.LocalDateParser;
+import team.teamby.teambyteam.schedule.exception.ScheduleException;
+
+import java.time.LocalDate;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+class LocalDateParserTest {
+
+ private final LocalDateParser localDateParser = new LocalDateParser();
+
+ @Test
+ @DisplayName("LocalDate 파싱을 성공한다")
+ void success() {
+ // given
+ final String input = "20230102";
+
+ // when
+ final LocalDate actual = localDateParser.parse(input);
+
+ // then
+ assertThat(actual).isEqualTo(LocalDate.of(2023, 1, 2));
+ }
+
+ @ParameterizedTest
+ @ValueSource(strings = {"2023-01-01", "2023721", "20230132"})
+ @DisplayName("yyyyMMdd형식이 아닌 경우 예외가 발생한다.")
+ void failWithWrongFormat(final String input) {
+ // given
+
+ // when
+ // then
+ assertThatThrownBy(() -> localDateParser.parse(input))
+ .isInstanceOf(ScheduleException.dateFormatException.class)
+ .hasMessage("잘못된 날짜 입력 형식입니다.");
+
+ }
+
+}
diff --git a/backend/src/test/java/team/teamby/teambyteam/schedule/application/MyCalendarScheduleServiceTest.java b/backend/src/test/java/team/teamby/teambyteam/schedule/application/MyCalendarScheduleServiceTest.java
index db0723229..5d80ec35a 100644
--- a/backend/src/test/java/team/teamby/teambyteam/schedule/application/MyCalendarScheduleServiceTest.java
+++ b/backend/src/test/java/team/teamby/teambyteam/schedule/application/MyCalendarScheduleServiceTest.java
@@ -17,6 +17,7 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.SoftAssertions.assertSoftly;
import static team.teamby.teambyteam.common.fixtures.MemberFixtures.PHILIP;
+import static team.teamby.teambyteam.common.fixtures.ScheduleFixtures.MONTH_5_LAST_DAY_SCHEDULE;
import static team.teamby.teambyteam.common.fixtures.ScheduleFixtures.MONTH_6_AND_MONTH_7_DAY_12_SCHEDULE;
import static team.teamby.teambyteam.common.fixtures.ScheduleFixtures.MONTH_6_AND_MONTH_7_SCHEDULE;
import static team.teamby.teambyteam.common.fixtures.ScheduleFixtures.MONTH_7_AND_DAY_12_ALL_DAY_SCHEDULE;
@@ -128,4 +129,43 @@ void successEmptyList() {
assertThat(dailyScheduleResponse.schedules()).hasSize(0);
}
}
+
+ @Nested
+ @DisplayName("특정 기간 안에서 내 캘린더 정보 조회 시")
+ class FindScheduleInMyCalendarInSpecificPeriod {
+
+ @Test
+ @DisplayName("내 캘린더 정보 조회를 성공한다.")
+ void success() {
+ // given
+ final Member PHILIP = testFixtureBuilder.buildMember(PHILIP());
+ final TeamPlace ENGLISH_TEAM_PLACE = testFixtureBuilder.buildTeamPlace(ENGLISH_TEAM_PLACE());
+ final TeamPlace JAPANESE_TEAM_PLACE = testFixtureBuilder.buildTeamPlace(JAPANESE_TEAM_PLACE());
+
+ testFixtureBuilder.buildMemberTeamPlace(PHILIP, ENGLISH_TEAM_PLACE);
+ testFixtureBuilder.buildMemberTeamPlace(PHILIP, JAPANESE_TEAM_PLACE);
+
+ final List expectedSchedules = List.of(
+ MONTH_5_LAST_DAY_SCHEDULE(ENGLISH_TEAM_PLACE.getId()),
+ MONTH_7_AND_DAY_12_ALL_DAY_SCHEDULE(ENGLISH_TEAM_PLACE.getId()),
+ MONTH_7_AND_DAY_12_N_HOUR_SCHEDULE(JAPANESE_TEAM_PLACE.getId())
+ );
+ testFixtureBuilder.buildSchedules(expectedSchedules);
+
+ final MemberEmailDto memberEmailDto = new MemberEmailDto(PHILIP.getEmail().getValue());
+ final String startDate = "20230601";
+ final String endDate = "20230712";
+
+ // when
+ final SchedulesWithTeamPlaceIdResponse scheduleInPeriod = myCalendarScheduleService.findScheduleInPeriod(memberEmailDto, startDate, endDate);
+ final List scheduleResponses = scheduleInPeriod.schedules();
+
+ //then
+ assertSoftly(softly -> {
+ softly.assertThat(scheduleResponses).hasSize(2);
+ softly.assertThat(scheduleResponses.get(0).title()).isEqualTo(expectedSchedules.get(1).getTitle().getValue());
+ softly.assertThat(scheduleResponses.get(1).title()).isEqualTo(expectedSchedules.get(2).getTitle().getValue());
+ });
+ }
+ }
}
diff --git a/backend/src/test/java/team/teamby/teambyteam/schedule/application/TeamCalendarScheduleServiceTest.java b/backend/src/test/java/team/teamby/teambyteam/schedule/application/TeamCalendarScheduleServiceTest.java
index 7ec53b1ed..8f81f0833 100644
--- a/backend/src/test/java/team/teamby/teambyteam/schedule/application/TeamCalendarScheduleServiceTest.java
+++ b/backend/src/test/java/team/teamby/teambyteam/schedule/application/TeamCalendarScheduleServiceTest.java
@@ -4,6 +4,7 @@
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.beans.factory.annotation.Autowired;
import team.teamby.teambyteam.common.ServiceTest;
@@ -108,8 +109,8 @@ void failFindOtherTeamPlaceSchedule() {
}
@Test
- @DisplayName("팀 캘린더에서 특정 기간 내 일정들을 조회한다.")
- void findAllInPeriod() {
+ @DisplayName("팀 캘린더에서 1달 내 일정들을 조회한다.")
+ void findAllInMonthlyPeriod() {
// given
final TeamPlace ENGLISH_TEAM_PLACE = testFixtureBuilder.buildTeamPlace(ENGLISH_TEAM_PLACE());
final Schedule MONTH_6_AND_MONTH_7_SCHEDULE = testFixtureBuilder.buildSchedule(MONTH_6_AND_MONTH_7_DAY_12_SCHEDULE(ENGLISH_TEAM_PLACE.getId()));
@@ -121,7 +122,7 @@ void findAllInPeriod() {
final int month = 7;
// when
- final SchedulesResponse schedulesResponse = teamCalendarScheduleService.findScheduleInPeriod(ENGLISH_TEAM_PLACE.getId(), year, month);
+ final SchedulesResponse schedulesResponse = teamCalendarScheduleService.findScheduleInMonth(ENGLISH_TEAM_PLACE.getId(), year, month);
final List scheduleResponses = schedulesResponse.schedules();
//then
@@ -134,6 +135,47 @@ void findAllInPeriod() {
});
}
+ @Test
+ @DisplayName("팀 캘린더에서 입력된 기간내 일정들을 조회한다.")
+ void findAllInSpecificPeriod() {
+ // given
+ final TeamPlace ENGLISH_TEAM_PLACE = testFixtureBuilder.buildTeamPlace(ENGLISH_TEAM_PLACE());
+ final Schedule MONTH_6_AND_MONTH_7_SCHEDULE = testFixtureBuilder.buildSchedule(MONTH_6_AND_MONTH_7_DAY_12_SCHEDULE(ENGLISH_TEAM_PLACE.getId()));
+ final Schedule MONTH_7_AND_DAY_12_N_HOUR_SCHEDULE = testFixtureBuilder.buildSchedule(MONTH_7_AND_DAY_12_N_HOUR_SCHEDULE(ENGLISH_TEAM_PLACE.getId()));
+ final Schedule MONTH_7_DAY_28_AND_MONTH_8_SCHEDULE = testFixtureBuilder.buildSchedule(MONTH_7_DAY_28_AND_MONTH_8_SCHEDULE(ENGLISH_TEAM_PLACE.getId()));
+ final Schedule MONTH_7_DAY_29_AND_MONTH_8_SCHEDULE = testFixtureBuilder.buildSchedule(MONTH_7_DAY_29_AND_MONTH_8_SCHEDULE(ENGLISH_TEAM_PLACE.getId()));
+
+ final String startDate = "20230712";
+ final String endDate = "20230728";
+
+ // when
+ final SchedulesResponse schedulesResponse = teamCalendarScheduleService.findScheduleInPeriod(ENGLISH_TEAM_PLACE.getId(), startDate, endDate);
+ final List scheduleResponses = schedulesResponse.schedules();
+
+ //then
+ assertSoftly(softly -> {
+ softly.assertThat(scheduleResponses).hasSize(3);
+ softly.assertThat(scheduleResponses.get(0).title()).isEqualTo(MONTH_6_AND_MONTH_7_SCHEDULE.getTitle().getValue());
+ softly.assertThat(scheduleResponses.get(1).title()).isEqualTo(MONTH_7_AND_DAY_12_N_HOUR_SCHEDULE.getTitle().getValue());
+ softly.assertThat(scheduleResponses.get(2).title()).isEqualTo(MONTH_7_DAY_28_AND_MONTH_8_SCHEDULE.getTitle().getValue());
+ });
+ }
+
+ @ParameterizedTest
+ @CsvSource(value = {"2023712,20230728", "20230712,0728"}, delimiter = ',')
+ @DisplayName("특정기간 조회시 일정 포멧이 yyyyMMdd와 다르면 예외를 발생시킨다.")
+ void failWithWrongDateFormat(final String startDate, final String endDate) {
+ // given
+ final TeamPlace ENGLISH_TEAM_PLACE = testFixtureBuilder.buildTeamPlace(ENGLISH_TEAM_PLACE());
+
+ // when
+ // then
+ assertThatThrownBy(() -> teamCalendarScheduleService.findScheduleInPeriod(ENGLISH_TEAM_PLACE.getId(), startDate, endDate))
+ .isInstanceOf(ScheduleException.dateFormatException.class)
+ .hasMessage("잘못된 날짜 입력 형식입니다.");
+
+ }
+
@Test
@DisplayName("팀 캘린더에서 일정이 없는 기간 내 일정들을 조회한다.")
void findAllInPeriodWith0Schedule() {
@@ -143,7 +185,7 @@ void findAllInPeriodWith0Schedule() {
final int month = 7;
// when
- final SchedulesResponse schedulesResponse = teamCalendarScheduleService.findScheduleInPeriod(ENGLISH_TEAM_PLACE.getId(), notExistYear, month);
+ final SchedulesResponse schedulesResponse = teamCalendarScheduleService.findScheduleInMonth(ENGLISH_TEAM_PLACE.getId(), notExistYear, month);
final List scheduleResponses = schedulesResponse.schedules();
//then
@@ -162,7 +204,7 @@ void firstAndLastDateScheduleFind() {
final int month = MONTH_5_FIRST_DAY_SCHEDULE.getSpan().getStartDateTime().getMonthValue();
// when
- final SchedulesResponse schedulesResponse = teamCalendarScheduleService.findScheduleInPeriod(ENGLISH_TEAM_PLACE.getId(), year, month);
+ final SchedulesResponse schedulesResponse = teamCalendarScheduleService.findScheduleInMonth(ENGLISH_TEAM_PLACE.getId(), year, month);
final List scheduleResponses = schedulesResponse.schedules();
//then
@@ -194,7 +236,7 @@ void success() {
// when
final SchedulesResponse dailySchedulesResponse =
- teamCalendarScheduleService.findScheduleInPeriod(ENGLISH_TEAM_PLACE_ID, year, month, day);
+ teamCalendarScheduleService.findScheduleInDay(ENGLISH_TEAM_PLACE_ID, year, month, day);
final List dailyTeamCalendarSchedulesResponses = dailySchedulesResponse.schedules();
// then
@@ -226,7 +268,7 @@ void wrongYear() {
final int day = MONTH_7_AND_DAY_12_N_HOUR_SCHEDULE.getSpan().getStartDateTime().getDayOfMonth();
// when & then
- assertThatThrownBy(() -> teamCalendarScheduleService.findScheduleInPeriod(ENGLISH_TEAM_PLACE_ID, wrongYear, month, day))
+ assertThatThrownBy(() -> teamCalendarScheduleService.findScheduleInDay(ENGLISH_TEAM_PLACE_ID, wrongYear, month, day))
.isInstanceOf(DateTimeException.class)
.hasMessageContaining("Invalid value for Year (valid values -999999999 - 999999999)");
}
@@ -243,7 +285,7 @@ void wrongMonth() {
final int day = MONTH_7_AND_DAY_12_N_HOUR_SCHEDULE.getSpan().getStartDateTime().getDayOfMonth();
// when & then
- assertThatThrownBy(() -> teamCalendarScheduleService.findScheduleInPeriod(ENGLISH_TEAM_PLACE_ID, year, wrongMonth, day))
+ assertThatThrownBy(() -> teamCalendarScheduleService.findScheduleInDay(ENGLISH_TEAM_PLACE_ID, year, wrongMonth, day))
.isInstanceOf(DateTimeException.class)
.hasMessageContaining("Invalid value for MonthOfYear (valid values 1 - 12)");
}
@@ -260,7 +302,7 @@ void wrongDay() {
final int wrongDay = -1;
// when & then
- assertThatThrownBy(() -> teamCalendarScheduleService.findScheduleInPeriod(ENGLISH_TEAM_PLACE_ID, year, month, wrongDay))
+ assertThatThrownBy(() -> teamCalendarScheduleService.findScheduleInDay(ENGLISH_TEAM_PLACE_ID, year, month, wrongDay))
.isInstanceOf(DateTimeException.class)
.hasMessageContaining("Invalid value for DayOfMonth (valid values 1 - 28/31)");
}
@@ -276,7 +318,7 @@ void successNotExistSchedule() {
final int day = 1;
// when
- SchedulesResponse schedules = teamCalendarScheduleService.findScheduleInPeriod(ENGLISH_TEAM_PLACE.getId(), year, month, day);
+ SchedulesResponse schedules = teamCalendarScheduleService.findScheduleInDay(ENGLISH_TEAM_PLACE.getId(), year, month, day);
// then
assertThat(schedules.schedules()).hasSize(0);
@@ -292,7 +334,7 @@ void failTeamPlaceNotExist() {
final int day = 1;
// when & then
- assertThatThrownBy(() -> teamCalendarScheduleService.findScheduleInPeriod(notExistTeamPlaceId, year, month, day))
+ assertThatThrownBy(() -> teamCalendarScheduleService.findScheduleInDay(notExistTeamPlaceId, year, month, day))
.isInstanceOf(TeamPlaceException.NotFoundException.class)
.hasMessageContaining("조회한 팀 플레이스가 존재하지 않습니다.");
}
diff --git a/backend/src/test/java/team/teamby/teambyteam/schedule/docs/TeamCalendarScheduleApiDocsTest.java b/backend/src/test/java/team/teamby/teambyteam/schedule/docs/TeamCalendarScheduleApiDocsTest.java
index 01ccf2cfd..0c630f5ec 100644
--- a/backend/src/test/java/team/teamby/teambyteam/schedule/docs/TeamCalendarScheduleApiDocsTest.java
+++ b/backend/src/test/java/team/teamby/teambyteam/schedule/docs/TeamCalendarScheduleApiDocsTest.java
@@ -426,7 +426,7 @@ void success() throws Exception {
List schedules = List.of(schedule1, schedule2);
SchedulesResponse response = SchedulesResponse.of(schedules);
- given(teamCalendarScheduleService.findScheduleInPeriod(teamPlaceId, 2023, 7))
+ given(teamCalendarScheduleService.findScheduleInMonth(teamPlaceId, 2023, 7))
.willReturn(response);
// when & then
@@ -469,7 +469,7 @@ void failNotExistTeamplaceId() throws Exception {
willThrow(new TeamPlaceException.NotFoundException(teamPlaceId))
.given(teamCalendarScheduleService)
- .findScheduleInPeriod(teamPlaceId, 2023, 7);
+ .findScheduleInMonth(teamPlaceId, 2023, 7);
// when & then
mockMvc.perform(get("/api/team-place/{teamPlaceId}/calendar/schedules", teamPlaceId)
@@ -504,7 +504,7 @@ void success() throws Exception {
List schedules = List.of(schedule1, schedule2);
SchedulesResponse response = SchedulesResponse.of(schedules);
- given(teamCalendarScheduleService.findScheduleInPeriod(teamPlaceId, 2023, 7, 12))
+ given(teamCalendarScheduleService.findScheduleInDay(teamPlaceId, 2023, 7, 12))
.willReturn(response);
// when & then
@@ -549,7 +549,7 @@ void failNotExistTeamplaceId() throws Exception {
willThrow(new TeamPlaceException.NotFoundException(teamPlaceId))
.given(teamCalendarScheduleService)
- .findScheduleInPeriod(teamPlaceId, 2023, 7, 12);
+ .findScheduleInDay(teamPlaceId, 2023, 7, 12);
// when & then
mockMvc.perform(get("/api/team-place/{teamPlaceId}/calendar/schedules", teamPlaceId)
diff --git a/backend/src/test/java/team/teamby/teambyteam/schedule/domain/CalendarPeriodTest.java b/backend/src/test/java/team/teamby/teambyteam/schedule/domain/CalendarPeriodTest.java
new file mode 100644
index 000000000..5407915ab
--- /dev/null
+++ b/backend/src/test/java/team/teamby/teambyteam/schedule/domain/CalendarPeriodTest.java
@@ -0,0 +1,46 @@
+package team.teamby.teambyteam.schedule.domain;
+
+import org.assertj.core.api.SoftAssertions;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import team.teamby.teambyteam.schedule.exception.ScheduleException;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static team.teamby.teambyteam.schedule.domain.CalendarPeriod.of;
+
+class CalendarPeriodTest {
+
+ @Test
+ @DisplayName("LocalDate로 생성 테스트")
+ void createWithLocalDate() {
+ // given
+ final LocalDate startDate = LocalDate.of(2023, 1, 1);
+ final LocalDate endDate = LocalDate.of(2023, 1, 1);
+
+ // when
+ final CalendarPeriod calendarPeriod = of(startDate, endDate);
+
+ // then
+ SoftAssertions.assertSoftly(softly -> {
+ softly.assertThat(calendarPeriod.startDateTime()).isEqualTo(LocalDateTime.of(2023, 1, 1, 0, 0, 0));
+ softly.assertThat(calendarPeriod.endDatetime()).isEqualTo(LocalDateTime.of(2023, 1, 2, 0, 0, 0));
+ });
+ }
+
+ @Test
+ @DisplayName("시작일보다 이른 종료일로 생성시 예외 발생")
+ void exceptionWithWrongPeriodOrder() {
+ // given
+ final LocalDate startDate = LocalDate.of(2023, 1, 2);
+ final LocalDate endDate = LocalDate.of(2023, 1, 1);
+
+ // when
+ // then
+ assertThatThrownBy(() -> of(startDate, endDate))
+ .isInstanceOf(ScheduleException.SpanWrongOrderException.class)
+ .hasMessageContaining("시작 일자가 종료 일자보다 이후일 수 없습니다.");
+ }
+}
diff --git a/frontend/src/App.css b/frontend/src/App.css
index 495aabeef..69be8de20 100644
--- a/frontend/src/App.css
+++ b/frontend/src/App.css
@@ -6,6 +6,9 @@ This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
*/
+:root {
+ --vh: 100%;
+}
@font-face {
font-family: 'Pretendard';
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 921601fa7..7a3e4228c 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -19,10 +19,16 @@ import { getIsMobile } from '~/utils/getIsMobile';
import M_LandingPage from '~/mobilePages/M_LandingPage/M_LandingPage';
import M_TeamSelectPage from '~/mobilePages/M_TeamSelectPage/M_TeamSelectPage';
import M_PageTemplate from '~/mobilePages/M_PageTemplate/M_PageTemplate';
+import { useEffect } from 'react';
const App = () => {
const isMobile = getIsMobile();
+ useEffect(() => {
+ const vh = window.innerHeight * 0.01;
+ document.documentElement.style.setProperty('--vh', `${vh}px`);
+ }, []);
+
return (
{isMobile ? (
diff --git a/frontend/src/apis/feed.ts b/frontend/src/apis/feed.ts
index 192cffd5b..f21b1db1f 100644
--- a/frontend/src/apis/feed.ts
+++ b/frontend/src/apis/feed.ts
@@ -2,7 +2,7 @@ import { http } from '~/apis/http';
import { THREAD_SIZE } from '~/constants/feed';
import type { Thread, NoticeThread } from '~/types/feed';
-interface ThreadsResponse {
+export interface ThreadsResponse {
threads: Thread[];
}
diff --git a/frontend/src/apis/schedule.ts b/frontend/src/apis/schedule.ts
index c3459e844..122c24046 100644
--- a/frontend/src/apis/schedule.ts
+++ b/frontend/src/apis/schedule.ts
@@ -19,25 +19,18 @@ interface ICalendarResponse {
export const fetchSchedules = (
teamPlaceId: number,
- year: number,
- month: number,
- day?: number,
+ startDate: string,
+ endDate: string,
) => {
- const query = day
- ? `year=${year}&month=${month}&day=${day}`
- : `year=${year}&month=${month}`;
-
return http.get(
- `/api/team-place/${teamPlaceId}/calendar/schedules?${query}`,
+ `/api/team-place/${teamPlaceId}/calendar/schedules?startDate=${startDate}&endDate=${endDate}`,
);
};
-export const fetchMySchedules = (year: number, month: number, day?: number) => {
- const query = day
- ? `year=${year}&month=${month}&day=${day}`
- : `year=${year}&month=${month}`;
-
- return http.get(`/api/my-calendar/schedules?${query}`);
+export const fetchMySchedules = (startDate: string, endDate: string) => {
+ return http.get(
+ `/api/my-calendar/schedules?startDate=${startDate}&endDate=${endDate}`,
+ );
};
export const fetchScheduleById = (teamPlaceId: number, scheduleId: number) => {
diff --git a/frontend/src/components/common/Header/Header.styled.ts b/frontend/src/components/common/Header/Header.styled.ts
index 78c5aff97..93227231c 100644
--- a/frontend/src/components/common/Header/Header.styled.ts
+++ b/frontend/src/components/common/Header/Header.styled.ts
@@ -14,7 +14,7 @@ export const Header = styled.header<{ $isMobile: boolean }>`
${({ $isMobile }) =>
$isMobile &&
css`
- height: 110px;
+ height: 90px;
flex-wrap: wrap;
flex-direction: row-reverse;
`}
@@ -62,9 +62,17 @@ export const TeamNameWrapper = styled.div`
align-items: center;
`;
-export const ProfileImage = styled.img`
- width: 40px;
- height: 40px;
+export const ProfileImage = styled.img<{ $isMobile: boolean }>`
+ ${({ $isMobile }) =>
+ $isMobile
+ ? css`
+ width: 30px;
+ height: 30px;
+ `
+ : css`
+ width: 40px;
+ height: 40px;
+ `}
border-radius: 50%;
object-fit: cover;
@@ -91,14 +99,22 @@ export const notificationButton = css`
}
`;
-export const teamPlaceInfoButton = css`
+export const teamPlaceInfoButton = ($isMobile: boolean) => css`
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
- width: 44px;
- height: 44px;
+ ${$isMobile
+ ? css`
+ width: 30px;
+ height: 30px;
+ `
+ : css`
+ width: 44px;
+ height: 44px;
+ `}
+
padding: 0;
border-radius: 50%;
@@ -108,13 +124,21 @@ export const teamPlaceInfoButton = css`
}
`;
-export const userInfoButton = css`
+export const userInfoButton = ($isMobile: boolean) => css`
display: flex;
align-items: center;
justify-content: center;
- width: 50px;
- height: 50px;
+ ${$isMobile
+ ? css`
+ width: 30px;
+ height: 30px;
+ `
+ : css`
+ width: 50px;
+ height: 50px;
+ `}
+
padding: 0;
`;
diff --git a/frontend/src/components/common/Header/Header.tsx b/frontend/src/components/common/Header/Header.tsx
index 384039809..461b66c10 100644
--- a/frontend/src/components/common/Header/Header.tsx
+++ b/frontend/src/components/common/Header/Header.tsx
@@ -171,7 +171,7 @@ const Header = () => {
onFocus={prefetchTeamPlaceInfo}
onMouseEnter={prefetchTeamPlaceInfo}
onClick={handleTeamButtonClick}
- css={S.teamPlaceInfoButton}
+ css={S.teamPlaceInfoButton(isMobile)}
aria-label="팀 정보 보기"
>
@@ -187,11 +187,15 @@ const Header = () => {
diff --git a/frontend/src/components/common/NavigationBar/NavigationBar.styled.ts b/frontend/src/components/common/NavigationBar/NavigationBar.styled.ts
index 1a5d486c9..58b58bdb1 100644
--- a/frontend/src/components/common/NavigationBar/NavigationBar.styled.ts
+++ b/frontend/src/components/common/NavigationBar/NavigationBar.styled.ts
@@ -9,7 +9,6 @@ export const Nav = styled.nav<{ $isMobile: boolean }>`
return css`
width: 100%;
height: 60px;
- padding: 10px;
`;
return css`
diff --git a/frontend/src/components/feed/ImageUploadDrawer/ImageUploadDrawer.stories.tsx b/frontend/src/components/feed/ImageUploadDrawer/ImageUploadDrawer.stories.tsx
index 655ed8e08..2a4371776 100644
--- a/frontend/src/components/feed/ImageUploadDrawer/ImageUploadDrawer.stories.tsx
+++ b/frontend/src/components/feed/ImageUploadDrawer/ImageUploadDrawer.stories.tsx
@@ -33,6 +33,10 @@ const meta = {
description:
'랜더링할 자식 요소를 의미합니다. `ThumbnailList` 컴포넌트가 여기에 오면 됩니다.',
},
+ slideDistance: {
+ description:
+ '서랍장이 열리게 될 경우 얼마나 많은 거리를 위로 움직여야 할 지를 의미합니다. 입력값은 숫자이며 단위는 `px`입니다.',
+ },
onClose: {
description:
'서랍장이 닫히게 될 때 실행시킬 함수를 의미합니다. 서랍장을 실질적으로 닫는 함수를 여기에 넣어 주시면 됩니다.',
@@ -47,6 +51,7 @@ type Story = StoryObj;
export const Default: Story = {
args: {
isOpen: false,
+ slideDistance: 163,
children: (
이 자리에 썸네일 리스트 컴포넌트가 올 것입니다.
@@ -62,6 +67,23 @@ export const Default: Story = {
export const Opened: Story = {
args: {
isOpen: true,
+ slideDistance: 163,
+ children: (
+