Skip to content

Commit

Permalink
[Feature] 과제 개설, 수정, 조회 UI 및 API 연결 (#76)
Browse files Browse the repository at this point in the history
* feat: 과제 페이지 기본 UI

* feat: 과제 위치 이동 및 폰트 적용

* feat: 과제 관련 DTO 추가

* chore: react-hook-form 설치

* feat: 과제 정보 입력 페이지

* feat: 과제 조회 페이지

* fix: 불필요한 use client 삭제

* feat: layout 타입 추가

* fix: 텍스트필드 onChange 에러 임시 주석처리

* fix: 렌더링 오류 수정

* fix: 과제 폴더구조 수정 및 라우팅 추가

* feat: Modal 컴포넌트 forwardRef 추가

* feat: 과제 생성 성공 모달, [id] 폴더 [week] 변경 및 모달 위치 변경

* rename: assignments 폴더 위치 변경

* rename: week -> studyDetailId 폴더구조 변경

* feat: 과제 개설 라우팅

* feat: 과제 내용 보기 페이지 API 연결

* fix: 과제 내용보기 라우팅 변경

* feat: 과제 조회 API 추가

* feat: 과제 수정/생성 페이지 과제 기본정보 API 연결

* feat: 과제 생성/수정 성공 모달 라우팅이 아닌 state로 관리하기

* feat: 과제 수정/생성 API 연결

* fix: 불필요한 모달 관련 코드 삭제

* fix: Modal로 내려주는 prop 타입에러 해결

* fix: assignment null 체크

* chore: TODO 주석

* feat: 과제 휴강 처리 보완

* feat: react-hook-form useController 활용해서 CustomTextField 만들기

* chore: defaultValue 적용 안됨

* rename: edit -> edit-assignment

* fix: 과제 리스트 revalidate

* refactor: 중복 로직 삼항연산자로 개선

* fix: defaultValue 적용 안되는 문제

* fix: 빌드 에러 수정

* chore: AssignemtPage 네이밍 변경

* fix: descriptionLink null로 오는 경우 가드

* feat: ItemSeparator 컴포넌트 분리, 적용

* chore: 타이틀 주차 색상 적용

* chore: 중복된 패딩 제거

* refactor: 수강 상태 텍스트 변환 함수에서 객체로 바꾸기

* chore: 불필요한 toString 사용 삭제

* fix: 디테일 페이지 과제 휴강 버튼 삭제

* refactor: 복잡한 삼항연산자 개선

* refactor: 과제 관련 router 상수화

* fix: 잘못된 변수명 수정

* chore: 불필요한 use client 삭제

* fix: 빌드 에러 수정
  • Loading branch information
hamo-o authored Aug 31, 2024
1 parent e00284e commit 1e6aa90
Show file tree
Hide file tree
Showing 21 changed files with 542 additions and 137 deletions.
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

0 comments on commit 1e6aa90

Please sign in to comment.