refactor: 폴더 구조 재편 (Phase 1)

- api/: common/, pc/common/, pc/public/, pc/admin/ 구조로 변경
- components/: pc/public/, pc/admin/ 구조로 변경
- hooks/: common/, pc/admin/ 구조로 변경
- pages/: pc/public/, mobile/ 구조로 변경
- confetti.js를 utils/로 이동
- 모든 import 경로 업데이트

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
caadiq 2026-01-22 18:37:30 +09:00
parent 58f359adfa
commit 67a41d78ea
67 changed files with 105 additions and 133 deletions

View file

@ -6,33 +6,34 @@ import { BrowserView, MobileView } from 'react-device-detect';
import { ScrollToTop } from '@/components/common'; import { ScrollToTop } from '@/components/common';
// PC // PC
import { Layout as PCLayout } from '@/components/pc'; import { Layout as PCLayout } from '@/components/pc/public';
// Mobile // Mobile
import { Layout as MobileLayout } from '@/components/mobile'; import { Layout as MobileLayout } from '@/components/mobile';
// // PC
import { PCHome, MobileHome } from '@/pages/home'; import PCHome from '@/pages/pc/public/home/Home';
import { PCMembers, MobileMembers } from '@/pages/members'; import PCMembers from '@/pages/pc/public/members/Members';
import { import PCSchedule from '@/pages/pc/public/schedule/Schedule';
PCSchedule, import PCScheduleDetail from '@/pages/pc/public/schedule/ScheduleDetail';
MobileSchedule, import PCBirthday from '@/pages/pc/public/schedule/Birthday';
PCScheduleDetail, import PCAlbum from '@/pages/pc/public/album/Album';
MobileScheduleDetail, import PCAlbumDetail from '@/pages/pc/public/album/AlbumDetail';
PCBirthday, import PCTrackDetail from '@/pages/pc/public/album/TrackDetail';
MobileBirthday, import PCAlbumGallery from '@/pages/pc/public/album/AlbumGallery';
} from '@/pages/schedule'; import PCNotFound from '@/pages/pc/public/common/NotFound';
import {
PCAlbum, // Mobile
MobileAlbum, import MobileHome from '@/pages/mobile/home/Home';
PCAlbumDetail, import MobileMembers from '@/pages/mobile/members/Members';
MobileAlbumDetail, import MobileSchedule from '@/pages/mobile/schedule/Schedule';
PCTrackDetail, import MobileScheduleDetail from '@/pages/mobile/schedule/ScheduleDetail';
MobileTrackDetail, import MobileBirthday from '@/pages/mobile/schedule/Birthday';
PCAlbumGallery, import MobileAlbum from '@/pages/mobile/album/Album';
MobileAlbumGallery, import MobileAlbumDetail from '@/pages/mobile/album/AlbumDetail';
} from '@/pages/album'; import MobileTrackDetail from '@/pages/mobile/album/TrackDetail';
import { PCNotFound, MobileNotFound } from '@/pages/common'; import MobileAlbumGallery from '@/pages/mobile/album/AlbumGallery';
import MobileNotFound from '@/pages/mobile/common/NotFound';
/** /**
* PC 환경에서 body에 클래스 추가하는 래퍼 * PC 환경에서 body에 클래스 추가하는 래퍼

View file

@ -0,0 +1 @@
export * from './client';

View file

@ -2,30 +2,19 @@
* API 통합 export * API 통합 export
*/ */
// 클라이언트 // 공통 유틸리티
export { export * from './common/client';
fetchApi,
fetchAuthApi,
fetchFormData,
ApiError,
get,
authGet,
post,
authPost,
put,
authPut,
del,
authDel,
} from './client';
// 인증 // 공개 API
export * as authApi from './auth'; export * as scheduleApi from './pc/public/schedules';
export * as albumApi from './pc/public/albums';
export * as memberApi from './pc/common/members';
// 스케줄 // 관리자 API
export * as scheduleApi from './schedules'; export * as authApi from './pc/admin/auth';
// 앨범 // 개별 함수도 export (하위 호환성)
export * as albumApi from './albums'; export * from './pc/public/schedules';
export * from './pc/public/albums';
// 멤버 export * from './pc/common/members';
export * as memberApi from './members'; export * from './pc/admin/auth';

