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

[Typescript] react-payments #2

Open
wants to merge 41 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
6c61808
chore: cra, eslint, prettier
hochan222 Jun 14, 2021
ead657e
chore: huskyrc 설정
hochan222 Jun 15, 2021
12c89ff
chore: huskyrc 설정
hochan222 Jun 15, 2021
6ff2473
chore: husky eslint setting
hochan222 Jun 15, 2021
7f5a6ca
이 커밋이 차단되기를 바랍니다.
hochan222 Jun 15, 2021
efd261d
이 커밋이 차단되기를 바랍니다.
hochan222 Jun 15, 2021
d5c4c69
이 커밋이 차단되기를 바랍니다.
hochan222 Jun 15, 2021
fc5538d
이 커밋이 차단되기를 바랍니다.
hochan222 Jun 15, 2021
a12ecc3
이 커밋이 차단되기를 바랍니다.
hochan222 Jun 15, 2021
f998299
이 커밋이 차단되기를 바랍니다.
hochan222 Jun 15, 2021
a3aad88
이 커밋이 차단되기를 바랍니다.
hochan222 Jun 15, 2021
fd7a155
test: 제발 블록 돼줘...
hochan222 Jun 15, 2021
eb91a91
fix: test err
hochan222 Jun 15, 2021
f4c53c9
chore: package script option 설정
hochan222 Jun 15, 2021
0d54399
chore: package script option 설정
hochan222 Jun 15, 2021
4f3d573
fix: jest err
hochan222 Jun 15, 2021
dd300f5
chore: prettierrc option 추가
hochan222 Jun 15, 2021
ef75ed4
chore: tsconfig.json, noImplicityAny: ture
hochan222 Jun 15, 2021
e8cf110
docs: 요구사항 작성
hochan222 Jun 15, 2021
7de1a6b
chore: react typescript husky storybook boilerplate
hochan222 Jun 17, 2021
179aefe
feat: container presenter pattern 틀 만들기
hochan222 Jun 17, 2021
2d8d461
chore: add scss
hochan222 Jun 17, 2021
cacc045
chore: remove 'import/no-unresolved'
hochan222 Jun 17, 2021
1ab66a7
style: MainLayout__Wrapper 구현
hochan222 Jun 17, 2021
bc80728
chore: gh-pages 추가
hochan222 Jun 17, 2021
d7c3d7e
style: Card 컴포넌트 구현중. 중간 저장
hochan222 Jun 17, 2021
756c4a5
feat: 버튼 기능 구현
hochan222 Jun 17, 2021
f466d42
feat: 버튼 기능 구현
hochan222 Jun 17, 2021
1de9593
feat: button component onclick 추가
hochan222 Jun 18, 2021
8c36a5f
feat: card component 구현 완료
hochan222 Jun 18, 2021
4d5bb91
feat: card form 구현 완료 스타일링 남음
hochan222 Jun 18, 2021
ee76060
feat: cardForm 디자인 완료
hochan222 Jun 19, 2021
f54ec46
feat: 입력된 번호가 카드 이미지에 실시간으로 표시된다.
hochan222 Jun 19, 2021
21abfb4
feat: portal 기능 구현 완료
hochan222 Jun 19, 2021
ba378fc
refactor: presenter container 로 분리 완료
hochan222 Jun 19, 2021
b2ae0f8
feat: input maxLength 추가
hochan222 Jun 19, 2021
83558b7
feat: ghpages ㅂㅐ포용으로 바꿈
hochan222 Jun 19, 2021
5bd14a2
feat: add Router basename
hochan222 Jun 19, 2021
63643bc
feat: error message 기본 기능 구현
hochan222 Jun 21, 2021
2bb840c
feat: forwardRef 로 input component 변경
hochan222 Jun 21, 2021
2a3d592
feat: focus 자동이동 구현
hochan222 Jun 21, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SKIP_PREFLIGHT_CHECK=true
33 changes: 33 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 2020,
sourceType: 'module',
},
settings: {
react: {
version: 'detect',
},
},
extends: [
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:@typescript-eslint/recommended',
'plugin:import/errors',
'plugin:import/warnings',
'plugin:import/typescript',
'plugin:jsx-a11y/recommended',
'plugin:eslint-comments/recommended',
'prettier/@typescript-eslint',
'plugin:prettier/recommended',
],
rules: {
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': ['error'],
'@typescript-eslint/no-var-requires': 'off',
'react/prop-types': 'off',
'react/jsx-uses-react': 'off',
'react/react-in-jsx-scope': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
},
};
25 changes: 25 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

