Skip to content

Commit

Permalink
[FE] feature/#302 내가 만든 지도 목록 모달에 띄우기 (#310)
Browse files Browse the repository at this point in the history
* feat: 내 지도 토픽 목록 list 컴포넌트 구현 및 모달 창에 적용

* fix: 내 지도 저장 모달 띄웠을 때 PinDetail 포커스 제거

* refactor: 내 지도 목록 모달 서버 요청 후 데이터 받도록 수정
  • Loading branch information
GC-Park authored Aug 16, 2023
1 parent 8ae58f2 commit 237830b
Show file tree
Hide file tree
Showing 6 changed files with 227 additions and 75 deletions.
2 changes: 2 additions & 0 deletions frontend/src/components/Modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ const Wrapper = styled.div<ModalWrapperType>`
${({ position }) => getModalPosition(position)};
top: ${({ top }) => top && top};
left: ${({ left }) => left && left};
z-index: 2;
`;

const WrapperDimmed = styled.div<{ $dimmedColor: string }>`
Expand All @@ -85,6 +86,7 @@ const WrapperDimmed = styled.div<{ $dimmedColor: string }>`
position: fixed;
top: 0;
background-color: ${({ $dimmedColor }) => $dimmedColor};
z-index: 2;
`;

const translateModalAnimation = keyframes`
Expand Down
47 changes: 47 additions & 0 deletions frontend/src/components/ModalMyTopicList/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Fragment, useEffect, useState } from 'react';
import { styled } from 'styled-components';
import { getApi } from '../../apis/getApi';
import { ModalMyTopicType } from '../../types/Topic';
import ModalTopicCard from '../ModalTopicCard';

const ModalMyTopicList = () => {
const [myTopics, setMyTopics] = useState<ModalMyTopicType[]>([]);

const getMyTopicFromServer = async () => {
const serverMyTopic = await getApi<ModalMyTopicType[]>(
'default',
'/members/my/topics',
);
setMyTopics(serverMyTopic);
};

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

if (!myTopics) return <></>;

return (
<ModalMyTopicListWrapper>
{myTopics.map((topic) => (
<Fragment key={topic.id}>
<ModalTopicCard
topicId={topic.id}
topicImage={topic.image}
topicTitle={topic.name}
topicUpdatedAt={topic.updatedAt}
topicPinCount={topic.pinCount}
/>
</Fragment>
))}
</ModalMyTopicListWrapper>
);
};

const ModalMyTopicListWrapper = styled.ul`
display: grid;
grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
grid-row-gap: ${({ theme }) => theme.spacing[5]};
`;

export default ModalMyTopicList;
115 changes: 115 additions & 0 deletions frontend/src/components/ModalTopicCard/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { styled } from 'styled-components';
import Text from '../common/Text';
import useNavigator from '../../hooks/useNavigator';
import Box from '../common/Box';
import Image from '../common/Image';
import { SyntheticEvent } from 'react';
import Space from '../common/Space';
import Flex from '../common/Flex';
import SmallTopicPin from '../../assets/smallTopicPin.svg';
import SmallTopicStar from '../../assets/smallTopicStar.svg';
import { DEFAULT_TOPIC_IMAGE } from '../../constants';

const FAVORITE_COUNT = 10;

export interface ModalTopicCardProps {
topicId: number;
topicImage: string;
topicTitle: string;
topicUpdatedAt: string;
topicPinCount: number;
}

