Skip to content

Commit

Permalink
(#58) Calendar Component 수정
Browse files Browse the repository at this point in the history
  • Loading branch information
JinJu committed Dec 4, 2023
1 parent 121e4f0 commit b093d07
Show file tree
Hide file tree
Showing 21 changed files with 412 additions and 284 deletions.
33 changes: 0 additions & 33 deletions src/core/components/Calendar/Calendar.stories.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { useState } from "react";
import dayjs from "dayjs";

import { Meta } from "@storybook/react";
import { PeriodDates } from "./types/CalendarCoimponentProps";
import DateSelectCalendar from "@/core/components/Calendar/DateSelectCalendar";

const meta = {
title: "core/Calendar/DateSelectCalendar",
component: DateSelectCalendar,
} satisfies Meta<typeof DateSelectCalendar>;

export default meta;

export const Default = () => {
const [ selectedDate, setSelectedDate ] = useState<string>("");
const [ periodDates, setPeriodDates ] = useState<PeriodDates>({
startDate: "",
endDate: "",
});

const onDateClick = (date: string, periodDates?: PeriodDates) => {
setSelectedDate(date);
setPeriodDates(periodDates!);
};

console.log(periodDates);
return (
<div className = {"w-[500px] border rounded-3xl py-6"}>
<DateSelectCalendar
selectedDate = {selectedDate}
currentMonth = {dayjs("2023-10-25")}
onDateClick = {onDateClick}
/>
</div>
);
};
119 changes: 119 additions & 0 deletions src/core/components/Calendar/DateSelectCalendar/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import clsx from "clsx";
import dayjs from "dayjs";
import { useState, useCallback } from "react";

import { CalendarWeekDayComponent } from "@/core/components/Calendar/subs/CalendarWeekdayComponent";
import { CalendarHeader } from "@/core/components/Calendar/subs/CalendarHeader";
import { CalendarDateDto } from "@/core/components/Calendar/types/CalendarDateDto";
import { CalendarComponentProps } from "./types/CalendarCoimponentProps";
import { useCalendar } from "@/core/components/Calendar/hooks/useCalendar";
import CalendarComponentDayText from "./subs/CalendarComponentDayText";
import CalendarComponentDaySubText from "./subs/CalendarComponentDaySubText";
import { PeriodDates } from "./types/CalendarCoimponentProps";

export interface UseDeateSelectCalendarResponse {
models: {
periodDateArray: string[];
},
operations: {
setCalendarPeriodDates: (periodDates: PeriodDates) => void;
}
}

export const useDateSelectCalendar = (): UseDeateSelectCalendarResponse => {
const [ periodDateArray, setPeriodDateArray ] = useState<string[]>([]);

const setCalendarPeriodDates = useCallback((periodDates: PeriodDates) => {
if(!periodDates.endDate || !periodDates.startDate) {
return;
}
const startDate: dayjs.Dayjs = dayjs(periodDates.startDate);
const endDate: dayjs.Dayjs = dayjs(periodDates.endDate);
const diffDate: number = endDate.diff(startDate, "day");
const newState: string[] = [];

for (let i = 0; i <= diffDate; i++) {
newState.push(startDate.add(i, "day").format("YYYY-MM-DD"));
}
setPeriodDateArray(newState);
}, [setPeriodDateArray]);
return {
models: {
periodDateArray,
},
operations: {
setCalendarPeriodDates,
},
};
};

const DateSelectCalendar = ({
selectedDate,
currentMonth = dayjs(),
disabledDates,
onDateClick,
}: CalendarComponentProps) => {
const { models: commonModels, operations: commonOperations } = useCalendar();
const { models, operations } = useDateSelectCalendar();
return (
<div className = {"flex flex-col h-full w-full"}>
<CalendarHeader
currentMonth = {currentMonth.locale("ko").format("YYYY. MM")}
onPreviousMonthClick = {commonOperations.onPreviousMonthClick}
onNextMonthClick = {commonOperations.onNextMonthClick}
/>
<CalendarWeekDayComponent />
<div className = {clsx("mt-4")}>
{
commonModels.calendarDates.map((calendarWeekDates: CalendarDateDto[], index: number) => {
return (
<div key = {index} className = {clsx("grid grid-cols-7")}>
{
calendarWeekDates.map((calendarDate: CalendarDateDto, index: number) => (
<div key = {index} className = {clsx("h-16")}>
<button
className = {"w-full h-full"}
disabled = {(!calendarDate.isThisMonth || disabledDates?.includes(calendarDate.dayjs.format("YYYY-MM-DD")))}
onClick = {(): void => {
const currentDate = calendarDate.dayjs.format("YYYY-MM-DD");
if (currentDate === selectedDate) {
return;
}
const prevDate: dayjs.Dayjs = dayjs(selectedDate);
const nowDate: dayjs.Dayjs = calendarDate.dayjs;
const isStartDate: boolean = !prevDate || prevDate <= nowDate;
const periodDates: PeriodDates = {
startDate: isStartDate ? prevDate.format("YYYY-MM-DD") : currentDate,
endDate: isStartDate ? currentDate : selectedDate,
};
operations.setCalendarPeriodDates(periodDates);
onDateClick(currentDate, periodDates);
return;
}}
>
<div className = {clsx("flex flex-col")}>
<CalendarComponentDayText
selectedDate = {selectedDate}
calendarDate = {calendarDate}
periodDateArray = {models.periodDateArray}
/>
<CalendarComponentDaySubText
selectedDate = {selectedDate}
calendarDate = {calendarDate}
periodDateArray = {models.periodDateArray}
/>
</div>
</button>
</div>
))
}
</div>
);
})
}
</div>
</div>
);
};

export default DateSelectCalendar;
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { cn } from "@/utilities/utils";
import { CalendarDateDto } from "@/core/components/Calendar/types/CalendarDateDto";

interface CalendarComponentDaySubTextProps {
selectedDate: string;
calendarDate: CalendarDateDto;
periodDateArray?: string[];
}

export default function CalendarComponentDaySubText({
selectedDate,
calendarDate,
periodDateArray,
}: CalendarComponentDaySubTextProps) {
const currentDate = calendarDate.dayjs.format("YYYY-MM-DD");
const isPeriod = periodDateArray && periodDateArray.length > 0;
const isStartDate = isPeriod && periodDateArray[0] === currentDate;
const isEndDate = isPeriod && periodDateArray[periodDateArray.length - 1] === currentDate;
const singleSelectedDate = !isPeriod && currentDate === selectedDate;
return (
<div
className = {cn("flex justify-center items-center text-sm font-light mt-1 z-10 whitespace-nowrap",
(isStartDate || isEndDate || singleSelectedDate) ? "text-[#007BC7]" : "text-black",
)}
>&nbsp;
{isStartDate ? "시작일" : isEndDate ? "종료일" : ""}
{!isPeriod && selectedDate === currentDate ? "시작일" : (calendarDate.isToday ? "오늘" : "")}&nbsp;
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { cn } from "@/utilities/utils";
import { CalendarDateDto } from "@/core/components/Calendar/types/CalendarDateDto";

interface CalendarComponentDayTextProps {
selectedDate: string;
calendarDate: CalendarDateDto;
periodDateArray?: string[];
}

export default function CalendarComponentDayText({
selectedDate,
calendarDate,
periodDateArray,
}: CalendarComponentDayTextProps) {
const currentDate = calendarDate.dayjs.format("YYYY-MM-DD");
const isPeriod = periodDateArray && periodDateArray.length > 0;
const isStartDate = isPeriod && periodDateArray[0] === currentDate;
const isEndDate = isPeriod && periodDateArray[periodDateArray.length - 1] === currentDate;
const singleSelectedDate = !isPeriod && currentDate === selectedDate;
return (
<div className = {cn("flex flex-col justify-between items-center")}>
<div
className = {cn("flex justify-center items-center h-8 leading-none text-xs",
{
"rounded-s-full w-full bg-[#206FE4] text-white": isStartDate,
"rounded-r-full w-full bg-[#206FE4] text-white": isEndDate,
"w-full bg-[#206FE4] text-white": periodDateArray?.includes(currentDate),
"rounded-full w-8 bg-[#206FE4] text-white": singleSelectedDate,
"bg-[#C9CCCF] text-white rounded-full w-8": calendarDate.isToday,
"text-[#C9CCCF]": !calendarDate.isThisMonth && !periodDateArray?.includes(currentDate) && !calendarDate.isToday!,
},
)}
>
{calendarDate.dayjs.date()}
</div>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import dayjs from "dayjs";

export interface PeriodDates {
startDate: string;
endDate: string;
}

export interface CalendarComponentProps {
selectedDate: string;
currentMonth?: dayjs.Dayjs;
disabledDates?: string[];
onDateClick: (date: string, periodDates?: PeriodDates) => void;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Meta } from "@storybook/react";

import ScheduleCalendar from "@/core/components/Calendar/ScheduleCalendar";

const meta = {
title: "core/Calendar/ScheduleCalendar",
component: ScheduleCalendar,
} satisfies Meta<typeof ScheduleCalendar>;

export default meta;

export const DefaultCalendar = () =>
<div className = {"w-screen"}>
<ScheduleCalendar
markedDates = {{
"2023-12-01": ["무료체험"],
"2023-12-02": [undefined],
"2023-12-03": [undefined],
"2023-12-04": [undefined],
"2023-12-05": [undefined],
"2023-12-06": [undefined],
"2023-12-07": [undefined],
"2023-12-08": [undefined],
"2023-12-09": [undefined],
"2023-12-10": [undefined],
"2023-12-11": [undefined],
"2023-12-15": ["정식 전환일"],
}}
/>
</div>
;
28 changes: 28 additions & 0 deletions src/core/components/Calendar/ScheduleCalendar/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useCalendar } from "@/core/components/Calendar/hooks/useCalendar";
import { CalendarWeekDayComponent } from "@/core/components/Calendar/subs/CalendarWeekdayComponent";
import { CalendarHeader } from "@/core/components/Calendar/subs/CalendarHeader";
import { CalendarDayComponent } from "@/core/components/Calendar/ScheduleCalendar/subs/ComponentDayComponent";
import { CalendarComponentProps } from "@/core/components/Calendar/ScheduleCalendar/types/CalendarComponentProps";

const ScheduleCalendar = ({
markedDates,
}: CalendarComponentProps) => {
const { models, operations } = useCalendar();

return (
<div className = {"flex flex-col h-full w-full"}>
<CalendarHeader
currentMonth = {models.selectedDayjs.locale("ko").format("YYYY. MM")}
onPreviousMonthClick = {operations.onPreviousMonthClick}
onNextMonthClick = {operations.onNextMonthClick}
/>
<CalendarWeekDayComponent />
<CalendarDayComponent
markedDates = {markedDates}
calendarDates = {models.calendarDates}
/>
</div>
);
};

export default ScheduleCalendar;
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import clsx from "clsx";

import { CalendarComponentProps } from "@/core/components/Calendar/ScheduleCalendar/types/CalendarComponentProps";
import { CalendarDateDto } from "@/core/components/Calendar/types/CalendarDateDto";
import Typography from "@/core/components/Typography";

interface CalendarDayComponentProps extends CalendarComponentProps {
calendarDates: CalendarDateDto[][];
}

export const CalendarDayComponent = ({
markedDates,
calendarDates,
}: CalendarDayComponentProps) => {
return(
<>
{ calendarDates.map((calendarWeekDates: CalendarDateDto[], index) => (
<div
key = {index}
className = {"grid grid-cols-7 min-w-full w-full h-28"}
>
{ calendarWeekDates.map((calendarDate: CalendarDateDto, index: number) =>
(
<div key = {index} className = "flex-v-stack items-center h-full text-center">
<div
className = {clsx("flex justify-center items-center h-8",
{
"w-8 rounded-full bg-gray-03": calendarDate.isToday,
"text-gray-03": !calendarDate.isThisMonth,
},
)}>
<Typography
theme = "body-01-bold"
text = {`${calendarDate.dayjs.date()}`}
className = "text-inherit"
/>
</div>
{
markedDates && Object.keys(markedDates).map(markedDate => (
markedDate === calendarDate.dayjs.format("YYYY-MM-DD") &&
<div className = "flex-v-stack gap-1 w-full pt-1" key = {markedDate}>
{markedDates?.[markedDate].map((markedDateValue, index) =>
(
(markedDateValue || markedDateValue === undefined) &&
<div key = {index} className = "bg-primary-00">
&nbsp;
<Typography theme = "body-02-bold" color = "primary-02" text = {markedDateValue === undefined ? "" : markedDateValue} />
&nbsp;
</div>
),
)}
</div>
))
}
</div>
),
)}
</div>
))}
</>
);
};
Loading

0 comments on commit b093d07

Please sign in to comment.