๋ชฉ์ฐจ
- 1) ๋ฆฌ์กํธ ์บ๋ฆฐ๋ ์ค์น (install)
- 2) ๋ฆฌ์กํธ ์บ๋ฆฐ๋ ์ฌ์ฉ (import)
- 3) ๋ ์ง ๊ฐ์ ธ์ค๊ธฐ (Date seleted)
- 4) ๋ ์ง ๋ง๊ธฐ (Date disabled)
- 5) ์๊ฐ ๊ฐ์ ธ์ค๊ธฐ (Time Selected)


์์ ๊ฐ์ด ๋ฆฌ์กํธ ์บ๋ฆฐ๋๋ฅผ ์ด์ฉํด์ ๋ ์ง๋ฅผ ๋ฐ์์ค๊ณ ์๊ฐ์ ๋ฐ์ ์ฌ ์ ์๋ค.
ํน์ ๋ ์ง๋ ๋นํ์ฑํ ์ํฌ ์ ์๋ ๊ธฐ๋ฅ๋ ์๋ค.
(์ฐ๋ฆฌ ๊ฐ์ ๊ฒฝ์ฐ์๋ ์์ฝ์ด ๊ฝ์ฐจ๊ฑฐ๋, ํด๋ฌด์ผ์ด๊ฑฐ๋ , ์ง๊ธ์ผ๋ก๋ถํฐ 3๊ฐ์ ๋ด ์ด์ธ์ ๊ฐ์ disabled ๋๋ค.)
1) ๋ฆฌ์กํธ ์บ๋ฆฐ๋ ์ค์น (install)
npm install react-calendar
2) ๋ฆฌ์กํธ ์บ๋ฆฐ๋ ์ฌ์ฉ (import)
import Calendar from 'react-calendar';
import "./Calendar.css";
react-calendar
์ css
import ์์ผ์ฃผ๊ธฐ
3) ๋ ์ง ๊ฐ์ ธ์ค๊ธฐ (Date seleted)
<Calendar onChange={handleDateChange} value={date} onClickDay={handleDateClick} locale="en-US" // ๋ฏธ๊ตญ ๋ก์ผ์ผ ์ค์ (์ผ์์ผ๋ถํฐ ์์) next2Label={null} prev2Label={null} tileDisabled={tileDisabled} tileClassName={getTileClass} formatDay={(locale, date) => moment(date).format('D')} formatShortWeekday={(locale, date) => ['์ผ', '์', 'ํ', '์', '๋ชฉ', '๊ธ', 'ํ '][date.getDay()] } formatMonthYear={(locale, date) => `${moment(date).format('YYYY๋
MMM')}` } />
Calendar ์ปดํฌ๋ํธ์ ์์ ๊ฐ์ด ๊ธฐ๋ณธ Props ์์ฑ๋ค์ ์ฃผ๋ฉด ๋๋๋ฐ
value
์ ํ๋ ๋ ์ง ๋๋ ๋ ์ง ๋ฐฐ์ด์ ์ค์ onChange
๋ ์ง๊ฐ ๋ณ๊ฒฝ๋ ๋ ์คํํ ํจ์onClickDay
ํน์ ๋ ์ง๋ฅผ ํด๋ฆญํ์ ๋ ์คํํ ํจ์
locale
๋ก์ผ์ผ ์ค์ (์: "ko-KR" ํ๋ฉด ํ๊ธ๋ก ํ์๋จ)
locale="en-US" // ๋ฏธ๊ตญ ๋ก์ผ์ผ ์ค์ (์ผ์์ผ๋ถํฐ ์์)
next2Label
๋ค์ 2๋ ์ด๋ ๋ฒํผ (๊ธฐ๋ณธ๊ฐ: ยป, null๋ก ์จ๊ธธ ์ ์์)prev2Label
์ด์ 2๋ ์ด๋ ๋ฒํผ (๊ธฐ๋ณธ๊ฐ: ยซ, null๋ก ์จ๊ธธ ์ ์์)
formatDay
,formatShortWeekday
,formatMonthYear
,formatYear
๋ฑ์ผ๋ก ์ปค์คํ ํฌ๋งท์ผ๋ก ํ์ํ ์ ์๋ค.
formatDay={(locale, date) => moment(date).format('D')} // date ๊ฐ์ฒด๋ฅผ moment.js ํํ๋ก ๋ฐ๊ฟใ
์ 1,2,3 (01,02 x ) ํํ๋ก ํ๊ธฐ formatShortWeekday={(locale, date) => ['์ผ', '์', 'ํ', '์', '๋ชฉ', '๊ธ', 'ํ '][date.getDay()] } // ์์ผ์ ํ๊ตญ์ด๋ก ํ์ formatMonthYear={(locale, date) => `${moment(date).format('YYYY๋
MMM')}` } // ์์ ํ๊ตญ์ด๋ก ํ์
tileDisabled
,tileClassName
,tileContent
์ผ๋ก ํน์ ๋ ์ง๋ฅผ ์คํ์ผ๋ง ํ ์ ์๋ค.
tileDisabled={tileDisabled} tileClassName={getTileClass} // ๋ ์ง ์คํ์ผ๋ง
์ด์ธ์๋
onClickMonth
ํน์ ์์ ํด๋ฆญํ์ ๋ ์คํํ ํจ์onClickYear
ํน์ ์ฐ๋๋ฅผ ํด๋ฆญํ์ ๋ ์คํํ ํจ์onActiveStartDateChange
ํ์ฌ ๋ณด์ด๋ ๋ ์ง๊ฐ ๋ณ๊ฒฝ๋ ๋ ์คํํ ํจ์minDate
์ ํํ ์ ์๋ ์ต์ ๋ ์งmaxDate
์ ํํ ์ ์๋ ์ต๋ ๋ ์งview
๋ชจ๋๋ฅผ ๋ณ๊ฒฝํ ์ ์๋ค.month
,year
,decade
,century
selectRange
๋ค์ค ๋ ์ง ์ ํ๋ ๊ฐ๋ฅselectRange={true}
4) ๋ ์ง ๋ง๊ธฐ (Date disabled)
๋ ์ง๋ฅผ ๋ง๋ ๋ฐฉ๋ฒ์ ๋๊ฐ์ง๊ฐ ์์๋๋ฐ
1. ํ๋๋ ์ค๋๋ก๋ถํฐ 3๊ฐ์ ๋ค์ ๋ ์ง๋ง ๋ณด์ฌ์ฃผ๊ฒ ํ๋ ๋ฐฉ์ โ tileDisabled
์์ฑ ์ฌ์ฉ

