feat: enhance dashboard with real streak calculation, answered prayers section, and more stats

This commit is contained in:
nmemmert committed 2026-01-16 08:25:02 -05:00
1 parent 1d9e2a5d38
commit 55076bbc0e
1 file changed
+110 -7
+110 -7
View File
@@ -10,6 +10,7 @@ interface Prayer {
text: string; text: string;
prayFor?: string; prayFor?: string;
answered?: boolean; answered?: boolean;
answerDetails?: string;
} }
interface HomePageProps { interface HomePageProps {
@@ -26,7 +27,53 @@ export default function HomePage({ prayers, todayCount, onStartPraying, onSelect
const totalPrayers = prayers.length; const totalPrayers = prayers.length;
const uniqueDays = new Set(prayers.map(p => p.date)).size; const uniqueDays = new Set(prayers.map(p => p.date)).size;
const answeredPrayers = prayers.filter(p => p.answered).length; const answeredPrayers = prayers.filter(p => p.answered).length;
const streak = Math.floor(Math.random() * 30) + 1; // Calculate actual streak
// Calculate actual streak - consecutive days with prayers
const calculateStreak = () => {
if (prayers.length === 0) return 0;
const prayerDates = Array.from(new Set(prayers.map(p => p.date))).sort().reverse();
let streak = 0;
let checkDate = new Date(today);
for (let i = 0; i < 365; i++) {
const dateStr = checkDate.toISOString().split('T')[0];
if (prayerDates.includes(dateStr)) {
streak++;
} else if (i === 0) {
// If today has no prayer, streak is broken (unless we haven't prayed today yet, which is ok)
break;
} else {
break;
}
checkDate.setDate(checkDate.getDate() - 1);
}
return streak;
};
const streak = calculateStreak();
// Calculate more stats
const avgPrayerLength = totalPrayers > 0
? Math.round(prayers.reduce((sum, p) => sum + p.text.length, 0) / totalPrayers)
: 0;
const answeredPercentage = totalPrayers > 0
? Math.round((answeredPrayers / totalPrayers) * 100)
: 0;
// Get most prayed for person/topic
const prayerForCounts: Record<string, number> = {};
prayers.forEach(p => {
if (p.prayFor) {
prayerForCounts[p.prayFor] = (prayerForCounts[p.prayFor] || 0) + 1;
}
});
const mostPrayedFor = Object.entries(prayerForCounts).sort((a, b) => b[1] - a[1])[0];
// Recent answered prayers
const recentAnswered = prayers.filter(p => p.answered).slice(0, 3);
return ( return (
<div className="min-h-screen bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 px-4 pb-32"> <div className="min-h-screen bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 px-4 pb-32">
@@ -67,7 +114,7 @@ export default function HomePage({ prayers, todayCount, onStartPraying, onSelect
</div> </div>
</div> </div>
{/* Stats Grid */} {/* Main Stats Grid */}
<div className="grid grid-cols-2 gap-4 mb-8"> <div className="grid grid-cols-2 gap-4 mb-8">
{/* Total Prayers */} {/* Total Prayers */}
<div className="bg-slate-800/60 backdrop-blur-xl rounded-xl p-4 border border-slate-700/50 hover:border-slate-600 transition-all"> <div className="bg-slate-800/60 backdrop-blur-xl rounded-xl p-4 border border-slate-700/50 hover:border-slate-600 transition-all">
@@ -83,20 +130,39 @@ export default function HomePage({ prayers, todayCount, onStartPraying, onSelect
<div className="text-xs text-slate-500 mt-2">Consistent</div> <div className="text-xs text-slate-500 mt-2">Consistent</div>
</div> </div>
{/* Answered */} {/* Answered Prayers */}
<div className="bg-slate-800/60 backdrop-blur-xl rounded-xl p-4 border border-slate-700/50 hover:border-slate-600 transition-all"> <div className="bg-slate-800/60 backdrop-blur-xl rounded-xl p-4 border border-slate-700/50 hover:border-slate-600 transition-all">
<div className="text-slate-400 text-xs font-semibold mb-2">✅ Answered</div> <div className="text-slate-400 text-xs font-semibold mb-2">✅ Answered</div>
<div className="text-3xl font-bold text-green-400">{answeredPrayers}</div> <div className="text-3xl font-bold text-green-400">{answeredPrayers}</div>
<div className="text-xs text-slate-500 mt-2">Blessings</div> <div className="text-xs text-slate-500 mt-2">{answeredPercentage}% answered</div>
</div> </div>
{/* Streak */} {/* Streak */}
<div className="bg-slate-800/60 backdrop-blur-xl rounded-xl p-4 border border-slate-700/50 hover:border-slate-600 transition-all"> <div className="bg-slate-800/60 backdrop-blur-xl rounded-xl p-4 border border-slate-700/50 hover:border-slate-600 transition-all">
<div className="text-slate-400 text-xs font-semibold mb-2">🔥 Streak</div> <div className="text-slate-400 text-xs font-semibold mb-2">🔥 Streak</div>
<div className="text-3xl font-bold text-orange-400">{streak} days</div> <div className="text-3xl font-bold text-orange-400">{streak}</div>
<div className="text-xs text-slate-500 mt-2">Keep going!</div> <div className="text-xs text-slate-500 mt-2">consecutive days</div>
</div> </div>
</div> </div>
{/* Secondary Stats */}
<div className="grid grid-cols-2 gap-4 mb-8">
{/* Avg Prayer Length */}
<div className="bg-purple-900/20 backdrop-blur-xl rounded-xl p-4 border border-purple-500/30">
<div className="text-purple-300 text-xs font-semibold mb-2">📊 Avg Length</div>
<div className="text-2xl font-bold text-purple-200">{avgPrayerLength}</div>
<div className="text-xs text-purple-400 mt-2">characters</div>
</div>
{/* Most Prayed For */}
{mostPrayedFor && (
<div className="bg-pink-900/20 backdrop-blur-xl rounded-xl p-4 border border-pink-500/30">
<div className="text-pink-300 text-xs font-semibold mb-2">💝 Most Prayed For</div>
<div className="text-sm font-bold text-pink-200 line-clamp-1">{mostPrayedFor[0]}</div>
<div className="text-xs text-pink-400 mt-2">{mostPrayedFor[1]} times</div>
</div>
)}
</div>
</div> </div>
{/* CTA Button */} {/* CTA Button */}
@@ -112,7 +178,7 @@ export default function HomePage({ prayers, todayCount, onStartPraying, onSelect
{/* Recent Prayers */} {/* Recent Prayers */}
{recentPrayers.length > 0 && ( {recentPrayers.length > 0 && (
<div className="max-w-md mx-auto"> <div className="max-w-md mx-auto mb-12">
<h2 className="text-lg font-bold text-white mb-4 flex items-center gap-2"> <h2 className="text-lg font-bold text-white mb-4 flex items-center gap-2">
<span>📖</span> Recent Prayers <span>📖</span> Recent Prayers
</h2> </h2>
@@ -144,6 +210,43 @@ export default function HomePage({ prayers, todayCount, onStartPraying, onSelect
</div> </div>
)} )}
{/* Recent Answered Prayers */}
{recentAnswered.length > 0 && (
<div className="max-w-md mx-auto mb-12">
<h2 className="text-lg font-bold text-green-400 mb-4 flex items-center gap-2">
<span>✨</span> Recently Answered
</h2>
<div className="space-y-3">
{recentAnswered.map((prayer) => (
<div
key={prayer.id}
className="bg-green-900/20 backdrop-blur-xl rounded-xl p-4 border border-green-500/30 hover:border-green-400/50 transition-all"
>
<div className="flex items-start gap-3">
<div className="text-2xl">✅</div>
<div className="flex-1 min-w-0">
{prayer.prayFor && (
<div className="text-xs font-bold text-green-300 mb-1 uppercase tracking-wider">
🙏 {prayer.prayFor}
</div>
)}
<p className="text-sm text-slate-300 line-clamp-2">{prayer.text}</p>
{prayer.answerDetails && (
<p className="text-xs text-green-400 mt-2 italic">
💬 "{prayer.answerDetails.substring(0, 60)}..."
</p>
)}
<div className="text-xs text-slate-500 mt-2">
{new Date(prayer.date).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}
</div>
</div>
</div>
</div>
))}
</div>
</div>
)}
{/* Empty State */} {/* Empty State */}
{prayers.length === 0 && ( {prayers.length === 0 && (
<div className="max-w-md mx-auto text-center py-12"> <div className="max-w-md mx-auto text-center py-12">