Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
0f033fa
feat(docs): pr.md 파일 생성
yeojinseok1 Aug 2, 2025
2d7bb1d
feat(docs): pr.md 파일 생성
yeojinseok1 Aug 2, 2025
73b2365
packages scripts 수정
Aug 3, 2025
a2dc34c
fix: 린트 수정
realstone2 Aug 3, 2025
0eb4ef6
feat: 1일차부터 5일차까지 리팩토링 문서 추가
realstone2 Aug 3, 2025
ab0e39f
feat: 기본 폴더 구조 추가
realstone2 Aug 3, 2025
904bab2
feat(deps): jotai 패키지 추가
realstone2 Aug 3, 2025
aebf998
feat: product 관련 코드 리팩토링
realstone2 Aug 3, 2025
3cab7c1
refactor(App): 제품 관련 코드 리팩토링
realstone2 Aug 3, 2025
581282b
refactor(App): 가격 포맷팅 및 재고 확인 로직 리팩토링
realstone2 Aug 3, 2025
c26d17f
feat(hooks): 디바운스 및 검색 파라미터 훅 추가
realstone2 Aug 4, 2025
2918ed1
refactor: basic 과제 advanced 과제 내용 반영
realstone2 Aug 4, 2025
981d140
refactor: 관리자 페이지 분리
realstone2 Aug 4, 2025
e6b4dd2
refactor: MainPage 분리
realstone2 Aug 4, 2025
6948fb9
feat(hooks): 검색 파라미터 변경 이벤트 처리 추가
realstone2 Aug 4, 2025
9219159
refactor: price display 유틸 함수 리팩토링
realstone2 Aug 4, 2025
eb56383
feat(hooks): useProducts localStorage 저장 로직 추가
realstone2 Aug 4, 2025
28b1098
refactor: AdminPage, MainPage 불필요 함수 제거
realstone2 Aug 4, 2025
64d1f34
refactor: cart domain 데이터 분리
realstone2 Aug 4, 2025
4951f09
refactor: ESLint 설정 파일 업데이트 및 React 관련 규칙 추가
realstone2 Aug 5, 2025
95c9395
refactor: useLocalStorage 및 useValidate 훅 삭제
realstone2 Aug 5, 2025
75780ec
refactor: useCart 함수 다일책임원칙 리팩토링
realstone2 Aug 5, 2025
b0451cf
refactor: App.tsx에서 불필요한 CartItem 임포트 제거 및 useProducts 임포트 위치 수정
realstone2 Aug 5, 2025
1841262
refactor: 쿠폰 domain 분리
realstone2 Aug 5, 2025
f36deee
refactor: Header 컴포넌트 분리
realstone2 Aug 5, 2025
f3545e4
refactor: App.tsx에서 NotificationList 컴포넌트로 알림 표시 로직 분리
realstone2 Aug 5, 2025
8202dbe
refactor: 폴더 구조 리팩토링
realstone2 Aug 5, 2025
dfb5ad4
refactor: 폴더 구조 리팩토링 import 에러 수정
realstone2 Aug 5, 2025
cb8feed
refactor: ProductList 컴포넌트 추가 및 장바구니 기능 개선
realstone2 Aug 5, 2025
81d290b
refactor: svg icon component로 분리
realstone2 Aug 5, 2025
23be1f8
refactor: ShopPage 컴포넌트 분리
realstone2 Aug 5, 2025
33275e2
refactor: adminPage 컴포넌트 분리
realstone2 Aug 5, 2025
c748070
refactor: advanced 과제 basic과제 내용 반영
realstone2 Aug 6, 2025
ec16324
refactor: 장바구니, 쿠폰, 상품 상태 관리를 Jotai로 변경
realstone2 Aug 6, 2025
51e34fd
refactor: 쿠폰 관련 로직을 CouponManagement 컴포넌트로 이동 및 App.tsx에서 제거
realstone2 Aug 6, 2025
d4e4e1e
refactor: App.tsx에서 useProducts 훅 제거 및 ProductAccordion, ProductList …
realstone2 Aug 6, 2025
bd952fe
refactor: useCart 훅을 사용하여 장바구니 관련 로직 통합 및 컴포넌트 간소화
realstone2 Aug 6, 2025
8120be8
refactor: hook에서 순수함수 사용 및 중복 handle 분리 방안 논의 추가
realstone2 Aug 6, 2025
4c699d6
refactor: ShopPage에서 쿠폰 상태 관리 로직을 내부 상태로 변경 및 App.tsx에서 관련 props 제거
realstone2 Aug 6, 2025
0600499
feat: jotai 알림 초기화 로직 추가
realstone2 Aug 6, 2025
9d9f893
refactor: notification domain 분리
realstone2 Aug 6, 2025
9fc68e3
refactor: 코드 정리
realstone2 Aug 7, 2025
78d4b42
feat: 상품 폼 데이터 타입 추가 및 Jotai를 통한 상태 관리 통합
realstone2 Aug 7, 2025
8d52559
feat: 상품 폼 상태 관리 로직 개선 및 초기화 데이터 통합
realstone2 Aug 7, 2025
e2738eb
feat: 상품 폼 초기화 로직을 상수로 통합하여 상태 관리 개선
realstone2 Aug 7, 2025
f0a9c20
feat: Vite 설정 파일 업데이트 및 GitHub Pages 배포 워크플로우 추가
realstone2 Aug 7, 2025
f559536
refactor: pr.md에 단순 계산 유틸 함수 사용 여부에 대한 선택 추가 및 vite.config.ts에서 주석 처리…
realstone2 Aug 7, 2025
3556115
refactor: 불필요 파일 제거
realstone2 Aug 7, 2025
9084ba9
refactor: useLocalStorage 훅을 추가하여 장바구니, 쿠폰, 상품 상태 관리 로직 개선
realstone2 Aug 7, 2025
070f468
feat: index.html 파일 추가 및 Vite 설정에서 입력 파일 경로 수정
realstone2 Aug 7, 2025
365d367
feat(cart): 장바구니 수량 변경 로직 개선
realstone2 Aug 9, 2025
cdf94ae
refactor(shop): 장바구니 수량 변경 로직 제거
realstone2 Aug 9, 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
49 changes: 40 additions & 9 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,48 @@ module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parser: '@typescript-eslint/parser',
plugins: ['react-refresh'],
ignorePatterns: ["dist", ".eslintrc.cjs"],
parser: "@typescript-eslint/parser",
plugins: ["react-refresh", "react"],
settings: {
react: {
version: "detect",
},
},
rules: {
'react-refresh/only-export-components': [
'warn',
"react-refresh/only-export-components": [
"warn",
{ allowConstantExport: true },
],
// React dependency 체크 관련 규칙들
"react-hooks/exhaustive-deps": "warn",
"react-hooks/rules-of-hooks": "error",
// React 관련 추가 규칙들
"react/jsx-key": "error",
"react/jsx-no-duplicate-props": "error",
"react/jsx-no-undef": "error",
"react/jsx-pascal-case": "warn",
"react/jsx-uses-react": "error",
"react/jsx-uses-vars": "error",
"react/no-array-index-key": "warn",
"react/no-danger": "warn",
"react/no-deprecated": "warn",
"react/no-direct-mutation-state": "error",
"react/no-find-dom-node": "warn",
"react/no-is-mounted": "error",
"react/no-render-return-value": "error",
"react/no-string-refs": "error",
"react/no-unescaped-entities": "warn",
"react/no-unknown-property": "error",
"react/no-unsafe": "warn",
"react/self-closing-comp": "warn",
"react/sort-comp": "warn",
"react/style-prop-object": "error",
"react/void-dom-elements-no-children": "error",
},
}
};
38 changes: 38 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Deploy to GitHub Pages

