Skip to content

Commit

Permalink
[FE] 날짜 선택 기능 추가 (#47)
Browse files Browse the repository at this point in the history
* style: 날짜에 hover 스타일 추가

Dae-Hwa/airbnb/#19

* refactor: Day 컴포넌트 분리

- 분리하면서 null인 날짜는 <Blink />를 반환하도록 변경
- 그래서 hover를 막을 수 있었다.

Dae-Hwa/airbnb/#19

* feat: 캘린더 날짜 선택 기능을 위한 상태 세팅 중

- Day.tsx에서 계속 useContext로 상태를 못받아서 디버깅해본 결과,
CalendarContext라는 이름의 컨텍스트가 CalendarModal에도 중복으로 있어서 덮어씌워짐을 확인했다.
- 그래서 일단 SearchBar에는 CalendarContextRaccoon이라고 이름 지어놓음..
- 콘솔에 warning 뜨는 것도 없애기 위해 테이블 관련 태그도 모두 div로 바꿈

Dae-Hwa/airbnb/#19

* refactor: 캘린더와 관련된 상태를 SearchBar에서 모두 provide

- 기존에 SearchBar와 CalendarModal 두 군데로 쪼개져 있던 CalendarContext를 하나로 합침
- 사용하지 않는 import 제거

Dae-Hwa/airbnb/#19

* feat: 날짜 클릭 이벤트 및 로직 추가

Dae-Hwa/airbnb/#19

* feat: 선택된 날짜 styling

- month 넘어갈 때 gradient, 체크인 체크아웃 날짜에 회색 박스 이어지게 하는 것 부족하지만
일단 이렇게만 해놓고 넘어가기로..

Dae-Hwa/airbnb/#19

* feat: 캘린더 과거 날짜 disabled 처리

Dae-Hwa/airbnb/#19
  • Loading branch information
deprecated-hongbiii authored May 30, 2021
1 parent 29721bf commit e734380
Show file tree
Hide file tree
Showing 9 changed files with 206 additions and 75 deletions.
1 change: 0 additions & 1 deletion FE/fe-airbnb/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import './App.css';
import Header from '@components/header/Header'
import SearchBar from '@components/searchBar/SearchBar';
import theme from './theme';
import CalendarModal from './components/calendar/CalendarModal';

function App() {
return (
Expand Down
30 changes: 7 additions & 23 deletions FE/fe-airbnb/src/components/calendar/Calendar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import styled from 'styled-components';
import CalendarHeader from './CalendarHeader';
import DayNames from './DayNames';
import getCalendarMatrix from './build';
import Day from './Day';

const Calendar = ({ calendar }) => {
const [calendarMatrix, setCalendarMatrix] = useState([]);
Expand All @@ -18,44 +19,27 @@ const Calendar = ({ calendar }) => {
<DayNames />
{calendarMatrix.map((week, i) => (
<Week key={i}>
{week.map((day, i) =>
day ? (
<Day key={day.format('YYYY-MM-DD')}>
{day && day.format('D').toString()}
</Day>
) : (
<Day key={i}></Day>
)
)}
{week.map((day, i) => (
<Day key={day ? day.format('YYYY-MM-DD') : i} day={day} />
))}
</Week>
))}
</CalendarBody>
</CalendarContainer>
);
};

const CalendarContainer = styled.table``;
const CalendarContainer = styled.div``;

const CalendarBody = styled.tbody`
const CalendarBody = styled.div`
display: flex;
flex-direction: column;
flex-wrap: wrap;
gap: 4px 0px;
`;

const Week = styled.tr`
display: flex;
`;

const Day = styled.td`
const Week = styled.div`
display: flex;
align-items: center;
justify-content: center;
width: 48px;
height: 48px;
font-weight: bold;
font-size: ${({ theme }) => theme.fontSizes.XS};
`;

export default Calendar;
2 changes: 1 addition & 1 deletion FE/fe-airbnb/src/components/calendar/CalendarHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const CalendarHeader = ({ calendar }) => {
);
};

const Title = styled.caption`
const Title = styled.div`
width: 336px;
display: flex;
justify-content: center;
Expand Down
2 changes: 1 addition & 1 deletion FE/fe-airbnb/src/components/calendar/CalendarList.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useContext } from 'react';
import styled from 'styled-components';
import Calendar from './Calendar';
import { CalendarContext } from './CalendarModal';
import { CalendarContext } from '@components/searchBar/SearchBar';

const CalendarList = ({ x, onTransitionEnd, leftSlide, rightSlide }) => {
const { calendars } = useContext(CalendarContext);
Expand Down
64 changes: 22 additions & 42 deletions FE/fe-airbnb/src/components/calendar/CalendarModal.jsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,16 @@
import { useState, createContext, useEffect } from 'react';
import moment from 'moment';
import { useState, useContext } from 'react';
import styled from 'styled-components';
import { Flex, Spacer } from '@chakra-ui/layout';
import { ReactComponent as LeftArrowIcon } from '../../icon/chevron-left.svg';
import { ReactComponent as RightArrowIcon } from '../../icon/chevron-right.svg';
import CalendarList from './CalendarList';

export const CalendarContext = createContext();
import { CalendarContext } from '@components/searchBar/SearchBar';

const CalendarModal = (props) => {
const initialCalendars = [
moment().add(-1, 'M'),
moment(),
moment().add(1, 'M'),
moment().add(2, 'M'),
];
const { calendars, setCalendars } = useContext(CalendarContext);

const gap = 68;
const calendarWidth = 336;
const [calendars, setCalendars] = useState(initialCalendars);

const calendarState = {
values: {
calendars,
setCalendars,
},
};

const [x, setX] = useState(-(calendarWidth + gap));
const [leftSlide, setLeftSlide] = useState(false);
Expand All @@ -34,17 +19,14 @@ const CalendarModal = (props) => {
const handleClickLeft = () => {
setLeftSlide(true);
setX(x + 336 + gap);
console.log('왼쪽 클릭');
};

const handleClickRight = () => {
setRightSlide(true);
setX(x - 336 - gap);
console.log('오른쪽 클릭');
};

const handleTransitionEnd = () => {
console.log('트랜지션 끝');
if (leftSlide) {
setLeftSlide(false);
setX(x - 336 - gap);
Expand All @@ -58,28 +40,26 @@ const CalendarModal = (props) => {
};

return (
<CalendarContext.Provider value={calendarState.values}>
<CalendarModalContainer>
<ViewArea>
<CalendarList
x={x}
onTransitionEnd={handleTransitionEnd}
leftSlide={leftSlide}
rightSlide={rightSlide}
/>
</ViewArea>
<CalendarModalContainer>
<ViewArea>
<CalendarList
x={x}
onTransitionEnd={handleTransitionEnd}
leftSlide={leftSlide}
rightSlide={rightSlide}
/>
</ViewArea>

<Flex justify="center">
<Controller>
<Flex>
<LeftArrowIcon onClick={handleClickLeft} />
<Spacer />
<RightArrowIcon onClick={handleClickRight} />
</Flex>
</Controller>
</Flex>
</CalendarModalContainer>
</CalendarContext.Provider>
<Flex justify="center">
<Controller>
<Flex>
<LeftArrowIcon onClick={handleClickLeft} />
<Spacer />
<RightArrowIcon onClick={handleClickRight} />
</Flex>
</Controller>
</Flex>
</CalendarModalContainer>
);
};

Expand Down
118 changes: 118 additions & 0 deletions FE/fe-airbnb/src/components/calendar/Day.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { ReactElement, useContext } from 'react';

import styled from 'styled-components'
import moment, { Moment } from 'moment';

import { CalendarContext } from '@components/searchBar/SearchBar'
import { CalendarContextType } from '@components/searchBar/SearchBar'
import { DayContainerProps } from '@components/searchBar/searchBarTypes';

type DayProps = {
day: Moment;
handleClickDate: () => void
}

function useCalendarState(): CalendarContextType {
const state = useContext(CalendarContext);
if(!state) throw new Error('에러발생~! state가 없습니다.🙅🏻');
return state;
}

function Day({ day }: DayProps): ReactElement {
const {
checkInMoment,
setCheckInMoment,
checkOutMoment,
setCheckOutMoment
} = useCalendarState();

const isSelected = () => {
if(day.isSame(checkInMoment) || day.isSame(checkOutMoment)) return true;
return false;
}

const isBetween = () => {
return (day.isBetween(checkInMoment, checkOutMoment))
}

const isBefore = () => {
if(day.isSame(moment().startOf('day'))) return false;
else return day.isBefore(moment());
}

const handleClickDate = (): void => {
if(!checkInMoment && !checkOutMoment) {
setCheckInMoment(day);
}

if(checkInMoment && !checkOutMoment) {
if(day.isSame(checkInMoment)) {
setCheckOutMoment(day);
}
if(day.isBefore(checkInMoment)) {
setCheckInMoment(day);
}
if(day.isAfter(checkInMoment)) {
setCheckOutMoment(day);
}
}

if(checkInMoment && checkOutMoment) {
if(day.isSame(checkInMoment)) {
setCheckOutMoment(day);
}
if(day.isBefore(checkInMoment)) {
setCheckInMoment(day);
setCheckOutMoment(null);
}
if(day.isAfter(checkInMoment)) {
setCheckOutMoment(day)
}
}
};

return (
<>
{day !== null
? <DayContainer disabled={isBefore()} onClick={handleClickDate} isSelected={isSelected()} isBetween={isBetween()}>
{day && day.format('D').toString()}
</DayContainer>
: <Blank />}
</>
)
}

const DayContainer = styled.button<DayContainerProps>`
display: flex;
align-items: center;
justify-content: center;
width: 48px;
height: 48px;
font-weight: bold;
font-size: ${({ theme }) => theme.fontSizes.XS};
background-color: ${({ theme, isSelected, isBetween }) => isSelected ? theme.colors.gray1 : isBetween ? theme.colors.gray6 : 'transparent'};
color: ${({ theme, isSelected }) => isSelected ? theme.colors.white : theme.colors.gray1};
border-radius: ${({ theme, isBetween }) => isBetween ? 0 : theme.borders.M};
&:disabled:hover {
cursor: default;
border: none;
}
&:hover {
border: 1px solid ${({ theme }) => theme.colors.black};
border-radius: ${({ theme }) => theme.borders.M};
cursor: pointer;
}
&:disabled {
color: ${({theme}) => theme.colors.gray4};
}
`

const Blank = styled.div`
width: 48px;
height: 48px;
`

export default Day
6 changes: 3 additions & 3 deletions FE/fe-airbnb/src/components/calendar/DayNames.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ import { dayNames } from '../../constant';

const DayNames = (props) => {
return (
<ul>
<div>
<Flex>
{dayNames.map((dayName, i) => (
<DayName key={i}>{dayName}</DayName>
))}
</Flex>
</ul>
</div>
);
};

const DayName = styled.th`
const DayName = styled.div`
color: ${({ theme }) => theme.colors.gray3};
font-size: ${({ theme }) => theme.fontSizes.XS};
width: 48px;
Expand Down
Loading

0 comments on commit e734380

Please sign in to comment.