Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
c40df91
chore: eslint prettier 기본 설정
Jul 28, 2025
828cc1a
refactor: main 파일 formatting
Jul 28, 2025
dddb8c1
refactor: product id 전역변수 구조 변경
Jul 28, 2025
f06fa9c
refactor: main 함수에서 render, initState 내용 분리
Jul 28, 2025
b06b383
refactor: 전역 product list 구조 변경
Jul 28, 2025
002ec70
refactor: 상품 select option 렌더링 함수 정리 & product item 컴포넌트화
Jul 28, 2025
dbc5df3
refactor: calculateCart 함수 불필요한 코드 정리 & 할인율 변수 분리
Jul 28, 2025
a33f80c
refactor: stock info 컴포넌트화
Jul 28, 2025
66c5c72
refactor: loyalty points ui 분리
Jul 28, 2025
93c9458
chore: eslint prettier rule 팀 컨벤션 반영
esoby Jul 28, 2025
c30f192
refactor: main 파일 formatting
esoby Jul 28, 2025
d6abb7d
fix: eslint 반영 후 error 수정
esoby Jul 29, 2025
6764522
refactor: event handler 함수 정리
Jul 29, 2025
dd7aa78
feat: add store
Jul 29, 2025
1251ed9
refactor: 상태 변경 로직 dispatch로 추출
esoby Jul 29, 2025
8c4c6e3
refactor: 데이터 계산 로직 스토어로 분리
esoby Jul 29, 2025
29edd19
refactor: 스토어 반영 & UI 코드 분리 & 초기 렌더링 분리
esoby Jul 29, 2025
ce3bcc2
refactor: 수량 버튼 dom 비교 및 부분 업데이트 로직 추가
esoby Jul 29, 2025
694b7a9
fix: 변경된 변수명 미반영 부분 수정
Jul 30, 2025
97824b0
fix: 중복 렌더링 코드 제거
Jul 30, 2025
4e5758e
refactor: sale interval 콜백 함수 정리 & 매직 넘버 상수화
Jul 30, 2025
3952a46
refactor: 반복적인 dom 탐색 방지를 위한 element 캐싱
Jul 30, 2025
28b11f7
refactor: 중복 코드 제거
Jul 30, 2025
28588c0
refactor: interval 해제 추가 - 타이머 side effect 최소화
Jul 30, 2025
1ee10be
refactor: 컴포넌트 & 상수 파일 분리
Jul 30, 2025
831c5c0
refactor: App 모듈 생성 & UI 책임 분리
Jul 30, 2025
1b72287
refactor: stock msg 생성 중복 코드 제거
Jul 30, 2025
9884e22
refactor: 비즈니스 로직 함수에서 alert ui 코드 분리
Jul 30, 2025
dc68bd3
refactor: app 모듈 내 함수 배치 변경
Jul 30, 2025
6a22124
refactor: sale timer 로직 utils로 파일 분리
Jul 30, 2025
88363c4
refactor: 선택된 상품 id store로 관리
Jul 30, 2025
2ba0166
refactor: 이벤트 핸들러 파일 분리
Jul 30, 2025
5ebb381
test: select 값 변동 이벤트 감지를 위한 테스트 코드 수정
Jul 30, 2025
fe586d3
refactor: dom elements & 접근 코드 분리
Jul 30, 2025
4610ec0
refactor: 렌더 내 세부 렌더링 로직 함수 분리
Jul 30, 2025
19c5e3b
refactor: components section별로 폴더 분리
Jul 30, 2025
aafe78f
refactor: store summary 값 각각 getter 함수로 정리
Jul 30, 2025
855309a
refactor: 적립 포인트 getter 선언적 코드로 수정
esoby Jul 30, 2025
68697ab
refactor: 상품 할인 결과 getter 선언적 코드로 수정
esoby Jul 30, 2025
5165b86
🚀 Init advanced react project
Jul 31, 2025
580da22
refactor: 초기 화면 레이아웃 컴포넌트 tsx로 변환
Jul 31, 2025
5687b3b
refactor: 레이아웃 컴포넌트 App에 구성
Jul 31, 2025
68cb747
refactor: product selector & cart list 컴포넌트 tsx로 변환 및 추가 분리
Jul 31, 2025
3079dae
refactor: order summary section 컴포넌트 tsx 변환 및 추가 분리
Jul 31, 2025
82a753d
refactor: 기존 store 이용해서 reducer 생성
Jul 31, 2025
7174129
refactor: 데이터 전역 관리용 cart context 생성
Jul 31, 2025
99d9e98
refactor: original state getters export
Jul 31, 2025
abd548c
refactor: cart section내 cart state 사용 컴포넌트 수정
Jul 31, 2025
30fa7c0
refactor: constant 파일 추가
Jul 31, 2025
944154b
refactor: summary section - cart state 사용 컴포넌트 수정
Jul 31, 2025
0a1e386
refactor: summary details 컴포넌트 추가 분리
Jul 31, 2025
e05daae
refactor: add button 이벤트 핸들러 등록
Jul 31, 2025
6a42002
refactor: add button 컴포넌트명 변경
Jul 31, 2025
3b47020
refactor: 카트 추가 시 last selected action
Jul 31, 2025
4516a26
refactor: selector onchange 이벤트 핸들러 등록
Jul 31, 2025
9adc706
refactor: cart item 수량 제어 버튼 클릭 핸들러 등록
Jul 31, 2025
bb72ff0
refactor: manual 토글 클릭 이벤트 처리
Jul 31, 2025
a946d1f
refactor: sale timers util 파일 hook으로 변환 및 적용
Jul 31, 2025
04ed759
refactor: noti 일괄 실행 함수 hook으로 변환
Jul 31, 2025
fc7a2c0
refactor: getters state 타입 지정
Jul 31, 2025
c5128cb
refactor: reducer type & interface 파일 분리
Jul 31, 2025
1f495b0
fix: reducer 반환값 타입 지정
Jul 31, 2025
d4a5c92
fix: stock 메세지 줄바꿈 특수문자 추가
Jul 31, 2025
b5d0c96
fix: product option value 문자열 수정
esoby Jul 31, 2025
ddef31e
fix: 중복 export 제거
esoby Jul 31, 2025
3f638a3
refactor: 불필요한 getCartSummary 함수 제거
esoby Jul 31, 2025
71cd7d9
chore: 배포 설정
esoby Jul 31, 2025
3c4fc14
refactor: getters 파일 분리
Aug 1, 2025
c849578
refactor: selected product id 상태 지역화
Aug 1, 2025
40ff029
refactor: getters 내 매직 넘버 분리 & ui 메세지 생성 코드 분리
Aug 1, 2025
a4935f2
refactor: 할인율 포인트 계산 함수 정리
Aug 1, 2025
b51c1e2
refactor: discount 텍스트 배열 리턴값 이름 변경
Aug 1, 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
15 changes: 15 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
eslint.config.js
.prettierrc.json


