Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
97f6bfe
feat: add prettier & eslint rules
geonhwi-jung Jul 28, 2025
a5325ff
docs: add docs files
geonhwi-jung Jul 28, 2025
e9132eb
리팩토링: main() 함수를 단일 책임 원칙에 따라 5개 함수로 분해
geonhwi-jung Jul 28, 2025
97eb05b
리팩토링: handleCalculateCartStuff() 함수를 단일 책임 원칙에 따라 분해
geonhwi-jung Jul 28, 2025
80f480b
리팩토링: 14개 전역 변수를 AppState 객체로 캡슐화
geonhwi-jung Jul 28, 2025
736c810
리팩토링: 중복된 상품 검색 로직을 유틸리티 함수로 통합
geonhwi-jung Jul 28, 2025
0080bab
리팩토링: 매직 넘버를 의미 있는 상수로 대체
geonhwi-jung Jul 28, 2025
28fed15
🚀 최종 리팩토링: 787줄 단일파일을 FSD 아키텍처 기반 모듈로 완전 분리
geonhwi-jung Jul 28, 2025
14eb658
🧹 레거시 코드 완전 제거 - 순수한 모던 아키텍처 완성
geonhwi-jung Jul 28, 2025
6c535de
feat: 테스트 성공 케이스 저장
geonhwi-jung Jul 29, 2025
a35c145
feat: 전역변수 상수로 통합 (레거시 정리)
geonhwi-jung Jul 29, 2025
96be0d2
feat: 중복 함수 통합
geonhwi-jung Jul 29, 2025
236f32c
feat: DOM 생성 함수 분리 및 정리
geonhwi-jung Jul 29, 2025
0499d2d
refact: 기존 이벤트 핸들러 코드 정리 및 개선
geonhwi-jung Jul 29, 2025
9399c82
refact: 계산 로직 최적화
geonhwi-jung Jul 29, 2025
89d61e5
refact: app state 모듈 분리
geonhwi-jung Jul 29, 2025
5f51a81
refact: 초기화 함수들을 features로 분리
geonhwi-jung Jul 29, 2025
467380e
refact: DOM 생성 함수를 widgets로 분리
geonhwi-jung Jul 29, 2025
2b8722b
refact: 프로모션 타이머를 features로 분리
geonhwi-jung Jul 29, 2025
1a98d95
refact: 계산 로직을 features로 분리
geonhwi-jung Jul 29, 2025
53980cf
refact: 이벤트 핸들러를 features로 분리
geonhwi-jung Jul 29, 2025
7916196
refact: 함수 모듈화
geonhwi-jung Jul 29, 2025
86d006a
refact: legacy 함수 제거
geonhwi-jung Jul 29, 2025
7da9c32
fix: remove legacy vars
geonhwi-jung Jul 29, 2025
3b362f9
refact: 미사용 변수 제거
geonhwi-jung Jul 29, 2025
aa2178a
fix: 로그 및 기타 처리
geonhwi-jung Jul 30, 2025
32a479d
fix: remove unused files
geonhwi-jung Jul 30, 2025
e595437
refact: dom-creator
geonhwi-jung Jul 30, 2025
3352a22
refact: 상수 중복 사용 제거
geonhwi-jung Jul 30, 2025
1730327
refact: app-state 코드 정리
geonhwi-jung Jul 30, 2025
c02f86c
refact: cart-management 정리
geonhwi-jung Jul 30, 2025
cc80b7f
refact: events 정리
geonhwi-jung Jul 30, 2025
0f8c144
refact: pricing 개별 함수 분리
geonhwi-jung Jul 30, 2025
4465bef
refact: pricing var 제거
geonhwi-jung Jul 30, 2025
04d09b3
refact: promotion 정리
geonhwi-jung Jul 30, 2025
58cde1a
feat: add advanced react
geonhwi-jung Jul 30, 2025
4f766bb
fix: design 통일
geonhwi-jung Jul 30, 2025
8d76bec
feat: add gh-pages
geonhwi-jung Jul 31, 2025
9d634f9
fix: config
geonhwi-jung Jul 31, 2025
58340e7
refactor: remove any types and improve type safety
geonhwi-jung Jul 31, 2025
ba5e6f1
refactor: extract magic numbers to constants
geonhwi-jung Aug 1, 2025
cfe30f1
refactor: break down large functions into smaller units
geonhwi-jung Aug 1, 2025
6e1a264
refactor: separate side effects with custom timer hook
geonhwi-jung Aug 1, 2025
181c1a3
refactor: improve Context composition pattern
geonhwi-jung Aug 1, 2025
d1335e1
refactor: eliminate code duplication with configuration-driven approach
geonhwi-jung Aug 1, 2025
c6c406b
refact: pricing hook 분리
geonhwi-jung 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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ dist-ssr
*.sw?

