Skip to content

Commit

Permalink
[FE] Feat/#592 핀 디테일의 핀 이미지 클릭 시 모달을 통해 크게 보이는 기능 구현 (#595)
Browse files Browse the repository at this point in the history
* feat: 이미지 클릭 시 이미지 모달 띄우는 기능 추가 및 반응형 적용

* refactor: context 역할에 맞게 이름 수정

* refactor: fetchDelete 안에 있는 불필요한 isThrow 속성 제거

* refactor: 필요없는 코드 및 수정 필요한 이름 변경

* refactor: 명시적인 함수 이름으로 수정
  • Loading branch information
GC-Park authored Oct 19, 2023
1 parent 4f477d0 commit d7fc2e0
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 51 deletions.
71 changes: 37 additions & 34 deletions frontend/src/components/Layout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import Map from '../Map';
import Toast from '../Toast';
import Logo from './Logo';
import Navbar from './Navbar';
import ImageModalContext from '../../context/ImageModalContext';

type LayoutProps = {
children: React.ReactNode;
Expand Down Expand Up @@ -43,44 +44,46 @@ function Layout({ children }: LayoutProps) {
return (
<ToastProvider>
<ModalProvider>
<CoordinatesProvider>
<MarkerProvider>
<SeeTogetherProvider>
<TagProvider>
<MediaWrapper
$isAddPage={navbarHighlights.addMapOrPin}
$layoutWidth={width}
>
<LayoutFlex
$flexDirection="column"
$minWidth={width}
height="calc(var(--vh, 1vh) * 100)"
$backgroundColor="white"
<ImageModalContext>
<CoordinatesProvider>
<MarkerProvider>
<SeeTogetherProvider>
<TagProvider>
<MediaWrapper
$isAddPage={navbarHighlights.addMapOrPin}
$layoutWidth={width}
>
<LogoWrapper $layoutWidth={width}>
<Box>
<Logo />
<Space size={2} />
</Box>
</LogoWrapper>
<Flex
<LayoutFlex
$flexDirection="column"
height="inherit"
overflow="auto"
padding="0"
$minWidth={width}
height="calc(var(--vh, 1vh) * 100)"
$backgroundColor="white"
$layoutWidth={width}
>
{children}
</Flex>
<Navbar $layoutWidth={width} />
<Toast />
</LayoutFlex>
<Map />
</MediaWrapper>
</TagProvider>
</SeeTogetherProvider>
</MarkerProvider>
</CoordinatesProvider>
<LogoWrapper $layoutWidth={width}>
<Box>
<Logo />
<Space size={2} />
</Box>
</LogoWrapper>
<Flex
$flexDirection="column"
height="inherit"
overflow="auto"
padding="0"
>
{children}
</Flex>
<Navbar $layoutWidth={width} />
<Toast />
</LayoutFlex>
<Map />
</MediaWrapper>
</TagProvider>
</SeeTogetherProvider>
</MarkerProvider>
</CoordinatesProvider>
</ImageModalContext>
</ModalProvider>
</ToastProvider>
);
Expand Down
67 changes: 56 additions & 11 deletions frontend/src/components/PinImageContainer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,23 @@ import Image from '../common/Image';
import RemoveImageButton from '../../assets/remove_image_icon.svg';
import useDelete from '../../apiHooks/useDelete';
import useToast from '../../hooks/useToast';
import { useModalContext, ImageModal } from '../../context/ImageModalContext';
import { useState } from 'react';
import Button from '../common/Button';
import Space from '../common/Space';

interface PinImageContainerProps {
images: ImageProps[];
getPinData: () => void;
}const NOT_FOUND_IMAGE =
'https://dr702blqc4x5d.cloudfront.net/2023-map-be-fine/icon/notFound_image.svg';
}
const NOT_FOUND_IMAGE =
'https://dr702blqc4x5d.cloudfront.net/2023-map-be-fine/icon/notFound_image.svg';

const PinImageContainer = ({ images, getPinData }: PinImageContainerProps) => {
const { fetchDelete } = useDelete();
const { showToast } = useToast();
const { isModalOpen, openModal, closeModal } = useModalContext();
const [modalImage, setModalImage] = useState<string>('');

const onRemovePinImage = (imageId: number) => {
const isRemoveImage = confirm('해당 이미지를 삭제하시겠습니까?');
Expand All @@ -24,28 +30,35 @@ const PinImageContainer = ({ images, getPinData }: PinImageContainerProps) => {
fetchDelete({
url: `/pins/images/${imageId}`,
errorMessage: '이미지 제거에 실패했습니다.',
isThrow: true,
onSuccess: () => {
showToast('info', '핀에서 이미지가 삭제 되었습니다.');
getPinData();
},
});
}
};

const onImageOpen = (imageUrl: string) => {
setModalImage(imageUrl);
openModal();
};

return (
<>
<FilmList>
{images.map(
(image, index) =>
index < 3 && (
<ImageWrapper>
<Image
key={image.id}
height="100px"
width="100px"
src={image.imageUrl}
$errorDefaultSrc={NOT_FOUND_IMAGE}
/>
<div onClick={() => onImageOpen(image.imageUrl)}>
<Image
key={image.id}
height="100px"
width="100px"
src={image.imageUrl}
$errorDefaultSrc={NOT_FOUND_IMAGE}
/>
</div>
<RemoveImageIconWrapper
onClick={() => onRemovePinImage(image.id)}
>
Expand All @@ -54,6 +67,17 @@ const PinImageContainer = ({ images, getPinData }: PinImageContainerProps) => {
</ImageWrapper>
),
)}
{isModalOpen && (
<ImageModal closeModalHandler={closeModal}>
<ModalImageWrapper>
<ModalImage src={modalImage} />
<Space size={3} />
<Button variant="custom" onClick={closeModal}>
닫기
</Button>
</ModalImageWrapper>
</ImageModal>
)}
</FilmList>
</>
);
Expand Down Expand Up @@ -84,4 +108,25 @@ const RemoveImageIconWrapper = styled.div`
}
`;

const ModalImageWrapper = styled.div`
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
margin: 0 auto;
overflow: hidden;
`;

const ModalImage = styled.img`
width: 100%;
height: 100%;
min-width: 360px;
min-height: 360px;
display: block;
`;
export default PinImageContainer;
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import React, {
import ReactDOM from 'react-dom';
import { styled } from 'styled-components';

interface ModalPortalProps {
interface ImageModalProps {
children: ReactChild;
closeModalHandler: () => void;
}

export const ModalPortal = (props: ModalPortalProps) => {
export const ImageModal = (props: ImageModalProps) => {
const $modalRoot = document.getElementById('modal-root') as HTMLElement;
const modalRef = useRef<HTMLDialogElement>(null);

Expand Down Expand Up @@ -54,8 +54,6 @@ export const ModalPortal = (props: ModalPortalProps) => {
};

const ModalContainer = styled.dialog`
width: 600px;
max-height: 600px;
padding: 32px 16px;
display: flex;
Expand Down Expand Up @@ -87,7 +85,7 @@ export const useModalContext = () => {

export const ModalContext = React.createContext<ModalContextType | null>(null);

function ModalContextProvider(props: { children: React.ReactNode }) {
function ImageModalContextProvider(props: { children: React.ReactNode }) {
const [isModalOpen, setIsModalOpen] = useState(false);

const openModal = () => {
Expand All @@ -111,4 +109,4 @@ function ModalContextProvider(props: { children: React.ReactNode }) {
);
}

export default ModalContextProvider;
export default ImageModalContextProvider;

0 comments on commit d7fc2e0

Please sign in to comment.