Skip to content

Commit 062ed4b

Browse files
authored
[EC-234 FE/refactor 마무리 수정 (#245)
* [EC-234] feat: 유고결석 신청일자 기간내인지 유효성 검증 * [EC-234] fix: 프론트 유고 결석 신청시 예외 메세지 처리 * [EC-234] feat: 유고결석 중복 신청 검증 * [EC-234] feat: 프론트엔드 유고결석 신청 유효성 검증 * [EC-234] feat: 처리된 유고 결석 신청은 취소 불가 예외 처리 * [EC-234] style: FE input box 폰트 적용
1 parent 6952ea2 commit 062ed4b

File tree

8 files changed

+68
-13
lines changed

8 files changed

+68
-13
lines changed

api/src/main/java/org/example/educheck/domain/absenceattendance/repository/AbsenceAttendanceRepository.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@
22

33
import org.example.educheck.domain.absenceattendance.dto.response.MyAbsenceAttendanceResponseDto;
44
import org.example.educheck.domain.absenceattendance.entity.AbsenceAttendance;
5+
import org.example.educheck.domain.course.entity.Course;
6+
import org.example.educheck.domain.member.student.entity.Student;
57
import org.springframework.data.domain.Page;
68
import org.springframework.data.domain.Pageable;
79
import org.springframework.data.jpa.repository.JpaRepository;
810
import org.springframework.data.jpa.repository.Query;
911
import org.springframework.data.repository.query.Param;
1012

13+
import java.time.LocalDate;
14+
1115
public interface AbsenceAttendanceRepository extends JpaRepository<AbsenceAttendance, Long> {
1216
Page<AbsenceAttendance> findByCourseId(Long courseId, Pageable pageable);
1317

@@ -21,4 +25,5 @@ public interface AbsenceAttendanceRepository extends JpaRepository<AbsenceAttend
2125
"WHERE a.course.id = :courseId AND a.student.id = :studentId")
2226
Page<MyAbsenceAttendanceResponseDto> findByStudentIdAndCourseId(@Param("studentId") Long studentId, @Param("courseId") Long courseId, Pageable pageable);
2327

28+
boolean existsByStudentAndCourseAndStartTimeLessThanEqualAndEndTimeGreaterThanEqual(Student student, Course course, LocalDate endDate, LocalDate startDate);
2429
}

api/src/main/java/org/example/educheck/domain/absenceattendance/service/AbsenceAttendanceService.java

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.example.educheck.domain.absenceattendanceattachmentfile.dto.response.AttachmentFileReposeDto;
1212
import org.example.educheck.domain.absenceattendanceattachmentfile.entity.AbsenceAttendanceAttachmentFile;
1313
import org.example.educheck.domain.absenceattendanceattachmentfile.repository.AbsenceAttendanceAttachmentFileRepository;
14+
import org.example.educheck.domain.course.entity.Course;
1415
import org.example.educheck.domain.course.repository.CourseRepository;
1516
import org.example.educheck.domain.member.entity.Member;
1617
import org.example.educheck.domain.member.entity.Role;
@@ -29,6 +30,7 @@
2930
import org.springframework.transaction.annotation.Transactional;
3031
import org.springframework.web.multipart.MultipartFile;
3132

33+
import java.time.LocalDate;
3234
import java.time.LocalDateTime;
3335
import java.util.List;
3436
import java.util.Map;
@@ -66,6 +68,12 @@ private static void validateModifiable(AbsenceAttendance absenceAttendance) {
6668
}
6769
}
6870