on:
push:
branches: [main]

jobs:
deploy:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'

- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 10.12.4

- name: Install dependencies
run: pnpm install

- name: Build
run: pnpm build
env:
NODE_ENV: production

- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
if: github.ref == 'refs/heads/main'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist
91 changes: 91 additions & 0 deletions 1days-refactoring-prd.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Day 1: Product 도메인 완전 분리 (컴포넌트 → 상수 → 순수함수 → 상태관리)

## 목표

- Product 도메인의 모든 요소를 단계별로 완전 분리
- 컴포넌트 → 상수 → 순수함수 → 상태관리 순서로 진행
- 테스트를 계속 통과시키며 점진적 리팩토링

## 작업 범위

### 1단계: Jotai 설치 및 기본 설정

```bash
npm install jotai
```

### 2단계: Product 관련 컴포넌트 분리

```typescript
// src/advanced/components/ProductList.tsx
export const ProductList: React.FC<{
products: ProductWithUI[];
onAddToCart: (product: ProductWithUI) => void;
isAdmin: boolean;
onEditProduct?: (product: ProductWithUI) => void;
}>;

// src/advanced/components/ProductCard.tsx
export const ProductCard: React.FC<ProductCardProps>;

// src/advanced/components/ProductForm.tsx (관리자용)
export const ProductForm: React.FC<ProductFormProps>;
```

