Skip to content

Commit 493847c

Browse files
Merge pull request #10 from ecommerce-systems/prod/temp
1. UI/UX 고도화
2 parents 0e546b9 + d2ff52d commit 493847c

9 files changed

Lines changed: 136 additions & 83 deletions

File tree

src/components/auth/Login.jsx

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,27 @@ function Login() {
1313
const res = await axiosInstance.post('/api/v2/auth/login', { username, password });
1414
const { accessToken } = res.data;
1515
setAccessToken(accessToken);
16-
setResult(`<p>✅ Login successful for ${username}</p>`);
16+
setResult(`<p style="color: var(--success-color); font-weight: bold;">✅ ${username}님, 환영합니다! 로그인에 성공했습니다.</p>`);
1717
} catch (error) {
18-
setResult(`<p>❌ Login failed: ${error.response?.data?.message || error.message}</p>`);
18+
setResult(`<p style="color: var(--error-color);">❌ 로그인 실패: 아이디 또는 비밀번호를 확인해주세요.</p>`);
1919
}
2020
};
2121

2222
return (
2323
<div>
24-
<h2>Log In</h2>
24+
<h2 style={{ marginBottom: '1.5rem' }}>로그인</h2>
2525
<form onSubmit={handleSubmit}>
26-
<input type="text" value={username} onChange={(e) => setUsername(e.target.value)} placeholder="Username" required />
27-
<input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Password" required />
28-
<button type="submit">Log In</button>
26+
<div style={{ marginBottom: '1rem' }}>
27+
<label style={{ fontSize: '0.85rem', color: 'var(--text-muted)', display: 'block', marginBottom: '0.4rem' }}>아이디</label>
28+
<input type="text" value={username} onChange={(e) => setUsername(e.target.value)} placeholder="아이디를 입력하세요" required style={{ marginBottom: 0 }} />
29+
</div>
30+
<div style={{ marginBottom: '1rem' }}>
31+
<label style={{ fontSize: '0.85rem', color: 'var(--text-muted)', display: 'block', marginBottom: '0.4rem' }}>비밀번호</label>
32+
<input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="비밀번호를 입력하세요" required style={{ marginBottom: 0 }} />
33+
</div>
34+
<button type="submit" style={{ width: '100%', marginTop: '0.5rem' }}>로그인하기</button>
2935
</form>
30-
<div dangerouslySetInnerHTML={{ __html: result }} />
36+
<div style={{ marginTop: '1rem', fontSize: '0.9rem' }} dangerouslySetInnerHTML={{ __html: result }} />
3137
</div>
3238
);
3339
}

src/components/auth/Logout.jsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,20 @@ function Logout() {
99
try {
1010
await axiosInstance.post('/api/v2/auth/logout');
1111
setAccessToken(null);
12-
setResult('<p>👋 Logout successful</p>');
12+
setResult('<p style="color: var(--text-muted); font-weight: bold;">👋 로그아웃되었습니다. 다시 방문해주세요!</p>');
1313
} catch (error) {
14-
setResult(`<p>❌ Logout failed: ${error.response?.data?.message || error.message}</p>`);
14+
setResult(`<p style="color: var(--error-color);">❌ 로그아웃 실패: 이미 로그아웃 상태이거나 서버 오류입니다.</p>`);
1515
}
1616
};
1717

1818
return (
1919
<div>
20-
<h2>Log Out</h2>
21-
<button onClick={handleLogout}>Log Out</button>
22-
<div dangerouslySetInnerHTML={{ __html: result }} />
20+
<h2 style={{ marginBottom: '1.5rem' }}>로그아웃</h2>
21+
<p style={{ fontSize: '0.9rem', color: 'var(--text-muted)', marginBottom: '1.5rem' }}>
22+
안전한 서비스 이용을 위해 사용을 마치신 후에는 로그아웃을 해주세요.
23+
</p>
24+
<button onClick={handleLogout} style={{ width: '100%', background: '#f1f5f9', color: '#475569' }}>로그아웃 하기</button>
25+
<div style={{ marginTop: '1rem', fontSize: '0.9rem' }} dangerouslySetInnerHTML={{ __html: result }} />
2326
</div>
2427
);
2528
}

