diff --git a/apps/admin/app/studies/detail-info/[studyId]/@modal/(.)detail-Info-check/_hooks/useSubmitStudyDetailInfo.ts b/apps/admin/app/studies/detail-info/[studyId]/@modal/(.)detail-Info-check/_hooks/useSubmitStudyDetailInfo.ts new file mode 100644 index 00000000..efcf46f0 --- /dev/null +++ b/apps/admin/app/studies/detail-info/[studyId]/@modal/(.)detail-Info-check/_hooks/useSubmitStudyDetailInfo.ts @@ -0,0 +1,38 @@ +import { createStudyApi } from "apis/study/createStudyApi"; +import { routerPath } from "constants/router/routerPath"; +import { tags } from "constants/tags"; +import { useRouter } from "next/navigation"; +import { useState } from "react"; +import type { CreateStudyDetailInfoApiRequestDto } from "types/dtos/studyDetailInfo"; +import { revalidateTagByName } from "utils/revalidateTagByName"; + +const useSubmitStudyDetailInfo = ( + studyId: number, + studyDetailData: CreateStudyDetailInfoApiRequestDto +) => { + const [isSuccess, setIsSuccess] = useState(false); + const router = useRouter(); + + const handleSubmitDetailInfo = async () => { + const data = await createStudyApi.postStudyDetailInfo( + studyDetailData, + studyId + ); + if (data.success) { + setIsSuccess(true); + revalidateTagByName(tags.curriculums); + const timerId = setTimeout(() => { + router.push(`${routerPath.root.href}/${studyId}`); + }, 500); + return () => clearTimeout(timerId); + } else { + setIsSuccess(false); + window.alert("스터디 상세 정보 저장에 실패했어요."); + router.push(`${routerPath.root.href}`); + } + }; + + return { isSuccess, handleSubmitDetailInfo }; +}; + +export default useSubmitStudyDetailInfo; 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 new file mode 100644 index 00000000..814e4458 --- /dev/null +++ b/apps/admin/app/studies/detail-info/[studyId]/@modal/(.)detail-Info-check/page.tsx @@ -0,0 +1,112 @@ +"use client"; + +import { Flex } from "@styled-system/jsx"; +import { Modal, Space, Text } from "@wow-class/ui"; +import { useModalRoute } from "@wow-class/ui/hooks"; +import { studyApi } from "apis/study/studyApi"; +import useParseSearchParams from "hooks/useParseSearchParams"; +import { useSearchParams } from "next/navigation"; +import { useEffect, useState } from "react"; +import type { CreateStudyDetailInfoApiRequestDto } from "types/dtos/studyDetailInfo"; +import Button from "wowds-ui/Button"; + +import useSubmitStudyDetailInfo from "./_hooks/useSubmitStudyDetailInfo"; + +const StudyDetailInfoCheckModal = () => { + const [studyName, setStudyName] = useState(""); + const { onClose } = useModalRoute(); + const { parseQueryString } = useParseSearchParams(); + const searchParams = useSearchParams(); + const { studyId, ...formData } = parseQueryString< + CreateStudyDetailInfoApiRequestDto & { studyId: string } + >(searchParams.toString()); + + const { isSuccess, handleSubmitDetailInfo } = useSubmitStudyDetailInfo( + parseInt(studyId, 10), + formData + ); + + useEffect(() => { + const fetchStudyData = async () => { + const response = await studyApi.getStudyBasicInfo(parseInt(studyId, 10)); + if (response) setStudyName(response.title); + }; + fetchStudyData(); + }, [studyId]); + + return ( + + + + + ); +}; + +export default StudyDetailInfoCheckModal; + +const SubmitSuccessMessage = ({ + success, + studyName, +}: { + success: boolean; + studyName: string; +}) => { + return ( + <> + {success && ( + + + {studyName} + + + 상세 정보가 저장되었어요. + + + )} + + ); +}; + +const SubmitConfirmMessage = ({ + success, + studyName, + closeModal, + handleSubmitDetailInfo, +}: { + success: boolean; + studyName: string; + closeModal: () => void; + handleSubmitDetailInfo: () => void; +}) => { + if (!success) { + return ( + + + + {studyName} + + + 의 상세정보 + + + + 입력 내용을 저장하시겠어요? + + + + + + + + ); + } else { + return; + } +}; diff --git a/apps/admin/app/studies/detail-info/[studyId]/@modal/default.tsx b/apps/admin/app/studies/detail-info/[studyId]/@modal/default.tsx new file mode 100644 index 00000000..395785b9 --- /dev/null +++ b/apps/admin/app/studies/detail-info/[studyId]/@modal/default.tsx @@ -0,0 +1,5 @@ +const Default = () => { + return null; +}; + +export default Default; diff --git a/apps/admin/app/studies/detail-info/[studyId]/default.tsx b/apps/admin/app/studies/detail-info/[studyId]/default.tsx new file mode 100644 index 00000000..395785b9 --- /dev/null +++ b/apps/admin/app/studies/detail-info/[studyId]/default.tsx @@ -0,0 +1,5 @@ +const Default = () => { + return null; +}; + +export default Default; diff --git a/apps/admin/constants/date.ts b/apps/admin/constants/date.ts new file mode 100644 index 00000000..e69de29b diff --git a/apps/client/app/(afterLogin)/my-study/my-assignment/@modal/(.)repository-url/confirmation/page.tsx b/apps/client/app/(afterLogin)/my-study/my-assignment/@modal/(.)repository-url/confirmation/page.tsx new file mode 100644 index 00000000..4c98645a --- /dev/null +++ b/apps/client/app/(afterLogin)/my-study/my-assignment/@modal/(.)repository-url/confirmation/page.tsx @@ -0,0 +1,46 @@ +"use client"; + +import { css } from "@styled-system/css"; +import { Flex } from "@styled-system/jsx"; +import { Modal, Space, Text } from "@wow-class/ui"; +import { tags } from "constants/tags"; +import useMatchedStudyHistoryId from "hooks/useMatchedStudyHistoryId"; +import { useSearchParams } from "next/navigation"; +import { revalidateTagByName } from "utils/revalidateTagByName"; +import Button from "wowds-ui/Button"; + +const RepositoryUrlConfirmationModal = () => { + const searchParams = useSearchParams(); + const url = searchParams.get("repositoryUrl"); + //const studyHistoryId = useMatchedStudyHistoryId(); + + const handleClickSubmitButton = async () => { + //await studyHistoryApi.putRepository(studyHistoryId, url); + //TODO: 제출 후에 RepositoryBox 를 SUBMITTED 로 상태로 바꿔줘야함. + revalidateTagByName(tags.studyDetailDashboard); + }; + return ( + + + 레포지토리를 입력하시겠어요? + + 최초 과제 제출 전까지 수정이 가능해요. + +
{url}
+ + +
+
+ ); +}; + +export default RepositoryUrlConfirmationModal; + +const urlBoxStyle = css({ + backgroundColor: "backgroundAlternative", + borderRadius: "5px", + color: "sub", + paddingX: "lg", + paddingY: "md", + textStyle: "h2", +}); diff --git a/apps/client/app/(afterLogin)/my-study/my-assignment/@modal/(.)repository-url/default.tsx b/apps/client/app/(afterLogin)/my-study/my-assignment/@modal/(.)repository-url/default.tsx new file mode 100644 index 00000000..395785b9 --- /dev/null +++ b/apps/client/app/(afterLogin)/my-study/my-assignment/@modal/(.)repository-url/default.tsx @@ -0,0 +1,5 @@ +const Default = () => { + return null; +}; + +export default Default; diff --git a/apps/client/app/(afterLogin)/my-study/my-assignment/@modal/default.tsx b/apps/client/app/(afterLogin)/my-study/my-assignment/@modal/default.tsx new file mode 100644 index 00000000..395785b9 --- /dev/null +++ b/apps/client/app/(afterLogin)/my-study/my-assignment/@modal/default.tsx @@ -0,0 +1,5 @@ +const Default = () => { + return null; +}; + +export default Default; diff --git a/apps/client/app/(afterLogin)/my-study/my-assignment/repository-url/confirmation/page.tsx b/apps/client/app/(afterLogin)/my-study/my-assignment/repository-url/confirmation/page.tsx new file mode 100644 index 00000000..8a3c9090 --- /dev/null +++ b/apps/client/app/(afterLogin)/my-study/my-assignment/repository-url/confirmation/page.tsx @@ -0,0 +1,8 @@ +import { routePath } from "constants/routePath"; +import { redirect } from "next/navigation"; + +const RepositoryUrlConfirmationPage = () => { + return redirect(routePath["my-assignment"]); +}; + +export default RepositoryUrlConfirmationPage; diff --git a/apps/client/constants/assignmentSubmissionStatusMap.ts b/apps/client/constants/assignmentSubmissionStatusMap.ts new file mode 100644 index 00000000..9a6dc670 --- /dev/null +++ b/apps/client/constants/assignmentSubmissionStatusMap.ts @@ -0,0 +1,12 @@ +import type { ComponentProps } from "react"; +import type { AssignmentSubmissionStatusType } from "types/entities/common/assignment"; +import type Tag from "wowds-ui/Tag"; + +export const assignmentSubmissionStatusMap: Record< + AssignmentSubmissionStatusType, + { label: string; color: ComponentProps["color"] } +> = { + SUCCESS: { label: "제출 완료", color: "blue" }, + FAILURE: { label: "제출 실패", color: "red" }, + PENDING: { label: "과제 휴강", color: "grey" }, +}; diff --git a/apps/client/hooks/useFetchAttendanceCheckModalInfoData.ts b/apps/client/hooks/useFetchAttendanceCheckModalInfoData.ts new file mode 100644 index 00000000..f53ba8b3 --- /dev/null +++ b/apps/client/hooks/useFetchAttendanceCheckModalInfoData.ts @@ -0,0 +1,45 @@ +import { myStudyApi } from "apis/myStudyApi"; +import { useEffect, useState } from "react"; + +const useFetchAttendanceCheckModalInfoData = () => { + const [studyInfo, setStudyInfo] = useState({ + currentWeek: 0, + studyName: "", + }); + + useEffect(() => { + const fetchAttendanceCheckModalInfoData = async () => { + const myOngoingStudyData = await myStudyApi.getMyOngoingStudyInfo(); + + if (!myOngoingStudyData?.studyId) { + return null; + } + + const dailyTaskListData = await myStudyApi.getDailyTaskList( + myOngoingStudyData?.studyId + ); + const basicStudyInfoData = await myStudyApi.getBasicStudyInfo( + myOngoingStudyData?.studyId + ); + + const attendanceDailyTask = dailyTaskListData?.find( + (dailyTask) => dailyTask.todoType === "ATTENDANCE" + ); + + if (!attendanceDailyTask?.week || !basicStudyInfoData?.title) { + return null; + } + + setStudyInfo({ + currentWeek: attendanceDailyTask?.week, + studyName: basicStudyInfoData?.title, + }); + }; + + fetchAttendanceCheckModalInfoData(); + }, []); + + return { studyInfo }; +}; + +export default useFetchAttendanceCheckModalInfoData; diff --git a/apps/client/hooks/useMatchedStudyHistoryId.ts b/apps/client/hooks/useMatchedStudyHistoryId.ts new file mode 100644 index 00000000..afff0ea9 --- /dev/null +++ b/apps/client/hooks/useMatchedStudyHistoryId.ts @@ -0,0 +1,33 @@ +"use client"; + +import { studyDetailApi } from "apis/studyDetailApi"; +import { studyHistoryApi } from "apis/studyHistoryApi"; +import { history, studyDashBoardData } from "constants/assignmentMockData"; +import { useEffect, useState } from "react"; + +export default function useMatchedStudyHistoryId() { + const [matchedStudyHistoryId, setMatchedStudyHistoryId] = useState(); + useEffect(() => { + const fetchData = async () => { + //TODO: 수강 중인 스터디 api 호출 + //const studyId = await myStudyApi.getMyOngoingStudyInfo(); + //const studyHistories = await studyHistoryApi.getStudyHistory(studyId); + const studyHistories = history; + // const studyDashboard = + // await studyDetailApi.getStudyDetailDashboard(studyId); + const studyDashboard = studyDashBoardData; + if (studyHistories && studyDashboard) { + const submittableWeek = studyDashboard.submittableAssignments[0]?.week; + const matchedHistory = studyHistories.find( + (item) => item.week === submittableWeek + ); + + setMatchedStudyHistoryId(matchedHistory?.assignmentHistoryId); + } + }; + + fetchData(); + }, []); + + return { matchedStudyHistoryId }; +} diff --git a/apps/client/utils/index.ts b/apps/client/utils/index.ts new file mode 100644 index 00000000..de1e7667 --- /dev/null +++ b/apps/client/utils/index.ts @@ -0,0 +1 @@ +export { default as isDeadlinePassed } from "./isDeadlinePassed";