### 3단계: Product 상수 분리

```typescript
// src/advanced/constants/product.ts
export const initialProducts: ProductWithUI[] = [...]
export const PRODUCT_FORM_INITIAL_STATE = {...}
```

### 4단계: Product 순수함수 분리

```typescript
// src/advanced/utils/productUtils.ts
export const filterProducts = (products: ProductWithUI[], searchTerm: string): ProductWithUI[]
export const generateProductId = (): string
export const validateProductData = (product: Partial<ProductWithUI>): boolean

// src/advanced/utils/formatters.ts
export const formatPrice = (price: number, isAdmin: boolean = false): string
```

### 5단계: Product 상태관리 (Atom + Hook)

```typescript
// src/advanced/models/productAtoms.ts
export const productsAtom = atom<ProductWithUI[]>(initialProducts);
export const searchTermAtom = atom<string>("");
export const debouncedSearchTermAtom = atom<string>("");

// src/advanced/hooks/useProducts.ts
export const useProducts = () => {
// atom 기반 상태 관리
// CRUD 함수들
};
```

### 6단계: App.tsx에서 Product 관련 코드 제거 및 연결

- useState들 제거
- 순수함수들 제거
- 컴포넌트 import로 교체

## 테스트 전략

- [ ] 각 단계 완료 후 즉시 테스트 실행
- [ ] 기존 Product 관련 테스트 통과 확인
- [ ] 새로운 유틸리티 함수 단위 테스트

## 성공 기준

1. Product 도메인이 완전히 분리됨
2. App 컴포넌트에서 Product 관련 코드가 모두 제거됨
3. 모든 기존 테스트가 통과함
4. 검색, 상품 관리 기능이 정상 동작함

## 다음 날 준비사항

- Cart 도메인 분석 준비
103 changes: 103 additions & 0 deletions 2days-refactoring-prd.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Day 2: Cart 도메인 완전 분리 (컴포넌트 → 상수 → 순수함수 → 상태관리)

## 목표

- Cart 도메인의 모든 요소를 단계별로 완전 분리
- 장바구니 관련 컴포넌트, 상수, 순수함수, 상태관리 모두 분리

## 작업 범위

### 1단계: Cart 관련 컴포넌트 분리

```typescript
// src/advanced/components/CartSummary.tsx
export const CartSummary: React.FC<{
cart: CartItem[];
selectedCoupon: Coupon | null;
onUpdateQuantity: (productId: string, quantity: number) => void;
onRemoveItem: (productId: string) => void;
onApplyCoupon: (coupon: Coupon) => void;
onCompleteOrder: () => void;
}>;

// src/advanced/components/CartItem.tsx
export const CartItem: React.FC<CartItemProps>;

// src/advanced/components/CouponSelector.tsx
export const CouponSelector: React.FC<CouponSelectorProps>;
```

### 2단계: Cart 상수 분리

```typescript
// src/advanced/constants/cart.ts
export const BULK_PURCHASE_THRESHOLD = 10;
export const BULK_PURCHASE_ADDITIONAL_DISCOUNT = 0.05;
export const MAX_DISCOUNT_RATE = 0.5;
export const MIN_PERCENTAGE_COUPON_AMOUNT = 10000;
```

### 3단계: Cart 순수함수 분리

```typescript
// src/advanced/utils/cartUtils.ts
export const getMaxApplicableDiscount = (item: CartItem, cart: CartItem[]): number
export const calculateItemTotal = (item: CartItem, cart: CartItem[]): number
export const calculateCartTotal = (cart: CartItem[], selectedCoupon: Coupon | null): CartTotal
export const getRemainingStock = (product: Product, cart: CartItem[]): number
export const getCartItemCount = (cart: CartItem[]): number

// src/advanced/utils/discountUtils.ts
export const calculateDiscountRate = (discounts: Discount[], quantity: number): number
export const hasBulkPurchase = (cart: CartItem[]): boolean
export const applyCouponDiscount = (total: number, coupon: Coupon): number
```

### 4단계: Cart 상태관리 (Atom + Hook)

