-
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] 임시 스터디원 관리 UI, API 연결 (#140)
* feat: fetcher에 임시 에러코드 토스트 추가 * feat: 어드민, 클라이언트에 css 및 토스트 컨테이너 추가 * feat: participants -> students url 변경 및 헤더 구현 * chore: 불필요한 예시 모달 삭제 * feat: 스터디리스트 드롭다운 api 연결 * feat: 임시 table UI * feat: 스터디 수강생 명단 api 등록 * feat: 스터디 수강생 api 연결 * fix: thead tbody 추가 * feat: studyAtom값으로 드롭다운 조절 * feat: studyList 상위에서 내려주기 * fix: 변경된 MyStudyList API 수정 * feat: 스터디 수강생이 없을 때 * chore: dto 네이밍 변경, studentList 초기값 변경 * chore: 불필요한 typo prop 삭제, style 객체 분리 * rename: StudyProvider 위치 변경 * chore: 타입 명시 삭제 * chore: PropsWithChildren 타입 사용 * rename: StudyDropDown 폴더 관리 * feat: 타이틀 줄바꿈 방지 및 스타일 분리 * refactor: useFetchStudents 커스텀 훅 분리 * feat: 담당한 스터디가 없을 때 * chore: study -> selectedStudy 네이밍 변경
- Loading branch information
Showing
19 changed files
with
359 additions
and
41 deletions.
There are no files selected for viewing
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 was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
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 was deleted.
Oops, something went wrong.
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 @@ | ||
import { css } from "@styled-system/css"; | ||
import { styled } from "@styled-system/jsx"; | ||
import { Text } from "@wow-class/ui"; | ||
import type { StudyStudentApiResponseDto } from "types/dtos/studyStudent"; | ||
|
||
import StudentListItem from "./StudentListItem"; | ||
|
||
const StudentList = ({ | ||
studentList, | ||
}: { | ||
studentList: StudyStudentApiResponseDto[] | []; | ||
}) => { | ||
if (!studentList.length) return <Text>스터디 수강생이 없어요.</Text>; | ||
|
||
return ( | ||
<styled.table borderCollapse="collapse"> | ||
<thead> | ||
<styled.tr borderBottom="1px solid" borderColor="sub"> | ||
<Text as="th" className={tableThStyle} typo="body2"> | ||
이름 | ||
</Text> | ||
<Text as="th" className={tableThStyle} typo="body2"> | ||
학번 | ||
</Text> | ||
<Text as="th" className={tableThStyle} typo="body2"> | ||
디스코드 사용자명 | ||
</Text> | ||
<Text as="th" className={tableThStyle} typo="body2"> | ||
디스코드 닉네임 | ||
</Text> | ||
<Text as="th" className={tableThStyle} typo="body2"> | ||
깃허브 링크 | ||
</Text> | ||
</styled.tr> | ||
</thead> | ||
<tbody> | ||
{studentList.map((student) => ( | ||
<StudentListItem key={student.memberId} {...student} /> | ||
))} | ||
</tbody> | ||
</styled.table> | ||
); | ||
}; | ||
|
||
const tableThStyle = css({ | ||
padding: "1rem", | ||
textAlign: "left", | ||
}); | ||
|
||
export default StudentList; |
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 { css } from "@styled-system/css"; | ||
import { styled } from "@styled-system/jsx"; | ||
import { Text } from "@wow-class/ui"; | ||
import Link from "next/link"; | ||
import type { CSSProperties } from "react"; | ||
import type { StudyStudentApiResponseDto } from "types/dtos/studyStudent"; | ||
import TextButton from "wowds-ui/TextButton"; | ||
|
||
const StudentListItem = ({ | ||
name, | ||
studentId, | ||
discordUsername, | ||
nickname, | ||
githubLink, | ||
}: StudyStudentApiResponseDto) => { | ||
return ( | ||
<styled.tr> | ||
<Text as="td" className={tableThStyle}> | ||
{name} | ||
</Text> | ||
<Text as="td" className={tableThStyle}> | ||
{studentId} | ||
</Text> | ||
<Text as="td" className={tableThStyle}> | ||
{discordUsername} | ||
</Text> | ||
<Text as="td" className={tableThStyle}> | ||
{nickname} | ||
</Text> | ||
<Text as="td" className={tableThStyle}> | ||
<TextButton | ||
asProp={Link} | ||
href={githubLink || ""} | ||
style={textButtonStyle} | ||
text={githubLink} | ||
/> | ||
</Text> | ||
</styled.tr> | ||
); | ||
}; | ||
|
||
const tableThStyle = css({ | ||
padding: "1rem", | ||
}); | ||
|
||
const textButtonStyle: CSSProperties = { | ||
width: "fit-content", | ||
padding: 0, | ||
}; | ||
|
||
export default StudentListItem; |
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 { Text } from "@wow-class/ui"; | ||
import ItemSeparator from "components/ItemSeparator"; | ||
import type { CSSProperties } from "react"; | ||
import type { StudyListApiResponseDto } from "types/dtos/studyList"; | ||
|
||
import StudyDropDown from "./StudyDropDown"; | ||
|
||
const StudentsHeader = ({ | ||
studyList, | ||
}: { | ||
studyList: StudyListApiResponseDto[]; | ||
}) => { | ||
return ( | ||
<Text as="h1" style={titleStyle} typo="h1"> | ||
수강생 관리 <ItemSeparator height={6} width={6} /> | ||
<StudyDropDown studyList={studyList} /> | ||
</Text> | ||
); | ||
}; | ||
|
||
const titleStyle: CSSProperties = { | ||
display: "flex", | ||
alignItems: "center", | ||
gap: "0.75rem", | ||
whiteSpace: "nowrap", | ||
}; | ||
|
||
export default StudentsHeader; |
19 changes: 19 additions & 0 deletions
19
apps/admin/app/students/_components/StudyDropDown/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,19 @@ | ||
import { Flex } from "@styled-system/jsx"; | ||
import { DownArrow } from "wowds-icons"; | ||
|
||
const DropDownTrigger = () => { | ||
return ( | ||
<Flex | ||
align="center" | ||
background="backgroundAlternative" | ||
borderRadius={9999} | ||
height={24} | ||
justify="center" | ||
width={24} | ||
> | ||
<DownArrow stroke="sub" /> | ||
</Flex> | ||
); | ||
}; | ||
|
||
export default DropDownTrigger; |
53 changes: 53 additions & 0 deletions
53
apps/admin/app/students/_components/StudyDropDown/index.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,53 @@ | ||
import { Flex } from "@styled-system/jsx"; | ||
import { useAtom } from "jotai"; | ||
import type { ReactNode } from "react"; | ||
import type { StudyListApiResponseDto } from "types/dtos/studyList"; | ||
import DropDown from "wowds-ui/DropDown"; | ||
import DropDownOption from "wowds-ui/DropDownOption"; | ||
|
||
import { studyAtom } from "../../_contexts/StudyProvider"; | ||
import DropDownTrigger from "./DropDownTrigger"; | ||
|
||
const StudyDropDown = ({ | ||
studyList, | ||
}: { | ||
studyList: StudyListApiResponseDto[]; | ||
}) => { | ||
const [study, setStudy] = useAtom(studyAtom); | ||
|
||
if (!study) return null; | ||
|
||
return ( | ||
<DropDown | ||
trigger={ | ||
<Flex | ||
align="center" | ||
color="primary" | ||
cursor="pointer" | ||
gap="sm" | ||
width="20rem" | ||
> | ||
{study.title} | ||
<DropDownTrigger /> | ||
</Flex> | ||
} | ||
onChange={(value: { selectedValue: string; selectedText: ReactNode }) => { | ||
setStudy({ | ||
studyId: +value.selectedValue, | ||
title: value.selectedText, | ||
}); | ||
}} | ||
> | ||
{studyList.map((study: StudyListApiResponseDto) => ( | ||
<DropDownOption | ||
key={study.studyId} | ||
style={{ cursor: "pointer" }} | ||
text={study.title} | ||
value={study.studyId.toString()} | ||
/> | ||
))} | ||
</DropDown> | ||
); | ||
}; | ||
|
||
export default StudyDropDown; |
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,18 @@ | ||
"use client"; | ||
|
||
import { atom, createStore, Provider } from "jotai"; | ||
import type { PropsWithChildren, ReactNode } from "react"; | ||
|
||
const studyIdStore = createStore(); | ||
|
||
export type StudyAtomprops = { | ||
studyId: number; | ||
title: ReactNode; | ||
}; | ||
|
||
export const studyAtom = atom<StudyAtomprops>(); | ||
studyIdStore.set(studyAtom, undefined); | ||
|
||
export const StudyProvider = ({ children }: PropsWithChildren) => { | ||
return <Provider store={studyIdStore}>{children}</Provider>; | ||
}; |
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,30 @@ | ||
import { css } from "@styled-system/css"; | ||
import { styled } from "@styled-system/jsx"; | ||
import Navbar from "components/Navbar"; | ||
|
||
import { StudyProvider } from "./_contexts/StudyProvider"; | ||
|
||
const StudentsLayout = ({ | ||
children, | ||
}: Readonly<{ | ||
children: React.ReactNode; | ||
}>) => { | ||
return ( | ||
<StudyProvider> | ||
<Navbar /> | ||
<styled.main className={StudentsLayoutStyle}>{children}</styled.main> | ||
</StudyProvider> | ||
); | ||
}; | ||
|
||
export default StudentsLayout; | ||
|
||
const StudentsLayoutStyle = css({ | ||
display: "flex", | ||
flexDirection: "column", | ||
gap: "sm", | ||
height: "100vh", | ||
overflow: "scroll", | ||
width: "100%", | ||
padding: "54px 101px", | ||
}); |
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,49 @@ | ||
"use client"; | ||
|
||
import { Flex } from "@styled-system/jsx"; | ||
import { Text } from "@wow-class/ui"; | ||
import { studyApi } from "apis/study/studyApi"; | ||
import useFetchStudents from "hooks/fetch/useFetchStudents"; | ||
import { useAtom } from "jotai"; | ||
import { useEffect, useState } from "react"; | ||
import type { StudyListApiResponseDto } from "types/dtos/studyList"; | ||
import isAdmin from "utils/isAdmin"; | ||
|
||
import StudentList from "./_components/StudentList"; | ||
import StudentsHeader from "./_components/StudentsHeader"; | ||
import { studyAtom } from "./_contexts/StudyProvider"; | ||
|
||
const StudentsPage = () => { | ||
const [studyList, setStudyList] = useState<StudyListApiResponseDto[]>(); | ||
const [selectedStudy, setSelectedStudy] = useAtom(studyAtom); | ||
|
||
useEffect(() => { | ||
const fetchData = async () => { | ||
const adminStatus = await isAdmin(); | ||
if (adminStatus) { | ||
const data = adminStatus | ||
? await studyApi.getStudyList() | ||
: await studyApi.getMyStudyList(); | ||
|
||
if (data && data.length && data[0]) { | ||
setStudyList(data); | ||
setSelectedStudy({ studyId: data[0].studyId, title: data[0].title }); | ||
} | ||
} | ||
}; | ||
|
||
fetchData(); | ||
}, [setSelectedStudy]); | ||
|
||
const student = useFetchStudents(selectedStudy); | ||
if (!studyList) return <Text>담당한 스터디가 없어요.</Text>; | ||
|
||
return ( | ||
<Flex direction="column" gap="3rem"> | ||
<StudentsHeader studyList={studyList} /> | ||
<StudentList studentList={student.studentList} /> | ||
</Flex> | ||
); | ||
}; | ||
|
||
export default StudentsPage; |
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
Oops, something went wrong.