-
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.
✨ feat: 회의 만들기 페이지 step2(회의 날짜 및 시간) UI 작성 (#47)
* feat: 회의실 만들기 step2 UI 틀 작성 * feat: 특정 날짜에 대한 요일 계산 함수 작성 * refactor: Input 컴포넌트의 interface 작성 * feat: DatePicker 컴포넌트 적용 * feat: Date Picker 컴포넌트의 Open, Close 액션 및 애니메이션 적용 * feat: 썸네일 state react-hook-form 적용 * feat: Date Picker & Time Picker 컴포넌트 hook 적용 * feat: 회의실 만들기 step2 UI 틀 작성 * feat: 특정 날짜에 대한 요일 계산 함수 작성 * refactor: Input 컴포넌트의 interface 작성 * feat: DatePicker 컴포넌트 적용 * feat: Date Picker 컴포넌트의 Open, Close 액션 및 애니메이션 적용 * feat: 썸네일 state react-hook-form 적용 * feat: Date Picker & Time Picker 컴포넌트 hook 적용 * fix: Date Picker type 에러 수정 * refactor: console.log 코드 제거 * refactor: eslint rule 주석 제거
- Loading branch information
1 parent
e074be6
commit fde345e
Showing
7 changed files
with
322 additions
and
62 deletions.
There are no files selected for viewing
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,2 @@ | ||
export * from './step1'; | ||
export * from './step2'; |
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,223 @@ | ||
/** @jsxImportSource @emotion/react */ | ||
import { Flex, Space } from '@/components/Wrapper'; | ||
import { DatePicker, Input, SvgIcon, TimePicker } from '@/components/common'; | ||
import { useDatePicker } from '@/hooks/useDatePicker'; | ||
import { useTimePicker } from '@/hooks/useTimePicker'; | ||
import { FormType } from '@/pages/createMeetingroom'; | ||
import { getDayOfWeek } from '@/utils/getDayOfWeek'; | ||
import { css } from '@emotion/react'; | ||
import styled from '@emotion/styled'; | ||
import { AnimatePresence, motion } from 'framer-motion'; | ||
import { useEffect } from 'react'; | ||
import { | ||
FieldErrors, | ||
UseFormRegister, | ||
UseFormSetValue, | ||
UseFormWatch | ||
} from 'react-hook-form'; | ||
|
||
interface Step2Props { | ||
register: UseFormRegister<FormType>; | ||
watch: UseFormWatch<FormType>; | ||
errors?: FieldErrors; | ||
setValue: UseFormSetValue<FormType>; | ||
} | ||
|
||
const pickerVariants = { | ||
invisible: { | ||
opacity: 0 | ||
}, | ||
visible: { | ||
opacity: 1 | ||
} | ||
}; | ||
|
||
export const Step2 = ({ register, watch, errors, setValue }: Step2Props) => { | ||
const { datePicker, setDate, openDatePicker, closeDatePicker } = | ||
useDatePicker(); | ||
const { | ||
timePicker: timePicker1, | ||
setTime: setTime1, | ||
openTimePicker: openTimePicker1, | ||
closeTimePicker: closeTimePicker1 | ||
} = useTimePicker(); | ||
const { | ||
timePicker: timePicker2, | ||
setTime: setTime2, | ||
openTimePicker: openTimePicker2, | ||
closeTimePicker: closeTimePicker2 | ||
} = useTimePicker(); | ||
|
||
useEffect(() => { | ||
const { year, month, date } = datePicker.date; | ||
setValue( | ||
'meetingRoomDate', | ||
`${month}월 ${date}일 ${getDayOfWeek(`${year}-${month}-${date}`)}요일` | ||
); | ||
}, [datePicker.date, setValue]); | ||
|
||
useEffect(() => { | ||
const { periodOfDay, hour, minute } = timePicker1.time; | ||
if (periodOfDay && hour && minute) { | ||
setValue('meetingRoomTime', `${periodOfDay} ${hour}시 ${minute}분`); | ||
} | ||
}, [timePicker1.time, setValue]); | ||
|
||
useEffect(() => { | ||
const { hour, minute } = timePicker2.time; | ||
if (hour && minute) { | ||
setValue('meetingRoomDuration', `${hour}시간 ${minute}분`); | ||
} | ||
}, [timePicker2.time, setValue]); | ||
return ( | ||
<Flex direction="column" align="flex-start"> | ||
<div | ||
css={css` | ||
width: 100%; | ||
`}> | ||
<StyledLabel> | ||
회의가 진행되는 날짜를 알려주세요 | ||
<SvgIcon id="star_orange" size={18} /> | ||
</StyledLabel> | ||
<div | ||
css={css` | ||
display: flex; | ||
gap: 1rem; | ||
`}> | ||
<Input | ||
{...register('meetingRoomDate', { | ||
required: '회의 날짜를 입력해주세요' | ||
})} | ||
value={watch('meetingRoomDate')} | ||
type="default" | ||
placeholder="0월 0일 00일" | ||
isError={errors?.meetingRoomDate ? true : false} | ||
errorText={errors?.meetingRoomDate?.message as string} | ||
readOnly | ||
onClick={() => { | ||
if (timePicker1.isOpen) { | ||
closeTimePicker1(); | ||
} | ||
if (timePicker2.isOpen) { | ||
closeTimePicker2(); | ||
} | ||
openDatePicker(); | ||
}} | ||
/> | ||
<Input | ||
{...register('meetingRoomTime', { | ||
required: '회의 시간을 입력해주세요' | ||
})} | ||
value={watch('meetingRoomTime')} | ||
type="default" | ||
placeholder="오후 00시 00분" | ||
isError={errors?.meetingRoomTime ? true : false} | ||
errorText={errors?.meetingRoomTime?.message as string} | ||
readOnly | ||
onClick={() => { | ||
if (datePicker.isOpen) { | ||
closeDatePicker(); | ||
} | ||
if (timePicker2.isOpen) { | ||
closeTimePicker2(); | ||
} | ||
openTimePicker1(); | ||
}} | ||
/> | ||
</div> | ||
|
||
<AnimatePresence> | ||
{datePicker.isOpen && ( | ||
<motion.div | ||
variants={pickerVariants} | ||
initial="invisible" | ||
animate="visible"> | ||
<DatePicker | ||
date={datePicker.date} | ||
setDate={setDate} | ||
onClose={closeDatePicker} | ||
/> | ||
<Space height={30} /> | ||
</motion.div> | ||
)} | ||
</AnimatePresence> | ||
|
||
<AnimatePresence> | ||
{timePicker1.isOpen && ( | ||
<motion.div | ||
variants={pickerVariants} | ||
initial="invisible" | ||
animate="visible"> | ||
<TimePicker | ||
type="time" | ||
setTime={setTime1} | ||
onClose={closeTimePicker1} | ||
/> | ||
<Space height={30} /> | ||
</motion.div> | ||
)} | ||
</AnimatePresence> | ||
|
||
<StyledLabel> | ||
회의 예상 소요시간을 알려주세요 | ||
<SvgIcon id="star_orange" size={18} /> | ||
</StyledLabel> | ||
<div | ||
css={css` | ||
display: flex; | ||
gap: 1rem; | ||
`}> | ||
<Input | ||
{...register('meetingRoomDuration', { | ||
required: '회의 예상 소요시간을 입력해주세요' | ||
})} | ||
value={watch('meetingRoomDuration')} | ||
type="default" | ||
placeholder="00시간 00분" | ||
isError={errors?.meetingRoomDuration ? true : false} | ||
errorText={errors?.meetingRoomDuration?.message as string} | ||
readOnly | ||
onClick={() => { | ||
if (datePicker.isOpen) { | ||
closeDatePicker(); | ||
} | ||
if (timePicker1.isOpen) { | ||
closeTimePicker1(); | ||
} | ||
openTimePicker2(); | ||
}} | ||
/> | ||
<div | ||
css={css` | ||
width: 100%; | ||
`} | ||
/> | ||
</div> | ||
|
||
<AnimatePresence> | ||
{timePicker2.isOpen && ( | ||
<motion.div | ||
variants={pickerVariants} | ||
initial="invisible" | ||
animate="visible"> | ||
<TimePicker | ||
type="duration" | ||
setTime={setTime2} | ||
onClose={closeTimePicker2} | ||
/> | ||
</motion.div> | ||
)} | ||
</AnimatePresence> | ||
</div> | ||
</Flex> | ||
); | ||
}; | ||
|
||
const StyledLabel = styled.label` | ||
${(props) => props.theme.typo.T5} | ||
color: ${(props) => props.theme.palette.dark_gray2}; | ||
display: flex; | ||
align-items: center; | ||
gap: 0.2rem; | ||
margin-bottom: 1rem; | ||
`; |
Oops, something went wrong.