Skip to content

Commit c1b1410

Browse files
jihun36661jiwoo27
andauthored
[Feat] 홈 페이지 구현 (#59)
* feat: homepage 일부 구성 * feat: 홈페이지 디자인 수정 * feat: homepage 일부 구성 * feat: 홈페이지 디자인 수정 * feat: px단위 수정 * chore: globalStyle 삭제 * chore: css 수정 * chore: vars 사용 * feat: 수정사항 반영 및 onclick 이벤트 추가 * feat: popular 컴포넌트 디자인 변경 및 메인버튼 디자인 변경 * chore: style 수정 * chore: 은행 이름 크기 변경 * feat: 전구 이모티콘 추가 --------- Co-authored-by: 1jiwoo27 <[email protected]>
1 parent ac75722 commit c1b1410

File tree

8 files changed

+404
-4
lines changed

8 files changed

+404
-4
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"preview": "vite preview"
1111
},
1212
"dependencies": {
13+
"@fortawesome/fontawesome-svg-core": "^7.1.0",
1314
"@fortawesome/free-solid-svg-icons": "^7.1.0",
1415
"@fortawesome/react-fontawesome": "^3.1.0",
1516
"@vanilla-extract/css": "^1.17.4",

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/pages/home/home-page.css.ts

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,80 @@
11
import { vars } from '../../styles/theme.css';
22
import { style } from '@vanilla-extract/css';
33

4-
export const title = style({
5-
color: vars.color.blue200,
4+
export const main = style({
5+
display: 'block',
6+
minHeight: '100vh',
7+
width: '70rem',
8+
margin: 'auto',
9+
padding: '11rem 0 4rem 0',
10+
});
11+
12+
export const mainButtonWrapper = style({
13+
display: 'flex',
14+
justifyContent: 'center',
15+
alignItems: 'center',
16+
gap: '2rem',
17+
width: '100%',
18+
});
19+
20+
export const mainButton = style({
21+
width: '34rem',
22+
flexShrink: 0,
23+
height: '40rem',
624
fontSize: vars.size.xl,
725
fontWeight: vars.weight.bold,
26+
display: 'flex',
27+
flexDirection: 'column',
28+
gap: '0.5rem',
29+
justifyContent: 'center',
30+
alignItems: 'center',
31+
});
32+
33+
export const popularityContainer = style({
34+
display: 'flex',
35+
flexDirection: 'column',
36+
gap: '1rem',
37+
marginTop: '5rem',
38+
width: '100%',
39+
});
40+
41+
export const popularityTitle = style({
42+
fontSize: vars.size.xl,
43+
fontWeight: vars.weight.medium,
44+
color: vars.color.gray800,
45+
marginBottom: '1rem',
46+
});
47+
48+
export const contentWrapper = style({
49+
display: 'flex',
50+
gap: '1rem',
51+
flexDirection: 'column',
52+
});
53+
54+
export const section = style({
55+
display: 'flex',
56+
flexDirection: 'column',
57+
gap: '1rem',
58+
marginBottom: '5rem',
59+
});
60+
61+
export const sectionTitle = style({
62+
fontSize: vars.size.lg,
63+
fontWeight: vars.weight.medium,
64+
marginBottom: '0.5rem',
65+
color: vars.color.gray800,
66+
});
67+
68+
export const listContainer = style({
69+
display: 'flex',
70+
flexDirection: 'column',
71+
gap: '2rem',
72+
});
73+
74+
export const emptyText = style({
75+
textAlign: 'center',
76+
padding: '2rem',
77+
color: vars.color.gray500,
78+
backgroundColor: vars.color.gray100,
79+
borderRadius: '8px',
880
});

src/pages/home/home-page.tsx

Lines changed: 136 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,145 @@
1-
import * as styles from './home-page.css';
1+
import { useState, useEffect } from 'react';
2+
import { getPopularSavings, getPopularDeposits } from '../../shared/api/popularity';
3+
import { button } from '../../shared/components/button/button.css';
4+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
5+
import { faPiggyBank } from '@fortawesome/free-solid-svg-icons';
6+
import { useNavigate } from 'react-router-dom';
27
import Header from '../../shared/components/header/header';
8+
import DepositPopular from '../../shared/components/deposit-popular/deposit-popular';
9+
import SavingsPopular from '../../shared/components/savings-popular/savings-popular';
10+
import * as styles from './home-page.css';
11+
12+
type ProductOptions = {
13+
optionId: number;
14+
interestType: string;
15+
reserveType: string;
16+
saveTerm: number;
17+
baseRate: number;
18+
maxRate: number;
19+
};
20+
21+
type PopularityProducts = {
22+
productId: number;
23+
bankName: string;
24+
productName: string;
25+
aiSummary: string;
26+
maxRate: number;
27+
options: ProductOptions[];
28+
};
329

430
const HomePage = () => {
31+
const navigate = useNavigate();
32+
const [deposits, setDeposits] = useState<PopularityProducts[]>([]);
33+
const [savings, setSavings] = useState<PopularityProducts[]>([]);
34+
const [Loading, setIsLoading] = useState(true);
35+
36+
useEffect(() => {
37+
setIsLoading(true);
38+
Promise.all([getPopularDeposits(), getPopularSavings()])
39+
.then(([depositRes, savingsRes]) => {
40+
setDeposits(depositRes?.result || []);
41+
setSavings(savingsRes?.result || []);
42+
})
43+
.catch(() => {
44+
setDeposits([]);
45+
setSavings([]);
46+
})
47+
.finally(() => {
48+
setIsLoading(false);
49+
});
50+
}, []);
51+
52+
if (Loading) {
53+
return (
54+
<>
55+
<Header />
56+
<main className={styles.main}>
57+
<div className={styles.mainButtonWrapper}>
58+
<button
59+
className={`${button({ variant: 'pink' })} ${styles.mainButton}`}
60+
onClick={() => {
61+
navigate('/deposit/search');
62+
window.scrollTo({ top: 0, behavior: 'smooth' });
63+
}}
64+
>
65+
예금
66+
</button>
67+
<button
68+
className={`${button({ variant: 'blue' })} ${styles.mainButton}`}
69+
onClick={() => {
70+
navigate('/savings/search');
71+
window.scrollTo({ top: 0, behavior: 'smooth' });
72+
}}
73+
>
74+
적금
75+
</button>
76+
</div>
77+
</main>
78+
</>
79+
);
80+
}
81+
582
return (
683
<>
784
<Header />
8-
<div className={styles.title}>홈 페이지</div>
85+
<main className={styles.main}>
86+
<div className={styles.mainButtonWrapper}>
87+
<button className={`${button({ variant: 'pink' })} ${styles.mainButton}`}>
88+
<FontAwesomeIcon icon={faPiggyBank} />
89+
예금
90+
</button>
91+
<button className={`${button({ variant: 'blue' })} ${styles.mainButton}`}>
92+
<FontAwesomeIcon icon={faPiggyBank} />
93+
적금
94+
</button>
95+
</div>
96+
<div className={styles.popularityContainer}>
97+
<div className={styles.popularityTitle}>이런 상품은 어떠신가요?</div>
98+
<div className={styles.contentWrapper}>
99+
{/* === 1. 예금 섹션 === */}
100+
<section className={styles.section}>
101+
<h2 className={styles.sectionTitle}>예금</h2>
102+
<div className={styles.listContainer}>
103+
{deposits.length > 0 ? (
104+
deposits.map((item) => (
105+
<DepositPopular
106+
key={item.productId}
107+
productId={item.productId}
108+
optionId={item.options[0]?.optionId || 0}
109+
bankName={item.bankName}
110+
productName={item.productName}
111+
aiSummary={item.aiSummary}
112+
/>
113+
))
114+
) : (
115+
<div className={styles.emptyText}>표시할 예금 상품이 없습니다.</div>
116+
)}
117+
</div>
118+
</section>
119+
120+
{/* === 2. 적금 섹션 === */}
121+
<section className={styles.section}>
122+
<h2 className={styles.sectionTitle}>적금</h2>
123+
<div className={styles.listContainer}>
124+
{savings.length > 0 ? (
125+
savings.map((item) => (
126+
<SavingsPopular
127+
key={item.productId}
128+
productId={item.productId}
129+
optionId={item.options[0]?.optionId || 0}
130+
bankName={item.bankName}
131+
productName={item.productName}
132+
aiSummary={item.aiSummary}
133+
/>
134+
))
135+
) : (
136+
<div className={styles.emptyText}>표시할 적금 상품이 없습니다.</div>
137+
)}
138+
</div>
139+
</section>
140+
</div>
141+
</div>
142+
</main>
9143
</>
10144
);
11145
};
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { vars } from '../../../styles/theme.css';
2+
import { style } from '@vanilla-extract/css';
3+
4+
export const depositContainer = style({
5+
display: 'flex',
6+
flexDirection: 'column',
7+
width: '70rem',
8+
height: '17rem',
9+
gap: '1rem',
10+
padding: '2rem 3rem',
11+
border: `1px solid ${vars.color.pink300}`,
12+
borderRadius: '10px',
13+
cursor: 'pointer',
14+
});
15+
16+
export const bankContainer = style({
17+
display: 'flex',
18+
justifyContent: 'flex-start',
19+
alignItems: 'center',
20+
height: '2rem',
21+
});
22+
23+
export const bank = style({
24+
fontSize: vars.size.ms,
25+
fontWeight: vars.weight.medium,
26+
color: vars.color.gray700,
27+
width: '15rem',
28+
});
29+
30+
export const productContainer = style({
31+
display: 'flex',
32+
justifyContent: 'flex-start',
33+
alignItems: 'center',
34+
height: '5rem',
35+
});
36+
37+
export const product = style({
38+
fontSize: vars.size.lg,
39+
fontWeight: vars.weight.bold,
40+
color: vars.color.gray700,
41+
margin: 0,
42+
});
43+
44+
export const detail = style({
45+
height: '10rem',
46+
display: 'flex',
47+
flexDirection: 'column',
48+
justifyContent: 'center',
49+
});
50+
51+
export const value = style({
52+
fontSize: vars.size.sm,
53+
fontWeight: vars.weight.regular,
54+
color: vars.color.gray700,
55+
});
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { useNavigate } from 'react-router-dom';
2+
import * as styles from './deposit-popular.css';
3+
4+
interface DepositPopularProps {
5+
productId: number;
6+
optionId: number;
7+
bankName: string;
8+
productName: string;
9+
aiSummary: string;
10+
}
11+
12+
const DepositPopular = ({
13+
productId,
14+
optionId,
15+
bankName,
16+
productName,
17+
aiSummary,
18+
}: DepositPopularProps) => {
19+
const navigate = useNavigate();
20+
21+
return (
22+
<div
23+
className={styles.depositContainer}
24+
onClick={() => {
25+
navigate(`/deposit/${productId}/${optionId}`);
26+
window.scrollTo({ top: 0, behavior: 'smooth' });
27+
}}
28+
>
29+
<div className={styles.bank}>{bankName}</div>
30+
<div className={styles.product}>{productName}</div>
31+
<div className={styles.detail}>
32+
<div className={styles.value}>💡{aiSummary}</div>
33+
</div>
34+
</div>
35+
);
36+
};
37+
38+
export default DepositPopular;
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { vars } from '../../../styles/theme.css';
2+
import { style } from '@vanilla-extract/css';
3+
4+
export const savingsContainer = style({
5+
display: 'flex',
6+
flexDirection: 'column',
7+
width: '70rem',
8+
height: '17rem',
9+
gap: '1rem',
10+
padding: '2rem 3rem',
11+
border: `1px solid ${vars.color.blue300}`,
12+
borderRadius: '10px',
13+
cursor: 'pointer',
14+
});
15+
16+
export const bankContainer = style({
17+
display: 'flex',
18+
justifyContent: 'flex-start',
19+
alignItems: 'center',
20+
height: '2rem',
21+
});
22+
23+
export const bank = style({
24+
fontSize: vars.size.ms,
25+
fontWeight: vars.weight.medium,
26+
color: vars.color.gray700,
27+
width: '15rem',
28+
});
29+
30+
export const productContainer = style({
31+
display: 'flex',
32+
justifyContent: 'flex-start',
33+
alignItems: 'center',
34+
height: '5rem',
35+
});
36+
37+
export const product = style({
38+
fontSize: vars.size.lg,
39+
fontWeight: vars.weight.bold,
40+
color: vars.color.gray700,
41+
margin: 0,
42+
});
43+
44+
export const detail = style({
45+
height: '10rem',
46+
display: 'flex',
47+
flexDirection: 'column',
48+
justifyContent: 'center',
49+
});
50+
51+
export const value = style({
52+
fontSize: vars.size.sm,
53+
fontWeight: vars.weight.regular,
54+
color: vars.color.gray700,
55+
});

0 commit comments

Comments
 (0)