Skip to content

Commit 9623a87

Browse files
committed
frontend streak_feature
1 parent 03cc78d commit 9623a87

4 files changed

Lines changed: 247 additions & 131 deletions

File tree

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { motion } from 'framer-motion'
2+
import { Flame, Trophy } from 'lucide-react';
3+
import { useStreak } from '../../hooks/useStreak'
4+
import { GlassCard } from '../ui/GlassCard';
5+
6+
const StreakCard = () => {
7+
const { data: streak ,isLoading} = useStreak();
8+
9+
if (isLoading) {
10+
return (
11+
<GlassCard>
12+
<div className='p-6 animate-pulse'>
13+
</div>
14+
</GlassCard>
15+
)
16+
}
17+
18+
19+
if (!streak) return null;
20+
21+
22+
return (
23+
<GlassCard className='relative overflow-hidden h-full flex flex-col justify-between'>
24+
<div className="absolute inset-0 bg-linear-to-br from-orange-500/10 to-red-500/10"></div>
25+
<div className="relative p-6 flex-1 flex flex-col justify-center">
26+
<div className="flex items-center justify-between mb-4">
27+
<h3 className="text-lg font-semibold text-slate-300">Streak</h3>
28+
<Trophy className="w-5 h-5 text-yellow-400" />
29+
</div>
30+
31+
<div className='flex items-center gap-4'>
32+
<div className='flex-1'>
33+
<motion.div
34+
initial={{ scale: 0 }}
35+
animate={{ scale: 1 }}
36+
transition={{ type: "spring", stiffness: 200 }}
37+
className='text-5xl font-bold flex items-center gap-2'>
38+
<Flame className={`w-12 h-12 ${streak.currentStreak > 0 ?
39+
"text-orange-400" :
40+
"text-slate-600"
41+
}`} />
42+
<span className={
43+
streak.currentStreak > 0 ?
44+
"bg-linear-to-r from-orange-400 to-red-400 bg-clip-text text-transparent"
45+
: "text-slate-600"
46+
}>
47+
{streak.currentStreak}
48+
</span>
49+
</motion.div>
50+
<p className='text-sm text-slate-400 mt-2'>
51+
{
52+
streak.currentStreak === 0 ?
53+
"Start your streak today" :
54+
streak.currentStreak === 1 ?
55+
"Day of good posture"
56+
: "Days of good posture"
57+
}
58+
</p>
59+
</div>
60+
61+
{/* Best Streak */}
62+
{streak.longestStreak > 0 && (
63+
<div className='text-right'>
64+
<div className='text-2xl font-bold text-slate-300'>
65+
{streak.longestStreak}
66+
</div>
67+
<div className='text-xs text-slate-500'>
68+
Best Streak
69+
</div>
70+
</div>
71+
)}
72+
</div>
73+
74+
{/* Motivational Message */}
75+
76+
{streak.currentStreak >=7 && (
77+
<motion.div initial={{opacity:0,y:10}}
78+
animate={{opacity:1,y:0}}
79+
className="mt-4 px-3 py-2 bg-orange-500/10 rounded-xl border border-orange-500/20">
80+
<p className='text-sm text-orange-300'>
81+
Amazing! {streak.currentStreak} days streak!
82+
</p>
83+
</motion.div>
84+
)}
85+
</div>
86+
</GlassCard>
87+
)
88+
89+
}
90+
91+
export default StreakCard

frontend/src/hooks/useStreak.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { useQuery } from "@tanstack/react-query"
2+
import { analyticsApi, type StreakResponse } from "../services/api"
3+
4+
5+
export const useStreak = () =>{
6+
return useQuery<StreakResponse>({
7+
queryKey: ['streak'],
8+
queryFn: analyticsApi.getStreak,
9+
refetchInterval: 60000,
10+
});
11+
}

0 commit comments

Comments
 (0)