const ModalTopicCard = ({
topicId,
topicImage,
topicTitle,
topicUpdatedAt,
topicPinCount,
}: ModalTopicCardProps) => {
const { routePage } = useNavigator();

const goToSelectedTopic = () => {
routePage(`/topics/${topicId}`, [topicId]);
};

return (
<Wrapper onClick={goToSelectedTopic}>
<Flex position="relative">
<TopicImage
height="138px"
width="138px"
src={topicImage}
alt="토픽 이미지"
$objectFit="cover"
onError={(e: SyntheticEvent<HTMLImageElement, Event>) => {
e.currentTarget.src = DEFAULT_TOPIC_IMAGE;
}}
/>

<Box width="192px" padding={1}>
<Box height="52px">
<Text color="black" $fontSize="default" $fontWeight="bold">
{topicTitle}
</Text>
</Box>

<Text color="black" $fontSize="small" $fontWeight="normal">
토픽 생성자
</Text>

<Space size={0} />

<Text color="gray" $fontSize="small" $fontWeight="normal">
{topicUpdatedAt.split('T')[0].replaceAll('-', '.')} 업데이트
</Text>

<Space size={0} />

<Flex>
<Flex $alignItems="center" width="64px">
<SmallTopicPin />
<Space size={0} />
<Text color="black" $fontSize="extraSmall" $fontWeight="normal">
{topicPinCount > 999 ? '+999' : topicPinCount}
</Text>
</Flex>
<Flex $alignItems="center" width="64px">
<SmallTopicStar />
<Space size={0} />
<Text color="black" $fontSize="extraSmall" $fontWeight="normal">
{FAVORITE_COUNT > 999 ? '+999' : FAVORITE_COUNT}
</Text>
</Flex>
</Flex>
</Box>
</Flex>
</Wrapper>
);
};

const Wrapper = styled.li`
width: 332px;
height: 140px;
cursor: pointer;
border: 1px solid ${({ theme }) => theme.color.gray};
border-radius: ${({ theme }) => theme.radius.small};
margin: 0 auto;
`;

const ButtonWrapper = styled.div`
display: flex;
justify-content: space-between;
position: absolute;
width: 72px;
top: 100px;
left: 60px;
`;

const TopicImage = styled(Image)`
border-radius: ${({ theme }) => theme.radius.small};
`;

export default ModalTopicCard;
21 changes: 18 additions & 3 deletions frontend/src/pages/NewPin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import useSetNavbarHighlight from '../hooks/useSetNavbarHighlight';
import { ModalContext } from '../context/ModalContext';
import Modal from '../components/Modal';
import { styled } from 'styled-components';
import ModalMyTopicList from '../components/ModalMyTopicList';

type NewPinFormValueType = Pick<
NewPinFormProps,
Expand Down Expand Up @@ -257,11 +258,21 @@ const NewPin = () => {
<Modal
modalKey="newPin"
position="center"
width="400px"
height="340px"
width="768px"
height="512px"
$dimmedColor="rgba(0,0,0,0.25)"
>
<ModalContentsWrapper>내 토픽 리스트</ModalContentsWrapper>
<ModalContentsWrapper>
<Space size={5} />
<Text color="black" $fontSize="extraLarge" $fontWeight="bold">
내 토픽 리스트
</Text>
<Text color="gray" $fontSize="small" $fontWeight="normal">
핀을 저장할 지도를 선택해주세요.
</Text>
<Space size={4} />
<ModalMyTopicList />
</ModalContentsWrapper>
</Modal>
</>
);
Expand All @@ -271,6 +282,10 @@ const ModalContentsWrapper = styled.div`
width: 100%;
height: 100%;
background-color: white;
text-align: center;
overflow: scroll;
`;

export default NewPin;
107 changes: 35 additions & 72 deletions frontend/src/pages/PinDetail.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Flex from '../components/common/Flex';
import Space from '../components/common/Space';
import Text from '../components/common/Text';
import { useEffect, useState } from 'react';
import { useContext, useEffect, useState } from 'react';
import { PinType } from '../types/Pin';
import { getApi } from '../apis/getApi';
import { useSearchParams } from 'react-router-dom';
Expand All @@ -11,8 +11,10 @@ import useFormValues from '../hooks/useFormValues';
import { ModifyPinFormProps } from '../types/FormValues';
import useToast from '../hooks/useToast';
import Button from '../components/common/Button';
import Modal from '../components/Modal';
import { styled } from 'styled-components';
import { ModalPortal, useModalContext } from '../context/AbsoluteModalContext';
import { ModalContext } from '../context/ModalContext';
import ModalMyTopicList from '../components/ModalMyTopicList';

