Skip to content

Commit 74510f4

Browse files
Merge pull request #7 from ecommerce-systems/prod/temp
1. UI/UX 고도화
2 parents 5d49bf4 + 1069fc7 commit 74510f4

6 files changed

Lines changed: 322 additions & 76 deletions

File tree

index.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<!doctype html>
2-
<html lang="en">
2+
<html lang="ko">
33
<head>
44
<meta charset="UTF-8" />
5-
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
5+
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%232563eb'><path d='M7 18c-1.1 0-1.99.9-1.99 2S5.9 22 7 22s2-.9 2-2-.9-2-2-2zM1 2v2h2l3.6 7.59-1.35 2.45c-.16.28-.25.61-.25.96 0 1.1.9 2 2 2h12v-2H7.42c-.14 0-.25-.11-.25-.25l.03-.12.9-1.63h7.45c.75 0 1.41-.41 1.75-1.03l3.58-6.49c.08-.14.12-.31.12-.48 0-.55-.45-1-1-1H5.21l-.94-2H1zm16 16c-1.1 0-1.99.9-1.99 2s.89 2 1.99 2 2-.9 2-2-.9-2-2-2z'/></svg>" />
66
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
7-
<title>my-react-app</title>
7+
<title>이커머스 시스템</title>
88
</head>
99
<body>
1010
<div id="app"></div>

src/App.jsx

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,46 +2,51 @@ import React from 'react';
22
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
33
import AuthPage from './pages/AuthPage';
44
import ProductPage from './pages/ProductPage';
5+
import ProductDetailPage from './pages/ProductDetailPage';
56
import OrderPage from './pages/OrderPage';
67
import UserPage from './pages/UserPage';
78
import CoPurchasePage from './pages/CoPurchasePage';
89
import ResponseTimeToast from './components/ResponseTimeToast';
10+
import { CartProvider } from './context/CartContext';
911

1012
function App() {
1113
return (
12-
<Router>
13-
<div id="app">
14-
<nav>
15-
<ul>
16-
<li>
17-
<Link to="/auth">Authentication</Link>
18-
</li>
19-
<li>
20-
<Link to="/products">Products</Link>
21-
</li>
22-
<li>
23-
<Link to="/orders">Orders</Link>
24-
</li>
25-
<li>
26-
<Link to="/user">User Profile</Link>
27-
</li>
28-
<li>
29-
<Link to="/co-purchase">Co-purchase</Link>
30-
</li>
31-
</ul>
32-
</nav>
14+
<CartProvider>
15+
<Router>
16+
<div id="app">
17+
<nav>
18+
<ul>
19+
<li>
20+
<Link to="/auth">Authentication</Link>
21+
</li>
22+
<li>
23+
<Link to="/products">Products</Link>
24+
</li>
25+
<li>
26+
<Link to="/orders">Orders</Link>
27+
</li>
28+
<li>
29+
<Link to="/user">User Profile</Link>
30+
</li>
31+
<li>
32+
<Link to="/co-purchase">Co-purchase</Link>
33+
</li>
34+
</ul>
35+
</nav>
3336

34-
<Routes>
35-
<Route path="/auth" element={<AuthPage />} />
36-
<Route path="/products" element={<ProductPage />} />
37-
<Route path="/orders" element={<OrderPage />} />
38-
<Route path="/user" element={<UserPage />} />
39-
<Route path="/co-purchase" element={<CoPurchasePage />} />
40-
</Routes>
37+
<Routes>
38+
<Route path="/auth" element={<AuthPage />} />
39+
<Route path="/products" element={<ProductPage />} />
40+
<Route path="/products/:productId" element={<ProductDetailPage />} />
41+
<Route path="/orders" element={<OrderPage />} />
42+
<Route path="/user" element={<UserPage />} />
43+
<Route path="/co-purchase" element={<CoPurchasePage />} />
44+
</Routes>
4145

42-
<ResponseTimeToast />
43-
</div>
44-
</Router>
46+
<ResponseTimeToast />
47+
</div>
48+
</Router>
49+
</CartProvider>
4550
);
4651
}
4752

src/components/orders/OrderCreate.jsx

Lines changed: 97 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
1-
import React, { useState } from 'react';
1+
import React, { useState, useEffect } from 'react';
22
import axiosInstance from '../../api';
3+
import { useCart } from '../../context/CartContext';
34

