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

경북대 FE_정서현 4주차 Step2 #79

Open
wants to merge 25 commits into
base: hyunaeri
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
556d5f5
Feat(package.json): lint 스크립트 명령어 추가
hyunaeri Jul 17, 2024
5c66012
Docs(README.md): Step1 구현 요구사항 작성
hyunaeri Jul 17, 2024
2964853
Chore: api 경로 (BASE_URL) 수정
hyunaeri Jul 17, 2024
1398355
Feat: Price 및 ProductsInfoData 타입 구현
hyunaeri Jul 18, 2024
b69e853
Feat(useGetProductsInfo.ts): Product 정보를 가져오는 custom hooks 구현
hyunaeri Jul 18, 2024
be1b5f2
Feat(path.ts): products 경로 추가
hyunaeri Jul 18, 2024
fd9d11e
Feat(path.ts): order 경로 추가
hyunaeri Jul 18, 2024
5e10f9e
Style: simple-import-sort 규칙 준수를 위해 import 문 정렬
hyunaeri Jul 18, 2024
91c3ca9
Feat: @chakra-ui/react 설치
hyunaeri Jul 18, 2024
d50f908
Feat(App.tsx): ChakraProvider 추가
hyunaeri Jul 18, 2024
d005bd3
Chore: fetchInstance 를 사용한 코드로 수정
hyunaeri Jul 18, 2024
2e2b5b5
Feat: api 형식에 맞춘 products 및 order 경로 및 페이지 라우팅 추가
hyunaeri Jul 18, 2024
0e26fb9
Feat: ProductsDetail 컴포넌트 구현 후 ProductsPage 추가
hyunaeri Jul 18, 2024
5d60c32
Feat: Order 컴포넌트 구현 후 OrderPage 추가
hyunaeri Jul 18, 2024
1b4cbae
Feat: 각 Product 클릭 시 해당 페이지로 연결되는 기능 구현
hyunaeri Jul 18, 2024
9891534
Docs(README.md): Step1 구현사항 체크 완료
hyunaeri Jul 18, 2024
2583991
Docs(README.md): Step2 구현 요구사항 작성
hyunaeri Jul 19, 2024
4aba548
Feat: 결제 페이지 Form Validation 기능 구현
hyunaeri Jul 19, 2024
1e8b382
Feat: 결제 페이지에서 카드 메시지의 길이가 100자를 넘어가면 안내 메시지 출력
hyunaeri Jul 19, 2024
8079bcb
Feat: 상품의 개수가 선물 최대가능수량을 초과한 경우 선택 불가 및 안내문 출력
hyunaeri Jul 19, 2024
86243b0
Feat: 키보드 입력으로 선물 최대 가능 수량을 초과 할 시 입력 값을 최대 가능 수량으로 수정
hyunaeri Jul 19, 2024
87f8952
Docs(README.md): Step2 구현사항 체크 완료
hyunaeri Jul 19, 2024
51549b9
Chore: 카드 메시지 크기 조절
hyunaeri Jul 19, 2024
0ed7b91
Docs(README.md): 오타 수정
hyunaeri Jul 19, 2024
ed8050a
Merge branch 'hyunaeri' into Step2
hyunaeri Jul 22, 2024
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
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@

<h3>2️⃣ Step 2 체크리스트</h3>

- [x] 상품 상세 페이지에서 상품의 개수를 Option API 의 giftOrderLimit 을 초과한 경우 선택이 불가능하도록 구현

- [x] 결제 페이지의 Form 을 Validation 하도록 구현

- [x] 카드 메시지를 입력하지 않으면 메시지를 입력하라고 안내

- [x] 카드 메시지가 100자를 넘어가면 100자 이내로 입력하라고 안내

- [x] 현금 영수증 checkbox 클릭 시 현금 영수증 번호가 입력되었는지 확인

- [x] 현금 영수증 입력은 숫자만 입력하도록 안내

<br>

Expand Down
24 changes: 18 additions & 6 deletions src/api/hooks/useGetProductsInfo.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
import { useQuery } from '@tanstack/react-query'

import type { ProductsInfoData } from '@/types'
import type { ProductsDetailData, ProductsOptionData } from '@/types'