71+
private static void validateAttendanceAbsenceCancellable(AbsenceAttendance absenceAttendance) {
72+
if (absenceAttendance.getIsApprove().equals('T') || absenceAttendance.getIsApprove().equals('F')) {
73+
throw new InvalidRequestException("처리된 신청 내역은 취소할 수 없습니다.");
74+
}
75+
}
76+
6977
@Transactional
7078
@PreAuthorize("hasAnyAuthority('MIDDLE_ADMIN')")
7179
public void processAbsenceAttendanceService(Long courseId, Long absenceAttendancesId, ProcessAbsenceAttendanceRequestDto requestDto, Member member) {
@@ -114,9 +122,13 @@ public CreateAbsenceAttendanceResponseDto createAbsenceAttendance(Member member,
114122

115123
validateRegistrationCourse(member, courseId);
116124

125+
Course course = getCourseById(courseId);
126+
validateAbsenceAttendanceDate(requestDto.getStartDate(), requestDto.getEndDate(), course);
127+
validateDuplicateAbsenceAttendance(member, course, requestDto.getStartDate(), requestDto.getEndDate());
128+
129+
117130
AbsenceAttendance absenceAttendance = AbsenceAttendance.builder()
118-
.course(courseRepository.findById(courseId)
119-
.orElseThrow(() -> new ResourceNotFoundException("해당 교육 과정을 찾을 수 없습니다.")))
131+
.course(course)
120132
.student(member.getStudent())
121133
.startTime(requestDto.getStartDate())
122134
.endTime(requestDto.getEndDate())
@@ -131,6 +143,30 @@ public CreateAbsenceAttendanceResponseDto createAbsenceAttendance(Member member,
131143
return CreateAbsenceAttendanceResponseDto.from(savedAbsenceAttendance);
132144
}
133145

146+
private void validateDuplicateAbsenceAttendance(Member member, Course course, LocalDate startDate, LocalDate endDate) {
147+
boolean isDuplicate = absenceAttendanceRepository.existsByStudentAndCourseAndStartTimeLessThanEqualAndEndTimeGreaterThanEqual(
148+
member.getStudent(), course, endDate, startDate);
149+
150+
if (isDuplicate) {
151+
throw new InvalidRequestException("해당 기간에 이미 유고결석 신청이 존재합니다.");
152+
}
153+
}
154+
155+
private void validateAbsenceAttendanceDate(LocalDate startDate, LocalDate endDate, Course course) {
156+
if (startDate.isBefore(course.getStartDate()) || endDate.isAfter(course.getEndDate())) {
157+
throw new InvalidRequestException("유고결석 신청 기간은 교육 과정 기간 내에 있어야 합니다.");
158+
}
159+
160+
if (startDate.isAfter(endDate)) {
161+
throw new InvalidRequestException("유고결석 시작일은 종료일보다 이후일 수 없습니다.");
162+
}
163+
}
164+
165+
private Course getCourseById(Long courseId) {
166+
return courseRepository.findById(courseId)
167+
.orElseThrow(() -> new ResourceNotFoundException("해당 교육 과정을 찾을 수 없습니다."));
168+
}
169+
134170
private void saveAttachmentFiles(MultipartFile[] files, AbsenceAttendance savedAbsenceAttendance) {
135171
log.info("첨부파일 저장 로직 동작");
136172
if (files != null && files.length > 0) {
@@ -178,14 +214,14 @@ public void cancelAttendanceAbsence(Member member, Long absenceAttendancesId) {
178214

179215
AbsenceAttendance absenceAttendance = getAbsenceAttendance(absenceAttendancesId);
180216
validateMatchApplicant(member, absenceAttendance);
217+
validateAttendanceAbsenceCancellable(absenceAttendance);
181218

182219
markAttachementFilesForDeletion(absenceAttendance);
183220

184221
absenceAttendance.markDeletionRequested();
185222
absenceAttendanceRepository.save(absenceAttendance);
186223
}
187224

188-
189225
@Transactional
190226
public UpdateAbsenceAttendanceReponseDto updateAttendanceAbsence(Member member, Long absenceAttendancesId, UpdateAbsenceAttendacneRequestDto requestDto, MultipartFile[] files) {
191227

api/src/main/java/org/example/educheck/domain/studentCourseAttendance/service/StudentCourseAttendanceService.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,6 @@ public TodayAttendanceResponseDto getTodayAttendances(Long courseId, Member memb
164164
.map(TodayAttendanceStatus::from)
165165
.toList();
166166

167-
//getAttendanceStatus() 를 기준으로 그룹화하고, 각 상태별 개수를 Map<String, Long> 형태로 저장
168167
Map<String, Long> statusCounts = studentRecords.stream()
169168
.collect(Collectors.groupingBy(TodayAttendanceStatus::getStatus, Collectors.counting()));
170169

api/src/main/java/org/example/educheck/global/common/exception/custom/common/InvalidRequestException.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33
import org.example.educheck.global.common.exception.ErrorCode;
44

55
public class InvalidRequestException extends GlobalException {
6-
public InvalidRequestException(ErrorCode errorCode) {
7-
super(errorCode);
8-
}
96

107
public InvalidRequestException() {
118
super(ErrorCode.INVALID_INPUT, ErrorCode.INVALID_INPUT.getMessage());

client/src/css/index.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,11 @@ form input {
9898
font-family: Pretendard, 'Pretendard Variable', 'Noto Sans KR', sans-serif;
9999
}
100100

101+
input {
102+
border: none;
103+
font-family: Pretendard, 'Pretendard Variable', 'Noto Sans KR', sans-serif;
104+
}
105+
101106
ol,
102107
ul,
103108
li {

client/src/pages/staffStudentManage/StaffStudentManage.jsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@ export default function StaffStudentManage() {
102102
updatedBirthday.day = '';
103103
}
104104

105-
106105
return updatedBirthday;
107106
});
108107
};
@@ -207,8 +206,14 @@ export default function StaffStudentManage() {
207206
return (
208207
<>
209208
<div>
210-
<MainButton title="학습자 등록" handleClick={() => setOpenModal(true)} isEnable={true} />
211209
<div className={styles.studentsBox}>
210+
<div>
211+
<MainButton
212+
title="학습자 등록"
213+
handleClick={() => setOpenModal(true)}
214+
isEnable={true}
215+
/>
216+
</div>
212217
{students.map((student) => (
213218
<BaseListItem
214219
key={student.memberId}

client/src/pages/studentAttendanceAbsence/StudentAttendanceAbsence.jsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -242,11 +242,18 @@ export default function StudentAttendanceAbsence() {
242242
reason: uploadData.reason,
243243
};
244244

245+
if (new Date(jsonData.endDate) < new Date(jsonData.startDate)) {
246+
alert('유고결석 종료일이 시작일 이전일 수 없습니다.');
247+
return;
248+
}
249+
245250
formData.append('data', new Blob([JSON.stringify(jsonData)], { type: 'application/json' }));
246251

247-
files.forEach((file) => {
248-
formData.append('files', file);
249-
});
252+
if (files && files.length > 0) {
253+
files.forEach((file) => {
254+
formData.append('files', file);
255+
});
256+
}
250257

251258
try {
252259
const response = await absenceAttendancesApi.submitAbsenceAttendance(courseId, formData);
@@ -258,7 +265,7 @@ export default function StudentAttendanceAbsence() {
258265
}
259266
}
260267
} catch (error) {
261-
console.error(error);
268+
alert(error.response?.data?.message || error.message);
262269
}
263270
};
264271

client/src/pages/studentAttendanceAbsence/StudentAttendanceAbsence.module.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565

6666
.reason {
6767
height: 200px;
68+
font-family: Pretendard, 'Pretendard Variable', 'Noto Sans KR', sans-serif;
6869
}
6970

7071
.submitButton {

0 commit comments

Comments
 (0)