418 lines
20 KiB
TypeScript
418 lines
20 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { useUser } from "@/lib/context";
|
|
import { Footprints, ShoppingBag, MapPin, Share2, ClipboardCheck, Sparkles, Check, RefreshCw } from "lucide-react";
|
|
|
|
export default function EarningFeatures() {
|
|
const { profile, addLyts, incrementSteps } = useUser();
|
|
|
|
// Walk simulator state
|
|
const [simSteps, setSimSteps] = useState(1200);
|
|
const [walkClaimed, setWalkClaimed] = useState(false);
|
|
const walkReward = Math.floor(simSteps / 400); // 1 LYT per 400 steps for the simulator
|
|
|
|
// Shop state
|
|
const [selectedItems, setSelectedItems] = useState<string[]>(["coffee"]);
|
|
const [shopClaimed, setShopClaimed] = useState(false);
|
|
|
|
const shopItems = [
|
|
{ id: "coffee", name: "Starbucks Iced Latte", cost: "$5.80", reward: 8 },
|
|
{ id: "sneakers", name: "Nike Air Max Essentials", cost: "$120.00", reward: 150 },
|
|
{ id: "gym", name: "Gymshark Fitness Tee", cost: "$35.00", reward: 40 },
|
|
];
|
|
|
|
const totalShopReward = shopItems
|
|
.filter((item) => selectedItems.includes(item.id))
|
|
.reduce((sum, item) => sum + item.reward, 0);
|
|
|
|
// Map state
|
|
const [visitedStores, setVisitedStores] = useState<string[]>([]);
|
|
const [mapClaimed, setMapClaimed] = useState<string | null>(null);
|
|
|
|
const checkinLocations = [
|
|
{ id: "cafe", name: "Brew & Co Cafe", reward: 5, checked: false },
|
|
{ id: "apparel", name: "H&M flagship", reward: 12, checked: false },
|
|
{ id: "arena", name: "Downtown Arena", reward: 25, checked: false },
|
|
];
|
|
|
|
// Referral state
|
|
const [referralCopied, setReferralCopied] = useState(false);
|
|
const referralCode = `lytsup.com/invite/${profile.name.toLowerCase().replace(/\s+/g, "")}-77`;
|
|
|
|
const handleSimulateWalk = () => {
|
|
incrementSteps(simSteps);
|
|
addLyts(walkReward);
|
|
setWalkClaimed(true);
|
|
setTimeout(() => {
|
|
setWalkClaimed(false);
|
|
setSimSteps(1200);
|
|
}, 4000);
|
|
};
|
|
|
|
const handleShopClaim = () => {
|
|
if (totalShopReward > 0) {
|
|
addLyts(totalShopReward);
|
|
setShopClaimed(true);
|
|
setTimeout(() => {
|
|
setShopClaimed(false);
|
|
setSelectedItems([]);
|
|
}, 4000);
|
|
}
|
|
};
|
|
|
|
const handleCheckin = (id: string, name: string, reward: number) => {
|
|
if (visitedStores.includes(id)) return;
|
|
setVisitedStores((prev) => [...prev, id]);
|
|
addLyts(reward);
|
|
setMapClaimed(name);
|
|
setTimeout(() => setMapClaimed(null), 3000);
|
|
};
|
|
|
|
const handleCopyReferral = () => {
|
|
navigator.clipboard.writeText(referralCode);
|
|
setReferralCopied(true);
|
|
addLyts(50); // Referral bonus!
|
|
setTimeout(() => setReferralCopied(false), 4000);
|
|
};
|
|
|
|
return (
|
|
<section id="earn" className="py-24 bg-[#090909] relative overflow-hidden">
|
|
{/* Background glow lines */}
|
|
<div className="absolute top-1/2 left-0 right-0 h-0.5 bg-gradient-to-r from-transparent via-white/5 to-transparent pointer-events-none" />
|
|
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
|
|
|
|
{/* Section Header */}
|
|
<div className="text-center max-w-3xl mx-auto mb-20 space-y-4">
|
|
<span className="text-accent-pink font-extrabold text-xs tracking-widest uppercase">
|
|
How it works
|
|
</span>
|
|
<h2 className="text-3xl sm:text-5xl font-extrabold font-sora text-white leading-tight">
|
|
Earn LYTs for <span className="text-glow-yellow text-primary">Living Your Life</span>
|
|
</h2>
|
|
<p className="text-white/60 text-base sm:text-lg">
|
|
Interact with our live simulations below to see how easy it is to rack up social currency.
|
|
</p>
|
|
</div>
|
|
|
|
{/* Feature Grid */}
|
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
|
|
|
|
{/* Card 1: Walk to Earn (Simulator) */}
|
|
<div className="glassmorphism rounded-3xl p-8 flex flex-col justify-between group hover:border-primary/20 transition-all duration-300">
|
|
<div className="space-y-6">
|
|
<div className="flex items-center justify-between">
|
|
<div className="w-12 h-12 rounded-2xl bg-primary/10 border border-primary/20 flex items-center justify-center text-primary">
|
|
<Footprints className="w-6 h-6 animate-pulse" />
|
|
</div>
|
|
<span className="text-xs font-bold px-3 py-1 rounded-full bg-white/5 text-white/50 border border-white/5">
|
|
1 LYT / 400 Steps
|
|
</span>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<h3 className="text-2xl font-bold font-sora text-white">Walk-to-Earn</h3>
|
|
<p className="text-white/60 text-sm">
|
|
Keep your phone in your pocket, walk to class, run errands, or jog. Watch your step count convert to LYTs automatically.
|
|
</p>
|
|
</div>
|
|
|
|
{/* Step Simulator Widget */}
|
|
<div className="bg-white/3 border border-white/5 rounded-2xl p-6 space-y-4">
|
|
<div className="flex justify-between items-end">
|
|
<div>
|
|
<span className="text-white/40 text-[10px] font-bold tracking-wider uppercase block">Steps to Simulate</span>
|
|
<span className="text-2xl font-extrabold font-sora text-white">
|
|
+{simSteps.toLocaleString()} <span className="text-xs text-white/40">Steps</span>
|
|
</span>
|
|
</div>
|
|
<div className="text-right">
|
|
<span className="text-white/40 text-[10px] font-bold tracking-wider uppercase block">Estimated Earn</span>
|
|
<span className="text-xl font-extrabold text-primary font-sora flex items-center justify-end gap-1">
|
|
+{walkReward} <span className="text-xs font-medium text-white/60">LYTs</span>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Range Slider */}
|
|
<input
|
|
type="range"
|
|
min="400"
|
|
max="12000"
|
|
step="400"
|
|
value={simSteps}
|
|
onChange={(e) => setSimSteps(parseInt(e.target.value))}
|
|
disabled={walkClaimed}
|
|
className="w-full h-1.5 bg-white/10 rounded-lg appearance-none cursor-pointer accent-primary"
|
|
/>
|
|
|
|
<div className="flex justify-between text-[10px] text-white/40 font-bold">
|
|
<span>400 Steps</span>
|
|
<span>6,000 Steps</span>
|
|
<span>12,000 Steps</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mt-8">
|
|
<button
|
|
onClick={handleSimulateWalk}
|
|
disabled={walkClaimed}
|
|
className={`w-full py-4 rounded-xl font-extrabold text-sm tracking-wider flex items-center justify-center gap-2 cursor-pointer transition-all ${
|
|
walkClaimed
|
|
? "bg-accent-lime text-dark shadow-[0_0_20px_rgba(200,255,55,0.3)]"
|
|
: "bg-white/5 hover:bg-primary hover:text-dark text-white border border-white/10 hover:border-primary"
|
|
}`}
|
|
>
|
|
{walkClaimed ? (
|
|
<>
|
|
<Check className="w-5 h-5" />
|
|
<span>Steps Synced! +{walkReward} LYTs Claimed</span>
|
|
</>
|
|
) : (
|
|
<>
|
|
<RefreshCw className="w-4 h-4 animate-spin-slow" />
|
|
<span>Simulate Walk & Sync Steps</span>
|
|
</>
|
|
)}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Card 2: Shop & Earn (Receipt Simulator) */}
|
|
<div className="glassmorphism rounded-3xl p-8 flex flex-col justify-between group hover:border-accent-pink/20 transition-all duration-300">
|
|
<div className="space-y-6">
|
|
<div className="flex items-center justify-between">
|
|
<div className="w-12 h-12 rounded-2xl bg-accent-pink/10 border border-accent-pink/20 flex items-center justify-center text-accent-pink">
|
|
<ShoppingBag className="w-6 h-6" />
|
|
</div>
|
|
<span className="text-xs font-bold px-3 py-1 rounded-full bg-white/5 text-white/50 border border-white/5">
|
|
10% LYT Cashback
|
|
</span>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<h3 className="text-2xl font-bold font-sora text-white">Shop-to-Earn</h3>
|
|
<p className="text-white/60 text-sm">
|
|
Shop from partner merchants (food, clothing, fitness centers) and scan your digital receipt to claim instant LYT cashback.
|
|
</p>
|
|
</div>
|
|
|
|
{/* Receipt Widget */}
|
|
<div className="bg-[#0b0b0b] border border-white/5 rounded-2xl p-5 space-y-3.5 relative overflow-hidden">
|
|
<div className="absolute top-0 right-0 bg-accent-pink/10 text-accent-pink px-2.5 py-0.5 text-[9px] font-bold tracking-wider rounded-bl-lg uppercase">
|
|
Pending Receipt
|
|
</div>
|
|
|
|
<h4 className="text-[10px] font-bold text-white/40 uppercase tracking-widest">Select items purchased:</h4>
|
|
<div className="space-y-2">
|
|
{shopItems.map((item) => (
|
|
<div
|
|
key={item.id}
|
|
onClick={() => {
|
|
if (shopClaimed) return;
|
|
setSelectedItems((prev) =>
|
|
prev.includes(item.id)
|
|
? prev.filter((id) => id !== item.id)
|
|
: [...prev, item.id]
|
|
);
|
|
}}
|
|
className={`flex items-center justify-between p-3 rounded-xl border cursor-pointer transition-all ${
|
|
selectedItems.includes(item.id)
|
|
? "bg-accent-pink/5 border-accent-pink/30 text-white"
|
|
: "bg-white/3 border-white/5 text-white/60 hover:border-white/10"
|
|
}`}
|
|
>
|
|
<div className="flex items-center space-x-3">
|
|
<div
|
|
className={`w-4 h-4 rounded flex items-center justify-center border transition-all ${
|
|
selectedItems.includes(item.id)
|
|
? "bg-accent-pink border-accent-pink"
|
|
: "border-white/20"
|
|
}`}
|
|
>
|
|
{selectedItems.includes(item.id) && <Check className="w-3 h-3 text-white" />}
|
|
</div>
|
|
<div className="text-xs font-semibold">{item.name}</div>
|
|
</div>
|
|
<div className="text-right">
|
|
<div className="text-xs font-extrabold text-white">{item.cost}</div>
|
|
<div className="text-[10px] text-accent-pink font-bold">+{item.reward} LYTs</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mt-8">
|
|
<button
|
|
onClick={handleShopClaim}
|
|
disabled={shopClaimed || totalShopReward === 0}
|
|
className={`w-full py-4 rounded-xl font-extrabold text-sm tracking-wider flex items-center justify-center gap-2 cursor-pointer transition-all ${
|
|
shopClaimed
|
|
? "bg-accent-lime text-dark shadow-[0_0_20px_rgba(200,255,55,0.3)]"
|
|
: totalShopReward === 0
|
|
? "bg-white/5 text-white/20 border border-white/5 cursor-not-allowed"
|
|
: "bg-white/5 hover:bg-accent-pink hover:text-white text-white border border-white/10 hover:border-accent-pink"
|
|
}`}
|
|
>
|
|
{shopClaimed ? (
|
|
<>
|
|
<Check className="w-5 h-5" />
|
|
<span>Receipt Scanned! +{totalShopReward} LYTs Claimed</span>
|
|
</>
|
|
) : (
|
|
<span>Claim Receipt Reward (+{totalShopReward} LYTs)</span>
|
|
)}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Card 3: Visit to Earn (Geofence Checkins) */}
|
|
<div className="glassmorphism rounded-3xl p-8 flex flex-col justify-between group hover:border-accent-purple/20 transition-all duration-300">
|
|
<div className="space-y-6">
|
|
<div className="flex items-center justify-between">
|
|
<div className="w-12 h-12 rounded-2xl bg-accent-purple/10 border border-accent-purple/20 flex items-center justify-center text-accent-purple">
|
|
<MapPin className="w-6 h-6" />
|
|
</div>
|
|
<span className="text-xs font-bold px-3 py-1 rounded-full bg-white/5 text-white/50 border border-white/5">
|
|
Location Check-Ins
|
|
</span>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<h3 className="text-2xl font-bold font-sora text-white">Visit-to-Earn</h3>
|
|
<p className="text-white/60 text-sm">
|
|
Explore your city! Check in at partner gyms, parks, retail shops, or cafes. Each location visit awards you instant points.
|
|
</p>
|
|
</div>
|
|
|
|
{/* Map Simulator Widget */}
|
|
<div className="bg-[#0b0b0b] border border-white/5 rounded-2xl p-5 space-y-4 relative overflow-hidden">
|
|
{mapClaimed && (
|
|
<div className="absolute inset-0 bg-dark/95 flex items-center justify-center z-10 p-4 text-center animate-in fade-in duration-200">
|
|
<div className="space-y-2">
|
|
<div className="w-10 h-10 rounded-full bg-accent-purple/10 border border-accent-purple/30 mx-auto flex items-center justify-center text-accent-purple">
|
|
<Sparkles className="w-5 h-5 animate-spin-slow" />
|
|
</div>
|
|
<p className="text-sm font-semibold text-white">Checked in at {mapClaimed}!</p>
|
|
<p className="text-xs text-accent-lime font-bold">LYTs Added directly to wallet</p>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<h4 className="text-[10px] font-bold text-white/40 uppercase tracking-widest">Active nodes near you:</h4>
|
|
<div className="space-y-2.5">
|
|
{checkinLocations.map((loc) => {
|
|
const visited = visitedStores.includes(loc.id);
|
|
return (
|
|
<div
|
|
key={loc.id}
|
|
className={`flex items-center justify-between p-3 rounded-xl border transition-all ${
|
|
visited
|
|
? "bg-white/2 border-white/5 opacity-50"
|
|
: "bg-white/3 border-white/5 hover:border-accent-purple/30"
|
|
}`}
|
|
>
|
|
<div className="flex items-center space-x-3">
|
|
<MapPin className={`w-4 h-4 ${visited ? "text-white/40" : "text-accent-purple animate-bounce"}`} />
|
|
<div className="text-xs font-semibold text-white">{loc.name}</div>
|
|
</div>
|
|
<button
|
|
onClick={() => handleCheckin(loc.id, loc.name, loc.reward)}
|
|
disabled={visited}
|
|
className={`px-3 py-1.5 rounded-lg text-xs font-bold transition-all cursor-pointer ${
|
|
visited
|
|
? "bg-white/5 text-white/40 cursor-not-allowed"
|
|
: "bg-accent-purple text-white hover:bg-accent-purple/90"
|
|
}`}
|
|
>
|
|
{visited ? "Visited" : `Check In (+${loc.reward} LYT)`}
|
|
</button>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mt-8 text-center text-xs text-white/40">
|
|
<span className="font-semibold text-accent-purple">Glow tips:</span> Allow location permissions in-app to auto check-in.
|
|
</div>
|
|
</div>
|
|
|
|
{/* Card 4: Refer to Earn (Social Loop) */}
|
|
<div className="glassmorphism rounded-3xl p-8 flex flex-col justify-between group hover:border-accent-orange/20 transition-all duration-300">
|
|
<div className="space-y-6">
|
|
<div className="flex items-center justify-between">
|
|
<div className="w-12 h-12 rounded-2xl bg-accent-orange/10 border border-accent-orange/20 flex items-center justify-center text-accent-orange">
|
|
<Share2 className="w-6 h-6" />
|
|
</div>
|
|
<span className="text-xs font-bold px-3 py-1 rounded-full bg-white/5 text-white/50 border border-white/5">
|
|
50 LYTs / Referral
|
|
</span>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<h3 className="text-2xl font-bold font-sora text-white">Refer-to-Earn</h3>
|
|
<p className="text-white/60 text-sm">
|
|
Everything is better with friends. Send your personal link to your friends. Get 50 LYTs the second they verify their profile!
|
|
</p>
|
|
</div>
|
|
|
|
{/* Referral Widget */}
|
|
<div className="bg-[#0b0b0b] border border-white/5 rounded-2xl p-5 space-y-4">
|
|
<div>
|
|
<label className="text-[10px] font-bold text-white/40 uppercase tracking-widest block mb-2">
|
|
Your Invite Link:
|
|
</label>
|
|
<div className="relative flex">
|
|
<input
|
|
type="text"
|
|
readOnly
|
|
value={referralCode}
|
|
className="w-full bg-white/3 border border-white/10 rounded-xl px-4 py-3 text-xs text-white/80 font-mono focus:outline-none select-all pr-12"
|
|
/>
|
|
<div className="absolute right-3 top-1/2 -translate-y-1/2 text-white/40">
|
|
<Share2 className="w-4 h-4" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="text-xs text-white/50 leading-relaxed bg-white/3 p-3 rounded-xl border border-white/5">
|
|
🔥 <span className="text-white font-semibold">Bonus:</span> Your friends also start with <span className="text-primary font-bold">50 LYTs</span> in their wallet when they sign up!
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mt-8">
|
|
<button
|
|
onClick={handleCopyReferral}
|
|
className={`w-full py-4 rounded-xl font-extrabold text-sm tracking-wider flex items-center justify-center gap-2 cursor-pointer transition-all ${
|
|
referralCopied
|
|
? "bg-accent-lime text-dark shadow-[0_0_20px_rgba(200,255,55,0.3)]"
|
|
: "bg-white/5 hover:bg-accent-orange hover:text-white text-white border border-white/10 hover:border-accent-orange"
|
|
}`}
|
|
>
|
|
{referralCopied ? (
|
|
<>
|
|
<ClipboardCheck className="w-5 h-5 animate-bounce" />
|
|
<span>Copied! +50 LYTs Added to wallet</span>
|
|
</>
|
|
) : (
|
|
<>
|
|
<span>Copy Invite Link & Earn</span>
|
|
</>
|
|
)}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|