```typescript
// src/advanced/models/cartAtoms.ts
export const cartAtom = atom<CartItem[]>([])
export const selectedCouponAtom = atom<Coupon | null>(null)
export const cartTotalAtom = atom<CartTotal>((get) => ...)
export const cartItemCountAtom = atom<number>((get) => ...)

// src/advanced/hooks/useCart.ts
export const useCart = () => {
// localStorage 연동
// CRUD 함수들
// 재고 검증
}
```

### 5단계: LocalStorage 연동

```typescript
// src/advanced/utils/hooks/useLocalStorage.ts
export const useLocalStorage = <T>(key: string, initialValue: T)
```

### 6단계: App.tsx에서 Cart 관련 코드 제거 및 연결

## 이전 작업과의 연결점

- Day 1에서 분리한 formatPrice 유틸리티 활용
- Product 도메인과의 연동 (재고 계산)

## 테스트 전략

- [ ] 각 단계 완료 후 즉시 테스트 실행
- [ ] 장바구니 CRUD 기능 테스트
- [ ] 할인 계산 로직 테스트
- [ ] localStorage 연동 테스트

## 성공 기준

1. Cart 도메인이 완전히 분리됨
2. App 컴포넌트에서 Cart 관련 코드가 모두 제거됨
3. 장바구니 기능이 정상 동작함
4. 모든 기존 테스트가 통과함

## 다음 날 준비사항

- Coupon 도메인 분석 준비
89 changes: 89 additions & 0 deletions 3days-refactoring-prd.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Day 3: Coupon 도메인 완전 분리 (컴포넌트 → 상수 → 순수함수 → 상태관리)

## 목표

- Coupon 도메인의 모든 요소를 단계별로 완전 분리
- 쿠폰 관련 컴포넌트, 상수, 순수함수, 상태관리 모두 분리

## 작업 범위

### 1단계: Coupon 관련 컴포넌트 분리

```typescript
// src/advanced/components/CouponList.tsx
export const CouponList: React.FC<{
coupons: Coupon[];
onApplyCoupon: (coupon: Coupon) => void;
selectedCoupon: Coupon | null;
}>;

// src/advanced/components/CouponCard.tsx
export const CouponCard: React.FC<CouponCardProps>;

// src/advanced/components/CouponForm.tsx (관리자용)
export const CouponForm: React.FC<CouponFormProps>;

// src/advanced/components/CouponManagement.tsx (관리자용)
export const CouponManagement: React.FC<CouponManagementProps>;
```

### 2단계: Coupon 상수 분리

```typescript
// src/advanced/constants/coupon.ts
export const initialCoupons: Coupon[] = [...]
export const COUPON_FORM_INITIAL_STATE = {...}
export const COUPON_VALIDATION_RULES = {...}
```

### 3단계: Coupon 순수함수 분리

```typescript
// src/advanced/utils/couponUtils.ts
export const validateCouponCondition = (coupon: Coupon, cartTotal: number): boolean
export const applyCouponDiscount = (total: number, coupon: Coupon): number
export const generateCouponCode = (): string
export const validateCouponData = (coupon: Partial<Coupon>): boolean
export const isCouponDuplicate = (coupons: Coupon[], code: string): boolean
export const getCouponDisplayText = (coupon: Coupon): string
```

### 4단계: Coupon 상태관리 (Atom + Hook)

```typescript
// src/advanced/models/couponAtoms.ts
export const couponsAtom = atom<Coupon[]>(initialCoupons)
export const availableCouponsAtom = atom<Coupon[]>((get) => ...)

// src/advanced/hooks/useCoupons.ts
export const useCoupons = () => {
// localStorage 연동
// CRUD 함수들
// 검증 로직
}
```

### 5단계: App.tsx에서 Coupon 관련 코드 제거 및 연결

## 이전 작업과의 연결점

- Day 2의 Cart total과 연동하여 쿠폰 적용 검증
- 기존 localStorage 유틸리티 재사용

## 테스트 전략

- [ ] 각 단계 완료 후 즉시 테스트 실행
- [ ] 쿠폰 적용 조건 검증 테스트
- [ ] 쿠폰 할인 계산 테스트
- [ ] 쿠폰 CRUD 기능 테스트

## 성공 기준

1. Coupon 도메인이 완전히 분리됨
2. App 컴포넌트에서 Coupon 관련 코드가 모두 제거됨
3. 쿠폰 적용 및 검증이 정상 동작함
4. 모든 기존 테스트가 통과함

## 다음 날 준비사항

- Notification 시스템 분석 준비
Loading