// ๋ ์ง ๋นํ์ฑํ const tileDisabled = ({ date }) => { const today = new Date(); const threeMonthsLater = new Date(); threeMonthsLater.setMonth(today.getMonth() + 3); // ์ง๊ธ๋ถํฐ 3๊ฐ์ ๋ค // ์ค๋๊ณผ 3๊ฐ์ ํ์ ๋ ์ง ์ฌ์ด์ ๋ ์ง๋ ๋นํ์ฑํ ํ์ง ์์ return date < today || date > threeMonthsLater; };
2. ์์ฝ์ด ๊ฝ์ฐฌ ๊ฒฝ์ฐ disabled ์ํค๋ ๊ฒฝ์ฐ โ tileClassName
์์ฑ ์ฌ์ฉ

tileClassName={getTileClass}
className ์ ์ถ๊ฐํด์ css ๋จน์ด๊ฒ ํด์ ์์ฝ์ด ๋งํ ๊ฒ ์ฒ๋ผ ํํํจ.

const getTileClass = ({ date }) => { const formattedDate = date.toLocaleDateString('en-CA'); // 'yyyy-mm-dd' ํ์์ผ๋ก ๋ณํ (๋ก์ปฌ ์๊ฐ ๊ธฐ์ค) // (... ๊ณ ์ ํด๋ฌด์ ๋ํ ์ฝ๋) // ์์ฝ ์ ๋ณด ํ์ธ const slot = dateTime2.find((slot) => slot.reservationSlotDate === formattedDate); // ํด๋น ๋ ์ง์ ์์ฝ ์ ๋ณด ์ฐพ๊ธฐ if (slot) { if (slot.slotStatusCount === slot.slotCount) { return 'reserved'; // ์์ฝ์ด ๋ชจ๋ ์ฐผ๋ค๋ฉด 'reserved' } } return ''; // ์์ฝ์ด ์ฐผ์ง ์๊ฑฐ๋ slot์ด ์์ผ๋ฉด ๋น ๋ฌธ์์ด ๋ฐํ };
5) ์๊ฐ ๊ฐ์ ธ์ค๊ธฐ (Time Selected)

