Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: ✨ LevelModal 컴포넌트 이관 #98

Merged
merged 10 commits into from
Jul 26, 2022
58 changes: 58 additions & 0 deletions src/components/mypage/LevelModal/LevelModal.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { ILevel } from '@/types';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { useState } from 'react';

import LevelModal from './LevelModal';

const LEVEL_DATA: ILevel[] = [
{
id: 1,
tier: 1,
imageUrl: 'https://cdn.pixabay.com/photo/2016/04/24/14/19/paper-1349664_1280.png',
req: 0,
},
{
id: 2,
tier: 2,
imageUrl: 'https://cdn.pixabay.com/photo/2016/04/24/14/19/paper-1349664_1280.png',
req: 1,
},
{
id: 3,
tier: 3,
imageUrl: 'https://cdn.pixabay.com/photo/2016/04/24/14/19/paper-1349664_1280.png',
req: 5,
},
{
id: 4,
tier: 4,
imageUrl: 'https://cdn.pixabay.com/photo/2016/04/24/14/19/paper-1349664_1280.png',
req: 12,
},
{
id: 5,
tier: 5,
imageUrl: 'https://cdn.pixabay.com/photo/2016/04/24/14/19/paper-1349664_1280.png',
req: 20,
},
];

export default {
title: 'Components/mypage/LevelModal',
component: LevelModal,
} as ComponentMeta<typeof LevelModal>;

const Template: ComponentStory<typeof LevelModal> = () => {
const [isOpen, setIsOpen] = useState(true);

return (
<LevelModal
isLevelModalOpen={isOpen}
openLevelModal={() => setIsOpen(true)}
closeLevelModal={() => setIsOpen(false)}
levelData={LEVEL_DATA}
/>
);
};

export const Default = Template.bind({});
98 changes: 98 additions & 0 deletions src/components/mypage/LevelModal/LevelModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import styled from '@emotion/styled';

import ModalLayout from '@/components/layouts/ModalLayout';
import Icon from '@/components/commons/Icon';
import { ILevel } from '@/types';

const LEVEL_MODAL_TITLE = 'Level 안내';

interface Props {
isLevelModalOpen: boolean;
openLevelModal: () => void;
closeLevelModal: () => void;
levelData: ILevel[];
}

const LevelModal = ({ isLevelModalOpen, closeLevelModal, levelData }: Props) => {
if (!levelData) {
return null;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

levelData는 필수값인데 해당 로직은 필요없을 것 같습니다.
levelData이 실제로 optional 한 데이터라면 타입을 optional로 변경하거나, 외부에서 levelData라는 타입을 정확히 명시해
해당 데이터가 있어야 LevelModal 컴포넌트를 렌더링해주는게 좀 더 type safe한것 같습니다.

그리고 levelData라는 변수명도 다른 pr comment와 마찬가지로 array인지 알 수 있는 변수명이면 좋을것 같고 data라는 postfix없이도 의미는 명확하게 지을 수 있을 것 같아요


return (
<ModalLayout open={isLevelModalOpen} onDimClick={closeLevelModal}>
<StyleLevelModal open={isLevelModalOpen}>
syoung125 marked this conversation as resolved.
Show resolved Hide resolved
<Header>
<CloseIcon name="Close" size={24} onClick={closeLevelModal} />
<Title>{LEVEL_MODAL_TITLE}</Title>
</Header>
<LevelList>
{levelData.map(({ id, imageUrl, req, tier }) => (
<LevelListItem key={id}>
<img src={imageUrl} alt={tier.toString()} width="64px" height="auto" />
<p>
Level {tier} : 기록한 티켓 {req}개 이상
</p>
</LevelListItem>
))}
</LevelList>
</StyleLevelModal>
</ModalLayout>
);
};

export default LevelModal;

const StyleLevelModal = styled.div<{ open: boolean }>`
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
flex-direction: column;
align-items: center;
width: 300px;
padding: 16px;
border-radius: 12px;
background-color: ${(p) => p.theme.color.white};

${(p) => !p.open && `display:none;`}
`;

const Header = styled.div`
position: relative;
width: 100%;
margin-bottom: 25px;
`;

const Title = styled.h1`
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-weight: 700;
font-size: 16px;
line-height: 19px;
color: #323232;
`;
syoung125 marked this conversation as resolved.
Show resolved Hide resolved

const CloseIcon = styled(Icon)`
cursor: pointer;
`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

전체적으로 Icon에 cursor: pointer 스타일을 오버라이딩해서 사용하는 경우가 많은것 같은데, 이러면 그냥 cursor props를 하나 추가해도 좋을 것 같습니다


const LevelList = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%;
gap: 40px;
margin-bottom: 8px;
`;

const LevelListItem = styled.div`
display: flex;
align-items: center;
gap: 13px;
${({ theme }) => theme.fonts.Body4};
color: ${({ theme }) => theme.color.grey4};
`;
1 change: 1 addition & 0 deletions src/components/mypage/LevelModal/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './LevelModal';
1 change: 1 addition & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export type { IFeel } from './feel';
export type { IReview } from './review';
export type { IContinent } from './continent';
export type { ICountry } from './country';
export type { ILevel } from './level';
6 changes: 6 additions & 0 deletions src/types/level.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface ILevel {
id: number;
tier: number;
imageUrl: string;
req: number;
}