Skip to content

Commit

Permalink
[Feat] 술집 피드 조회 UI 구현 #32
Browse files Browse the repository at this point in the history
  • Loading branch information
soonki-98 committed Nov 30, 2022
1 parent e73f504 commit 7736de7
Showing 5 changed files with 277 additions and 1 deletion.
132 changes: 132 additions & 0 deletions src/components/pages/map/FeedMenu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { PostType } from '@lib/types';
import { uuid } from '@lib/utils';
import { filterAtom } from '@recoil/map';
import { useRouter } from 'next/router';
import { useEffect, useRef, useState } from 'react';
import { useRecoilState } from 'recoil';
import styled, { css } from 'styled-components';
import PostItem from './PostItem';

function FeedMenu({ posts }: { posts: PostType.PostType[] }) {
const [isOpen, setIsOpen] = useState(true);
const router = useRouter();
const foodList = ['전체', '한식', '중식', '양식', '일식', '기타'];
const [filterState, setFilterState] = useRecoilState(filterAtom);
const feedRef = useRef<HTMLDivElement>(null);

const closeClickOutSide = (e: MouseEvent) => {
if (!feedRef.current) return;
if (isOpen && !feedRef.current.contains(e.target as HTMLElement)) {
closeFilter();
}
};

const closeFilter = () => {
setFilterState({ drinkTag: '', moodTag: '', isOpen: false });
setIsOpen(false);
router.push('/map');
};

useEffect(() => {
document.addEventListener('click', closeClickOutSide);
return () => document.removeEventListener('click', closeClickOutSide);
}, [filterState.isOpen]);

return (
<Wrapper isOpen={isOpen} ref={feedRef}>
<Title>
<FoodListWrapper>
{foodList.map((food) => {
return (
<li key={uuid()}>
<FoodButton value={food}>{food}</FoodButton>
</li>
);
})}
</FoodListWrapper>
</Title>
<PostList>
{posts.map((post: PostType.PostType) => {
return <PostItem post={post} />;
})}
</PostList>
</Wrapper>
);
}

export default FeedMenu;

const Wrapper = styled.div<{ isOpen: boolean }>`
position: fixed;
bottom: 0;
width: 100%;
background: #fafafa;
z-index: 500;
transition: 0.5s;
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.15);
border-radius: 16px 16px 0px 0px;
max-height: 80vh;
${({ isOpen }) => {
if (isOpen) {
return css`
bottom: 0;
`;
} else {
return css`
bottom: -100%;
`;
}
}}
`;

const Title = styled.header`
position: relative;
padding: 12px;
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.15);
color: #000;
text-align: center;
background: #fff;
border-radius: 16px 16px 0px 0px;
height: 60px;
h1 {
font-size: 18px;
line-height: 24px;
margin: 0;
}
.close-icon {
position: absolute;
top: 50%;
left: 16px;
z-index: 400;
width: 18px;
height: 18px;
}
`;

const FoodListWrapper = styled.ul`
display: flex;
justify-content: center;
gap: 7px;
`;

const FoodButton = styled.button`
width: 100%;
padding: 8px 16px;
border-radius: 26px;
border: 1px solid #f0f0f0;
background-color: #fff;
color: #000;
&:hover {
border: 1px solid #715ae4;
color: #715ae4;
}
cursor: pointer;
`;

