Skip to content

kmin 과제 제출입니다. #1

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

Open
wants to merge 39 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
dcb0e31
feat: initial setting react, typescript, babel, webpack
KyungHan-Min Jul 4, 2021
2be16bb
add gitignore
KyungHan-Min Jul 4, 2021
aa60090
fix: remove .idea, dist
KyungHan-Min Jul 4, 2021
269a00e
webpack.config.ts 수정 \n devServer를 받을 수 있는 타입으로 설정
KyungHan-Min Jul 4, 2021
06b4dd0
fix: 불필요한 패키지 제거
KyungHan-Min Jul 4, 2021
a17ce88
feat: storybook init
Jul 5, 2021
e0b9359
feat: add card component 생성
Jul 5, 2021
27f3f69
feat: Add componenet 생성
Jul 5, 2021
8251705
fix: add Component position fix
Jul 5, 2021
64f7dca
feat: cardList component 생성
Jul 5, 2021
01299e9
feat: add component 분리
Jul 5, 2021
8d478fd
fix: storybook path resolve 에러 해결
KyungHan-Min Jul 5, 2021
ecabc1d
feat: label component 추가
KyungHan-Min Jul 6, 2021
1b8d0bb
feat: input에 forwardRef 사용
KyungHan-Min Jul 6, 2021
8865f6e
feat: flex-space-around 생성
KyungHan-Min Jul 6, 2021
7775f6e
feat: 카드 번호 입력 폼 생성
KyungHan-Min Jul 6, 2021
1b59505
feat: add form ref 위치 조정
KyungHan-Min Jul 6, 2021
ec895d7
feat: cardPublisherForm 추가
KyungHan-Min Jul 6, 2021
8cdbc2c
refactor: flexColumn, flexCenter 변경
KyungHan-Min Jul 6, 2021
55d8de7
feat: utils 생성
KyungHan-Min Jul 6, 2021
8a69d0d
feat: flex-between 컴포넌트 생성
KyungHan-Min Jul 6, 2021
8e366f2
feat: firstNumber ref 추가
KyungHan-Min Jul 6, 2021
bab4125
feat: password 컴포넌트 생성
KyungHan-Min Jul 6, 2021
77caaa3
style: 전체 폰트 적용
KyungHan-Min Jul 6, 2021
760403b
style: card style 변경
KyungHan-Min Jul 6, 2021
cf9c5f5
feat: card 컴포넌트 구현
KyungHan-Min Jul 6, 2021
97ab44d
style: card chip 추가
KyungHan-Min Jul 6, 2021
255cfae
refactor: cardConatiner children 변경
KyungHan-Min Jul 6, 2021
2ca0ddd
feat: cvc 컴포넌트 생성
KyungHan-Min Jul 6, 2021
a0d5eb1
feat: expireDate 컴포넌트 생성
KyungHan-Min Jul 6, 2021
bd03715
feat: password 컴포넌트 props 전달
KyungHan-Min Jul 6, 2021
196a0ff
feat: publisher 컴포넌트 props 전달
KyungHan-Min Jul 6, 2021
512af16
style: input style 변경
KyungHan-Min Jul 6, 2021
1442ba1
style: label style 변경
KyungHan-Min Jul 6, 2021
64f9b9a
docs: 기능 목록 1차 확인
KyungHan-Min Jul 6, 2021
aba57da
feat & refactoring: todo 해결과 리팩토링
KyungHan-Min Jul 7, 2021
07bc769
style: 배치 위치 조정
Jul 8, 2021
dfa739e
feat: virtual keyboard 추가
Jul 8, 2021
b754beb
feat: virtual keyboard ref를 주입받도록 수정
KyungHan-Min Jul 9, 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
7 changes: 7 additions & 0 deletions .babelrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"presets": [
"@babel/preset-env",
"@babel/preset-react",
"@babel/preset-typescript"
]
}
24 changes: 24 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"plugin:react/recommended",
"airbnb"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 12,
"sourceType": "module"
},
"plugins": [
"react",
"@typescript-eslint"
],
"rules": {
}
}
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
dist
.idea
*.log
8 changes: 8 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"useTabs": false,
"tabWidth": 2,
"singleQuote": true,
"trailingComma": "all",
"semi": true,
"endOfLine": "auto"
}
22 changes: 22 additions & 0 deletions .storybook/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const path = require('path');

