Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] 과제 개설, 수정, 조회 UI 및 API 연결 #76

Merged
merged 47 commits into from
Aug 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
7e539df
feat: 과제 페이지 기본 UI
hamo-o Aug 13, 2024
15ca4b6
feat: 과제 위치 이동 및 폰트 적용
hamo-o Aug 14, 2024
ae0be40
feat: 과제 관련 DTO 추가
hamo-o Aug 14, 2024
c81782d
chore: react-hook-form 설치
hamo-o Aug 14, 2024
499fb95
feat: 과제 정보 입력 페이지
hamo-o Aug 14, 2024
b4d6d47
feat: 과제 조회 페이지
hamo-o Aug 14, 2024
284e63e
fix: 불필요한 use client 삭제
hamo-o Aug 14, 2024
63f711c
feat: layout 타입 추가
hamo-o Aug 14, 2024
90b8c8b
fix: 텍스트필드 onChange 에러 임시 주석처리
hamo-o Aug 14, 2024
1c56688
fix: 렌더링 오류 수정
hamo-o Aug 14, 2024
e20616c
fix: 과제 폴더구조 수정 및 라우팅 추가
hamo-o Aug 14, 2024
6b3e1ba
feat: Modal 컴포넌트 forwardRef 추가
hamo-o Aug 27, 2024
86c02c7
feat: 과제 생성 성공 모달, [id] 폴더 [week] 변경 및 모달 위치 변경
hamo-o Aug 27, 2024
1ac3306
rename: assignments 폴더 위치 변경
hamo-o Aug 27, 2024
9d1b842
rename: week -> studyDetailId 폴더구조 변경
hamo-o Aug 27, 2024
77714f2
feat: 과제 개설 라우팅
hamo-o Aug 27, 2024
d452152
feat: 과제 내용 보기 페이지 API 연결
hamo-o Aug 27, 2024
e7058c3
fix: 과제 내용보기 라우팅 변경
hamo-o Aug 27, 2024
1f25f6f
feat: 과제 조회 API 추가
hamo-o Aug 27, 2024
bd2c13d
feat: 과제 수정/생성 페이지 과제 기본정보 API 연결
hamo-o Aug 27, 2024
99db3ad
feat: 과제 생성/수정 성공 모달 라우팅이 아닌 state로 관리하기
hamo-o Aug 27, 2024
cec6a27
feat: 과제 수정/생성 API 연결
hamo-o Aug 27, 2024
cb9c21e
fix: 불필요한 모달 관련 코드 삭제
hamo-o Aug 27, 2024
4c50727
fix: Modal로 내려주는 prop 타입에러 해결
hamo-o Aug 27, 2024
d76544a
fix: assignment null 체크
hamo-o Aug 27, 2024
84991d4
chore: TODO 주석
hamo-o Aug 27, 2024
7012c30
feat: 과제 휴강 처리 보완
hamo-o Aug 28, 2024
e537558
feat: react-hook-form useController 활용해서 CustomTextField 만들기
hamo-o Aug 28, 2024
38f65fc
chore: defaultValue 적용 안됨
hamo-o Aug 28, 2024
7be4bd9
rename: edit -> edit-assignment
hamo-o Aug 28, 2024
a5494bd
fix: 과제 리스트 revalidate
hamo-o Aug 28, 2024
738e514
refactor: 중복 로직 삼항연산자로 개선
hamo-o Aug 28, 2024
e626369
fix: defaultValue 적용 안되는 문제
hamo-o Aug 29, 2024
e67be58
fix: 빌드 에러 수정
hamo-o Aug 30, 2024
734ca99
chore: AssignemtPage 네이밍 변경
hamo-o Aug 30, 2024
5b41ad5
fix: descriptionLink null로 오는 경우 가드
hamo-o Aug 30, 2024
6c7260d
feat: ItemSeparator 컴포넌트 분리, 적용
hamo-o Aug 30, 2024
4d0c483
chore: 타이틀 주차 색상 적용
hamo-o Aug 30, 2024
a2116a5
chore: 중복된 패딩 제거
hamo-o Aug 30, 2024
9c0daa9
refactor: 수강 상태 텍스트 변환 함수에서 객체로 바꾸기
hamo-o Aug 30, 2024
ee100a1
chore: 불필요한 toString 사용 삭제
hamo-o Aug 30, 2024
116393e
fix: 디테일 페이지 과제 휴강 버튼 삭제
hamo-o Aug 30, 2024
5983ad6
refactor: 복잡한 삼항연산자 개선
hamo-o Aug 30, 2024
667616d
refactor: 과제 관련 router 상수화
hamo-o Aug 30, 2024
e73527e
fix: 잘못된 변수명 수정
hamo-o Aug 30, 2024
ba87513
chore: 불필요한 use client 삭제
hamo-o Aug 30, 2024
4e4d0a3
fix: 빌드 에러 수정
hamo-o Aug 30, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion apps/admin/apis/study/studyApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { fetcher } from "@wow-class/utils";
import { apiPath, mentorApiPath } from "constants/apiPath";
import { tags } from "constants/tags";
import type { AnnouncementApiResponseDto } from "types/dtos/announcement";
import type { AssignmentApiResponseDto } from "types/dtos/assignmentList";
import type {
AssignmentApiRequestDto,
AssignmentApiResponseDto,
} from "types/dtos/assignmentList";
import type { CurriculumApiResponseDto } from "types/dtos/curriculumList";
import type { StudyBasicInfoApiResponseDto } from "types/dtos/studyBasicInfo";
import type { StudyAnnouncementType } from "types/entities/study";
Expand Down Expand Up @@ -40,6 +43,36 @@ export const studyApi = {
);
return response.data;
},
getAssignment: async (studyDetailId: number) => {
const response = await fetcher.get<AssignmentApiResponseDto>(
`/mentor/study-details/${studyDetailId}/assignments`,
{
next: { tags: [`${tags.assignments} ${studyDetailId}`] },
cache: "force-cache",
}
);
return response.data;
},
createAssignment: async (
studyDetailId: number,
data: AssignmentApiRequestDto
) => {
const response = await fetcher.put(
`/mentor/study-details/${studyDetailId}/assignments`,
data
);
return { success: response.ok };
},
patchAssignment: async (
studyDetailId: number,
data: AssignmentApiRequestDto
) => {
const response = await fetcher.patch(
`/mentor/study-details/${studyDetailId}/assignments`,
data
);
return { success: response.ok };
},
cancelAssignment: async (studyDetailId: number) => {
const response = await fetcher.patch(
`/mentor/study-details/${studyDetailId}/assignments/cancel`,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"use client";
import { Flex } from "@styled-system/jsx";
import { studyApi } from "apis/study/studyApi";
import { routerPath } from "constants/router/routerPath";
import Link from "next/link";
import type { StudyAssignmentStatusType } from "types/entities/study";
import Button from "wowds-ui/Button";

const AssignmentButtons = ({
studyDetailId,
assignmentStatus,
}: {
studyDetailId: number;
assignmentStatus: StudyAssignmentStatusType;
}) => {
const handleCancelAssignment = async () => {
const { success } = await studyApi.cancelAssignment(studyDetailId);
if (success) {
console.log("휴강 처리에 성공했어요.");
} else {
console.log("휴강 처리에 실패했어요.");
}
};

if (assignmentStatus === "OPEN") {
return (
<Button
asProp={Link}
href={routerPath["assignment-detail"].href(studyDetailId)}
size="sm"
variant="outline"
>
과제 내용보기
</Button>
);
}

if (assignmentStatus === "CANCELLED") {
return (
<Flex gap="sm">
<Button size="sm" variant="sub">
과제 휴강완료
</Button>
<Button disabled size="sm" variant="solid">
과제 개설하기
</Button>
</Flex>
);
}

return (
<Flex gap="sm">
<Button size="sm" variant="sub" onClick={handleCancelAssignment}>
과제 휴강처리
</Button>
<Button
asProp={Link}
href={routerPath["assignment-edit"].href(studyDetailId)}
size="sm"
variant="solid"
>
과제 개설하기
</Button>
</Flex>
);
};

export default AssignmentButtons;
Original file line number Diff line number Diff line change
@@ -1,43 +1,23 @@
"use client";
import { cva } from "@styled-system/css";
import { Flex } from "@styled-system/jsx";
import { Table, Text } from "@wow-class/ui";
import { padWithZero, parseISODate } from "@wow-class/utils";
import { studyApi } from "apis/study/studyApi";
import { tags } from "constants/tags";
import Link from "next/link";
import type { AssignmentApiResponseDto } from "types/dtos/assignmentList";
import getIsCurrentWeek from "utils/getIsCurrentWeek";
import { revalidateTagByName } from "utils/revalidateTagByName";
import Button from "wowds-ui/Button";

import AssignmentButtons from "./AssignmentButtons";

const AssignmentListItem = ({
assignment,
}: {
assignment: AssignmentApiResponseDto;
}) => {
const {
studyDetailId,
title,
deadline,
week,
descriptionLink,
assignmentStatus,
} = assignment;
const { studyDetailId, title, deadline, week, assignmentStatus } = assignment;
const thisWeekAssignment = getIsCurrentWeek(deadline);
const { year, month, day, hours, minutes } = parseISODate(deadline);

const studyDeadline = `종료 : ${year}년 ${month}월 ${day}일 ${padWithZero(hours)}:${padWithZero(minutes)}`;

const handleCancelAssignment = async (studyDetailId: number) => {
const { success } = await studyApi.cancelAssignment(studyDetailId);
if (success) {
window.alert("휴강 처리에 성공했어요.");
revalidateTagByName(tags.assignments);
} else {
window.alert("휴강 처리에 실패했어요.");
}
};
return (
<Table>
<Table.Left style={TableLeftStyle}>
Expand All @@ -57,38 +37,10 @@ const AssignmentListItem = ({
</Flex>
</Table.Left>
<Table.Right>
<>
{assignmentStatus === "OPEN" ? (
<Button
asProp={Link}
href={descriptionLink || ""}
size="sm"
variant="outline"
>
과제 내용보기
</Button>
) : (
<Flex gap="sm">
<Button
color="sub"
size="sm"
variant="sub"
onClick={() => handleCancelAssignment(studyDetailId)}
>
과제 휴강처리
</Button>
<Button
size="sm"
variant="solid"
onClick={() => {
console.log("TODO: 과제 개설 페이지 연결");
}}
>
과제 개설하기
</Button>
</Flex>
)}
</>
<AssignmentButtons
assignmentStatus={assignmentStatus}
studyDetailId={+studyDetailId}
/>
</Table.Right>
</Table>
);
Expand Down

This file was deleted.

14 changes: 5 additions & 9 deletions apps/admin/app/studies/[studyId]/_components/header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { Flex } from "@styled-system/jsx";
import { Space, Text } from "@wow-class/ui";
import { padWithZero, parseISODate } from "@wow-class/utils";
import { studyApi } from "apis/study/studyApi";
import ItemSeparator from "components/ItemSeparator";
import { dayToKorean } from "constants/dayToKorean";
import Image from "next/image";
import Link from "next/link";
import { useEffect, useState } from "react";
import type { StudyBasicInfoApiResponseDto } from "types/dtos/studyBasicInfo";
Expand Down Expand Up @@ -114,11 +114,11 @@ const Header = ({
<Text as="h5" color="sub">
{studySemester}
</Text>
<ItemSeparator />
<ItemSeparator height={4} width={4} />
<Text as="h5" color="sub">
{mentorName} 멘토
</Text>
<ItemSeparator />
<ItemSeparator height={4} width={4} />
<Text as="h5" color="sub">
{studyType}
</Text>
Expand All @@ -138,13 +138,13 @@ const Header = ({
<Text as="h5" color="sub">
{studySchedule()}
</Text>
<ItemSeparator />
<ItemSeparator height={4} width={4} />
</Flex>
)}
<Text as="h5" color="sub">
{totalWeek}주 코스
</Text>
<ItemSeparator />
<ItemSeparator height={4} width={4} />
<Text as="h5" color="sub">
{studyPeriod}
</Text>
Expand Down Expand Up @@ -175,10 +175,6 @@ const Header = ({

export default Header;

const ItemSeparator = () => (
<Image alt="item separator" height={4} src="/images/dot.svg" width={4} />
);

const downArrowIconStyle = css({
cursor: "pointer",
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Flex } from "@styled-system/jsx";
import { useFormContext } from "react-hook-form";
import type {
AssignmentApiRequestDto,
AssignmentApiResponseDto,
} from "types/dtos/assignmentList";

import CustomTextField from "./CustomTextField";

const AssignmentForm = ({
assignment,
}: {
assignment: AssignmentApiResponseDto;
}) => {
const { control } = useFormContext<AssignmentApiRequestDto>();
const { title, descriptionLink } = assignment;

// TODO: Picker 컴포넌트 추가
return (
<Flex direction="column" gap="2.25rem">
<CustomTextField
control={control}
defaultValue={title}
label="과제 제목"
maxLength={100}
name="title"
placeholder="Ex. HTTP 통신 코드 작성하기"
/>
<CustomTextField
control={control}
defaultValue={descriptionLink}
label="과제 명세 링크"
name="descriptionNotionLink"
placeholder="https://example.com"
// TODO: 링크 형식 validate
/>
</Flex>
);
};

export default AssignmentForm;
Loading
Loading