From 943da6f3aef6454b39bb7824af2d579f488a16b5 Mon Sep 17 00:00:00 2001 From: CHOI-HYOJEONG Date: Mon, 16 Jun 2025 17:11:05 +0900 Subject: [PATCH 01/17] assignment --- src/app/checkout/page.tsx | 61 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 4 deletions(-) diff --git a/src/app/checkout/page.tsx b/src/app/checkout/page.tsx index 0d40153..282154d 100644 --- a/src/app/checkout/page.tsx +++ b/src/app/checkout/page.tsx @@ -1,21 +1,74 @@ +"use client"; // CheckoutPage -import { useState } from "react"; +import { useEffect, useState } from "react"; import { ProductItem } from "@/types/Product"; +import Link from "next/link"; -interface CheckoutItem { - product: ProductItem; +interface CheckoutItem extends ProductItem { quantity: number; } // 과제 3 export default function CheckoutPage() { const [items, setItems] = useState([]); + const [total, setTotal] = useState(0); + + useEffect(() => { + const orderedItemsString = localStorage.getItem("order"); + + if (orderedItemsString) { + const orderedItems: CheckoutItem[] = JSON.parse(orderedItemsString); + setItems(orderedItems); + + const calculatedTotal = orderedItems.reduce( + (sum, item) => sum + Number(item.lprice) * item.quantity, + 0 + ); + setTotal(calculatedTotal); + + localStorage.removeItem("order"); + } + }, + []); // 3.1. 결제하기 구현 return (

✅ 결제가 완료되었습니다!

