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

[6팀 방재현] [Chapter 2-1] 클린코드와 리팩토링 #50

Open
wants to merge 38 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
2393a22
chore : constants 파일 추가
JaeHyunBang-plea Jan 7, 2025
c2b9252
refactor : main.origin.js 파일명 변경
JaeHyunBang-plea Jan 7, 2025
e0a0c60
refactor : index.html에 main.js 파일명 적용
JaeHyunBang-plea Jan 7, 2025
af02ff5
docs : main.js 함수에 대한 주석 작성
JaeHyunBang-plea Jan 7, 2025
76a57df
refactor : 장바구니 아이템 삭제, 수량 증가, 수량 감소 함수 분리
CRITICBANGGU Jan 7, 2025
c73a428
feat : createElement 함수 작성
CRITICBANGGU Jan 7, 2025
a703c59
feat : appendChildren 함수 작성
CRITICBANGGU Jan 7, 2025
23a0c6d
refactor : main.js createElement 적용
CRITICBANGGU Jan 7, 2025
d98bac3
fix : cartEvent 총액 및 제품 금액 변경되는 이슈 수정
CRITICBANGGU Jan 7, 2025
3c8ad89
refactor : 상품리스트 상수 적용
JaeHyunBang-plea Jan 9, 2025
577729e
refactor : 초기 화면 렌더링 하는 initApp 함수 작성
JaeHyunBang-plea Jan 9, 2025
0557a0f
origin 코드 살림
JaeHyunBang-plea Jan 9, 2025
c99acc8
refactor : 파일 이동
JaeHyunBang-plea Jan 9, 2025
d00de57
(과제 재시작)프리티어 적용
JaeHyunBang-plea Jan 9, 2025
59282ee
chore : PRODUCT_LIST 상수화, 카트 계산 변수명 변경
JaeHyunBang-plea Jan 9, 2025
6133bd7
fix :PRODUCT_LIST key 값 중, stock 빠진 곳 수정
JaeHyunBang-plea Jan 9, 2025
68f965f
fix : main.origin.js 파일명 변경
JaeHyunBang-plea Jan 9, 2025
5193d20
chore : PRODUCT_LIST 에 discount 값 추가
JaeHyunBang-plea Jan 9, 2025
3d33a5c
refactor : calcCart함수 리펙토링
JaeHyunBang-plea Jan 9, 2025
17556cf
refactor : 불필요한 전역변수 삭제
JaeHyunBang-plea Jan 9, 2025
901f2ab
refactor : 불필요한 전역변수 삭제
JaeHyunBang-plea Jan 9, 2025
9a31f8a
refactor : UI 업데이트 로직에 보너스포인트,재고현황 이동
JaeHyunBang-plea Jan 9, 2025
e25ef84
fix : PRODUCT_LIST 적용 안된 곳 수정
JaeHyunBang-plea Jan 9, 2025
11d837d
fix : 삭제 버튼 핸들러 함수 분리.
JaeHyunBang-plea Jan 10, 2025
7b75f45
refactor : addBtn 핸들러 함수 분리
JaeHyunBang-plea Jan 10, 2025
a3d5a3f
refactor : cartDisp 클릭 이벤트 수정
JaeHyunBang-plea Jan 10, 2025
5ef9569
chore : react 의존성 추가
JaeHyunBang-plea Jan 10, 2025
c298760
chore : eslint 설정
JaeHyunBang-plea Jan 10, 2025
da4e830
chore : 심화과제 셋팅
JaeHyunBang-plea Jan 10, 2025
e000182
chore : ts 대응
JaeHyunBang-plea Jan 10, 2025
6ff2183
feat : type 지정
JaeHyunBang-plea Jan 10, 2025
a26b0a0
feat : 상품 선택 select box ui 컴포넌트 생성
JaeHyunBang-plea Jan 10, 2025
b5a7367
feat : 품절 및 품절 임박 레이블 ui 컴포넌트 생성
JaeHyunBang-plea Jan 10, 2025
c9bc151
feat : 장바구니 목록 ui 컴포넌트 작성
JaeHyunBang-plea Jan 10, 2025
06cbaaa
feat : App.tsx에 ui 컴포넌트 추가
JaeHyunBang-plea Jan 10, 2025
366e4e4
fix : index.advanced.html 연결된 스크립트 파일명 수정
JaeHyunBang-plea Jan 10, 2025
be46896
chore : tsconfig추가
JaeHyunBang-plea Jan 10, 2025
8d9d58d
chore : package 수정
JaeHyunBang-plea Jan 10, 2025
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
19 changes: 19 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"plugin:prettier/recommended"
],
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint", "react", "react-hooks"],
"rules": {
"react/react-in-jsx-scope": "off"
},
"settings": {
"react": {
"version": "detect"
}
}
}
20 changes: 10 additions & 10 deletions index.advanced.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>장바구니</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-100 p-8">
<main id="app"></main>
<script type="module" src="./src/advanced/main.advanced.js"></script>
</body>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>장바구니</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-100 p-8">
<main id="app"></main>
<script type="module" src="./src/advanced/main.advanced.tsx"></script>
</body>
</html>
26 changes: 13 additions & 13 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>장바구니</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-100 p-8">
<main id="app"></main>
<script type="module" src="/src/main.original.js"></script>
</body>
</html>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>장바구니</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-100 p-8">
<main id="app"></main>
<script type="module" src="./src/basic/main.basic.js"></script>
</body>
</html>
13 changes: 11 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
"start:basic": "vite serve --open ./index.basic.html",
"start:advanced": "vite serve --open ./index.advanced.html",
"test": "vitest",
"test:basic": "vitest basic.test.js",
"test:advanced": "vitest advanced.test.js",
"test:basic": "vitest basic.test",
"test:advanced": "vitest advanced.test",
"test:ui": "vitest --ui"
},
"devDependencies": {
Expand All @@ -21,5 +21,14 @@
"jsdom": "^25.0.0",
"vite": "^5.1.0",
"vitest": "^2.1.1"
},
"dependencies": {
"@testing-library/react": "^16.1.0",
"@types/react": "^19.0.4",
"@types/react-dom": "^19.0.2",
"@vitejs/plugin-react": "^4.3.4",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"typescript": "^5.7.3"
}
}
5 changes: 0 additions & 5 deletions src/advanced/__tests__/advanced.test.js