module.exports = {
stories: ['../src/components/**/*.stories.@(js|jsx|ts|tsx)'],
addons: ['@storybook/addon-links', '@storybook/addon-essentials'],
webpackFinal: async (config) => {
config.resolve.alias['@components'] = path.resolve(
__dirname,
'../src/components',
);
config.resolve.alias['@constant'] = path.resolve(
__dirname,
'../src/constant',
);
config.resolve.alias['@utils'] = path.resolve(__dirname, '../src/utils');
config.resolve.alias['@types'] = path.resolve(
__dirname,
'../src/typesCards',
);
return config;
},
};
9 changes: 9 additions & 0 deletions .storybook/preview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const parameters = {
actions: { argTypesRegex: "^on[A-Z].*" },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
}
25 changes: 25 additions & 0 deletions REQUIREMENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# 카드 추가 폼
- 카드 번호
- [x] 자동 포커싱
- [x] 4자리번호 입력 완료시 다음 창으로 이동
- [ ] 6자리 입력 완료시 카드사 매칭
- [ ] 매칭되는 카드사가 없는 경우 카드사 선택 모달
- [x] 뒤에서부터 8자리의 카드번호는 마스킹 처리
- [x] 카드 번호는 실시간으로 카드에 반영
- [x] 카드 번호 입력 완료시 카드 만료일로 포커싱 이동
- 카드 만료시기
- [x] MM(월) 입력이 완료되면 YY(년) 입력으로 포커스 이동
- [x] 4자리 모두 입력시 카드 소유자로 포커싱 이동
- 카드 소유자
- [ ] 알파벳만 입력가능
- [ ] 알파벳 대문자로 항상 적용
- [ ] 이름은 30자 이내만 가능
- 보안 코드
- [x] 입력시 마스킹처리
- [ ] 3자리 입력시 비밀번호 창으로 포커스 이동
- 비밀번호
- [x] 입력시 마스킹 처리
- 카드 등록
- [ ] 모든 입력이 완료됐을 시 활성화
# 카드 확인
- 등록된 카드가 표시된다.
58 changes: 58 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"name": "react-payments",
"version": "1.0.0",
"description": "<p align=\"middle\" >\r <img src=\"https://techcourse-storage.s3.ap-northeast-2.amazonaws.com/0fefce79602043a9b3281ee1dd8f4be6\" width=\"400\">\r </p>\r <h2 align=\"middle\">Level2 - 페이먼츠</h2>\r <p align=\"middle\">React 모바일 페이먼츠 애플리케이션</p>\r </p>",
"main": "index.js",
"scripts": {
"start": "webpack serve",
"build": "webpack --config webpack.config.ts --watch",
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook"
},
"repository": {
"type": "git",
"url": "git+https://github.com/kmin-283/react-payments.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/kmin-283/react-payments/issues"
},
"homepage": "https://github.com/kmin-283/react-payments#readme",
"devDependencies": {
"@babel/core": "^7.14.6",
"@babel/preset-env": "^7.14.7",
"@babel/preset-react": "^7.14.5",
"@babel/preset-typescript": "^7.14.5",
"@babel/register": "^7.14.5",
"@storybook/addon-actions": "^6.3.2",
"@storybook/addon-essentials": "^6.3.2",
"@storybook/addon-links": "^6.3.2",
"@storybook/react": "^6.3.2",
"@types/node": "^16.0.0",
"@types/react": "^17.0.13",
"@types/react-dom": "^17.0.8",
"@types/webpack": "^5.28.0",
"@types/webpack-dev-server": "^3.11.5",
"@typescript-eslint/eslint-plugin": "^4.28.1",
"@typescript-eslint/parser": "^4.28.1",
"babel-loader": "^8.2.2",
"css-loader": "^5.2.6",
"eslint": "^7.30.0",
"eslint-config-airbnb": "^18.2.1",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-jsx-a11y": "^6.4.1",
"eslint-plugin-react-hooks": "^4.2.0",
"prettier": "^2.3.2",
"style-loader": "^3.0.0",
"typescript": "^4.3.5",
"webpack": "^5.42.0",
"webpack-cli": "^4.7.2",
"webpack-dev-server": "^3.11.2"
},
"dependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2"
}
}
18 changes: 18 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="description" content="react-payments">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100;300;400;500;700;900&display=swap" rel="stylesheet">
<title>Payments</title>
</head>
<body>
<div id="app"></div>
<script src='../dist/app.js'></script>
</body>
</html>
4 changes: 4 additions & 0 deletions src/app.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#app {
font-family: 'Noto Sans KR', sans-serif;
box-sizing: border-box;
}
47 changes: 47 additions & 0 deletions src/app.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React, { useState } from 'react';
import { View } from '@constant/constant';
import CardList from '@components/CardList/cardList';
import CardAddForm from '@components/CardAddForm/cardAddForm';
import Card from '@typesCards/types.cards';
import './app.css';

