diff --git a/src/pages/indicator/assets/next.svg b/src/pages/indicator/assets/next.svg new file mode 100644 index 0000000..768d07b --- /dev/null +++ b/src/pages/indicator/assets/next.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/pages/indicator/assets/prev.svg b/src/pages/indicator/assets/prev.svg new file mode 100644 index 0000000..3c1febf --- /dev/null +++ b/src/pages/indicator/assets/prev.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/pages/indicator/economic/EconomicPage.tsx b/src/pages/indicator/economic/EconomicPage.tsx index 7227c8f..8001e2e 100644 --- a/src/pages/indicator/economic/EconomicPage.tsx +++ b/src/pages/indicator/economic/EconomicPage.tsx @@ -1,9 +1,15 @@ -import React from "react"; +import React, { useState, useMemo } from "react"; +import Calendar from "./components/Calendar" const EconomicPage = () => { + const [pickedRange, setPickedRange] = useState<{ + start: Date; + end: Date; + } | null>(null); + return (
-

경제 페이지 내용 들어올 곳

+
); }; diff --git a/src/pages/indicator/economic/components/Calendar.tsx b/src/pages/indicator/economic/components/Calendar.tsx new file mode 100644 index 0000000..fd302ec --- /dev/null +++ b/src/pages/indicator/economic/components/Calendar.tsx @@ -0,0 +1,228 @@ +import React, { useState } from "react"; +import PrevIcon from "@/pages/indicator/assets/prev.svg"; +import NextIcon from "@/pages/indicator/assets/next.svg"; + +interface DailyData { + text: string; + flag: string; +} + +interface CalendarData { + [key: string]: DailyData[]; +} + +const calendarData: CalendarData = { + "2025-09-01": [{ text: "무역수지", flag: "🇬🇧" }], + "2025-09-02": [{ text: "무역수지", flag: "🇬🇧" }], + "2025-09-11": [ + { text: "무역수지", flag: "🇬🇧" }, + { text: "생산자물가지수(PPI)", flag: "🇺🇸" }, + { text: "물가지수", flag: "🇺🇸" }, + { text: "소비자물가지수(CPI)", flag: "🇫🇷" }, + ], +}; + +const days = ["일", "월", "화", "수", "목", "금", "토"]; + +interface CalendarProps { + onDayClick?: (date: Date) => void; + highlightToday?: (date: Date) => boolean; +} + +const Calendar: React.FC = ({ onDayClick, highlightToday }) => { + const [currentDate, setCurrentDate] = useState(new Date()); + const today: Date = new Date(); + + const handlePrevMonth = () => + setCurrentDate( + (prev) => new Date(prev.getFullYear(), prev.getMonth() - 1, 1) + ); + + const handleNextMonth = () => + setCurrentDate( + (prev) => new Date(prev.getFullYear(), prev.getMonth() + 1, 1) + ); + + const year: number = currentDate.getFullYear(); + const month: number = currentDate.getMonth(); + + const getDaysInMonth = (year: number, month: number): number => + new Date(year, month + 1, 0).getDate(); + + const getFirstDayOfMonth = (year: number, month: number): number => + new Date(year, month, 1).getDay(); + + const daysInMonth: number = getDaysInMonth(year, month); + const startDay: number = getFirstDayOfMonth(year, month); + + const formatDate = (date: Date): string => { + const year: number = date.getFullYear(); + const month: string = (date.getMonth() + 1).toString().padStart(2, "0"); + const day: string = date.getDate().toString().padStart(2, "0"); + return `${year}-${month}-${day}`; + }; + + return ( +
+
+ {/* 헤더 영역 */} +
+ {/* 왼쪽: 화살표 두 개와 오늘 버튼 */} +
+ {/* 화살표 두 개 */} +
+ + +
+ + {/* 오늘 버튼 */} + +
+ + {/* 가운데: 달(month) 텍스트 */} +

+ {year}년 {month + 1}월 +

+ + {/* 오른쪽: 빈 공간 */} +
+
+ + {/* 달력 grid */} +
+ {/* 요일 헤더 */} + {days.map((day, i) => ( +
+ {day} +
+ ))} + + {/* 이번 달 앞부분 (지난 달 날짜 채우기) */} + {Array.from({ length: startDay }).map((_, i) => { + const prevDate = new Date(year, month, -startDay + i + 1); + const isLastInRow = (i + 1) % 7 === 0; + return ( +
+ {prevDate.getDate()} +
+ ); + })} + + {/* 이번 달 날짜 */} + {Array.from({ length: daysInMonth }, (_, i) => { + const date = new Date(year, month, i + 1); + const isSunday = (i + startDay) % 7 === 0; + const isToday = + date.getFullYear() === today.getFullYear() && + date.getMonth() === today.getMonth() && + date.getDate() === today.getDate(); + + const isTodayHighlighted = + typeof highlightToday === "function" + ? highlightToday(date) + : isToday; + + const dailyData = calendarData[formatDate(date)] || []; + const isLastInRow = (i + startDay + 1) % 7 === 0; + + return ( +
onDayClick?.(date)} + > +
+ + {i + 1} + + {dailyData.length > 0 && ( + + )} +
+ {dailyData.length > 0 && ( +
+ {dailyData.slice(0, 2).map((item, dataIndex) => ( +
+ {item.flag} + {item.text} +
+ ))} + {dailyData.length > 2 && ( +
+ +{dailyData.length - 2}개 더 +
+ )} +
+ )} +
+ ); + })} + + {/* 다음 달 날짜 채우기 */} + {Array.from({ + length: (7 - ((daysInMonth + startDay) % 7)) % 7, + }).map((_, i) => { + const nextDate = new Date(year, month + 1, i + 1); + const isLastInRow = (i + 1) % 7 === 0; + return ( +
+ {nextDate.getDate()} +
+ ); + })} +
+
+
+ ); +}; + +export default Calendar; diff --git a/src/router/AppRouter.tsx b/src/router/AppRouter.tsx index efe6cdb..03647b1 100644 --- a/src/router/AppRouter.tsx +++ b/src/router/AppRouter.tsx @@ -13,6 +13,9 @@ import AITradingPage from "@pages/ai-trade/aiTradingPage.tsx"; import SignupPage from "@pages/signup/SignupPage.tsx"; import PortfolioPage from "@/pages/portfolio/PortfolioPage"; import Account from "@pages/account/AccountPage.tsx"; +import EconomicPage from "@pages/indicator/economic/EconomicPage"; +import NewsPage from "@pages/indicator/news/NewsPage"; +import IndicatorPage from "@pages/indicator/IndicatorPage"; const AppRouter = () => { return ( @@ -38,6 +41,11 @@ const AppRouter = () => { } /> } /> + }> + } /> + } /> + } /> +