-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
8 changed files
with
184 additions
and
4 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { getDaysInMonth } from 'date-fns'; | ||
import React, { useState } from 'react'; | ||
import { CALENDAR_LENGTH, DAY_OF_WEEK } from '../user/utill/constants'; | ||
|
||
interface CalendarData { | ||
weekCalendarList: number[][]; // 주별 날짜 리스트 | ||
currentDate: Date; // 현재 날짜 | ||
setCurrentDate: React.Dispatch<React.SetStateAction<Date>>; // 현재 날짜를 설정하는 함수 | ||
} | ||
|
||
// 이전 달의 날짜를 계산하는 함수 | ||
const getPreviousDays = (firstDayOfCurrentMonth: Date, totalPrevMonthDays: number): number[] => | ||
// 현재 월의 첫 번째 날의 요일을 기준으로 이전 달의 날짜를 배열로 반환 | ||
Array.from({ length: firstDayOfCurrentMonth.getDay() }, (_, index) => totalPrevMonthDays - firstDayOfCurrentMonth.getDay() + index + 1); | ||
// 현재 월의 날짜를 배열로 반환하는 함수 | ||
const getCurrentDays = (totalMonthDays: number): number[] => Array.from({ length: totalMonthDays }, (_, i) => i + 1); // 1부터 totalMonthDays까지의 배열 생성 | ||
// 다음 달의 날짜를 계산하는 함수 | ||
const getNextDays = (currentDayList: number[], prevDayList: number[]): number[] => { | ||
// 다음 달의 날짜 수를 계산하여 배열로 반환 | ||
const nextDayCount = CALENDAR_LENGTH - currentDayList.length - prevDayList.length; | ||
return Array.from({ length: Math.max(nextDayCount, 0) }, (_, index) => index + 1); | ||
}; | ||
|
||
const useCalendar = (): CalendarData => { | ||
const [currentDate, setCurrentDate] = useState<Date>(new Date()); // 현재 날짜를 상태로 관리 | ||
|
||
// 현재 월의 총 날짜 수를 가져옴 | ||
const totalMonthDays = getDaysInMonth(currentDate); | ||
|
||
// 이전 달의 마지막 날짜를 계산 | ||
const prevMonthLastDate = new Date(currentDate.getFullYear(), currentDate.getMonth(), 0); | ||
// 이전 달의 총 날짜 수를 가져옴 | ||
const totalPrevMonthDays = getDaysInMonth(prevMonthLastDate); | ||
|
||
// 현재 월의 첫 번째 날짜를 계산 | ||
const firstDayOfCurrentMonth = new Date(currentDate.getFullYear(), currentDate.getMonth(), 1); | ||
// 이전 달의 날짜 리스트 | ||
const prevDayList = getPreviousDays(firstDayOfCurrentMonth, totalPrevMonthDays); | ||
// 현재 월의 날짜 리스트 | ||
const currentDayList = getCurrentDays(totalMonthDays); | ||
// 다음 달의 날짜 리스트 | ||
const nextDayList = getNextDays(currentDayList, prevDayList); | ||
|
||
// 전체 날짜 리스트 (이전 / 현재 / 다음 달 날짜 포함) | ||
const currentCalendarList = [...prevDayList, ...currentDayList, ...nextDayList]; | ||
|
||
// 주별로 날짜 리스트를 분할 | ||
const weekCalendarList: number[][] = []; | ||
currentCalendarList.forEach((currDate, index) => { | ||
const chunkIndex = Math.floor(index / DAY_OF_WEEK); | ||
if (!weekCalendarList[chunkIndex]) { | ||
weekCalendarList[chunkIndex] = []; // 주 배열이 없으면 초기화 | ||
} | ||
weekCalendarList[chunkIndex].push(currDate); // 누적값 반환 | ||
}); | ||
|
||
// NOTE: 한 달이 5주 일 수도, 6주 일 수도 있을 때 5주인 경우 해당 달에 필요없는 다음 달의 날짜가 출력되기 때문에 (CALENDAR_LENGTH를 최대치인 42로 잡아서) 마지막 주의 첫 번째 숫자가 10이하의 날짜로 시작한다면 해당 배열을 삭제하도록 추가. | ||
// TODO: 추후 다른 방법이 있다면 변경 할 예정 | ||
if (weekCalendarList.length > 0) { | ||
const lastWeek = weekCalendarList[weekCalendarList.length - 1]; | ||
if (lastWeek[0] <= 10) { | ||
weekCalendarList.pop(); | ||
} | ||
} | ||
|
||
// 캘린더 정보를 반환 | ||
return { | ||
weekCalendarList, // 주별 날짜 리스트 | ||
currentDate, | ||
setCurrentDate, | ||
}; | ||
}; | ||
|
||
export default useCalendar; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import React, { useState } from 'react'; | ||
import Image from 'next/image'; | ||
import { subMonths } from 'date-fns'; | ||
import { Button } from '@/components/ui/button'; | ||
import { DropdownMenu, DropdownMenuContent, DropdownMenuRadioGroup, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'; | ||
import ARROW_BOTTOM_ICON from '../../../public/icon/arrow-bottom-icon.svg'; | ||
import ARROW_RIGHT_ICON from '../../../public/icon/arrow-right-icon.svg'; | ||
import ARROW_LEFT_ICON from '../../../public/icon/arrow-left-icon.svg'; | ||
import useCalendar from '../../hooks/useCalendar'; | ||
import { DAY_LIST, DATE_MONTH_FIXER, DEFAULT_TRASH_VALUE } from '../utill/constants'; | ||
|
||
export default function Calendar() { | ||
const [position, setPosition] = useState<string>('bottom'); | ||
const { weekCalendarList, currentDate, setCurrentDate } = useCalendar(); | ||
|
||
// 이전 달 클릭 | ||
const handlePrevMonth = () => setCurrentDate((prevDate) => subMonths(prevDate, DATE_MONTH_FIXER)); | ||
// 다음 달 클릭 | ||
const handleNextMonth = () => setCurrentDate((prevDate) => subMonths(prevDate, -DATE_MONTH_FIXER)); | ||
|
||
return ( | ||
<div className='flex flex-col w-full lg:max-w-[640px] md:max-w-[640px] mt-[160px] space-y-0 md:mb-10 mb-5 gap-[48px]'> | ||
{/* 캘린더 헤더 */} | ||
<div className='w-full flex justify-between items-center'> | ||
<div className='flex w-full h-[52px] justify-between items-center'> | ||
<div className='text-neutral-700 text-2xl font-semibold leading-loose'>{`${currentDate.getFullYear()}년 ${currentDate.getMonth() + 1}월`}</div> | ||
<DropdownMenu> | ||
<DropdownMenuTrigger asChild> | ||
<Button variant='outline' className='flex items-center gap-1 bg-slate-100 rounded-[14px] text-center text-stone-300 text-xl'> | ||
필터: 감동 | ||
<div className='w-9 h-9 relative'> | ||
<Image src={ARROW_BOTTOM_ICON} alt='필터 선택' width={36} height={36} /> | ||
</div> | ||
</Button> | ||
</DropdownMenuTrigger> | ||
<DropdownMenuContent className='bg-white'> | ||
<DropdownMenuSeparator /> | ||
<DropdownMenuRadioGroup value={position} onValueChange={setPosition} className='flex flex-row'> | ||
<DropdownMenuItem>EmotionSelector 추가 예정</DropdownMenuItem> | ||
</DropdownMenuRadioGroup> | ||
</DropdownMenuContent> | ||
</DropdownMenu> | ||
</div> | ||
<div className='flex gap-6'> | ||
<Button variant='default' className='p-0' onClick={handlePrevMonth}> | ||
<Image src={ARROW_LEFT_ICON} alt='이전' width={36} height={36} /> | ||
</Button> | ||
<Button variant='default' className='p-0' onClick={handleNextMonth}> | ||
<Image src={ARROW_RIGHT_ICON} alt='다음' width={36} height={36} /> | ||
</Button> | ||
</div> | ||
</div> | ||
{/* 캘린더 */} | ||
<div> | ||
<div className='flex'> | ||
{DAY_LIST.map((day) => ( | ||
<div key={day} className='w-[91px] h-[91px] px-[15px] py-[9px] border-b border-gray-100 text-stone-300 font-semibold flex items-center justify-center'> | ||
{day} | ||
</div> | ||
))} | ||
</div> | ||
{weekCalendarList.map((week, weekIndex) => ( | ||
// eslint-disable-next-line react/no-array-index-key | ||
<div key={weekIndex} className='flex'> | ||
{week.map((day, dayIndex) => ( | ||
// eslint-disable-next-line react/no-array-index-key | ||
<div key={dayIndex} className='w-[91px] h-[91px] px-[15px] py-[9px] border-b border-gray-100 text-stone-300 font-semibold flex items-center justify-center'> | ||
{day === DEFAULT_TRASH_VALUE ? '' : day} | ||
</div> | ||
))} | ||
</div> | ||
))} | ||
</div> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,11 @@ | ||
export const MAX_FILE_SIZE = 1024 * 1024 * 5; // 5MB | ||
export const ACCEPTED_IMAGE_TYPES = ['image/jpeg', 'image/jpg', 'image/png']; | ||
export const sampleImage = '/ProfileTestImage.jpg'; | ||
// 파일 업로드 관련 | ||
export const MAX_FILE_SIZE = 1024 * 1024 * 5; // 파일 업로드 최대 용량 5MB | ||
export const ACCEPTED_IMAGE_TYPES = ['image/jpeg', 'image/jpg', 'image/png']; // 허용 가능 확장자 | ||
export const sampleImage = '/ProfileTestImage.jpg'; // 초기프로필 이미지 | ||
|
||
// 캘린더 관련 상수 | ||
export const DAY_LIST = ['일', '월', '화', '수', '목', '금', '토']; // 요일 | ||
export const DATE_MONTH_FIXER = 1; // 날짜 조정 상수 (현재 사용되지 않음, 필요에 따라 활용 가능) | ||
export const CALENDAR_LENGTH = 42; // 6주에 맞추어 캘린더의 총 길이를 42로 설정 | ||
export const DAY_OF_WEEK = 7; // 한 주의 날 수 (일~토) | ||
export const DEFAULT_TRASH_VALUE = -1; // 기본값 설정 (필요에 따라 사용 가능) |