From 39c7a469b0ab86b556d825197719ccb52bbd0271 Mon Sep 17 00:00:00 2001 From: 2ndSilverMAn <2ndsilverman@gmail.com> Date: Sun, 15 Jun 2025 21:05:53 +0900 Subject: [PATCH] =?UTF-8?q?(=EB=8D=B0=EC=8A=A4=ED=81=AC=ED=83=91)=20?= =?UTF-8?q?=EA=B3=BC=EC=A0=9C=201,=202,=203=20=EA=B5=AC=ED=98=84=EC=99=84?= =?UTF-8?q?=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/checkout/page.tsx | 66 +++++++++++++++++++++++--- src/app/layout.tsx | 5 +- src/app/mypage/page.tsx | 46 +++++++++++++++--- src/component/search/SearchInput.tsx | 11 ++++- src/component/shopping/CartList.tsx | 26 +++++++++- src/component/shopping/ProductCart.tsx | 9 +++- src/context/UserContext.tsx | 12 +++-- 7 files changed, 154 insertions(+), 21 deletions(-) diff --git a/src/app/checkout/page.tsx b/src/app/checkout/page.tsx index 0d40153..dd19857 100644 --- a/src/app/checkout/page.tsx +++ b/src/app/checkout/page.tsx @@ -1,21 +1,75 @@ -// CheckoutPage -import { useState } from "react"; +"use client"; +import { useEffect, useState } from "react"; import { ProductItem } from "@/types/Product"; +import Link from "next/link"; interface CheckoutItem { - product: ProductItem; + productId: string; + title: string; + lprice: string; quantity: number; } // 과제 3 export default function CheckoutPage() { const [items, setItems] = useState([]); + // 3.1. 결제하기 구현 + useEffect(() => { + // localStorage에서 결제된 아이템 가져오기 + const checkoutItems = localStorage.getItem('checkoutItems'); + if (checkoutItems) { + setItems(JSON.parse(checkoutItems)); + // 결제 완료 후 localStorage에서 데이터 삭제 + localStorage.removeItem('checkoutItems'); + } + }, []); + + // 총 금액 계산 + const total = items.reduce( + (sum, item) => sum + Number(item.lprice) * item.quantity, + 0 + ); + return (

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

- {/* 3.1. 결제하기 구현 */} -
- {/* 3.2. 홈으로 가기 버튼 구현 */} + + {items.length === 0 ? ( +

결제된 아이템이 없습니다

+ ) : ( +
+ {items.map((item) => ( +
+

+
+ 수량: {item.quantity}개 + 가격: {Number(item.lprice).toLocaleString()}원 +
+
+ 소계: {(Number(item.lprice) * item.quantity).toLocaleString()}원 +
+
+ ))} + +
+
+ 총 결제 금액 + + {total.toLocaleString()}원 + +
+
+
+ )} + +
+ + 홈으로 가기 + +
); } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index f7fa87e..b770786 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,9 @@ export default function RootLayout({ - {children} + + {children} + ); diff --git a/src/app/mypage/page.tsx b/src/app/mypage/page.tsx index 93b3ba9..5cbcad1 100644 --- a/src/app/mypage/page.tsx +++ b/src/app/mypage/page.tsx @@ -1,14 +1,48 @@ +"use client"; +import Header from "@/component/layout/Header"; +import { useUser } from "@/context/UserContext"; +import Link from "next/link"; + // 과제 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 활용) */} +
+ + 홈으로 가기 + +
); } diff --git a/src/component/search/SearchInput.tsx b/src/component/search/SearchInput.tsx index aea7294..f84e752 100644 --- a/src/component/search/SearchInput.tsx +++ b/src/component/search/SearchInput.tsx @@ -1,8 +1,10 @@ "use client"; import { useSearch } from "@/context/SearchContext"; +import { useEffect, useRef } from "react"; export default function SearchInput() { const { query, setQuery, setResult } = useSearch(); + const inputRef = useRef(null); // 검색 기능 const search = async () => { @@ -19,13 +21,18 @@ export default function SearchInput() { }; // 2.2. SearchInput 컴포넌트가 최초 렌더링 될 때, input tag에 포커스 되는 기능 - const handleInputChange = () => {}; + useEffect(() => { + inputRef.current?.focus(); + }, []); - // 과제 1-2-3: 페이지 최초 렌더링 시, input에 포커스 되는 기능 (useRef) + const handleInputChange = (e: React.ChangeEvent) => { + setQuery(e.target.value); + }; return (
void; // 삭제 핸들러 추가 + onRemove: (productId: string) => void; } export default function CartList({ cart, products, onRemove }: Props) { + const [showCart, setShowCart] = useState(true); + const router = useRouter(); + + // 2.1. 장바구니에 아이템이 없을 때, 장바구니 영역이 보이지 않는 기능 + useEffect(() => { + setShowCart(Object.keys(cart).length > 0); + }, [cart]); + const cartItems = Object.entries(cart) .map(([id, quantity]) => { const product = products.find((p) => p.productId === id); @@ -21,7 +31,19 @@ export default function CartList({ cart, products, onRemove }: Props) { ); // 2.4 결제하기: "결제하기" 버튼을 클릭하면, 현재 장바구니에 담긴 상품을 확인해 **localStorage**에 저장 후, 결제완료(/checkout) 페이지로 이동한다. - const handleCheckout = () => {}; + const handleCheckout = () => { + const checkoutItems = cartItems.map(item => ({ + productId: item.productId, + title: item.title, + lprice: item.lprice, + quantity: item.quantity + })); + + localStorage.setItem('checkoutItems', JSON.stringify(checkoutItems)); + router.push('/checkout'); + }; + + if (!showCart) return null; return (
diff --git a/src/component/shopping/ProductCart.tsx b/src/component/shopping/ProductCart.tsx index a66c2b3..23f0856 100644 --- a/src/component/shopping/ProductCart.tsx +++ b/src/component/shopping/ProductCart.tsx @@ -20,7 +20,14 @@ export default function ProductCart({ items }: { items: ProductItem[] }) { }; /* 과제 2-3: Cart 아이템 지우기 */ - const handleRemoveFromCart = () => {}; + const handleRemoveFromCart = (productId: string) => { + setCart((prev) => { + const newCart = { ...prev }; + delete newCart[productId]; + localStorage.removeItem(productId); + return newCart; + }); + }; return (
diff --git a/src/context/UserContext.tsx b/src/context/UserContext.tsx index e5d3f14..f80e26a 100644 --- a/src/context/UserContext.tsx +++ b/src/context/UserContext.tsx @@ -6,8 +6,9 @@ import { createContext, ReactNode, useContext, useState } from "react"; // User interface User { name: string; - // age: number - // 추가하고 싶은 속성들 ... + userId: string; + age: number; + phoneNumber: string; } // UserContextType interface UserContextType { @@ -22,7 +23,12 @@ export const UserContext = createContext( // 2. Provider 생성 export const UserProvider = ({ children }: { children: ReactNode }) => { - const [user, setUser] = useState({ name: "" }); + const [user, setUser] = useState({ + name: "홍길동", + userId: "hong123", + age: 25, + phoneNumber: "010-1234-5678" + }); return ( {children}