-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Feature] 우수회원/수료회원 처리 및 철회 모달 구현 (#164)
* feat: 우수 회원 수료 처리 및 철회 드롭다운 버튼 UI * refactor: 엑셀 다운로드 fetch 로직 hook으로 분리 * refactor: 헤더 버튼 묶음 컴포넌트 분리 * refactor: 우수회원 옵션 상수 분리 * feat: 1차/2차 우수회원 처리/철회 버튼 상태관리 * feat: 선택된 학생 목록 상태관리 * refactor: 불필요한 분기처리 삭제 * feat: AchievementType, 우수회원 API DTO 등록 * feat: fetch delete 메서드에도 body 추가 * feat: 우수회원 처리, 철회 API 등록 * feat: 우수회원 처리, 철회 API 버튼 클릭이벤트 연결 * fix: 잘못된 AchievementType import * fix: delete 메서드 body 기본값 설정 * feat: 우수회원 처리/철회 모달 임시구현 * fix: 처리, 철회 type으로 사용 및 outstandingRoundMap으로 1차, 2차 워딩 관리 * feat: 우수 처리, 철회 로직 모달로 이동 * feat: 첫 번째 선택된 학생 이름 렌더링 * chore: CODEOWNER 수정 * fix: delete 메서드 body 필수 해제 * fix: 불필요한 코드 제거, 코드 순서 변경 * refactor: 수강생 목록 헤더, 컨텐츠 컴포넌트 분리 * fix: 스터디 변경 시 선택 학생 초기화 * fix: 페이지네이션 시에도 첫번째 학생 이름 유지하도록 * fix: pathname의 변화에 따라 fetch * feat: 모달 닫을 때 선택된 학생 정보 초기화 * refactor: Modal Header, Footer 분리 * fix: 변경된 타입명 적용 * feat: 드롭다운 수료 타입 추가 * feat: 수강생 수료 처리, 철회 API * chore: TODO 주석 추가 * feat: 수료 처리, 철회 API 연결 * chore: TODO 주석 추가 * refactor: 우수, 수료에 따른 분기처리 * fix: 선택한 학생 수가 1명일 때 나머지 학생 수 렌더링하지 않음 * fix: 코드오너 추가 * fix: OutstandingModalFooter -> OutstandingModalButton 네이밍 변경 * feat: 취소하기 버튼 클릭 시 selectedStudentsAtom 초기화 * fix: fragment 대신 span 태그로 변경 * chore: wowds-ui 버전업 * fix: 선택된 학생들 배열 대신 Set으로 관리, 디자인 시스템의 onChange 대신 직접 구현한 핸들러 사용 * fix: 체크박스 직접 관리, 선택된 학생 리스트 API 요청 시 배열로 변환 * fix: selectedRowsProp Set이 아닌 Array로 넘겨주기 * fix: Table.Tr 대신 styled.tr 사용, 개별 체크박스 직접 구현 * fix: 허용되지 않은 value prop 삭제 * feat: 우수 및 수료 모달 버튼 분리, 공통 로직 훅 분리, 모달 네이밍 변경 * feat: 중복처리 체크박스 막기 * fix: 불필요한 styled 태그 삭제, 클래스명 컨벤션 통일
- Loading branch information
Showing
36 changed files
with
829 additions
and
157 deletions.
There are no files selected for viewing
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
* @ghdtjgus76 @eugene028 @hamo-o @SeieunYoo | ||
* @eugene028 @hamo-o @SeieunYoo @soulchicken |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { fetcher } from "@wow-class/utils"; | ||
import type { OutstandingStudentApiRequestDto } from "types/dtos/outstandingStudent"; | ||
|
||
const studyAchievementApi = { | ||
postStudyAchievement: async ( | ||
studyId: number, | ||
data: OutstandingStudentApiRequestDto | ||
) => { | ||
const response = await fetcher.post( | ||
`/mentor/study-achievements?studyId=${studyId}`, | ||
data | ||
); | ||
return { success: response.ok }; | ||
}, | ||
|
||
deleteStudyAchievement: async ( | ||
studyId: number, | ||
data: OutstandingStudentApiRequestDto | ||
) => { | ||
const response = await fetcher.delete( | ||
`/mentor/study-achievements?studyId=${studyId}`, | ||
data | ||
); | ||
return { success: response.ok }; | ||
}, | ||
}; | ||
|
||
export default studyAchievementApi; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { fetcher } from "@wow-class/utils"; | ||
import type { StudyCompleteRequestDto } from "types/dtos/studyComplete"; | ||
|
||
const studyCompleteApi = { | ||
postStudyComplete: async (data: StudyCompleteRequestDto) => { | ||
const response = await fetcher.post(`/mentor/study-history/complete`, data); | ||
return { success: response.ok }; | ||
}, | ||
|
||
postStudyCompleteWithdraw: async (data: StudyCompleteRequestDto) => { | ||
const response = await fetcher.post( | ||
`/mentor/study-history/withdraw-completion`, | ||
data | ||
); | ||
return { success: response.ok }; | ||
}, | ||
}; | ||
|
||
export default studyCompleteApi; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import StudentStatusModal from "../_components/StudentStatusModal"; | ||
|
||
const StudentStatusModalPage = () => { | ||
return <StudentStatusModal />; | ||
}; | ||
|
||
export default StudentStatusModalPage; |
55 changes: 55 additions & 0 deletions
55
apps/admin/app/students/@modal/_components/CompleteModalButton.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
"use client"; | ||
|
||
import studyCompleteApi from "apis/study/studyCompleteApi"; | ||
import { useAtomValue } from "jotai"; | ||
import Button from "wowds-ui/Button"; | ||
|
||
import { | ||
enabledOutstandingStudentsAtom, | ||
outstandingStudentsAtom, | ||
selectedStudentsAtom, | ||
studyAtom, | ||
} from "@/students/_contexts/StudyProvider"; | ||
|
||
import useCloseStudentStatusModal from "../_hooks/useCloseStudentStatusModal"; | ||
|
||
const CompleteModalButton = () => { | ||
const study = useAtomValue(studyAtom); | ||
const { enabled } = useAtomValue(enabledOutstandingStudentsAtom); | ||
const { type } = useAtomValue(outstandingStudentsAtom); | ||
const { students } = useAtomValue(selectedStudentsAtom); | ||
|
||
const { | ||
handleClickCloseModal, | ||
closeModalWithSuccess, | ||
closeModalWithFailure, | ||
} = useCloseStudentStatusModal(); | ||
|
||
const handleClickComplete = async () => { | ||
if (!study || !type) return; | ||
|
||
const apiMap = { | ||
처리: studyCompleteApi.postStudyComplete, | ||
철회: studyCompleteApi.postStudyCompleteWithdraw, | ||
}; | ||
|
||
const fetchApi = () => { | ||
const fetch = apiMap[type]; | ||
return fetch({ | ||
studyId: study.studyId, | ||
studentIds: Array.from(students), | ||
}); | ||
}; | ||
const result = await fetchApi(); | ||
if (result.success) closeModalWithSuccess(); | ||
else closeModalWithFailure(); | ||
}; | ||
|
||
return enabled ? ( | ||
<Button onClick={handleClickComplete}>선택한 회원 수료 {type}</Button> | ||
) : ( | ||
<Button onClick={handleClickCloseModal}>확인하기</Button> | ||
); | ||
}; | ||
|
||
export default CompleteModalButton; |
56 changes: 56 additions & 0 deletions
56
apps/admin/app/students/@modal/_components/OutstandingModalButton.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
"use client"; | ||
|
||
import studyAchievementApi from "apis/study/studyAchievementApi"; | ||
import { useAtomValue } from "jotai"; | ||
import type { AchievementType } from "types/entities/achievement"; | ||
import Button from "wowds-ui/Button"; | ||
|
||
import { | ||
enabledOutstandingStudentsAtom, | ||
outstandingStudentsAtom, | ||
selectedStudentsAtom, | ||
studyAtom, | ||
} from "@/students/_contexts/StudyProvider"; | ||
|
||
import useCloseStudentStatusModal from "../_hooks/useCloseStudentStatusModal"; | ||
|
||
const OutstandingModalButton = () => { | ||
const study = useAtomValue(studyAtom); | ||
const { enabled } = useAtomValue(enabledOutstandingStudentsAtom); | ||
const { type, achievement } = useAtomValue(outstandingStudentsAtom); | ||
const { students } = useAtomValue(selectedStudentsAtom); | ||
|
||
const { | ||
handleClickCloseModal, | ||
closeModalWithSuccess, | ||
closeModalWithFailure, | ||
} = useCloseStudentStatusModal(); | ||
|
||
const handleClickOutstanding = async () => { | ||
if (!study || !achievement || !type) return; | ||
|
||
const apiMap = { | ||
처리: studyAchievementApi.postStudyAchievement, | ||
철회: studyAchievementApi.deleteStudyAchievement, | ||
}; | ||
|
||
const fetchApi = () => { | ||
const fetch = apiMap[type]; | ||
return fetch(study.studyId, { | ||
studentIds: Array.from(students), | ||
achievementType: achievement as AchievementType, | ||
}); | ||
}; | ||
const result = await fetchApi(); | ||
if (result.success) closeModalWithSuccess(); | ||
else closeModalWithFailure(); | ||
}; | ||
|
||
return enabled ? ( | ||
<Button onClick={handleClickOutstanding}>선택한 회원 우수 {type}</Button> | ||
) : ( | ||
<Button onClick={handleClickCloseModal}>확인하기</Button> | ||
); | ||
}; | ||
|
||
export default OutstandingModalButton; |
50 changes: 50 additions & 0 deletions
50
apps/admin/app/students/@modal/_components/StudentStatusModal.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
"use client"; | ||
|
||
import { Flex, styled } from "@styled-system/jsx"; | ||
import { Modal, Text } from "@wow-class/ui"; | ||
import { useAtomValue } from "jotai"; | ||
|
||
import { | ||
outstandingStudentsAtom, | ||
selectedStudentsAtom, | ||
} from "@/students/_contexts/StudyProvider"; | ||
|
||
import CompleteModalButton from "./CompleteModalButton"; | ||
import OutstandingModalButton from "./OutstandingModalButton"; | ||
import StudentStatusModalHeader from "./StudentStatusModalHeader"; | ||
|
||
const StudentStatusModal = () => { | ||
const { firstStudentName, students } = useAtomValue(selectedStudentsAtom); | ||
const { type, achievement } = useAtomValue(outstandingStudentsAtom); | ||
|
||
const STUDENTS_NUM = students.size; | ||
if (!type || !achievement) return null; | ||
if (!STUDENTS_NUM) return <Text>선택된 수강생이 없습니다.</Text>; | ||
|
||
const renderAdditionalStudents = () => { | ||
if (STUDENTS_NUM === 1) return null; | ||
return ( | ||
<styled.span> | ||
외 <styled.span color="primary">{STUDENTS_NUM - 1}명</styled.span> | ||
</styled.span> | ||
); | ||
}; | ||
|
||
return ( | ||
<Modal> | ||
<Flex align="center" direction="column" gap="1.5rem"> | ||
<StudentStatusModalHeader /> | ||
<Text color="sub"> | ||
{firstStudentName} 님 {renderAdditionalStudents()} | ||
</Text> | ||
{achievement === "COMPLETE" ? ( | ||
<CompleteModalButton /> | ||
) : ( | ||
<OutstandingModalButton /> | ||
)} | ||
</Flex> | ||
</Modal> | ||
); | ||
}; | ||
|
||
export default StudentStatusModal; |
38 changes: 38 additions & 0 deletions
38
apps/admin/app/students/@modal/_components/StudentStatusModalHeader.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
"use client"; | ||
|
||
import { Text } from "@wow-class/ui"; | ||
import { | ||
outstandingRoundMap, | ||
outstandingTypeMap, | ||
} from "constants/status/outstandigOptions"; | ||
import { useAtomValue } from "jotai"; | ||
|
||
import { | ||
enabledOutstandingStudentsAtom, | ||
outstandingStudentsAtom, | ||
} from "@/students/_contexts/StudyProvider"; | ||
|
||
const StudentStatusModalHeader = () => { | ||
const { enabled } = useAtomValue(enabledOutstandingStudentsAtom); | ||
const { type, achievement } = useAtomValue(outstandingStudentsAtom); | ||
|
||
if (!type || !achievement) return null; | ||
return enabled ? ( | ||
<Text | ||
typo="h1" | ||
style={{ | ||
textAlign: "center", | ||
}} | ||
> | ||
선택한 수강생을 <br /> | ||
{outstandingRoundMap[achievement]} {outstandingTypeMap[type]} | ||
하시겠어요? | ||
</Text> | ||
) : ( | ||
<Text typo="h1"> | ||
{outstandingRoundMap[achievement]} {outstandingTypeMap[type]} | ||
되었어요. | ||
</Text> | ||
); | ||
}; | ||
export default StudentStatusModalHeader; |
51 changes: 51 additions & 0 deletions
51
apps/admin/app/students/@modal/_hooks/useCloseStudentStatusModal.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import { useModalRoute } from "@wow-class/ui/hooks"; | ||
import { tags } from "constants/tags"; | ||
import { useSetAtom } from "jotai"; | ||
import { revalidateTagByName } from "utils/revalidateTagByName"; | ||
|
||
import { | ||
enabledOutstandingStudentsAtom, | ||
selectedStudentsAtom, | ||
} from "@/students/_contexts/StudyProvider"; | ||
|
||
const useCloseStudentStatusModal = () => { | ||
const setSelectedStudents = useSetAtom(selectedStudentsAtom); | ||
const setEnabledOutstandingStudents = useSetAtom( | ||
enabledOutstandingStudentsAtom | ||
); | ||
const { onClose } = useModalRoute(); | ||
|
||
const handleClickCloseModal = () => { | ||
setSelectedStudents({ | ||
students: new Set(), | ||
firstStudentName: "", | ||
}); | ||
onClose(); | ||
}; | ||
|
||
const resetStudents = () => { | ||
revalidateTagByName(tags.students); | ||
setEnabledOutstandingStudents({ | ||
enabled: false, | ||
}); | ||
}; | ||
|
||
const closeModalWithSuccess = () => { | ||
resetStudents(); | ||
setTimeout(() => { | ||
handleClickCloseModal(); | ||
}, 1000); | ||
}; | ||
|
||
const closeModalWithFailure = () => { | ||
resetStudents(); | ||
handleClickCloseModal(); | ||
}; | ||
|
||
return { | ||
handleClickCloseModal, | ||
closeModalWithSuccess, | ||
closeModalWithFailure, | ||
}; | ||
}; | ||
export default useCloseStudentStatusModal; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
const Default = () => { | ||
return null; | ||
}; | ||
|
||
export default Default; |
12 changes: 12 additions & 0 deletions
12
apps/admin/app/students/_components/OutstandingDropDown/DropDownTrigger.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import type { OutstandingType } from "constants/status/outstandigOptions"; | ||
import Button from "wowds-ui/Button"; | ||
|
||
const DropDownTrigger = ({ type }: { type: OutstandingType }) => { | ||
return ( | ||
<Button size="sm" variant="outline"> | ||
우수 및 수료 {type} | ||
</Button> | ||
); | ||
}; | ||
|
||
export default DropDownTrigger; |
Oops, something went wrong.