FocusGuardBaseModel / src /components /Achievement.jsx
Kexin-251202's picture
Deploy base model
c86c45b verified
import React, { useState, useEffect } from 'react';
function Achievement() {
const [stats, setStats] = useState({
total_sessions: 0,
total_focus_time: 0,
avg_focus_score: 0,
streak_days: 0
});
const [badges, setBadges] = useState([]);
const [loading, setLoading] = useState(true);
// 格式化时间显示
const formatTime = (seconds) => {
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
if (hours > 0) return `${hours}h ${minutes}m`;
return `${minutes}m`;
};
// 加载统计数据
useEffect(() => {
fetch('/api/stats/summary')
.then(res => res.json())
.then(data => {
setStats(data);
calculateBadges(data);
setLoading(false);
})
.catch(err => {
console.error('Failed to load stats:', err);
setLoading(false);
});
}, []);
// 根据统计数据计算徽章
const calculateBadges = (data) => {
const earnedBadges = [];
// 首次会话徽章
if (data.total_sessions >= 1) {
earnedBadges.push({
id: 'first-session',
name: 'First Step',
description: 'Complete your first focus session',
icon: '🎯',
unlocked: true
});
}
// 10次会话徽章
if (data.total_sessions >= 10) {
earnedBadges.push({
id: 'ten-sessions',
name: 'Getting Started',
description: 'Complete 10 focus sessions',
icon: '⭐',
unlocked: true
});
}
// 50次会话徽章
if (data.total_sessions >= 50) {
earnedBadges.push({
id: 'fifty-sessions',
name: 'Dedicated',
description: 'Complete 50 focus sessions',
icon: '🏆',
unlocked: true
});
}
// 专注大师徽章 (平均专注度 > 80%)
if (data.avg_focus_score >= 0.8 && data.total_sessions >= 5) {
earnedBadges.push({
id: 'focus-master',
name: 'Focus Master',
description: 'Maintain 80%+ average focus score',
icon: '🧠',
unlocked: true
});
}
// 连续天数徽章
if (data.streak_days >= 7) {
earnedBadges.push({
id: 'week-streak',
name: 'Week Warrior',
description: '7 day streak',
icon: '🔥',
unlocked: true
});
}
if (data.streak_days >= 30) {
earnedBadges.push({
id: 'month-streak',
name: 'Month Master',
description: '30 day streak',
icon: '💎',
unlocked: true
});
}
// 时长徽章 (10小时+)
if (data.total_focus_time >= 36000) {
earnedBadges.push({
id: 'ten-hours',
name: 'Endurance',
description: '10+ hours total focus time',
icon: '⏱️',
unlocked: true
});
}
// 未解锁徽章(示例)
const allBadges = [
{
id: 'first-session',
name: 'First Step',
description: 'Complete your first focus session',
icon: '🎯',
unlocked: data.total_sessions >= 1
},
{
id: 'ten-sessions',
name: 'Getting Started',
description: 'Complete 10 focus sessions',
icon: '⭐',
unlocked: data.total_sessions >= 10
},
{
id: 'fifty-sessions',
name: 'Dedicated',
description: 'Complete 50 focus sessions',
icon: '🏆',
unlocked: data.total_sessions >= 50
},
{
id: 'focus-master',
name: 'Focus Master',
description: 'Maintain 80%+ average focus score',
icon: '🧠',
unlocked: data.avg_focus_score >= 0.8 && data.total_sessions >= 5
},
{
id: 'week-streak',
name: 'Week Warrior',
description: '7 day streak',
icon: '🔥',
unlocked: data.streak_days >= 7
},
{
id: 'month-streak',
name: 'Month Master',
description: '30 day streak',
icon: '💎',
unlocked: data.streak_days >= 30
},
{
id: 'ten-hours',
name: 'Endurance',
description: '10+ hours total focus time',
icon: '⏱️',
unlocked: data.total_focus_time >= 36000
},
{
id: 'hundred-sessions',
name: 'Centurion',
description: 'Complete 100 focus sessions',
icon: '👑',
unlocked: data.total_sessions >= 100
}
];
setBadges(allBadges);
};
return (
<main id="page-c" className="page">
<h1 className="page-title">My Achievement</h1>
{loading ? (
<div style={{ textAlign: 'center', padding: '40px', color: '#888' }}>
Loading stats...
</div>
) : (
<>
<div className="stats-grid">
<div className="stat-card">
<div className="stat-number" id="total-sessions">{stats.total_sessions}</div>
<div className="stat-label">Total Sessions</div>
</div>
<div className="stat-card">
<div className="stat-number" id="total-hours">{formatTime(stats.total_focus_time)}</div>
<div className="stat-label">Total Focus Time</div>
</div>
<div className="stat-card">
<div className="stat-number" id="avg-focus">{(stats.avg_focus_score * 100).toFixed(1)}%</div>
<div className="stat-label">Average Focus</div>
</div>
<div className="stat-card">
<div className="stat-number" id="current-streak">{stats.streak_days}</div>
<div className="stat-label">Day Streak</div>
</div>
</div>
<div className="achievements-section">
<h2>Badges</h2>
<div id="badges-container" className="badges-grid">
{badges.map(badge => (
<div
key={badge.id}
className={`badge ${badge.unlocked ? 'unlocked' : 'locked'}`}
style={{
padding: '20px',
textAlign: 'center',
border: '2px solid',
borderColor: badge.unlocked ? '#00FF00' : '#444',
borderRadius: '10px',
backgroundColor: badge.unlocked ? 'rgba(0, 255, 0, 0.1)' : 'rgba(68, 68, 68, 0.1)',
opacity: badge.unlocked ? 1 : 0.5,
transition: 'all 0.3s'
}}
>
<div style={{ fontSize: '48px', marginBottom: '10px' }}>
{badge.unlocked ? badge.icon : '🔒'}
</div>
<div style={{ fontWeight: 'bold', marginBottom: '5px' }}>
{badge.name}
</div>
<div style={{ fontSize: '12px', color: '#888' }}>
{badge.description}
</div>
</div>
))}
</div>
</div>
</>
)}
</main>
);
}
export default Achievement;