diff --git a/apps/admin/app/studies/[study]/_components/assignment/AssignmentList.tsx b/apps/admin/app/studies/[studyId]/_components/assignment/AssignmentList.tsx similarity index 88% rename from apps/admin/app/studies/[study]/_components/assignment/AssignmentList.tsx rename to apps/admin/app/studies/[studyId]/_components/assignment/AssignmentList.tsx index 1af84e73..7e67d3a9 100644 --- a/apps/admin/app/studies/[study]/_components/assignment/AssignmentList.tsx +++ b/apps/admin/app/studies/[studyId]/_components/assignment/AssignmentList.tsx @@ -1,7 +1,7 @@ import { Space, Text } from "@wow-class/ui"; import { studyInfoApi } from "apis/study/studyInfoApi"; -import AssignmentItem from "./AssignmentItem"; +import AssignmentListItem from "./AssignmentListItem"; const AssignmentList = async ({ studyId }: { studyId: string }) => { const assignmentList = await studyInfoApi.getAssignmentList( @@ -14,7 +14,7 @@ const AssignmentList = async ({ studyId }: { studyId: string }) => { {assignmentList?.map((assignment, index) => { return ( - diff --git a/apps/admin/app/studies/[studyId]/_components/assignment/AssignmentListItem.tsx b/apps/admin/app/studies/[studyId]/_components/assignment/AssignmentListItem.tsx new file mode 100644 index 00000000..9cd37f9f --- /dev/null +++ b/apps/admin/app/studies/[studyId]/_components/assignment/AssignmentListItem.tsx @@ -0,0 +1,119 @@ +"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 { studyInfoApi } from "apis/study/studyInfoApi"; +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"; + +const AssignmentListItem = ({ + assignment, +}: { + assignment: AssignmentApiResponseDto; +}) => { + const { + studyDetailId, + title, + deadline, + week, + descriptionLink, + 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 studyInfoApi.cancelAssignment(studyDetailId); + if (success) { + window.alert("휴강 처리에 성공했어요."); + revalidateTagByName(tags.assignments); + } else { + window.alert("휴강 처리에 실패했어요."); + } + }; + return ( + + + +
+ {week}주차 + + + {title || "-"} + + {deadline ? studyDeadline : "-"} + + + + + <> + {assignmentStatus === "OPEN" ? ( + + ) : ( + + + + + )} + + +
+ ); +}; +export default AssignmentListItem; + +const ThisWeekBarStyle = cva({ + base: { + width: "4px", + height: "18px", + }, + variants: { + type: { + thisWeek: { + backgroundColor: "primary", + }, + notThisWeek: { + backgroundColor: "transparent", + }, + }, + }, +}); + +const TableLeftStyle = { + display: "flex", + alignItems: "center", + gap: "47px", +}; diff --git a/apps/admin/app/studies/[study]/_components/attendance/CheckAttendanceNumber.tsx b/apps/admin/app/studies/[studyId]/_components/attendance/CheckAttendanceNumber.tsx similarity index 82% rename from apps/admin/app/studies/[study]/_components/attendance/CheckAttendanceNumber.tsx rename to apps/admin/app/studies/[studyId]/_components/attendance/CheckAttendanceNumber.tsx index 95000d34..8cfdffd1 100644 --- a/apps/admin/app/studies/[study]/_components/attendance/CheckAttendanceNumber.tsx +++ b/apps/admin/app/studies/[studyId]/_components/attendance/CheckAttendanceNumber.tsx @@ -11,7 +11,7 @@ const CheckAttendanceNumber = () => {
@@ -25,17 +25,14 @@ const CheckAttendanceNumber = () => { 2024년 5월 23일 00:00 - 23:59까지 - + 2143 } /> @@ -49,10 +46,7 @@ const CheckAttendanceNumber = () => { 2024년 5월 23일 00:00 - 23:59까지 - + 4176 @@ -72,6 +66,11 @@ const AttendanceContainerStyle = css({ gap: "md", }); -const SectionStyle = css({ - padding: "24px 0px", -}); +const AttendanceBoxStyle = { + maxWidth: "282px", +}; + +const AttendanceNumberStyle = { + fontSize: "40px", + fontWeight: 700, +}; diff --git a/apps/admin/app/studies/[studyId]/_components/header/Header.tsx b/apps/admin/app/studies/[studyId]/_components/header/Header.tsx new file mode 100644 index 00000000..3c6a0ea4 --- /dev/null +++ b/apps/admin/app/studies/[studyId]/_components/header/Header.tsx @@ -0,0 +1,165 @@ +"use client"; + +import { css } from "@styled-system/css"; +import { Flex } from "@styled-system/jsx"; +import { Space, Text } from "@wow-class/ui"; +import { padWithZero, parseISODate } from "@wow-class/utils"; +import { studyInfoApi } from "apis/study/studyInfoApi"; +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"; +import { DownArrow } from "wowds-icons"; +import TextButton from "wowds-ui/TextButton"; + +const Header = ({ studyId }: { studyId: string }) => { + const [showIntro, setShowIntro] = useState(false); + const [studyInfo, setStudyInfo] = useState< + StudyBasicInfoApiResponseDto | undefined + >(undefined); + + useEffect(() => { + const fetchData = async () => { + if (studyId) { + const data = await studyInfoApi.getStudyBasicInfo( + parseInt(studyId, 10) + ); + if (data) setStudyInfo(data); + } + }; + + fetchData(); + }, [studyId]); + + const handleClickShowIntro = () => { + setShowIntro((prev) => !prev); + }; + + const introSectionButtonAriaLabel = showIntro + ? "Collapse introduction" + : "Expand introduction"; + const introSectionIconAriaLabel = showIntro + ? "Collapse introduction icon" + : "Expand introduction icon"; + + if (!studyInfo) return null; + + const { + title, + academicYear, + semester, + mentorName, + studyType, + dayOfWeek, + startTime: { hour: startHour, minute: startMinute }, + endTime: { hour: endHour, minute: endMinute }, + totalWeek, + period: { startDate, endDate }, + introduction, + notionLink, + } = studyInfo; + + const { month: startMonth, day: startDay } = parseISODate(startDate); + const { month: endMonth, day: endDay } = parseISODate(endDate); + const studySemester = `${academicYear}-${semester === "FIRST" ? 1 : 2}`; + const studySchedule = `${dayToKorean[dayOfWeek]} ${startHour}:${padWithZero(startMinute)}- + ${endHour}:${padWithZero(endMinute)}`; + const studyPeriod = `${padWithZero(startMonth)}.${padWithZero(startDay)}- + ${padWithZero(endMonth)}.${padWithZero(endDay)}`; + + return ( +
+
+ + + {title} + + + +
+
+ + + + {studySemester} + + + + {mentorName} 멘토 + + + + {studyType} + + +
+ {showIntro && ( +
+
+ + + + 스터디 일정 + + + + {studySchedule} + + + + {totalWeek}주 코스 + + + + {studyPeriod} + + + +
+
+ + + + 스터디 소개 + + + + + + + {introduction} + + + +
+
+ )} +
+ ); +}; + +export default Header; + +const ItemSeparator = () => ( + item separator +); + +const downArrowIconStyle = css({ + cursor: "pointer", +}); diff --git a/apps/admin/app/studies/[study]/_components/session/EmptySessionList.tsx b/apps/admin/app/studies/[studyId]/_components/session/EmptySessionList.tsx similarity index 100% rename from apps/admin/app/studies/[study]/_components/session/EmptySessionList.tsx rename to apps/admin/app/studies/[studyId]/_components/session/EmptySessionList.tsx diff --git a/apps/admin/app/studies/[study]/_components/session/SessionList.tsx b/apps/admin/app/studies/[studyId]/_components/session/SessionList.tsx similarity index 83% rename from apps/admin/app/studies/[study]/_components/session/SessionList.tsx rename to apps/admin/app/studies/[studyId]/_components/session/SessionList.tsx index 8d053ff0..e9ce7a3e 100644 --- a/apps/admin/app/studies/[study]/_components/session/SessionList.tsx +++ b/apps/admin/app/studies/[studyId]/_components/session/SessionList.tsx @@ -2,7 +2,7 @@ import { Space, Text } from "@wow-class/ui"; import { studyInfoApi } from "apis/study/studyInfoApi"; import EmptySessionList from "./EmptySessionList"; -import SessionItem from "./SessionItem"; +import SessionListItem from "./SessionListItem"; const SessionList = async ({ studyId }: { studyId: string }) => { const sessionList = await studyInfoApi.getSessionList(parseInt(studyId, 10)); @@ -16,7 +16,7 @@ const SessionList = async ({ studyId }: { studyId: string }) => { 스터디 커리큘럼 {sessionList?.map((session, index) => ( - + ))} ); diff --git a/apps/admin/app/studies/[study]/_components/session/SessionItem.tsx b/apps/admin/app/studies/[studyId]/_components/session/SessionListItem.tsx similarity index 82% rename from apps/admin/app/studies/[study]/_components/session/SessionItem.tsx rename to apps/admin/app/studies/[studyId]/_components/session/SessionListItem.tsx index 8b267491..4ea0568c 100644 --- a/apps/admin/app/studies/[study]/_components/session/SessionItem.tsx +++ b/apps/admin/app/studies/[studyId]/_components/session/SessionListItem.tsx @@ -5,15 +5,18 @@ import { padWithZero, parseISODate } from "@wow-class/utils"; import type { ComponentProps } from "react"; import type { SessionApiResponseDto } from "types/dtos/sessionList"; import type { DifficultyType } from "types/entities/difficulty"; -import checkThisWeek from "utils/checkThisWeek"; +import getIsCurrentWeek from "utils/getIsCurrentWeek"; import Tag from "wowds-ui/Tag"; -const SessionItem = ({ session }: { session: SessionApiResponseDto }) => { +const SessionListItem = ({ session }: { session: SessionApiResponseDto }) => { const { description = "", period, week, title, difficulty } = session; const { startDate, endDate } = period; const { month: startMonth, day: startDay } = parseISODate(startDate); const { month: endMonth, day: endDay } = parseISODate(endDate); - const thisWeekAssignment = checkThisWeek(endDate); + + const sessionTimeLine = `${padWithZero(startMonth)}.${padWithZero(startDay)} - ${padWithZero(endMonth)}.${padWithZero(endDay)}`; + const thisWeekAssignment = getIsCurrentWeek(endDate); + return ( @@ -42,16 +45,13 @@ const SessionItem = ({ session }: { session: SessionApiResponseDto }) => { - - {padWithZero(startMonth)}.{padWithZero(startDay)} -{" "} - {padWithZero(endMonth)}.{padWithZero(endDay)} - + {sessionTimeLine}
); }; -export default SessionItem; +export default SessionListItem; const ThisWeekBarStyle = cva({ base: { @@ -72,7 +72,6 @@ const ThisWeekBarStyle = cva({ const DifficultyMap: Record< DifficultyType, - // eslint-disable-next-line no-undef { text: string; color: ComponentProps["color"] } > = { HIGH: { @@ -87,4 +86,8 @@ const DifficultyMap: Record< text: "기초", color: "blue", }, + BASIC: { + text: "초급", + color: "yellow", + }, }; diff --git a/apps/admin/app/studies/[study]/page.tsx b/apps/admin/app/studies/[studyId]/page.tsx similarity index 60% rename from apps/admin/app/studies/[study]/page.tsx rename to apps/admin/app/studies/[studyId]/page.tsx index 522719ce..b41d1966 100644 --- a/apps/admin/app/studies/[study]/page.tsx +++ b/apps/admin/app/studies/[studyId]/page.tsx @@ -7,18 +7,23 @@ import CheckAttendanceNumber from "./_components/attendance/CheckAttendanceNumbe import Header from "./_components/header/Header"; import SessionList from "./_components/session/SessionList"; -const StudyPage = ({ params }: { params: { study: string } }) => { +const StudyPage = ({ params }: { params: { studyId: string } }) => { + const { studyId } = params; return ( -
+
- - - - + + + + ); }; export default StudyPage; + +const MinHeightFullDividerStyle = { + minHeight: "1.2px", +}; diff --git a/apps/admin/app/studies/[study]/_components/assignment/AssignmentControlButton.tsx b/apps/admin/app/studies/[study]/_components/assignment/AssignmentControlButton.tsx deleted file mode 100644 index a0ca6971..00000000 --- a/apps/admin/app/studies/[study]/_components/assignment/AssignmentControlButton.tsx +++ /dev/null @@ -1,65 +0,0 @@ -"use client"; -import { Flex } from "@styled-system/jsx"; -import { studyInfoApi } from "apis/study/studyInfoApi"; -import { tags } from "constants/tags"; -import { useRouter } from "next/navigation"; -import type { AssignStatusType } from "types/entities/assignStatus"; -import { revalidateTagByName } from "utils/revalidateTagByName"; -import Button from "wowds-ui/Button"; - -const AssignmentControlButton = ({ - descriptionLink, - studyDetailId, - assignmentStatus, -}: { - descriptionLink: string; - studyDetailId: number; - assignmentStatus: AssignStatusType; -}) => { - const router = useRouter(); - - const handleCancelAssignment = async (studyDetailId: number) => { - const { success } = await studyInfoApi.cancelAssignment(studyDetailId); - if (success) { - window.alert("휴강 처리에 성공했어요."); - revalidateTagByName(tags.assignments); - } else { - window.alert("휴강 처리에 실패했어요."); - } - }; - return ( - <> - {assignmentStatus === "OPEN" ? ( - - ) : ( - - - - - )} - - ); -}; - -export default AssignmentControlButton; diff --git a/apps/admin/app/studies/[study]/_components/assignment/AssignmentItem.tsx b/apps/admin/app/studies/[study]/_components/assignment/AssignmentItem.tsx deleted file mode 100644 index 77d1bbf8..00000000 --- a/apps/admin/app/studies/[study]/_components/assignment/AssignmentItem.tsx +++ /dev/null @@ -1,79 +0,0 @@ -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 type { AssignmentApiResponseDto } from "types/dtos/assignmentList"; -import type { AssignStatusType } from "types/entities/assignStatus"; -import checkThisWeek from "utils/checkThisWeek"; - -import AssignmentControlButton from "./AssignmentControlButton"; - -const AssignmentItem = ({ - assignment, -}: { - assignment: AssignmentApiResponseDto; -}) => { - const { - studyDetailId, - title, - deadline, - week, - descriptionLink, - assignmentStatus, - } = assignment; - const thisWeekAssignment = checkThisWeek(deadline); - const { year, month, day, hours, minutes } = parseISODate(deadline); - return ( - - - -
- {week}주차 - - - {title || "-"} - - {deadline - ? `종료 : ${year}년 ${month}월 ${day}일 ${padWithZero(hours)}:${padWithZero(minutes)}` - : "-"} - - - - - - -
- ); -}; -export default AssignmentItem; - -const ThisWeekBarStyle = cva({ - base: { - width: "4px", - height: "18px", - }, - variants: { - type: { - thisWeek: { - backgroundColor: "primary", - }, - notThisWeek: { - backgroundColor: "transparent", - }, - }, - }, -}); - -const TableLeftStyle = { - display: "flex", - alignItems: "center", - gap: "47px", -}; diff --git a/apps/admin/app/studies/[study]/_components/header/Header.tsx b/apps/admin/app/studies/[study]/_components/header/Header.tsx deleted file mode 100644 index 87bddccf..00000000 --- a/apps/admin/app/studies/[study]/_components/header/Header.tsx +++ /dev/null @@ -1,166 +0,0 @@ -"use client"; - -import { css } from "@styled-system/css"; -import { Flex } from "@styled-system/jsx"; -import { Space, Text } from "@wow-class/ui"; -import { padWithZero, parseISODate } from "@wow-class/utils"; -import { studyInfoApi } from "apis/study/studyInfoApi"; -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"; -import { DownArrow } from "wowds-icons"; -import TextButton from "wowds-ui/TextButton"; - -const Header = ({ studyId }: { studyId: string }) => { - const [showIntro, setShowIntro] = useState(false); - const [studyInfo, setStudyInfo] = useState< - StudyBasicInfoApiResponseDto | undefined - >(undefined); - - useEffect(() => { - const fetchData = async () => { - if (studyId) { - const data = await studyInfoApi.getStudyBasicInfo( - parseInt(studyId, 10) - ); - if (data) setStudyInfo(data); - } - }; - - fetchData(); - }, [studyId]); - - const handleClickShowIntro = () => { - setShowIntro((prev) => !prev); - }; - - const introSectionButtonAriaLabel = showIntro - ? "Collapse introduction" - : "Expand introduction"; - const introSectionIconAriaLabel = showIntro - ? "Collapse introduction icon" - : "Expand introduction icon"; - - if (!studyInfo) return null; - else { - const { - title, - academicYear, - semester, - mentorName, - studyType, - dayOfWeek, - startTime: { hour: startHour, minute: startMinute }, - endTime: { hour: endHour, minute: endMinute }, - totalWeek, - period: { startDate, endDate }, - introduction, - notionLink, - } = studyInfo; - - const { month: startMonth, day: startDay } = parseISODate(startDate); - const { month: endMonth, day: endDay } = parseISODate(endDate); - const studySemester = `${academicYear}-${semester === "FIRST" ? 1 : 2}`; - const studySchedule = `${dayToKorean[dayOfWeek]} ${startHour}:${padWithZero(startMinute)}- - ${endHour}:${padWithZero(endMinute)}`; - const studyPeriod = `${padWithZero(startMonth)}.${padWithZero(startDay)}- - ${padWithZero(endMonth)}.${padWithZero(endDay)}`; - - return ( -
-
- - - {title} - - - -
-
- - - - {studySemester} - - - - {mentorName} 멘토 - - - - {studyType} - - -
- {showIntro && ( -
-
- - - - 스터디 일정 - - - - {studySchedule} - - - - {totalWeek}주 코스 - - - - {studyPeriod} - - - -
-
- - - - 스터디 소개 - - - - - - - {introduction} - - - -
-
- )} -
- ); - } -}; - -export default Header; - -const ItemSeparator = () => ( - item separator -); - -const downArrowIconStyle = css({ - cursor: "pointer", -}); diff --git a/apps/admin/types/dtos/assignmentList.ts b/apps/admin/types/dtos/assignmentList.ts index 7f18b41e..9d98ea74 100644 --- a/apps/admin/types/dtos/assignmentList.ts +++ b/apps/admin/types/dtos/assignmentList.ts @@ -1,4 +1,4 @@ -import type { AssignStatusType } from "types/entities/assignStatus"; +import type { AssignmentStatusType } from "types/entities/assignStatus"; export interface AssignmentApiResponseDto { studyDetailId: number; @@ -6,5 +6,5 @@ export interface AssignmentApiResponseDto { deadline: string; week: number; descriptionLink: string; - assignmentStatus: AssignStatusType; + assignmentStatus: AssignmentStatusType; } diff --git a/apps/admin/types/entities/assignStatus.ts b/apps/admin/types/entities/assignStatus.ts index b646eb0a..936248af 100644 --- a/apps/admin/types/entities/assignStatus.ts +++ b/apps/admin/types/entities/assignStatus.ts @@ -1 +1 @@ -export type AssignStatusType = "NONE" | "OPEN" | "CANCELLED"; +export type AssignmentStatusType = "NONE" | "OPEN" | "CANCELLED"; diff --git a/apps/admin/types/entities/difficulty.ts b/apps/admin/types/entities/difficulty.ts index fed23a94..2f6d3663 100644 --- a/apps/admin/types/entities/difficulty.ts +++ b/apps/admin/types/entities/difficulty.ts @@ -1 +1 @@ -export type DifficultyType = "HIGH" | "MEDIUM" | "LOW"; +export type DifficultyType = "HIGH" | "MEDIUM" | "LOW" | "BASIC"; diff --git a/apps/admin/utils/checkThisWeek.ts b/apps/admin/utils/getIsCurrentWeek.ts similarity index 68% rename from apps/admin/utils/checkThisWeek.ts rename to apps/admin/utils/getIsCurrentWeek.ts index b11f6ea9..474225ab 100644 --- a/apps/admin/utils/checkThisWeek.ts +++ b/apps/admin/utils/getIsCurrentWeek.ts @@ -1,4 +1,4 @@ -const checkThisWeek = (dateString: string): boolean => { +const getIsCurrentWeek = (dateString: string): boolean => { const date = new Date(dateString); const today = new Date(); @@ -8,4 +8,4 @@ const checkThisWeek = (dateString: string): boolean => { return today >= pastWeekDate && today <= date; }; -export default checkThisWeek; +export default getIsCurrentWeek; diff --git a/package.json b/package.json index 8caa0e99..af29f891 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,6 @@ "clsx": "^2.1.1", "wowds-icons": "^0.1.3", "wowds-tokens": "^0.1.1", - "wowds-ui": "^0.1.8" + "wowds-ui": "^0.1.14" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cd44ffd0..1050cfb5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,8 +18,8 @@ importers: specifier: ^0.1.1 version: 0.1.3 wowds-ui: - specifier: ^0.1.8 - version: 0.1.12(next@14.2.5)(react-dom@18.3.1)(react@18.3.1) + specifier: ^0.1.14 + version: 0.1.14(next@14.2.5)(react-dom@18.3.1)(react@18.3.1) devDependencies: '@pandacss/dev': specifier: ^0.44.0 @@ -13740,6 +13740,21 @@ packages: - react-dom dev: false + /wowds-ui@0.1.14(next@14.2.5)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-pIj4lOL/sVoHU6x+YtnsUbmmTHDDjBC8dkO4W6xN7jxJDFgCivK47SUA8ltiI4OMBLsuqUBfqdRuZQbR25IJnw==} + peerDependencies: + next: ^14.1.1 + react: ^18.2.0 + dependencies: + clsx: 2.1.1 + lottie-react: 2.4.0(react-dom@18.3.1)(react@18.3.1) + next: 14.2.5(@babel/core@7.25.2)(react-dom@18.3.1)(react@18.3.1) + react: 18.3.1 + wowds-icons: 0.1.3 + transitivePeerDependencies: + - react-dom + dev: false + /wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'}