Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
55 changes: 53 additions & 2 deletions src/app/checkout/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// CheckoutPage
import { useState } from "react";
import { useState, useEffect } from "react";
import Link from 'next/link';
import { ProductItem } from "@/types/Product";

interface CheckoutItem {
Expand All @@ -9,13 +10,63 @@ interface CheckoutItem {
// 과제 3
export default function CheckoutPage() {
const [items, setItems] = useState<CheckoutItem[]>([]);
const [totalPrice, setTotalPrice] = useState<number>(0);
// 3.1. 결제하기 구현

useEffect(() => {
const storedItemsJSON = localStorage.getItem('checkoutItems');

if (storedItemsJSON) {
const parsedItems: CheckoutItem[] = JSON.parse(storedItemsJSON);
setItems(parsedItems);

const total = parsedItems.reduce((sum, item) => {
return sum + (Number(item.product.lprice) * item.quantity);
}, 0);
setTotalPrice(total);

localStorage.removeItem('checkoutItems');
}
}, []);

return (
<div className="p-6 max-w-3xl mx-auto bg-white rounded shadow mt-6">
<h1 className="text-2xl font-bold mb-4">✅ 결제가 완료되었습니다!</h1>
{/* 3.1. 결제하기 구현 */}
<div></div>
{items.length === 0 ? (
<p className="text-center text-gray-500 py-4">결제된 아이템이 없습니다.</p>
) : (
<div>
<h2 className="text-xl font-semibold mb-4 border-b pb-2">결제 내역</h2>
<ul className="space-y-4 mb-6">
{items.map((item) => (
<li key={item.product.productId} className="flex justify-between items-center p-2 bg-gray-50 rounded-md">
<div>
<p className="font-semibold" dangerouslySetInnerHTML={{ __html: item.product.title }}></p>
<p className="text-sm text-gray-600">
{Number(item.product.lprice).toLocaleString()}원 x {item.quantity}개
</p>
</div>
<p className="font-bold text-lg text-blue-600">
{(Number(item.product.lprice) * item.quantity).toLocaleString()}원
</p>
</li>
))}
</ul>
<div className="text-right text-2xl font-bold py-4 border-t">
<span>총 결제 금액: </span>
<span className="text-red-500">{totalPrice.toLocaleString()}원</span>
</div>
</div>
)}
{/* 3.2. 홈으로 가기 버튼 구현 */}
<div className="mt-8 text-center">
<Link href="/">
<button className="px-8 py-3 bg-gray-800 text-white font-bold rounded-lg hover:bg-gray-700 transition-colors">
홈 화면으로 돌아가기
</button>
</Link>
</div>
</div>
);
}
51 changes: 43 additions & 8 deletions src/app/mypage/page.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,49 @@
import React, { useContext } from 'react';
import { Link } from 'react-router-dom';
import { UserContext } from '../contexts/UserContext';
import Header from '../components/layout/Header.tsx';

// 과제 1: 마이페이지 구현
export default function MyPage() {
// 1.1. UserContext를 활용한 Mypage 구현 (UserContext에 아이디(userId: string), 나이(age: number), 핸드폰번호(phoneNumber: string) 추가)
// 1.1. UserContext를 활용한 Mypage 구현 (UserContext에 아이디(userId: string), 나이(age: number), 핸드폰번호(phoneNumber: string) 추가)
const { user } = userContext;

return (
<div className="flex flex-col items-center min-h-screen bg-gray-50">
{/* 1.2. Header Component를 재활용하여 Mypage Header 표기 (title: 마이페이지) */}
<Header title="마이페이지" />
{/* Mypage 정보를 UserContext 활용하여 표시 (이름, 아이디, 나이, 핸드폰번호 모두 포함) */}
<main className="p-8 mt-4 bg-white rounded-lg shadow-md w-full max-w-md">
<h2 className="text-2xl font-bold mb-6 text-center text-gray-800">내 정보</h2>

return (
<div className="flex flex-col items-center min-h-screen bg-gray-50">
{/* 1.2. Header Component를 재활용하여 Mypage Header 표기 (title: 마이페이지) */}
<p>마이페이지</p>
{/* Mypage 정보를 UserContext 활용하여 표시 (이름, 아이디, 나이, 핸드폰번호 모두 포함) */}
<div className="space-y-4">
<p className="text-lg">
<span className="font-semibold text-gray-600">이름: </span>
{user.name}
</p>
<p className="text-lg">
<span className="font-semibold text-gray-600">아이디: </span>
{user.userId}
</p>
<p className="text-lg">
<span className="font-semibold text-gray-600">나이: </span>
{user.age}세
</p>
<p className="text-lg">
<span className="font-semibold text-gray-600">핸드폰번호: </span>
{user.phoneNumber}
</p>
</div>

{/* 1.3. 홈으로 가기 버튼 구현(Link or Router 활용) */}
</div>
{/* 1.3. 홈으로 가기 버튼 구현(Link or Router 활용) */}
<div className="mt-8 text-center">
<Link to="/">
<button className="px-6 py-2 bg-gray-800 text-white font-bold rounded-lg hover:bg-gray-700 transition-colors">
홈으로 가기
</button>
</Link>
</div>
</main>
</div>
);
}
13 changes: 12 additions & 1 deletion src/component/search/SearchInput.tsx
Original file line number Diff line number Diff line change
@@ -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<HTMLInputElement>(null);

useEffect(() => {
if (inputRef.current) {
inputRef.current.focus();
}
}, []);

// 검색 기능
const search = async () => {
Expand All @@ -19,13 +27,16 @@ export default function SearchInput() {
};

// 2.2. SearchInput 컴포넌트가 최초 렌더링 될 때, input tag에 포커스 되는 기능
const handleInputChange = () => {};
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setQuery(e.target.value);
};

// 과제 1-2-3: 페이지 최초 렌더링 시, input에 포커스 되는 기능 (useRef)

return (
<div className="flex justify-center items-center gap-2 mt-4">
<input
ref={inputRef}
type="text"
value={query}
onChange={handleInputChange}
Expand Down
22 changes: 21 additions & 1 deletion src/component/shopping/CartList.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"use client";
import { ProductItem } from "@/types/Product";
import { useRouter } from 'next/navigation';

interface Props {
cart: { [productId: string]: number };
Expand All @@ -8,6 +9,8 @@ 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);
Expand All @@ -21,7 +24,23 @@ export default function CartList({ cart, products, onRemove }: Props) {
);

// 2.4 결제하기: "결제하기" 버튼을 클릭하면, 현재 장바구니에 담긴 상품을 확인해 **localStorage**에 저장 후, 결제완료(/checkout) 페이지로 이동한다.
const handleCheckout = () => {};
const handleCheckout = () => {
if (cartItems.length === 0) {
alert("장바구니에 상품이 없습니다.");
return;
}

const itemsToCheckout = cartItems.map(item => {
const { quantity, ...productDetails } = item;
return {
product: productDetails,
quantity: quantity
};
});

localStorage.setItem('checkoutItems', JSON.stringify(itemsToChechout));
router.push('/checkout');
};

return (
<div className="p-4 bg-white rounded shadow mt-6">
Expand Down Expand Up @@ -62,6 +81,7 @@ export default function CartList({ cart, products, onRemove }: Props) {
<button
onClick={handleCheckout}
className="mt-4 w-full bg-green-500 text-white py-2 rounded hover:bg-green-600 flex justify-center"
disabled={cartItems.length === 0}
>
결제하기
</button>
Expand Down
18 changes: 15 additions & 3 deletions src/component/shopping/ProductCart.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// ProductCartPage.tsx
"use client";
import { useEffect, useState } from "react";
import ProductList from "./ProductList";
import { ProductItem } from "@/types/Product";
Expand All @@ -8,19 +9,30 @@ 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);
//localStorage.setItem(item.productId, quantity + "");
//localStorage.getItem(item.productId);
};

/* 과제 2-3: Cart 아이템 지우기 */
const handleRemoveFromCart = () => {};
const handleRemoveFromCart = (productIdToRemove: string) => {
setCart((prevCart) => {
const cartEntries = Object.entries(prevCart);
const filteredEntries = cartEntries.filter(([key, value]) => key !== productIdToRemove);
const newCart = Object.fromEntries(filteredEntries);
return newCart;
};

return (
<div className="p-10">
Expand Down
3 changes: 3 additions & 0 deletions src/context/UserContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ interface User {
name: string;
// age: number
// 추가하고 싶은 속성들 ...
userId: string;
age: number;
phoneNumber: string;
}
// UserContextType
interface UserContextType {
Expand Down