import { fetchInstance } from '../instance'

const getProductsPath = (product: string) => `/v1/products/${product}/detail`
const getProductsDetailPath = (product: string) => `/v1/products/${product}/detail`
const getProductsOptionPath = (product: string) => `/v1/products/${product}/options`

export const getProducts = async (product: string) => {
const response = await fetchInstance.get<ProductsInfoData>(getProductsPath(product))
export const getProductsDetail = async (product: string) => {
const response = await fetchInstance.get<ProductsDetailData>(getProductsDetailPath(product))
return response.data.detail
}

export const getProductsOptions = async (product: string) => {
const response = await fetchInstance.get<ProductsOptionData>(getProductsOptionPath(product))
return response.data.options
}

export const useGetProductsInfo = (product: string) =>
useQuery({
queryKey: [getProductsPath(product)],
queryFn: () => getProducts(product)
queryKey: [getProductsDetailPath(product), getProductsOptionPath(product)],
queryFn: async () => {
const [detail, options] = await Promise.all([
getProductsDetail(product),
getProductsOptions(product),
])
Comment on lines +24 to +27
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여러 api를 호출해야 한다면 useQueries를 사용해보면 좋을 것 같아요!
https://tanstack.com/query/latest/docs/framework/react/reference/useQueries

return { detail, options }
}
})
39 changes: 25 additions & 14 deletions src/components/features/Order/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Box, Button, Checkbox, Grid, GridItem, HStack, Image,Input, Select, Text, VStack } from '@chakra-ui/react';
import { Box, Button, Checkbox, Grid, GridItem, HStack, Image, Input, Select, Text, VStack } from '@chakra-ui/react';
import styled from '@emotion/styled';
import { useRef, useState } from 'react';
import { useLocation } from 'react-router-dom';
Expand All @@ -18,23 +18,33 @@ export const Order = () => {
const number = numberRef.current?.value;
const message = messageRef.current?.value;

// 카드 메시지가 100자를 초과할 경우 경고 표시
if (message && message.length > 100) {
alert('카드 메시지는 100자 이내로 입력해 주세요!');
return;
}

// 현금 영수증 신청을 한 경우 (체크 박스 활성화 상태)
if (check) {
if (number && message) {
if (Number.isNaN(Number(number))) {
alert('현금 영수증 번호는 숫자만 입력해주세요');
alert('현금 영수증 전화번호는 숫자만 입력 가능합니다!');
} else {
alert('주문이 완료되었습니다.');
}
} else if (!number) {
alert('현금 영수증 번호를 입력해주세요');
} else if (!message) {
alert('메시지를 입력해주세요');
}
} else {
alert('선물과 함께 보낼 카드 메시지를 작성해 주세요!');
} else if (!number) {
alert('현금 영수증에 필요한 전화번호를 입력해주세요!');
}
}

