-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[1단계 - 행운의 로또미션] 하루(김하루) 미션 제출합니다. (#8)
* docs: 1단계 구현 기능 목록 작성 * chore: 코드포매터, 린터 초기 설정 Co-authored-by: JUNMO HAN <wnsah052@naver.com> * feat: 앱 전체 구조 설정 Co-authored-by: JUNMO HAN <wnsah052@naver.com> * fix: index.html 경로 수정 Co-authored-by: 365kim <365kim@users.noreply.github.com> * chore: lottie 설치, 린터 설정 추가 Co-authored-by: 365kim <365kim@users.noreply.github.com> * docs: 구현 기능 목록 수정 Co-authored-by: 365kim <365kim@users.noreply.github.com> * feat: 구입금액 입력 컴포넌트 구현 Co-authored-by: 365kim <365kim@users.noreply.github.com> * feat: 로또 발급 및 확인 컴포넌트 구현 Co-authored-by: 365kim <365kim@users.noreply.github.com> * refactor: 삼항연산자 대신 단축평가 사용 Co-authored-by: JUNMO HAN <wnsah052@naver.com> * feat: 표시되는 로또 번호의 자릿수 맞춤 * refactor: 로또 배열의 key값 수정 Co-authored-by: JUNMO HAN <wnsah052@naver.com> * feat: 당첨번호 발표 컴포넌트 구현 Co-authored-by: JUNMO HAN <wnsah052@naver.com> * feat: 당첨결과 확인 컴포넌트 구현 Co-authored-by: JUNMO HAN <wnsah052@naver.com> * refactor: 당첨번호 JSON에서 가져오도록 변경 Co-authored-by: JUNMO HAN <wnsah052@naver.com> * feat: 로또볼 CSS 스타일링 및 메인색상 적용 * feat: 애니메이션 구현 Co-authored-by: 365kim <365kim@users.noreply.github.com> * feat: 구매한 복권별 당첨 여부 확인 기능 구현 * chore: 회차 당첨번호 현행화 * refactor: 변수명 수정 * fix: 콘솔 에러 수정 * refactor: 컴포넌트 구조 변경 * refactor: 재정렬 가능성 없는 배열의 key값 index로 설정 * refactor: getMatchCount 함수에 reduce 활용 * refactor: getStatistics -> getComputedResult 이름 변경 * refactor: shouldPlayAnimation -> isLoading 이름 변경 * refactor: 버튼 스타일 변경 * refactor: 불필요한 클래스 삭제 * refactor: HTML 태그 변경 및 삭제 * refactor: CSS 클래스 제어 및 BEM 네이밍 적용 * refactor: App.js에 initialState 추가 * refactor: 리팩토링에 따른 네이밍 통일 * refactor: <Lottie /> props 스프레드로 전달 * refactor: let 대신 const 사용 * refactor: props 중 자식요소 네이밍 변경 Co-authored-by: Jbee <ljyhanll@gmail.com> * refactor: props 중 자식요소 네이밍 변경 Co-authored-by: Jbee <ljyhanll@gmail.com> * refactor: 버튼의 필수 props 외에는 스프레드로 전달 Co-authored-by: Jbee <ljyhanll@gmail.com> * chore: 브랜치 병합 * refactor: Classnames 라이브러리 적용 * refactor: String 내장메서드 padStart 적용 * refactor: Plain/SubmitButton -> Button컴포넌트로 통합 * refactor: <Record> 생성, <ResultSummary> 삭제 Co-authored-by: JUNMO HAN <wnsah052@naver.com> Co-authored-by: 365kim <365kim@users.noreply.github.com> Co-authored-by: Jbee <ljyhanll@gmail.com>
- Loading branch information
1 parent
be409b4
commit 174ea4c
Showing
51 changed files
with
12,926 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
{ | ||
"env": { | ||
"browser": true | ||
}, | ||
"extends": ["airbnb", "airbnb/hooks", "plugin:prettier/recommended"], | ||
"plugins": ["prettier"], | ||
"parserOptions": { | ||
"sourceType": "module" | ||
}, | ||
"parser": "babel-eslint", | ||
"rules": { | ||
"no-new": "off", | ||
"no-alert": "off", | ||
"no-param-reassign": "off", | ||
"no-return-assign": "off", | ||
"import/extensions": "off", | ||
"import/prefer-default-export": "off", | ||
"max-depth": ["error", 1], | ||
"react/react-in-jsx-scope": "off", | ||
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], | ||
"react/jsx-one-expression-per-line": "off", | ||
"react/prefer-stateless-function": "off", | ||
"react/prop-types": "off", | ||
"react/destructuring-assignment": "off", | ||
"max-classes-per-file": ["error", 3] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
||
# 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* | ||
|
||
# editor | ||
.vscode/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"semi": true, | ||
"useTabs": false, | ||
"tabWidth": 2, | ||
"printWidth": 100, | ||
"endOfLine": "auto", | ||
"singleQuote": true, | ||
"arrowParens": "always", | ||
"trailingComma": "all" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
{ | ||
"name": "1st-react-lotto", | ||
"version": "0.1.0", | ||
"private": true, | ||
"dependencies": { | ||
"@testing-library/jest-dom": "^5.11.4", | ||
"@testing-library/react": "^11.1.0", | ||
"@testing-library/user-event": "^12.1.10", | ||
"babel-eslint": "^10.1.0", | ||
"classnames": "^2.3.1", | ||
"react": "^17.0.2", | ||
"react-dom": "^17.0.2", | ||
"react-lottie": "^1.2.3", | ||
"react-scripts": "4.0.3", | ||
"web-vitals": "^1.0.1" | ||
}, | ||
"scripts": { | ||
"start": "react-scripts start", | ||
"build": "react-scripts build", | ||
"test": "react-scripts test", | ||
"eject": "react-scripts eject" | ||
}, | ||
"eslintConfig": { | ||
"extends": [ | ||
"react-app", | ||
"react-app/jest" | ||
] | ||
}, | ||
"browserslist": { | ||
"production": [ | ||
">0.2%", | ||
"not dead", | ||
"not op_mini all" | ||
], | ||
"development": [ | ||
"last 1 chrome version", | ||
"last 1 firefox version", | ||
"last 1 safari version" | ||
] | ||
}, | ||
"devDependencies": { | ||
"eslint": "^7.24.0", | ||
"eslint-config-airbnb": "^18.2.1", | ||
"eslint-config-prettier": "^8.1.0", | ||
"eslint-plugin-prettier": "^3.3.1", | ||
"prettier": "^2.2.1" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1" /> | ||
<meta name="description" content="Lotto App" /> | ||
<title>🎱 행운의 로또</title> | ||
</head> | ||
<body> | ||
<div id="root"></div> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
/* eslint-disable react/sort-comp */ | ||
import { Component } from 'react'; | ||
import PurchaseForm from '../containers/PurchaseForm'; | ||
import UserLotto from '../containers/UserLotto'; | ||
import WinningNumbers from '../containers/WinningNumbers'; | ||
import UserResult from '../containers/UserResult'; | ||
import { createLotto } from './service'; | ||
import './style.css'; | ||
|
||
const initialState = { | ||
lottoBundle: [], | ||
winningNumber: {}, | ||
shouldReset: false, | ||
isShowingUserResult: false, | ||
}; | ||
export default class App extends Component { | ||
constructor() { | ||
super(); | ||
|
||
this.state = { ...initialState }; | ||
this.onPurchaseLotto = this.onPurchaseLotto.bind(this); | ||
this.setWinningNumber = this.setWinningNumber.bind(this); | ||
this.onShowUserResult = this.onShowUserResult.bind(this); | ||
this.onCloseUserResult = this.onCloseUserResult.bind(this); | ||
this.onReset = this.onReset.bind(this); | ||
this.didReset = this.didReset.bind(this); | ||
} | ||
|
||
onPurchaseLotto({ numOfLotto }) { | ||
this.setState({ lottoBundle: [...Array(numOfLotto)].map(() => createLotto()) }); | ||
} | ||
|
||
setWinningNumber({ winningNumber }) { | ||
this.setState({ winningNumber }); | ||
} | ||
|
||
onShowUserResult() { | ||
this.setState({ isShowingUserResult: true }); | ||
} | ||
|
||
onCloseUserResult() { | ||
this.setState({ isShowingUserResult: false }); | ||
} | ||
|
||
onReset() { | ||
this.setState({ ...initialState, shouldReset: true }); | ||
} | ||
|
||
didReset() { | ||
this.setState({ shouldReset: false }); | ||
} | ||
|
||
render() { | ||
const { lottoBundle, winningNumber, isShowingUserResult, shouldReset } = this.state; | ||
const isPurchased = Boolean(lottoBundle.length); | ||
|
||
return ( | ||
<> | ||
<main className="App__main"> | ||
<h1 className="App__title">행운의 로또</h1> | ||
<PurchaseForm | ||
lottoBundle={lottoBundle} | ||
onPurchaseLotto={this.onPurchaseLotto} | ||
shouldReset={shouldReset} | ||
didReset={this.didReset} | ||
/> | ||
{isPurchased && ( | ||
<> | ||
<UserLotto lottoBundle={this.state.lottoBundle} /> | ||
<WinningNumbers | ||
setWinningNumber={this.setWinningNumber} | ||
onShowUserResult={this.onShowUserResult} | ||
/> | ||
</> | ||
)} | ||
</main> | ||
{isShowingUserResult && ( | ||
<UserResult | ||
lottoBundle={lottoBundle} | ||
winningNumber={winningNumber} | ||
onCloseUserResult={this.onCloseUserResult} | ||
onReset={this.onReset} | ||
/> | ||
)} | ||
</> | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { getRandomNumber } from '../../utils'; | ||
import { LOTTO_MIN_NUMBER, LOTTO_MAX_NUMBER, LOTTO_NUMBERS_LENGTH } from '../../constants'; | ||
|
||
export const createLotto = (array = []) => { | ||
const number = getRandomNumber({ min: LOTTO_MIN_NUMBER, max: LOTTO_MAX_NUMBER }); | ||
|
||
if (array.length === LOTTO_NUMBERS_LENGTH) { | ||
return array.sort((a, b) => a - b); | ||
} | ||
if (!array.includes(number)) { | ||
array.push(number); | ||
} | ||
|
||
return createLotto(array); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
.App__main { | ||
position: absolute; | ||
top: 3rem; | ||
left: 50%; | ||
transform: translateX(-50%); | ||
background-color: rgba(0, 0, 0, 0.005); | ||
padding: 3.5rem 2.5rem; | ||
border-radius: 1.5rem; | ||
width: 400px; | ||
min-height: 440px; | ||
box-shadow: 6px 10px 20px rgb(0, 0, 0, 0.15); | ||
} | ||
|
||
.App__title { | ||
text-align: center; | ||
color: #333; | ||
font-size: 1.5rem; | ||
margin: 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
/* eslint-disable jsx-a11y/label-has-associated-control */ | ||
import React, { Component } from 'react'; | ||
import { Button } from '../../shared'; | ||
import { validatePurchaseAmount, payForLotto } from './service'; | ||
import { MESSAGE } from '../../../constants'; | ||
import './style.css'; | ||
|
||
export default class PurchaseForm extends Component { | ||
constructor(props) { | ||
super(props); | ||
|
||
this.state = { | ||
validationMessage: '', | ||
isInputDisabled: false, | ||
isSubmitButtonDisabled: true, | ||
}; | ||
this.paymentInput = React.createRef(); | ||
this.onChangeInput = this.onChangeInput.bind(this); | ||
this.onSubmit = this.onSubmit.bind(this); | ||
} | ||
|
||
componentDidMount() { | ||
this.paymentInput.current.focus(); | ||
} | ||
|
||
componentDidUpdate() { | ||
if (this.props.shouldReset) { | ||
this.paymentInput.current.value = ''; | ||
this.paymentInput.current.disabled = false; | ||
this.paymentInput.current.focus(); | ||
this.props.didReset(); | ||
} | ||
} | ||
|
||
onSubmit(e) { | ||
e.preventDefault(); | ||
|
||
const money = e.target.input.value; | ||
const { change, numOfLotto } = payForLotto(money); | ||
|
||
if (change > 0) { | ||
alert(MESSAGE.PURCHASE_AMOUNT_HAS_CHANGE(change)); | ||
} | ||
|
||
this.props.onPurchaseLotto({ numOfLotto }); | ||
this.setState({ isInputDisabled: true, isSubmitButtonDisabled: true }); | ||
} | ||
|
||
onChangeInput(e) { | ||
const money = e.target.value; | ||
const { validationMessage, isSubmitButtonDisabled } = validatePurchaseAmount(money); | ||
|
||
this.setState({ validationMessage, isSubmitButtonDisabled }); | ||
} | ||
|
||
render() { | ||
const { validationMessage, isInputDisabled, isSubmitButtonDisabled } = this.state; | ||
|
||
return ( | ||
<div> | ||
<form className="PurchaseForm" onSubmit={this.onSubmit}> | ||
<label className="PurchaseForm__label"> | ||
<span className="PurchaseForm__text">구입할 금액을 입력해주세요.</span> | ||
<input | ||
className="PurchaseForm__input" | ||
name="input" | ||
type="number" | ||
placeholder="구입 금액" | ||
onChange={this.onChangeInput} | ||
ref={this.paymentInput} | ||
disabled={isInputDisabled} | ||
/> | ||
</label> | ||
<div className="PurchaseForm__button_wrapper"> | ||
<Button | ||
type="submit" | ||
className="PurchaseForm__button" | ||
disabled={isSubmitButtonDisabled} | ||
> | ||
구매 | ||
</Button> | ||
</div> | ||
</form> | ||
<div className="ValidationMessage">{validationMessage}</div> | ||
</div> | ||
); | ||
} | ||
} |
Oops, something went wrong.