This file was deleted.

12 changes: 12 additions & 0 deletions src/advanced/__tests__/advanced.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from "react"; // React import 추가
import { render, screen } from "@testing-library/react";
import { describe, it, expect } from "vitest";
import { App } from "../src/App";

describe("advanced test", () => {
it("초기 상태: 상품 목록이 올바르게 렌더링 되는지 확인", () => {
render(<App />);
const select = screen.getByRole("combobox");
expect(select).toBeInTheDocument();
});
});
Empty file removed src/advanced/main.advanced.js
Empty file.
167 changes: 167 additions & 0 deletions src/advanced/main.advanced.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
// import { PRODUCT_LIST } from "./src/data/prodList";
// import { calculateCartTotals } from "./src/util/calculate";
// import { handleDeleteToCart, updateCartList } from "./src/events/cartEvent";
// var sel, addBtn, cartDisp, sum, stockInfo;
// var lastSel,
// bonusPoints = 0;

// function main() {
// var root = document.getElementById("app");
// let cont = document.createElement("div");
// var wrap = document.createElement("div");
// let hTxt = document.createElement("h1");
// cartDisp = document.createElement("div");
// sum = document.createElement("div");
// sel = document.createElement("select");
// addBtn = document.createElement("button");
// stockInfo = document.createElement("div");
// cartDisp.id = "cart-items";
// sum.id = "cart-total";
// sel.id = "product-select";
// addBtn.id = "add-to-cart";
// stockInfo.id = "stock-status";
// cont.className = "bg-gray-100 p-8";
// wrap.className =
// "max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden md:max-w-2xl p-8";
// hTxt.className = "text-2xl font-bold mb-4";
// sum.className = "text-xl font-bold my-4";
// sel.className = "border rounded p-2 mr-2";
// addBtn.className = "bg-blue-500 text-white px-4 py-2 rounded";
// stockInfo.className = "text-sm text-gray-500 mt-2";
// hTxt.textContent = "장바구니";
// addBtn.textContent = "추가";
// updateSelOpts();
// wrap.appendChild(hTxt);
// wrap.appendChild(cartDisp);
// wrap.appendChild(sum);
// wrap.appendChild(sel);
// wrap.appendChild(addBtn);
// wrap.appendChild(stockInfo);
// cont.appendChild(wrap);
// root.appendChild(cont);
// calcCart();
// setTimeout(function () {
// setInterval(function () {
// var luckyItem =
// PRODUCT_LIST[Math.floor(Math.random() * PRODUCT_LIST.length)];
// if (Math.random() < 0.3 && luckyItem.stock > 0) {
// luckyItem.cost = Math.round(luckyItem.cost * 0.8);
// alert("번개세일! " + luckyItem.name + "이(가) 20% 할인 중입니다!");
// updateSelOpts();
// }
// }, 30000);
// }, Math.random() * 10000);
// setTimeout(function () {
// setInterval(function () {
// if (lastSel) {
// var suggest = PRODUCT_LIST.find(function (item) {
// return item.id !== lastSel && item.stock > 0;
// });
// if (suggest) {
// alert(
// suggest.name + "은(는) 어떠세요? 지금 구매하시면 5% 추가 할인!"
// );
// suggest.cost = Math.round(suggest.cost * 0.95);
// updateSelOpts();
// }
// }
// }, 60000);
// }, Math.random() * 20000);
// }
// function updateSelOpts() {
// sel.innerHTML = "";
// PRODUCT_LIST.forEach(function (item) {
// var opt = document.createElement("option");
// opt.value = item.id;
// opt.textContent = item.name + " - " + item.cost + "원";
// if (item.stock === 0) opt.disabled = true;
// sel.appendChild(opt);
// });
// }
// function calcCart() {
// let totalAmount = 0;
// const cartItems = Array.from(cartDisp.children);
// const { subTotal, totalDiscount, itemCount, discountRate } =
// calculateCartTotals(cartItems);
// totalAmount = subTotal - totalDiscount;

