Skip to content
Merged
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
6 changes: 6 additions & 0 deletions src/App.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
@import url('https://fonts.googleapis.com/css2?family=42dot+Sans:wght@300..800&family=Gowun+Batang&display=swap');

body {
font-family: "42dot Sans", sans-serif;
}

#root {
margin: 0 auto;
padding: 2rem;
Expand Down
4 changes: 3 additions & 1 deletion src/index.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
@import url('https://fonts.googleapis.com/css2?family=42dot+Sans:wght@300..800&family=Gowun+Batang&display=swap');

@tailwind base;
@tailwind components;
@tailwind utilities;

:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
font-family: "42dot Sans", Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;

Expand Down
120 changes: 99 additions & 21 deletions src/pages/Home.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const Home = () => {
const [userInfo, setUserInfo] = useState({});
const [userLoading, setUserLoading] = useState(true);
const [userError, setUserError] = useState(null);
const [prevTier, setPrevTier] = useState(null);

const [loading, setLoading] = useState(true);
const [user, setUser] = useState(null);
Expand All @@ -38,6 +39,15 @@ const Home = () => {
const navigate = useNavigate();
const [client, setClient] = useState(null); // WebSocket 클라이언트 상태

// 티어 아이콘 매핑
const tierEmojis = {
NONE: "❌미획득",
SEED: "🫘씨앗",
SPROUT: "🌱새싹",
FLOWER: "🌺꽃",
FRUIT: "🍎열매",
TREE: "🌳나무",
};

// 사용자 정보 불러오기
useEffect(() => {
Expand All @@ -56,6 +66,33 @@ const Home = () => {
fetchUserInfo();
}, []);

// 업적 기록을 가져오기
const fetchTierInfo = async () => {
try {
const response = await fetch("/api/user/tierinfo");
const data = await response.json();

// "2025년 겨울 시즌" 데이터 필터링
const winterTier = data.find(item => item.year === "2025" && item.season === "winter");

if (winterTier) {
console.log("겨울 시즌 티어:", winterTier.tier);
setPrevTier(winterTier.tier); // 상태로 저장하여 UI에 반영
} else {
console.log("겨울 시즌 데이터 없음");
setPrevTier("미획득");
}
} catch (error) {
console.error("Tier 정보를 가져오는 중 오류 발생:", error);
}
};

// useEffect를 사용하여 API 호출
useEffect(() => {
fetchTierInfo();
}, []);


const toggleModal = async () => {
// 읽은 알림들을 필터링하여 제거
setNotifications(prev => prev.filter(noti => !noti.read));
Expand Down Expand Up @@ -366,8 +403,6 @@ useEffect(() => {
<Profile userInfo={userInfo} />
</div>



<h2 style={{ fontSize: '24px', fontWeight: 'bold', marginBottom: '24px', paddingLeft: '16px' }}>내 커밋 기록</h2>

{/* 커밋 통계 - 테이블과 너비 동일하게 */}
Expand Down Expand Up @@ -420,7 +455,7 @@ useEffect(() => {
<table className="season-table">
<thead>
<tr>
<th className="table-header">시즌</th>
<th className="table-header">현재 시즌 (봄)</th>
<th className="table-header table-header-center">총 커밋</th>
<th className="table-header table-header-center">공개 커밋</th>
<th className="table-header table-header-center">비공개 커밋</th>
Expand All @@ -429,19 +464,56 @@ useEffect(() => {
</tr>
</thead>
<tbody>
{Object.entries(seasonData).map(([season, data], index) => {
if (!data) return null;
{seasonData.spring && (
<tr className="row-spring">
<td className="table-cell">
<div style={{ display: 'flex', alignItems: 'center' }}>
{getSeasonIcon("spring")}
<span style={{ marginLeft: '8px', color: '#333' }}>봄 시즌</span>
</div>
</td>
<td className="table-cell table-cell-center" style={{ fontWeight: 'bold', color: '#333' }}>
{seasonData.spring.totalCommitContributions + seasonData.spring.restrictedContributionsCount}
</td>
<td className="table-cell table-cell-center" style={{ color: '#333' }}>
{seasonData.spring.totalCommitContributions}
</td>
<td className="table-cell table-cell-center" style={{ color: '#333' }}>
{seasonData.spring.restrictedContributionsCount}
</td>
<td className="table-cell table-cell-center">
<span className={`streak-badge ${seasonData.spring.currentStreakDays > 0 ? 'current-streak-badge' : 'zero-value'}`}>
{seasonData.spring.currentStreakDays}일
</span>
</td>
<td className="table-cell table-cell-center">
<span className={`streak-badge ${seasonData.spring.maxStreakDays > 0 ? 'max-streak-badge' : 'zero-value'}`}>
{seasonData.spring.maxStreakDays}일
</span>
</td>
</tr>
)}
</tbody>
</table>

const totalSeasonContributions = data.totalCommitContributions + data.restrictedContributionsCount;
let rowClass = '';
{/* 지난 시즌 테이블 */}
<table className="season-table">
<thead>
<tr>
<th className="table-header">지난 시즌</th>
<th className="table-header table-header-center">총 커밋</th>
<th className="table-header table-header-center">공개 커밋</th>
<th className="table-header table-header-center">비공개 커밋</th>
<th className="table-header table-header-center">획득 티어</th>
<th className="table-header table-header-center">최장 연속</th>
</tr>
</thead>
<tbody>
{["summer", "fall", "winter"].map((season) => {
if (!seasonData[season]) return null;

switch (season) {
case 'spring': rowClass = 'row-spring'; break;
case 'summer': rowClass = 'row-summer'; break;
case 'fall': rowClass = 'row-fall'; break;
case 'winter': rowClass = 'row-winter'; break;
default: rowClass = '';
}
const totalSeasonContributions = seasonData[season].totalCommitContributions + seasonData[season].restrictedContributionsCount;
let rowClass = `row-${season}`;

return (
<tr key={season} className={rowClass}>
Expand All @@ -455,26 +527,32 @@ useEffect(() => {
{totalSeasonContributions}
</td>
<td className="table-cell table-cell-center" style={{ color: '#333' }}>
{data.totalCommitContributions}
{seasonData[season].totalCommitContributions}
</td>
<td className="table-cell table-cell-center" style={{ color: '#333' }}>
{data.restrictedContributionsCount}
{seasonData[season].restrictedContributionsCount}
</td>
<td className="table-cell table-cell-center">
<span className={`streak-badge ${data.currentStreakDays > 0 ? 'current-streak-badge' : 'zero-value'}`}>
{data.currentStreakDays}일
</span>
{season === "winter" ? (
<span className="streak-badge">
{tierEmojis[prevTier] || tierEmojis['NONE']}
</span>
) : (
<span className="streak-badge">
{tierEmojis['NONE']}</span>
)}
</td>
<td className="table-cell table-cell-center">
<span className={`streak-badge ${data.maxStreakDays > 0 ? 'max-streak-badge' : 'zero-value'}`}>
{data.maxStreakDays}일
<span className={`streak-badge ${seasonData[season].maxStreakDays > 0 ? 'max-streak-badge' : 'zero-value'}`}>
{seasonData[season].maxStreakDays}일
</span>
</td>
</tr>
);
})}
</tbody>
</table>

</div>
</div>
</div>
Expand Down
18 changes: 10 additions & 8 deletions src/pages/Profile.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@ const Profile = ({ userInfo }) => {
const [isRefreshing, setIsRefreshing] = useState(false);
const refreshTimerRef = useRef(null);

const maxExp = userInfo.petGrow === "EGG" ? 150 : userInfo.petGrow === "HATCH" ? 300 : 300;
//FIXME: 테스트를 위해 수치 줄임. 차후 150/300으로 변경 필요.
const maxExp = userInfo.petGrow === "EGG" ? 20 : userInfo.petGrow === "HATCH" ? 40 : 40;

// 티어 아이콘 매핑
const tierEmojis = {
SEED: "🫘",
SPROUT: "🌱",
FLOWER: "🌺",
FRUIT: "🍎",
TREE: "🌳",
NONE: "❌미획득",
SEED: "🫘씨앗",
SPROUT: "🌱새싹",
FLOWER: "🌺꽃",
FRUIT: "🍎열매",
TREE: "🌳나무",
};

// 펫 성장 단계 한글화
Expand Down Expand Up @@ -170,7 +172,7 @@ useEffect(() => {
<div className="avatar-container">
<img src={userInfo.avatarUrl} alt="User Avatar" />
</div>
z<span className="username">{userInfo.username || "사용자"}</span>
<span className="username">{userInfo.nickname || userInfo.username}({userInfo.username || "사용자"})</span>
</div>

{/* 유저 세부 정보 */}
Expand All @@ -193,7 +195,7 @@ useEffect(() => {
<span className="detail-icon">🏆</span>
<span className="detail-text">
티어: <span className="tier-badge">
{tierEmojis[userInfo.tier] || ""} {userInfo.tier || "없음"}
{tierEmojis[userInfo.tier] || ""}
</span>
</span>
</div>
Expand Down