View file

@ -1,7 +1,7 @@
/** /**
* 인증 API * 관리자 인증 API
*/ */
import { fetchApi, fetchAuthApi } from './client'; import { fetchApi, fetchAuthApi } from '@/api/common/client';
/** /**
* 로그인 * 로그인

View file

@ -0,0 +1 @@
export * from './auth';

View file

@ -0,0 +1 @@
export * from './members';

View file

@ -1,7 +1,7 @@
/** /**
* 멤버 API * 멤버 API
*/ */
import { fetchApi, fetchAuthApi, fetchFormData } from './client'; import { fetchApi, fetchAuthApi, fetchFormData } from '@/api/common/client';
// ==================== 공개 API ==================== // ==================== 공개 API ====================

View file

@ -1,7 +1,7 @@
/** /**
* 앨범 API * 앨범 API
*/ */
import { fetchApi, fetchAuthApi, fetchFormData } from './client'; import { fetchApi, fetchAuthApi, fetchFormData } from '@/api/common/client';
// ==================== 공개 API ==================== // ==================== 공개 API ====================

View file

@ -0,0 +1,2 @@
export * from './schedules';
export * from './albums';

View file

@ -1,7 +1,7 @@
/** /**
* 스케줄 API * 스케줄 API
*/ */
import { fetchApi, fetchAuthApi, fetchFormData } from './client'; import { fetchApi, fetchAuthApi, fetchFormData } from '@/api/common/client';
import { getTodayKST, dayjs } from '@/utils'; import { getTodayKST, dayjs } from '@/utils';
/** /**

View file

@ -1,11 +1,8 @@
// 공통 컴포넌트 (디바이스 무관) // 공통 컴포넌트 (디바이스 무관)
export * from './common'; export * from './common';
// 스케줄 컴포넌트
export * from './schedule';
// PC 컴포넌트 // PC 컴포넌트
export * as PC from './pc'; export * as PC from './pc/public';
// Mobile 컴포넌트 // Mobile 컴포넌트
export * as Mobile from './mobile'; export * as Mobile from './mobile';

View file

@ -1,5 +1,2 @@
// 공용 함수
export { fireBirthdayConfetti } from './confetti';
// 관리자 컴포넌트 // 관리자 컴포넌트
export { default as AdminScheduleCard } from './AdminScheduleCard'; export { default as AdminScheduleCard } from './AdminScheduleCard';

View file

@ -0,0 +1,28 @@
// 미디어 쿼리
export { useMediaQuery, useIsMobile, useIsDesktop, useIsTablet } from './useMediaQuery';
// 멤버 데이터
export { useMembers, useMemberDetail } from './useMemberData';
// 앨범 데이터
export { useAlbums, useAlbumDetail, useAlbumGallery } from './useAlbumData';
// 스케줄 데이터
export {
useScheduleData,
useScheduleDetail,
useUpcomingSchedules,
useCategories,
} from './useScheduleData';
// 스케줄 검색
export { useScheduleSearch } from './useScheduleSearch';
// 스케줄 필터링
export { useScheduleFiltering, useCategoryCounts } from './useScheduleFiltering';
// 캘린더
export { useCalendar } from './useCalendar';
// 라이트박스
export { useLightbox } from './useLightbox';

View file

@ -2,31 +2,8 @@
* 통합 export * 통합 export
*/ */
// 미디어 쿼리 // 공통 훅
export { useMediaQuery, useIsMobile, useIsDesktop, useIsTablet } from './useMediaQuery'; export * from './common';
// 멤버 데이터 // 관리자 훅
export { useMembers, useMemberDetail } from './useMemberData'; export * from './pc/admin';
// 앨범 데이터
export { useAlbums, useAlbumDetail, useAlbumGallery } from './useAlbumData';
// 스케줄 데이터
export {
useScheduleData,
useScheduleDetail,
useUpcomingSchedules,
useCategories,
} from './useScheduleData';
// 스케줄 검색
export { useScheduleSearch } from './useScheduleSearch';
// 스케줄 필터링
export { useScheduleFiltering, useCategoryCounts } from './useScheduleFiltering';
// 캘린더
export { useCalendar } from './useCalendar';
// 인증
export { useAdminAuth, useRedirectIfAuthenticated } from './useAdminAuth';

