Implement streak celebration animation

This commit is contained in:
2026-07-10 12:51:59 +05:30
parent d5199682e3
commit 79dde09304
4 changed files with 855 additions and 67 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

98
scratch/port_streak.py Normal file

File diff suppressed because one or more lines are too long

View File

@@ -1,8 +1,6 @@
"use client"; "use client";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { Button } from "@/components/ui/button";
import { Flame, Trophy, Award, Sparkles } from "lucide-react";
import { useActiveUser } from "@/hooks/useActiveUser"; import { useActiveUser } from "@/hooks/useActiveUser";
export function StreakOnboardingModal() { export function StreakOnboardingModal() {
@@ -19,76 +17,31 @@ export function StreakOnboardingModal() {
} }
}, [user, loading]); }, [user, loading]);
useEffect(() => {
const handleMessage = (event: MessageEvent) => {
if (event.data === 'close-streak-modal') {
if (user) {
sessionStorage.setItem(`hasSeenStreakPopup_${user.id}`, "true");
}
setIsOpen(false);
}
};
window.addEventListener("message", handleMessage);
return () => window.removeEventListener("message", handleMessage);
}, [user]);
if (!isOpen || !user) return null; if (!isOpen || !user) return null;
const streak = user.streak_count; const streak = user.streak_count;
const targetExam = user.target_exam?.replace("_", " ") || "JEE/NEET";
// Streak-based wishes and titles
let wishTitle = "Welcome to PragatiVeer! 🌟";
let wishMessage = `Prepare yourself to conquer ${targetExam}. Your daily practice starts here!`;
let iconTheme = "text-[#00F0FF] bg-[#00F0FF]/10";
let iconComponent = <Sparkles className="size-10" />;
if (streak === 0) {
wishTitle = "Start Your Streak Today! 🚀";
wishMessage = "Today is Day 1 of your journey. Establish your streak now and build the consistency needed for IIT/AIIMS!";
iconTheme = "text-blue-500 bg-blue-500/10";
iconComponent = <Sparkles className="size-10" />;
} else if (streak < 4) {
wishTitle = "Keep the Fire Burning! 🔥";
wishMessage = `Great job! You have maintained a ${streak}-day study streak. Keep practicing daily to build solid muscle memory!`;
iconTheme = "text-orange-500 bg-orange-500/10 animate-bounce";
iconComponent = <Flame className="size-10 fill-current" />;
} else {
wishTitle = "Unstoppable Dedication! ⚡";
wishMessage = `Incredible! A ${streak}-day streak shows true championship discipline. You are outperforming the competition. Let's make today count!`;
iconTheme = "text-[#D1FF4D] bg-[#D1FF4D]/10 animate-pulse";
iconComponent = <Trophy className="size-10" />;
}
const handleEnter = () => {
sessionStorage.setItem(`hasSeenStreakPopup_${user.id}`, "true");
setIsOpen(false);
};
return ( return (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/85 backdrop-blur-md animate-in fade-in duration-300"> <div className="fixed inset-0 z-[100] bg-black">
<div className="bg-background border border-border shadow-[0_0_50px_-12px_rgba(0,240,255,0.2)] rounded-3xl w-full max-w-lg p-8 text-center space-y-6 relative overflow-hidden animate-in zoom-in-95 slide-in-from-bottom-4 duration-300"> <iframe
src={`/streak-animation.html?streak=${streak}`}
{/* Animated Background Gradients */} className="w-full h-full border-none"
<div className="absolute -right-20 -top-20 size-48 bg-[#00F0FF]/10 rounded-full blur-3xl pointer-events-none" /> title="Streak Celebration"
<div className="absolute -left-20 -bottom-20 size-48 bg-primary/10 rounded-full blur-3xl pointer-events-none" /> />
{/* Dynamic Icon Badge */}
<div className={`size-20 rounded-2xl ${iconTheme} flex items-center justify-center mx-auto border border-current/20 shadow-[0_0_15px_rgba(0,0,0,0.1)]`}>
{iconComponent}
</div>
<div className="space-y-2">
{streak > 0 && (
<div className="inline-flex items-center gap-1.5 px-3 py-1 bg-orange-500/10 border border-orange-500/20 text-orange-500 text-xs font-extrabold rounded-full tracking-wider uppercase">
<Flame size={12} className="fill-current" /> {streak} Day Streak Active
</div>
)}
<h3 className="text-3xl font-black tracking-tight bg-gradient-to-r from-foreground via-foreground to-muted-foreground bg-clip-text text-transparent">
{wishTitle}
</h3>
<p className="text-muted-foreground text-sm md:text-base leading-relaxed max-w-md mx-auto pt-2">
{wishMessage}
</p>
</div>
<div className="pt-4">
<Button
onClick={handleEnter}
className="w-full h-14 rounded-xl text-lg font-black bg-[#00F0FF] text-black hover:bg-[#00F0FF]/90 shadow-[0_0_20px_-3px_#00F0FF] hover:shadow-[0_0_30px_#00F0FF] hover:-translate-y-1 transition-all duration-300"
>
Enter Workspace
</Button>
</div>
</div>
</div> </div>
); );
} }