From 27a340d6c68e838815b2339c0259f43660574e4b Mon Sep 17 00:00:00 2001 From: jihwooon Date: Thu, 7 Mar 2024 18:21:39 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=9E=A5=EB=B0=94=EA=B5=AC=EB=8B=88=20?= =?UTF-8?q?=EB=8B=B4=EA=B8=B0=20=EA=B8=B0=EB=8A=A5=20=EB=B0=8F=20=EB=8F=84?= =?UTF-8?q?=EC=84=9C=20=EC=83=81=EC=84=B8=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 주요 변경 사항 - 장바구니 담기 API를 추가했습니다. - useBook hook을 수정하여 장바구니 담기 기능과 상태 관리를 추가했습니다. - AddToCart 컴포넌트를 생성하여 장바구니 담기 폼 구현했습니다. - 도서 상세 페이지에 AddToCart 컴포넌트를 추가하여 장바구니 담기 기능을 제공했습니다. 관련 변경 사항 - cart.api.ts 파일 생성 - AddToCart.tsx 파일 생성 - useBook.ts 파일 수정 - BookDetail.tsx 파일 수정 --- client/src/api/cart.api.ts | 14 +++++ client/src/components/book/AddToCart.tsx | 80 ++++++++++++++++++++++++ client/src/hooks/useBook.ts | 18 +++++- client/src/pages/BookDetail.tsx | 5 +- 4 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 client/src/api/cart.api.ts create mode 100644 client/src/components/book/AddToCart.tsx diff --git a/client/src/api/cart.api.ts b/client/src/api/cart.api.ts new file mode 100644 index 0000000..fb98d4b --- /dev/null +++ b/client/src/api/cart.api.ts @@ -0,0 +1,14 @@ +import { httpClient } from "./http"; + +interface AddCartParams { + book_id: number; + quantity: number; +} + +const addCart = async (params: AddCartParams) => { + const response = await httpClient.post('/cart', params) + + return response.data +}; + +export default addCart; diff --git a/client/src/components/book/AddToCart.tsx b/client/src/components/book/AddToCart.tsx new file mode 100644 index 0000000..282a034 --- /dev/null +++ b/client/src/components/book/AddToCart.tsx @@ -0,0 +1,80 @@ +import { useState } from "react"; +import { Link } from "react-router-dom"; +import styled from "styled-components"; +import { useBook } from "../../hooks/useBook"; +import { BookDetail } from "../../models/book.model"; +import Button from "../common/Button"; +import { InputText } from "../common/InputText"; + +interface Props { + book: BookDetail; +} + +const AddToCart = ({ book }: Props) => { + const [quantity, setQuantity] = useState(1) + const { addToCart, cartAdded } = useBook(book.id.toString()); + + const handleChange = (e: React.ChangeEvent) => { + setQuantity(Number(e.target.value)) + } + + const handleIncrease = () => { + setQuantity(quantity + 1) + } + + const handleDecrease = () => { + if (quantity === 1) return + setQuantity(quantity - 1) + } + + return ( + +
+ + + +
+ +
+

장바구니에 추가되었습니다.

+ 장바구니 이동 +
+
+ ); +} + +interface AddToCartStyleProps { + $added: boolean; +} + +const AddToCartStyle = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + + position: relative; + + .added { + position: absolute; + right: 0; + bottom: -90px; + background: ${({ theme }) => theme.color.background}; + border-radius: ${({ theme }) => theme.borderRadius.default}; + padding: 8px 12px; + opacity: ${({ $added }) => $added ? "1" : "0"}; + transition: all 0.5s ease; + } + + p { + padding: 0 0 8px 0; + margin: 0; + } +`; + +export default AddToCart; diff --git a/client/src/hooks/useBook.ts b/client/src/hooks/useBook.ts index 88fd7db..06bded3 100644 --- a/client/src/hooks/useBook.ts +++ b/client/src/hooks/useBook.ts @@ -1,5 +1,6 @@ import { useEffect, useState } from "react"; import { fetchBook, likeBook, unlikeBook } from "../api/books.api"; +import addCart from "../api/cart.api"; import { BookDetail } from "../models/book.model"; import { useAuthStore } from "../store/authStore"; import { useAlert } from "./useAlert"; @@ -8,6 +9,7 @@ export const useBook = (bookId: string | undefined) => { const [book, setBook] = useState(null); const { isLoggedIn } = useAuthStore(); const showAlert = useAlert(); + const [cartAdded, setCartAdded] = useState(false) const likeToggle = () => { if (!isLoggedIn) { @@ -36,6 +38,20 @@ export const useBook = (bookId: string | undefined) => { } } + const addToCart = (quantity: number) => { + if (!book) return + + addCart({ + book_id: book.id, + quantity: quantity + }).then(() => { + setCartAdded(true) + setTimeout(() => { + setCartAdded(false) + }, 3000) + }) + } + useEffect(() => { if (!bookId) return; @@ -44,5 +60,5 @@ export const useBook = (bookId: string | undefined) => { }) }, [bookId]) - return { book, likeToggle } + return { book, likeToggle, addToCart, cartAdded } } diff --git a/client/src/pages/BookDetail.tsx b/client/src/pages/BookDetail.tsx index 95fbd19..b4dd554 100644 --- a/client/src/pages/BookDetail.tsx +++ b/client/src/pages/BookDetail.tsx @@ -1,5 +1,6 @@ import { Link, useParams } from "react-router-dom"; import styled from "styled-components"; +import AddToCart from "../components/book/AddToCart"; import LikeButton from "../components/book/LikeButton"; import EllipsisBox from "../components/common/EllipisisBox"; import Title from "../components/common/Title"; @@ -77,7 +78,9 @@ const BookDetail = () => {
-
Cart
+
+ +