// const bulkDiscountRate = itemCount >= 30 ? 0.25 : discountRate;
// const tuesdayDiscountRate = new Date().getDay() === 2 ? 0.1 : 0;

// const finalDiscountRate = Math.max(bulkDiscountRate, tuesdayDiscountRate);
// totalAmount *= 1 - finalDiscountRate;

// updateSummaryUI(totalAmount, finalDiscountRate);
// }

// const updateSummaryUI = (totalAmount, finalDiscountRate) => {
// sum.textContent = "총액: " + Math.round(totalAmount) + "원";

// if (finalDiscountRate > 0) {
// var span = document.createElement("span");
// span.className = "text-green-500 ml-2";
// span.textContent = `(${(finalDiscountRate * 100).toFixed(1)}% 할인 적용)`;
// sum.appendChild(span);
// }
// updateStockInfo();
// renderBonusPts(totalAmount);
// };
// const renderBonusPts = (totalAmount) => {
// bonusPoints = Math.floor(totalAmount / 1000);
// var pointTag = document.getElementById("loyalty-points");
// if (!pointTag) {
// pointTag = document.createElement("span");
// pointTag.id = "loyalty-points";
// pointTag.className = "text-blue-500 ml-2";
// sum.appendChild(pointTag);
// }
// pointTag.textContent = "(포인트: " + bonusPoints + ")";
// };
// function updateStockInfo() {
// var infoMsg = "";
// PRODUCT_LIST.forEach(function (item) {
// if (item.stock < 5) {
// infoMsg +=
// item.name +
// ": " +
// (item.stock > 0 ? "재고 부족 (" + item.stock + "개 남음)" : "품절") +
// "\n";
// }
// });
// stockInfo.textContent = infoMsg;
// }
// main();

// addBtn.addEventListener("click", function () {
// var selItem = sel.value;
// var itemToAdd = PRODUCT_LIST.find(function (p) {
// return p.id === selItem;
// });
// const newItem = updateCartList(itemToAdd);
// if (newItem) {
// cartDisp.appendChild(newItem);
// lastSel = itemToAdd;
// }
// calcCart();
// });

// cartDisp.addEventListener("click", function (event) {
// var target = event.target;
// if (
// target.classList.contains("quantity-change") ||
// target.classList.contains("remove-item")
// ) {
// handleDeleteToCart(target);
// calcCart();
// }
// });
import ReactDOM from "react-dom/client";
import { App } from "./src/App";

const container = document.getElementById("app");
if (container) {
const root = ReactDOM.createRoot(container);
root.render(<App />);
} else {
console.error("Target container 'app' not found in the DOM.");
}
23 changes: 23 additions & 0 deletions src/advanced/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { FunctionComponent, useState } from "react";
import { PRODUCT_LIST } from "./data/prodList";
import { ICart, IProduct } from "./types/types";
import CartList from "./components/Cart";
import ProductSelect from "./components/ProductSelect";
import SummaryStock from "./components/SummaryStock";

export const App: FunctionComponent = () => {
const [products, setProducts] = useState<IProduct[]>(PRODUCT_LIST);
const [selectedProducts, setSelectedProducts] = useState<ICart[]>([
{ id: "p1", name: "상품1", cost: 10000, count: 5, discount: 0.1 },
]);
return (
<div className="bg-gray-100 p-8">
<div className="max-w-md mx-auto bg-white rounded-xl shadow-md overflow-hidden md:max-w-2xl p-8">
<h1 className="text-2xl font-bold mb-4">장바구니</h1>
<CartList products={selectedProducts} />
<ProductSelect products={products} handler={() => {}} />
<SummaryStock products={products} />
</div>
</div>
);
};
52 changes: 52 additions & 0 deletions src/advanced/src/components/Cart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { FunctionComponent } from "react";
import { ICart, IProduct } from "../types/types";
interface ICartList {
products: ICart[];
}
const CartList: FunctionComponent<ICartList> = ({ products }) => {
return (
<div>
{products.map((product, idx) => {
return <CartItem key={product.id} item={product} />; // key를 고유 ID로 지정
})}
</div>
);
};

interface ICartItem {
item: ICart;
}

const CartItem: FunctionComponent<ICartItem> = ({ item }) => {
return (
<div id={item.id} className="flex justify-between items-center mb-2">
<span>
{item.name} - {item.cost}원 x {item.count}
</span>
<div>
<button
className="quantity-change bg-blue-500 text-white px-2 py-1 rounded mr-1"
data-product-id={item.id}
data-change="-1"
>
-
</button>
<button
className="quantity-change bg-blue-500 text-white px-2 py-1 rounded mr-1"
data-product-id={item.id}
data-change="1"
>
+
</button>
<button
className="remove-item bg-red-500 text-white px-2 py-1 rounded"
data-product-id={item.id}
>
삭제
</button>
</div>
</div>
);
};

export default CartList;
Loading
Loading