diff --git a/apps/client/app/(afterLogin)/my-page/@modal/(.)logout/page.tsx b/apps/client/app/(afterLogin)/my-page/@modal/(.)logout/page.tsx index 96711cb6..57f56a3b 100644 --- a/apps/client/app/(afterLogin)/my-page/@modal/(.)logout/page.tsx +++ b/apps/client/app/(afterLogin)/my-page/@modal/(.)logout/page.tsx @@ -4,7 +4,9 @@ import { css } from "@styled-system/css"; import { Flex } from "@styled-system/jsx"; import { Modal, Space, Text } from "@wow-class/ui"; import { useModalRoute } from "@wow-class/ui/hooks"; +import { fetcher } from "@wow-class/utils"; import { authApi } from "apis/authApi"; +import { baseUrl } from "constants/environment"; import { routePath } from "constants/routePath"; import { useRouter } from "next/navigation"; import Button from "wowds-ui/Button"; @@ -13,8 +15,14 @@ const LogoutModal = () => { const router = useRouter(); const { onClose } = useModalRoute(); const handleClickLogoutButton = async () => { - const response = await authApi.logout(); - if (response.success) { + fetcher.setBaseUrl(`https://${window.location.hostname}`); + await fetcher.post("/api/my-page/logout", {}); + + baseUrl && fetcher.setBaseUrl(baseUrl); + + const { success } = await authApi.logout(); + + if (success) { router.push(routePath["landing"]); } else { router.back(); diff --git a/apps/client/app/(afterLogin)/my-study/_components/AssignmentStatusBox.tsx b/apps/client/app/(afterLogin)/my-study/_components/AssignmentStatusBox.tsx index 2d7c416b..9d4a0341 100644 --- a/apps/client/app/(afterLogin)/my-study/_components/AssignmentStatusBox.tsx +++ b/apps/client/app/(afterLogin)/my-study/_components/AssignmentStatusBox.tsx @@ -30,9 +30,9 @@ const AssignmentStatusBox = ({ const attendanceDeadline = `${year}년 ${month}월 ${day}일 ${hours}:${minutes}까지`; const { - label: assignmentSubmissionStatusLabel, + label: assignmentSubmissionStatusLabel = "", color: assignmentSubmissionStatusColor, - } = assignmentSubmissionStatusMap[assignmentSubmissionStatus]; + } = assignmentSubmissionStatusMap[assignmentSubmissionStatus] || {}; return ( {week}주차 과제 - - {assignmentSubmissionStatusLabel} - + {assignmentSubmissionStatusLabel && ( + + {assignmentSubmissionStatusLabel} + + )} {name} diff --git a/apps/client/app/(afterLogin)/my-study/_components/Header.tsx b/apps/client/app/(afterLogin)/my-study/_components/Header.tsx index 4b41e56c..71447422 100644 --- a/apps/client/app/(afterLogin)/my-study/_components/Header.tsx +++ b/apps/client/app/(afterLogin)/my-study/_components/Header.tsx @@ -39,8 +39,8 @@ const Header = () => { mentorName, studyType, dayOfWeek, - startTime: { hour: startHour, minute: startMinute }, - endTime: { hour: endHour, minute: endMinute }, + startTime, + endTime, totalWeek, period: { startDate, endDate }, introduction, @@ -51,8 +51,10 @@ const Header = () => { 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 studySchedule = + startTime && endTime + ? `${dayToKorean[dayOfWeek]} ${startTime.hour}:${padWithZero(startTime.minute)}-${endTime.hour}:${padWithZero(endTime.minute)}` + : ""; const studyPeriod = `${padWithZero(startMonth)}.${padWithZero(startDay)}- ${padWithZero(endMonth)}.${padWithZero(endDay)}`; diff --git a/apps/client/app/api/my-page/logout/route.ts b/apps/client/app/api/my-page/logout/route.ts new file mode 100644 index 00000000..24fbc521 --- /dev/null +++ b/apps/client/app/api/my-page/logout/route.ts @@ -0,0 +1,17 @@ +import { cookieKey } from "constants/cookieKey"; +import { cookies } from "next/headers"; +import { NextResponse } from "next/server"; + +export async function POST() { + const cookieStore = cookies(); + + cookieStore.set(cookieKey["middleware-executed"], "", { + httpOnly: true, + secure: true, + sameSite: "lax", + expires: new Date(0), + path: "/", + }); + + return NextResponse.json({ success: true }); +} diff --git a/apps/client/components/Navbar.tsx b/apps/client/components/Navbar.tsx index 68707284..17066953 100644 --- a/apps/client/components/Navbar.tsx +++ b/apps/client/components/Navbar.tsx @@ -41,7 +41,7 @@ const Navbar = async () => { className={navContainerStyle} role="navigation" > - - {showConvertToMentorPageButton && ( - - )} + +
+ {showConvertToMentorPageButton && ( + + )} +
); diff --git a/apps/client/constants/cookieKey.ts b/apps/client/constants/cookieKey.ts index 6ed5f754..d8861d97 100644 --- a/apps/client/constants/cookieKey.ts +++ b/apps/client/constants/cookieKey.ts @@ -1,3 +1,4 @@ -export const enum cookieKey { - accessToken = "accessToken", -} +export const cookieKey = { + accessToken: "accessToken", + ["middleware-executed"]: "middleware-executed", +}; diff --git a/apps/client/middleware.ts b/apps/client/middleware.ts index fa67d875..d0f189d2 100644 --- a/apps/client/middleware.ts +++ b/apps/client/middleware.ts @@ -12,13 +12,29 @@ export const config = { const middleware = async (req: NextRequest) => { const cookieStore = cookies(); const accessToken = cookieStore.get(cookieKey.accessToken)?.value; + const cacheCookie = cookieStore.get(cookieKey["middleware-executed"]); - const { memberRole } = await dashboardApi.getDashboardInfo(); - - if (!accessToken || memberRole !== "REGULAR") { + if (!accessToken) { return NextResponse.redirect(new URL(routePath.auth, req.url)); } + if (!cacheCookie) { + const { memberRole } = await dashboardApi.getDashboardInfo(); + + if (memberRole !== "REGULAR") { + return NextResponse.redirect(new URL(routePath.auth, req.url)); + } + + const response = NextResponse.next(); + response.cookies.set(cookieKey["middleware-executed"], "true", { + httpOnly: true, + secure: true, + sameSite: "lax", + }); + + return response; + } + return NextResponse.next(); }; diff --git a/apps/client/types/dtos/myStudy.ts b/apps/client/types/dtos/myStudy.ts index 3146a774..614ebec9 100644 --- a/apps/client/types/dtos/myStudy.ts +++ b/apps/client/types/dtos/myStudy.ts @@ -23,8 +23,8 @@ export interface BasicStudyInfoDto { introduction: string; mentorName: string; dayOfWeek: DayOfWeekType; - startTime: Time; - endTime: Time; + startTime: Time | null; + endTime: Time | null; totalWeek: number; period: { startDate: string; diff --git a/packages/fonts/ProductSans-Bold.woff b/packages/fonts/ProductSans-Bold.woff new file mode 100644 index 00000000..25bcd0ce Binary files /dev/null and b/packages/fonts/ProductSans-Bold.woff differ diff --git a/packages/fonts/ProductSans-Bold.woff2 b/packages/fonts/ProductSans-Bold.woff2 new file mode 100644 index 00000000..194ff5e2 Binary files /dev/null and b/packages/fonts/ProductSans-Bold.woff2 differ diff --git a/packages/fonts/ProductSans-Regular.woff b/packages/fonts/ProductSans-Regular.woff new file mode 100644 index 00000000..df7ffeef Binary files /dev/null and b/packages/fonts/ProductSans-Regular.woff differ diff --git a/packages/fonts/ProductSans-Regular.woff2 b/packages/fonts/ProductSans-Regular.woff2 new file mode 100644 index 00000000..f3d79f7c Binary files /dev/null and b/packages/fonts/ProductSans-Regular.woff2 differ diff --git a/packages/fonts/SUIT-Bold.woff b/packages/fonts/SUIT-Bold.woff new file mode 100644 index 00000000..37ad5b0e Binary files /dev/null and b/packages/fonts/SUIT-Bold.woff differ diff --git a/packages/fonts/SUIT-Bold.woff2 b/packages/fonts/SUIT-Bold.woff2 new file mode 100644 index 00000000..7b4f136d Binary files /dev/null and b/packages/fonts/SUIT-Bold.woff2 differ diff --git a/packages/fonts/SUIT-ExtraBold.woff b/packages/fonts/SUIT-ExtraBold.woff new file mode 100644 index 00000000..d1bc9b32 Binary files /dev/null and b/packages/fonts/SUIT-ExtraBold.woff differ diff --git a/packages/fonts/SUIT-ExtraBold.woff2 b/packages/fonts/SUIT-ExtraBold.woff2 new file mode 100644 index 00000000..823bfbb8 Binary files /dev/null and b/packages/fonts/SUIT-ExtraBold.woff2 differ diff --git a/packages/fonts/SUIT-ExtraLight.woff b/packages/fonts/SUIT-ExtraLight.woff new file mode 100644 index 00000000..73e6c74f Binary files /dev/null and b/packages/fonts/SUIT-ExtraLight.woff differ diff --git a/packages/fonts/SUIT-ExtraLight.woff2 b/packages/fonts/SUIT-ExtraLight.woff2 new file mode 100644 index 00000000..048fd7ba Binary files /dev/null and b/packages/fonts/SUIT-ExtraLight.woff2 differ diff --git a/packages/fonts/SUIT-Heavy.woff b/packages/fonts/SUIT-Heavy.woff new file mode 100644 index 00000000..ed57ba76 Binary files /dev/null and b/packages/fonts/SUIT-Heavy.woff differ diff --git a/packages/fonts/SUIT-Heavy.woff2 b/packages/fonts/SUIT-Heavy.woff2 new file mode 100644 index 00000000..2c3ec6d1 Binary files /dev/null and b/packages/fonts/SUIT-Heavy.woff2 differ diff --git a/packages/fonts/SUIT-Light.woff b/packages/fonts/SUIT-Light.woff new file mode 100644 index 00000000..1cfba14d Binary files /dev/null and b/packages/fonts/SUIT-Light.woff differ diff --git a/packages/fonts/SUIT-Light.woff2 b/packages/fonts/SUIT-Light.woff2 new file mode 100644 index 00000000..1b42dc20 Binary files /dev/null and b/packages/fonts/SUIT-Light.woff2 differ diff --git a/packages/fonts/SUIT-Medium.woff b/packages/fonts/SUIT-Medium.woff new file mode 100644 index 00000000..c60e25a4 Binary files /dev/null and b/packages/fonts/SUIT-Medium.woff differ diff --git a/packages/fonts/SUIT-Medium.woff2 b/packages/fonts/SUIT-Medium.woff2 new file mode 100644 index 00000000..35b294ea Binary files /dev/null and b/packages/fonts/SUIT-Medium.woff2 differ diff --git a/packages/fonts/SUIT-Regular.woff b/packages/fonts/SUIT-Regular.woff new file mode 100644 index 00000000..56128825 Binary files /dev/null and b/packages/fonts/SUIT-Regular.woff differ diff --git a/packages/fonts/SUIT-Regular.woff2 b/packages/fonts/SUIT-Regular.woff2 new file mode 100644 index 00000000..1a2aaf30 Binary files /dev/null and b/packages/fonts/SUIT-Regular.woff2 differ diff --git a/packages/fonts/SUIT-SemiBold.woff b/packages/fonts/SUIT-SemiBold.woff new file mode 100644 index 00000000..bdb678e0 Binary files /dev/null and b/packages/fonts/SUIT-SemiBold.woff differ diff --git a/packages/fonts/SUIT-SemiBold.woff2 b/packages/fonts/SUIT-SemiBold.woff2 new file mode 100644 index 00000000..7e2778a4 Binary files /dev/null and b/packages/fonts/SUIT-SemiBold.woff2 differ diff --git a/packages/fonts/SUIT-Thin.woff b/packages/fonts/SUIT-Thin.woff new file mode 100644 index 00000000..12cd03b3 Binary files /dev/null and b/packages/fonts/SUIT-Thin.woff differ diff --git a/packages/fonts/SUIT-Thin.woff2 b/packages/fonts/SUIT-Thin.woff2 new file mode 100644 index 00000000..eb3c4a8f Binary files /dev/null and b/packages/fonts/SUIT-Thin.woff2 differ diff --git a/packages/fonts/index.css b/packages/fonts/index.css index f1abf4f0..85fd3af5 100644 --- a/packages/fonts/index.css +++ b/packages/fonts/index.css @@ -1,61 +1,101 @@ @font-face { font-family: "SUIT"; font-weight: 200; - src: url("./SUIT-Thin.ttf") format("truetype"); + font-display: swap; + src: + url("./SUIT-Thin.woff2") format("woff2"), + url("./SUIT-Thin.woff") format("woff"), + url("./SUIT-Thin.ttf") format("truetype"); } @font-face { font-family: "SUIT"; font-weight: 300; - src: url("./SUIT-ExtraLight.ttf") format("truetype"); + font-display: swap; + src: + url("./SUIT-ExtraLight.woff2") format("woff2"), + url("./SUIT-ExtraLight.woff") format("woff"), + url("./SUIT-ExtraLight.ttf") format("truetype"); } @font-face { font-family: "SUIT"; font-weight: 400; - src: url("./SUIT-Regular.ttf") format("truetype"); + font-display: swap; + src: + url("./SUIT-Regular.woff2") format("woff2"), + url("./SUIT-Regular.woff") format("woff"), + url("./SUIT-Regular.ttf") format("truetype"); } @font-face { font-family: "SUIT"; font-weight: 500; - src: url("./SUIT-Medium.ttf") format("truetype"); + font-display: swap; + src: + url("./SUIT-Medium.woff2") format("woff2"), + url("./SUIT-Medium.woff") format("woff"), + url("./SUIT-Medium.ttf") format("truetype"); } @font-face { font-family: "SUIT"; font-weight: 600; - src: url("./SUIT-SemiBold.ttf") format("truetype"); + font-display: swap; + src: + url("./SUIT-SemiBold.woff2") format("woff2"), + url("./SUIT-SemiBold.woff") format("woff"), + url("./SUIT-SemiBold.ttf") format("truetype"); } @font-face { font-family: "SUIT"; font-weight: 700; - src: url("./SUIT-Bold.ttf") format("truetype"); + font-display: swap; + src: + url("./SUIT-Bold.woff2") format("woff2"), + url("./SUIT-Bold.woff") format("woff"), + url("./SUIT-Bold.ttf") format("truetype"); } @font-face { font-family: "SUIT"; font-weight: 800; - src: url("./SUIT-ExtraBold.ttf") format("truetype"); + font-display: swap; + src: + url("./SUIT-ExtraBold.woff2") format("woff2"), + url("./SUIT-ExtraBold.woff") format("woff"), + url("./SUIT-ExtraBold.ttf") format("truetype"); } @font-face { font-family: "SUIT"; font-weight: 900; - src: url("./SUIT-Heavy.ttf") format("truetype"); + font-display: swap; + src: + url("./SUIT-Heavy.woff2") format("woff2"), + url("./SUIT-Heavy.woff") format("woff"), + url("./SUIT-Heavy.ttf") format("truetype"); } @font-face { font-family: "Product Sans"; font-weight: 400; - src: url("./ProductSans-Regular.ttf") format("truetype"); + font-display: swap; + src: + url("./ProductSans-Regular.woff2") format("woff2"), + url("./ProductSans-Regular.woff") format("woff"), + url("./ProductSans-Regular.ttf") format("truetype"); } @font-face { font-family: "Product Sans"; font-weight: 700; - src: url("./ProductSans-Bold.ttf") format("truetype"); + font-display: swap; + src: + url("./ProductSans-Bold.woff2") format("woff2"), + url("./ProductSans-Bold.woff") format("woff"), + url("./ProductSans-Bold.ttf") format("truetype"); } body { diff --git a/packages/ui/src/components/NavItem/index.tsx b/packages/ui/src/components/NavItem/index.tsx index 6bc3b581..fea1e725 100644 --- a/packages/ui/src/components/NavItem/index.tsx +++ b/packages/ui/src/components/NavItem/index.tsx @@ -47,13 +47,12 @@ const NavItem = ({ href, imageUrl, alt, name, items }: NavItemProps) => { }; return ( - + 1 ? "true" : undefined} href={`${href}`} - role="menuitem" tabIndex={0} className={navItemStyle({ type: @@ -63,7 +62,7 @@ const NavItem = ({ href, imageUrl, alt, name, items }: NavItemProps) => { > {alt} { {items?.length && items?.length > 1 && ( toggle-icon )} @@ -101,7 +96,7 @@ const NavItem = ({ href, imageUrl, alt, name, items }: NavItemProps) => { > {item.alt} { ))} )} - + ); }; @@ -139,3 +134,11 @@ const navItemStyle = cva({ }, }, }); + +const toggleIconStyle = css({ + width: "20px", + height: "20px", + marginLeft: "auto", +}); + +const navItemImageStyle = css({ width: "20px", height: "20px" }); diff --git a/packages/ui/src/styles.css b/packages/ui/src/styles.css index 96fc873e..8a3a60aa 100644 --- a/packages/ui/src/styles.css +++ b/packages/ui/src/styles.css @@ -418,13 +418,9 @@ progress { .h_20:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { height: 20px; } -.w_20:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#), -.w_20px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { +.w_20:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { width: 20px; } -.h_20px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - height: 20px; -} .gap_12px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { gap: 12px; } @@ -437,6 +433,12 @@ progress { .bg_white:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { background: var(--colors-white); } +.w_20px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { + width: 20px; +} +.h_20px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { + height: 20px; +} .h_80px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { height: 80px; } @@ -824,12 +826,12 @@ progress { .right_xl:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { right: var(--spacing-xl); } -.ml_auto:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { - margin-left: auto; -} .mr_8px:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { margin-right: 8px; } +.ml_auto:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { + margin-left: auto; +} .jc_space-between:not(#\#):not(#\#):not(#\#):not(#\#):not(#\#) { justify-content: space-between; } diff --git a/packages/utils/src/fetcher/index.ts b/packages/utils/src/fetcher/index.ts index 3f7c7870..c91cc884 100644 --- a/packages/utils/src/fetcher/index.ts +++ b/packages/utils/src/fetcher/index.ts @@ -1,4 +1,4 @@ -type ApiResponse = Response & { data?: T }; +type ApiResponse = Response & { data?: T; success?: boolean }; type RequestInterceptor = ( options: RequestInit