interface PinDetailProps {
pinId: number;
Expand All @@ -28,7 +30,6 @@ const PinDetail = ({
const [searchParams, setSearchParams] = useSearchParams();
const [pin, setPin] = useState<PinType | null>(null);
const { showToast } = useToast();
const { isModalOpen, openModal, closeModal } = useModalContext();
const {
formValues,
errorMessages,
Expand All @@ -40,6 +41,7 @@ const PinDetail = ({
images: [],
description: '',
});
const { openModal } = useContext(ModalContext);

useEffect(() => {
const getPinData = async () => {
Expand Down Expand Up @@ -175,7 +177,12 @@ const PinDetail = ({
position="fixed"
bottom="24px"
>
<SaveToMyMapButton variant="primary" onClick={openModal}>
<SaveToMyMapButton
variant="primary"
onClick={() => {
openModal('saveMyMap');
}}
>
내 지도에 저장하기
</SaveToMyMapButton>
<Space size={4} />
Expand All @@ -184,70 +191,25 @@ const PinDetail = ({
</ShareButton>
</Flex>

<Space size={9} />

{isModalOpen && (
<ModalPortal closeModalHandler={closeModal}>
<>
<Text
color="black"
$fontSize="extraLarge"
$fontWeight="bold"
$textAlign="center"
>
내 지도 목록
</Text>
<Space size={5} />
<Flex $flexDirection="row">
<Text
color="black"
$fontSize="small"
$fontWeight="bold"
$textAlign="center"
>
최신순
</Text>
<Space size={3} />
<Text
color="black"
$fontSize="small"
$fontWeight="bold"
$textAlign="center"
>
글자순
</Text>
<Space size={3} />
<Text
color="black"
$fontSize="small"
$fontWeight="bold"
$textAlign="center"
>
인기순
</Text>
</Flex>
<Space size={2} />
<Flex $flexDirection="column">
<ModalMapItem>아이템</ModalMapItem>
<Space size={4} />
<ModalMapItem>아이템</ModalMapItem>
<Space size={4} />
<ModalMapItem>아이템</ModalMapItem>
<Space size={4} />
<ModalMapItem>아이템</ModalMapItem>
<Space size={4} />
<ModalMapItem>아이템</ModalMapItem>
<Space size={4} />
</Flex>

<Flex $justifyContent="center">
<SaveToMyMapButton variant="secondary" onClick={closeModal}>
Close Modal
</SaveToMyMapButton>
</Flex>
</>
</ModalPortal>
)}
<Modal
modalKey="saveMyMap"
position="center"
width="768px"
height="512px"
$dimmedColor="rgba(0,0,0,0.25)"
>
<ModalContentsWrapper>
<Space size={5} />
<Text color="black" $fontSize="extraLarge" $fontWeight="bold">
내 토픽 리스트
</Text>
<Text color="gray" $fontSize="small" $fontWeight="normal">
핀을 저장할 지도를 선택해주세요.
</Text>
<Space size={4} />
<ModalMyTopicList />
</ModalContentsWrapper>
</Modal>
</>
);
};
Expand All @@ -270,13 +232,14 @@ const ShareButton = styled(Button)`
box-shadow: 8px 8px 8px 0px rgba(69, 69, 69, 0.15);
`;

const ModalMapItem = styled(Box)`
const ModalContentsWrapper = styled.div`
width: 100%;
height: 48px;
height: 100%;
background-color: white;
text-align: center;
border: 1px solid black;
border-radius: 8px;
overflow: scroll;
`;

export default PinDetail;
10 changes: 10 additions & 0 deletions frontend/src/types/Topic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,13 @@ export interface TopicInfoType {
updatedAt: string;
pins: PinType[];
}

export interface ModalMyTopicType {
id: number;
name: string;
image: string;
pinCount: number;
bookmarkCount: number;
isBookmarked: boolean;
updatedAt: string;
}

0 comments on commit 237830b

Please sign in to comment.