first commit
This commit is contained in:
157
src/components/sections/SquadChallenges.tsx
Normal file
157
src/components/sections/SquadChallenges.tsx
Normal file
@@ -0,0 +1,157 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useUser } from "@/lib/context";
|
||||
import { Users, Footprints, Check, Zap, Landmark } from "lucide-react";
|
||||
import { motion } from "framer-motion";
|
||||
|
||||
interface TeamChallenge {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
reward: number;
|
||||
current: number;
|
||||
goal: number;
|
||||
joined: boolean;
|
||||
icon: React.ReactNode;
|
||||
}
|
||||
|
||||
export default function SquadChallenges() {
|
||||
const { addLyts } = useUser();
|
||||
const [challenges, setChallenges] = useState<TeamChallenge[]>([
|
||||
{
|
||||
id: "ch-steps",
|
||||
title: "Weekend Step Sprint",
|
||||
description: "Collectively log 50,000 steps with your team this weekend.",
|
||||
reward: 100,
|
||||
current: 41200,
|
||||
goal: 50000,
|
||||
joined: false,
|
||||
icon: <Footprints className="w-5 h-5 text-accent-lime" />,
|
||||
},
|
||||
{
|
||||
id: "ch-stores",
|
||||
title: "Starbucks Double Drop",
|
||||
description: "Check in at any two Starbucks locations within 7 days.",
|
||||
reward: 40,
|
||||
current: 1,
|
||||
goal: 2,
|
||||
joined: true,
|
||||
icon: <Landmark className="w-5 h-5 text-emerald-400" />,
|
||||
},
|
||||
]);
|
||||
|
||||
const handleJoinChallenge = (id: string, reward: number) => {
|
||||
setChallenges((prev) =>
|
||||
prev.map((ch) => {
|
||||
if (ch.id === id) {
|
||||
if (ch.joined) {
|
||||
addLyts(reward);
|
||||
return { ...ch, current: ch.goal };
|
||||
}
|
||||
return { ...ch, joined: true };
|
||||
}
|
||||
return ch;
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="py-24 bg-[#090909] relative overflow-hidden">
|
||||
<div className="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
|
||||
|
||||
<div className="glassmorphism rounded-3xl p-8 sm:p-12 border border-primary/10 space-y-8">
|
||||
<div className="text-left space-y-4">
|
||||
<div className="w-12 h-12 rounded-2xl bg-primary/10 border border-primary/20 flex items-center justify-center text-primary">
|
||||
<Users className="w-6 h-6" />
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<span className="text-primary font-bold text-xs uppercase tracking-wider">Section 13 • Squad Goals</span>
|
||||
<h3 className="text-2xl sm:text-4xl font-extrabold font-sora text-white">
|
||||
Cooperative Team <br />
|
||||
<span className="text-glow-yellow text-primary">Active Challenges</span>
|
||||
</h3>
|
||||
<p className="text-white/60 text-sm leading-relaxed">
|
||||
Connect with friends or match with nearby community squads. Log steps, complete visits, and unlock bulk LYT currency bonuses together.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Challenges listing */}
|
||||
<div className="space-y-4 pt-4">
|
||||
{challenges.map((ch) => {
|
||||
const percentage = Math.min(100, Math.round((ch.current / ch.goal) * 100));
|
||||
const isCompleted = ch.current >= ch.goal;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={ch.id}
|
||||
className={`glassmorphism rounded-2xl p-6 border transition-colors ${
|
||||
ch.joined ? "border-primary/20 bg-primary/2" : "border-white/5"
|
||||
}`}
|
||||
>
|
||||
<div className="flex justify-between items-start gap-4 mb-4">
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="w-10 h-10 rounded-xl bg-white/5 border border-white/10 flex items-center justify-center">
|
||||
{ch.icon}
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="text-sm font-bold text-white font-sora">{ch.title}</h4>
|
||||
<p className="text-white/60 text-xs mt-0.5 leading-relaxed">{ch.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="text-right">
|
||||
<span className="text-[9px] text-white/40 font-bold uppercase tracking-wider block">Reward</span>
|
||||
<span className="text-xs font-extrabold text-primary">+{ch.reward} LYTs</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between text-xs font-semibold">
|
||||
<span className="text-white/50">{ch.current.toLocaleString()} / {ch.goal.toLocaleString()}</span>
|
||||
<span className="text-primary">{percentage}%</span>
|
||||
</div>
|
||||
<div className="w-full h-1.5 bg-white/5 rounded-full overflow-hidden">
|
||||
<div
|
||||
style={{ width: `${percentage}%` }}
|
||||
className="h-full bg-gradient-to-r from-primary to-accent-lime rounded-full"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-4 flex justify-end">
|
||||
<button
|
||||
onClick={() => handleJoinChallenge(ch.id, ch.reward)}
|
||||
disabled={isCompleted}
|
||||
className={`px-4 py-2 rounded-xl text-xs font-bold transition-all flex items-center gap-1.5 cursor-pointer ${
|
||||
isCompleted
|
||||
? "bg-accent-lime/10 border border-accent-lime/20 text-accent-lime cursor-not-allowed"
|
||||
: ch.joined
|
||||
? "bg-primary text-dark hover:bg-primary/90"
|
||||
: "bg-white/5 border border-white/10 text-white hover:bg-white/10"
|
||||
}`}
|
||||
>
|
||||
{isCompleted ? (
|
||||
<>
|
||||
<Check className="w-3.5 h-3.5" />
|
||||
<span>Claimed</span>
|
||||
</>
|
||||
) : ch.joined ? (
|
||||
<span>Complete & Claim</span>
|
||||
) : (
|
||||
<span>Join Squad Goal</span>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user