{/* 3.1. 결제하기 구현 */} -
+ + {items.length > 0 ? ( +
+
    + {items.map((item) => ( +
  • +
    +

    +

    + {Number(item.lprice).toLocaleString()}원 x {item.quantity}개 +

    +
    +

    + {(Number(item.lprice) * item.quantity).toLocaleString()}원 +

    +
  • + ))} +
+ +
+ 총 결제 금액: {total.toLocaleString()}원 +
+
+ ) : ( +

결제된 아이템이 없습니다.

+ )} + {/* 3.2. 홈으로 가기 버튼 구현 */} +
+ + + +
); } From b981527d15d263db423cbf2dfaea297b60a04f38 Mon Sep 17 00:00:00 2001 From: CHOI-HYOJEONG Date: Mon, 16 Jun 2025 17:11:55 +0900 Subject: [PATCH 02/17] assign --- src/app/layout.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/layout.tsx b/src/app/layout.tsx index f7fa87e..3725a53 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,6 +1,7 @@ import type { Metadata } from "next"; import { Geist, Geist_Mono } from "next/font/google"; import "./globals.css"; +import { UserProvider } from "@/context/UserContext"; const geistSans = Geist({ variable: "--font-geist-sans", @@ -27,7 +28,7 @@ export default function RootLayout({ - {children} + {children} ); From 39af6beedcb4119c376f36d595c5ee832cdf808b Mon Sep 17 00:00:00 2001 From: CHOI-HYOJEONG Date: Mon, 16 Jun 2025 17:12:43 +0900 Subject: [PATCH 03/17] Update page.tsx --- src/app/mypage/page.tsx | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/app/mypage/page.tsx b/src/app/mypage/page.tsx index 93b3ba9..e216bdd 100644 --- a/src/app/mypage/page.tsx +++ b/src/app/mypage/page.tsx @@ -1,14 +1,39 @@ +use client"; +import Link from "next/link"; +import Header from "@/component/layout/Header"; +import { useUser } from "@/context/UserContext"; + // 과제 1: 마이페이지 구현 export default function MyPage() { // 1.1. UserContext를 활용한 Mypage 구현 (UserContext에 아이디(userId: string), 나이(age: number), 핸드폰번호(phoneNumber: string) 추가) - + const { user } = useUser(); return (
{/* 1.2. Header Component를 재활용하여 Mypage Header 표기 (title: 마이페이지) */} -

마이페이지

+
{/* Mypage 정보를 UserContext 활용하여 표시 (이름, 아이디, 나이, 핸드폰번호 모두 포함) */} - +
+

+ 이름: {user.name} +

+

+ 아이디: {user.userId} +

+

+ 나이: {user.age} +

+

+ 핸드폰번호: {user.phoneNumber} +

+
{/* 1.3. 홈으로 가기 버튼 구현(Link or Router 활용) */} +
+ + + +
); } From d1fa959bf1161f8d5032d7312100ded2f0a6329c Mon Sep 17 00:00:00 2001 From: CHOI-HYOJEONG Date: Mon, 16 Jun 2025 17:13:10 +0900 Subject: [PATCH 04/17] Update page.tsx --- src/app/search/page.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/app/search/page.tsx b/src/app/search/page.tsx index c3b6212..b01d7a4 100644 --- a/src/app/search/page.tsx +++ b/src/app/search/page.tsx @@ -11,11 +11,15 @@ import { useSearch } from "../../context/SearchContext"; export default function SearchHome() { const { user, setUser } = useUser(); const { result } = useSearch(); - // 페이지 최초 렌더링 될 때, setUser로 이름 설정 useEffect(() => { // 학번 + 이름 형태로 작성 (ex. 2025***** 내이름 ) - setUser({ name: "" }); + setUser({ + userId: "202102693 장성근", + name: "jangseonggeun", + age: 24, + phoneNumber: "010-1234-5678", + }); }, []); return ( From 1e4f64caaca14eb1762e95022363a5b3072bfd46 Mon Sep 17 00:00:00 2001 From: CHOI-HYOJEONG Date: Mon, 16 Jun 2025 17:13:36 +0900 Subject: [PATCH 05/17] Update SearchInput.tsx --- src/component/search/SearchInput.tsx | 61 ++++++++++++---------------- 1 file changed, 26 insertions(+), 35 deletions(-) diff --git a/src/component/search/SearchInput.tsx b/src/component/search/SearchInput.tsx index aea7294..b01d7a4 100644 --- a/src/component/search/SearchInput.tsx +++ b/src/component/search/SearchInput.tsx @@ -1,43 +1,34 @@ "use client"; -import { useSearch } from "@/context/SearchContext"; -export default function SearchInput() { - const { query, setQuery, setResult } = useSearch(); +import Header from "../../component/layout/Header"; +import Footer from "../../component/layout/Footer"; +import SearchInput from "../../component/search/SearchInput"; +import ProductCart from "../../component/shopping/ProductCart"; +import { useUser } from "../../context/UserContext"; +import { useEffect } from "react"; +import { useSearch } from "../../context/SearchContext"; - // 검색 기능 - const search = async () => { - try { - const res = await fetch(`/api/search?query=${encodeURIComponent(query)}`); - if (!res.ok) throw new Error(`${res.status} 에러 발생`); - - const data = await res.json(); - setResult(data.items || []); - } catch (error) { - alert(error); - setResult([]); - } - }; - - // 2.2. SearchInput 컴포넌트가 최초 렌더링 될 때, input tag에 포커스 되는 기능 - const handleInputChange = () => {}; - - // 과제 1-2-3: 페이지 최초 렌더링 시, input에 포커스 되는 기능 (useRef) +export default function SearchHome() { + const { user, setUser } = useUser(); + const { result } = useSearch(); + // 페이지 최초 렌더링 될 때, setUser로 이름 설정 + useEffect(() => { + // 학번 + 이름 형태로 작성 (ex. 2025***** 내이름 ) + setUser({ + userId: "202102693 장성근", + name: "jangseonggeun", + age: 24, + phoneNumber: "010-1234-5678", + }); + }, []); return ( -
- - +
+
+
+ + +
); } From ccf0b8856380912a7ddd9632f8cf178f234eb53a Mon Sep 17 00:00:00 2001 From: CHOI-HYOJEONG Date: Mon, 16 Jun 2025 17:14:10 +0900 Subject: [PATCH 06/17] Update CartList.tsx --- src/component/shopping/CartList.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/component/shopping/CartList.tsx b/src/component/shopping/CartList.tsx index adc8745..4efcd76 100644 --- a/src/component/shopping/CartList.tsx +++ b/src/component/shopping/CartList.tsx @@ -1,5 +1,6 @@ "use client"; import { ProductItem } from "@/types/Product"; +import { useRouter } from "next/navigation"; interface Props { cart: { [productId: string]: number }; @@ -8,6 +9,7 @@ interface Props { } export default function CartList({ cart, products, onRemove }: Props) { + const router = useRouter(); const cartItems = Object.entries(cart) .map(([id, quantity]) => { const product = products.find((p) => p.productId === id); @@ -21,8 +23,12 @@ export default function CartList({ cart, products, onRemove }: Props) { ); // 2.4 결제하기: "결제하기" 버튼을 클릭하면, 현재 장바구니에 담긴 상품을 확인해 **localStorage**에 저장 후, 결제완료(/checkout) 페이지로 이동한다. - const handleCheckout = () => {}; + const handleCheckout = () => { + localStorage.setItem("order", JSON.stringify(cartItems)); + router.push("/checkout"); + }; + return (

🛒 장바구니

From 3624b607e3da2b67742ff3cacac50c29cb4b51fd Mon Sep 17 00:00:00 2001 From: CHOI-HYOJEONG Date: Mon, 16 Jun 2025 17:14:57 +0900 Subject: [PATCH 07/17] Update ProductCard.tsx --- src/component/shopping/ProductCard.tsx | 118 ++++++++++--------------- 1 file changed, 47 insertions(+), 71 deletions(-) diff --git a/src/component/shopping/ProductCard.tsx b/src/component/shopping/ProductCard.tsx index 8a8327b..c7264c0 100644 --- a/src/component/shopping/ProductCard.tsx +++ b/src/component/shopping/ProductCard.tsx @@ -1,78 +1,54 @@ -import Image from "next/image"; -import { useState } from "react"; +// ProductCartPage.tsx +import { useEffect, useState } from "react"; +import ProductList from "./ProductList"; import { ProductItem } from "@/types/Product"; +import CartList from "./CartList"; -interface Props { - item: ProductItem; - onAddToCart: (item: ProductItem, quantity: number) => void; -} +export default function ProductCart({ items }: { items: ProductItem[] }) { + const [cart, setCart] = useState<{ [id: string]: number }>({}); // {"88159814281" : 1} + const [showCart, setShowCart] = useState(false); // 과제 2.1 -export default function ProductCard({ item, onAddToCart }: Props) { - const [quantity, setQuantity] = useState(1); + // 카트에 담기 - return ( -
  • -
    - {item.title} -
    -
    -
    -

    -

    - {item.brand} / {item.maker} -

    -

    {item.mallName}

    -

    - {Number(item.lprice).toLocaleString()}원 -

    -

    - 카테고리:{" "} - {[item.category1, item.category2, item.category3] - .filter(Boolean) - .join(" > ")} -

    - {/* 수량 조절 UI */} -
    - - {quantity} - + useEffect(() => { + const hasItems = Object.keys(cart).length > 0; + setShowCart(hasItems); + }, [cart]); + + const handleAddToCart = (item: ProductItem, quantity: number) => { + setCart((prev) => ({ + ...prev, + [item.productId]: quantity, + })); + + localStorage.setItem(item.productId, quantity + ""); + localStorage.getItem(item.productId); + }; - -
    -

    - - 상세 보기 - -
    -
  • + /* 과제 2-3: Cart 아이템 지우기 */ + const handleRemoveFromCart = (productId: string) => { + setCart((prev) => { + const cartEntries = Object.entries(prev); + const filteredEntries = cartEntries.filter( + ([key, value]) => key !== productId + ); + const newCart = Object.fromEntries(filteredEntries); + + return newCart; + }); + + localStorage.removeItem(productId); + }; + + return ( +
    + {/* 상품 리스트 */} + + {/* 장바구니 */} + {/* 2.1. 조건부 카트 보이기: 카트에 담긴 상품이 없으면 카트가 보이지 않고, 카트에 담긴 물건이 있으면 카트가 보인다 */} + {showCart && ( + + )} +
    ); } From f2ebb3a2ec91aadc28046114a0cc9bde90edf146 Mon Sep 17 00:00:00 2001 From: CHOI-HYOJEONG Date: Mon, 16 Jun 2025 17:15:36 +0900 Subject: [PATCH 08/17] Update UserContext.tsx --- src/context/UserContext.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/context/UserContext.tsx b/src/context/UserContext.tsx index e5d3f14..2e92093 100644 --- a/src/context/UserContext.tsx +++ b/src/context/UserContext.tsx @@ -8,6 +8,9 @@ interface User { name: string; // age: number // 추가하고 싶은 속성들 ... + userId: string; + age: number; + phoneNumber: string; } // UserContextType interface UserContextType { @@ -22,7 +25,12 @@ export const UserContext = createContext( // 2. Provider 생성 export const UserProvider = ({ children }: { children: ReactNode }) => { - const [user, setUser] = useState({ name: "" }); + const [user, setUser] = useState({ + name: "최효정", + userId: "202302632", + age: 24, + phoneNumber: "010-1234-5678", + }); return ( {children} From 6ddc7bd5cdcfe6671f0dd5f9f5306f333f4e10d5 Mon Sep 17 00:00:00 2001 From: CHOI-HYOJEONG Date: Mon, 16 Jun 2025 17:20:33 +0900 Subject: [PATCH 09/17] Update SearchInput.tsx --- src/component/search/SearchInput.tsx | 66 ++++++++++++++++++---------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/src/component/search/SearchInput.tsx b/src/component/search/SearchInput.tsx index b01d7a4..bae7c03 100644 --- a/src/component/search/SearchInput.tsx +++ b/src/component/search/SearchInput.tsx @@ -1,34 +1,52 @@ "use client"; +import { useSearch } from "@/context/SearchContext"; +import { useRef, useEffect } from "react"; -import Header from "../../component/layout/Header"; -import Footer from "../../component/layout/Footer"; -import SearchInput from "../../component/search/SearchInput"; -import ProductCart from "../../component/shopping/ProductCart"; -import { useUser } from "../../context/UserContext"; -import { useEffect } from "react"; -import { useSearch } from "../../context/SearchContext"; +export default function SearchInput() { + const { query, setQuery, setResult } = useSearch(); + const inputRef = useRef(null); -export default function SearchHome() { - const { user, setUser } = useUser(); - const { result } = useSearch(); - // 페이지 최초 렌더링 될 때, setUser로 이름 설정 useEffect(() => { - // 학번 + 이름 형태로 작성 (ex. 2025***** 내이름 ) - setUser({ - userId: "202102693 장성근", - name: "jangseonggeun", - age: 24, - phoneNumber: "010-1234-5678", - }); + if (inputRef.current) { + inputRef.current.focus(); + } }, []); + + // 검색 기능 + const search = async () => { + try { + const res = await fetch(`/api/search?query=${encodeURIComponent(query)}`); + if (!res.ok) throw new Error(`${res.status} 에러 발생`); + + const data = await res.json(); + } catch (error) { + alert(error); + setResult([]); + } + }; + + // 2.2. SearchInput 컴포넌트가 최초 렌더링 될 때, input tag에 포커스 되는 기능 + const handleInputChange = (e: React.ChangeEvent) => { + setQuery(e.target.value); + }; + // 과제 1-2-3: 페이지 최초 렌더링 시, input에 포커스 되는 기능 (useRef) return ( -
    -
    -
    - - -
    +
    + +
    ); } From acc08551d5bdac8984ed034302a199a31d2babd6 Mon Sep 17 00:00:00 2001 From: CHOI-HYOJEONG Date: Mon, 16 Jun 2025 17:24:29 +0900 Subject: [PATCH 10/17] Update page.tsx --- src/app/search/page.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/search/page.tsx b/src/app/search/page.tsx index b01d7a4..50266a9 100644 --- a/src/app/search/page.tsx +++ b/src/app/search/page.tsx @@ -15,9 +15,9 @@ export default function SearchHome() { useEffect(() => { // 학번 + 이름 형태로 작성 (ex. 2025***** 내이름 ) setUser({ - userId: "202102693 장성근", - name: "jangseonggeun", - age: 24, + userId: "202302632 최효정", + name: "choihyojeong", + age: 26, phoneNumber: "010-1234-5678", }); }, []); From 3556d06068b691839375de69ecb0550fade7271b Mon Sep 17 00:00:00 2001 From: CHOI-HYOJEONG Date: Wed, 25 Jun 2025 19:08:05 +0900 Subject: [PATCH 11/17] Update SearchInput.tsx --- src/component/search/SearchInput.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/component/search/SearchInput.tsx b/src/component/search/SearchInput.tsx index bae7c03..b29dd33 100644 --- a/src/component/search/SearchInput.tsx +++ b/src/component/search/SearchInput.tsx @@ -11,7 +11,7 @@ export default function SearchInput() { inputRef.current.focus(); } }, []); - + // 검색 기능 const search = async () => { try { @@ -19,6 +19,8 @@ export default function SearchInput() { if (!res.ok) throw new Error(`${res.status} 에러 발생`); const data = await res.json(); + console.log("검색 결과:", data.items); + setResult(data.items || []); } catch (error) { alert(error); setResult([]); @@ -29,6 +31,7 @@ export default function SearchInput() { const handleInputChange = (e: React.ChangeEvent) => { setQuery(e.target.value); }; + // 과제 1-2-3: 페이지 최초 렌더링 시, input에 포커스 되는 기능 (useRef) return ( From 2de52cd68471149c39fe60298e6f256483b5b224 Mon Sep 17 00:00:00 2001 From: CHOI-HYOJEONG Date: Wed, 25 Jun 2025 19:21:05 +0900 Subject: [PATCH 12/17] Update page.tsx --- src/app/checkout/page.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/checkout/page.tsx b/src/app/checkout/page.tsx index 282154d..fc499e4 100644 --- a/src/app/checkout/page.tsx +++ b/src/app/checkout/page.tsx @@ -60,7 +60,6 @@ export default function CheckoutPage() { ) : (

    결제된 아이템이 없습니다.

    )} - {/* 3.2. 홈으로 가기 버튼 구현 */}
    From 8753aeb649bedc1ef55858b83a48218e56899add Mon Sep 17 00:00:00 2001 From: CHOI-HYOJEONG Date: Wed, 25 Jun 2025 19:22:32 +0900 Subject: [PATCH 13/17] Update CartList.tsx --- src/component/shopping/CartList.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/component/shopping/CartList.tsx b/src/component/shopping/CartList.tsx index 4efcd76..4000f77 100644 --- a/src/component/shopping/CartList.tsx +++ b/src/component/shopping/CartList.tsx @@ -28,7 +28,7 @@ export default function CartList({ cart, products, onRemove }: Props) { router.push("/checkout"); }; - + return (

    🛒 장바구니

    From cb89acff425ff126d8c9d07e479bcabbffe6bd1f Mon Sep 17 00:00:00 2001 From: CHOI-HYOJEONG Date: Wed, 25 Jun 2025 19:23:32 +0900 Subject: [PATCH 14/17] Update CartList.tsx From 981fe6dc9cd32b2ec6088e075322c8cd3fbd4457 Mon Sep 17 00:00:00 2001 From: CHOI-HYOJEONG Date: Wed, 25 Jun 2025 19:24:27 +0900 Subject: [PATCH 15/17] Update ProductCard.tsx --- src/component/shopping/ProductCard.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/component/shopping/ProductCard.tsx b/src/component/shopping/ProductCard.tsx index c7264c0..9393bab 100644 --- a/src/component/shopping/ProductCard.tsx +++ b/src/component/shopping/ProductCard.tsx @@ -20,7 +20,6 @@ export default function ProductCart({ items }: { items: ProductItem[] }) { ...prev, [item.productId]: quantity, })); - localStorage.setItem(item.productId, quantity + ""); localStorage.getItem(item.productId); }; @@ -39,7 +38,7 @@ export default function ProductCart({ items }: { items: ProductItem[] }) { localStorage.removeItem(productId); }; - + return (
    {/* 상품 리스트 */} From 43c38b37c6adb6f7742d0fb1dddaea37ef3a6124 Mon Sep 17 00:00:00 2001 From: CHOI-HYOJEONG Date: Wed, 25 Jun 2025 19:27:49 +0900 Subject: [PATCH 16/17] Update ProductCard.tsx --- src/component/shopping/ProductCard.tsx | 117 +++++++++++++++---------- 1 file changed, 71 insertions(+), 46 deletions(-) diff --git a/src/component/shopping/ProductCard.tsx b/src/component/shopping/ProductCard.tsx index 9393bab..8a8327b 100644 --- a/src/component/shopping/ProductCard.tsx +++ b/src/component/shopping/ProductCard.tsx @@ -1,53 +1,78 @@ -// ProductCartPage.tsx -import { useEffect, useState } from "react"; -import ProductList from "./ProductList"; +import Image from "next/image"; +import { useState } from "react"; import { ProductItem } from "@/types/Product"; -import CartList from "./CartList"; -export default function ProductCart({ items }: { items: ProductItem[] }) { - const [cart, setCart] = useState<{ [id: string]: number }>({}); // {"88159814281" : 1} - const [showCart, setShowCart] = useState(false); // 과제 2.1 - - // 카트에 담기 - - useEffect(() => { - const hasItems = Object.keys(cart).length > 0; - setShowCart(hasItems); - }, [cart]); - - const handleAddToCart = (item: ProductItem, quantity: number) => { - setCart((prev) => ({ - ...prev, - [item.productId]: quantity, - })); - localStorage.setItem(item.productId, quantity + ""); - localStorage.getItem(item.productId); - }; - - /* 과제 2-3: Cart 아이템 지우기 */ - const handleRemoveFromCart = (productId: string) => { - setCart((prev) => { - const cartEntries = Object.entries(prev); - const filteredEntries = cartEntries.filter( - ([key, value]) => key !== productId - ); - const newCart = Object.fromEntries(filteredEntries); - - return newCart; - }); +interface Props { + item: ProductItem; + onAddToCart: (item: ProductItem, quantity: number) => void; +} - localStorage.removeItem(productId); - }; +export default function ProductCard({ item, onAddToCart }: Props) { + const [quantity, setQuantity] = useState(1); return ( -
    - {/* 상품 리스트 */} - - {/* 장바구니 */} - {/* 2.1. 조건부 카트 보이기: 카트에 담긴 상품이 없으면 카트가 보이지 않고, 카트에 담긴 물건이 있으면 카트가 보인다 */} - {showCart && ( - - )} -
    +
  • +
    + {item.title} +
    +
    +
    +

    +

    + {item.brand} / {item.maker} +

    +

    {item.mallName}

    +

    + {Number(item.lprice).toLocaleString()}원 +

    +

    + 카테고리:{" "} + {[item.category1, item.category2, item.category3] + .filter(Boolean) + .join(" > ")} +

    + {/* 수량 조절 UI */} +
    + + {quantity} + + + +
    +

    + + 상세 보기 + +
    +
  • ); } From 9dd587a207843a66e8694277fcb276a624d87e8b Mon Sep 17 00:00:00 2001 From: CHOI-HYOJEONG Date: Wed, 25 Jun 2025 19:31:14 +0900 Subject: [PATCH 17/17] Update ProductCart.tsx --- src/component/shopping/ProductCart.tsx | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/component/shopping/ProductCart.tsx b/src/component/shopping/ProductCart.tsx index a66c2b3..9393bab 100644 --- a/src/component/shopping/ProductCart.tsx +++ b/src/component/shopping/ProductCart.tsx @@ -9,18 +9,35 @@ export default function ProductCart({ items }: { items: ProductItem[] }) { const [showCart, setShowCart] = useState(false); // 과제 2.1 // 카트에 담기 + + useEffect(() => { + const hasItems = Object.keys(cart).length > 0; + setShowCart(hasItems); + }, [cart]); + const handleAddToCart = (item: ProductItem, quantity: number) => { setCart((prev) => ({ ...prev, [item.productId]: quantity, })); - localStorage.setItem(item.productId, quantity + ""); localStorage.getItem(item.productId); }; /* 과제 2-3: Cart 아이템 지우기 */ - const handleRemoveFromCart = () => {}; + const handleRemoveFromCart = (productId: string) => { + setCart((prev) => { + const cartEntries = Object.entries(prev); + const filteredEntries = cartEntries.filter( + ([key, value]) => key !== productId + ); + const newCart = Object.fromEntries(filteredEntries); + + return newCart; + }); + + localStorage.removeItem(productId); + }; return (
    @@ -28,7 +45,9 @@ export default function ProductCart({ items }: { items: ProductItem[] }) { {/* 장바구니 */} {/* 2.1. 조건부 카트 보이기: 카트에 담긴 상품이 없으면 카트가 보이지 않고, 카트에 담긴 물건이 있으면 카트가 보인다 */} - + {showCart && ( + + )}
    ); }