Skip to content

Commit def9a21

Browse files
authored
메뉴상세에서 menu preview를 위한 모달 추가 (#58)
* feat: menu preview용 모달 컴포넌트 추가 * feat: menu에 previewModal 추가
1 parent 601d0dd commit def9a21

File tree

3 files changed

+174
-1
lines changed

3 files changed

+174
-1
lines changed
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import React from 'react';
2+
import styled from '@emotion/styled';
3+
import { MenuPreviewModalProps } from './index.types';
4+
5+
const ModalOverlay = styled.div`
6+
position: fixed;
7+
top: 0;
8+
left: 0;
9+
width: 100%;
10+
height: 100%;
11+
background: rgba(0, 0, 0, 0.5);
12+
display: flex;
13+
justify-content: center;
14+
align-items: center;
15+
`;
16+
17+
const ModalContent = styled.div`
18+
background: #f5f5f5;
19+
border-radius: 16px;
20+
width: 90%;
21+
max-width: 420px;
22+
padding: 36px;
23+
`;
24+
25+
const MenuImageWrap = styled.div`
26+
width: 100%;
27+
height: 200px;
28+
background: #c4c4c4;
29+
border-radius: 16px;
30+
display: flex;
31+
justify-content: center;
32+
align-items: center;
33+
color: #fff;
34+
font-size: 16px;
35+
overflow: hidden;
36+
`;
37+
38+
const MenuImage = styled.img`
39+
width: 100%;
40+
`;
41+
42+
const MenuTitle = styled.h2`
43+
margin: 16px 0;
44+
font-size: 24px;
45+
`;
46+
47+
const MenuDescription = styled.p`
48+
color: #666;
49+
font-size: 14px;
50+
line-height: 1.5;
51+
`;
52+
53+
const OptionSection = styled.div`
54+
margin: 16px 0;
55+
`;
56+
57+
const OptionTitle = styled.div`
58+
margin-bottom: 8px;
59+
font-size: 16px;
60+
`;
61+
62+
const OptionItem = styled.label`
63+
display: flex;
64+
align-items: center;
65+
margin-bottom: 8px;
66+
`;
67+
68+
const OptionCheckbox = styled.input`
69+
margin-right: 8px;
70+
`;
71+
72+
const Price = styled.span`
73+
margin-left: auto;
74+
`;
75+
76+
const CloseButton = styled.button`
77+
width: 100%;
78+
background: #6779ff;
79+
color: #fff;
80+
border: none;
81+
padding: 12px;
82+
border-radius: 8px;
83+
cursor: pointer;
84+
font-size: 16px;
85+
margin-top: 16px;
86+
`;
87+
88+
const MenuPreviewModal: React.FC<MenuPreviewModalProps> = ({
89+
onClose,
90+
menuImage,
91+
menuTitle,
92+
menuDescription,
93+
optionSections,
94+
}) => {
95+
return (
96+
<ModalOverlay>
97+
<ModalContent>
98+
<MenuImageWrap>
99+
<MenuImage src={menuImage} alt={`preview_${menuTitle}`} />
100+
</MenuImageWrap>
101+
<MenuTitle>{menuTitle}</MenuTitle>
102+
<MenuDescription>{menuDescription}</MenuDescription>
103+
104+
{optionSections.map((section, sectionIndex) => (
105+
<OptionSection key={sectionIndex}>
106+
<OptionTitle>
107+
{section.title} ({section.requirement} - {section.type})
108+
</OptionTitle>
109+
{section.options.map((option, index) => (
110+
<OptionItem key={index}>
111+
<OptionCheckbox
112+
type="checkbox"
113+
defaultChecked={option.checked}
114+
disabled={section.type === '단일'}
115+
/>{' '}
116+
{option.name} <Price>+ ₩{option.price}</Price>
117+
</OptionItem>
118+
))}
119+
</OptionSection>
120+
))}
121+
122+
<CloseButton onClick={onClose}>닫기</CloseButton>
123+
</ModalContent>
124+
</ModalOverlay>
125+
);
126+
};
127+
128+
export default MenuPreviewModal;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
type Option = {
2+
name: string;
3+
price: number;
4+
checked?: boolean;
5+
};
6+
7+
type OptionSectionData = {
8+
title: string;
9+
requirement: string;
10+
type: string;
11+
options: Option[];
12+
};
13+
14+
export type MenuPreviewModalProps = {
15+
onClose: () => void;
16+
menuImage: string;
17+
menuTitle: string;
18+
menuDescription: string;
19+
optionSections: OptionSectionData[];
20+
};

src/pages/menu/detail.tsx

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ import type {
1717
} from 'api/modules/stores/types';
1818
import useMenuDetail from './hooks/useMenuDetail';
1919
import useMenuOption from './hooks/useMenuOption';
20+
import MenuPreviewModal from './components/menuPreviewModal';
2021

2122
//TODO status 뭐로 추가하지?
2223
const MenuDetail = ({ data }: { data: MenuDetailInfo }) => {
2324
const { options } = data;
2425
const [isOptionModalOpen, setIsOptionModalOpen] = useState<boolean>(false);
26+
const [isPreviewModalOpen, setIsPreviewModalOpen] = useState<boolean>(false);
2527
const [selectedOptionToEdit, setSelectedOptionToEdit] = useState<{
2628
data: CreateMenuOptionGroupReq;
2729
index: number;
@@ -41,12 +43,29 @@ const MenuDetail = ({ data }: { data: MenuDetailInfo }) => {
4143
const handleCloseEditModal = () => setSelectedOptionToEdit(null);
4244
const handleOptionModalOpen = () => setIsOptionModalOpen((prev) => !prev);
4345

46+
const menuPreviewModel = {
47+
menuImage: imageMetadata ? imageMetadata.src : originalImage,
48+
menuTitle: data.name,
49+
menuDescription: data.desc,
50+
optionSections: data.options.map((optionGroup) => ({
51+
title: optionGroup.title,
52+
requirement: optionGroup.isRequired ? '필수' : '선택',
53+
type: optionGroup.isMultiple ? '다중' : '단일',
54+
options: optionGroup.details.map((detail) => ({
55+
name: detail.name,
56+
price: detail.price,
57+
checked: false, // 기본값으로 false 설정
58+
})),
59+
})),
60+
};
4461
return (
4562
<>
4663
<div css={[_container]}>
4764
<div css={_titleWrap}>
4865
<h2>Menu</h2>
49-
<button css={_subButton}>미리보기</button>
66+
<button css={_subButton} onClick={() => setIsPreviewModalOpen(true)}>
67+
미리보기
68+
</button>
5069
</div>
5170
<section css={_menuContainer}>
5271
<h3 css={_subtitle}>기본 정보</h3>
@@ -132,6 +151,12 @@ const MenuDetail = ({ data }: { data: MenuDetailInfo }) => {
132151
}}
133152
/>
134153
)}
154+
{isPreviewModalOpen && (
155+
<MenuPreviewModal
156+
onClose={() => setIsPreviewModalOpen(false)}
157+
{...menuPreviewModel}
158+
/>
159+
)}
135160
</>
136161
);
137162
};

0 commit comments

Comments
 (0)