-
-
최근 공지
+
+
+
+ Recent Notice
+ {notices.length}
+
+
- show more
+
+ SHOW MORE
+
- {loading &&
Loading...
}
-
- {error &&
{error}
}
-
- {!loading && !error && (
-
- {notices.length > 0 ? (
- notices.map((notice) => (
- //TODO: 공지 요소 누르면 해당 페이지로 넘어가는 기능 필요!
- -
+
+ {notices.length > 0 ? (
+ notices.map((notice) => (
+ //TODO: 공지 요소 누르면 해당 페이지로 넘어가는 기능 필요!
+ -
+
●
-
+
{notice.title}
-
- ))
- ) : (
- 공지사항이 없습니다.
- )}
-
- )}
+
+
+
+ ))
+ ) : (
+ 공지사항이 없습니다.
+ )}
+
)
}
diff --git a/apps/frontend/app/(client)/(main)/course/[courseId]/_components/RecentUpdate.tsx b/apps/frontend/app/(client)/(main)/course/[courseId]/_components/RecentUpdate.tsx
index c29d1e768a..885e169133 100644
--- a/apps/frontend/app/(client)/(main)/course/[courseId]/_components/RecentUpdate.tsx
+++ b/apps/frontend/app/(client)/(main)/course/[courseId]/_components/RecentUpdate.tsx
@@ -1,24 +1,19 @@
'use client'
-import Link from 'next/link'
-import { useSearchParams } from 'next/navigation'
+import { cn } from '@/libs/utils'
+import type { CourseRecentUpdate, RecentUpdateType } from '@/types/type'
+// import { useSearchParams } from 'next/navigation'
import { useState, useEffect } from 'react'
-
-interface Notice {
- id: number
- title: string
- isNew: boolean
-}
+import { toast } from 'sonner'
+import { AssignmentIcon, ExamIcon, GradeIcon, QnaIcon } from './UpdateIcon'
export function RecentUpdate() {
- const searchParams = useSearchParams()
- const courseId = searchParams.get('courseId')
- const [notices, setNotices] = useState
([])
- const [loading, setLoading] = useState(true)
- const [error, setError] = useState(null)
+ // const searchParams = useSearchParams()
+ // const courseId = searchParams.get('courseId')
+ const [updates, setUpdates] = useState([])
useEffect(() => {
- const fetchNotices = () => {
+ const fetchUpdates = () => {
try {
// TODO: API 연동 시 사용할 코드입니다.
// const response = await fetch('')
@@ -36,71 +31,99 @@ export function RecentUpdate() {
// setNotices(formattedData)
// 이것은 샘플 데이터입니다.
- setNotices([
+ setUpdates([
{
id: 999,
- title: '[필독] 3주차 과제 1번 문제 수정사항',
- isNew: true
+ title: 'Week 2 Assignment Uploaded',
+ isNew: true,
+ type: 'Assignment'
},
{
id: 998,
- title: '[필독] 확인된 공지명은 이렇게 보이는 식',
- isNew: false
+ title: 'Week 1 Assignment Graded',
+ isNew: false,
+ type: 'Grade'
},
- { id: 997, title: '[샘플] 공지 테스트 3', isNew: false }
+ {
+ id: 997,
+ title: 'New Answer Registered',
+ isNew: false,
+ type: 'QnA'
+ }
])
} catch (err) {
- setError('공지사항을 불러오는 중 오류가 발생했습니다.')
- } finally {
- setLoading(false)
+ toast.error(`Failed to fetch updates: ${err}`)
}
}
- fetchNotices()
+ fetchUpdates()
}, [])
return (
-
-
-
최근 공지
-
- show more
+
-
+
+
+
+ RECENT UPDATE
+ {updates.length}
+
- {loading &&
Loading...
}
-
- {error &&
{error}
}
-
- {!loading && !error && (
-
- {notices.length > 0 ? (
- notices.map((notice) => (
- //TODO: 공지 요소 누르면 해당 페이지로 넘어가는 기능 필요!
- -
+
+ {updates.length > 0 ? (
+ updates.map((update) => (
+ //TODO: 업데이트 요소 누르면 해당 페이지로 넘어가는 기능 필요!
+ -
+
●
-
- {notice.title}
+
+
+
+
+ {update.title}
-
- ))
- ) : (
- 공지사항이 없습니다.
- )}
-
- )}
+
+
+ ))
+ ) : (
+ 공지사항이 없습니다.
+ )}
+
)
}
+
+interface RecentUpdateIconProps {
+ type: RecentUpdateType
+ isNew: boolean
+}
+
+function RecentUpdateIcon({ type, isNew }: RecentUpdateIconProps) {
+ const strokeColor = isNew ? 'black' : '#8A8A8A'
+ switch (type) {
+ case 'Assignment':
+ return
+ case 'Grade':
+ return
+ case 'QnA':
+ return
+ case 'Exam':
+ return
+ default:
+ throw new Error(`Unknown type: ${type}`)
+ }
+}
diff --git a/apps/frontend/app/(client)/(main)/course/[courseId]/_components/Sidebar.tsx b/apps/frontend/app/(client)/(main)/course/[courseId]/_components/Sidebar.tsx
index 8084f33696..aec0065759 100644
--- a/apps/frontend/app/(client)/(main)/course/[courseId]/_components/Sidebar.tsx
+++ b/apps/frontend/app/(client)/(main)/course/[courseId]/_components/Sidebar.tsx
@@ -1,9 +1,12 @@
'use client'
+import { Separator } from '@/components/shadcn/separator'
import assignmentIcon from '@/public/icons/assignment.svg'
import examIcon from '@/public/icons/exam.svg'
+import gradeIcon from '@/public/icons/grade.svg'
import homeIcon from '@/public/icons/home.svg'
import noticeIcon from '@/public/icons/notice.svg'
+import qnaIcon from '@/public/icons/qna.svg'
import Image from 'next/image'
import Link from 'next/link'
import { useSearchParams } from 'next/navigation'
@@ -32,12 +35,12 @@ export function Sidebar() {
{
name: 'Grade',
path: `/course/${courseId}/grade` as const,
- icon: assignmentIcon
+ icon: gradeIcon
},
{
name: 'Q&A',
path: `/course/${courseId}/qna` as const,
- icon: assignmentIcon
+ icon: qnaIcon
}
]
@@ -52,13 +55,13 @@ export function Sidebar() {
{item.name}
+
))}
diff --git a/apps/frontend/app/(client)/(main)/course/[courseId]/_components/UpdateIcon.tsx b/apps/frontend/app/(client)/(main)/course/[courseId]/_components/UpdateIcon.tsx
new file mode 100644
index 0000000000..0896674e7d
--- /dev/null
+++ b/apps/frontend/app/(client)/(main)/course/[courseId]/_components/UpdateIcon.tsx
@@ -0,0 +1,134 @@
+interface IconProps {
+ strokeColor?: string
+}
+export function AssignmentIcon({ strokeColor }: IconProps) {
+ return (
+
+ )
+}
+
+export function GradeIcon({ strokeColor }: IconProps) {
+ return (
+
+ )
+}
+
+export function QnaIcon({ strokeColor }: IconProps) {
+ return (
+
+ )
+}
+
+export function ExamIcon({ strokeColor }: IconProps) {
+ return (
+
+ )
+}
diff --git a/apps/frontend/app/(client)/(main)/course/[courseId]/layout.tsx b/apps/frontend/app/(client)/(main)/course/[courseId]/layout.tsx
index cb5516fba2..92a0166d11 100644
--- a/apps/frontend/app/(client)/(main)/course/[courseId]/layout.tsx
+++ b/apps/frontend/app/(client)/(main)/course/[courseId]/layout.tsx
@@ -1,33 +1,24 @@
import { Separator } from '@/components/shadcn/separator'
-import codedangLogo from '@/public/logos/codedang-with-text.svg'
-import Image from 'next/image'
-import Link from 'next/link'
-import { Header } from './_components/Header'
+import { CourseInfoBox } from './_components/CourseInfoBox'
+import { Cover } from './_components/Cover'
import { Sidebar } from './_components/Sidebar'
export default function Layout({ children }: { children: React.ReactNode }) {
return (
-
-
-
-
-
-
-
- {children}
-
+ <>
+
+
+
+
+
+
+ {children}
+
+
-
+ >
)
}
diff --git a/apps/frontend/app/(client)/(main)/course/[courseId]/page.tsx b/apps/frontend/app/(client)/(main)/course/[courseId]/page.tsx
index d5034cb0d7..590bce7f98 100644
--- a/apps/frontend/app/(client)/(main)/course/[courseId]/page.tsx
+++ b/apps/frontend/app/(client)/(main)/course/[courseId]/page.tsx
@@ -1,5 +1,5 @@
import { Separator } from '@/components/shadcn/separator'
-import { AssignmentOverview } from './_components/AssignmentOverview'
+import { OngoingAssignments } from './_components/OngoingAssignments'
import { RecentNotice } from './_components/RecentNotice'
import { RecentUpdate } from './_components/RecentUpdate'
@@ -16,7 +16,7 @@ export default function Dashboard() {
-
+
)
}
diff --git a/apps/frontend/app/(client)/(main)/course/_components/CourseCardList.tsx b/apps/frontend/app/(client)/(main)/course/_components/CourseCardList.tsx
index f496697af1..a37f1e6a7b 100644
--- a/apps/frontend/app/(client)/(main)/course/_components/CourseCardList.tsx
+++ b/apps/frontend/app/(client)/(main)/course/_components/CourseCardList.tsx
@@ -66,7 +66,7 @@ const getUsername = async () => {
const getCourses = async () => {
try {
const rawData: RawCourse[] = await safeFetcherWithAuth
- .get('group/joined')
+ .get('course/joined')
.json()
const data: Course[] = rawData.map((item: RawCourse) => ({
id: item.id,
diff --git a/apps/frontend/app/(client)/(main)/course/_components/Cover.tsx b/apps/frontend/app/(client)/(main)/course/_components/Cover.tsx
new file mode 100644
index 0000000000..39bb26efcc
--- /dev/null
+++ b/apps/frontend/app/(client)/(main)/course/_components/Cover.tsx
@@ -0,0 +1,116 @@
+import { Button } from '@/components/shadcn/button'
+import { cn } from '@/libs/utils'
+import Image from 'next/image'
+import { FaArrowRightLong } from 'react-icons/fa6'
+
+interface CoverProps {
+ title: string
+ welcomeText: string
+ mainText: string
+ buttonText: string
+}
+
+interface OvalIconProps {
+ position: string
+ transform: string
+ additionalClasses?: string
+}
+
+const bgColors: { [key: string]: string } = {
+ course: 'bg-gradient-to-r from-[#E9D0FF] via-[#DAB5FF] to-[#C9F]'
+}
+
+const titleTextColors: { [key: string]: string } = {
+ course: 'text-[#3E29A0]'
+}
+
+const gradientTextColors: { [key: string]: string } = {
+ course:
+ 'bg-gradient-to-r from-[#1D124A] via-[#3B2699] via-[#5942D7] to-[#5C3CCF] bg-clip-text text-transparent' // 그라디언트 보조 텍스트 색상
+}
+
+const icons: { [key: string]: string } = {
+ course: '/banners/book.png'
+}
+
+export function Cover({
+ title,
+ welcomeText,
+ mainText,
+ buttonText
+}: CoverProps) {
+ return (
+
+
+
+
+
+
+ {welcomeText}
+
+
+
CODEDANG
+
{mainText}
+
+
+
+
+
+
+
+
+ )
+}
+
+function OvalIcon({ position, transform, additionalClasses }: OvalIconProps) {
+ return (
+
+ )
+}
diff --git a/apps/frontend/app/(client)/(main)/course/page.tsx b/apps/frontend/app/(client)/(main)/course/page.tsx
index 5db126db00..00b77b066c 100644
--- a/apps/frontend/app/(client)/(main)/course/page.tsx
+++ b/apps/frontend/app/(client)/(main)/course/page.tsx
@@ -1,4 +1,3 @@
-import { Cover } from '@/app/(client)/(main)/_components/Cover'
import { FetchErrorFallback } from '@/components/FetchErrorFallback'
import { Separator } from '@/components/shadcn/separator'
import { Skeleton } from '@/components/shadcn/skeleton'
@@ -6,6 +5,7 @@ import { auth } from '@/libs/auth'
import { ErrorBoundary } from '@suspensive/react'
import { Suspense } from 'react'
import { CourseCardList } from './_components/CourseCardList'
+import { Cover } from './_components/Cover'
import { Dashboard } from './_components/Dashboard'
function CardListFallback() {
@@ -24,7 +24,12 @@ export default async function Course() {
const session = await auth()
return (
<>
-
+
}>
@@ -40,7 +45,6 @@ export default async function Course() {
Course Overview
- {/* TODO: 완성되면 주석해제 할 거예요! */}