/build

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
8 changes: 8 additions & 0 deletions .prettierrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
semi: true,
printWidth: 120,
endOfLine: 'auto',
singleQuote: true,
trailingComma: 'all',
arrowParens: 'always'
};
2 changes: 2 additions & 0 deletions .storybook/addons.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import '@storybook/addon-actions/register';
import '@storybook/addon-knobs/register';
7 changes: 7 additions & 0 deletions .storybook/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { configure } from "@storybook/react";
import requireContext from "require-context.macro";
const req = requireContext("../src", true, /\.stories\.tsx$/);
function loadStories() {
req.keys().forEach(req);
}
configure(loadStories, module);
11 changes: 11 additions & 0 deletions .storybook/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module.exports = ({ config, mode }) => {
config.module.rules.push({
test: /\.(ts|tsx)$/,
loader: require.resolve('babel-loader'),
options: {
presets: [['react-app', { flow: false, typescript: true }]],
},
});
config.resolve.extensions.push('.ts', '.tsx');
return config;
};
5 changes: 5 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"powermode.enabled": true,
"powermode.enableShake": false
}
77 changes: 4 additions & 73 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,74 +1,5 @@
<p align="middle" >
<img src="https://techcourse-storage.s3.ap-northeast-2.amazonaws.com/0fefce79602043a9b3281ee1dd8f4be6" width="400">
</p>
<h2 align="middle">Level2 - 페이먼츠</h2>
<p align="middle">React 모바일 페이먼츠 애플리케이션</p>
</p>
https://hochan222.github.io/react-payments/

## 🚀 Getting Started

> `Component-Driven Development` 에 따라 UI를 구성하고 재사용 가능한 `Component`를 작성합니다.

✔️ `모바일 타겟`의 웹 앱을 구현하며 사용하기 `편리한 모바일 UI/UX`에 대해 고민해봅니다.
✔️ 다른 라이브러리나 프레임워크 없이 오로지 `React`만으로 상태를 관리하고 컴포넌트를 설계합니다.
✔️ React `Hooks API`를 활용합니다.
✔️ `재사용 가능한 Component`를 직접 작성하고 사용합니다.
✔️ `Controlled` & `Uncontrolled Components`에 입각하여 `Form`을 핸들링합니다.

## 📝 Requirements

### 공통 요구사항

- [ ] `Storybook` 상호 작용 테스트

### Step1

> 권장 마감기한 - **4월 27일 화요일**

- [ ] `REQUIREMENTS.md`에 요구 사항 도출
- [ ] `재사용 가능한 Component` 작성

##### 필수 구현

- [ ] 카드 추가 폼
- [ ] 카드 추가 확인

### 심화 요구사항

- [ ] `Storybook` 단위 테스트
- [ ] 유효성 검증 실패에 대한 UI/UX 추가
- [ ] 가상 키보드
- [ ] 마스킹 처리된 값 입력시 사용
- [ ] 숫자를 랜덤으로 배열

### Step2

> 권장 마감기한 - **5월 4일 화요일**

### 필수 요구사항

- [ ] `Controlled` & `Uncontrolled Components`에 입각하여 `Form` 핸들링
- [ ] `Context API`를 활용해 전역 상태 관리 및 계층 재구성

#### 필수 구현

- [ ] 카드 목록

### 심화 요구사항

- [ ] `Storybook` 스냅샷 테스트
- [ ] 비동기 통신
- [ ] 다양한 도구를 활용 (예 JSON Server, Strapi 등등)
- [ ] 등록된 카드 정보를 CRUD 합니다.
- [ ] 나열된 카드 클릭시 `카드 추가 확인` 화면 재활용
- [ ] 별칭 수정 가능

## 👏 Contributing

만약 미션 수행 중에 개선사항이 보인다면, 언제든 자유롭게 PR을 보내주세요.

<br>

## 🐞 Bug Report

