diff --git a/app/components/Header.tsx b/app/components/Header.tsx new file mode 100644 index 0000000..e9b2a27 --- /dev/null +++ b/app/components/Header.tsx @@ -0,0 +1,119 @@ +"use client"; + +import { useRouter } from 'next/navigation'; +import Image from 'next/image'; +import logo from '../logo.svg'; + +type ActivePage = 'home' | 'lecturelist' | 'studydata' | null; + +interface HeaderProps { + activePage?: ActivePage; +} + +export default function Header({ activePage = null }: HeaderProps) { + const router = useRouter(); + + const handleNoticeClick = () => { + if (activePage === 'home') { + window.scrollTo({ top: 1213, behavior: 'smooth' }); + } else { + router.push('/'); + // 홈 페이지로 이동 후 스크롤 + setTimeout(() => { + window.scrollTo({ top: 1213, behavior: 'smooth' }); + }, 100); + } + }; + + const handleLogout = () => { + localStorage.removeItem('isLoggedIn'); + router.push('/'); + }; + + const getMenuTextColor = (page: 'lecturelist' | 'studydata' | 'notice') => { + if (page === 'lecturelist' && activePage === 'lecturelist') { + return 'text-[#1669ca]'; + } + if (page === 'studydata' && activePage === 'studydata') { + return 'text-[#1669ca]'; + } + if (page === 'notice' && activePage === 'home') { + // 홈 페이지에서는 공지사항이 활성화된 것으로 간주하지 않음 + return 'text-[#515151] group-hover:text-blue-500'; + } + return 'text-[#515151] group-hover:text-blue-500'; + }; + + return ( +
+
+ {/* 로고 */} + + {/* 메뉴 */} +
+ + + +
+
+ {/* 사용자 메뉴 */} +
+ + +
+
+ ); +} + diff --git a/app/lecturelist/page.tsx b/app/lecturelist/page.tsx index e69de29..4fa1860 100644 --- a/app/lecturelist/page.tsx +++ b/app/lecturelist/page.tsx @@ -0,0 +1,163 @@ +"use client"; + +import { useEffect, useState } from 'react'; +import { useRouter } from 'next/navigation'; +import Image from 'next/image'; +import Header from '../components/Header'; +import logo from '../logo.svg'; + +const imgLine2 = "http://localhost:3845/assets/6ee8cf4ebb6bc2adb14aab8c9940b3002c20af35.svg"; + +export default function LectureListPage() { + const router = useRouter(); + const [isLoggedIn, setIsLoggedIn] = useState(false); + const [isLoading, setIsLoading] = useState(true); + const [curriculums, setCurriculums] = useState([]); + + useEffect(() => { + // 로그인 상태 확인 + const loginStatus = localStorage.getItem('isLoggedIn') === 'true'; + setIsLoggedIn(loginStatus); + setIsLoading(false); + + // TODO: DB에서 교육 과정 목록 가져오기 + // const fetchCurriculums = async () => { + // const response = await fetch('/api/curriculums'); + // const data = await response.json(); + // setCurriculums(data); + // }; + // fetchCurriculums(); + }, []); + + if (isLoading) { + return null; // 로딩 중 + } + + // 로그인되지 않았으면 로그인 페이지로 리다이렉트 + if (!isLoggedIn) { + router.push('/login'); + return null; + } + + return ( +
+ {/* 헤더 */} +
+ + {/* 구분선 */} +
+
+ +
+
+ + {/* 메인 콘텐츠 */} +
+ {/* 페이지 제목 */} +
+

+ 교육 과정 목록 ({curriculums.length}건) +

+
+ + {/* 테이블 헤더 */} +
+
+
+
+

제목

+
+
+
+
+

등록자

+
+
+
+
+

등록일

+
+
+
+
+ + {/* 테이블 내용 */} + {curriculums.length > 0 ? ( +
+ {curriculums.map((curriculum) => ( +
+
+

+ {curriculum.title} +

+
+
+

+ {curriculum.instructorName || '-'} +

+
+
+

+ {curriculum.createdAt ? new Date(curriculum.createdAt).toLocaleDateString('ko-KR') : '-'} +

+
+
+ ))} +
+ ) : ( +
+

+ 등록된 교육 과정이 없습니다. +

+
+ )} +
+ + {/* 푸터 */} +
+
+
+ 로고 +
+
+
+
+

+ 이용 약관 +

+
+
+

+ 개인정보처리방침 +

+
+
+

+ 고객센터 +

+
+
+
+

+ (12345) 서울특별시 광진구 구의동 123-12(구의타워1) +

+

+ 문의: 1234-1234 (평일 09:00 ~ 18:00) +

+

+ 이메일: qwer1234@go.or.kr +

+
+
+
+
+
+ ); +} + diff --git a/app/page.tsx b/app/page.tsx index 5ae8f73..23e1170 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -4,7 +4,7 @@ import { useEffect, useState } from 'react'; import { useRouter } from 'next/navigation'; import Image from 'next/image'; import LoginPage from './login/page'; -import logo from './logo.svg'; +import Header from './components/Header'; const imgImage2 = "http://localhost:3845/assets/89fda8e949171025b1232bae70fc9d442e4e70c8.png"; const imgImage7 = "http://localhost:3845/assets/a4e4d09643b890b56084560cc24d6e532a03487b.png"; @@ -70,82 +70,7 @@ export default function HomePage() { return (
{/* 헤더 */} -
-
- {/* 로고 */} - - {/* 메뉴 */} -
- - - -
-
- {/* 사용자 메뉴 */} -
- - -
-
+
{/* 구분선 */}
diff --git a/app/studydata/page.tsx b/app/studydata/page.tsx index e69de29..598df4e 100644 --- a/app/studydata/page.tsx +++ b/app/studydata/page.tsx @@ -0,0 +1,163 @@ +"use client"; + +import { useEffect, useState } from 'react'; +import { useRouter } from 'next/navigation'; +import Image from 'next/image'; +import Header from '../components/Header'; +import logo from '../logo.svg'; + +const imgLine2 = "http://localhost:3845/assets/6ee8cf4ebb6bc2adb14aab8c9940b3002c20af35.svg"; + +export default function StudyDataPage() { + const router = useRouter(); + const [isLoggedIn, setIsLoggedIn] = useState(false); + const [isLoading, setIsLoading] = useState(true); + const [curriculums, setCurriculums] = useState([]); + + useEffect(() => { + // 로그인 상태 확인 + const loginStatus = localStorage.getItem('isLoggedIn') === 'true'; + setIsLoggedIn(loginStatus); + setIsLoading(false); + + // TODO: DB에서 교육 과정 목록 가져오기 + // const fetchCurriculums = async () => { + // const response = await fetch('/api/curriculums'); + // const data = await response.json(); + // setCurriculums(data); + // }; + // fetchCurriculums(); + }, []); + + if (isLoading) { + return null; // 로딩 중 + } + + // 로그인되지 않았으면 로그인 페이지로 리다이렉트 + if (!isLoggedIn) { + router.push('/login'); + return null; + } + + return ( +
+ {/* 헤더 */} +
+ + {/* 구분선 */} +
+
+ +
+
+ + {/* 메인 콘텐츠 */} +
+ {/* 페이지 제목 */} +
+

+ 학습 자료 ({curriculums.length}건) +

+
+ + {/* 테이블 헤더 */} +
+
+
+
+

제목

+
+
+
+
+

등록자

+
+
+
+
+

등록일

+
+
+
+
+ + {/* 테이블 내용 */} + {curriculums.length > 0 ? ( +
+ {curriculums.map((curriculum) => ( +
+
+

+ {curriculum.title} +

+
+
+

+ {curriculum.instructorName || '-'} +

+
+
+

+ {curriculum.createdAt ? new Date(curriculum.createdAt).toLocaleDateString('ko-KR') : '-'} +

+
+
+ ))} +
+ ) : ( +
+

+ 등록된 학습 자료가 없습니다. +

+
+ )} +
+ + {/* 푸터 */} + +
+ ); +} + diff --git a/prisma/schema.prisma b/prisma/schema.prisma index d9086a8..d28102f 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -4,19 +4,101 @@ // Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? // Try Prisma Accelerate: https://pris.ly/cli/accelerate-init +// This is your Prisma schema file, +// learn more about it in the docs: https://pris.ly/d/prisma-schema + generator client { provider = "prisma-client" output = "../lib/generated/prisma" } datasource db { - provider = "postgresql" - url = env("DATABASE_URL") + provider = "sqlite" + url = "file:./prisma/dev.db" +} + +// 사용자 권한 Enum +enum UserRole { + STUDENT // 학습자 + INSTRUCTOR // 강사 + ADMIN // 관리자 +} + +// User 모델 +model User { + id String @id @default(cuid()) + email String @unique + name String? + password String + phone String? + gender String? + birthYear Int? + birthMonth Int? + birthDay Int? + role UserRole @default(STUDENT) // 권한 (기본값: 학습자) + isActive Boolean @default(true) // 계정 활성화 여부 (true: 활성화, false: 비활성화) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + registeredLectures Lecture[] @relation("Registrant") // 등록한 강좌 목록 + enrolledLectures UserLecture[] // 수강 중인 강좌 목록 + + @@map("users") +} + +// 교육 과정 관리 +model Curriculum { + id String @id @default(cuid()) + title String // 과정 제목 + thumbnailImage String? // 썸네일 이미지 경로 + instructorId String // 강사 ID (User와의 관계) + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + lectures Lecture[] // 강좌 목록 (1:N 관계) + + @@map("curriculums") +} + +// 강좌 관리 +model Lecture { + id String @id @default(cuid()) + title String // 강좌명 + thumbnailImage String? // 썸네일 이미지 경로 + attachmentFile String? // 첨부 파일 경로 + evaluationQuestionCount Int @default(0) // 학습 평가 문제 수 + curriculumId String // 교육 과정 ID (Curriculum과의 관계) + registrantId String // 등록자 ID (User와의 관계) + registeredAt DateTime @default(now()) // 등록일 + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + curriculum Curriculum @relation(fields: [curriculumId], references: [id], onDelete: Cascade) + registrant User @relation("Registrant", fields: [registrantId], references: [id]) + enrolledUsers UserLecture[] // 수강 중인 사용자 목록 + + @@map("lectures") +} + +// 사용자-강좌 수강 관계 (다대다 관계) +model UserLecture { + id String @id @default(cuid()) + userId String // 사용자 ID + lectureId String // 강좌 ID + enrolledAt DateTime @default(now()) // 수강 시작일 + completedAt DateTime? // 수강 완료일 + isCompleted Boolean @default(false) // 수강 완료 여부 + progress Int @default(0) // 수강 진행률 (0-100) + score Int? // 평가 점수 + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + lecture Lecture @relation(fields: [lectureId], references: [id], onDelete: Cascade) + + @@unique([userId, lectureId]) // 한 사용자는 같은 강좌를 중복 수강할 수 없음 + @@map("user_lectures") } model Test { - id String @id @default(uuid()) - name String - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + id String @id @default(cuid()) + name String }