Files
aurorabot/web/src/components/lootdrop-card.tsx
2026-01-09 16:18:52 +01:00

129 lines
6.0 KiB
TypeScript

import { Card, CardContent, CardHeader, CardTitle } from "./ui/card";
import { Progress } from "./ui/progress";
import { Gift, Clock, Sparkles, Zap, Timer } from "lucide-react";
import { cn } from "../lib/utils";
import { Skeleton } from "./ui/skeleton";
export interface LootdropData {
rewardAmount: number;
currency: string;
createdAt: string;
expiresAt: string | null;
}
export interface LootdropState {
monitoredChannels: number;
hottestChannel: {
id: string;
messages: number;
progress: number;
cooldown: boolean;
} | null;
config: {
requiredMessages: number;
dropChance: number;
};
}
interface LootdropCardProps {
drop?: LootdropData | null;
state?: LootdropState;
isLoading?: boolean;
className?: string;
}
export function LootdropCard({ drop, state, isLoading, className }: LootdropCardProps) {
if (isLoading) {
return (
<Card className={cn("glass-card border-none bg-card/40", className)}>
<CardHeader className="flex flex-row items-center justify-between pb-2">
<CardTitle className="text-sm font-medium">Lootdrop Status</CardTitle>
<Gift className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="space-y-3">
<Skeleton className="h-8 w-[120px]" />
<Skeleton className="h-4 w-[80px]" />
</div>
</CardContent>
</Card>
);
}
const isActive = !!drop;
const progress = state?.hottestChannel?.progress || 0;
const isCooldown = state?.hottestChannel?.cooldown || false;
return (
<Card className={cn(
"glass-card border-none transition-all duration-500 overflow-hidden relative",
isActive ? "bg-primary/5 border-primary/20 hover-glow ring-1 ring-primary/20" : "bg-card/40",
className
)}>
{/* Ambient Background Effect */}
{isActive && (
<div className="absolute -right-4 -top-4 w-24 h-24 bg-primary/20 blur-3xl rounded-full pointer-events-none animate-pulse" />
)}
<CardHeader className="flex flex-row items-center justify-between pb-2 relative z-10">
<CardTitle className="text-sm font-medium flex items-center gap-2">
{isActive ? "Active Lootdrop" : "Lootdrop Potential"}
{isActive && (
<span className="relative flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-primary opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-primary"></span>
</span>
)}
</CardTitle>
<Gift className={cn("h-4 w-4 transition-colors", isActive ? "text-primary " : "text-muted-foreground")} />
</CardHeader>
<CardContent className="relative z-10">
{isActive ? (
<div className="space-y-3 animate-in fade-in slide-up">
<div className="flex items-center justify-between">
<span className="text-2xl font-bold text-primary flex items-center gap-2">
<Sparkles className="w-5 h-5 text-yellow-500 fill-yellow-500 animate-pulse" />
{drop.rewardAmount.toLocaleString()} {drop.currency}
</span>
</div>
<div className="flex items-center gap-2 text-xs text-muted-foreground">
<Clock className="w-3 h-3" />
<span>Dropped {new Date(drop.createdAt).toLocaleTimeString()}</span>
</div>
</div>
) : (
<div className="space-y-4">
{isCooldown ? (
<div className="flex flex-col items-center justify-center py-2 text-muted-foreground space-y-1">
<Timer className="w-6 h-6 text-yellow-500 opacity-80" />
<p className="text-sm font-medium text-yellow-500/80">Cooling Down...</p>
<p className="text-xs opacity-50">Channels are recovering.</p>
</div>
) : (
<div className="space-y-2">
<div className="flex items-center justify-between text-xs text-muted-foreground">
<div className="flex items-center gap-1.5">
<Zap className={cn("w-3 h-3", progress > 80 ? "text-yellow-500" : "text-muted-foreground")} />
<span>Next Drop Chance</span>
</div>
<span className="font-mono">{Math.round(progress)}%</span>
</div>
<Progress value={progress} className="h-1.5" indicatorClassName={cn(progress > 80 ? "bg-yellow-500" : "bg-primary")} />
{state?.hottestChannel ? (
<p className="text-[10px] text-muted-foreground text-right opacity-70">
{state.hottestChannel.messages} / {state.config.requiredMessages} msgs
</p>
) : (
<p className="text-[10px] text-muted-foreground text-center opacity-50 pt-1">
No recent activity
</p>
)}
</div>
)}
</div>
)}
</CardContent>
</Card>
);
}