버그를 발견한다면, [Issues](https://github.com/woowacourse/react-payments/issues)에 등록해주세요.
- SyntheticEvent
- object pooling
- React 17 에서는 Event Pooling 이 제거돼서 `e.persist()`는 아무런 영향을 주지못한다.
74 changes: 74 additions & 0 deletions REQUIREMENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# 요구 사항

## Step1

### 공통

- [ ] REQUIREMENTS.md에 요구 사항 도출
- [ ] 재사용 가능한 Component 작성

### 카드 목록 화면

- [ ] 카드 추가 버튼(이미지)를 클릭하면 카드 추가 폼 화면이 표시된다.

### 카드 추가 폼 화면

- 데이터 형식

```
{
Type: {
name: '',
color: ''
},
Number: '',
ExpirationDate: {
month: '',
year: ''
},
OwnerName: '',
CVC: '',
Password: '',
nickname: ''
}
```

- 카드 번호
- [x] 입력전 기본 카드 이미지에는 '\_**\_-\_\_**-\_**\_-\_\_**' 가 출력된다.
- [x] 카드 번호 입력 폼이 자동으로 포커싱 된다.
- [x] 입력된 번호가 카드 이미지에 실시간으로 표시된다.
- [x] 네 자리 입력 완료시 다음 입력창으로 자동으로 넘어간다.
- [x] 8자리까지 입력 헀을 때, 매칭되는 카드사가 있을 경우, 카드사가 자동으로 선택된다.
- [x] 8자리까지 입력 했을 때, 매칭되는 카드사가 없을 경우, 카드사 선택 모달이 표시된다.
- [x] 카드사 버튼을 클릭했을 때, 카드사를 선택 할 수 있다.
- [ ] 모달의 Dimmed 영역을 클릭해서, 모달을 닫을 수 있다.
- [x] 카드번호 9자리부터 표시되는 카드 이미지에 마스킹되서 표시된다.
- [x] 16자리 번호를 모두 입력하면, 만료일 입력창으로 자동으로 넘어간다.
- 카드 만료일
- [x] 입력전 기본 카드 이미지에는 'MM/YY'가 출려된다.
- [x] 월 2자리 입력이 완료되면 연 2자리 입력창으로 자동으로 포커싱 된다.
- [x] 4자리를 모두 입력하면, 카드 소유자 이름 입력창으로 자동으로 넘어간다.
- [x] 카드 만료일이 카드 이미지에 실시간으로 표시한다.
- [x] 유효한 달을 입력하지 않으면 `유효한 달을 입력해주세요.` 에러메세지가 뜬다.
- 카드 소유자 이름
- [x] 입력전 기본 카드 이미지에는 'NAME이 출력된다.
- [x] 입력된 글자가 카드 이미지에 실시간으로 표시된다.
- [x] 이름 글자는 18자를 넘지 않는다.
- [x] 소문자를 입력해도 자동으로 대문자로 전환해준다.
- [x] 알파벳, 한글만 입력 가능하다.
- 보안 코드
- [ ] 입력 시 마스킹되어 표시된다.
- [ ] 물음표 hover 이벤트로 안내 설명 모달이 표시된다.
- [x] 3자리를 모두 입력하면 카드 비밀번호 입력창으로 포커스가 넘어간다.
- 카드 비밀번호
- [x] 입력 시 마스킹되어 표시된다.
- 카드 등록
- [ ] 모든 칸이 완전할 때, '등록' 버튼을 클릭할 수 있다.
- 공통
- 카드 번호에 불완전한 입력이 있을 때,
- [ ] 빨간색 테두리가 표시된다.
- [x] 안내 문구가 빨간색으로 표시된다.

### 카드 추가 확인 화면

- [ ] 카드 목록 화면에서 등록된 카드의 이미지를 확인 할 수 있다.
85 changes: 85 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
{
"name": "react-ts-storybook",
"version": "0.1.0",
"private": true,
"dependencies": {
"@types/jest": "24.0.15",
"@types/node": "12.0.12",
"@types/react": "16.8.23",
"@types/react-dom": "16.8.4",
"classnames": "^2.3.1",
"node-sass": "yarn:sass",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-router-dom": "^5.2.0",
"react-scripts": "3.0.1",
"typescript": "3.4.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"lint": "eslint --fix \"./src/**/*.{js,jsx,ts,tsx,json}\"",
"format": "prettier --write \"./src/**/*.{js,jsx,ts,tsx,json,css,scss,md}\"",
"storybook": "start-storybook -p 9009 -s public",
"build-storybook": "build-storybook -s public",
"predeploy": "yarn build",
"deploy": "gh-pages -d build"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@storybook/addon-actions": "^5.1.9",
"@storybook/addon-knobs": "^5.1.9",
"@storybook/addon-storyshots": "^5.1.9",
"@storybook/react": "^5.1.9",
"@types/react-router-dom": "^5.1.7",
"@types/storybook__addon-knobs": "^5.0.2",
"@types/storybook__addon-storyshots": "^4.0.1",
"@types/storybook__react": "^4.0.2",
"@typescript-eslint/eslint-plugin": "^4.27.0",
"@typescript-eslint/parser": "^4.27.0",
"eslint": "^7.19.0",
"eslint-config-prettier": "^7.2.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-react": "^7.22.0",
"eslint-plugin-react-hooks": "^4.2.0",
"gh-pages": "^3.2.1",
"husky": "4",
"lint-staged": "^10.5.4",
"prettier": "^2.2.1",
"react-test-renderer": "^16.8.6",
"require-context.macro": "^1.0.4"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"src/**/*.{js,jsx,ts,tsx,json}": [
"eslint --fix"
],
"src/**/*.{js,jsx,ts,tsx,json,css,scss,md}": [
"prettier --write"
]
},
"homepage": "https://hochan222.github.io/react-payments/"
}
Binary file added public/favicon.ico
Binary file not shown.
39 changes: 39 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<!--
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>
<div id="portal-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`.
-->
</body>
</html>
15 changes: 15 additions & 0 deletions public/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
Loading