/* eslint-disable @next/next/no-img-element */ 'use client'; import { useEffect, useMemo, useRef, useState } from 'react'; import { useRouter } from 'next/navigation'; import Link from 'next/link'; import MainLogoSvg from './svgs/mainlogosvg'; import apiService from './lib/apiService'; import type { Notice } from './admin/notices/mockData'; interface Subject { id: string | number; title: string; imageKey?: string; instructor?: string; } interface CourseCard { id: string | number; title: string; meta: string; image: string; } export default function Home() { const router = useRouter(); const containerRef = useRef(null); const [currentIndex, setCurrentIndex] = useState(0); const [userName, setUserName] = useState(''); const [subjects, setSubjects] = useState([]); const [courseCards, setCourseCards] = useState([]); const [loadingSubjects, setLoadingSubjects] = useState(true); const [totalSubjectsCount, setTotalSubjectsCount] = useState(0); const [notices, setNotices] = useState([]); const [loadingNotices, setLoadingNotices] = useState(true); // NOTE: 실제 이미지 자산 연결 시 해당 src를 교체하세요. const slides = useMemo( () => [ { id: 1, title: '시스템 점검 안내', description: '11월 10일 새벽 2시~4시 시스템 점검이 진행됩니다.', imageSrc: 'https://picsum.photos/seed/xrlms-slide1/1600/900', }, { id: 2, title: '신규 과정 오픈', description: '최신 커리큘럼으로 업스킬링하세요.', imageSrc: 'https://picsum.photos/seed/xrlms-slide2/1600/900', }, { id: 3, title: '수강 이벤트', description: '이번 달 수강 혜택을 확인해보세요.', imageSrc: 'https://picsum.photos/seed/xrlms-slide3/1600/900', }, ], [] ); // 사용자 정보 가져오기 useEffect(() => { let isMounted = true; async function fetchUserInfo() { try { const localStorageToken = localStorage.getItem('token'); const cookieToken = document.cookie .split('; ') .find(row => row.startsWith('token=')) ?.split('=')[1]; const token = localStorageToken || cookieToken; if (!token) { return; } const response = await apiService.getCurrentUser(); if (response.status !== 200) { return; } const data = response.data; if (isMounted) { // 사용자 권한 확인 const userRole = data.role || data.userRole; if (userRole === 'ADMIN' || userRole === 'admin') { // admin 권한이면 /admin/id로 리다이렉트 router.push('/admin/id'); return; } if (data.name) { setUserName(data.name); } } } catch (error) { console.error('사용자 정보 조회 오류:', error); } } fetchUserInfo(); return () => { isMounted = false; }; }, []); // 과목 리스트 가져오기 useEffect(() => { let isMounted = true; async function fetchSubjects() { try { setLoadingSubjects(true); const response = await apiService.getSubjects(); if (response.status !== 200 || !response.data) { return; } // 응답 데이터 구조 확인 및 배열 추출 let subjectsData: any[] = []; let totalCount = 0; if (Array.isArray(response.data)) { subjectsData = response.data; totalCount = response.data.length; } else if (response.data && typeof response.data === 'object') { // 다양한 응답 구조 처리 subjectsData = response.data.items || response.data.courses || response.data.data || response.data.list || response.data.subjects || response.data.subjectList || []; // 전체 개수는 total, totalCount, count 등의 필드에서 가져오거나 배열 길이 사용 totalCount = response.data.total !== undefined ? response.data.total : response.data.totalCount !== undefined ? response.data.totalCount : response.data.count !== undefined ? response.data.count : subjectsData.length; } console.log('과목 리스트 응답:', response.data); console.log('추출된 과목 데이터:', subjectsData); console.log('전체 과목 개수:', totalCount); if (!isMounted) return; // 전체 과목 개수 저장 setTotalSubjectsCount(totalCount); // 상위 10개만 가져오기 const top10Subjects = subjectsData.slice(0, 10); setSubjects(top10Subjects); // 각 과목의 이미지 다운로드 const courseCardsWithImages = await Promise.all( top10Subjects.map(async (subject: Subject) => { let imageUrl = 'https://picsum.photos/seed/xrlms-fallback-card/1200/800'; if (subject.imageKey) { try { const fileUrl = await apiService.getFile(subject.imageKey); if (fileUrl) { imageUrl = fileUrl; } } catch (error) { console.error(`이미지 다운로드 실패 (과목 ID: ${subject.id}):`, error); } } return { id: subject.id, title: subject.title || '', meta: subject.instructor ? `강사: ${subject.instructor}` : 'VOD • 온라인', image: imageUrl, }; }) ); if (isMounted) { setCourseCards(courseCardsWithImages); } } catch (error) { console.error('과목 리스트 조회 오류:', error); } finally { if (isMounted) { setLoadingSubjects(false); } } } fetchSubjects(); return () => { isMounted = false; }; }, []); // 공지사항 리스트 가져오기 useEffect(() => { let isMounted = true; async function fetchNotices() { try { setLoadingNotices(true); const response = await apiService.getNotices(); if (response.status !== 200 || !response.data) { return; } // API 응답이 배열이 아닌 경우 처리 (예: { items: [...] } 형태) let noticesArray: any[] = []; if (Array.isArray(response.data)) { noticesArray = response.data; } else if (response.data && typeof response.data === 'object') { noticesArray = response.data.items || response.data.notices || response.data.data || response.data.list || []; } // 날짜를 yyyy-mm-dd 형식으로 포맷팅 const formatDate = (dateString: string): string => { if (!dateString) return ''; try { const date = new Date(dateString); if (isNaN(date.getTime())) { // 이미 yyyy-mm-dd 형식인 경우 그대로 반환 if (/^\d{4}-\d{2}-\d{2}$/.test(dateString)) { return dateString; } return dateString; } const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; } catch { return dateString; } }; // API 응답 데이터를 Notice 형식으로 변환 const transformedNotices: Notice[] = noticesArray.map((notice: any) => ({ id: notice.id || notice.noticeId || 0, title: notice.title || '', date: formatDate(notice.date || notice.createdAt || notice.createdDate || new Date().toISOString().split('T')[0]), views: notice.views || notice.viewCount || 0, writer: notice.writer || notice.author || notice.createdBy || '관리자', content: notice.content ? (Array.isArray(notice.content) ? notice.content : [notice.content]) : undefined, hasAttachment: notice.hasAttachment || notice.attachment || false, })); if (!isMounted) return; // 날짜 내림차순 정렬 (최신 날짜가 먼저) const sortedNotices = [...transformedNotices].sort((a, b) => b.date.localeCompare(a.date)); setNotices(sortedNotices); } catch (error) { console.error('공지사항 리스트 조회 오류:', error); } finally { if (isMounted) { setLoadingNotices(false); } } } fetchNotices(); return () => { isMounted = false; }; }, []); useEffect(() => { const containerEl = containerRef.current; if (!containerEl) return; const handleScroll = () => { const width = containerEl.clientWidth; const index = Math.round(containerEl.scrollLeft / Math.max(width, 1)); setCurrentIndex(index); }; containerEl.addEventListener('scroll', handleScroll, { passive: true }); return () => { containerEl.removeEventListener('scroll', handleScroll); }; }, []); const scrollToIndex = (index: number) => { const containerEl = containerRef.current; if (!containerEl) return; const clamped = Math.max(0, Math.min(index, slides.length - 1)); const width = containerEl.clientWidth; containerEl.scrollTo({ left: clamped * width, behavior: 'smooth' }); }; const handlePrev = () => scrollToIndex(currentIndex - 1); const handleNext = () => scrollToIndex(currentIndex + 1); return (
{/* 메인 컨테이너 */}
{/* 배너 + 사이드 */}
{/* 배너 */}
{slides.map((slide) => (
{slide.title} { const t = e.currentTarget as HTMLImageElement; if (!t.src.includes('picsum.photos')) t.src = 'https://picsum.photos/seed/xrlms-fallback-slide/1600/900'; }} />
{slide.title}
{slide.description}
))}
{/* 좌/우 내비게이션 버튼 */} {/* 인디케이터 */}
{slides.map((_, idx) => ( ))}
{/* 사이드 패널 (피그마 디자인 적용) */}
{/* 교육 과정 */}

