diff --git a/apps/admin/apis/study/studyApi.ts b/apps/admin/apis/study/studyApi.ts index d9a060b9..cd1de72d 100644 --- a/apps/admin/apis/study/studyApi.ts +++ b/apps/admin/apis/study/studyApi.ts @@ -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"; @@ -40,6 +43,36 @@ export const studyApi = { ); return response.data; }, + getAssignment: async (studyDetailId: number) => { + const response = await fetcher.get( + `/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`, diff --git a/apps/admin/app/@modal/(.)participants/page.tsx b/apps/admin/app/@modal/(.)participants/page.tsx index a28df54a..b90748d3 100644 --- a/apps/admin/app/@modal/(.)participants/page.tsx +++ b/apps/admin/app/@modal/(.)participants/page.tsx @@ -6,11 +6,12 @@ import { useModalRoute } from "@wow-class/ui/hooks"; import Button from "wowds-ui/Button"; const TestModal = () => { - const { closeModal } = useModalRoute(); + const { onClose } = useModalRoute(); + return ( - + - diff --git a/apps/admin/app/layout.tsx b/apps/admin/app/layout.tsx index ef62f3f8..42b0d62c 100644 --- a/apps/admin/app/layout.tsx +++ b/apps/admin/app/layout.tsx @@ -7,8 +7,34 @@ import type { Metadata } from "next"; import type { ReactNode } from "react"; export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: { + default: "GDSC Hongik 스터디 서비스, 와우클래스 멘토", + template: "%s | 와우클래스 멘토", + }, + description: "와우클래스는 GDSC Hongik이 제공하는 스터디 관리 플랫폼입니다.", + openGraph: { + title: "GDSC Hongik 스터디 서비스, 와우클래스 멘토", + description: + "와우클래스는 GDSC Hongik이 제공하는 스터디 관리 플랫폼입니다.", + images: ["/images/og-image.png"], + siteName: "GDSC Hongik 스터디 서비스, 와우클래스 멘토", + type: "website", + }, + robots: { + index: false, + follow: false, + }, + icons: { + icon: "/images/logo.svg", + apple: "/images/logo.svg", + other: [ + { + rel: "icon", + type: "image/svg+xml", + url: "/images/logo.svg", + }, + ], + }, }; const RootLayout = ({ diff --git a/apps/admin/app/studies/[studyId]/@modal/(.)announcement-delete/page.tsx b/apps/admin/app/studies/[studyId]/@modal/(.)announcement-delete/page.tsx index 0bdb74dd..363e7d34 100644 --- a/apps/admin/app/studies/[studyId]/@modal/(.)announcement-delete/page.tsx +++ b/apps/admin/app/studies/[studyId]/@modal/(.)announcement-delete/page.tsx @@ -14,7 +14,7 @@ const AnnouncementDeleteModal = () => { const studyAnnouncementId = searchParams.get("studyAnnouncementId"); - const { closeModal } = useModalRoute(); + const { onClose } = useModalRoute(); const handleClickDeleteButton = async () => { const result = await studyApi.deleteStudyAnnouncement( @@ -22,7 +22,7 @@ const AnnouncementDeleteModal = () => { ); if (result.success) { revalidateTagByName(tags.announcements); - closeModal(); + onClose(); } }; @@ -33,7 +33,7 @@ const AnnouncementDeleteModal = () => { - diff --git a/apps/admin/app/studies/[studyId]/@modal/(.)announcement-modify/page.tsx b/apps/admin/app/studies/[studyId]/@modal/(.)announcement-modify/page.tsx index b0dd036d..db003d05 100644 --- a/apps/admin/app/studies/[studyId]/@modal/(.)announcement-modify/page.tsx +++ b/apps/admin/app/studies/[studyId]/@modal/(.)announcement-modify/page.tsx @@ -22,7 +22,7 @@ const AnnouncementModifyModal = () => { const studyAnnouncementId = searchParams.get("studyAnnouncementId"); - const { closeModal } = useModalRoute(); + const { onClose } = useModalRoute(); const handleClickModifyButton = async () => { const result = await studyApi.modifyStudyAnnouncement( @@ -31,7 +31,7 @@ const AnnouncementModifyModal = () => { ); if (result.success) { revalidateTagByName(tags.announcements); - closeModal(); + onClose(); } }; @@ -58,7 +58,7 @@ const AnnouncementModifyModal = () => { - diff --git a/apps/admin/app/studies/[studyId]/_components/assignment/AssignmentButtons.tsx b/apps/admin/app/studies/[studyId]/_components/assignment/AssignmentButtons.tsx new file mode 100644 index 00000000..9d4b92df --- /dev/null +++ b/apps/admin/app/studies/[studyId]/_components/assignment/AssignmentButtons.tsx @@ -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 ( + + ); + } + + if (assignmentStatus === "CANCELLED") { + return ( + + + + + ); + } + + return ( + + + + + ); +}; + +export default AssignmentButtons; diff --git a/apps/admin/app/studies/[studyId]/_components/assignment/AssignmentListItem.tsx b/apps/admin/app/studies/[studyId]/_components/assignment/AssignmentListItem.tsx index 7b6040f0..10e7f3cd 100644 --- a/apps/admin/app/studies/[studyId]/_components/assignment/AssignmentListItem.tsx +++ b/apps/admin/app/studies/[studyId]/_components/assignment/AssignmentListItem.tsx @@ -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 ( @@ -57,38 +37,10 @@ const AssignmentListItem = ({ - <> - {assignmentStatus === "OPEN" ? ( - - ) : ( - - - - - )} - +
); diff --git a/apps/admin/app/studies/[studyId]/_components/assignment/CancelStudyButton.tsx b/apps/admin/app/studies/[studyId]/_components/assignment/CancelStudyButton.tsx deleted file mode 100644 index d29b64f9..00000000 --- a/apps/admin/app/studies/[studyId]/_components/assignment/CancelStudyButton.tsx +++ /dev/null @@ -1,61 +0,0 @@ -"use client"; -import { Flex } from "@styled-system/jsx"; -import { studyApi } from "apis/study/studyApi"; -import { useRouter } from "next/navigation"; -import type { StudyAssignmentStatusType } from "types/entities/study"; -import Button from "wowds-ui/Button"; - -const CancelStudyButton = ({ - descriptionLink, - studyDetailId, - assignmentStatus, -}: { - descriptionLink: string; - studyDetailId: number; - assignmentStatus: StudyAssignmentStatusType; -}) => { - const router = useRouter(); - const handleCancelAssignment = async (studyDetailId: number) => { - const { success } = await studyApi.cancelAssignment(studyDetailId); - if (success) { - console.log("휴강 처리에 성공했어요."); - } else { - console.log("휴강 처리에 실패했어요."); - } - }; - return ( - <> - {assignmentStatus === "OPEN" ? ( - - ) : ( - - - - - )} - - ); -}; - -export default CancelStudyButton; diff --git a/apps/admin/app/studies/[studyId]/_components/header/Header.tsx b/apps/admin/app/studies/[studyId]/_components/header/Header.tsx index 5c64473f..89df9166 100644 --- a/apps/admin/app/studies/[studyId]/_components/header/Header.tsx +++ b/apps/admin/app/studies/[studyId]/_components/header/Header.tsx @@ -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"; @@ -114,11 +114,11 @@ const Header = ({ {studySemester} - + {mentorName} 멘토 - + {studyType} @@ -138,13 +138,13 @@ const Header = ({ {studySchedule()} - +
)} {totalWeek}주 코스 - + {studyPeriod} @@ -175,10 +175,6 @@ const Header = ({ export default Header; -const ItemSeparator = () => ( - item separator -); - const downArrowIconStyle = css({ cursor: "pointer", }); diff --git a/apps/admin/app/studies/[studyId]/layout.tsx b/apps/admin/app/studies/[studyId]/layout.tsx index e2b816c8..05e232d2 100644 --- a/apps/admin/app/studies/[studyId]/layout.tsx +++ b/apps/admin/app/studies/[studyId]/layout.tsx @@ -13,9 +13,9 @@ const StudyLayout = ({ ); }; -export default StudyLayout; - const MainLayoutStyle = { height: "100%", overflow: "auto", }; + +export default StudyLayout; diff --git a/apps/admin/app/studies/[studyId]/page.tsx b/apps/admin/app/studies/[studyId]/page.tsx index 6514a528..a1ec6482 100644 --- a/apps/admin/app/studies/[studyId]/page.tsx +++ b/apps/admin/app/studies/[studyId]/page.tsx @@ -1,5 +1,6 @@ import { Flex } from "@styled-system/jsx"; import { Space } from "@wow-class/ui"; +import { studyApi } from "apis/study/studyApi"; import Divider from "wowds-ui/Divider"; import StudyAnnouncement from "./_components/announcement/StudyAnnouncement"; @@ -8,6 +9,17 @@ import CheckAttendanceNumber from "./_components/attendance/CheckAttendanceNumbe import CurriculumList from "./_components/curriculum/CurriculumList"; import Header from "./_components/header/Header"; +export const generateMetadata = async ({ + params: { studyId }, +}: { + params: { studyId: string }; +}) => { + const study = await studyApi.getStudyBasicInfo(+studyId); + return { + title: study ? study.title : "스터디", + }; +}; + const StudyPage = ({ params }: { params: { studyId: string } }) => { const { studyId } = params; return ( diff --git a/apps/admin/app/studies/assignments/[studyDetailId]/_components/AssignmentForm.tsx b/apps/admin/app/studies/assignments/[studyDetailId]/_components/AssignmentForm.tsx new file mode 100644 index 00000000..840d930a --- /dev/null +++ b/apps/admin/app/studies/assignments/[studyDetailId]/_components/AssignmentForm.tsx @@ -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(); + const { title, descriptionLink } = assignment; + + // TODO: Picker 컴포넌트 추가 + return ( + + + + + ); +}; + +export default AssignmentForm; diff --git a/apps/admin/app/studies/assignments/[studyDetailId]/_components/AssignmentHeader.tsx b/apps/admin/app/studies/assignments/[studyDetailId]/_components/AssignmentHeader.tsx new file mode 100644 index 00000000..f2803f10 --- /dev/null +++ b/apps/admin/app/studies/assignments/[studyDetailId]/_components/AssignmentHeader.tsx @@ -0,0 +1,80 @@ +"use client"; + +import { css } from "@styled-system/css"; +import { Flex } from "@styled-system/jsx"; +import { Text } from "@wow-class/ui"; +import { studyApi } from "apis/study/studyApi"; +import { tags } from "constants/tags"; +import { useFormContext } from "react-hook-form"; +import type { + AssignmentApiRequestDto, + AssignmentApiResponseDto, +} from "types/dtos/assignmentList"; +import { revalidateTagByName } from "utils/revalidateTagByName"; +import Button from "wowds-ui/Button"; + +interface AssignmentHeaderProps { + assignment: AssignmentApiResponseDto; + disabled: boolean; +} + +const AssignmentHeader = ({ assignment, disabled }: AssignmentHeaderProps) => { + const { studyDetailId, week, assignmentStatus } = assignment; + const methods = useFormContext< + AssignmentApiRequestDto & { + onOpen: () => void; + } + >(); + + const onOpen = methods.getValues("onOpen"); + + const handleClickSubmit = async () => { + if (assignmentStatus === "CANCELLED") return; + + const data = { + title: methods.getValues("title"), + descriptionNotionLink: methods.getValues("descriptionNotionLink"), + deadLine: methods.getValues("deadLine"), + }; + + const { success } = + assignmentStatus === "NONE" + ? await studyApi.createAssignment(studyDetailId, data) + : await studyApi.patchAssignment(studyDetailId, data); + if (success) { + revalidateTagByName(`${tags.assignments} ${studyDetailId}`); + revalidateTagByName(tags.assignments); + onOpen(); + } + }; + + return ( +
+ + + 과제 정보를 입력해주세요 + + + {week}주차 과제 + + + +
+ ); +}; + +const headerStyle = css({ + width: "100%", + display: "flex", + alignItems: "top", + justifyContent: "space-between", +}); + +export default AssignmentHeader; diff --git a/apps/admin/app/studies/assignments/[studyDetailId]/_components/CustomTextField.tsx b/apps/admin/app/studies/assignments/[studyDetailId]/_components/CustomTextField.tsx new file mode 100644 index 00000000..28979eba --- /dev/null +++ b/apps/admin/app/studies/assignments/[studyDetailId]/_components/CustomTextField.tsx @@ -0,0 +1,37 @@ +"use client"; + +import { useController } from "react-hook-form"; +import type { TextFieldProps } from "wowds-ui/TextField"; +import TextField from "wowds-ui/TextField"; + +interface CustomTextFieldProps extends TextFieldProps { + name: string; + control: any; +} + +const CustomTextField = ({ + name, + control, + defaultValue, + ...rest +}: CustomTextFieldProps) => { + const { field } = useController({ + name, + control, + rules: { required: true }, + defaultValue, + }); + + return ( + + ); +}; + +export default CustomTextField; diff --git a/apps/admin/app/studies/assignments/[studyDetailId]/_components/SuccessModal.tsx b/apps/admin/app/studies/assignments/[studyDetailId]/_components/SuccessModal.tsx new file mode 100644 index 00000000..fa8d1421 --- /dev/null +++ b/apps/admin/app/studies/assignments/[studyDetailId]/_components/SuccessModal.tsx @@ -0,0 +1,39 @@ +"use client"; + +import { Flex, styled } from "@styled-system/jsx"; +import { Modal, Text } from "@wow-class/ui"; +import Link from "next/link"; +import Button from "wowds-ui/Button"; + +interface SuccesModalProps { + studyName: string; + week: number; + type: "개설" | "수정"; + studyDetailId: string; +} + +const SuccessModal = ({ + studyName, + week, + type, + studyDetailId, +}: SuccesModalProps) => { + return ( + + + + + {studyName} {week}주차 + +
+ 과제가 {type}되었어요 +
+ +
+
+ ); +}; + +export default SuccessModal; diff --git a/apps/admin/app/studies/assignments/[studyDetailId]/edit-assignment/page.tsx b/apps/admin/app/studies/assignments/[studyDetailId]/edit-assignment/page.tsx new file mode 100644 index 00000000..6be479aa --- /dev/null +++ b/apps/admin/app/studies/assignments/[studyDetailId]/edit-assignment/page.tsx @@ -0,0 +1,79 @@ +"use client"; + +import { useOpenState } from "@wow-class/ui/hooks"; +import { studyApi } from "apis/study/studyApi"; +import { assignmentStatusMap } from "constants/assignmentStatusMap"; +import { useEffect, useState } from "react"; +import { FormProvider, useForm } from "react-hook-form"; +import type { + AssignmentApiRequestDto, + AssignmentApiResponseDto, +} from "types/dtos/assignmentList"; + +import AssignmentForm from "../_components/AssignmentForm"; +import AssignmentHeader from "../_components/AssignmentHeader"; +import SuccessModal from "../_components/SuccessModal"; + +const Assignments = ({ + params: { studyDetailId }, +}: { + params: { study: string; studyDetailId: string }; +}) => { + const { open, onOpen } = useOpenState(); + + const [assignment, setAssignment] = useState( + null + ); + + useEffect(() => { + const fetchAssignment = async () => { + if (studyDetailId) { + const data = await studyApi.getAssignment(+studyDetailId); + if (data) setAssignment(data); + } + }; + fetchAssignment(); + }, [studyDetailId]); + + const methods = useForm< + AssignmentApiRequestDto & { + onOpen: () => void; + } + >({ + defaultValues: { + title: assignment?.title, + deadLine: "2024-09-07T00:00:00", + descriptionNotionLink: assignment?.descriptionLink, + onOpen: onOpen, + }, + }); + + if (!assignment) return null; + const { assignmentStatus, week } = assignment; + + // TODO: 휴강된 경우 진입 막기 + if (assignmentStatus === "CANCELLED") return null; + + // TODO: studyName 추가 + return ( + <> + {open && ( + + )} + + + + + + ); +}; + +export default Assignments; diff --git a/apps/admin/app/studies/assignments/[studyDetailId]/page.tsx b/apps/admin/app/studies/assignments/[studyDetailId]/page.tsx new file mode 100644 index 00000000..ec89fc91 --- /dev/null +++ b/apps/admin/app/studies/assignments/[studyDetailId]/page.tsx @@ -0,0 +1,85 @@ +import { css } from "@styled-system/css"; +import { Flex, styled } from "@styled-system/jsx"; +import { Text } from "@wow-class/ui"; +import { padWithZero, parseISODate } from "@wow-class/utils"; +import { studyApi } from "apis/study/studyApi"; +import ItemSeparator from "components/ItemSeparator"; +import { routerPath } from "constants/router/routerPath"; +import Link from "next/link"; +import Button from "wowds-ui/Button"; +import TextButton from "wowds-ui/TextButton"; + +const AssignmentsPage = async ({ + params: { studyDetailId }, +}: { + params: { studyDetailId: string }; +}) => { + const assignment = await studyApi.getAssignment(+studyDetailId); + if (!assignment) return null; + + const { week, title, descriptionLink, deadline } = assignment; + + const { year, month, day, hours, minutes } = parseISODate(deadline); + + // TODO: studyName 추가 + return ( + <> +
+ + {title} + + {week}주차 과제 + + + +
+ + + 과제 제목 + + {title} + + + + 과제 명세 링크 + + + + 과제 기한 + + {year}년 {month}월 {day}일 {hours}:{padWithZero(minutes)} + + + + + ); +}; + +const headerStyle = css({ + width: "100%", + display: "flex", + justifyContent: "space-between", +}); + +const textButtonStyle = css({ + color: "sub", +}); + +export default AssignmentsPage; diff --git a/apps/admin/app/studies/assignments/layout.tsx b/apps/admin/app/studies/assignments/layout.tsx new file mode 100644 index 00000000..e79da0ff --- /dev/null +++ b/apps/admin/app/studies/assignments/layout.tsx @@ -0,0 +1,15 @@ +import { Flex } from "@styled-system/jsx"; + +const AssignmentsLayout = ({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) => { + return ( + + {children} + + ); +}; + +export default AssignmentsLayout; diff --git a/apps/admin/app/studies/create-study/@modal/(.)created-study-check/page.tsx b/apps/admin/app/studies/create-study/@modal/(.)created-study-check/page.tsx index 768e92d3..4b2bcbbe 100644 --- a/apps/admin/app/studies/create-study/@modal/(.)created-study-check/page.tsx +++ b/apps/admin/app/studies/create-study/@modal/(.)created-study-check/page.tsx @@ -4,10 +4,10 @@ import { Flex } from "@styled-system/jsx"; import { Modal, Space, Text } from "@wow-class/ui"; import { useModalRoute } from "@wow-class/ui/hooks"; import { createStudyApi } from "apis/study/createStudyApi"; +import ItemSeparator from "components/ItemSeparator"; import { routerPath } from "constants/router/routerPath"; import { tags } from "constants/tags"; import useParseSearchParams from "hooks/useParseSearchParams"; -import Image from "next/image"; import { useRouter, useSearchParams } from "next/navigation"; import type { CreateStudyApiRequestDto } from "types/dtos/createStudy"; import { revalidateTagByName } from "utils/revalidateTagByName"; @@ -17,7 +17,7 @@ const CreatedStudyCheckModal = () => { const { parseQueryString } = useParseSearchParams(); const searchParams = useSearchParams(); const router = useRouter(); - const { closeModal } = useModalRoute(); + const { onClose } = useModalRoute(); const data = parseQueryString( searchParams.toString() @@ -45,7 +45,7 @@ const CreatedStudyCheckModal = () => { {studyName} - + {semester} @@ -53,7 +53,7 @@ const CreatedStudyCheckModal = () => { 새로운 스터디를 개설하시겠어요? - @@ -64,7 +64,3 @@ const CreatedStudyCheckModal = () => { }; export default CreatedStudyCheckModal; - -const ItemSeparator = () => ( - item separator -); diff --git a/apps/admin/app/studies/create-study/layout.tsx b/apps/admin/app/studies/create-study/layout.tsx index 5257e48c..7ce95455 100644 --- a/apps/admin/app/studies/create-study/layout.tsx +++ b/apps/admin/app/studies/create-study/layout.tsx @@ -1,3 +1,9 @@ +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: "스터디 만들기", +}; + const CreateStudyLayout = ({ children, modal, diff --git a/apps/admin/app/studies/detail-info/[studyId]/@modal/(.)detail-Info-check/page.tsx b/apps/admin/app/studies/detail-info/[studyId]/@modal/(.)detail-Info-check/page.tsx index ca4668b1..5a84a2d6 100644 --- a/apps/admin/app/studies/detail-info/[studyId]/@modal/(.)detail-Info-check/page.tsx +++ b/apps/admin/app/studies/detail-info/[studyId]/@modal/(.)detail-Info-check/page.tsx @@ -14,7 +14,7 @@ import useSubmitStudyDetailInfo from "./_hooks/useSubmitStudyDetailInfo"; const StudyDetailInfoCheckModal = () => { const [studyName, setStudyName] = useState(""); - const { closeModal } = useModalRoute(); + const { onClose } = useModalRoute(); const { parseToNumberSearchParams, parseQueryString } = useParseSearchParams(); const searchParams = useSearchParams(); @@ -39,7 +39,7 @@ const StudyDetailInfoCheckModal = () => { { + const { studyId } = params; + const router = useRouter(); + const methods = useForm(); + + const handleSubmit = (e: MouseEvent) => { + e.preventDefault(); + const formData = methods.getValues(); + const route = createQueryString( + `${studyId}/${routerPath["detail-info-check"].href}?studyId=${studyId}`, + formData + ); + + router.push(route); + }; + return ( + + + + 스터디 상세 정보를 입력해주세요 + + + loading..}> +
+ +
+ + + + + + + + + ); +}; + +export default CreateStudyDetailInfo; + +const FormStyle = { + maxWidth: "60%", +}; + +const SubmitButtonStyle: CSSProperties = { + top: "0px", + right: "0px", + position: "absolute", +}; diff --git a/apps/admin/app/studies/detail-info/[studyId]/layout.tsx b/apps/admin/app/studies/detail-info/[studyId]/layout.tsx index e432b3d2..d7907bbe 100644 --- a/apps/admin/app/studies/detail-info/[studyId]/layout.tsx +++ b/apps/admin/app/studies/detail-info/[studyId]/layout.tsx @@ -13,9 +13,9 @@ const StudyDetailInfoLayout = ({ ); }; -export default StudyDetailInfoLayout; - const MainLayoutStyle = { height: "100vh", overflow: "auto", }; + +export default StudyDetailInfoLayout; diff --git a/apps/admin/app/studies/detail-info/[studyId]/page.tsx b/apps/admin/app/studies/detail-info/[studyId]/page.tsx index ae494118..27c968fd 100644 --- a/apps/admin/app/studies/detail-info/[studyId]/page.tsx +++ b/apps/admin/app/studies/detail-info/[studyId]/page.tsx @@ -1,84 +1,26 @@ -"use client"; -import { Flex } from "@styled-system/jsx"; -import { Space, Text } from "@wow-class/ui"; -import { routerPath } from "constants/router/routerPath"; -import { useRouter } from "next/navigation"; -import type { CSSProperties, MouseEvent } from "react"; -import { Suspense } from "react"; -import { FormProvider, useForm } from "react-hook-form"; -import type { CreateStudyDetailInfoApiRequestDto } from "types/dtos/studyDetailInfo"; -import createQueryString from "utils/createQueryString"; -import Button from "wowds-ui/Button"; +import { studyApi } from "apis/study/studyApi"; -import Header from "@/studies/[studyId]/_components/header/Header"; +import CreateStudyDetailInfo from "./_components/CreateStudyDetailInfo"; -import StudyCurriculum from "./_components/StudyCurriculum"; -import StudyDescription from "./_components/StudyDescription"; +export const generateMetadata = async ({ + params: { studyId }, +}: { + params: { studyId: string }; +}) => { + const study = await studyApi.getStudyBasicInfo(+studyId); + return { + title: study + ? `${study.title} 스터디 상세 작성하기` + : "스터디 상세 작성하기", + }; +}; const CreateStudyDetailInfoPage = ({ params, }: { params: { studyId: string }; }) => { - const { studyId } = params; - const router = useRouter(); - const methods = useForm(); - - const handleSubmit = (e: MouseEvent) => { - e.preventDefault(); - const formData = methods.getValues(); - const route = createQueryString( - `${studyId}/${routerPath["detail-info-check"].href}?studyId=${studyId}`, - formData - ); - - router.push(route); - }; - return ( - - - - 스터디 상세 정보를 입력해주세요 - - - loading..}> -
- -
- - - - - - - - - ); + return ; }; export default CreateStudyDetailInfoPage; - -const FormStyle = { - maxWidth: "60%", -}; - -const SubmitButtonStyle: CSSProperties = { - top: "0px", - right: "0px", - position: "absolute", -}; diff --git a/apps/admin/app/studies/layout.tsx b/apps/admin/app/studies/layout.tsx index a99c702d..7cb5699e 100644 --- a/apps/admin/app/studies/layout.tsx +++ b/apps/admin/app/studies/layout.tsx @@ -22,6 +22,7 @@ const StudiesLayoutStyle = css({ flexDirection: "column", gap: "sm", height: "100vh", + overflow: "scroll", width: "100%", padding: "54px 101px", }); diff --git a/apps/admin/components/ItemSeparator.tsx b/apps/admin/components/ItemSeparator.tsx new file mode 100644 index 00000000..4c8cc0e6 --- /dev/null +++ b/apps/admin/components/ItemSeparator.tsx @@ -0,0 +1,18 @@ +import Image from "next/image"; + +const ItemSeparator = ({ + width, + height, +}: { + width: number; + height: number; +}) => ( + item separator +); + +export default ItemSeparator; diff --git a/apps/admin/components/Navbar.tsx b/apps/admin/components/Navbar.tsx index ccfddb78..ea5d79dc 100644 --- a/apps/admin/components/Navbar.tsx +++ b/apps/admin/components/Navbar.tsx @@ -1,5 +1,4 @@ import { css } from "@styled-system/css"; -import { Flex } from "@styled-system/jsx"; import { NavItem } from "@wow-class/ui"; import { dashboardApi } from "apis/auth/dashboardApi"; import { studyApi } from "apis/study/studyApi"; @@ -24,13 +23,13 @@ const Navbar = async () => { const navMenu = [ { - href: "studies", + href: "", imageUrl: homeImageUrl, alt: "home-icon", name: "개설된 스터디", items: studyList?.map(({ studyId, title }) => { return { - href: `${studyId}`, + href: `studies/${studyId}`, imageUrl: folderImageUrl, alt: title, name: title, @@ -47,10 +46,8 @@ const Navbar = async () => { return (