Implement streak celebration animation
This commit is contained in:
364
pragativeer-celebration_1.html
Normal file
364
pragativeer-celebration_1.html
Normal file
File diff suppressed because one or more lines are too long
373
public/streak-animation.html
Normal file
373
public/streak-animation.html
Normal file
File diff suppressed because one or more lines are too long
98
scratch/port_streak.py
Normal file
98
scratch/port_streak.py
Normal file
File diff suppressed because one or more lines are too long
@@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user