1. ์์ฝ ๊ฐ๋ฅ (์๊ฐ ์ถ๋ ฅ)
{dateTime.map((slot) => ( !noSlotsMessage ? ( <div key={slot.reservationSlotKey}> <div className="user-reserve-date-time"> {timeSlots.map((timeSlot, index) => ( <button key={index} type="button" onClick={() => { handleSlotClick(index); // ์ฌ๋กฏ ์ ํ ๊ด๋ฆฌ handleSlotClick2(timeSlot.time); // ์ฌ๋กฏ ์๊ฐ ์ถ๋ ฅ handleSlotClick3(slot.reservationSlotKey); }} // ์๋ ์๊ฐ ๊ด๋ จ ์์ฑ์ ์ด์ ์์.. (์๊ฐ ๊ด๋ฆฌ๊น์ง ์์ฐ) //disabled={disabledTimes.includes(timeSlot.time)} // ๋นํ์ฑํ ์กฐ๊ฑด ์ถ๊ฐ //style={{ //backgroundColor: selectedSlot === index ? '#fd8517' : 'transparent', //color: selectedSlot === index ? 'white' : 'black', //</div></div> opacity: disabledTimes.includes(timeSlot.time) ? 0.5 : 1, // ๋นํ์ฑํ๋ ์ฌ๋กฏ์ ํฌ๋ช
๋ ์กฐ์ //}} > {timeSlot.time} {/* ์ฌ๋กฏ ์๊ฐ ํ์ */} </button> ))} </div> </div> ) : ( <div className='msg1'> ์์ฝ ๊ฐ๋ฅํ ์๊ฐ์ด ์์ต๋๋ค. <br /> ๋ค๋ฅธ ๋ ์ง๋ฅผ ์ ํํด์ฃผ์ธ์. </div> ) ))}
ํ์๋น ์์ฝ์ด ์ด๋ฏธ ๊ฑธ๋ ค์๋ ๊ฒฝ์ฐ ์์ฝ์ด ๋ถ๊ฐํ๋๋ก (1ํ์ = 1์์ฝ) ํ๋ ค๊ณ ํ๋ค.
ํ์ง๋ง, ํน์ ํ์์ ์ฌ๋ฌ ์์ฝ์ ๋ฐ๊ฒํ๊ณ ์์ฝ์ด ๋ชฐ๋ฆฌ๋ ๊ฒฝ์ฐ์๋ ๊ฐ๊ฒ์ฌ์ฅ๋์ด ์ฃผ๋ฌธ์ทจ์๋ก ์ ๋์ํ๋ ์ชฝ์ผ๋ก ๋ณ๊ฒฝํ๊ฒ๋์๋ค.
(์๊ฐ์ ๋ง๋ ๊ธฐ๋ฅ์ ๋บ์ง๋ง ์๋ฌดํผ ๊ตฌํ ํด๋ณธ ๊ฒฐ๊ณผ ์๊ฐ์ ๋ง์ ์๋ ์์)

2. ์์ฝ ๋ถ๊ฐ (์์ฝ ๋ถ๊ฐ ๋ฉ์ธ์ง ๋์)
onClickDay={handleDateClick}
const handleDateClick = (selectedDate) => { setDate(selectedDate); const isReserved = getTileClass({ date: selectedDate }) === 'reserved'; setNoSlotsMessage(isReserved); // 'reserved' ๋ ์ง๋ฅผ ํด๋ฆญํ๋ฉด ์์ฝ ๋ถ๊ฐ ๋ฉ์์ง ํ์ if (isReserved) { console.log('์์ฝ๋ถ๊ฐ'); } };
์บ๋ฆฐ๋ ์ปดํฌ๋ํธ์ Day Click ์ด๋ฒคํธ์ ํด๋น ํจ์๋ฅผ ๊ฑธ์ด์ค๋ค.