diff --git a/docs/code-improvements.md b/docs/code-improvements.md
index a401b5f..05d2f62 100644
--- a/docs/code-improvements.md
+++ b/docs/code-improvements.md
@@ -943,12 +943,14 @@ export function decodeHtmlEntities(text) {
---
-## 4. 낮은 우선순위 (Low)
+## 4. 낮은 우선순위 (Low) ✅ 완료
-### 4.1 하드코딩된 값
+### 4.1 하드코딩된 값 ✅
**파일**: `pages/home/pc/Home.jsx`, `pages/home/mobile/Home.jsx`
+**상태**: ✅ 완료 - `GROUP_INFO` 상수 추가, 멤버 수는 API에서 동적 계산
+
```javascript
// 하드코딩된 데뷔일
const debutDate = new Date('2018-01-24');
@@ -959,51 +961,57 @@ const debutDate = new Date('2018-01-24');
{ value: '2018.01.24', label: '데뷔일' },
```
-**해결방법**: 상수 또는 API로 이동
+**해결방법**: 상수 + 동적 계산
```javascript
// constants/index.js에 추가
export const GROUP_INFO = {
+ NAME: 'fromis_9',
+ NAME_KR: '프로미스나인',
DEBUT_DATE: '2018-01-24',
+ DEBUT_DATE_DISPLAY: '2018.01.24',
FANDOM_NAME: 'flover',
};
-// 또는 멤버 수는 API에서 동적으로 계산
-const activeMembers = members.filter(m => !m.is_former);
-const memberCount = activeMembers.length;
+// 멤버 수는 API에서 동적으로 계산
+const activeMemberCount = members.filter(m => !m.is_former).length;
```
---
-### 4.2 미사용 유틸리티 함수
+### 4.2 미사용 유틸리티 함수 ✅ (유지)
**파일**: `utils/format.js`, `utils/schedule.js`
+**상태**: ✅ 검토 완료 - 관리자 페이지 마이그레이션에서 사용 예정으로 유지
+
**미사용 함수 목록**:
- `formatViewCount()` - 검색 결과 0건
- `formatFileSize()` - 검색 결과 0건
- `groupSchedulesByDate()` - 검색 결과 0건 (정의부만)
- `countByCategory()` - 검색 결과 0건 (정의부만)
-**권장**: 관리자 페이지 마이그레이션 후 재검토, 여전히 미사용이면 삭제
+**결정**: 관리자 페이지 마이그레이션 후 재검토, 여전히 미사용이면 삭제
---
-### 4.3 mobile/Layout.jsx 컴포넌트 분리
+### 4.3 mobile/Layout.jsx 컴포넌트 분리 ✅
**파일**: `components/mobile/Layout.jsx`
+**상태**: ✅ 완료 - Header.jsx, BottomNav.jsx로 분리
+
**문제**: 한 파일에 3개 컴포넌트 존재
- `MobileHeader`
- `MobileBottomNav`
- `Layout`
-**권장**: 별도 파일로 분리
+**해결**: 별도 파일로 분리
```
components/mobile/
-├── Layout.jsx
+├── Layout.jsx # 분리된 컴포넌트 import
├── Header.jsx # MobileHeader
├── BottomNav.jsx # MobileBottomNav
-└── index.js
+└── index.js # Header, BottomNav export 추가
```
---
diff --git a/docs/migration.md b/docs/migration.md
index 4f43464..7ff6850 100644
--- a/docs/migration.md
+++ b/docs/migration.md
@@ -277,6 +277,8 @@ function App() {
### Mobile 컴포넌트 (components/mobile/)
- [x] Layout.jsx
+- [x] Header.jsx (MobileHeader)
+- [x] BottomNav.jsx (MobileBottomNav)
- [x] Calendar.jsx
- [x] ScheduleCard.jsx
- [x] ScheduleListCard.jsx
diff --git a/frontend-temp/src/components/mobile/BottomNav.jsx b/frontend-temp/src/components/mobile/BottomNav.jsx
new file mode 100644
index 0000000..f1fbae0
--- /dev/null
+++ b/frontend-temp/src/components/mobile/BottomNav.jsx
@@ -0,0 +1,45 @@
+import { NavLink, useLocation } from 'react-router-dom';
+import { Home, Users, Disc3, Calendar } from 'lucide-react';
+
+/**
+ * 모바일 하단 네비게이션
+ */
+function MobileBottomNav() {
+ const location = useLocation();
+
+ const navItems = [
+ { path: '/', label: '홈', icon: Home },
+ { path: '/members', label: '멤버', icon: Users },
+ { path: '/album', label: '앨범', icon: Disc3 },
+ { path: '/schedule', label: '일정', icon: Calendar },
+ ];
+
+ return (
+
+ );
+}
+
+export default MobileBottomNav;
diff --git a/frontend-temp/src/components/mobile/Header.jsx b/frontend-temp/src/components/mobile/Header.jsx
new file mode 100644
index 0000000..9a9fe60
--- /dev/null
+++ b/frontend-temp/src/components/mobile/Header.jsx
@@ -0,0 +1,26 @@
+import { NavLink } from 'react-router-dom';
+
+/**
+ * 모바일 헤더 컴포넌트
+ * @param {string} title - 페이지 제목 (없으면 fromis_9)
+ * @param {boolean} noShadow - 그림자 숨김 여부
+ */
+function MobileHeader({ title, noShadow = false }) {
+ return (
+
+ );
+}
+
+export default MobileHeader;
diff --git a/frontend-temp/src/components/mobile/Layout.jsx b/frontend-temp/src/components/mobile/Layout.jsx
index 9d44951..a4d65d3 100644
--- a/frontend-temp/src/components/mobile/Layout.jsx
+++ b/frontend-temp/src/components/mobile/Layout.jsx
@@ -1,70 +1,8 @@
-import { NavLink, useLocation } from 'react-router-dom';
-import { Home, Users, Disc3, Calendar } from 'lucide-react';
import { useEffect } from 'react';
+import MobileHeader from './Header';
+import MobileBottomNav from './BottomNav';
import '@/mobile.css';
-/**
- * 모바일 헤더 컴포넌트
- */
-function MobileHeader({ title, noShadow = false }) {
- return (
-
- );
-}
-
-/**
- * 모바일 하단 네비게이션
- */
-function MobileBottomNav() {
- const location = useLocation();
-
- const navItems = [
- { path: '/', label: '홈', icon: Home },
- { path: '/members', label: '멤버', icon: Users },
- { path: '/album', label: '앨범', icon: Disc3 },
- { path: '/schedule', label: '일정', icon: Calendar },
- ];
-
- return (
-
- );
-}
-
/**
* 모바일 레이아웃 컴포넌트
* @param {React.ReactNode} children - 페이지 컨텐츠
diff --git a/frontend-temp/src/components/mobile/index.js b/frontend-temp/src/components/mobile/index.js
index 4533f85..cc5f621 100644
--- a/frontend-temp/src/components/mobile/index.js
+++ b/frontend-temp/src/components/mobile/index.js
@@ -1,5 +1,7 @@
// 레이아웃
export { default as Layout } from './Layout';
+export { default as Header } from './Header';
+export { default as BottomNav } from './BottomNav';
// 일정 컴포넌트
export { default as Calendar } from './Calendar';
diff --git a/frontend-temp/src/constants/index.js b/frontend-temp/src/constants/index.js
index 7b52724..f821698 100644
--- a/frontend-temp/src/constants/index.js
+++ b/frontend-temp/src/constants/index.js
@@ -57,3 +57,12 @@ export const MONTH_NAMES = [
'1월', '2월', '3월', '4월', '5월', '6월',
'7월', '8월', '9월', '10월', '11월', '12월',
];
+
+/** 그룹 정보 */
+export const GROUP_INFO = {
+ NAME: 'fromis_9',
+ NAME_KR: '프로미스나인',
+ DEBUT_DATE: '2018-01-24',
+ DEBUT_DATE_DISPLAY: '2018.01.24',
+ FANDOM_NAME: 'flover',
+};
diff --git a/frontend-temp/src/pages/home/pc/Home.jsx b/frontend-temp/src/pages/home/pc/Home.jsx
index 86d1d89..c91ae00 100644
--- a/frontend-temp/src/pages/home/pc/Home.jsx
+++ b/frontend-temp/src/pages/home/pc/Home.jsx
@@ -1,8 +1,10 @@
+import { useMemo } from 'react';
import { motion } from 'framer-motion';
import { Link } from 'react-router-dom';
import { Calendar, ArrowRight, Music } from 'lucide-react';
import { useMembers, useAlbums, useUpcomingSchedules } from '@/hooks';
import { ScheduleCard } from '@/components/pc';
+import { GROUP_INFO } from '@/constants';
/**
* PC 홈 페이지
@@ -18,10 +20,18 @@ function Home() {
// 다가오는 일정 (3개)
const { data: upcomingSchedules = [] } = useUpcomingSchedules(3);
+ // 활동 멤버 수
+ const activeMemberCount = useMemo(
+ () => members.filter((m) => !m.is_former).length,
+ [members]
+ );
+
// D+Day 계산
- const debutDate = new Date('2018-01-24');
- const today = new Date();
- const dDay = Math.floor((today - debutDate) / (1000 * 60 * 60 * 24)) + 1;
+ const dDay = useMemo(() => {
+ const debutDate = new Date(GROUP_INFO.DEBUT_DATE);
+ const today = new Date();
+ return Math.floor((today - debutDate) / (1000 * 60 * 60 * 24)) + 1;
+ }, []);
return (
@@ -67,10 +77,10 @@ function Home() {
}}
>
{[
- { value: '2018.01.24', label: '데뷔일' },
+ { value: GROUP_INFO.DEBUT_DATE_DISPLAY, label: '데뷔일' },
{ value: `D+${dDay.toLocaleString()}`, label: 'D+Day' },
- { value: '5', label: '멤버 수' },
- { value: 'flover', label: '팬덤명' },
+ { value: String(activeMemberCount || '-'), label: '멤버 수' },
+ { value: GROUP_INFO.FANDOM_NAME, label: '팬덤명' },
].map((stat, index) => (