헤더 버튼 활성화화
This commit is contained in:
119
app/components/Header.tsx
Normal file
119
app/components/Header.tsx
Normal file
@@ -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 (
|
||||||
|
<header className="absolute content-stretch flex items-center justify-between left-[332px] top-[43px] w-[1332px]">
|
||||||
|
<div className="content-stretch flex gap-[99px] items-center relative shrink-0">
|
||||||
|
{/* 로고 */}
|
||||||
|
<button
|
||||||
|
onClick={() => router.push('/')}
|
||||||
|
className="h-[74px] relative shrink-0 w-[72px] cursor-pointer"
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src={logo}
|
||||||
|
alt="로고"
|
||||||
|
className="w-full h-full object-contain"
|
||||||
|
width={72}
|
||||||
|
height={74}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
{/* 메뉴 */}
|
||||||
|
<div className="content-stretch flex gap-[24px] items-center relative shrink-0">
|
||||||
|
<button
|
||||||
|
onClick={() => router.push('/lecturelist')}
|
||||||
|
className="content-stretch flex gap-[150px] items-center relative shrink-0 cursor-pointer group transition-colors"
|
||||||
|
>
|
||||||
|
<div className="box-border content-stretch flex gap-[10px] items-center justify-center p-[10px] relative shrink-0">
|
||||||
|
<p className={`font-bold leading-[normal] not-italic relative shrink-0 text-[24px] text-nowrap whitespace-pre transition-colors ${getMenuTextColor('lecturelist')}`}>
|
||||||
|
교육 과정 목록
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => router.push('/studydata')}
|
||||||
|
className="content-stretch flex gap-[150px] items-center relative shrink-0 cursor-pointer group transition-colors"
|
||||||
|
>
|
||||||
|
<div className="box-border content-stretch flex gap-[10px] items-center justify-center p-[10px] relative shrink-0">
|
||||||
|
<p className={`font-bold leading-[normal] not-italic relative shrink-0 text-[24px] text-nowrap whitespace-pre transition-colors ${getMenuTextColor('studydata')}`}>
|
||||||
|
학습 자료실
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={handleNoticeClick}
|
||||||
|
className="content-stretch flex gap-[150px] items-center relative shrink-0 cursor-pointer group transition-colors"
|
||||||
|
>
|
||||||
|
<div className="box-border content-stretch flex gap-[10px] items-center justify-center p-[10px] relative shrink-0">
|
||||||
|
<p className={`font-bold leading-[normal] not-italic relative shrink-0 text-[24px] text-nowrap whitespace-pre transition-colors ${getMenuTextColor('notice')}`}>
|
||||||
|
공지사항
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* 사용자 메뉴 */}
|
||||||
|
<div className="content-stretch flex gap-[20px] items-center relative shrink-0">
|
||||||
|
<button
|
||||||
|
onClick={() => router.push('/myinfo')}
|
||||||
|
className="box-border content-stretch flex gap-[10px] items-center justify-center p-[10px] relative shrink-0 cursor-pointer group transition-colors"
|
||||||
|
>
|
||||||
|
<p className="font-medium leading-[normal] not-italic relative shrink-0 text-[#515151] text-[18px] text-nowrap whitespace-pre group-hover:text-blue-500 transition-colors">
|
||||||
|
내 강좌실
|
||||||
|
</p>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={handleLogout}
|
||||||
|
className="box-border content-stretch flex gap-[10px] items-center justify-center p-[10px] relative shrink-0 cursor-pointer group transition-colors"
|
||||||
|
>
|
||||||
|
<p className="font-medium leading-[normal] not-italic relative shrink-0 text-[#515151] text-[18px] text-nowrap whitespace-pre group-hover:text-blue-500 transition-colors">
|
||||||
|
로그아웃
|
||||||
|
</p>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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<any[]>([]);
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<div className="bg-white relative min-h-screen w-full pb-[199px]">
|
||||||
|
{/* 헤더 */}
|
||||||
|
<Header activePage="lecturelist" />
|
||||||
|
|
||||||
|
{/* 구분선 */}
|
||||||
|
<div className="absolute h-0 left-1/2 top-[150px] translate-x-[-50%] w-[1920px]">
|
||||||
|
<div className="absolute bottom-0 left-0 right-0 top-[-1px]">
|
||||||
|
<img alt="" className="block max-w-none size-full" src={imgLine2} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 메인 콘텐츠 */}
|
||||||
|
<div className="absolute content-stretch flex flex-col items-start left-[calc(6.25%+79px)] top-[270px] w-[1521px]">
|
||||||
|
{/* 페이지 제목 */}
|
||||||
|
<div className="content-stretch flex items-center relative shrink-0 mb-[20px]">
|
||||||
|
<p className="font-bold leading-[normal] not-italic relative shrink-0 text-[#515151] text-[28px]">
|
||||||
|
교육 과정 목록 ({curriculums.length}건)
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 테이블 헤더 */}
|
||||||
|
<div className="bg-[rgba(235,247,255,0.5)] content-stretch flex h-[41px] items-center relative shrink-0 w-full">
|
||||||
|
<div className="content-stretch flex items-center relative shrink-0 w-full">
|
||||||
|
<div className="basis-0 border-[0.5px_0px_0.5px_0.5px] border-[#b9b9b9] border-solid box-border content-stretch flex gap-[10px] grow items-center min-h-px min-w-px p-[10px] relative shrink-0">
|
||||||
|
<div className="basis-0 flex flex-col font-bold grow justify-center leading-[0] min-h-px min-w-px not-italic relative shrink-0 text-[18px] text-[#515151]">
|
||||||
|
<p className="leading-[normal]">제목</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="basis-0 border-[0.5px_0px_0.5px_0.5px] border-[#b9b9b9] border-solid box-border content-stretch flex gap-[10px] grow items-center min-h-px min-w-px p-[10px] relative shrink-0">
|
||||||
|
<div className="basis-0 flex flex-col font-bold grow justify-center leading-[0] min-h-px min-w-px not-italic relative shrink-0 text-[18px] text-[#515151]">
|
||||||
|
<p className="leading-[normal]">등록자</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="basis-0 border-[0.5px_0px_0.5px_0.5px] border-[#b9b9b9] border-solid box-border content-stretch flex gap-[10px] grow items-center min-h-px min-w-px p-[10px] relative shrink-0">
|
||||||
|
<div className="basis-0 flex flex-col font-bold grow justify-center leading-[0] min-h-px min-w-px not-italic relative shrink-0 text-[18px] text-[#515151]">
|
||||||
|
<p className="leading-[normal]">등록일</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 테이블 내용 */}
|
||||||
|
{curriculums.length > 0 ? (
|
||||||
|
<div className="content-stretch flex flex-col items-start relative shrink-0 w-full">
|
||||||
|
{curriculums.map((curriculum) => (
|
||||||
|
<div key={curriculum.id} className="content-stretch flex items-center relative shrink-0 w-full border-[0.5px] border-[#b9b9b9] border-solid">
|
||||||
|
<div className="basis-0 border-[0.5px_0px_0.5px_0.5px] border-[#b9b9b9] border-solid box-border content-stretch flex gap-[10px] grow items-center min-h-px min-w-px p-[10px] relative shrink-0">
|
||||||
|
<p className="font-medium leading-[normal] not-italic relative shrink-0 text-[#515151] text-[18px]">
|
||||||
|
{curriculum.title}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="basis-0 border-[0.5px_0px_0.5px_0.5px] border-[#b9b9b9] border-solid box-border content-stretch flex gap-[10px] grow items-center min-h-px min-w-px p-[10px] relative shrink-0">
|
||||||
|
<p className="font-medium leading-[normal] not-italic relative shrink-0 text-[#515151] text-[18px]">
|
||||||
|
{curriculum.instructorName || '-'}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="basis-0 border-[0.5px_0px_0.5px_0.5px] border-[#b9b9b9] border-solid box-border content-stretch flex gap-[10px] grow items-center min-h-px min-w-px p-[10px] relative shrink-0">
|
||||||
|
<p className="font-medium leading-[normal] not-italic relative shrink-0 text-[#515151] text-[18px]">
|
||||||
|
{curriculum.createdAt ? new Date(curriculum.createdAt).toLocaleDateString('ko-KR') : '-'}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="content-stretch flex items-center justify-center relative shrink-0 w-full py-[40px]">
|
||||||
|
<p className="font-medium leading-[normal] not-italic relative shrink-0 text-[#b9b9b9] text-[18px]">
|
||||||
|
등록된 교육 과정이 없습니다.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 푸터 */}
|
||||||
|
<footer className="absolute bg-[#f7f7f7] box-border content-stretch flex flex-col gap-[10px] h-[225px] items-start left-0 px-[243px] py-[39px] top-[855px] w-[1920px]">
|
||||||
|
<div className="content-stretch flex gap-[49px] items-center relative shrink-0">
|
||||||
|
<div className="h-[74px] relative shrink-0 w-[72px]">
|
||||||
|
<Image
|
||||||
|
src={logo}
|
||||||
|
alt="로고"
|
||||||
|
className="w-full h-full object-contain"
|
||||||
|
width={72}
|
||||||
|
height={74}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="content-stretch flex flex-col gap-[5px] items-start relative shrink-0 w-[479px]">
|
||||||
|
<div className="content-stretch flex gap-[27px] items-center relative shrink-0 w-full">
|
||||||
|
<div className="box-border content-stretch flex gap-[10px] items-center justify-center p-[10px] relative shrink-0">
|
||||||
|
<p className="font-bold leading-[normal] not-italic relative shrink-0 text-[#515151] text-[18px] text-nowrap whitespace-pre">
|
||||||
|
이용 약관
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="box-border content-stretch flex gap-[10px] items-center justify-center p-[10px] relative shrink-0">
|
||||||
|
<p className="font-bold leading-[normal] not-italic relative shrink-0 text-[#515151] text-[18px] text-nowrap whitespace-pre">
|
||||||
|
개인정보처리방침
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="box-border content-stretch flex gap-[10px] items-center justify-center p-[10px] relative shrink-0">
|
||||||
|
<p className="font-bold leading-[normal] not-italic relative shrink-0 text-[#515151] text-[18px] text-nowrap whitespace-pre">
|
||||||
|
고객센터
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="box-border content-stretch flex flex-col font-medium gap-[10px] items-center justify-center leading-[normal] not-italic p-[10px] relative shrink-0 text-[#515151] text-[16px]">
|
||||||
|
<p className="relative shrink-0 w-[400px]">
|
||||||
|
(12345) 서울특별시 광진구 구의동 123-12(구의타워1)
|
||||||
|
</p>
|
||||||
|
<p className="relative shrink-0 w-[400px]">
|
||||||
|
문의: 1234-1234 (평일 09:00 ~ 18:00)
|
||||||
|
</p>
|
||||||
|
<p className="relative shrink-0 w-[400px]">
|
||||||
|
이메일: qwer1234@go.or.kr
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
79
app/page.tsx
79
app/page.tsx
@@ -4,7 +4,7 @@ import { useEffect, useState } from 'react';
|
|||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import LoginPage from './login/page';
|
import LoginPage from './login/page';
|
||||||
import logo from './logo.svg';
|
import Header from './components/Header';
|
||||||
|
|
||||||
const imgImage2 = "http://localhost:3845/assets/89fda8e949171025b1232bae70fc9d442e4e70c8.png";
|
const imgImage2 = "http://localhost:3845/assets/89fda8e949171025b1232bae70fc9d442e4e70c8.png";
|
||||||
const imgImage7 = "http://localhost:3845/assets/a4e4d09643b890b56084560cc24d6e532a03487b.png";
|
const imgImage7 = "http://localhost:3845/assets/a4e4d09643b890b56084560cc24d6e532a03487b.png";
|
||||||
@@ -70,82 +70,7 @@ export default function HomePage() {
|
|||||||
return (
|
return (
|
||||||
<div className="bg-white relative min-h-screen w-full pb-[199px]">
|
<div className="bg-white relative min-h-screen w-full pb-[199px]">
|
||||||
{/* 헤더 */}
|
{/* 헤더 */}
|
||||||
<header className="absolute content-stretch flex items-center justify-between left-[332px] top-[43px] w-[1332px]">
|
<Header activePage="home" />
|
||||||
<div className="content-stretch flex gap-[99px] items-center relative shrink-0">
|
|
||||||
{/* 로고 */}
|
|
||||||
<button
|
|
||||||
onClick={() => router.push('/')}
|
|
||||||
className="h-[74px] relative shrink-0 w-[72px] cursor-pointer"
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
src={logo}
|
|
||||||
alt="로고"
|
|
||||||
className="w-full h-full object-contain"
|
|
||||||
width={72}
|
|
||||||
height={74}
|
|
||||||
/>
|
|
||||||
</button>
|
|
||||||
{/* 메뉴 */}
|
|
||||||
<div className="content-stretch flex gap-[24px] items-center relative shrink-0">
|
|
||||||
<button
|
|
||||||
onClick={() => router.push('/lecturelist')}
|
|
||||||
className="content-stretch flex gap-[150px] items-center relative shrink-0 cursor-pointer group transition-colors"
|
|
||||||
>
|
|
||||||
<div className="box-border content-stretch flex gap-[10px] items-center justify-center p-[10px] relative shrink-0">
|
|
||||||
<p className="font-bold leading-[normal] not-italic relative shrink-0 text-[#515151] text-[24px] text-nowrap whitespace-pre group-hover:text-blue-500 transition-colors">
|
|
||||||
교육 과정 목록
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={() => router.push('/studydata')}
|
|
||||||
className="content-stretch flex gap-[150px] items-center relative shrink-0 cursor-pointer group transition-colors"
|
|
||||||
>
|
|
||||||
<div className="box-border content-stretch flex gap-[10px] items-center justify-center p-[10px] relative shrink-0">
|
|
||||||
<p className="font-bold leading-[normal] not-italic relative shrink-0 text-[#515151] text-[24px] text-nowrap whitespace-pre group-hover:text-blue-500 transition-colors">
|
|
||||||
학습 자료실
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
// 공지사항 섹션으로 스크롤
|
|
||||||
window.scrollTo({ top: 1213, behavior: 'smooth' });
|
|
||||||
}}
|
|
||||||
className="content-stretch flex gap-[150px] items-center relative shrink-0 cursor-pointer group transition-colors"
|
|
||||||
>
|
|
||||||
<div className="box-border content-stretch flex gap-[10px] items-center justify-center p-[10px] relative shrink-0">
|
|
||||||
<p className="font-bold leading-[normal] not-italic relative shrink-0 text-[#515151] text-[24px] text-nowrap whitespace-pre group-hover:text-blue-500 transition-colors">
|
|
||||||
공지사항
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/* 사용자 메뉴 */}
|
|
||||||
<div className="content-stretch flex gap-[20px] items-center relative shrink-0">
|
|
||||||
<button
|
|
||||||
onClick={() => router.push('/myinfo')}
|
|
||||||
className="box-border content-stretch flex gap-[10px] items-center justify-center p-[10px] relative shrink-0 cursor-pointer group transition-colors"
|
|
||||||
>
|
|
||||||
<p className="font-medium leading-[normal] not-italic relative shrink-0 text-[#515151] text-[18px] text-nowrap whitespace-pre group-hover:text-blue-500 transition-colors">
|
|
||||||
내 강좌실
|
|
||||||
</p>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
localStorage.removeItem('isLoggedIn');
|
|
||||||
setIsLoggedIn(false);
|
|
||||||
router.push('/');
|
|
||||||
}}
|
|
||||||
className="box-border content-stretch flex gap-[10px] items-center justify-center p-[10px] relative shrink-0 cursor-pointer group transition-colors"
|
|
||||||
>
|
|
||||||
<p className="font-medium leading-[normal] not-italic relative shrink-0 text-[#515151] text-[18px] text-nowrap whitespace-pre group-hover:text-blue-500 transition-colors">
|
|
||||||
로그아웃
|
|
||||||
</p>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
{/* 구분선 */}
|
{/* 구분선 */}
|
||||||
<div className="absolute h-0 left-1/2 top-[150px] translate-x-[-50%] w-[1920px]">
|
<div className="absolute h-0 left-1/2 top-[150px] translate-x-[-50%] w-[1920px]">
|
||||||
|
|||||||
@@ -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<any[]>([]);
|
||||||
|
|
||||||
|
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 (
|
||||||
|
<div className="bg-white relative min-h-screen w-full pb-[199px]">
|
||||||
|
{/* 헤더 */}
|
||||||
|
<Header activePage="studydata" />
|
||||||
|
|
||||||
|
{/* 구분선 */}
|
||||||
|
<div className="absolute h-0 left-1/2 top-[150px] translate-x-[-50%] w-[1920px]">
|
||||||
|
<div className="absolute bottom-0 left-0 right-0 top-[-1px]">
|
||||||
|
<img alt="" className="block max-w-none size-full" src={imgLine2} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 메인 콘텐츠 */}
|
||||||
|
<div className="absolute content-stretch flex flex-col items-start left-[calc(6.25%+79px)] top-[270px] w-[1521px]">
|
||||||
|
{/* 페이지 제목 */}
|
||||||
|
<div className="content-stretch flex items-center relative shrink-0 mb-[20px]">
|
||||||
|
<p className="font-bold leading-[normal] not-italic relative shrink-0 text-[#515151] text-[28px]">
|
||||||
|
학습 자료 ({curriculums.length}건)
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 테이블 헤더 */}
|
||||||
|
<div className="bg-[rgba(235,247,255,0.5)] content-stretch flex h-[41px] items-center relative shrink-0 w-full">
|
||||||
|
<div className="content-stretch flex items-center relative shrink-0 w-full">
|
||||||
|
<div className="basis-0 border-[0.5px_0px_0.5px_0.5px] border-[#b9b9b9] border-solid box-border content-stretch flex gap-[10px] grow items-center min-h-px min-w-px p-[10px] relative shrink-0">
|
||||||
|
<div className="basis-0 flex flex-col font-bold grow justify-center leading-[0] min-h-px min-w-px not-italic relative shrink-0 text-[18px] text-[#515151]">
|
||||||
|
<p className="leading-[normal]">제목</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="basis-0 border-[0.5px_0px_0.5px_0.5px] border-[#b9b9b9] border-solid box-border content-stretch flex gap-[10px] grow items-center min-h-px min-w-px p-[10px] relative shrink-0">
|
||||||
|
<div className="basis-0 flex flex-col font-bold grow justify-center leading-[0] min-h-px min-w-px not-italic relative shrink-0 text-[18px] text-[#515151]">
|
||||||
|
<p className="leading-[normal]">등록자</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="basis-0 border-[0.5px_0px_0.5px_0.5px] border-[#b9b9b9] border-solid box-border content-stretch flex gap-[10px] grow items-center min-h-px min-w-px p-[10px] relative shrink-0">
|
||||||
|
<div className="basis-0 flex flex-col font-bold grow justify-center leading-[0] min-h-px min-w-px not-italic relative shrink-0 text-[18px] text-[#515151]">
|
||||||
|
<p className="leading-[normal]">등록일</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 테이블 내용 */}
|
||||||
|
{curriculums.length > 0 ? (
|
||||||
|
<div className="content-stretch flex flex-col items-start relative shrink-0 w-full">
|
||||||
|
{curriculums.map((curriculum) => (
|
||||||
|
<div key={curriculum.id} className="content-stretch flex items-center relative shrink-0 w-full border-[0.5px] border-[#b9b9b9] border-solid">
|
||||||
|
<div className="basis-0 border-[0.5px_0px_0.5px_0.5px] border-[#b9b9b9] border-solid box-border content-stretch flex gap-[10px] grow items-center min-h-px min-w-px p-[10px] relative shrink-0">
|
||||||
|
<p className="font-medium leading-[normal] not-italic relative shrink-0 text-[#515151] text-[18px]">
|
||||||
|
{curriculum.title}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="basis-0 border-[0.5px_0px_0.5px_0.5px] border-[#b9b9b9] border-solid box-border content-stretch flex gap-[10px] grow items-center min-h-px min-w-px p-[10px] relative shrink-0">
|
||||||
|
<p className="font-medium leading-[normal] not-italic relative shrink-0 text-[#515151] text-[18px]">
|
||||||
|
{curriculum.instructorName || '-'}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="basis-0 border-[0.5px_0px_0.5px_0.5px] border-[#b9b9b9] border-solid box-border content-stretch flex gap-[10px] grow items-center min-h-px min-w-px p-[10px] relative shrink-0">
|
||||||
|
<p className="font-medium leading-[normal] not-italic relative shrink-0 text-[#515151] text-[18px]">
|
||||||
|
{curriculum.createdAt ? new Date(curriculum.createdAt).toLocaleDateString('ko-KR') : '-'}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="content-stretch flex items-center justify-center relative shrink-0 w-full py-[40px]">
|
||||||
|
<p className="font-medium leading-[normal] not-italic relative shrink-0 text-[#b9b9b9] text-[18px]">
|
||||||
|
등록된 학습 자료가 없습니다.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 푸터 */}
|
||||||
|
<footer className="absolute bg-[#f7f7f7] box-border content-stretch flex flex-col gap-[10px] h-[225px] items-start left-0 px-[243px] py-[39px] top-[855px] w-[1920px]">
|
||||||
|
<div className="content-stretch flex gap-[49px] items-center relative shrink-0">
|
||||||
|
<div className="h-[74px] relative shrink-0 w-[72px]">
|
||||||
|
<Image
|
||||||
|
src={logo}
|
||||||
|
alt="로고"
|
||||||
|
className="w-full h-full object-contain"
|
||||||
|
width={72}
|
||||||
|
height={74}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="content-stretch flex flex-col gap-[5px] items-start relative shrink-0 w-[479px]">
|
||||||
|
<div className="content-stretch flex gap-[27px] items-center relative shrink-0 w-full">
|
||||||
|
<div className="box-border content-stretch flex gap-[10px] items-center justify-center p-[10px] relative shrink-0">
|
||||||
|
<p className="font-bold leading-[normal] not-italic relative shrink-0 text-[#515151] text-[18px] text-nowrap whitespace-pre">
|
||||||
|
이용 약관
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="box-border content-stretch flex gap-[10px] items-center justify-center p-[10px] relative shrink-0">
|
||||||
|
<p className="font-bold leading-[normal] not-italic relative shrink-0 text-[#515151] text-[18px] text-nowrap whitespace-pre">
|
||||||
|
개인정보처리방침
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="box-border content-stretch flex gap-[10px] items-center justify-center p-[10px] relative shrink-0">
|
||||||
|
<p className="font-bold leading-[normal] not-italic relative shrink-0 text-[#515151] text-[18px] text-nowrap whitespace-pre">
|
||||||
|
고객센터
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="box-border content-stretch flex flex-col font-medium gap-[10px] items-center justify-center leading-[normal] not-italic p-[10px] relative shrink-0 text-[#515151] text-[16px]">
|
||||||
|
<p className="relative shrink-0 w-[400px]">
|
||||||
|
(12345) 서울특별시 광진구 구의동 123-12(구의타워1)
|
||||||
|
</p>
|
||||||
|
<p className="relative shrink-0 w-[400px]">
|
||||||
|
문의: 1234-1234 (평일 09:00 ~ 18:00)
|
||||||
|
</p>
|
||||||
|
<p className="relative shrink-0 w-[400px]">
|
||||||
|
이메일: qwer1234@go.or.kr
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,19 +4,101 @@
|
|||||||
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
|
// 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
|
// 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 {
|
generator client {
|
||||||
provider = "prisma-client"
|
provider = "prisma-client"
|
||||||
output = "../lib/generated/prisma"
|
output = "../lib/generated/prisma"
|
||||||
}
|
}
|
||||||
|
|
||||||
datasource db {
|
datasource db {
|
||||||
provider = "postgresql"
|
provider = "sqlite"
|
||||||
url = env("DATABASE_URL")
|
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 {
|
model Test {
|
||||||
id String @id @default(uuid())
|
id String @id @default(cuid())
|
||||||
name String
|
name String
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @updatedAt
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user