View file

@ -0,0 +1,2 @@
// 관리자 인증
export { useAdminAuth, useRedirectIfAuthenticated } from './useAdminAuth';

View file

@ -1,8 +0,0 @@
export { default as PCAlbum } from './pc/Album';
export { default as MobileAlbum } from './mobile/Album';
export { default as PCAlbumDetail } from './pc/AlbumDetail';
export { default as MobileAlbumDetail } from './mobile/AlbumDetail';
export { default as PCTrackDetail } from './pc/TrackDetail';
export { default as MobileTrackDetail } from './mobile/TrackDetail';
export { default as PCAlbumGallery } from './pc/AlbumGallery';
export { default as MobileAlbumGallery } from './mobile/AlbumGallery';

View file

@ -1,5 +0,0 @@
// PC
export { default as PCNotFound } from './pc/NotFound';
// Mobile
export { default as MobileNotFound } from './mobile/NotFound';

View file

@ -1,2 +0,0 @@
export { default as PCHome } from './pc/Home';
export { default as MobileHome } from './mobile/Home';

View file

@ -1,5 +0,0 @@
// 홈 페이지
export * from './home';
// 멤버 페이지
export * from './members';

View file

@ -1,2 +0,0 @@
export { default as PCMembers } from './pc/Members';
export { default as MobileMembers } from './mobile/Members';

View file