45
function OrderCreate() {
6+
const { cartItems, clearCart } = useCart();
57
const [items, setItems] = useState([{ productId: '', quantity: '' }]);
68
const [result, setResult] = useState('');
79
const [loading, setLoading] = useState(false);
810

11+
// Sync with cart items if available
12+
useEffect(() => {
13+
if (cartItems.length > 0) {
14+
setItems(cartItems.map(item => ({
15+
productId: item.productId.toString(),
16+
quantity: item.quantity
17+
})));
18+
}
19+
}, [cartItems]);
20+
921
const handleAddItem = () => {
1022
setItems([...items, { productId: '', quantity: '' }]);
1123
};
@@ -17,6 +29,10 @@ function OrderCreate() {
1729
setItems(newItems);
1830
};
1931

32+
const handleRemoveItem = (index) => {
33+
setItems(items.filter((_, i) => i !== index));
34+
};
35+
2036
const handleSubmit = async (e) => {
2137
e.preventDefault();
2238
setResult('');
@@ -34,8 +50,9 @@ function OrderCreate() {
3450
}
3551

3652
const response = await axiosInstance.post('/api/v1/orders', { items: orderItems });
37-
setResult(`<p>✅ Order created successfully!</p><pre>${JSON.stringify(response.data, null, 2)}</pre>`);
38-
setItems([{ productId: '', quantity: '' }]); // Reset form
53+
setResult(`<p>✅ Order created successfully!</p><pre style="background: #f8fafc; padding: 1rem; border-radius: 8px; font-size: 0.8rem;">${JSON.stringify(response.data, null, 2)}</pre>`);
54+
setItems([{ productId: '', quantity: '' }]);
55+
clearCart(); // Clear cart on success
3956
} catch (error) {
4057
setResult(`<p style="color: red;">❌ Order creation failed: ${error.response?.data?.message || error.message}</p>`);
4158
console.error(error);
@@ -46,33 +63,88 @@ function OrderCreate() {
4663

4764
return (
4865
<div>
49-
<h3>Create Order</h3>
66+
<h3 style={{ marginBottom: '1.5rem' }}>Create New Order</h3>
67+
68+
{cartItems.length > 0 && (
69+
<div style={{
70+
background: '#eff6ff',
71+
padding: '1rem',
72+
borderRadius: '8px',
73+
marginBottom: '1.5rem',
74+
border: '1px solid #bfdbfe',
75+
fontSize: '0.9rem'
76+
}}>
77+
🛒 <strong>Cart Sync:</strong> {cartItems.length} items from your cart are ready to be ordered.
78+
</div>
79+
)}
80+
5081
<form onSubmit={handleSubmit}>
5182
{items.map((item, index) => (
52-
<div key={index} style={{ marginBottom: '10px' }}>
53-
<input
54-
type="text"
55-
placeholder="Product ID"
56-
value={item.productId}
57-
onChange={(e) => handleItemChange(index, 'productId', e.target.value)}
58-
style={{ width: '100px', marginRight: '5px' }}
59-
/>
60-
<input
61-
type="number"
62-
placeholder="Quantity"
63-
value={item.quantity}
64-
onChange={(e) => handleItemChange(index, 'quantity', e.target.value)}
65-
min="1"
66-
style={{ width: '80px' }}
67-
/>
83+
<div key={index} style={{
84+
display: 'flex',
85+
gap: '0.5rem',
86+
marginBottom: '0.75rem',
87+
alignItems: 'center',
88+
background: '#f8fafc',
89+
padding: '0.5rem',
90+
borderRadius: '8px'
91+
}}>
92+
<div style={{ flex: 2 }}>
93+
<label style={{ fontSize: '0.75rem', color: '#64748b', display: 'block' }}>Product ID</label>
94+
<input
95+
type="text"
96+
placeholder="ID"
97+
value={item.productId}
98+
onChange={(e) => handleItemChange(index, 'productId', e.target.value)}
99+
style={{ marginBottom: 0 }}
100+
/>
101+
</div>
102+
<div style={{ flex: 1 }}>
103+
<label style={{ fontSize: '0.75rem', color: '#64748b', display: 'block' }}>Qty</label>
104+
<input
105+
type="number"
106+
placeholder="Qty"
107+
value={item.quantity}
108+
onChange={(e) => handleItemChange(index, 'quantity', e.target.value)}
109+
min="1"
110+
style={{ marginBottom: 0 }}
111+
/>
112+
</div>
113+
<button
114+
type="button"
115+
onClick={() => handleRemoveItem(index)}
116+
style={{
117+
marginTop: '1.2rem',
118+
background: '#fee2e2',
119+
color: '#ef4444',
120+
padding: '0.5rem',
121+
minWidth: '40px'
122+
}}
123+
>
124+
×
125+
</button>
68126
</div>
69127
))}
70-
<button type="button" onClick={handleAddItem}>Add Item</button>
71-
<button type="submit" disabled={loading}>
72-
{loading ? 'Creating...' : 'Create Order'}
73-
</button>
128+
129+
<div style={{ display: 'flex', gap: '1rem', marginTop: '1rem' }}>
130+
<button
131+
type="button"
132+
onClick={handleAddItem}
133+
style={{ flex: 1, background: '#f1f5f9', color: '#475569' }}
134+
>
135+
+ Add Product
136+
</button>
137+
<button
138+
type="submit"
139+
disabled={loading}
140+
style={{ flex: 2 }}
141+
>
142+
{loading ? 'Processing...' : 'Place Order Now'}
143+
</button>
144+
</div>
74145
</form>
75-
<div dangerouslySetInnerHTML={{ __html: result }} />
146+
147+
<div style={{ marginTop: '1.5rem' }} dangerouslySetInnerHTML={{ __html: result }} />
76148
</div>
77149
);
78150
}

src/components/products/ProductList.jsx

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import React from 'react';
2+
import { useNavigate } from 'react-router-dom';
3+
import { useCart } from '../../context/CartContext';
24

35
function ProductList({ products }) {
6+
const navigate = useNavigate();
7+
const { addToCart } = useCart();
8+
49
if (!products || products.length === 0) {
510
return (
611
<div style={{ textAlign: 'center', padding: '2rem', color: '#64748b' }}>
@@ -14,26 +19,60 @@ function ProductList({ products }) {
1419
<h3 style={{ marginBottom: '1.5rem' }}>Available Products</h3>
1520
<div className="product-list">
1621
{products.map((product) => (
17-
<div key={product.productId} className="product-card">
18-
<div style={{
19-
height: '150px',
20-
background: '#f1f5f9',
21-
borderRadius: '8px',
22-
display: 'flex',
23-
alignItems: 'center',
24-
justifyContent: 'center',
25-
marginBottom: '1rem',
26-
color: '#94a3b8',
27-
fontSize: '0.875rem'
28-
}}>
29-
Product Image Placeholder
22+
<div key={product.productId} className="product-card" style={{ cursor: 'pointer' }}>
23+
<div
24+
onClick={() => navigate(`/products/${product.productId}`)}
25+
style={{
26+
height: '180px',
27+
background: '#f1f5f9',
28+
borderRadius: '8px',
29+
overflow: 'hidden',
30+
marginBottom: '1rem',
31+
display: 'flex',
32+
alignItems: 'center',
33+
justifyContent: 'center'
34+
}}
35+
>
36+
{product.imageUrl ? (
37+
<img
38+
src={product.imageUrl}
39+
alt={product.prodName}
40+
style={{
41+
width: '100%',
42+
height: '100%',
43+
objectFit: 'cover'
44+
}}
45+
onError={(e) => {
46+
e.target.src = 'https://via.placeholder.com/180x180?text=No+Image';
47+
}}
48+
/>
49+
) : (
50+
<div style={{ color: '#94a3b8', fontSize: '0.875rem' }}>No Image</div>
51+
)}
3052
</div>
31-
<h4 style={{ margin: '0 0 0.5rem 0', fontSize: '1.1rem' }}>{product.prodName}</h4>
32-
<div className="product-price">
33-
{product.price?.toLocaleString()}
53+
<div onClick={() => navigate(`/products/${product.productId}`)}>
54+
<h4 style={{
55+
margin: '0 0 0.5rem 0',
56+
fontSize: '1rem',
57+
overflow: 'hidden',
58+
textOverflow: 'ellipsis',
59+
whiteSpace: 'nowrap'
60+
}} title={product.prodName}>
61+
{product.prodName}
62+
</h4>
63+
<div className="product-price">
64+
{product.price?.toLocaleString()}
65+
</div>
3466
</div>
3567
<div style={{ marginTop: '1rem' }}>
36-
<button style={{ width: '100%', fontSize: '0.875rem', padding: '0.5rem' }}>
68+
<button
69+
style={{ width: '100%', fontSize: '0.875rem', padding: '0.5rem' }}
70+
onClick={(e) => {
71+
e.stopPropagation();
72+
addToCart(product);
73+
alert('Added to cart!');
74+
}}
75+
>
3776
Add to Cart
3877
</button>
3978
</div>

src/context/CartContext.jsx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import React, { createContext, useContext, useState } from 'react';
2+
3+
const CartContext = createContext();
4+
5+
export const CartProvider = ({ children }) => {
6+
const [cartItems, setCartItems] = useState([]);
7+
8+
const addToCart = (product) => {
9+
setCartItems((prev) => {
10+
const existing = prev.find((item) => item.productId === product.productId);
11+
if (existing) {
12+
return prev.map((item) =>
13+
item.productId === product.productId
14+
? { ...item, quantity: item.quantity + 1 }
15+
: item
16+
);
17+
}
18+
return [...prev, { ...product, quantity: 1 }];
19+
});
20+
};
21+
22+
const removeFromCart = (productId) => {
23+
setCartItems((prev) => prev.filter((item) => item.productId !== productId));
24+
};
25+
26+
const clearCart = () => setCartItems([]);
27+
28+
return (
29+
<CartContext.Provider value={{ cartItems, addToCart, removeFromCart, clearCart }}>
30+
{children}
31+
</CartContext.Provider>
32+
);
33+
};
34+
35+
export const useCart = () => useContext(CartContext);

0 commit comments

Comments
 (0)