Skip to content

[1단계 - 장바구니 미션] 에리얼(정예지) 미션 제출합니다. #327

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

Merged
merged 116 commits into from
Jun 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
116 commits
Select commit Hold shift + click to select a range
7b0fffd
chore: 프로젝트 eslint, prettierrc 셋팅
keemsebin May 27, 2025
4aabce2
chore: emotion 셋팅
keemsebin May 27, 2025
f03237f
chore: 폴더 구조 정의
keemsebin May 27, 2025
595545e
chore: react-router-dom install
keemsebin May 27, 2025
bd71ded
docs: readme 작성
keemsebin May 27, 2025
ba792ae
feat: Header 컴포넌트 구현
keemsebin May 27, 2025
209a0cc
feat: Flex 컴포넌트 구현
keemsebin May 27, 2025
373b885
feat: Text 컴포넌트 구현
keemsebin May 27, 2025
7ea185a
feat: Button 컴포넌트 구현
keemsebin May 27, 2025
4b4a5ce
feat: AppLayout 구현
keemsebin May 27, 2025
0d0cefa
feat: CartPage 구현
keemsebin May 27, 2025
884f193
feat: CartListContainer 컴포넌트 구현
keemsebin May 27, 2025
9a80d3c
feat: CartItemDetail 컴포넌트 구현
keemsebin May 27, 2025
2751777
chore: 불필요한 파일 삭제
keemsebin May 27, 2025
b09d30f
chore: emotion 라이브러리 install
keemsebin May 27, 2025
a4854a1
chore: font 추가
keemsebin May 27, 2025
13324ff
docs: readme 업데이트
keemsebin May 27, 2025
4d0aefb
feat: QuantitySelector 컴포넌트 구현
keemsebin May 27, 2025
8c082cd
feat: 체크박스 컴포넌트 구현
keemsebin May 27, 2025
153ab3f
feat: Cart, Product type 정의
keemsebin May 27, 2025
cff3c31
chore: cart mock data 추가
keemsebin May 27, 2025
0625b01
chore: tsconfig jsxImportSource 설정
keemsebin May 27, 2025
372151b
refactor: Button 컴포넌트 isLoading 삭제
keemsebin May 27, 2025
6f34648
style: StyledCartListContainer padding 값 수정
keemsebin May 27, 2025
00c0027
refactor: CartItemDetail 컴포넌트 체크박스 컴포넌트 추가
keemsebin May 27, 2025
dcd5381
chore: index.css에 font 추가
keemsebin May 27, 2025
b6095a0
feat: App.tsx에 CartPage import
keemsebin May 27, 2025
e4fa8bf
chore: 불필요한 파일 정리
keemsebin May 27, 2025
5b16f1b
feat: PriceSummary 컴포넌트 구현
keemsebin May 27, 2025
47b7077
style: CartListContainer max height 설정
keemsebin May 27, 2025
08d0292
style: Spacing border, margin 수정
keemsebin May 27, 2025
b30a514
chore: gitignore 설정
keemsebin May 27, 2025
f190015
feat: ENV 파일 설정
keemsebin May 27, 2025
1292d8d
feat: fetcher 함수 구현
keemsebin May 27, 2025
4bb9ba3
feat: cart api 호출 함수 구현
keemsebin May 27, 2025
6e7dd0f
refactor: CartItem type에 isChecked 속성 추가
keemsebin May 27, 2025
e5f0bc7
refactor: CheckBox 컴포넌트에 type, props 설정 추가
keemsebin May 27, 2025
12290ce
feat: cart 데이터 패치 hook 구현
keemsebin May 27, 2025
178ed2a
feat: useFetchData hook 구현
keemsebin May 27, 2025
1ffb2d1
feat: CartPage에 cartItems ,PriceSummary, Button 연결
keemsebin May 27, 2025
10250a5
feat: useScrollStatus hook 구현
keemsebin May 27, 2025
a7c642c
refactor: useCart 데이터 패치 함수 추가
keemsebin May 27, 2025
9c7202c
style: CartListContainer 컴포넌트에 Overlay 추가
keemsebin May 27, 2025
7a02c9f
feat: CartItemDetail 컴포넌트에 삭제 함수 추가
keemsebin May 27, 2025
70c1373
chore: prettier 적용
keemsebin May 27, 2025
4caa9ce
feat: 수량 업데이트 함수 구현
keemsebin May 28, 2025
6b67d10
style: 장바구니 리스트 높이 변경
keemsebin May 28, 2025
c4d7b46
feat: 동적으로 결제 금액, 배송비 계산 및 렌더링
keemsebin May 28, 2025
fdb0283
feat: 체크박스 이벤트 핸들러 등록
keemsebin May 28, 2025
46f9061
docs: 기능 요구 사항 업데이트
keemsebin May 28, 2025
6638967
chore: eslint 설정
keemsebin May 28, 2025
2a3c585
style: eslint 적용으로 인한 스타일 변경
keemsebin May 28, 2025
cf5fbd7
feat: 체크박스 전체 선택/해제 기능 구현
keemsebin May 28, 2025
e0c4e5e
feat: CartInfo 컴포넌트 구현
keemsebin May 28, 2025
1291dfa
feat: OrderConfirm 컴포넌트 구현
keemsebin May 28, 2025
97047de
chore: eslint 적용
keemsebin May 28, 2025
134b08f
feat: useFunnel 구현
keemsebin May 28, 2025
11f3314
fear: shoppingContext 전역 도구 추가
keemsebin May 28, 2025
5746b2c
refactor: CartPage 컴포넌트에 funnel 추가
keemsebin May 28, 2025
783f36c
chore: Back png 추가
keemsebin May 28, 2025
6727845
feat: App.tsx에 AppLayout 추가
keemsebin May 28, 2025
d55a8b4
refactor: useCart 커스텀 훅에 useCartContext 적용
keemsebin May 28, 2025
94b9d64
chore: 불필요한 파일 정리
keemsebin May 28, 2025
522ebb0
chore: vitest config, jest config 설정
keemsebin May 28, 2025
daae642
refactor: `cartItems?.length === 0` 일 경우 조건문 추가
keemsebin May 28, 2025
c510209
refactor: StyledCartItemImg alt 문구 수정
keemsebin May 28, 2025
7765efb
chore: 불필요한 코드 정리
keemsebin May 28, 2025
475104a
test: 장바구니에 상품이 존재하는 경우 목록, 페이지에 진입했을 경우 메시지 노출 테스트 작성
keemsebin May 28, 2025
529a116
docs: 테스트 readme 업데이트
keemsebin May 28, 2025
2bf8448
docs: readme 업데이트
keemsebin May 29, 2025
87690f4
chore: test를 위한 mock 데이터 정의
keemsebin May 29, 2025
19eb17b
refactor: 장바구니 속성 props 전달
keemsebin May 29, 2025
15b75ef
feat: 컴포넌트 role 속성 추가
keemsebin May 29, 2025
6de20ab
feat: Progress 컴포넌트 구현
keemsebin May 29, 2025
dc9ec4c
test: 장바구니 금액에 따른 배송비 측정 테스트 구현
keemsebin May 29, 2025
1a0cd8e
test: + 버튼을 통한 수량 증가 테스트 작선
keemsebin May 29, 2025
956ad51
test: 전체 체크박스 해제시 구매 금액 테스트 작성
keemsebin May 29, 2025
cfc829f
test: 체크박스 선택시 상태 변경 테스트 작성
keemsebin May 29, 2025
7e7926a
test: 삭제 버튼 클릭시 해당 상품이 정상적으로 삭제되는지에 대한 테스트 작성
keemsebin May 29, 2025
f5d31b6
chore: mock 데이터 Object.freeze 적용
keemsebin May 29, 2025
53fa933
test: 주문 확인 버튼 클릭시 주문 정보 표시 테스트 작성
keemsebin May 29, 2025
2f3b0cb
chore: 사용하지 않는 코드 제거
keemsebin May 29, 2025
cc637c3
feat: Toast 컴포넌트 구현
keemsebin May 29, 2025
094b4dc
feat: isError 타입가드 구현
keemsebin May 29, 2025
2260547
refactor: isError(e) 타입 가드 적용
keemsebin May 29, 2025
a0eb3b5
chore: 사용하지 않는 파일 제거
keemsebin May 29, 2025
e3a8e73
feat: ToastProvider 적용
keemsebin May 29, 2025
5e85681
feat: 이미지 경로가 잘못되거나 엑박이뜨는 경우 NoImage 보여줌
keemsebin May 29, 2025
ed689be
docs: pr template 추가
keemsebin May 29, 2025
0ef143e
refactor: shoppingContext 제거
yeji0214 May 29, 2025
8b33f0d
chore: eslint 설치로 인한 설정 파일 수정
yeji0214 May 31, 2025
b128244
refactor: cart 관련 api를 features/Cart 내부로 이동하여 응집도 향상
yeji0214 Jun 2, 2025
1dd5cd7
refactor: 쿼리 문자열 생성을 buildQueryParams 유틸로 분리
yeji0214 Jun 2, 2025
ce502de
refactor: CartInfo의 파생값 계산을 useCartInfo 커스텀 훅으로 추출
yeji0214 Jun 2, 2025
a42e2e7
refactor: 주문 정보 계산 로직을 useOrderInfo 훅으로 분리
yeji0214 Jun 2, 2025
157a185
refactor: 가격 요약 계산 로직을 usePriceInfo 훅으로 분리
yeji0214 Jun 2, 2025
725348c
refactor: 공통 fetch 헤더 DEFAULT_HEADER 상수로 관리
yeji0214 Jun 2, 2025
3241ea6
refactor: shared/components 하위 index.tsx 파일명을 컴포넌트명으로 통일
yeji0214 Jun 2, 2025
fcf9da6
refactor: Toast 컴포넌트의 message prop을 children으로 변경
yeji0214 Jun 2, 2025
419401e
refactor: STEPS 타입을 CartPage 내부로 이동하고 setStep 파일 제거
yeji0214 Jun 2, 2025
01c15d5
feat: fetcher에서 실패 응답 시 HttpError로 명확하게 예외 처리
yeji0214 Jun 2, 2025
bc335c1
refactor: CheckBox 컴포넌트에 input 요소 추가
yeji0214 Jun 3, 2025
c62bcd3
refactor: 불필요한 컴포넌트 props 주석 제거
yeji0214 Jun 3, 2025
4d6b070
refactor: Header 컴포넌트의 justifyContent를 prop으로 제어하도록 변경
yeji0214 Jun 3, 2025
cd613a9
refactor: Toast 컴포넌트의 렌더링 타겟을 parent prop으로 주입 가능하도록 수정
yeji0214 Jun 3, 2025
605d4ef
refactor: Toast 유지 시간을 showToast의 duration 파라미터로 조절 가능하도록 수정
yeji0214 Jun 3, 2025
dbe7014
refactor: refetchFn을 직접 호출하여 mutate 흐름 단순화
yeji0214 Jun 3, 2025
c084bf1
refactor: ToastContext value를 useMemo로 최적화
yeji0214 Jun 3, 2025
7432bde
refactor: 장바구니 로직 CartContext로 이동
yeji0214 Jun 3, 2025
2c48802
refactor: useState 초기값에서 불필요한 제네릭 제거
yeji0214 Jun 3, 2025
cf0affc
chore: 불필요한 jest 코드 및 파일 제거
yeji0214 Jun 3, 2025
f400154
refactor: import 경로 alias(@) 기반으로 통일
yeji0214 Jun 3, 2025
37e78e3
feat: 배송비 무료 기준 금액을 상수로 분리하여 관리
yeji0214 Jun 3, 2025
cbc43fe
test: 통합 테스트에 실패 케이스 추가
yeji0214 Jun 4, 2025
32471d0
test: 단위 테스트 작성
yeji0214 Jun 4, 2025
02d0845
style: 포맷팅 prettier로 통일
yeji0214 Jun 4, 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
53 changes: 49 additions & 4 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,59 @@ module.exports = {
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
'plugin:import/typescript',
'plugin:import/recommended',
'prettier',
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parser: '@typescript-eslint/parser',
plugins: ['react-refresh'],
plugins: ['react-refresh', 'react'],
rules: {
'react-refresh/only-export-components': [
'@typescript-eslint/no-unused-vars': 'warn',
'@typescript-eslint/consistent-type-definitions': ['error', 'type'],
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
'react/destructuring-assignment': ['warn', 'always', { destructureInSignature: 'always' }],
'react/jsx-curly-brace-presence': [
'warn',
{ allowConstantExport: true },
{ props: 'never', children: 'never', propElementValues: 'always' },
],
'react/function-component-definition': [
'error',
{
namedComponents: 'arrow-function',
unnamedComponents: 'arrow-function',
},
],
'react/jsx-tag-spacing': 1,
'no-restricted-exports': ['error', { restrictDefaultExports: { direct: true } }],
'import/no-unresolved': 'off',
'import/order': [
'error',
{
groups: ['builtin', 'external', 'internal', 'sibling'],
pathGroups: [
{
pattern: 'react',
group: 'external',
position: 'before',
},
{
pattern: '@/**',
group: 'internal',
},
{
pattern: './*',
group: 'sibling',
},
],
distinctGroup: false,
pathGroupsExcludedImportTypes: ['builtin'],
alphabetize: {
order: 'asc',
caseInsensitive: true,
},
'newlines-between': 'always',
},
],
},
}
};
58 changes: 58 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
## 📦 장바구니 미션

