Skip to content

Commit

Permalink
[team-33 포키 & bangtae] 2주차 첫번째 pr보냅니다. (#145)
Browse files Browse the repository at this point in the history
* Feature/3 (#26)

* rename: gnb 폴더 생성하여 관련 컴포넌트 이동
   - styled -> customStyled 로 변경 적용
* refactor: gnb 컴포넌트 css 수정
* feat: main banner UI 구현
* refactor: gnb 컴포넌트 hover 및 cursor pointer 적용

* Feature/2 (#27)

* chore: mui 버전 통일

* feat: 글로벌 스타일 추가

* feat: SearchBar 컴포넌트 style 작성 및 이벤트 추가

* Feature/alias (#28)

* chore: alias 경로 설정을 위한 react-app-rewired 설치 및 설정파일 생성
* refactor: 절대경로 반영 (index, app, gnb, main-banner)
* fix: search input width 고정

* Feature/4 (#29)

* feat: calender page component 구현
* feat: 달력 월~일요일 부분 컴포넌트 구현
* feat: 해당 연-월에 맞는 날짜 영역 컴포넌트 구현
* feat: 이전, 다음 버튼 컴포넌트 및 클릭 기능 구현
* feat: calender 컴포넌트 구현
   - 보여줄 달력 개수를 정하는 page 옵션
   - curData 기반으로 page 만큼의 달력 렌더링
* chore: 브라우저 확인용 App 에 calender 반영
* feat: calender 관련 상태 context 사용하여 분리 및 provider 컴포넌트 생성
   - 불필요한 주석 제거
* refactor: 컴포넌트 이름 변경, DatesOfMonth 에서 DateBox 컴포넌트 분리
* feat: DateBox 컴포넌트 구현
   - 클릭 시 checkIn, checkOut 상태 변경
   - checkIn, checkOut 날짜에 따라 동적 css 적용
* chore: 오타 수정, app.js 에 provider 적용

* feat: header 컴포넌트 생성
- gnb, search-bar, calender를 header 하위 컴포넌트로 수정

* Feature/30 (#32)

* refactor: 캘린더 체크인/체크아웃 모드와 date box 체크 위치 상태를 나타내는 문자열을 상수화
* refactor: 컴포넌트 별 데이터 가공 유틸 함수를 컴포넌트 밖으로 분리
* refactor: Date box 내부에 있던 날짜 비교용 checkInTime, checkOutTime 을 콘텍스트 provider 로 이동
   - checkInDate, checkOutDate 변수명 변경 -> checkInInfo, checkOutInfo
   - checkIn, checkOut, current 변수명 변경 -> checkInTime, checkOutTime, currentTime

* refactor: 캘린더 month 빈배열 생성 시 0 -> Null 로 변경

* Feature/31 (#33)

* refactor: 코드 리뷰 반영
- visibility 속성 display로 변경
- bool 타입 결과값 함수 중복 검사 제거
- SearchMenu 컴포넌트 div 태그로 변경

* feat & refactor: SearchBar 컴포넌트 컨텍스트 추가
- props로 내려주던 상태 context로 관리 하도록 함

* feat : 검색바 반응형 컴포넌트로 수정

* refactor: isFocus를 상태 관리에서 제외
- currentInput의 상태를 통해 얻을 수 있도록 함

* feat&refactor: Header 컴포넌트 반응형으로 수정
- GNB, MainBanner, SearchBar 모두 적용

* feat: 체크인, 체크아웃 인풋 영역 클릭 시 캘린더 모달 팝업 기능 추가

* feat: Header 컴포넌트 fixed 속성 추가

* feat: 모달창 클릭시 검색바 blur가 적용되지 않게 함

* Feature/34 (#36)

* feat: 체크인-체크아웃 사이 날짜 1일과 마지막일 전후 음영 반영
   - DatesOfMonth 컴포넌트 last date 월이 안맞는 오류 수정
     : getDate() 는 현재달 인덱스에 date 0을 주면 이전달 마지막날 반환
* feat: 현재 날짜 이전 날짜 선택 불가 및 회색 표시

* feat: 검색바 체크인, 체크아웃 날짜 출력 기능 추가 (#38)

* feat: 검색바 체크인, 체크아웃 날짜 출력 기능 추가
- 캘린더에서 선택한 날짜를 출력하도록 함

* Feature/20 (#40)

* refactor: ResetButton 동적으로 추가하도록 수정
- input요소의 value 유무에 따라 추가, 삭제

* feat: ResetButton 클릭 이벤트 추가
- 버튼 클릭시 input value 초기화
- 검색바가 포커스되어 있을 때만 버튼이 노출되도록 수정

* feat: 검색바 캘린더 체크인 체크아웃 상태 연동 (#41)

* fix: 포커스 이벤트 에러 수정
- ResetButton 포커스 시에만 노출되도록 수정
- 검색바 포커스 시 세로로 늘어나는 오류 수정

* fix: 캘린더 날짜 선택 오류 수정
- 체크아웃을 먼저 선택 후 체크인 선택 시 체크아웃보다 뒷날이어도 선택되는 오류 수정
- DateBox 컴포넌트 내 handle click 로직 수정

* feat: 캘린더 모달 선택 시 보여지는 달 업데이트
- 체크인 날짜 있는 경우 체크인 달로 시작
- 없는 경우 현재 달로 시작

* fix: 캘린더 토요일과 날짜 정렬

Co-authored-by: bangdler <90082464+bangdler@users.noreply.github.com>
Co-authored-by: bangdler <zbthz90@gmail.com>
  • Loading branch information
3 people committed May 31, 2022
1 parent fd418d3 commit 21c4ad7
Show file tree
Hide file tree
Showing 25 changed files with 703 additions and 158 deletions.
6 changes: 2 additions & 4 deletions airbnb-app/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,16 @@ import { CustomThemeProvider } from '@/custom-styled-component/CustomThemeProvid
import { ThemeProvider } from 'styled-components';
import { GlobalStyle } from '@/common/globalStyle';
import theme from '@/common/theme';
import GNB from '@component/gnb/GNB';
import SearchBar from '@component/search-bar/SearchBar';
import MainBanner from '@component/main-banner/MainBanner';
import Header from '@/component/header/Header';

function App() {
return (
<CustomThemeProvider theme={theme}>
<ThemeProvider theme={theme}>
<GlobalStyle />
<GNB />
<Header />
<MainBanner />
<SearchBar />
</ThemeProvider>
</CustomThemeProvider>
);
Expand Down
28 changes: 28 additions & 0 deletions airbnb-app/src/component/header/Header.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import customStyled from '@/custom-styled-component/customStyled';
import { CalenderDateProvider } from '@/component/header/calender/CalenderDateProvider';
import GNB from '@/component/header/gnb/GNB';
import SearchBar from '@/component/header/search-bar/SearchBar';
import { SearchBarProvider } from '@/component/header/search-bar/SearchBarProvider';

function Header() {
return (
<Container>
<GNB />
<SearchBarProvider>
<CalenderDateProvider>
<SearchBar />
</CalenderDateProvider>
</SearchBarProvider>
</Container>
);
}

const Container = customStyled.div`
box-sizing: border-box;
position: fixed;
width: 100%;
min-width: 900px;
padding: 0 30px;
`;

export default Header;
65 changes: 65 additions & 0 deletions airbnb-app/src/component/header/calender/Calender.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import styled from 'styled-components';
import { useContext } from 'react';
import { CalenderDateContext } from '@/component/header/calender/CalenderDateProvider';
import CalenderPage from '@/component/header/calender/CalenderPage';
import PrevButton from '@/component/header/calender/PrevButton';
import NextButton from '@/component/header/calender/NextButton';

function Calender({ page = 1 }) {
const { curDate } = useContext(CalenderDateContext);

const displayPageArray = getDisplayPageArray({ curDate, page });

return (
<StyledContainer
page={page}
onMouseDown={e => {
e.preventDefault();
}}
>
<PrevButton />
<NextButton />
<StyledCalenderPageWrapper page={page}>
{displayPageArray.map((date, idx) => (
<CalenderPage key={idx} date={date} />
))}
</StyledCalenderPageWrapper>
</StyledContainer>
);
}

function getDisplayPageArray({ curDate, page }) {
const displayPageArray = [curDate];
for (let i = 1; i < page; i++) {
const prevYear = displayPageArray[i - 1].year;
const prevMonth = displayPageArray[i - 1].month;
const newDate = prevMonth === 12 ? { year: prevYear + 1, month: 1 } : { year: prevYear, month: prevMonth + 1 };
displayPageArray.push(newDate);
}
return displayPageArray;
}

const StyledContainer = styled.div`
position: relative;
margin: 30px auto 0;
background-color: white;
border-radius: 40px;
box-shadow: 0 4px 10px rgba(51, 51, 51, 0.1), 0 0 4px rgba(51, 51, 51, 0.05);
${({ page }) =>
`width: ${page === 1 ? 370 : 828}px;
height: ${382 * Math.ceil(page / 2)}px;
padding: ${page === 1 ? `65px 44px` : `65px 88px`};
`}
`;

const StyledCalenderPageWrapper = styled.div`
display: grid;
${({ page }) =>
`grid-template-columns: ${page > 1 ? `repeat(2, 1fr)` : ``};
column-gap: ${page > 1 ? 20 : 0}px;
row-gap: ${page > 2 ? 40 : 0}px;
`}
justify-items: center;
`;

export default Calender;
68 changes: 68 additions & 0 deletions airbnb-app/src/component/header/calender/CalenderDateProvider.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { createContext, useEffect, useState } from 'react';

export const CalenderDateContext = createContext({});

export function CalenderDateProvider({ children }) {
const today = new Date();
const initialCurDateState = { year: today.getFullYear(), month: today.getMonth() + 1 };

const [curDate, setCurDate] = useState(initialCurDateState);
// 체크인 모드에서 클릭하면 체크인 날짜가 선택, 체크아웃 모드에서 클릭하면 체크아웃 날짜가 선택.
const [mode, setMode] = useState(null);
const [checkInInfo, setCheckInInfo] = useState(null);
const [checkOutInfo, setCheckOutInfo] = useState(null);

const [checkInTime, setCheckInTime] = useState(0);
const [checkOutTime, setCheckOutTime] = useState(0);

useEffect(() => {
const newCheckInTime =
checkInInfo === null ? 0 : new Date(`${checkInInfo.year}-${checkInInfo.month}-${checkInInfo.date}`).getTime();
setCheckInTime(newCheckInTime);
}, [checkInInfo]);

useEffect(() => {
const newCheckOutTime =
checkOutInfo === null ? 0 : new Date(`${checkOutInfo.year}-${checkOutInfo.month}-${checkOutInfo.date}`).getTime();
setCheckOutTime(newCheckOutTime);
}, [checkOutInfo]);

const checkInValue = checkInInfo ? `${checkInInfo.month}${checkInInfo.date}일` : '';
const checkOutValue = checkOutInfo ? `${checkOutInfo.month}${checkOutInfo.date}일` : '';

const resetInfos = () => {
setCheckInInfo(null);
setCheckOutInfo(null);
};

const resetCurDate = () => {
if (checkInInfo) {
setCurDate(checkInInfo);
} else {
setCurDate(initialCurDateState);
}
};

return (
<CalenderDateContext.Provider
value={{
curDate,
setCurDate,
mode,
setMode,
checkInInfo,
setCheckInInfo,
checkOutInfo,
setCheckOutInfo,
checkInTime,
checkOutTime,
checkInValue,
checkOutValue,
resetInfos,
resetCurDate,
}}
>
{children}
</CalenderDateContext.Provider>
);
}
29 changes: 29 additions & 0 deletions airbnb-app/src/component/header/calender/CalenderPage.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import Days from '@/component/header/calender/Days';
import DatesOfMonth from '@/component/header/calender/DatesOfMonth';
import styled from 'styled-components';

function CalenderPage({ date }) {
return (
<StyledContainer>
<StyledTitle>
{date.year}{date.month}
</StyledTitle>
<Days />
<DatesOfMonth date={date} />
</StyledContainer>
);
}

const StyledContainer = styled.div`
width: 336px;
`;

const StyledTitle = styled.h2`
text-align: center;
font-weight: 700;
font-size: 16px;
line-height: 23px;
margin-bottom: 24px;
`;

export default CalenderPage;
133 changes: 133 additions & 0 deletions airbnb-app/src/component/header/calender/DateBox.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import styled from 'styled-components';
import { useContext } from 'react';
import { CalenderDateContext } from '@/component/header/calender/CalenderDateProvider';
import { CALENDER_MODE, DATE_CHECK_STATE } from '@/constants/calenderText';
import { SearchBarContext } from '@component/header/search-bar/SearchBarProvider';

function DateBox({ year, month, date, lastDate, disabled }) {
const { setCheckInInfo, setCheckOutInfo, checkInTime, checkOutTime } = useContext(CalenderDateContext);
const { updateFocusState, currentInput } = useContext(SearchBarContext);

const currentTime = new Date(`${year}-${month}-${date}`).getTime();
const checkState = getCheckStateOfCurrent({ currentTime, checkInTime, checkOutTime });

function handleClick() {
// 검색바에서 체크인을 누른 경우 - 체크인을 바꾼다. 체크아웃 날짜와 비교
if (currentInput === CALENDER_MODE.CHECKIN) {
if (currentTime > checkOutTime) {
setCheckOutInfo(null);
}
setCheckInInfo({ year, month, date });
updateFocusState(CALENDER_MODE.CHECKOUT);
return;
// 검색바에서 체크아웃을 누른 경우 - 체크아웃을 바꾼다. 체크인 날짜와 비교
}
if (currentInput === CALENDER_MODE.CHECKOUT) {
if (checkInTime > currentTime) {
setCheckOutInfo(null);
setCheckInInfo({ year, month, date });
return;
}
if (!checkInTime) {
setCheckOutInfo({ year, month, date });
updateFocusState(CALENDER_MODE.CHECKIN);
return;
}
setCheckOutInfo({ year, month, date });
return;
}
}

return (
<StyledBackground checkState={checkState}>
{!date ? null : (
<StyledDate disabled={disabled} checkState={checkState} onClick={handleClick}>
{date}
</StyledDate>
)}
<StyledExpandBackground checkState={checkState} date={date} lastDate={lastDate} />
</StyledBackground>
);
}

function getCheckStateOfCurrent({ currentTime, checkInTime, checkOutTime }) {
if (currentTime === checkInTime) return DATE_CHECK_STATE.CHECKIN;
if (currentTime === checkOutTime) return DATE_CHECK_STATE.CHECKOUT;
if (checkInTime && checkOutTime && currentTime > checkInTime && currentTime < checkOutTime) {
return DATE_CHECK_STATE.BETWEEN;
}
return false;
}

const StyledBackground = styled.div`
position: relative;
${({ checkState }) => {
if (checkState === DATE_CHECK_STATE.CHECKIN) {
return `background: linear-gradient(90deg, #fff 50%, #F5F5F7 50%)`;
} else if (checkState === DATE_CHECK_STATE.CHECKOUT) {
return `background: linear-gradient(90deg, #F5F5F7 50%, #fff 50%)`;
} else if (checkState === DATE_CHECK_STATE.BETWEEN) {
return `background-color: #F5F5F7`;
}
}}
`;

const StyledExpandBackground = styled.div`
${({ checkState, date, lastDate }) => {
if (checkState === DATE_CHECK_STATE.BETWEEN && date === 1) {
return `
position: absolute;
top: 0;
left: -50px;
width: 50px;
height: 50px;
background: linear-gradient(270deg, #F5F5F7 30%, #fff);
`;
} else if (checkState === DATE_CHECK_STATE.BETWEEN && date === lastDate) {
return `
position: absolute;
top: 0;
right: -50px;
width: 50px;
height: 50px;
background: linear-gradient(90deg, #F5F5F7 30%, #fff);
`;
}
}}
`;

const StyledDate = styled.div`
display: flex;
align-items: center;
justify-content: center;
text-align: center;
width: 48px;
height: 48px;
border-radius: 24px;
font-weight: 400;
font-size: 17px;
line-height: 17px;
cursor: pointer;
border: 1px solid white;
&:hover {
border: 1px solid black;
}
${({ checkState }) => {
if (checkState === DATE_CHECK_STATE.CHECKIN || checkState === DATE_CHECK_STATE.CHECKOUT) {
return `background-color: black; color:white; font-weight:600;`;
}
if (checkState === DATE_CHECK_STATE.BETWEEN) {
return `border: 1px solid #F5F5F7;`;
}
}}
${({ disabled }) => {
if (disabled) {
return `
color: #BDBDBD;
pointer-events: none;
`;
}
}}
`;

export default DateBox;
47 changes: 47 additions & 0 deletions airbnb-app/src/component/header/calender/DatesOfMonth.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import styled from 'styled-components';
import DateBox from '@/component/header/calender/DateBox';

function DatesOfMonth({ date }) {
const year = date.year;
const month = date.month;
const firstDay = new Date(year, month - 1, 1).getDay();
const lastDate = new Date(year, month, 0).getDate();
const dateArray = getDateArray({ firstDay, lastDate });

return (
<StyledDatesWrapper>
{dateArray.map((date, idx) => {
if (isBeforeToday({ year, month, date })) {
return <DateBox key={idx} year={year} month={month} date={date} disabled={true} />;
}
return <DateBox key={idx} year={year} month={month} date={date} lastDate={lastDate} />;
})}
</StyledDatesWrapper>
);
}

function getDateArray({ firstDay, lastDate }) {
// 이전달 빈칸
const blanks = Array(firstDay).fill(null);
const dates = Array.from({ length: lastDate }, (_, idx) => idx + 1);

return [...blanks, ...dates];
}

function isBeforeToday({ year, month, date }) {
const today = new Date();
const todayYear = today.getFullYear();
const todayMonth = today.getMonth() + 1;
const todayDate = today.getDate();
if (todayYear > year) return true;
if (todayYear === year && todayMonth > month) return true;
if (todayYear === year && todayMonth === month && todayDate > date) return true;
return false;
}

const StyledDatesWrapper = styled.div`
display: grid;
grid-template-columns: repeat(7, 1fr);
`;

export default DatesOfMonth;
Loading

0 comments on commit 21c4ad7

Please sign in to comment.