diff --git a/package.json b/package.json
index 7d48988..e32988f 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
"format": "prettier --write --cache ."
},
"dependencies": {
+ "date-fns": "^2.30.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-jsx-a11y": "^6.7.1",
@@ -19,9 +20,9 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-query": "^3.39.3",
- "react-router-dom": "^6.14.0",
+ "react-router-dom": "^6.14.1",
"recoil": "^0.7.7",
- "styled-components": "^6.0.0",
+ "styled-components": "^6.0.1",
"vite-plugin-svgr": "^3.2.0",
"vite-tsconfig-paths": "^4.2.0"
},
diff --git a/src/components/hyein/.keep b/src/components/hyein/.keep
deleted file mode 100644
index e69de29..0000000
diff --git a/src/components/hyein/Calendar.tsx b/src/components/hyein/Calendar.tsx
new file mode 100644
index 0000000..cf62759
--- /dev/null
+++ b/src/components/hyein/Calendar.tsx
@@ -0,0 +1,29 @@
+import React, { useState } from "react";
+import CalendarHeader from "./CalendarHeader";
+import { format, subMonths, addMonths } from "date-fns";
+import Week from "./Week";
+import Days from "./Days";
+
+export default function Calendar() {
+ const [currentMonth, setCurrentMonth] = useState(new Date());
+ const [selectedDate, setSelectedDate] = useState(new Date());
+
+ function prevMonth() {
+ setCurrentMonth(subMonths(currentMonth, 1));
+ }
+ function nextMonth() {
+ setCurrentMonth(addMonths(currentMonth, 1));
+ }
+
+ function onClickDate(day) {
+ setSelectedDate(day);
+ }
+
+ return (
+
+
+
+
+
+ );
+}
diff --git a/src/components/hyein/CalendarHeader.tsx b/src/components/hyein/CalendarHeader.tsx
new file mode 100644
index 0000000..515ad71
--- /dev/null
+++ b/src/components/hyein/CalendarHeader.tsx
@@ -0,0 +1,48 @@
+import React from "react";
+import styled from "styled-components";
+import { format, add, subMonths } from "date-fns";
+
+interface CalendarHeaderProps {
+ currentMonth: Date;
+ prevMonth: Date;
+ nextMonth: Date;
+}
+
+export default function CalendarHeader({ currentMonth, prevMonth, nextMonth }: CalendarHeaderProps) {
+ return (
+
+ {"<"}
+
+ {format(currentMonth, "yyyy")}년 {format(currentMonth, "MM")}월
+
+ {">"}
+
+ );
+}
+
+const HeaderWrapper = styled.header`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-size: 1.1rem;
+ gap: 1.6rem;
+`;
+
+const YearMonthWrapper = styled.span`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-size: 1.1rem;
+`;
+
+const PrevMonthButton = styled.button`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+`;
+
+const NextMonthButton = styled.button`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+`;
diff --git a/src/components/hyein/Days.tsx b/src/components/hyein/Days.tsx
new file mode 100644
index 0000000..4d6fe89
--- /dev/null
+++ b/src/components/hyein/Days.tsx
@@ -0,0 +1,167 @@
+import React from "react";
+import styled from "styled-components";
+import {
+ parse,
+ format,
+ endOfMonth,
+ endOfWeek,
+ startOfMonth,
+ startOfWeek,
+ addDays,
+ isSameDay,
+ isSunday,
+} from "date-fns";
+
+import { SCHEDULE_DATA, COLOR_DATA } from "../../mocks/data";
+
+interface DaysProps {
+ currentMonth: Date;
+ selectedDate: Date;
+ // onClickDate: (date: Date) => void;
+}
+
+export default function Days({ currentMonth, selectedDate }: DaysProps) {
+ const monthStart = startOfMonth(currentMonth);
+ const monthEnd = endOfMonth(monthStart);
+ const startDate = startOfWeek(monthStart);
+ const endDate: Date = endOfWeek(monthEnd);
+ const scheduleData = SCHEDULE_DATA.map((item) => ({
+ ...item,
+ date: item.date.map((data) => parse(data, "yyyy.MM.dd", new Date())),
+ }));
+
+ const sortedScheduleData = scheduleData.sort((a, b) => a.time.localeCompare(b.time));
+
+ const rows: React.ReactNode[] = [];
+ let days: React.ReactNode[] = [];
+ let day: Date = startDate;
+ let formattedDate = "";
+
+ while (day <= endDate) {
+ for (let i = 0; i < 7; i++) {
+ formattedDate = format(day, "d");
+ const sunDay = isSunday(day);
+ const daySchedule = sortedScheduleData.filter((item) => item.date.some((date) => isSameDay(date, day)));
+
+ days.push(
+
+
+ {formattedDate}
+
+ {daySchedule.map((schedule) => (
+
+ {schedule.student} {schedule.time.slice(0, 5)}
+
+ ))}
+ ,
+ );
+ day = addDays(day, 1);
+ }
+ rows.push({days});
+ days = [];
+ }
+
+ return {rows};
+}
+
+const Wrapper = styled.section`
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-top: 5rem;
+ gap: 2rem;
+ flex-direction: column;
+`;
+
+const DaysWrapper = styled.article`
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 2rem;
+ width: 48rem;
+ cursor: pointer;
+`;
+
+interface DayProp {
+ $issunday: boolean;
+}
+
+const Day = styled.article`
+ display: flex;
+ align-items: center;
+ flex-direction: column;
+ height: 5rem;
+ width: 30rem;
+
+ ${({ $issunday }) => `
+ ${$issunday ? "color: #FCB3A6" : undefined}
+ `};
+`;
+
+interface DayTextProps {
+ $isnotvalid: boolean;
+ $issameday: boolean;
+}
+
+const DayText = styled.p`
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 1.2rem;
+ height: 1.2rem;
+
+ ${({ $isnotvalid, $issameday }) => `
+ ${$isnotvalid ? "color: #CED4DA" : ""}
+ ${$issameday ? "color: white; background-color: #0DA98E; border-radius: 50%; " : ""}
+ `};
+`;
+
+interface ScheduleWrapper {
+ $student: string;
+}
+
+const ScheduleWrapper = styled.p`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+ margin-top: 0.5rem;
+
+ padding: 0.2rem 0;
+
+ ${({ $student }) => {
+ switch ($student) {
+ case "지수":
+ return `
+ background-color: #FFD9F2
+ `;
+ break;
+
+ case "희정":
+ return `
+ background-color:#E3D2FA`;
+ break;
+
+ case "혜인":
+ return `
+ background-color:#D3F1C1`;
+ break;
+
+ case "성경":
+ return `
+ background-color: #CCF5ED
+ `;
+ break;
+
+ case "은빈":
+ return `
+ background-color:#EBDDD5 `;
+ break;
+
+ default:
+ return undefined;
+ }
+ }}
+`;
diff --git a/src/components/hyein/Week.tsx b/src/components/hyein/Week.tsx
new file mode 100644
index 0000000..a215c4f
--- /dev/null
+++ b/src/components/hyein/Week.tsx
@@ -0,0 +1,26 @@
+import React from "react";
+import styled from "styled-components";
+
+export default function Week() {
+ const DATE: string[] = ["일", "월", "화", "수", "목", "금", "토", "일"];
+
+ const dateList: JSX.Element[] = DATE.map((day, index) => {day});
+ return {dateList};
+}
+
+const WeekWrapper = styled.section`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-size: 1rem;
+ font-weight: 400;
+ margin-top: 1.8rem;
+`;
+
+const DayWrapper = styled.span`
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ height: auto;
+ width: 6rem;
+`;
diff --git a/src/mocks/.keep b/src/mocks/.keep
deleted file mode 100644
index e69de29..0000000
diff --git a/src/mocks/data.ts b/src/mocks/data.ts
new file mode 100644
index 0000000..8c236f8
--- /dev/null
+++ b/src/mocks/data.ts
@@ -0,0 +1,15 @@
+interface ScheduleData {
+ id: number;
+ student: string;
+ time: string;
+ date: string[];
+}
+[];
+
+export const SCHEDULE_DATA: ScheduleData[] = [
+ { id: 1, student: "지수", time: "13:00~14:00", date: ["2023.07.06", "2023.07.13", "2023.07.20", "2023.07.27"] },
+ { id: 2, student: "희정", time: "19:00~20:00", date: ["2023.07.06", "2023.07.16"] },
+ { id: 3, student: "혜인", time: "10:00~12:00", date: ["2023.07.06", "2023.07.16"] },
+ { id: 4, student: "은빈", time: "22:00~23:00", date: ["2023.07.03", "2023.07.27"] },
+ { id: 5, student: "성경", time: "21:00~22:30", date: ["2023.07.15"] },
+];
diff --git a/src/pages/Hyein.tsx b/src/pages/Hyein.tsx
index 4b97a8f..c00b324 100644
--- a/src/pages/Hyein.tsx
+++ b/src/pages/Hyein.tsx
@@ -1,3 +1,5 @@
+import Calendar from "../components/hyein/Calendar";
+
export default function Hyein() {
- return Hyein
;
+ return ;
}
diff --git a/yarn.lock b/yarn.lock
index 3c5a3f2..3705f88 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1047,7 +1047,7 @@
resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310"
integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==
-"@babel/runtime@^7.12.5", "@babel/runtime@^7.20.7", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4":
+"@babel/runtime@^7.12.5", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.5.tgz#8564dd588182ce0047d55d7a75e93921107b57ec"
integrity sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA==
@@ -1329,10 +1329,10 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
-"@remix-run/router@1.7.0":
- version "1.7.0"
- resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.7.0.tgz#550a8d5760b78efc5d60f62b5829b0f74c1fde81"
- integrity sha512-Eu1V3kz3mV0wUpVTiFHuaT8UD1gj/0VnoFHQYX35xlslQUpe8CuYoKFn9d4WZFHm3yDywz6ALZuGdnUPKrNeAw==
+"@remix-run/router@1.7.1":
+ version "1.7.1"
+ resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.7.1.tgz#fea7ac35ae4014637c130011f59428f618730498"
+ integrity sha512-bgVQM4ZJ2u2CM8k1ey70o1ePFXsEzYVZoWghh6WjM8p59jQ7HxzbHW4SbnWFG7V9ig9chLawQxDTZ3xzOF8MkQ==
"@rollup/pluginutils@^5.0.2":
version "5.0.2"
@@ -2011,6 +2011,13 @@ damerau-levenshtein@^1.0.8:
resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7"
integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==
+date-fns@^2.30.0:
+ version "2.30.0"
+ resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0"
+ integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==
+ dependencies:
+ "@babel/runtime" "^7.21.0"
+
debug@^3.2.7:
version "3.2.7"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
@@ -3491,20 +3498,20 @@ react-refresh@^0.14.0:
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e"
integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==
-react-router-dom@^6.14.0:
- version "6.14.0"
- resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.14.0.tgz#7ce6c3f73549e4d40216ba150253d3bf30812b33"
- integrity sha512-YEwlApKwzMMMbGbhh+Q7MsloTldcwMgHxUY/1g0uA62+B1hZo2jsybCWIDCL8zvIDB1FA0pBKY9chHbZHt+2dQ==
+react-router-dom@^6.14.1:
+ version "6.14.1"
+ resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.14.1.tgz#0ad7ba7abdf75baa61169d49f096f0494907a36f"
+ integrity sha512-ssF6M5UkQjHK70fgukCJyjlda0Dgono2QGwqGvuk7D+EDGHdacEN3Yke2LTMjkrpHuFwBfDFsEjGVXBDmL+bWw==
dependencies:
- "@remix-run/router" "1.7.0"
- react-router "6.14.0"
+ "@remix-run/router" "1.7.1"
+ react-router "6.14.1"
-react-router@6.14.0:
- version "6.14.0"
- resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.14.0.tgz#1c3e8e922d934d43a253fd862c72c82167c0a7f1"
- integrity sha512-OD+vkrcGbvlwkspUFDgMzsu1RXwdjNh83YgG/28lBnDzgslhCgxIqoExLlxsfTpIygp7fc+Hd3esloNwzkm2xA==
+react-router@6.14.1:
+ version "6.14.1"
+ resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.14.1.tgz#5e82bcdabf21add859dc04b1859f91066b3a5810"
+ integrity sha512-U4PfgvG55LdvbQjg5Y9QRWyVxIdO1LlpYT7x+tMAxd9/vmiPuJhIwdxZuIQLN/9e3O4KFDHYfR9gzGeYMasW8g==
dependencies:
- "@remix-run/router" "1.7.0"
+ "@remix-run/router" "1.7.1"
react@^18.2.0:
version "18.2.0"
@@ -3851,10 +3858,10 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
-styled-components@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-6.0.0.tgz#f42abb6bd8a9cfc21f16ddfe00513da939e054b6"
- integrity sha512-OPraU50BgQ+cqiXmO9JnJiDP8N7gTB7Pzx9Yk6M+koZuzOvFf+Fd8ff6Qp57OnE65KAYO058IIWj+RWng3Cmiw==
+styled-components@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-6.0.1.tgz#f4db3195e5e510ff3cd0909b1a7b103f4440cbbc"
+ integrity sha512-6VAlf5A9KZJOnX54becRCLnBFSfeqP+q3raTCdPDPFg4HOy7MNlnWFqAq3sHlQVDdZh5jcsDwK06vTU3NMO6yQ==
dependencies:
"@babel/cli" "^7.21.0"
"@babel/core" "^7.21.0"