src/components/auth/RefreshToken.jsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,20 @@ function RefreshToken() {
1010
const res = await axiosInstance.post('/api/v2/auth/refresh');
1111
const newAccessToken = res.data.accessToken;
1212
setAccessToken(newAccessToken);
13-
setResult('<p>🔄 Access token refreshed!</p>');
13+
setResult('<p style="color: var(--success-color); font-weight: bold;">🔄 로그인 연장에 성공했습니다!</p>');
1414
} catch (error) {
15-
setResult(`<p>❌ Failed to refresh token: ${error.response?.data?.message || error.message}</p>`);
15+
setResult(`<p style="color: var(--error-color);">❌ 연장 실패: 다시 로그인해야 합니다.</p>`);
1616
}
1717
};
1818

1919
return (
2020
<div>
21-
<h2>Refresh Token</h2>
22-
<button onClick={handleRefresh}>Refresh Token</button>
23-
<div dangerouslySetInnerHTML={{ __html: result }} />
21+
<h2 style={{ marginBottom: '1.5rem' }}>로그인 연장</h2>
22+
<p style={{ fontSize: '0.9rem', color: 'var(--text-muted)', marginBottom: '1.5rem' }}>
23+
보안을 위해 주기적으로 로그인 세션을 연장할 수 있습니다.
24+
</p>
25+
<button onClick={handleRefresh} style={{ width: '100%', background: 'var(--primary-color)' }}>로그인 세션 연장</button>
26+
<div style={{ marginTop: '1rem', fontSize: '0.9rem' }} dangerouslySetInnerHTML={{ __html: result }} />
2427
</div>
2528
);
2629
}

src/components/auth/SignUp.jsx

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,39 @@ function SignUp() {
1414
setResult('');
1515
try {
1616
const res = await axiosInstance.post('/api/v2/auth/signup', { username, password, name, phone, address });
17-
setResult(`<p>✅ Signup successful for ${username}</p><pre>${JSON.stringify(res.data, null, 2)}</pre>`);
17+
setResult(`<p style="color: var(--success-color); font-weight: bold;">✅ 회원가입 완료! ${username}님 가입을 축하드립니다.</p>`);
1818
} catch (error) {
19-
setResult(`<p>❌ Signup failed: ${error.response?.data?.message || error.message}</p>`);
19+
setResult(`<p style="color: var(--error-color);">❌ 회원가입 실패: 이미 존재하는 아이디이거나 입력 정보를 확인해주세요.</p>`);
2020
}
2121
};
2222

2323
return (
2424
<div>
25-
<h2>Sign Up</h2>
25+
<h2 style={{ marginBottom: '1.5rem' }}>회원가입</h2>
2626
<form onSubmit={handleSubmit}>
27-
<input type="text" value={username} onChange={(e) => setUsername(e.target.value)} placeholder="Username" required />
28-
<input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Password" required />
29-
<input type="text" value={name} onChange={(e) => setName(e.target.value)} placeholder="Name" required />
30-
<input type="text" value={phone} onChange={(e) => setPhone(e.target.value)} placeholder="Phone" required />
31-
<input type="text" value={address} onChange={(e) => setAddress(e.target.value)} placeholder="Address" required />
32-
<button type="submit">Sign Up</button>
27+
<div style={{ marginBottom: '0.8rem' }}>
28+
<label style={{ fontSize: '0.8rem', color: 'var(--text-muted)', display: 'block' }}>아이디</label>
29+
<input type="text" value={username} onChange={(e) => setUsername(e.target.value)} placeholder="아이디" required style={{ marginBottom: 0 }} />
30+
</div>
31+
<div style={{ marginBottom: '0.8rem' }}>
32+
<label style={{ fontSize: '0.8rem', color: 'var(--text-muted)', display: 'block' }}>비밀번호</label>
33+
<input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="비밀번호" required style={{ marginBottom: 0 }} />
34+
</div>
35+
<div style={{ marginBottom: '0.8rem' }}>
36+
<label style={{ fontSize: '0.8rem', color: 'var(--text-muted)', display: 'block' }}>이름</label>
37+
<input type="text" value={name} onChange={(e) => setName(e.target.value)} placeholder="성함" required style={{ marginBottom: 0 }} />
38+
</div>
39+
<div style={{ marginBottom: '0.8rem' }}>
40+
<label style={{ fontSize: '0.8rem', color: 'var(--text-muted)', display: 'block' }}>전화번호</label>
41+
<input type="text" value={phone} onChange={(e) => setPhone(e.target.value)} placeholder="010-0000-0000" required style={{ marginBottom: 0 }} />
42+
</div>
43+
<div style={{ marginBottom: '1rem' }}>
44+
<label style={{ fontSize: '0.8rem', color: 'var(--text-muted)', display: 'block' }}>주소</label>
45+
<input type="text" value={address} onChange={(e) => setAddress(e.target.value)} placeholder="상세 주소" required style={{ marginBottom: 0 }} />
46+
</div>
47+
<button type="submit" style={{ width: '100%' }}>회원가입하기</button>
3348
</form>
34-
<div dangerouslySetInnerHTML={{ __html: result }} />
49+
<div style={{ marginTop: '1rem', fontSize: '0.9rem' }} dangerouslySetInnerHTML={{ __html: result }} />
3550
</div>
3651
);
3752
}

