Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
7b216b6
docs: UI 기반 로또 미션 요구사항 명세서 작성
GamjaIsMine02 Mar 11, 2026
fa37771
init: UI 기반 렌더링 초기 세팅 및 전역 속성 디자인 추가
GamjaIsMine02 Mar 11, 2026
1bb5d05
feat: Header.js 구현 및 전역 텍스트 속성 추가
GamjaIsMine02 Mar 11, 2026
c56ced8
feat: Footer.js 구현
GamjaIsMine02 Mar 11, 2026
5e96b6d
docs: css 속성 작성 순서 추가
GamjaIsMine02 Mar 11, 2026
1258512
feat: MainApp.js 생성 및 구입 금액 폼 구현
GamjaIsMine02 Mar 11, 2026
b060e53
feat: 구입한 로또 아이콘과 번호 렌더링
GamjaIsMine02 Mar 11, 2026
4eea726
feat: 당첨 번호 & 보너스 번호 입력 폼, 결과 확인하기 버튼 구현
GamjaIsMine02 Mar 12, 2026
e508fbb
feat: 결과 확인하기 버튼 및 모달 닫기 버튼 이벤트 연결, 당첨 통계 모달 구현
GamjaIsMine02 Mar 12, 2026
6fa98a6
feat: 로또 테이블 스크롤링 및 텍스트 추가
GamjaIsMine02 Mar 12, 2026
68823e9
refactor: 구입 금액 입력 폼 및 텍스트 UI 분리, 구입 금액 유효성 검사 추가
GamjaIsMine02 Mar 12, 2026
36bc068
fix: 구입 로또 테이블 세로 크기를 고정 크기로 변경
GamjaIsMine02 Mar 12, 2026
9e27d0d
feat: 구입 금액 에러 메세지 구현, 발급 후 구입 금액을 받을 경우 다시 구입 로또 테이블과 당첨번호 & 보너스번호 입…
GamjaIsMine02 Mar 12, 2026
4e62ad3
fix: 당첨 번호 & 보너스 번호 label을 input과 연결, 오타 수정
GamjaIsMine02 Mar 12, 2026
d0a9338
fix: attributeChangedCallback 메서드 대소문자 오타 수정
GamjaIsMine02 Mar 12, 2026
70f5422
feat: 구입 로또 UI 분리, 구입 금액에 따라 로또 발급하여 렌더링하도록 수정
GamjaIsMine02 Mar 12, 2026
fb08897
feat: 당첨 번호 & 보너스 번호 입력 폼 UI 분리, 당첨 번호 & 보너스 번호 유효성 검사 로직 추가, 입력 에러메세…
GamjaIsMine02 Mar 12, 2026
f05dea6
feat: 당첨 통계 데이터를 목데이터에서 실제 통계 데이터로 변경
GamjaIsMine02 Mar 12, 2026
bae4f95
feat: 당첨 통계 모달 UI 분리 및 재시작 기능 구현
GamjaIsMine02 Mar 12, 2026
820f6ea
fix: package.json homepage username 추가
GamjaIsMine02 Mar 13, 2026
de32d93
fix: 사파리에서 폰트가 달라지는 문제 수정
GamjaIsMine02 Mar 13, 2026
a4baaea
docs: 배포링크 추가
GamjaIsMine02 Mar 13, 2026
3a482b7
docs: 2단계 미션 구조 추가
GamjaIsMine02 Mar 13, 2026
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
73 changes: 71 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,111 @@
1. 기능

1-1. 입력

- 로또 금액을 입력받는다
- 보너스 번호를 입력받는다
- 당첨 번호를 입력받는다
- 재시작 여부를 입력받는다

1-2. 출력

- 로또 배열을 출력한다
- 당첨 내역을 출력한다
- 수익률을 출력한다

1-3. 로또

- 6자리의 번호 배열을 가진다.
- 6자리의 번호를 반환한다.

1-4. 로또들

- 로또의 총 개수를 가진다.
- 로또 배열을 가진다.
- 로또 배열을 생성하는 기능
- 중복되지 않은 랜덤 숫자 6개로 이루어진 배열을 반환한다.
-
-