// 현금 영수증 신청을 하지 않은 경우 (체크 박스 비활성화 상태)
else {
if (message) {
alert('주문이 완료되었습니다.');
} else if (!message) {
alert('메시지를 입력해주세요');
alert('선물과 함께 보낼 카드 메시지를 작성해 주세요!');
}
}
};
Expand All @@ -49,28 +59,29 @@ export const Order = () => {
p={4}
>
<GridItem>
<VStack align="start" spacing={10}>
<Box>
<VStack align="center" spacing={10}>
<Box textAlign="center">
<Text fontSize="2xl" fontWeight="bold">나에게 주는 선물</Text>
<Input
backgroundColor="gray.100"
placeholder="선물과 함께 보낼 메시지를 적어보세요"
ref={messageRef}
mt={4}
size="lg"
width="300px"
width="750px"
height="150px"
/>
</Box>
<Box w="100%">
<Text fontSize="xl" fontWeight="bold">선물 내역</Text>
<GiftDetailBox>
<Image src={location.state.data.imageURL} alt={location.state.data.name} width="150px" height="150px" />
<Image src={location.state.data.detail.imageURL} alt={location.state.data.detail.name} width="150px" height="150px" />
<Box>
<Text fontSize="lg" fontWeight="semibold" color="gray.700">
{location.state.data.brandInfo.name}
{location.state.data.detail.brandInfo.name}
</Text>
<Text fontSize="md" fontWeight="medium" color="gray.500">
{location.state.data.name} x {location.state.itemCount}개
{location.state.data.detail.name} x {location.state.itemCount}개
</Text>
</Box>
</GiftDetailBox>
Expand Down
48 changes: 38 additions & 10 deletions src/components/features/Products/ProductsDetail/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,36 @@ export const ProductsDetail = ({ productId }: Props) => {
const authInfo = useAuth()
const navigate = useNavigate()

// 선물 최대 제한 수량
const giftOrderLimit = data?.options?.giftOrderLimit ?? 0
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0으로 방어를 하셨군요...? 그래도 괜찮나요??

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어 .. 임의로 넣은 값이긴 합니다

0으로 undefined 를 방어하면 선물하기가 안되긴 하겠네요.. ㅠㅠ


const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const value = Number(event.target.value)
if (isNaN(value)) return
setItemCount(value)
if (isNaN(value)) {
return
}

if (value > giftOrderLimit) {
alert(`최대 선물 가능 수량은 ${giftOrderLimit}개 입니다.`)
setItemCount(giftOrderLimit)
}
else {
setItemCount(value)
}
Comment on lines +33 to +39
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else로 연결하는 방식을 많이 사용하시는 것 같아요. 대신 얼리 리턴에 익숙해지는 것이 좋을 것 같습니다

}

const handleIncrement = () => {
if (itemCount < giftOrderLimit) {
setItemCount(itemCount + 1)
} else {
alert(`최대 선물 가능 수량은 ${giftOrderLimit}개 입니다.`)
}
}

const handleDecrement = () => {
if (itemCount > 1) {
setItemCount(itemCount - 1)
}
}

const handleNavigate = () => {
Expand All @@ -39,10 +65,11 @@ export const ProductsDetail = ({ productId }: Props) => {
}

useEffect(() => {
if (data) {
setTotalPrice(data.price.basicPrice * itemCount)
if (data)
setTotalPrice(data.detail.price.basicPrice * itemCount)
console.log(`상품명: ${data.detail.name} / 선물 최대 제한 수량: ${giftOrderLimit}`)
}
}, [data, itemCount])
}, [data, itemCount, giftOrderLimit])

if (isLoading) {
return (
Expand All @@ -68,30 +95,31 @@ export const ProductsDetail = ({ productId }: Props) => {
p={4}
>
<GridItem>
<Image src={data?.imageURL} alt={data?.name} />
<Image src={data?.detail?.imageURL} alt={data?.detail?.name} />
</GridItem>

<GridItem>
<Box>
<Text fontSize="2xl" fontWeight="bold">{data?.name}</Text>
<Text fontSize="xl" color="gray.600">{data?.price.basicPrice} 원</Text>
<Text fontSize="2xl" fontWeight="bold">{data?.detail?.name}</Text>
<Text fontSize="xl" color="gray.600">{data?.detail?.price.basicPrice} 원</Text>
<Text mt={4} fontSize="md" color="gray.500">
카톡 친구가 아니어도 선물 코드로 선물 할 수 있어요!
</Text>
</Box>

<Box mt={6}>
<QuantityControl>
<Button size="sm" onClick={() => setItemCount(itemCount - 1)}>-</Button>
<Button size="sm" onClick={handleDecrement}>-</Button>
<Input
type="number"
width="60px"
textAlign="center"
value={itemCount}
onChange={handleChange}
mx={2}
min={1}
/>
<Button size="sm" onClick={() => setItemCount(itemCount + 1)}>+</Button>
<Button size="sm" onClick={handleIncrement}>+</Button>
</QuantityControl>
</Box>

Expand Down
14 changes: 13 additions & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export type GoodsData = {
}
}

export type ProductsInfoData = {
export type ProductsDetailData = {
detail: {
id: number
imageURL: string
Expand All @@ -47,3 +47,15 @@ export type ProductsInfoData = {
id: number
}
}

export type ProductsOptionData = {
options: {
productId: number;
productName: string;
productPrice: number;
hasOption: boolean;
giftOrderLimit: number;
names: [];
options: [];
}
}