이번 미션을 통해 다음과 같은 학습 경험들을 쌓는 것을 목표로 합니다.

### 1단계

- 클라이언트 상태를 효과적으로 모델링하고 관리할 수 있다.
- Jest, React Testing Library(RTL)를 활용하여 주요 기능에 대한 테스트를 작성할 수 있다.

## 🕵️ 셀프 리뷰(Self-Review)

### 제출 전 체크 리스트

- [ ] 기능 요구 사항을 모두 구현했고, 정상적으로 동작하는지 확인했나요?
- [ ] RTL 테스트 케이스를 모두 작성했나요?
- [ ] 배포한 데모 페이지에 정상적으로 접근할 수 있나요?

- 배포 링크 기입: **\_\_**

- [ ] 리뷰어가 장바구니 추가를 쉽게 할 수 있도록 Curl 명령어를 전달해주세요. (토큰을 채워주세요)

```
curl -X 'POST' \
'http://techcourse-lv2-alb-974870821.ap-northeast-2.elb.amazonaws.com/cart-items' \
-H 'accept: */*' \
-H 'Authorization: Basic <토큰>' \
-H 'Content-Type: application/json' \
-d '{
"productId": 1,
"quantity": 1
}'
```

### 리뷰 요청 & 논의하고 싶은 내용

