project-standalo-todo-super/app/referral/page.tsx

293 lines
15 KiB
TypeScript

"use client";
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import DarkThemeLayout from "../components/DarkThemeLayout";
import Navbar from "../components/Navbar";
interface User {
id: string;
username: string;
points: number;
referralCode: string;
}
interface Referral {
id: string;
username: string;
joinedDate: string;
pointsEarned: number;
}
interface ReferralStats {
totalReferrals: number;
totalPointsEarned: number;
referrals: Referral[];
}
export default function ReferralPage() {
const router = useRouter();
const [user, setUser] = useState<User | null>(null);
const [stats, setStats] = useState<ReferralStats | null>(null);
const [loading, setLoading] = useState(true);
const [copied, setCopied] = useState(false);
useEffect(() => {
const token = localStorage.getItem("token");
if (!token) {
router.push("/login");
return;
}
fetchData();
}, [router]);
const fetchData = async () => {
try {
const token = localStorage.getItem("token");
const headers = { Authorization: `Bearer ${token}` };
const [userRes, statsRes] = await Promise.all([
fetch("/api/users/me", { headers }),
fetch("/api/referrals", { headers })
]);
if (!userRes.ok || !statsRes.ok) {
throw new Error("Failed to fetch data");
}
const userData = await userRes.json();
const statsData = await statsRes.json();
if (userData.success && userData.data) {
setUser({
id: userData.data.id,
username: userData.data.name,
points: userData.data.pointsBalance || 0,
referralCode: userData.data.referralCode || userData.data.id.slice(0, 8),
});
}
if (statsData.success && statsData.data) {
setStats(statsData.data);
}
} catch (error) {
console.error("Error fetching data:", error);
localStorage.removeItem("token");
router.push("/login");
} finally {
setLoading(false);
}
};
const copyReferralCode = () => {
if (user) {
const referralUrl = `${window.location.origin}/register?ref=${user.referralCode}`;
navigator.clipboard.writeText(referralUrl);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
}
};
const shareToSocial = (platform: string) => {
if (!user) return;
const referralUrl = `${window.location.origin}/register?ref=${user.referralCode}`;
const text = "Join me on EarnPlay and start earning points!";
const urls: Record<string, string> = {
twitter: `https://twitter.com/intent/tweet?text=${encodeURIComponent(text)}&url=${encodeURIComponent(referralUrl)}`,
facebook: `https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(referralUrl)}`,
whatsapp: `https://wa.me/?text=${encodeURIComponent(text + " " + referralUrl)}`,
telegram: `https://t.me/share/url?url=${encodeURIComponent(referralUrl)}&text=${encodeURIComponent(text)}`
};
window.open(urls[platform], "_blank", "width=600,height=400");
};
if (loading) {
return (
<DarkThemeLayout>
<div className="flex items-center justify-center min-h-screen">
<div className="animate-spin rounded-full h-16 w-16 border-b-2 border-yellow-500"></div>
</div>
</DarkThemeLayout>
);
}
if (!user || !stats) {
return null;
}
const referralUrl = `${typeof window !== "undefined" ? window.location.origin : ""}/register?ref=${user.referralCode}`;
return (
<>
<Navbar user={user} />
<DarkThemeLayout>
<div className="space-y-8">
<div className="text-center">
<h1 className="text-4xl font-bold text-white mb-2">Referral Program</h1>
<p className="text-gray-400 text-lg">
Invite friends and earn rewards together
</p>
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div className="lg:col-span-2 space-y-6">
<div className="bg-gradient-to-br from-gray-800 to-gray-900 border-2 border-yellow-500/30 rounded-xl p-8">
<div className="flex items-center gap-3 mb-6">
<div className="w-12 h-12 bg-gradient-to-br from-yellow-400 to-orange-500 rounded-full flex items-center justify-center shadow-lg shadow-yellow-500/50">
<svg className="w-6 h-6 text-white" fill="currentColor" viewBox="0 0 20 20">
<path d="M8 9a3 3 0 100-6 3 3 0 000 6zM8 11a6 6 0 016 6H2a6 6 0 016-6zM16 7a1 1 0 10-2 0v1h-1a1 1 0 100 2h1v1a1 1 0 102 0v-1h1a1 1 0 100-2h-1V7z" />
</svg>
</div>
<h2 className="text-2xl font-bold text-white">Your Referral Code</h2>
</div>
<div className="bg-gray-900 border border-gray-700 rounded-lg p-4 mb-4">
<div className="flex items-center justify-between">
<div className="flex-1">
<p className="text-gray-400 text-xs mb-1">Referral URL</p>
<p className="text-white font-mono text-sm break-all">{referralUrl}</p>
</div>
<button
onClick={copyReferralCode}
className="ml-4 bg-gradient-to-r from-yellow-500 to-orange-500 text-white px-6 py-2 rounded-lg hover:from-yellow-600 hover:to-orange-600 transition transform hover:scale-105"
>
{copied ? "Copied!" : "Copy"}
</button>
</div>
</div>
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
<button
onClick={() => shareToSocial("twitter")}
className="bg-blue-500 hover:bg-blue-600 text-white px-4 py-3 rounded-lg transition flex items-center justify-center gap-2"
>
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
<path d="M23 3a10.9 10.9 0 01-3.14 1.53 4.48 4.48 0 00-7.86 3v1A10.66 10.66 0 013 4s-4 9 5 13a11.64 11.64 0 01-7 2c9 5 20 0 20-11.5a4.5 4.5 0 00-.08-.83A7.72 7.72 0 0023 3z" />
</svg>
Twitter
</button>
<button
onClick={() => shareToSocial("facebook")}
className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-3 rounded-lg transition flex items-center justify-center gap-2"
>
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
<path d="M18 2h-3a5 5 0 00-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 011-1h3z" />
</svg>
Facebook
</button>
<button
onClick={() => shareToSocial("whatsapp")}
className="bg-green-500 hover:bg-green-600 text-white px-4 py-3 rounded-lg transition flex items-center justify-center gap-2"
>
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
<path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z" />
</svg>
WhatsApp
</button>
<button
onClick={() => shareToSocial("telegram")}
className="bg-blue-400 hover:bg-blue-500 text-white px-4 py-3 rounded-lg transition flex items-center justify-center gap-2"
>
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
<path d="M11.944 0A12 12 0 000 12a12 12 0 0012 12 12 12 0 0012-12A12 12 0 0012 0a12 12 0 00-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 01.171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z" />
</svg>
Telegram
</button>
</div>
</div>
<div>
<h2 className="text-2xl font-bold text-white mb-4">Your Referrals</h2>
<div className="bg-gray-800 border border-gray-700 rounded-xl overflow-hidden">
{stats.referrals.length === 0 ? (
<div className="text-center py-12">
<svg className="w-16 h-16 mx-auto text-gray-600 mb-4" fill="currentColor" viewBox="0 0 20 20">
<path d="M8 9a3 3 0 100-6 3 3 0 000 6zM8 11a6 6 0 016 6H2a6 6 0 016-6zM16 7a1 1 0 10-2 0v1h-1a1 1 0 100 2h1v1a1 1 0 102 0v-1h1a1 1 0 100-2h-1V7z" />
</svg>
<p className="text-gray-400">No referrals yet</p>
<p className="text-gray-500 text-sm mt-2">Share your code to start earning!</p>
</div>
) : (
<div className="divide-y divide-gray-700">
{stats.referrals.map(referral => (
<div key={referral.id} className="p-4 hover:bg-gray-750 transition">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-full bg-gradient-to-br from-yellow-400 to-orange-500 flex items-center justify-center text-white font-bold">
{referral.username[0].toUpperCase()}
</div>
<div>
<p className="text-white font-medium">{referral.username}</p>
<p className="text-gray-400 text-sm">
Joined {new Date(referral.joinedDate).toLocaleDateString()}
</p>
</div>
</div>
<div className="text-right">
<p className="text-green-400 font-bold">+{referral.pointsEarned}</p>
<p className="text-gray-400 text-xs">points earned</p>
</div>
</div>
</div>
))}
</div>
)}
</div>
</div>
</div>
<div className="space-y-6">
<div className="bg-gray-800 border border-gray-700 rounded-xl p-6">
<h3 className="text-xl font-bold text-white mb-4">Referral Stats</h3>
<div className="space-y-4">
<div>
<p className="text-gray-400 text-sm mb-1">Total Referrals</p>
<p className="text-3xl font-bold text-white">{stats.totalReferrals}</p>
</div>
<div>
<p className="text-gray-400 text-sm mb-1">Total Points Earned</p>
<p className="text-3xl font-bold text-green-400">+{stats.totalPointsEarned}</p>
</div>
</div>
</div>
<div className="bg-gradient-to-br from-yellow-500/20 to-orange-500/20 border-2 border-yellow-500/30 rounded-xl p-6">
<h3 className="text-lg font-bold text-white mb-3">How it works</h3>
<ul className="space-y-3 text-sm text-gray-300">
<li className="flex items-start gap-2">
<svg className="w-5 h-5 text-yellow-400 mt-0.5 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
</svg>
Share your unique referral link with friends
</li>
<li className="flex items-start gap-2">
<svg className="w-5 h-5 text-yellow-400 mt-0.5 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
</svg>
They sign up using your link
</li>
<li className="flex items-start gap-2">
<svg className="w-5 h-5 text-yellow-400 mt-0.5 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
</svg>
You both earn bonus points!
</li>
<li className="flex items-start gap-2">
<svg className="w-5 h-5 text-yellow-400 mt-0.5 flex-shrink-0" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clipRule="evenodd" />
</svg>
Unlimited referrals = unlimited rewards
</li>
</ul>
</div>
</div>
</div>
</div>
</DarkThemeLayout>
</>
);
}