src/components/user/UserProfile.jsx

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ function UserProfile() {
1212
const response = await axiosInstance.get('/api/v1/users/me');
1313
setUser(response.data);
1414
} catch (err) {
15-
setError('Failed to fetch user profile.');
15+
setError('사용자 프로필을 가져오는데 실패했습니다. 로그인이 필요합니다.');
1616
console.error(err);
1717
} finally {
1818
setLoading(false);
@@ -22,21 +22,33 @@ function UserProfile() {
2222
fetchUserProfile();
2323
}, []);
2424

25-
if (loading) return <p>Loading user profile...</p>;
26-
if (error) return <p style={{ color: 'red' }}>{error}</p>;
25+
if (loading) return <p style={{ color: 'var(--text-muted)' }}>프로필 불러오는 중...</p>;
26+
if (error) return <p style={{ color: 'var(--error-color)', padding: '1rem', background: '#fef2f2', borderRadius: '8px' }}>{error}</p>;
2727

2828
return (
2929
<div>
30-
<h3>My Profile</h3>
30+
<h3 style={{ marginBottom: '1.5rem' }}>내 프로필 정보</h3>
3131
{user ? (
32-
<div>
33-
<p>Username: {user.username}</p>
34-
<p>Name: {user.name}</p>
35-
<p>Phone: {user.phone}</p>
36-
<p>Address: {user.address}</p>
32+
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.8rem' }}>
33+
<div style={{ display: 'flex', borderBottom: '1px solid #f1f5f9', paddingBottom: '0.5rem' }}>
34+
<span style={{ width: '100px', fontWeight: 600, color: 'var(--text-muted)' }}>아이디</span>
35+
<span>{user.username}</span>
36+
</div>
37+
<div style={{ display: 'flex', borderBottom: '1px solid #f1f5f9', paddingBottom: '0.5rem' }}>
38+
<span style={{ width: '100px', fontWeight: 600, color: 'var(--text-muted)' }}>이름</span>
39+
<span>{user.name}</span>
40+
</div>
41+
<div style={{ display: 'flex', borderBottom: '1px solid #f1f5f9', paddingBottom: '0.5rem' }}>
42+
<span style={{ width: '100px', fontWeight: 600, color: 'var(--text-muted)' }}>전화번호</span>
43+
<span>{user.phone}</span>
44+
</div>
45+
<div style={{ display: 'flex', borderBottom: '1px solid #f1f5f9', paddingBottom: '0.5rem' }}>
46+
<span style={{ width: '100px', fontWeight: 600, color: 'var(--text-muted)' }}>주소</span>
47+
<span>{user.address}</span>
48+
</div>
3749
</div>
3850
) : (
39-
<p>No user profile found.</p>
51+
<p>사용자 정보를 찾을 수 없습니다.</p>
4052
)}
4153
</div>
4254
);