1-5. 로또게임

- 당첨 로또 객체(당첨 번호와 보너스 번호로 이루어진)
- 등수 계산 기능

1-6. 통계

- 수익률 계산 기능

1-7. 컨트롤러

- 입력이 잘못된 경우 다시 입력받는다.
- 재시작 여부에 따라 프로그램을 재시작하거나 종료한다.

1-8. 유효성 검사

- 구입 금액은 1000원 단위 양수여야 한다.

- 로또는 6개의 1~45 사이의 중복되지 않은 정수로 이루어져야 한다.
- 당첨 로또는 6개의 1~45 사이의 중복되지 않은 정수로 이루어져야 한다.
- 당첨 로또는 6개의 1~45 사이의 중복되지 않은 정수로 이루어져야 한다.
- 보너스 번호는 1개의 1~45 사이의 당첨 로또와 중복되지 않은 정수로 이루어져야 한다.

### 2. UI 기반 로또 미션 요구사항

#### 2-1. 로또 구입

- 구입 금액에 5000원을 입력하고 `구입` 버튼을 누르면 구매한 로또 개수 텍스트가 화면에 렌더링된다.
- 구매한 로또 개수만큼 로또 아이콘과 번호가 렌더링된다.

- 올바른 입력이 아닐 때 `구입` 버튼을 누르면 화면에 에러를 발생시킨다.
- 에러가 발생하는 경우 입력 칸을 비운 후 다시 입력받는다.

#### 2-2. 당첨 번호와 보너스 번호

- 로또 구입이 완료되기 전까지는 화면에 렌더링하지 않는다.
- 로또 구매가 완료되면 당첨 번호와 보너스 번호를 입력하는 폼이 렌더링된다.
- 당첨 번호와 보너스 번호를 입력한 후, `결과 확인하기` 버튼을 누르면 당첨 통계를 화면에 렌더링한다.

- 올바른 입력이 아닐 때 `결과 확인하기` 버튼을 누르면 화면에 에러를 발생시킨다.
- 에러가 발생하는 경우 입력 칸을 비운 후 다시 입력받는다.

#### 2-3. 당첨 통계 모달

- 당첨 통계는 모달 형식으로 렌더링되며, 당첨 통계에는 `일치 개수`, `당첨금`, `당첨 개수`가 포함된다.
- 총 수익률이 렌더링된다.

- `X` 버튼을 눌러 모달을 닫을 수 있다.
- `다시 시작하기` 버튼을 누르면 모달이 닫힌다.
- `다시 시작하기` 버튼을 누르면 입력 폼의 값이 비워진다.
- `다시 시작하기` 버튼을 누르면 렌더링되었던 로또 아이콘과 당첨 번호와 보너스 번호 입력 폼이 사라진다.

## 3. CSS 속성 작성 순서

### 1. 레이아웃/정렬

display, position, top, right, bottom, left, z-index, float, clear, flex, flex-direction, flex-wrap, flex-flow, flex-grow, flex-shrink, flex-basis, justify-content, align-items, align-content, align-self, gap, row-gap, column-gap, order, grid, grid-template, grid-template-rows, grid-template-columns, grid-template-areas, grid-auto-rows, grid-auto-columns, grid-auto-flow, grid-column, grid-row, place-items, place-content, place-self, overflow, overflow-x, overflow-y

### 2. 박스모델

box-sizing, width, min-width, max-width, height, min-height, max-height, margin, margin-top, margin-right, margin-bottom, margin-left, padding, padding-top, padding-right, padding-bottom, padding-left

### 3. 비주얼

background, background-color, background-image, background-size, background-position, background-repeat, border, border-width, border-style, border-color, border-radius, box-shadow, outline, outline-width, outline-style, outline-color, opacity, filter, transform

### 4. 타이포

font, font-family, font-size, font-weight, font-style, font-variant, line-height, letter-spacing, text-align, text-decoration, text-transform, text-shadow, color, white-space, word-break, word-spacing, text-overflow

