Skip to content

Commit

Permalink
[페이먼츠 미션 Step 2] 우디(류정우) 미션 제출합니다. (#267)
Browse files Browse the repository at this point in the history
* refactor: 범용적인 함수 utils 폴더로 분리

* refactor: Card 컴포넌트 내부의 any 타입 제거

* refactor: nullable하지 않은 데이터에서 옵셔널 체이닝 제거

* refactor(InputBox): nullable하지 않은 데이터에서 옵셔널 체이닝 제거

* refactor: CardRegisterPage를 typescript로 마이그레이션

* refactor: 보안 코드의 에러 메세지에 left:0 스타일 적용

* refactor: 만료일 전체에 대한 유효성 검사 제거 (임시)

* feat: Input, Card, Header에 대한 스토리 북 구현

* feat: 등록한 카드 정보를 기억하기 위해 useLocalStorage 훅 구현

* refactor: localStorage 관련 로직을 hook이 아닌 utils로 변경

* refactor: utils 폴더로 분리

* refactor: 타입 정리

* refactor: Year 데이터를 렌더링 할 때, 불필요한 반복문 제거

* chore: 카드 회사 로고 이미지 폴더, 파일 생성

* chore: svg 모듈 declare 작성

* feat: 모달을 열고 닫는 기능 구현

* feat: 카드 회사 정보를 담은 constants 생성

* feat: 모달을 넣어주기 위한 Portal 구현

* feat: 카드사를 선택하는 컴포넌트의 템플릿 구현

* feat: 모달을 여는 클릭 이벤트 추가

* feat: 등록할 카드 정보에 대한 상태를 다루는 context 구현

* feat: 카드사의 정보를 표시

* refactor: 모달의 초기 상태를 외부에서 주입 받도록 변경

* feat: 카드의 닉네임을 표시

* feat: cardList에 대한 context 구현

* refactor: context파일 typescript로 마이그레이션

* refactor: useModalSwitch를  useSwitch로 범용성 있게 수정

* refactor: 폴더 내 파일 이름 구체화

* feat: overflow 히든 추가

* refactor: 폴더 구조 변경 및 폴더 별 내보내기 합치기

* refactor: useForm을 범용성 있게 변경

* refactor: cardInfo, cardList에 대한 Context 적용

* refactor: 상수에 타입 부여

* feat: modal-root 태그 추가

* chore: 파일 구조 변경 및 컴포넌트 파일 이름 구체화

* chore: react-hooks 테스팅 라이브러리 설치

* test: useSwitch hook 테스트 코드 작성

* chore: 불필요한 파일 삭제

* feat: form이 렌더링되면 input에 focus되도록 구현

* feat: form 화면에서 첫 input을 focus하는 기능 구현

* refactor: 닉네임 Input에 대한 스타일을 동적으로 변경하도록 변경

* chore: 폴더 구조 변경

* story: Card 컴포넌트에 대한 스토리 구현

* stody: Header 컴포넌트에 대한 스토리 구현

* stody: SelectBank 컴포넌트에 대한 스토리 구현

* feat: Input에 max-width 추가

* story: Input 컴포넌트에 대한 스토리 구현

* chore: import 개행 정리

* story: InputBox 컴포넌트들에 대한 스토리 구현

* story: 내보내기 이름 변경

* story: Page 컴포넌트에 대한 스토리 구현

* refactor: nullable하지 않은 객체에 대한 옵셔널 연산자 제거

* refactor: context에서 상태와 actions에 대한 타입 네로잉

* refactor: 카드사의 정보가 담긴 오브젝트에 반복문을 실행할 때 entries로 key와 value를 가져오도록 변경

* refactor: 삼항 연산자 대신 or, and 연산자를 사용하도록 변경

* refactor: 로컬 스토리지 로직을 custom hook으로 구현

* refactor: set 함수를 사용할 때, 이전 상태 값을 변경하도록 수정

* feat: errorOptions의 타입 지정

* feat: props.name이 nickname이 아닐 경우 border 지정
  • Loading branch information
jw-r committed May 3, 2023
1 parent 1aa6c2e commit 40469e2
Show file tree
Hide file tree
Showing 77 changed files with 1,776 additions and 640 deletions.
19 changes: 19 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
"@storybook/react-webpack5": "7.0.6",
"@storybook/testing-library": "^0.0.14-next.2",
"@types/styled-components": "5.1.26",
"@testing-library/react-hooks": "^8.0.1",
"@types/uuid": "^9.0.1",
"babel-plugin-named-exports-order": "0.0.2",
"eslint-config-prettier": "8.8.0",
Expand Down
29 changes: 2 additions & 27 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,14 @@
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<meta name="description" content="Web site created using create-react-app" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
<div id="modal-root"></div>
</body>
</html>
26 changes: 4 additions & 22 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,14 @@
import { useState } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { v4 as uuid } from 'uuid';
import MyCardPage from './pages/MyCardPage';
import CardRegisterPage from './pages/CardRegisterPage';
import { CardInfo } from './types/card';

const App = () => {
const [cardList, setCardList] = useState<CardInfo[]>([]);

const onChangeCardList = (values: any) => {
setCardList((prev) => [
{
id: uuid,
...values,
},
...prev,
]);
};
import { MyCardPage, CardRegisterPage } from './components/pages';

const App = () => {
return (
<div className="App">
<BrowserRouter basename={process.env.PUBLIC_URL}>
<Routes>
<Route path="/" element={<MyCardPage cardList={cardList} />} />
<Route
path="/register"
element={<CardRegisterPage onChangeCardList={onChangeCardList} />}
/>
<Route path="/" element={<MyCardPage />} />
<Route path="/register" element={<CardRegisterPage />} />
</Routes>
</BrowserRouter>
</div>
Expand Down
9 changes: 8 additions & 1 deletion src/GlobalStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ const GlobalStyles = createGlobalStyle`
${reset}
body{
padding:28px 24px;
margin:0 auto;
max-width: 600px;
height:100%;
Expand Down Expand Up @@ -33,6 +32,14 @@ const GlobalStyles = createGlobalStyle`
padding: 0;
cursor: pointer;
}
.App {
padding:28px 24px;
}
.overflowHidden {
overflow: hidden;
};
`;

export default GlobalStyles;
22 changes: 22 additions & 0 deletions src/__tests__/useSwitch.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { renderHook } from '@testing-library/react-hooks';
import { act } from 'react-dom/test-utils';

import useSwitch from '../hooks/useSwitch';

test('useSwitch hook 테스트', () => {
// useSwitch 훅을 사용한다. 초기 상태 값을 false로 설정한다
const { result } = renderHook(() => useSwitch(false));

// 상태 값의 초기 상태 값은 false이다
expect(result.current.state).toBe(false);

// state의 상태 값을 true로 변경한다
act(() => result.current.turnOn());

expect(result.current.state).toBe(true);

// state의 상태 값을 false로 변경한다
act(() => result.current.turnOff());

expect(result.current.state).toBe(false);
});
66 changes: 0 additions & 66 deletions src/__tests__/validator.test.js

This file was deleted.

30 changes: 19 additions & 11 deletions src/components/Card/Card.styled.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
import styled from 'styled-components';

export const Card = styled.div<any>`
interface CardProps {
bgColor?: string;
color?: string;
}

export const Card = styled.div<CardProps>`
position: relative;
width: 240px;
height: 150px;
padding: 12px 18px;
padding: 15px 18px;
background-color: ${(props: any) => props.bgColor};
color: white;
background-color: ${(props) => props.bgColor || 'black'};
color: ${(props) => props.color || 'white'};
box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.25);
border-radius: 5px;
letter-spacing: 1.5px;
&:not(:last-child) {
margin-bottom: 50px;
}
`;

export const Rectangle = styled.div`
Expand All @@ -36,11 +37,18 @@ export const Rectangle = styled.div`
export const CardInfos = styled.div`
display: flex;
flex-direction: column;
justify-content: flex-end;
justify-content: space-between;
height: 100%;
`;

export const BankName = styled.div`
font-size: 12px;
font-weight: 400;
`;

export const Bottom = styled.div``;

export const CardNumbers = styled.div`
display: flex;
justify-content: space-between;
Expand All @@ -67,12 +75,12 @@ export const Ellipse = styled.div`
border-radius: 50%;
background-color: white;
background-color: ${(props) => props.color || 'white'};
margin-right: 5px;
`;

export const CardBottomInfos = styled.div`
export const ExtraInfos = styled.div`
display: flex;
justify-content: space-between;
align-items: end;
Expand Down
52 changes: 52 additions & 0 deletions src/components/Card/Card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import * as styled from './Card.styled';

import { BANKS } from '../../constants';

import { CardInfo } from '../../types/card';

interface CardProps {
cardInfo: CardInfo;
}

const Card = ({ cardInfo }: CardProps) => {
return (
<styled.Card bgColor={BANKS[cardInfo.bank]?.bgColor} color={BANKS[cardInfo.bank]?.color}>
<styled.Rectangle />
<styled.CardInfos>
<styled.BankName>{BANKS[cardInfo.bank]?.name}</styled.BankName>
<styled.Bottom>
<styled.CardNumbers>
<div>{cardInfo.firstCardNumbers}</div>
<div>{cardInfo.secondCardNumbers}</div>
<styled.EllipseContainer>
{Array.from({ length: cardInfo.thirdCardNumbers.length }).map((_, index) => (
<styled.Ellipse key={index} color={BANKS[cardInfo.bank]?.color} />
))}
</styled.EllipseContainer>
<styled.EllipseContainer>
{Array.from({ length: cardInfo.fourthCardNumbers.length }).map((_, index) => (
<styled.Ellipse key={index} color={BANKS[cardInfo.bank]?.color} />
))}
</styled.EllipseContainer>
</styled.CardNumbers>
<styled.ExtraInfos>
<styled.CardOwnerName>
{cardInfo.ownerName ? cardInfo.ownerName : 'NAME'}
</styled.CardOwnerName>
<styled.ExpirationDate>
<styled.ExpirationMonth>
<span>{cardInfo.expirationMonth ? cardInfo.expirationMonth : 'MM'}</span>
</styled.ExpirationMonth>
<span>/</span>
<styled.ExpirationYear>
<span>{cardInfo.expirationYear || 'YY'}</span>
</styled.ExpirationYear>
</styled.ExpirationDate>
</styled.ExtraInfos>
</styled.Bottom>
</styled.CardInfos>
</styled.Card>
);
};

export default Card;
Loading

0 comments on commit 40469e2

Please sign in to comment.