node_modules
dist
build
.cache
*.lock

README.md
.github

# 더티 코드 유지
main.original.js
11 changes: 11 additions & 0 deletions .prettierrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default {
semi: true,
singleQuote: true,
jsxSingleQuote: true,
tabWidth: 2,
bracketSpacing: true,
bracketSameLine: false,
arrowParens: 'always',
printWidth: 100,
endOfLine: 'auto',
};
174 changes: 174 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import typescript from '@typescript-eslint/eslint-plugin';
import typescriptParser from '@typescript-eslint/parser';
import prettier from 'eslint-config-prettier';
import compat from 'eslint-plugin-compat';
import cypressPlugin from 'eslint-plugin-cypress';
import importPlugin from 'eslint-plugin-import';
import eslintPluginPrettier from 'eslint-plugin-prettier';
import react from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks';
import vitestPlugin from 'eslint-plugin-vitest';
import globals from 'globals';

export default [
{
ignores: ['**/node_modules/**', 'dist/**'],
},
{
files: ['**/*.{js,jsx,ts,tsx}'],
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
globals: {
...globals.browser,
...globals.es2021,
Set: true,
Map: true,
},
parser: typescriptParser,
parserOptions: {
ecmaFeatures: {
jsx: true,
},
tsconfigRootDir: '.',
},
},
plugins: {
prettier: eslintPluginPrettier,
react,
'react-hooks': reactHooks,
'@typescript-eslint': typescript,
compat,
import: importPlugin,
},
settings: {
react: {
version: 'detect',
},
browsers: '> 0.5%, last 2 versions, not op_mini all, Firefox ESR, not dead',
},
rules: {
// Prettier 통합 규칙
'comma-dangle': [
'error',
{
arrays: 'always-multiline',
objects: 'always-multiline',
imports: 'always-multiline',
exports: 'always-multiline',
functions: 'never',
},
],

// React 관련 규칙
'react/prop-types': 'off',
'react/react-in-jsx-scope': 'off',
'react-hooks/rules-of-hooks': 'error',

// TypeScript 관련 규칙
'@typescript-eslint/no-explicit-any': 'warn',

// 팀 컨벤션 - var 사용 금지
'no-var': 'error',
'@typescript-eslint/no-unused-vars': 'error',

// 팀 컨벤션 - 동등 연산자 (==, !=) 금지
eqeqeq: ['error', 'always', { null: 'ignore' }],

// 팀 컨벤션 - 얼리 리턴 권장
'consistent-return': 'error',
'no-else-return': ['error', { allowElseIf: false }],

// 팀 컨벤션 - 템플릿 리터럴 규칙
'prefer-template': 'error',

// 팀 컨벤션 - 상수는 대문자
camelcase: [
'error',
{
properties: 'never',
ignoreDestructuring: false,
ignoreImports: false,
ignoreGlobals: false,
allow: ['^[A-Z][A-Z0-9_]*$'],
},
],

// 팀 컨벤션 - 구조분해할당 권장
'prefer-destructuring': [
'error',
{
array: true,
object: true,
},
{
enforceForRenamedProperties: false,
},
],

// 기본 코드 품질 규칙
'prefer-const': 'error',
'arrow-body-style': ['error', 'as-needed'],
'object-shorthand': 'error',
'no-multiple-empty-lines': ['error', { max: 1, maxEOF: 0 }],
'no-console': ['warn', { allow: ['warn', 'error'] }],
'no-debugger': 'warn',
'no-undef': 'off',

// import 순서 규칙
'import/order': [
'error',
{
groups: ['builtin', 'external', ['parent', 'sibling'], 'index'],
alphabetize: {
order: 'asc',
caseInsensitive: true,
},
'newlines-between': 'always',
},
],
'import/extensions': 'off',
},
},
// 테스트 파일 설정
{
files: [
'**/src/**/*.{spec,test}.[jt]s?(x)',
'**/__mocks__/**/*.[jt]s?(x)',
'./src/setupTests.ts',
],
plugins: {
vitest: vitestPlugin,
},
rules: {
'vitest/expect-expect': 'off',
},
languageOptions: {
globals: {
...globals.browser,
globalThis: true,
describe: true,
it: true,
expect: true,
beforeEach: true,
afterEach: true,
beforeAll: true,
afterAll: true,
vi: true,
},
},
},
// Cypress 테스트 파일 설정
{
files: ['cypress/e2e/**/*.cy.js'],
plugins: {
cypress: cypressPlugin,
},
languageOptions: {
globals: {
cy: true,
},
},
},
prettier,
];
68 changes: 38 additions & 30 deletions index.advanced.html
Original file line number Diff line number Diff line change
@@ -1,32 +1,40 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hanghae Shopping Cart</title>
<!-- Note: Tailwind CDN is for development only. For production, use PostCSS or Tailwind CLI -->
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {'sans': ['-apple-system', 'BlinkMacSystemFont', 'Helvetica Neue', 'Arial', 'sans-serif']},
letterSpacing: {
'extra-wide': '0.3em',
'super-wide': '0.25em',
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Hanghae Shopping Cart</title>
<!-- Note: Tailwind CDN is for development only. For production, use PostCSS or Tailwind CLI -->
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
sans: [
'-apple-system',
'BlinkMacSystemFont',
'Helvetica Neue',
'Arial',
'sans-serif',
],
},
letterSpacing: {
'extra-wide': '0.3em',
'super-wide': '0.25em',
},
fontSize: { '2xs': '0.625rem' },
maxHeight: { 800: '800px' },
backgroundImage: { 'gradient-black': 'linear-gradient(135deg, #000 0%, #333 100%)' },
},
},
fontSize: {'2xs': '0.625rem'},
maxHeight: {'800': '800px'},
backgroundImage: {'gradient-black': 'linear-gradient(135deg, #000 0%, #333 100%)',}
}
}
}
</script>
</head>
<body class="bg-gray-50 text-black antialiased overflow-hidden h-screen text-sm">
<div id="app" class="max-w-screen-xl h-screen max-h-800 mx-auto p-8 flex flex-col">
<!-- Content will be dynamically generated here -->
</div>
<script type="module" src="./src/advanced/main.advanced.js"></script>
</body>
</html>
};
</script>
</head>
<body class="bg-gray-50 text-black antialiased overflow-hidden h-screen text-sm">
<div id="app" class="max-w-screen-xl h-screen max-h-800 mx-auto p-8 flex flex-col">
<!-- Content will be dynamically generated here -->
</div>
<script type="module" src="./src/advanced/main.advanced.tsx"></script>
</body>
</html>
28 changes: 27 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
{
"name": "front-6th-chapter2-1",
"homepage": "https://esoby.github.io/front_6th_chapter2-1/",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"deploy": "vite build && cp dist/index.advanced.html dist/index.html && gh-pages -d dist",
"preview": "vite preview",
"start:basic": "vite serve --open ./index.basic.html",
"start:advanced": "vite serve --open ./index.advanced.html",
Expand All @@ -15,11 +17,35 @@
"test:ui": "vitest --ui"
},
"devDependencies": {
"@eslint/js": "^9.32.0",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/user-event": "^14.6.1",
"@types/react": "^19.1.9",
"@types/react-dom": "^19.1.7",
"@vitest/coverage-v8": "^3.2.4",
"@vitest/ui": "^3.2.4",
"eslint": "^9.32.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-cypress": "^5.1.0",
"eslint-plugin-prettier": "^5.5.3",
"eslint-plugin-react": "^7.37.5",
"gh-pages": "^6.3.0",
"globals": "^16.3.0",
"jsdom": "^26.1.0",
"vite": "^7.0.5",
"prettier": "^3.6.2",
"typescript": "^5.8.3",
"vite": "^5.4.19",
"vitest": "^3.2.4"
},
"dependencies": {
"@typescript-eslint/eslint-plugin": "^8.38.0",
"@typescript-eslint/parser": "^8.38.0",
"@vitejs/plugin-react": "^4.7.0",
"eslint-plugin-compat": "^6.0.2",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-vitest": "^0.5.4",
"react": "^19.1.1",
"react-dom": "^19.1.1"
}
}
Loading