## 4. 배포 링크

https://gamjaismine02.github.io/javascript-lotto/

### 구조

- Controller: `src/Controller/WebController.js`
- Service: `src/Service/LottoService.js`
- View:
- `src/webView/PurchaseView/PurchaseView.js`
- `src/webView/LottoView/LottoView.js`
- `src/webView/UserLottoView/UserLottoView.js`
- `src/webView/ModalView/ModalView.js`
- Model: `src/Model/*`
36 changes: 36 additions & 0 deletions index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
.main-container {
display: flex;
align-items: center;
justify-content: center;

margin: 84px;
margin-top: 154px;

background-color: var(--color-lotto-greyscale-2);
}

.card-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;

width: 414px;
padding: 40px;
gap: 28px;

background-color: var(--color-lotto-greyscale-1);
border: 1px solid var(--color-lotto-greyscale-3);
}
.card-header {
font: var(--text-title);
}

lotto-purchase {
display: block;
width: 100%;
}

.card-hidden-section {
width: 100%;
}
116 changes: 114 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,124 @@
<title>🎱 행운의 로또</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>

<link rel="stylesheet" href="./src/webView/global.css" />
<link rel="stylesheet" href="./index.css" />
<link rel="stylesheet" href="./src/webView/PurchaseView/PurchaseView.css" />
<link rel="stylesheet" href="./src/webView/LottoView/LottoView.css" />
<link
rel="stylesheet"
href="./src/webView/UserLottoView/UserLottoView.css"
/>
<link rel="stylesheet" href="./src/webView/ModalView/ModalView.css" />
<link rel="stylesheet" href="./src/webView/Header/Header.css" />
<link rel="stylesheet" href="./src/webView/Footer/Footer.css" />
</head>

<body>
<div id="app">
<h1>🎱 행운의 로또</h1>
<header class="header-container">
<div class="header-text-box">🎱 행운의 로또</div>
</header>

<div class="main-container">
<section class="card-container">
<!-- 1. 헤더 -->
<div class="card-header">🎱 내 번호 당첨 확인 🎱</div>

<!-- 2. 구입 금액 입력 폼 -->
<section class="card-input-container">
<label class="input-label" for="purchase-amount">
구입할 금액을 입력해주세요.
</label>
<form class="input-container" id="purchase-form">
<input class="input-line" id="purchase-amount" placeholder="금액" />
<button class="input-button">구입</button>
</form>
<p class="input-error" id="purchase-error" hidden></p>
</section>

<div class="card-hidden-section" id="lotto-section" hidden>
<!-- 3. 구입 로또 -->
<section class="lottos-container">
<div class="lottos-container-header" id="purchase-summary"></div>
<div class="lottos-table" id="ticket-container">
<div class="lotto-line">
<div class="lotto-line-icon">🎟️</div>
</div>
</div>
</section>

<!-- 4. 당첨 번호 & 보너스 번호 입력 폼 -->
<form class="userLotto-container" id="user-form">
<label class="userLotto-header" for="winningNumber">
지난 주 당첨번호 6개와 보너스 번호 1개를 입력해주세요.
</label>
<div class="input-container">
<div class="winningNumber-container">
<label
class="winningNumber-container-header"
for="winningNumber"
>
당첨 번호
</label>
<div class="winningNumber-input-container">
<input
type="text"
id="winningNumber"
class="winningNumber-line"
/>
<input type="text" class="winningNumber-line" />
<input type="text" class="winningNumber-line" />
<input type="text" class="winningNumber-line" />
<input type="text" class="winningNumber-line" />
<input type="text" class="winningNumber-line" />
</div>
</div>
<div class="bonusNumber-container">
<label class="bonusNumber-container-header" for="bonusNumber">
보너스 번호
</label>

<input type="text" id="bonusNumber" class="bonusNumber-line" />
</div>
</div>

<p class="input-error" id="user-lotto-error" hidden></p>

<button class="result-button">결과 확인하기</button>
</form>
</div>

<!-- 결과 모달 -->
<section class="result-modal-overlay" id="result-modal" hidden>
<div class="modal">
<button class="modal-close" aria-label="닫기">×</button>

