Skip to content

Commit

Permalink
Merge pull request #119 from devping-kr/THKV-122
Browse files Browse the repository at this point in the history
Feat[THKV-122]: DatepickerCalendar 컴포넌트 리디자인
  • Loading branch information
plla2 authored Jan 23, 2025
2 parents c0565d8 + 4e86ced commit f71c1a9
Show file tree
Hide file tree
Showing 12 changed files with 149 additions and 101 deletions.
81 changes: 81 additions & 0 deletions src/components/common/DatepickerCalendar/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
'use client';

import React, { useRef } from 'react';
import { ko } from 'date-fns/locale';
import DatePicker from 'react-datepicker';
import { getCurrentYearMonthNow } from '@/utils/calendar';
import { cn } from '@/utils/core';
import Button from '@/components/common/Button/Button';
import Icon from '@/components/common/Icon';
import { Subtitle2Black } from '@/components/common/Typography';
import CustomDatePickerHeader from '@/components/shared/Survey/CustomDatePickerHeader';
import 'react-datepicker/dist/react-datepicker.css';
import '@/styles/datepicker-custom.css';

interface Props {
isChangeable: boolean;
deadLine: Date | null;
setDeadLine: React.Dispatch<React.SetStateAction<Date | null>>;
}

const TWO_WEEK_DAYS = 14;
const { now: twoWeeksLater } = getCurrentYearMonthNow();
twoWeeksLater.setDate(twoWeeksLater.getDate() + TWO_WEEK_DAYS);
const { now } = getCurrentYearMonthNow();

const DatepickerCalendar = ({ isChangeable, deadLine, setDeadLine }: Props) => {
const deadLineDatePickerRef = useRef<DatePicker | null>(null);

const handleChangeDate = (date: Date | null) => {
if (date) {
setDeadLine!(date);
}
};

return (
<div className='w-[216px]'>
<DatePicker
disabled={!isChangeable}
ref={deadLineDatePickerRef}
className='disabled:bg-grey-100 disabled:text-grey-500'
selected={deadLine}
minDate={now}
onChange={handleChangeDate}
locale={ko}
shouldCloseOnSelect
dateFormat='yyyy-MM-dd'
calendarClassName='custom-calendar'
dayClassName={() => 'custom-day'}
enableTabLoop={false}
renderCustomHeader={CustomDatePickerHeader}
customInput={
<Button
variant='default'
width='full'
size='sm'
className='relative gap-1 rounded-lg bg-white-100 py-3 pl-4 pr-[46px]'
disabled={!isChangeable}
>
<Subtitle2Black
className={cn('flex-shrink-0', !isChangeable && 'text-grey-500')}
>
마감 일자
</Subtitle2Black>
<span className='flex-1 text-base font-medium'>
{deadLine!.toISOString().split('T')[0]}
</span>
<Icon
name='calendar'
width={20}
height={20}
color={!isChangeable ? 'grey500' : 'black'}
className='absolute right-[14px]'
/>
</Button>
}
/>
</div>
);
};

