Skip to content

Commit

Permalink
refactor: 메인페이지 리팩터링 (#659)
Browse files Browse the repository at this point in the history
* chore: 리액트 헬멧 라이브러리 제거 (#658)

* chore: 리액트 헬멧 라이브러리 제거 (#658)

* refactor: 셀럽잇 추천 맛집 섹션 분리 (#658)

* refactor: 배너 섹션 분리 (#658)

* refactor: 카테고리 섹션 분리 (#658)

* refactor: 셀럽 베스트 섹션 분리 (#658)

* refactor: 지역맛집 섹션 분리 (#658)

* refactor: 메인페이지 리팩터링 (#658)
  • Loading branch information
shackstack authored Dec 29, 2023
1 parent b6d6998 commit cf6eb1b
Show file tree
Hide file tree
Showing 12 changed files with 3,739 additions and 1,111 deletions.
1 change: 0 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
"celuveat-ui-library": "^1.2.8",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-helmet-async": "^1.3.0",
"react-router-dom": "^6.14.2",
"react-slick": "^0.29.0",
"slick-carousel": "^1.8.1",
Expand Down
202 changes: 12 additions & 190 deletions frontend/src/pages/MainPage.tsx
Original file line number Diff line number Diff line change
@@ -1,155 +1,27 @@
import { useQuery } from '@tanstack/react-query';
import { useNavigate } from 'react-router-dom';
import styled from 'styled-components';
import { Helmet } from 'react-helmet-async';
import { useEffect } from 'react';
import Slider from 'react-slick';
import ProfileImage from '~/components/@common/ProfileImage';
import CategoryNavbar from '~/components/CategoryNavbar';
import MiniRestaurantCard from '~/components/MiniRestaurantCard';
import RegionList from '~/components/RegionList';
import RESTAURANT_CATEGORY from '~/constants/restaurantCategory';
import { FONT_SIZE, hideScrollBar } from '~/styles/common';
import { RestaurantData } from '~/@types/api.types';
import { getRecommendedRestaurants } from '~/api/restaurant';
import useBottomNavBarState from '~/hooks/store/useBottomNavBarState';
import BannerSlider from './MainPage/BannerSlider';
import { CelebCarouselSettings, RestaurantCardCarouselSettings } from '~/constants/carouselSettings';
import useMediaQuery from '~/hooks/useMediaQuery';
import { celebOptions } from '~/constants/celeb';
import MiniRestaurantCardSkeleton from '~/components/MiniRestaurantCard/MiniRestaurantCardSkeleton';
import CeluveatRecommendSection from './MainPage/CeluveatRecommendSection/CeluveatRecommendSection';
import CelebBestSection from './MainPage/CelebBestSection/CelebBestSection';
import CategorySection from './MainPage/CategorySection/CategorySection';
import BannerSection from './MainPage/BannerSection/BannerSection';
import RegionSection from './MainPage/RegionSection/RegionSection';

function MainPage() {
const { isMobile } = useMediaQuery();
const navigate = useNavigate();
// const { data: celebOptions } = useQuery({
// queryKey: ['celebOptions'],
// queryFn: () => getCelebs(),
// suspense: true,
// });
const setHomeSelected = useBottomNavBarState(state => state.setHomeSelected);

useEffect(() => {
setHomeSelected();
}, []);

const { data: recommendedRestaurantData } = useQuery<RestaurantData[]>({
queryKey: ['recommendedRestaurants'],
queryFn: getRecommendedRestaurants,
});

const clickCelebIcon = (id: number) => {
navigate(`/celeb/${id}`);
};

const clickRestaurantCategory = (e: React.MouseEvent<HTMLElement>) => {
const currentCategory = e.currentTarget.dataset.label;

navigate(`/category/${currentCategory}`);
};

return (
<>
<Helmet>
<meta property="og:title" content="Celuveat" />
<meta property="og:url" content="celuveat.com" />
<meta name="image" property="og:image" content="https://www.celuveat.com/og-image.jpeg" />
<meta name="description" property="og:description" content="셀럽 추천 맛집 서비스, 셀럽잇" />
</Helmet>
<StyledContainer>
{isMobile ? (
<BannerSlider />
) : (
<StyledSliderContainer>
<BannerSlider />
</StyledSliderContainer>
)}

<div>
<StyledTitle>셀럽 BEST</StyledTitle>
{isMobile ? (
<StyledIconBox>
{celebOptions.map(celeb => {
const { name, profileImageUrl, id } = celeb;
return (
<StyledCeleb onClick={() => clickCelebIcon(id)}>
<ProfileImage name={name} imageUrl={profileImageUrl} size="64px" boxShadow />
<span>{name}</span>
</StyledCeleb>
);
})}
</StyledIconBox>
) : (
<StyledSliderContainer>
<Slider {...CelebCarouselSettings}>
{celebOptions.map(celeb => {
const { name, profileImageUrl, id } = celeb;
return (
<StyledCeleb onClick={() => clickCelebIcon(id)}>
<ProfileImage name={name} imageUrl={profileImageUrl} size="64px" boxShadow />
<span>{name}</span>
</StyledCeleb>
);
})}
</Slider>
</StyledSliderContainer>
)}
</div>

<div>
<StyledTitle>셀럽잇 추천 맛집!</StyledTitle>
{isMobile ? (
<StyledPopularRestaurantBox>
{recommendedRestaurantData ? (
recommendedRestaurantData?.map(({ celebs, ...restaurant }) => (
<MiniRestaurantCard celebs={celebs} restaurant={restaurant} flexColumn showRating />
))
) : (
<>
<MiniRestaurantCardSkeleton flexColumn />
<MiniRestaurantCardSkeleton flexColumn />
<MiniRestaurantCardSkeleton flexColumn />
<MiniRestaurantCardSkeleton flexColumn />
<MiniRestaurantCardSkeleton flexColumn />
</>
)}
</StyledPopularRestaurantBox>
) : (
<StyledSliderContainer>
<Slider {...RestaurantCardCarouselSettings}>
{recommendedRestaurantData
? recommendedRestaurantData?.map(({ celebs, ...restaurant }) => (
<MiniRestaurantCard
celebs={celebs}
restaurant={restaurant}
flexColumn
showRating
isCarouselItem
/>
))
: new Array(5).fill('1').map(() => <MiniRestaurantCardSkeleton flexColumn isCarouselItem />)}
</Slider>
</StyledSliderContainer>
)}
</div>

<div>
<StyledTitle>어디로 가시나요?</StyledTitle>
<RegionList />
</div>
<div>
<StyledTitle>카테고리</StyledTitle>
<StyledCategoryBox>
<CategoryNavbar
categories={RESTAURANT_CATEGORY}
externalOnClick={clickRestaurantCategory}
includeAll={false}
grid
/>
</StyledCategoryBox>
</div>
</StyledContainer>
</>
<StyledContainer>
<BannerSection />
<CelebBestSection />
<CeluveatRecommendSection />
<RegionSection />
<CategorySection />
</StyledContainer>
);
}

Expand All @@ -170,53 +42,3 @@ const StyledContainer = styled.div`
padding-bottom: 4.4rem;
`;

const StyledIconBox = styled.div`
display: flex;
gap: 2rem;
padding: 1.6rem;
justify-items: flex-start;
overflow-x: scroll;
&::-webkit-scrollbar {
display: none;
}
`;

const StyledCeleb = styled.div`
display: flex !important;
flex-direction: column;
align-items: center;
gap: 0.8rem;
font-size: ${FONT_SIZE.sm};
cursor: pointer;
`;

const StyledPopularRestaurantBox = styled.div`
display: flex;
align-items: center;
gap: 1.2rem;
padding: 1.6rem;
overflow-x: scroll;
${hideScrollBar}
`;

const StyledCategoryBox = styled.div`
padding: 1.6rem 0.8rem;
`;

const StyledTitle = styled.h5`
margin-left: 1.6rem;
`;

const StyledSliderContainer = styled.div`
padding: 2rem 4rem;
`;
25 changes: 25 additions & 0 deletions frontend/src/pages/MainPage/BannerSection/BannerSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import styled from 'styled-components';
import useMediaQuery from '~/hooks/useMediaQuery';
import BannerSlider from './components/BannerSlider';

function BannerSection() {
const { isMobile } = useMediaQuery();

return (
<section>
{isMobile ? (
<BannerSlider />
) : (
<StyledSliderContainer>
<BannerSlider />
</StyledSliderContainer>
)}
</section>
);
}

export default BannerSection;

const StyledSliderContainer = styled.div`
padding: 2rem 4rem;
`;
39 changes: 39 additions & 0 deletions frontend/src/pages/MainPage/CategorySection/CategorySection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react';
import { useNavigate } from 'react-router-dom';
import styled from 'styled-components';
import CategoryNavbar from '~/components/CategoryNavbar';
import RESTAURANT_CATEGORY from '~/constants/restaurantCategory';

function CategorySection() {
const navigate = useNavigate();

const clickRestaurantCategory = (e: React.MouseEvent<HTMLElement>) => {
const currentCategory = e.currentTarget.dataset.label;

navigate(`/category/${currentCategory}`);
};

return (
<section>
<StyledTitle>카테고리</StyledTitle>
<StyledCategoryBox>
<CategoryNavbar
categories={RESTAURANT_CATEGORY}
externalOnClick={clickRestaurantCategory}
includeAll={false}
grid
/>
</StyledCategoryBox>
</section>
);
}

export default CategorySection;

const StyledTitle = styled.h5`
margin-left: 1.6rem;
`;

const StyledCategoryBox = styled.div`
padding: 1.6rem 0.8rem;
`;
87 changes: 87 additions & 0 deletions frontend/src/pages/MainPage/CelebBestSection/CelebBestSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React from 'react';
import { useNavigate } from 'react-router-dom';
import Slider from 'react-slick';
import styled from 'styled-components';
import ProfileImage from '~/components/@common/ProfileImage';
import { CelebCarouselSettings } from '~/constants/carouselSettings';
import { celebOptions } from '~/constants/celeb';
import useMediaQuery from '~/hooks/useMediaQuery';
import { FONT_SIZE } from '~/styles/common';

function CelebBestSection() {
const { isMobile } = useMediaQuery();
const navigate = useNavigate();

const clickCelebIcon = (id: number) => {
navigate(`/celeb/${id}`);
};

return (
<section>
<StyledTitle>셀럽 BEST</StyledTitle>
{isMobile ? (
<StyledIconBox>
{celebOptions.map(celeb => {
const { name, profileImageUrl, id } = celeb;
return (
<StyledCeleb onClick={() => clickCelebIcon(id)}>
<ProfileImage name={name} imageUrl={profileImageUrl} size="64px" boxShadow />
<span>{name}</span>
</StyledCeleb>
);
})}
</StyledIconBox>
) : (
<StyledSliderContainer>
<Slider {...CelebCarouselSettings}>
{celebOptions.map(celeb => {
const { name, profileImageUrl, id } = celeb;
return (
<StyledCeleb onClick={() => clickCelebIcon(id)}>
<ProfileImage name={name} imageUrl={profileImageUrl} size="64px" boxShadow />
<span>{name}</span>
</StyledCeleb>
);
})}
</Slider>
</StyledSliderContainer>
)}
</section>
);
}

export default CelebBestSection;

const StyledIconBox = styled.div`
display: flex;
gap: 2rem;
padding: 1.6rem;
justify-items: flex-start;
overflow-x: scroll;
&::-webkit-scrollbar {
display: none;
}
`;

const StyledCeleb = styled.div`
display: flex !important;
flex-direction: column;
align-items: center;
gap: 0.8rem;
font-size: ${FONT_SIZE.sm};
cursor: pointer;
`;

const StyledTitle = styled.h5`
margin-left: 1.6rem;
`;

const StyledSliderContainer = styled.div`
padding: 2rem 4rem;
`;
Loading

0 comments on commit cf6eb1b

Please sign in to comment.