src/components/user/UserProfileUpdate.jsx

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,14 @@ function UserProfileUpdate() {
77
const [result, setResult] = useState('');
88
const [loading, setLoading] = useState(false);
99

10-
// Optionally fetch current profile data to pre-fill the form
1110
useEffect(() => {
1211
const fetchCurrentProfile = async () => {
1312
try {
1413
const response = await axiosInstance.get('/api/v1/users/me');
1514
setPhone(response.data.phone || '');
1615
setAddress(response.data.address || '');
1716
} catch (err) {
18-
console.error('Failed to fetch current user profile for update form:', err);
17+
console.error('기존 프로필 정보를 불러오는데 실패했습니다:', err);
1918
}
2019
};
2120
fetchCurrentProfile();
@@ -26,10 +25,10 @@ function UserProfileUpdate() {
2625
setResult('');
2726
setLoading(true);
2827
try {
29-
const response = await axiosInstance.put('/api/v1/users/me', { phone, address });
30-
setResult(`<p>✅ Profile updated successfully!</p><pre>${JSON.stringify(response.data, null, 2)}</pre>`);
28+
await axiosInstance.put('/api/v1/users/me', { phone, address });
29+
setResult(`<p style="color: var(--success-color); font-weight: bold;">✅ 프로필 정보가 성공적으로 수정되었습니다!</p>`);
3130
} catch (error) {
32-
setResult(`<p style="color: red;">❌ Profile update failed: ${error.response?.data?.message || error.message}</p>`);
31+
setResult(`<p style="color: var(--error-color);">❌ 프로필 수정 실패: 입력 정보를 다시 확인해주세요.</p>`);
3332
console.error(error);
3433
} finally {
3534
setLoading(false);
@@ -38,25 +37,33 @@ function UserProfileUpdate() {
3837

3938
return (
4039
<div>
41-
<h3>Update My Profile</h3>
40+
<h3 style={{ marginBottom: '1.5rem' }}>내 프로필 수정</h3>
4241
<form onSubmit={handleSubmit}>
43-
<input
44-
type="text"
45-
value={phone}
46-
onChange={(e) => setPhone(e.target.value)}
47-
placeholder="Phone Number"
48-
/>
49-
<input
50-
type="text"
51-
value={address}
52-
onChange={(e) => setAddress(e.target.value)}
53-
placeholder="Address"
54-
/>
55-
<button type="submit" disabled={loading}>
56-
{loading ? 'Updating...' : 'Update Profile'}
42+
<div style={{ marginBottom: '1rem' }}>
43+
<label style={{ fontSize: '0.85rem', color: 'var(--text-muted)', display: 'block', marginBottom: '0.4rem' }}>전화번호</label>
44+
<input
45+
type="text"
46+
value={phone}
47+
onChange={(e) => setPhone(e.target.value)}
48+
placeholder="010-0000-0000"
49+
style={{ marginBottom: 0 }}
50+
/>
51+
</div>
52+
<div style={{ marginBottom: '1rem' }}>
53+
<label style={{ fontSize: '0.85rem', color: 'var(--text-muted)', display: 'block', marginBottom: '0.4rem' }}>주소</label>
54+
<input
55+
type="text"
56+
value={address}
57+
onChange={(e) => setAddress(e.target.value)}
58+
placeholder="상세 주소를 입력하세요"
59+
style={{ marginBottom: 0 }}
60+
/>
61+
</div>
62+
<button type="submit" disabled={loading} style={{ width: '100%', background: 'var(--primary-color)' }}>
63+
{loading ? '수정 처리 중...' : '프로필 정보 저장'}
5764
</button>
5865
</form>
59-
<div dangerouslySetInnerHTML={{ __html: result }} />
66+
<div style={{ marginTop: '1rem', fontSize: '0.9rem' }} dangerouslySetInnerHTML={{ __html: result }} />
6067
</div>
6168
);
6269
}

src/pages/AuthPage.jsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@ import RefreshToken from '../components/auth/RefreshToken';
77
function AuthPage() {
88
return (
99
<div>
10-
<h1>Auth Operations</h1>
10+
<div style={{ marginBottom: '2rem' }}>
11+
<h1>계정 관리 및 인증</h1>
12+
<p style={{ color: 'var(--text-muted)' }}>회원가입 및 로그인을 통해 다양한 서비스를 이용해보세요.</p>
13+
</div>
1114
<div className="container">
1215
<div className="card">
13-
<SignUp />
16+
<Login />
1417
</div>
1518
<div className="card">
16-
<Login />
19+
<SignUp />
1720
</div>
1821
<div className="card">
1922
<RefreshToken />

src/pages/ProductDetailPage.jsx

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ function ProductDetailPage() {
1818
const response = await axiosInstance.get(`/api/v2/products/${productId}`);
1919
setProduct(response.data);
2020
} catch (err) {
21-
setError('Failed to fetch product details.');
21+
setError('상품 정보를 불러오는 데 실패했습니다.');
2222
console.error(err);
2323
} finally {
2424
setLoading(false);
@@ -27,26 +27,27 @@ function ProductDetailPage() {
2727
fetchProduct();
2828
}, [productId]);
2929

30-
if (loading) return <div style={{ textAlign: 'center', padding: '5rem' }}>Loading product...</div>;
31-
if (error) return <div style={{ color: 'red', textAlign: 'center', padding: '5rem' }}>{error}</div>;
30+
if (loading) return <div style={{ textAlign: 'center', padding: '5rem', color: 'var(--text-muted)' }}>상품 정보를 불러오는 중...</div>;
31+
if (error) return <div style={{ color: 'var(--error-color)', textAlign: 'center', padding: '5rem' }}>{error}</div>;
3232
if (!product) return null;
3333

3434
return (
3535
<div className="container">
3636
<div className="card" style={{ padding: '2rem' }}>
3737
<button
3838
onClick={() => navigate(-1)}
39-
style={{ background: 'transparent', color: 'var(--text-muted)', padding: 0, marginBottom: '1rem' }}
39+
style={{ background: 'transparent', color: 'var(--text-muted)', padding: 0, marginBottom: '1rem', border: 'none', cursor: 'pointer', fontSize: '1rem' }}
4040
>
41-
Back to list
41+
목록으로 돌아가기
4242
</button>
4343

4444
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '2rem' }}>
45-
<div style={{ background: '#f1f5f9', borderRadius: '12px', overflow: 'hidden' }}>
45+
<div style={{ background: '#f1f5f9', borderRadius: '12px', overflow: 'hidden', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
4646
<img
4747
src={product.imageUrl || 'https://via.placeholder.com/400x400?text=No+Image'}
4848
alt={product.prodName}
49-
style={{ width: '100%', height: 'auto', display: 'block' }}
49+
style={{ width: '100%', height: 'auto', display: 'block', objectFit: 'contain' }}
50+
onError={(e) => { e.target.src = 'https://via.placeholder.com/400x400?text=No+Image'; }}
5051
/>
5152
</div>
5253

@@ -59,31 +60,31 @@ function ProductDetailPage() {
5960
fontSize: '0.75rem',
6061
fontWeight: 'bold'
6162
}}>
62-
{product.productTypeName}
63+
{product.productTypeName || '상품'}
6364
</span>
64-
<h1 style={{ margin: '0.5rem 0' }}>{product.prodName}</h1>
65-
<div className="product-price" style={{ fontSize: '2rem', marginBottom: '1.5rem' }}>
65+
<h1 style={{ margin: '0.5rem 0', fontSize: '2rem' }}>{product.prodName}</h1>
66+
<div className="product-price" style={{ fontSize: '2.5rem', marginBottom: '1.5rem', fontWeight: 800 }}>
6667
{product.price?.toLocaleString()}
6768
</div>
6869

6970
<div style={{ borderTop: '1px solid var(--border-color)', paddingTop: '1.5rem', marginBottom: '2rem' }}>
70-
<h3 style={{ fontSize: '1.1rem', marginBottom: '0.5rem' }}>Product Information</h3>
71-
<p style={{ color: 'var(--text-muted)' }}>
72-
Section: {product.sectionName}<br />
73-
Department: {product.departmentName}<br />
74-
Group: {product.indexGroupName}<br />
75-
Colour: {product.colourGroupName}
76-
</p>
71+
<h3 style={{ fontSize: '1.1rem', marginBottom: '1rem', color: 'var(--text-main)' }}>상품 상세 정보</h3>
72+
<div style={{ display: 'flex', flexDirection: 'column', gap: '0.6rem', color: 'var(--text-muted)', fontSize: '0.95rem' }}>
73+
<div style={{ display: 'flex' }}><span style={{ width: '100px', fontWeight: 600 }}>섹션</span><span>{product.sectionName}</span></div>
74+
<div style={{ display: 'flex' }}><span style={{ width: '100px', fontWeight: 600 }}>부서</span><span>{product.departmentName}</span></div>
75+
<div style={{ display: 'flex' }}><span style={{ width: '100px', fontWeight: 600 }}>그룹</span><span>{product.indexGroupName}</span></div>
76+
<div style={{ display: 'flex' }}><span style={{ width: '100px', fontWeight: 600 }}>색상</span><span>{product.colourGroupName}</span></div>
77+
</div>
7778
</div>
7879

7980
<button
80-
style={{ width: '100%', padding: '1rem', fontSize: '1.1rem' }}
81+
style={{ width: '100%', padding: '1.2rem', fontSize: '1.2rem', fontWeight: 'bold' }}
8182
onClick={() => {
8283
addToCart(product);
83-
alert('Added to cart!');
84+
alert('장바구니에 추가되었습니다!');
8485
}}
8586
>
86-
Add to Shopping Cart
87+
장바구니에 담기
8788
</button>
8889
</div>
8990
</div>

0 commit comments

Comments
 (0)