feat(realestate): 청약 가점 현황 카드 + 매칭 가점 비교
- 내 프로필 탭: 가점 현황 카드 (무주택/부양가족/통장 프로그레스 바) - 매칭 결과 탭: 상단에 내 가점 뱃지, 각 카드에 가점 표시 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -741,6 +741,7 @@ function AnnouncementsTab() {
|
||||
function MatchesTab() {
|
||||
const [items, setItems] = useState([]);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [myPoints, setMyPoints] = useState(null);
|
||||
const [page, setPage] = useState(1);
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
const [loading, setLoading] = useState(true);
|
||||
@@ -753,6 +754,7 @@ function MatchesTab() {
|
||||
const data = await apiGet(`/api/realestate/matches?page=${page}&size=${size}`);
|
||||
setItems(data.items || []);
|
||||
setTotal(data.total || 0);
|
||||
if (data.my_points) setMyPoints(data.my_points);
|
||||
} catch (e) {
|
||||
console.error('Matches load error:', e);
|
||||
setItems([]);
|
||||
@@ -789,9 +791,20 @@ function MatchesTab() {
|
||||
return (
|
||||
<div style={{ display: 'grid', gap: 16 }}>
|
||||
<div className="sub-tabs-bar">
|
||||
<p style={{ margin: 0, fontSize: 13, color: 'var(--text-dim)' }}>
|
||||
총 {total}건의 매칭 결과
|
||||
</p>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
|
||||
<p style={{ margin: 0, fontSize: 13, color: 'var(--text-dim)' }}>
|
||||
총 {total}건의 매칭 결과
|
||||
</p>
|
||||
{myPoints && (
|
||||
<span className="sub-badge" style={{
|
||||
color: myPoints.total >= 60 ? '#34d399' : myPoints.total >= 40 ? '#f59e0b' : '#f87171',
|
||||
background: myPoints.total >= 60 ? 'rgba(52,211,153,0.1)' : myPoints.total >= 40 ? 'rgba(245,158,11,0.1)' : 'rgba(248,113,113,0.1)',
|
||||
fontWeight: 700, fontSize: 12,
|
||||
}}>
|
||||
내 가점 {myPoints.total}/{myPoints.max_total}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<button
|
||||
className="sub-filter-btn is-active"
|
||||
onClick={handleRefresh}
|
||||
@@ -868,19 +881,31 @@ function MatchesTab() {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div style={{ textAlign: 'center', flexShrink: 0 }}>
|
||||
<div style={{
|
||||
fontFamily: 'var(--font-display)',
|
||||
fontSize: 28,
|
||||
fontWeight: 700,
|
||||
color: (match.match_score ?? 0) >= 70 ? '#34d399' : (match.match_score ?? 0) >= 40 ? '#f59e0b' : '#f87171',
|
||||
lineHeight: 1,
|
||||
}}>
|
||||
{match.match_score ?? '-'}
|
||||
</div>
|
||||
<div style={{ fontSize: 10, color: 'var(--text-muted)', marginTop: 4 }}>
|
||||
매칭 점수
|
||||
<div style={{ textAlign: 'center', flexShrink: 0, display: 'grid', gap: 6 }}>
|
||||
<div>
|
||||
<div style={{
|
||||
fontFamily: 'var(--font-display)',
|
||||
fontSize: 28,
|
||||
fontWeight: 700,
|
||||
color: (match.match_score ?? 0) >= 70 ? '#34d399' : (match.match_score ?? 0) >= 40 ? '#f59e0b' : '#f87171',
|
||||
lineHeight: 1,
|
||||
}}>
|
||||
{match.match_score ?? '-'}
|
||||
</div>
|
||||
<div style={{ fontSize: 10, color: 'var(--text-muted)', marginTop: 4 }}>
|
||||
매칭 점수
|
||||
</div>
|
||||
</div>
|
||||
{myPoints && (
|
||||
<div style={{
|
||||
fontSize: 11, padding: '3px 8px', borderRadius: 4,
|
||||
background: myPoints.total >= 50 ? 'rgba(52,211,153,0.1)' : 'rgba(248,113,113,0.1)',
|
||||
color: myPoints.total >= 50 ? '#34d399' : '#f87171',
|
||||
fontWeight: 600, whiteSpace: 'nowrap',
|
||||
}}>
|
||||
가점 {myPoints.total}점
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
@@ -985,7 +1010,53 @@ function ProfileTab() {
|
||||
|
||||
if (loading) return <div className="sub-empty">불러오는 중...</div>;
|
||||
|
||||
const pts = profile.subscription_points;
|
||||
|
||||
return (
|
||||
<div style={{ display: 'grid', gap: 16 }}>
|
||||
{/* 가점 카드 */}
|
||||
{pts && pts.total > 0 && (
|
||||
<div className="sub-panel">
|
||||
<div className="sub-panel__head">
|
||||
<div>
|
||||
<p className="sub-panel__eyebrow">청약 가점</p>
|
||||
<h3>내 가점 현황</h3>
|
||||
</div>
|
||||
<div style={{
|
||||
fontFamily: 'var(--font-display)', fontSize: 36, fontWeight: 700,
|
||||
color: pts.total >= 60 ? '#34d399' : pts.total >= 40 ? '#f59e0b' : '#f87171',
|
||||
lineHeight: 1,
|
||||
}}>
|
||||
{pts.total}<span style={{ fontSize: 16, color: 'var(--text-muted)', fontWeight: 400 }}> / {pts.max_total}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="sub-panel__body" style={{ display: 'grid', gap: 12 }}>
|
||||
{[
|
||||
{ label: '무주택기간', data: pts.homeless_duration, color: '#00d4ff' },
|
||||
{ label: '부양가족 수', data: pts.dependents, color: '#8b5cf6' },
|
||||
{ label: '청약통장 가입기간', data: pts.subscription_period, color: '#f59e0b' },
|
||||
].map(({ label, data, color }) => (
|
||||
<div key={label} style={{ display: 'grid', gap: 4 }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13 }}>
|
||||
<span style={{ color: 'var(--text-bright)', fontWeight: 500 }}>{label}</span>
|
||||
<span>
|
||||
<span style={{ fontWeight: 700, color }}>{data.score}</span>
|
||||
<span style={{ color: 'var(--text-dim)' }}> / {data.max}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div style={{ height: 6, borderRadius: 3, background: 'var(--surface-raised)', overflow: 'hidden' }}>
|
||||
<div style={{
|
||||
height: '100%', borderRadius: 3, background: color,
|
||||
width: `${(data.score / data.max) * 100}%`, transition: 'width 0.3s',
|
||||
}} />
|
||||
</div>
|
||||
<span style={{ fontSize: 11, color: 'var(--text-muted)' }}>{data.detail}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="sub-panel">
|
||||
<div className="sub-panel__head">
|
||||
<div>
|
||||
@@ -1198,6 +1269,7 @@ function ProfileTab() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user