<div class="modal-header">🏆 당첨 통계 🏆</div>

<div class="modal-table">
<div class="row-header">
<div>일치 갯수</div>
<div>당첨금</div>
<div>당첨 갯수</div>
</div>
<div class="row-container" id="result-rows"></div>
</div>

<div class="benefit-messege"></div>

<button class="modal-restart" id="restart-btn">
다시 시작하기
</button>
</div>
</section>
</section>
</div>

<footer class="footer-container">
<div class="footer-text-box">Copyright 2023. woowacourse</div>
</footer>

<script type="module" src="./src/step2-index.js"></script>
</body>
</html>
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"start-step2": "vite",
"deploy": "vite build --base=/javascript-lotto/ --minify=false && npx gh-pages -d dist"
},
"homepage": "https://{username}.github.io/javascript-lotto",
"homepage": "https://GamjaIsMine02.github.io/javascript-lotto",
"devDependencies": {
"@babel/cli": "^7.28.6",
"@babel/core": "^7.29.0",
Expand Down
62 changes: 62 additions & 0 deletions src/Controller/WebController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import LottoService from "../Service/LottoService.js";
import LottoView from "../webView/LottoView/LottoView.js";
import ModalView from "../webView/ModalView/ModalView.js";
import PurchaseView from "../webView/PurchaseView/PurchaseView.js";
import UserLottoView from "../webView/UserLottoView/UserLottoView.js";

export default class WebController {
constructor() {
this.service = new LottoService();

this.purchaseView = new PurchaseView();
this.lottoView = new LottoView();
this.userLottoView = new UserLottoView();
this.modalView = new ModalView();
}

init() {
this.purchaseView.bindPurchase(this.handlePurchase.bind(this));
this.userLottoView.bindCheckResult(this.handleResult.bind(this));
this.modalView.bindClose(this.handleCloseModal.bind(this));
this.modalView.bindRestart(this.handleRestart.bind(this));
}

handlePurchase(amount) {
try {
const lottos = this.service.purchaseLottos(amount);

this.lottoView.renderLottos(lottos);
this.lottoView.open();
this.purchaseView.clearError();
} catch (error) {
this.purchaseView.showError(error.message);
}
}

handleResult({ winningNumbers, bonusNumber }) {
try {
const { statistics, yieldRate } = this.service.calculateResult(
winningNumbers,
bonusNumber
);

this.userLottoView.clearError();
this.modalView.renderStatistics(statistics);
this.modalView.renderRate(yieldRate);
this.modalView.open();
} catch (error) {
this.userLottoView.showError(error.message);
}
}

handleCloseModal() {
this.modalView.close();
}

handleRestart() {
this.modalView.close();
this.purchaseView.clearInput();
this.userLottoView.clearInputs();
this.lottoView.close();
}
}
43 changes: 43 additions & 0 deletions src/Service/LottoService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import Validator from "../Validator.js";
import LottoGame from "../Model/LottoGame.js";

import LottoList from "../Model/LottoList.js";
import Rate from "../Model/Rate.js";

export default class LottoService {
#validator;
#lottoList;
#purchaseAmount;

constructor() {
this.#validator = new Validator();
this.#lottoList = null;
this.#purchaseAmount = 0;
}

purchaseLottos(purchasePrice) {
this.#validator.validatePrice(purchasePrice);

this.#purchaseAmount = purchasePrice / 1000;

this.#lottoList = new LottoList(this.#purchaseAmount);

return this.#lottoList.getLottoList();
}

calculateResult(winningNumbers, bonusNumber) {
this.#validator.validateLottoNumbers(winningNumbers);
this.#validator.validateBonusNumber(winningNumbers, bonusNumber);

const lottoGame = new LottoGame(winningNumbers, bonusNumber);

const statistics = lottoGame.calculateStatistics(this.#lottoList);

const rate = new Rate(statistics, this.#purchaseAmount);

return {
statistics: statistics,
yieldRate: rate.getRate(),
};
}
}
Loading