export default DatepickerCalendar;
4 changes: 2 additions & 2 deletions src/components/common/Icon/assets/ArrowNext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ const ArrowNext = ({
<svg
width={width}
height={height}
viewBox='0 0 24 24'
viewBox='0 0 20 20'
fill='none'
xmlns='http://www.w3.org/2000/svg'
{...props}
>
<path
d='M8.25 4.5L15.75 12L8.25 19.5'
d='M6.875 3.75L13.125 10L6.875 16.25'
stroke={color}
strokeWidth='1.5'
strokeLinecap='round'
Expand Down
13 changes: 7 additions & 6 deletions src/components/common/Icon/assets/ArrowPrev.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,17 @@ const ArrowPrev = ({
<svg
width={width}
height={height}
viewBox='0 0 24 24'
viewBox='0 0 20 20'
fill='none'
xmlns='http://www.w3.org/2000/svg'
{...props}
>
<path
fillRule='evenodd'
clipRule='evenodd'
d='M14.1364 6.2636C14.4879 6.61508 14.4879 7.18492 14.1364 7.5364L9.67279 12L14.1364 16.4636C14.4879 16.8151 14.4879 17.3849 14.1364 17.7364C13.7849 18.0879 13.2151 18.0879 12.8636 17.7364L7.7636 12.6364C7.41213 12.2849 7.41213 11.7151 7.7636 11.3636L12.8636 6.2636C13.2151 5.91213 13.7849 5.91213 14.1364 6.2636Z'
stroke='none'
fill={color}
d='M13.125 16.25L6.875 10L13.125 3.75'
stroke={color}
strokeWidth='1.5'
strokeLinecap='round'
strokeLinejoin='round'
/>
</svg>
);
Expand Down
4 changes: 2 additions & 2 deletions src/components/common/Icon/assets/Calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ const Calendar = ({
<svg
width={width}
height={height}
viewBox='0 0 24 24'
viewBox='0 0 20 20'
fill='none'
xmlns='http://www.w3.org/2000/svg'
{...props}
>
<path
d='M6.75 3V5.25M17.25 3V5.25M3 18.75V7.5C3 6.25736 4.00736 5.25 5.25 5.25H18.75C19.9926 5.25 21 6.25736 21 7.5V18.75M3 18.75C3 19.9926 4.00736 21 5.25 21H18.75C19.9926 21 21 19.9926 21 18.75M3 18.75V11.25C3 10.0074 4.00736 9 5.25 9H18.75C19.9926 9 21 10.0074 21 11.25V18.75M12 12.75H12.0075V12.7575H12V12.75ZM12 15H12.0075V15.0075H12V15ZM12 17.25H12.0075V17.2575H12V17.25ZM9.75 15H9.7575V15.0075H9.75V15ZM9.75 17.25H9.7575V17.2575H9.75V17.25ZM7.5 15H7.5075V15.0075H7.5V15ZM7.5 17.25H7.5075V17.2575H7.5V17.25ZM14.25 12.75H14.2575V12.7575H14.25V12.75ZM14.25 15H14.2575V15.0075H14.25V15ZM14.25 17.25H14.2575V17.2575H14.25V17.25ZM16.5 12.75H16.5075V12.7575H16.5V12.75ZM16.5 15H16.5075V15.0075H16.5V15Z'
d='M5.62433 2.49526V4.37026M14.3746 2.49414V4.36914M2.49805 15.618V6.24288C2.49805 5.2074 3.33755 4.36797 4.37313 4.36797H15.623C16.6585 4.36797 17.498 5.2074 17.498 6.24289V15.618M2.49805 15.618C2.49805 16.6535 3.33755 17.493 4.37313 17.493H15.623C16.6585 17.493 17.498 16.6535 17.498 15.618M2.49805 15.618V9.36829C2.49805 8.3328 3.33755 7.49337 4.37313 7.49337H15.623C16.6585 7.49337 17.498 8.3328 17.498 9.36829V15.618M11.873 10.6182H13.748M6.24802 12.4932H9.99802M9.9998 10.6182H10.0045V10.6229H9.9998V10.6182ZM9.9992 14.3684H10.0039V14.3731H9.9992V14.3684ZM8.1239 14.369H8.12859V14.3737H8.1239V14.369ZM6.24862 14.3684H6.2533V14.3731H6.24862V14.3684ZM11.8739 12.4963H11.8786V12.501H11.8739V12.4963ZM11.8745 14.369H11.8792V14.3737H11.8745V14.369ZM13.7498 12.4951H13.7545V12.4998H13.7498V12.4951Z'
stroke={color}
strokeWidth='1.5'
strokeLinecap='round'
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/Icon/assets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export const iconMap: Record<string, IconMapEntry> = {
plus: { type: 'stroke', file: Plus },
arrowUp: { type: 'fill', file: Arrowup },
arrowDown: { type: 'fill', file: ArrowDown },
arrowPrev: { type: 'fill', file: ArrowPrev },
arrowPrev: { type: 'stroke', file: ArrowPrev },
arrowNext: { type: 'stroke', file: ArrowNext },
arrowPrevBlock: { type: 'fill', file: ArrowPrevBlock },
arrowNextBlock: { type: 'fill', file: ArrowNextBlock },
Expand Down
5 changes: 5 additions & 0 deletions src/components/common/Typography/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ export const Body2Black = customTypography('span', {
color: 'black',
});

export const SubTitle1Black = customTypography('span', {
type: 'Subtitle1',
color: 'black',
});

export const Subtitle2Black = customTypography('span', {
type: 'Subtitle2',
color: 'black',
Expand Down
4 changes: 1 addition & 3 deletions src/components/feature/Survey/Create/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ import { surveyKeys } from '@/hooks/survey/queryKey';
import { usePostSurvey } from '@/hooks/survey/usePostSurvey';
import { usePostSurveyQrCode } from '@/hooks/survey/usePostSurveyQrCode';
import { useToastStore } from '@/stores/useToastStore';
import 'react-datepicker/dist/react-datepicker.css';
import '@/styles/datepicker-custom.css';

const TWO_WEEK_DAYS = 14;
const { now: twoWeeksLater } = getCurrentYearMonthNow();
Expand Down Expand Up @@ -96,7 +94,7 @@ const SurveyCreate = ({ id }: { id: string }) => {
accessHandler={submitSurvey}
/>
<SurveyControls
type='create'
isChangeable
surveyName={surveyName}
setSurveyName={setSurveyName}
deadLine={deadLine}
Expand Down
2 changes: 1 addition & 1 deletion src/components/feature/Survey/Edit/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ const SurveyEdit = ({ id }: Props) => {
accessHandler={submitSurvey}
/>
<SurveyControls
type='edit'
isChangeable
surveyName={editSurveyName!}
setEditSurveyName={setEditSurveyName}
deadLine={editDeadLine!}
Expand Down
61 changes: 8 additions & 53 deletions src/components/shared/Survey/Controls/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
import { useRef } from 'react';
import { ko } from 'date-fns/locale';
import DatePicker from 'react-datepicker';
import { getCurrentYearMonthNow } from '@/utils/calendar';
import Icon from '@/components/common/Icon';
import DatepickerCalendar from '@/components/common/DatepickerCalendar';
import { Input } from '@/components/common/Input';
import { Label } from '@/components/common/Typography';
import CustomDatePickerHeader from '@/components/shared/Survey/CustomDatePickerHeader';

interface Props {
type: 'create' | 'edit';
isChangeable: boolean;
surveyName: string;
setEditSurveyName?: React.Dispatch<React.SetStateAction<string>>;
setSurveyName?: React.Dispatch<React.SetStateAction<string>>;
Expand All @@ -19,23 +13,13 @@ interface Props {
const EXTRA_SURVEYNAME_LIMIT = 30;

const SurveyControls = ({
type,
isChangeable,
surveyName,
setEditSurveyName,
setSurveyName,
deadLine,
setDeadLine,
}: Props) => {
const { now } = getCurrentYearMonthNow();
const deadLineDatePickerRef = useRef<DatePicker | null>(null);
const isChangeable = type === 'create';

const handleChangeDate = (date: Date | null) => {
if (date) {
setDeadLine!(date);
}
};

const handleChangeSurveyName = (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.value.length <= EXTRA_SURVEYNAME_LIMIT && !isChangeable) {
setEditSurveyName!(e.target.value);
Expand All @@ -45,10 +29,6 @@ const SurveyControls = ({
}
};

const handleOpenDatePicker = () => {
deadLineDatePickerRef.current!.setFocus();
};

return (
<div className='flex gap-4'>
<div className='w-1/3'>
Expand All @@ -61,36 +41,11 @@ const SurveyControls = ({
height='basic'
/>
</div>
<div className='relative flex w-56 items-center gap-2'>
<Label>마감 일자</Label>
<DatePicker
ref={deadLineDatePickerRef}
className='flex w-28 cursor-pointer border-b border-green-400 bg-transparent pl-1 focus:outline-none disabled:cursor-not-allowed disabled:opacity-80'
shouldCloseOnSelect
dateFormat='yyyy-MM-dd'
selected={deadLine}
locale={ko}
minDate={now}
onChange={handleChangeDate}
calendarClassName='custom-calendar'
dayClassName={() => 'custom-day'}
placeholderText='마감날짜 선택'
renderCustomHeader={CustomDatePickerHeader}
/>
<button
onClick={handleOpenDatePicker}
disabled={!isChangeable}
className='disabled:cursor-not-allowed'
>
<Icon
name='calendar'
width={16}
height={16}
color='active'
className='absolute bottom-3 right-9'
/>
</button>
</div>
<DatepickerCalendar
isChangeable={isChangeable}
deadLine={deadLine}
setDeadLine={setDeadLine}
/>
</div>
);
};
Expand Down
30 changes: 12 additions & 18 deletions src/components/shared/Survey/CustomDatePickerHeader/index.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,30 @@
import Button from '@/components/common/Button/Button';
import Icon from '@/components/common/Icon';
import { SubTitle1Black } from '@/components/common/Typography';

interface Props {
date: Date | null;
decreaseMonth: () => void;
increaseMonth: () => void;
prevMonthButtonDisabled: boolean;
nextMonthButtonDisabled: boolean;
}

const CustomDatePickerHeader = ({
date,
decreaseMonth,
increaseMonth,
prevMonthButtonDisabled,
nextMonthButtonDisabled,
}: Props) => (
<div className='mb-2 flex items-center justify-between px-6 font-semibold'>
<button
onClick={decreaseMonth}
className={prevMonthButtonDisabled ? 'invisible' : 'block'}
disabled={prevMonthButtonDisabled}
>
<Icon name='arrowPrev' width={20} color='active' />
</button>
<div className='text-base font-bold'>
<div className='mb-3 flex items-center justify-between'>
<Button variant='default' onClick={decreaseMonth} className='p-0'>
<Icon name='arrowPrev' width={20} height={20} color='black' />
</Button>
<SubTitle1Black>
{date instanceof Date && !isNaN(date.getTime())
? `${date.getFullYear()}${date.toLocaleString('default', { month: 'long' })}`
? `${date.getFullYear()}${date.toLocaleString('ko-KR', { month: 'long' })}`
: '날짜 정보 없음'}
</div>
<button onClick={increaseMonth} disabled={nextMonthButtonDisabled}>
<Icon name='arrowNext' width={20} color='active' />
</button>
</SubTitle1Black>
<Button variant='default' onClick={increaseMonth} className='p-0'>
<Icon name='arrowNext' width={20} height={20} color='black' />
</Button>
</div>
);

Expand Down
Loading

0 comments on commit f71c1a9

Please sign in to comment.