diff --git "a/dfasdfasdfasdfasdfasdfasdf\357\200\233" "b/dfasdfasdfasdfasdfasdfasdf\357\200\233" new file mode 100644 index 0000000..5623ae7 --- /dev/null +++ "b/dfasdfasdfasdfasdfasdfasdf\357\200\233" @@ -0,0 +1,24 @@ +diff.astextplain.textconv=astextplain +filter.lfs.clean=git-lfs clean -- %f +filter.lfs.smudge=git-lfs smudge -- %f +filter.lfs.process=git-lfs filter-process +filter.lfs.required=true +http.sslbackend=schannel +core.autocrlf=true +core.fscache=true +core.symlinks=false +pull.rebase=false +credential.helper=manager +credential.https://dev.azure.com.usehttppath=true +init.defaultbranch=master +core.repositoryformatversion=0 +core.filemode=false +core.bare=false +core.logallrefupdates=true +core.symlinks=false +core.ignorecase=true +remote.origin.url=https://github.com/donghyodong/cnu-next.git +remote.origin.fetch=+refs/heads/*:refs/remotes/origin/* +branch.main.remote=origin +branch.main.merge=refs/heads/main +branch.main.vscode-merge-base=origin/main diff --git a/src/app/checkout/page.tsx b/src/app/checkout/page.tsx index 0d40153..f04b0f6 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. 홈으로 가기 버튼 구현 */} +
+ + + +
); -} +} \ No newline at end of file diff --git a/src/app/layout.tsx b/src/app/layout.tsx index f7fa87e..fbd6448 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,22 +1,20 @@ 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", subsets: ["latin"], }); - const geistMono = Geist_Mono({ variable: "--font-geist-mono", subsets: ["latin"], }); - export const metadata: Metadata = { title: "Create Next App", description: "Generated by create next app", }; - export default function RootLayout({ children, }: Readonly<{ @@ -27,8 +25,8 @@ export default function RootLayout({ - {children} + {children} ); -} +} \ No newline at end of file diff --git a/src/app/mypage/page.tsx b/src/app/mypage/page.tsx index 93b3ba9..52d25cb 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 활용) */} +
+ + + +
); -} +} \ No newline at end of file diff --git a/src/app/search/page.tsx b/src/app/search/page.tsx index c3b6212..840ff60 100644 --- a/src/app/search/page.tsx +++ b/src/app/search/page.tsx @@ -1,5 +1,4 @@ "use client"; - import Header from "../../component/layout/Header"; import Footer from "../../component/layout/Footer"; import SearchInput from "../../component/search/SearchInput"; @@ -7,15 +6,18 @@ import ProductCart from "../../component/shopping/ProductCart"; import { useUser } from "../../context/UserContext"; import { useEffect } from "react"; import { useSearch } from "../../context/SearchContext"; - export default function SearchHome() { const { user, setUser } = useUser(); const { result } = useSearch(); - // 페이지 최초 렌더링 될 때, setUser로 이름 설정 useEffect(() => { // 학번 + 이름 형태로 작성 (ex. 2025***** 내이름 ) - setUser({ name: "" }); + setUser({ + userId: "202302531 김동효", + name: "kimdonghyo", + age: 24, + phoneNumber: "010-1234-5678", + }); }, []); return ( @@ -27,4 +29,4 @@ export default function SearchHome() { ); -} +} \ No newline at end of file diff --git a/src/component/search/SearchInput.tsx b/src/component/search/SearchInput.tsx index aea7294..dd749c5 100644 --- a/src/component/search/SearchInput.tsx +++ b/src/component/search/SearchInput.tsx @@ -1,8 +1,16 @@ "use client"; import { useSearch } from "@/context/SearchContext"; +import { useRef, useEffect } from "react"; export default function SearchInput() { const { query, setQuery, setResult } = useSearch(); + const inputRef = useRef(null); + + useEffect(() => { + if (inputRef.current) { + inputRef.current.focus(); + } + }, []); // 검색 기능 const search = async () => { @@ -11,7 +19,6 @@ export default function SearchInput() { if (!res.ok) throw new Error(`${res.status} 에러 발생`); const data = await res.json(); - setResult(data.items || []); } catch (error) { alert(error); setResult([]); @@ -19,13 +26,15 @@ export default function SearchInput() { }; // 2.2. SearchInput 컴포넌트가 최초 렌더링 될 때, input tag에 포커스 되는 기능 - const handleInputChange = () => {}; - + const handleInputChange = (e: React.ChangeEvent) => { + setQuery(e.target.value); + }; // 과제 1-2-3: 페이지 최초 렌더링 시, input에 포커스 되는 기능 (useRef) return (
); -} +} \ No newline at end of file diff --git a/src/component/shopping/CartList.tsx b/src/component/shopping/CartList.tsx index adc8745..d3d7151 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,20 +9,24 @@ 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); return product ? { ...product, quantity } : null; }) .filter((item): item is NonNullable => item !== null); - const total = cartItems.reduce( (sum, item) => sum + Number(item.lprice) * item.quantity, 0 ); // 2.4 결제하기: "결제하기" 버튼을 클릭하면, 현재 장바구니에 담긴 상품을 확인해 **localStorage**에 저장 후, 결제완료(/checkout) 페이지로 이동한다. - const handleCheckout = () => {}; + const handleCheckout = () => { + localStorage.setItem("order", JSON.stringify(cartItems)); + + router.push("/checkout"); + }; return (
@@ -57,7 +62,6 @@ export default function CartList({ cart, products, onRemove }: Props) {
총 합계: {total.toLocaleString()}원
-
); -} +} \ No newline at end of file diff --git a/src/component/shopping/ProductCart.tsx b/src/component/shopping/ProductCart.tsx index a66c2b3..ab372ab 100644 --- a/src/component/shopping/ProductCart.tsx +++ b/src/component/shopping/ProductCart.tsx @@ -3,24 +3,40 @@ import { useEffect, useState } from "react"; import ProductList from "./ProductList"; 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 = () => {}; + 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 +44,9 @@ export default function ProductCart({ items }: { items: ProductItem[] }) { {/* 장바구니 */} {/* 2.1. 조건부 카트 보이기: 카트에 담긴 상품이 없으면 카트가 보이지 않고, 카트에 담긴 물건이 있으면 카트가 보인다 */} - + {showCart && ( + + )}
); -} +} \ No newline at end of file diff --git a/src/context/UserContext.tsx b/src/context/UserContext.tsx index e5d3f14..e3fb051 100644 --- a/src/context/UserContext.tsx +++ b/src/context/UserContext.tsx @@ -1,20 +1,20 @@ "use client"; import { createContext, ReactNode, useContext, useState } from "react"; - // 과제 1.1 UserContext 구현 - // User interface User { name: string; // age: number // 추가하고 싶은 속성들 ... + userId: string; + age: number; + phoneNumber: string; } // UserContextType interface UserContextType { user: User; setUser: (user: User) => void; } - // 1. createContext export const UserContext = createContext( undefined @@ -22,14 +22,18 @@ export const UserContext = createContext( // 2. Provider 생성 export const UserProvider = ({ children }: { children: ReactNode }) => { - const [user, setUser] = useState({ name: "" }); + const [user, setUser] = useState({ + name: "김동효", + userId: "202302531 김동효", + age: 23, + phoneNumber: "010-2883-1032", + }); return ( {children} ); }; - // 3. user 정보를 사용하기 위한 custom hook export const useUser = () => { const context = useContext(UserContext); @@ -38,4 +42,4 @@ export const useUser = () => { throw new Error("error"); } return context; -}; +}; \ No newline at end of file