### 1) 상태 설계 의도

### 2) 이번 단계에서 가장 많이 고민했던 문제와 해결 과정에서 배운 점

### 3) 이번 리뷰를 통해 논의하고 싶은 부분

---

## ✅ 리뷰어 체크 포인트

<!-- 리뷰어가 이 PR을 검토할 때 중점적으로 확인할 사항입니다.
코드의 완성도뿐만 아니라, 리뷰이가 구현 과정에서 어떤 고민과 결정을 하며 학습했는지도 함께 고려해 주세요. -->

### 1. 클라이언트 상태관리

- 원본상태/파생상태를 적절히 구분하여 선언하였나요?
- React state 를 불필요하게 선언한 부분은 없나요?
- 상태 관리 로직의 책임이 적절히 응집/분리되었나요? (ex. reducer, hook, Context)

### 2. MSW/Test

- 주요 기능을 적절히 정의하였나요?
- 주요 기능/예외에 대한 테스트가 충분히 이루어졌나요?
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,5 @@ dist-ssr
*.njsproj
*.sln
*.sw?

.env
11 changes: 11 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"trailingComma": "es5",
"bracketSpacing": true,
"arrowParens": "always",
"endOfLine": "auto"
}
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,39 @@
# react-shopping-cart

**기능 요구 사항**