const PostList = styled.ul`
max-height: calc(80vh - 60px);
overflow: auto;
padding: 16px;
padding-top: 0;
`;
2 changes: 1 addition & 1 deletion src/components/pages/map/FilterMenu.tsx
Original file line number Diff line number Diff line change
@@ -99,7 +99,7 @@ const Wrapper = styled.div<{ isOpen: boolean }>`
bottom: 0;
width: 100%;
background: #fafafa;
z-index: 500;
z-index: 600;
transition: 0.5s;
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.15);
border-radius: 16px 16px 0px 0px;
80 changes: 80 additions & 0 deletions src/components/pages/map/PostItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { PostType } from '@lib/types';
import styled from 'styled-components';

function PostItem({ post }: { post: PostType.PostType }) {
return (
<Wrapper>
<PostTitle>
<h2>{post.store.storeName}</h2>
</PostTitle>
<PostBody>
<p>{post.store.description}</p>
<ImageWrapper>
{post.imageUrls.length === 0 ? (
<>
<PostImage imageUrl="https://fastly.4sqi.net/img/general/600x600/8372463_U4wVZXx6tWL6imrW2sDwglyjgu7NQiWuvS04gWd13BE.jpg" />
<PostImage imageUrl="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQhF8FQXUT7URFFwf3f-m5auiuo2aI2GYB1AA&usqp=CAU" />
<PostImage imageUrl="https://mblogthumb-phinf.pstatic.net/MjAxOTA2MjVfMzMg/MDAxNTYxNDQ2Nzg4MTUw.J9RsOmXQonsT7eVuKSbCw8dbwJ_HVNTFK4qh88TroDwg.MH2mr0QmpEsozD4kkANhkULL_Oiu1I66mXClaqScXDgg.JPEG.cosney/SE-8384796e-a3e9-4105-a5d4-a4657264ef48.jpg?type=w800" />
<PostImage imageUrl="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTnxivypgzjIrY-8vIicYzFKosBFI-dw6_oyg&usqp=CAU" />
<PostImage imageUrl="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR3zPmrztxmOzc89kxElUqs21fIMG4Fnj1LLg&usqp=CAU" />
</>
) : (
post.imageUrls.map((imageUrl) => <PostImage imageUrl={imageUrl} />)
)}
</ImageWrapper>
</PostBody>
</Wrapper>
);
}

export default PostItem;

const Wrapper = styled.li`
display: flex;
flex-direction: column;
gap: 10px;
border-bottom: 0.25px solid #000000;
margin-top: 28px;
`;

const PostTitle = styled.div`
h2 {
margin: 0;
font-weight: 500;
font-size: 18px;
line-height: 24px;
color: #000;
}
`;

const PostBody = styled.div`
display: flex;
flex-direction: column;
gap: 8px;
margin-bottom: 24px;
p {
margin: 0;
color: #000;
font-weight: 200;
font-size: 16px;
line-height: 24px;
}
`;

const ImageWrapper = styled.ul`
display: flex;
overflow: auto;
gap: 11px;
`;

const PostImage = styled.li<{ imageUrl?: string }>`
height: 30vw;
max-height: calc(480px / 3);
aspect-ratio: 1/1;
background: #d9d9d9;
border-radius: 6px;
background-image: url(${({ imageUrl }) => imageUrl});
background-repeat: no-repeat;
background-position: center center;
background-size: cover;
`;
1 change: 1 addition & 0 deletions src/components/pages/map/index.ts
Original file line number Diff line number Diff line change
@@ -5,3 +5,4 @@ export { default as CurrentLocationButton } from './CurrentLocationButton';
export { default as Header } from './Header';
export { default as Marker } from './MapMarker';
export { default as FilterMenu } from './FilterMenu';
export { default as FeedMenu } from './FeedMenu';
63 changes: 63 additions & 0 deletions src/pages/map/[search]/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import dynamic from 'next/dynamic';
import { Map } from 'react-kakao-maps-sdk';
import styled from 'styled-components';
import { BottomMenu } from '@components/common';
import { CommonWrapper } from '@components/common/commonStyle';
import { Marker, CurrentLocationButton, Error, Header, FilterMenu, FeedMenu } from '@components/pages/map';
import { useMap } from '@hooks/pages/map';
import { useRecoilValue } from 'recoil';
import { filterAtom } from '@recoil/map';
import { useEffect, useState } from 'react';
import apis from '@apis/index';
import { PostType } from '@lib/types';

function MapPage() {
const filterState = useRecoilValue(filterAtom);
const [posts, setPosts] = useState<PostType.PostType[]>([]);
const { barList, mapInfo, myLocation, handleBoundsChanged, handleClickCurrentLocation } = useMap();

useEffect(() => {
(async () => {
const result = await apis.posts.getFeeds({ latitude: 37.565314, longitude: 126.992646, pages: 0 });
setPosts(result!.data.postList);
})();
}, []);

if (!mapInfo || !myLocation) {
return <Error />;
} else {
return (
<CommonWrapper>
<StyledMap center={{ ...mapInfo }} onBoundsChanged={handleBoundsChanged} isPanto={true} tileAnimation={true}>
<Header />
{barList?.map((bar) => {
return <Marker {...bar} name={bar.barName} />;
})}
<Marker latitude={myLocation.coords.latitude} longitude={myLocation.coords.longitude} name="현위치" />
<CurrentLocationButton onClick={handleClickCurrentLocation} />
<BottomMenu />
<FilterMenu />
<FeedMenu posts={posts} />
</StyledMap>
{filterState.isOpen && <Shadow />}
</CommonWrapper>
);
}
}

export default dynamic(() => Promise.resolve(MapPage), { ssr: false });

const StyledMap = styled(Map)`
height: 100%;
width: 100%;
transition: 0.5s;
`;

const Shadow = styled.div`
position: fixed;
top: 0;
width: 100%;
height: 100%;
z-index: 400;
background-color: #272727a1;
`;

0 comments on commit 7736de7

Please sign in to comment.