@ -1,7 +1,7 @@
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { getAlbums } from '@/api/albums'; import { getAlbums } from '@/api';
/** /**
* Mobile 앨범 목록 페이지 * Mobile 앨범 목록 페이지

View file

@ -13,7 +13,7 @@ import {
FileText, FileText,
ChevronRight, ChevronRight,
} from 'lucide-react'; } from 'lucide-react';
import { getAlbumByName } from '@/api/albums'; import { getAlbumByName } from '@/api';
import { formatDate, calculateTotalDuration } from '@/utils'; import { formatDate, calculateTotalDuration } from '@/utils';
import { MobileLightbox } from '@/components/common'; import { MobileLightbox } from '@/components/common';

View file

@ -3,7 +3,7 @@ import { useParams, useNavigate } from 'react-router-dom';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { ChevronRight } from 'lucide-react'; import { ChevronRight } from 'lucide-react';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { getAlbumByName } from '@/api/albums'; import { getAlbumByName } from '@/api';
import { MobileLightbox } from '@/components/common'; import { MobileLightbox } from '@/components/common';
/** /**

View file

@ -3,7 +3,7 @@ import { useParams, useNavigate, Link } from 'react-router-dom';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { Clock, User, Music, Mic2, ChevronDown, ChevronUp } from 'lucide-react'; import { Clock, User, Music, Mic2, ChevronDown, ChevronUp } from 'lucide-react';
import { getTrack } from '@/api/albums'; import { getTrack } from '@/api';
import { getYoutubeVideoId, parseCredits } from '@/utils'; import { getYoutubeVideoId, parseCredits } from '@/utils';
/** /**

View file

@ -2,7 +2,7 @@ import { useParams, Link } from 'react-router-dom';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { ChevronLeft } from 'lucide-react'; import { ChevronLeft } from 'lucide-react';
import { fetchApi } from '@/api/client'; import { fetchApi } from '@/api';
/** /**
* Mobile 생일 페이지 * Mobile 생일 페이지

View file

@ -7,7 +7,7 @@ import { useInView } from 'react-intersection-observer';
import { useVirtualizer } from '@tanstack/react-virtual'; import { useVirtualizer } from '@tanstack/react-virtual';
import { getTodayKST, getCategoryInfo } from '@/utils'; import { getTodayKST, getCategoryInfo } from '@/utils';
import { getSchedules, searchSchedules } from '@/api/schedules'; import { getSchedules, searchSchedules } from '@/api';
import { useScheduleStore } from '@/stores'; import { useScheduleStore } from '@/stores';
import { MIN_YEAR, SEARCH_LIMIT } from '@/constants'; import { MIN_YEAR, SEARCH_LIMIT } from '@/constants';
import { import {
@ -16,7 +16,7 @@ import {
ScheduleSearchCard as MobileScheduleSearchCard, ScheduleSearchCard as MobileScheduleSearchCard,
BirthdayCard as MobileBirthdayCard, BirthdayCard as MobileBirthdayCard,
} from '@/components/mobile'; } from '@/components/mobile';
import { fireBirthdayConfetti } from '@/components/schedule'; import { fireBirthdayConfetti } from '@/utils';
/** /**
* 모바일 일정 페이지 * 모바일 일정 페이지

View file

@ -4,8 +4,9 @@ import { useEffect, useState, useRef } from 'react';
import { motion, AnimatePresence } from 'framer-motion'; import { motion, AnimatePresence } from 'framer-motion';
import { Calendar, Clock, ChevronLeft, Link2, X, ChevronRight } from 'lucide-react'; import { Calendar, Clock, ChevronLeft, Link2, X, ChevronRight } from 'lucide-react';
import Linkify from 'react-linkify'; import Linkify from 'react-linkify';
import { getSchedule } from '@/api/schedules'; import { getSchedule } from '@/api';
import { CATEGORY_ID, decodeHtmlEntities, formatFullDate, formatTime, formatXDateTime } from '../sections/utils'; import { CATEGORY_ID } from '@/constants';
import { decodeHtmlEntities, formatFullDate, formatTime, formatXDateTime } from '@/utils';
/** /**
* 전체화면 자동 가로 회전 (숏츠가 아닐 때만) * 전체화면 자동 가로 회전 (숏츠가 아닐 때만)

View file

@ -2,7 +2,7 @@ import { useQuery } from '@tanstack/react-query';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { Calendar, Music } from 'lucide-react'; import { Calendar, Music } from 'lucide-react';
import { getAlbums } from '@/api/albums'; import { getAlbums } from '@/api';
import { formatDate } from '@/utils'; import { formatDate } from '@/utils';
/** /**

View file

@ -3,7 +3,7 @@ import { useParams, useNavigate } from 'react-router-dom';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { motion, AnimatePresence } from 'framer-motion'; import { motion, AnimatePresence } from 'framer-motion';
import { Calendar, Music2, Clock, X, MoreVertical, FileText } from 'lucide-react'; import { Calendar, Music2, Clock, X, MoreVertical, FileText } from 'lucide-react';
import { getAlbumByName } from '@/api/albums'; import { getAlbumByName } from '@/api';
import { formatDate, calculateTotalDuration } from '@/utils'; import { formatDate, calculateTotalDuration } from '@/utils';
import { Lightbox } from '@/components/common'; import { Lightbox } from '@/components/common';

View file

@ -5,7 +5,7 @@ import { motion, AnimatePresence } from 'framer-motion';
import { X, ChevronLeft, ChevronRight, Download } from 'lucide-react'; import { X, ChevronLeft, ChevronRight, Download } from 'lucide-react';
import { RowsPhotoAlbum } from 'react-photo-album'; import { RowsPhotoAlbum } from 'react-photo-album';
import 'react-photo-album/rows.css'; import 'react-photo-album/rows.css';
import { getAlbumByName } from '@/api/albums'; import { getAlbumByName } from '@/api';
import { LightboxIndicator } from '@/components/common'; import { LightboxIndicator } from '@/components/common';
// CSS // CSS

View file

@ -3,7 +3,7 @@ import { useParams, useNavigate, Link } from 'react-router-dom';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { Clock, User, Music, Mic2, ChevronRight } from 'lucide-react'; import { Clock, User, Music, Mic2, ChevronRight } from 'lucide-react';
import { getTrack } from '@/api/albums'; import { getTrack } from '@/api';
import { getYoutubeVideoId, parseCredits } from '@/utils'; import { getYoutubeVideoId, parseCredits } from '@/utils';
/** /**

View file

@ -3,7 +3,7 @@ import { motion } from 'framer-motion';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { Calendar, ArrowRight, Music } from 'lucide-react'; import { Calendar, ArrowRight, Music } from 'lucide-react';
import { useMembers, useAlbums, useUpcomingSchedules } from '@/hooks'; import { useMembers, useAlbums, useUpcomingSchedules } from '@/hooks';
import { ScheduleCard } from '@/components/pc'; import { ScheduleCard } from '@/components/pc/public';
import { GROUP_INFO } from '@/constants'; import { GROUP_INFO } from '@/constants';
/** /**

View file

@ -2,7 +2,7 @@ import { useParams, Link } from 'react-router-dom';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { ChevronRight } from 'lucide-react'; import { ChevronRight } from 'lucide-react';
import { fetchApi } from '@/api/client'; import { fetchApi } from '@/api';
/** /**
* PC 생일 페이지 * PC 생일 페이지

View file

@ -11,9 +11,9 @@ import {
CategoryFilter, CategoryFilter,
ScheduleCard, ScheduleCard,
BirthdayCard, BirthdayCard,
} from '@/components/pc'; } from '@/components/pc/public';
import { fireBirthdayConfetti } from '@/components/schedule'; import { fireBirthdayConfetti } from '@/utils';
import { getSchedules, searchSchedules } from '@/api/schedules'; import { getSchedules, searchSchedules } from '@/api';
import { useScheduleStore } from '@/stores'; import { useScheduleStore } from '@/stores';
import { getTodayKST } from '@/utils'; import { getTodayKST } from '@/utils';
import { SEARCH_LIMIT } from '@/constants'; import { SEARCH_LIMIT } from '@/constants';

View file

@ -2,7 +2,7 @@ import { useParams, Link } from 'react-router-dom';
import { useQuery, keepPreviousData } from '@tanstack/react-query'; import { useQuery, keepPreviousData } from '@tanstack/react-query';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { Calendar, ChevronRight } from 'lucide-react'; import { Calendar, ChevronRight } from 'lucide-react';
import { getSchedule } from '@/api/schedules'; import { getSchedule } from '@/api';
// //
import { YoutubeSection, XSection, DefaultSection, CATEGORY_ID, decodeHtmlEntities } from '../sections'; import { YoutubeSection, XSection, DefaultSection, CATEGORY_ID, decodeHtmlEntities } from '../sections';

View file

@ -1,6 +0,0 @@
export { default as PCSchedule } from './pc/Schedule';
export { default as MobileSchedule } from './mobile/Schedule';
export { default as PCScheduleDetail } from './pc/ScheduleDetail';
export { default as MobileScheduleDetail } from './mobile/ScheduleDetail';
export { default as PCBirthday } from './pc/Birthday';
export { default as MobileBirthday } from './mobile/Birthday';

View file

@ -54,3 +54,6 @@ export {
groupSchedulesByDate, groupSchedulesByDate,
countByCategory, countByCategory,
} from './schedule'; } from './schedule';
// 애니메이션 관련
export { fireBirthdayConfetti } from './confetti';