교육 과정

{totalSubjectsCount}
전체보기
{loadingSubjects ? (

로딩 중...

) : (
{courseCards.map((c) => (
router.push(`/course-list/${c.id}`)} className="flex flex-col gap-4 h-[260px] cursor-pointer" >
{c.title} { const t = e.currentTarget as HTMLImageElement; if (!t.src.includes('picsum.photos')) t.src = 'https://picsum.photos/seed/xrlms-fallback-card/1200/800'; }} />
{c.title}

{c.meta}

))}
)}
{/* 공지사항 */}

공지사항

{notices.length}
전체보기
{loadingNotices ? (

로딩 중...

) : (
번호
제목
게시일
조회수
작성자
{notices.map((notice, index) => { // 번호는 정렬된 목록에서의 순서 (최신이 1번) const noticeNumber = notices.length - index; return (
router.push(`/notices/${notice.id}`)} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); router.push(`/notices/${notice.id}`); } }} className="grid grid-cols-[57px_1fr_140px_140px_140px] h-[48px] text-[15px] font-medium text-[#1B2027] border-t border-[#DEE1E6] hover:bg-[rgba(236,240,255,0.5)] cursor-pointer" >
{noticeNumber}
{notice.title}
{notice.date}
{notice.views.toLocaleString()}
{notice.writer}
); })}
)}
{/* 전역 Footer는 layout.tsx에서 렌더링됩니다. */}
); }