- [x] **`/cart-items`** API를 호출하여 장바구니 상품 데이터를 불러온다.
- [x] 개별 상품의 선택 여부, 결제 금액, 배송비 등의 상태를 관리한다.
- [x] 상품 선택에 따른 주문 금액, 배송비 등의 동적인 변경 사항을 처리한다.
- [x] 진입 시, 전체 선택 되어 있는 것이 디폴트이다.
- [x] 상품 선택/해제 시 주문 금액을 동적으로 변경한다.
- [x] 결제 금액이 10만원 이상일 경우 배송비는 무료이다.
- [x] 장바구니 상품의 수량을 변경할 수 있다.
- [x] 장바구니에 담긴 상품을 제거할 수 있다.
- [x] 장바구니에 담긴 상품이 없는 경우 헬퍼문구를 보여준다.
- [x] 주문 확인버튼을 클릭할 경우 페이지 이동과 함께 선택정보들과 결제금액을 보여준다.

**컴포넌트**

- [x] AppLayout
- [x] Header
- [x] CartItem
- [x] CartItemList
- [x] Text
- [x] Flex
- [x] Checkbox
- [x] Button
- [x] PriceSummary
- [x] QuantityController

**테스트**

- [x] 장바구니 목록을 렌더링한다.
- [x] 수량 조절 기능이 가능하다. (-/+)
- [x] 주문 금액이 10만원 이상인 경우 배송비가 0원이 된다.
- [x] 주문 금액이 10만원 이하인 경우 배송비가 3000원이 된다.
- [x] 체크박스 선택 시 주문 금액에 변동이 생긴다.
- [x] 장바구니에 담긴 상품 개수를 문구로 보여준다.
- [x] 장바구니에 담긴 상품이 없는 경우 `장바구니에 담은 상품이 없다`라는 메세지를 보여준다.
- [x] 삭제 버튼 클릭 시 장바구니에서 해당 상품이 삭제된다.
- [x] 주문 확인 버튼을 클릭했을 때, 정보를 집약해서 보여준다.
15 changes: 15 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import js from '@eslint/js';
import globals from 'globals';
import tseslint from 'typescript-eslint';
import pluginReact from 'eslint-plugin-react';
import { defineConfig } from 'eslint/config';

export default defineConfig([
{ files: ['**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], plugins: { js }, extends: ['js/recommended'] },
{
files: ['**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
languageOptions: { globals: { ...globals.browser, ...globals.node } },
},
tseslint.configs.recommended,
pluginReact.configs.flat.recommended,
]);
6 changes: 3 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<!DOCTYPE html>
<html lang="en">
<!doctype html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<link rel="icon" type="image/svg+xml" href="./public/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>React Shopping Cart</title>
</head>
Expand Down
11 changes: 0 additions & 11 deletions jest.config.ts

This file was deleted.

1 change: 0 additions & 1 deletion jest.setup.ts

This file was deleted.

Loading