const App = () => {
const [currentView, setCurrentView] = useState<View>(View.List);
const [cardList, setCardList] = useState<Card[]>([
{
cardBrand: 'blue-card',
cardNumber: ['1234', '1234', '1234', '1234'],
expDate: '0123',
publisher: 'person A',
cvc: '123',
password: '1234',
nickname: '파랑이 좋겠어',
},
{
cardBrand: 'red-card',
cardNumber: ['3456', '3456', '3456', '3456'],
expDate: '1223',
publisher: 'person A',
cvc: '123',
password: '1234',
nickname: '빨강이 좋겠어',
},
]);

return (
<>
{currentView === View.List && (
<CardList cardList={cardList} onClick={setCurrentView} />
)}
{currentView === View.Add && (
<CardAddForm
cardList={cardList}
setCurrentView={setCurrentView}
setCardList={setCardList}
/>
)}
</>
);
};

export default App;
74 changes: 74 additions & 0 deletions src/components/CardAddComplete/cardAddComplete.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React, { Dispatch, SetStateAction, useState } from 'react';
import Label from '@components/share/Label/label';
import Input from '@components/share/Input/input';
import Button from '@components/share/Button/button';
import { View } from '@constant/constant';
import Card from '@typesCards/types.cards';

interface CardAddCompleteProps {
cardList: Card[];
brandName: string;
firstNumbers: string;
secondNumbers: string;
thirdNumbers: string;
fourthNumbers: string;
expireDate: string;
publisher: string;
cvc: string;
password: string;
setCurrentView: Dispatch<SetStateAction<View>>;
setCardList: Dispatch<SetStateAction<Card[]>>;
}

const CardAddComplete = ({
cardList,
brandName,
firstNumbers,
secondNumbers,
thirdNumbers,
fourthNumbers,
setCurrentView,
setCardList,
expireDate,
publisher,
cvc,
password,
}: CardAddCompleteProps) => {
const [nickname, setNickname] = useState('기본 카드');
const handleNicknameChange = ({ target }: { target: HTMLInputElement }) => {
setNickname(target.value);
};
const goToCardList = (event: Event) => {
event.preventDefault();
const newCard: Card = {
cardBrand: brandName,
cardNumber: [firstNumbers, secondNumbers, thirdNumbers, fourthNumbers],
expDate: expireDate,
publisher,
cvc,
password,
nickname,
};
setCurrentView(View.List);
setCardList([...cardList, newCard]);
};
return (
<>
<Label value={'카드 등록이 완료되었습니다!'}>
<Input
placeholder={'별칭을 입력해주십시오...'}
value={nickname}
onChange={handleNicknameChange}
/>
<Button
variant={'active'}
value={'완료'}
position={'bottom-right'}
onClick={goToCardList}
/>
</Label>
</>
);
};

export default CardAddComplete;
Loading