CLAUDE.md
.claude
.claude
.cursor
11 changes: 11 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"semi": true,
"singleQuote": true,
"jsxSingleQuote": true,
"tabWidth": 2,
"bracketSpacing": true,
"bracketSameLine": false,
"arrowParens": "always",
"printWidth": 100,
"endOfLine": "auto"
}
158 changes: 158 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
// eslint.config.js

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/**'], // 구성 개체가 적용되지 않아야 하는 파일을 나타내는 glob패턴, 지정하지 않으면 모든 파일에 적용
},
{
files: ['**/*.{js,jsx,ts,tsx}'], // 구성 개체가 적용되어야 하는 피일을 나타는 glob패턴, 지정하지 않으면 모든 파일에 적용
languageOptions: {
ecmaVersion: 'latest', // 지원할 ECMAScript 버전 기본 값은 'latest'
sourceType: 'module', // js 소스코드의 유형, ECMAScript의 모듈일 경우 'module', Commonjs인 경우 'commonjs'
globals: {
// linting 중 전역 범위에 추가되어야하는 추가 개체를 지정
...globals.browser,
...globals.es2021,
Set: true,
Map: true,
},
parser: typescriptParser, // parse() 또는 parseForESLint() 메서드를 포함하는 객체, 기본 값은 'espree', 추가적으로 레거시 프로젝트에서는 babel로 되어있는 parser일 수 있음
parserOptions: {
// parse() 또는 parseForESLint() 메서드에 직접 전달되는 추가 옵션을 지정
ecmaFeatures: {
jsx: true,
},
tsconfigRootDir: '.',
},
},
plugins: {
// 플러그인 개체를 매핑
prettier: eslintPluginPrettier,
react,
'react-hooks': reactHooks,
'@typescript-eslint': typescript,
compat,
import: importPlugin,
},
settings: {
// 모든 규칙에 사용할 수 있는 정보의 key-value 쌍이 포함된 객체
react: {
version: 'detect',
},
browsers: '> 0.5%, last 2 versions, not op_mini all, Firefox ESR, not dead',
},
rules: {
// 구성된 규칙이 포함된 객체, files가 지정되면 포함된 파일만 검사
// Prettier 통합 규칙
'prettier/prettier': 'error', // Prettier 포맷팅 오류를 ESLint 에러로 표시
'comma-dangle': [
'error',
{
arrays: 'always-multiline',
objects: 'always-multiline',
imports: 'always-multiline',
exports: 'always-multiline',
functions: 'never',
},
],
// React 관련 규칙
'react/prop-types': 'off', // TypeScript 사용 시 prop-types 검사를 비활성화
'react/react-in-jsx-scope': 'off', // React 17+에서는 필요 없음
'react-hooks/rules-of-hooks': 'error', // 훅 사용 시 규칙 강제
// 'react-hooks/exhaustive-deps': 'warn', // useEffect 의존성 배열 검증

// TypeScript 관련 규칙
'@typescript-eslint/no-explicit-any': 'warn', // any 사용 최소화
// '@typescript-eslint/no-unused-vars': [
// 'warn',
// { argsIgnorePattern: '^_' }, // 사용하지 않는 변수 중 '_'로 시작하는 인자는 무시
// ],

// 최신 JavaScript 스타일 규칙
// 'prefer-const': 'error', // 가능하면 const 사용
'no-var': 'error', // var 사용 금지
'arrow-body-style': ['error', 'as-needed'], // 필요할 때만 중괄호 사용
'object-shorthand': 'error', // 객체 속성 단축 표기법 사용
'no-multiple-empty-lines': ['error', { max: 1, maxEOF: 0 }], // 빈 줄 제한

// 코드 안전성 및 문제 방지
eqeqeq: ['error', 'always'], // 항상 === 사용
'no-console': ['warn', { allow: ['warn', 'error'] }], // console.log는 경고
'no-debugger': 'warn', // 디버거 사용 경고
// 'no-unused-vars': 'warn', // TypeScript 규칙으로 대체
'no-undef': 'off', // TypeScript 환경에서 처리

// 브라우저 호환성 (Compat) 규칙
// 'compat/compat': 'warn', // 호환성 검사

// import 순서 규칙 추가
'import/order': [
'error',
{
groups: ['builtin', 'external', ['parent', 'sibling'], 'index'],
alphabetize: {
order: 'asc',
caseInsensitive: true,
},
'newlines-between': 'always',
},
],

// import 확장자 규칙만 비활성화
'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, // 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>
27 changes: 24 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,44 @@
"private": true,
"version": "0.0.0",
"type": "module",
"homepage": "https://geonhwiii.github.io/front_6th_chapter2-1",
"scripts": {
"dev": "vite",
"build": "vite build",
"build": "vite build && cp ./dist/index.advanced.html ./dist/404.html",
"preview": "vite preview",
"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:ui": "vitest --ui"
"test:advanced": "vitest advanced.test.tsx",
"test:ui": "vitest --ui",
"predeploy": "pnpm run build",
"deploy": "gh-pages -d dist"
},
"devDependencies": {
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.3.0",
"@testing-library/react-hooks": "^8.0.1",
"@testing-library/user-event": "^14.6.1",
"@typescript-eslint/eslint-plugin": "^8.38.0",
"@typescript-eslint/parser": "^8.38.0",
"@vitest/ui": "^3.2.4",
"eslint": "^9.32.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-prettier": "^5.5.3",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-vitest": "^0.5.4",
"gh-pages": "^6.3.0",
"globals": "^16.3.0",
"jsdom": "^26.1.0",
"prettier": "^3.6.2",
"vite": "^7.0.5",
"vitest": "^3.2.4"
},
"dependencies": {
"react": "^19.1.1",
"react-dom": "^19.1.1"
}
}
Loading