420 lines
16 KiB
TypeScript
420 lines
16 KiB
TypeScript
import React, { useState } from "react";
|
|
import {
|
|
Users,
|
|
DollarSign,
|
|
TrendingUp,
|
|
Link2,
|
|
Copy,
|
|
Search,
|
|
Filter,
|
|
Download,
|
|
Calendar,
|
|
CheckCircle,
|
|
Clock,
|
|
MoreVertical,
|
|
} from "lucide-react";
|
|
|
|
interface Referral {
|
|
name: string;
|
|
email: string;
|
|
date: string;
|
|
earnings: string;
|
|
status: "Active" | "Pending";
|
|
signupDate: string;
|
|
totalCommission: string;
|
|
country: string;
|
|
}
|
|
|
|
const referrals: Referral[] = [
|
|
{
|
|
name: "John Doe",
|
|
email: "john@example.com",
|
|
date: "2025-09-20",
|
|
earnings: "$50",
|
|
status: "Active",
|
|
signupDate: "2025-08-15",
|
|
totalCommission: "$450",
|
|
country: "United States",
|
|
},
|
|
{
|
|
name: "Jane Smith",
|
|
email: "jane@example.com",
|
|
date: "2025-09-18",
|
|
earnings: "$20",
|
|
status: "Pending",
|
|
signupDate: "2025-09-10",
|
|
totalCommission: "$20",
|
|
country: "Canada",
|
|
},
|
|
{
|
|
name: "Michael Chen",
|
|
email: "michael@example.com",
|
|
date: "2025-09-15",
|
|
earnings: "$120",
|
|
status: "Active",
|
|
signupDate: "2025-07-22",
|
|
totalCommission: "$890",
|
|
country: "Singapore",
|
|
},
|
|
{
|
|
name: "Sarah Johnson",
|
|
email: "sarah@example.com",
|
|
date: "2025-09-12",
|
|
earnings: "$85",
|
|
status: "Active",
|
|
signupDate: "2025-06-30",
|
|
totalCommission: "$1,240",
|
|
country: "United Kingdom",
|
|
},
|
|
{
|
|
name: "David Williams",
|
|
email: "david@example.com",
|
|
date: "2025-09-25",
|
|
earnings: "$15",
|
|
status: "Pending",
|
|
signupDate: "2025-09-20",
|
|
totalCommission: "$15",
|
|
country: "Australia",
|
|
},
|
|
];
|
|
|
|
const Referrals: React.FC = () => {
|
|
const [searchTerm, setSearchTerm] = useState("");
|
|
const [copied, setCopied] = useState(false);
|
|
const referralLink = "https://affiliatepro.com/ref/ABC123";
|
|
|
|
const handleCopy = () => {
|
|
navigator.clipboard.writeText(referralLink);
|
|
setCopied(true);
|
|
setTimeout(() => setCopied(false), 2000);
|
|
};
|
|
|
|
const stats = [
|
|
{
|
|
label: "Total Referrals",
|
|
value: "5",
|
|
icon: Users,
|
|
color: "bg-blue-500",
|
|
change: "+12% from last month",
|
|
},
|
|
{
|
|
label: "Active Referrals",
|
|
value: "3",
|
|
icon: CheckCircle,
|
|
color: "bg-green-500",
|
|
change: "60% conversion rate",
|
|
},
|
|
{
|
|
label: "Total Earnings",
|
|
value: "$2,615",
|
|
icon: DollarSign,
|
|
color: "bg-purple-500",
|
|
change: "+$450 this month",
|
|
},
|
|
{
|
|
label: "Avg. Per Referral",
|
|
value: "$523",
|
|
icon: TrendingUp,
|
|
color: "bg-orange-500",
|
|
change: "+18% growth",
|
|
},
|
|
];
|
|
|
|
const filteredReferrals = referrals.filter(
|
|
(r) =>
|
|
r.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
r.email.toLowerCase().includes(searchTerm.toLowerCase())
|
|
);
|
|
|
|
return (
|
|
<div className="min-h-screen bg-gray-50 p-4">
|
|
<div className="max-w-7xl mx-auto">
|
|
{/* Header */}
|
|
<div className="mb-6 sm:mb-8">
|
|
<h3 className="text-2xl sm:text-3xl font-bold text-gray-900 mb-2">
|
|
Referrals
|
|
</h3>
|
|
<p className="text-sm sm:text-base text-gray-600">
|
|
Track and manage your affiliate referrals
|
|
</p>
|
|
</div>
|
|
|
|
{/* Stats Grid */}
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 sm:gap-6 mb-6 sm:mb-8">
|
|
{stats.map((stat, idx) => (
|
|
<div
|
|
key={idx}
|
|
className="bg-white rounded-xl shadow-sm border border-gray-100 p-4 sm:p-6 hover:shadow-md transition-shadow"
|
|
>
|
|
<div className="flex items-center justify-between mb-3 sm:mb-4">
|
|
<div
|
|
className={`${stat.color} w-10 h-10 sm:w-12 sm:h-12 rounded-lg flex items-center justify-center`}
|
|
>
|
|
<stat.icon className="w-5 h-5 sm:w-6 sm:h-6 text-white" />
|
|
</div>
|
|
</div>
|
|
<div className="text-2xl sm:text-3xl font-bold text-gray-900 mb-1">
|
|
{stat.value}
|
|
</div>
|
|
<div className="text-xs sm:text-sm text-gray-600 mb-2">
|
|
{stat.label}
|
|
</div>
|
|
<div className="text-xs text-gray-500">{stat.change}</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
{/* Referral Link Section */}
|
|
<div className="bg-gradient-to-r from-indigo-600 to-purple-600 rounded-xl p-4 sm:p-6 mb-6 sm:mb-8 shadow-lg">
|
|
<div className="flex items-start justify-between">
|
|
<div className="flex-1">
|
|
<div className="flex items-center gap-2 mb-2">
|
|
<Link2 className="w-4 h-4 sm:w-5 sm:h-5 text-white" />
|
|
<h3 className="text-base sm:text-lg font-semibold text-white">
|
|
Your Referral Link
|
|
</h3>
|
|
</div>
|
|
<p className="text-indigo-100 text-xs sm:text-sm mb-3 sm:mb-4">
|
|
Share this link to earn commissions
|
|
</p>
|
|
<div className="flex flex-col sm:flex-row gap-3">
|
|
<div className="flex-1 bg-white bg-opacity-20 backdrop-blur-sm rounded-lg px-3 sm:px-4 py-2.5 sm:py-3 text-white font-mono text-xs sm:text-sm break-all">
|
|
{referralLink}
|
|
</div>
|
|
<button
|
|
onClick={handleCopy}
|
|
className="bg-white text-indigo-600 px-4 sm:px-6 py-2.5 sm:py-3 rounded-lg font-semibold hover:bg-gray-50 transition-all flex items-center justify-center gap-2 shadow-md text-sm sm:text-base"
|
|
>
|
|
{copied ? (
|
|
<>
|
|
<CheckCircle className="w-4 h-4 sm:w-5 sm:h-5" />
|
|
Copied!
|
|
</>
|
|
) : (
|
|
<>
|
|
<Copy className="w-4 h-4 sm:w-5 sm:h-5" />
|
|
Copy Link
|
|
</>
|
|
)}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Table Section */}
|
|
<div className="bg-white rounded-xl shadow-sm border border-gray-100">
|
|
{/* Table Header */}
|
|
<div className="p-4 sm:p-6 border-b border-gray-100">
|
|
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
|
|
<h2 className="text-lg sm:text-xl font-semibold text-gray-900">
|
|
Referral List
|
|
</h2>
|
|
<div className="flex gap-2 sm:gap-3">
|
|
<div className="relative flex-1 sm:flex-initial">
|
|
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 sm:w-5 sm:h-5 text-gray-400" />
|
|
<input
|
|
type="text"
|
|
placeholder="Search..."
|
|
value={searchTerm}
|
|
onChange={(e) => setSearchTerm(e.target.value)}
|
|
className="pl-9 sm:pl-10 pr-3 sm:pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent outline-none w-full sm:w-64 text-sm"
|
|
/>
|
|
</div>
|
|
<button className="px-3 sm:px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors flex items-center gap-2">
|
|
<Filter className="w-4 h-4 sm:w-5 sm:h-5 text-gray-600" />
|
|
<span className="hidden sm:inline text-sm">Filter</span>
|
|
</button>
|
|
<button className="px-3 sm:px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors flex items-center gap-2">
|
|
<Download className="w-4 h-4 sm:w-5 sm:h-5" />
|
|
<span className="hidden sm:inline text-sm">Export</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Mobile Card View */}
|
|
<div className="block lg:hidden">
|
|
{filteredReferrals.map((r, idx) => (
|
|
<div
|
|
key={idx}
|
|
className="p-4 border-b border-gray-100 hover:bg-gray-50 transition-colors"
|
|
>
|
|
<div className="flex items-start justify-between mb-3">
|
|
<div className="flex items-center gap-3">
|
|
<div className="w-10 h-10 rounded-full bg-gradient-to-br from-indigo-500 to-purple-500 flex items-center justify-center text-white font-semibold text-sm">
|
|
{r.name.charAt(0)}
|
|
</div>
|
|
<div>
|
|
<div className="font-semibold text-gray-900 text-sm">
|
|
{r.name}
|
|
</div>
|
|
<div className="text-xs text-gray-500">{r.email}</div>
|
|
</div>
|
|
</div>
|
|
<span
|
|
className={`inline-flex items-center gap-1 px-2.5 py-1 rounded-full text-xs font-semibold ${
|
|
r.status === "Active"
|
|
? "bg-green-100 text-green-700"
|
|
: "bg-yellow-100 text-yellow-700"
|
|
}`}
|
|
>
|
|
{r.status === "Active" ? (
|
|
<CheckCircle className="w-3 h-3" />
|
|
) : (
|
|
<Clock className="w-3 h-3" />
|
|
)}
|
|
{r.status}
|
|
</span>
|
|
</div>
|
|
<div className="grid grid-cols-2 gap-3 text-sm">
|
|
<div>
|
|
<div className="text-xs text-gray-500 mb-1">
|
|
Signup Date
|
|
</div>
|
|
<div className="text-gray-700">{r.signupDate}</div>
|
|
</div>
|
|
<div>
|
|
<div className="text-xs text-gray-500 mb-1">Country</div>
|
|
<div className="text-gray-700">{r.country}</div>
|
|
</div>
|
|
<div>
|
|
<div className="text-xs text-gray-500 mb-1">
|
|
Last Earning
|
|
</div>
|
|
<div className="font-semibold text-gray-900">
|
|
{r.earnings}
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div className="text-xs text-gray-500 mb-1">
|
|
Total Commission
|
|
</div>
|
|
<div className="font-semibold text-gray-900">
|
|
{r.totalCommission}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
{/* Desktop Table View */}
|
|
<div className="hidden lg:block overflow-x-auto">
|
|
<table className="w-full">
|
|
<thead className="bg-gray-50 border-b border-gray-100">
|
|
<tr>
|
|
<th className="text-left p-4 text-sm font-semibold text-gray-700">
|
|
Referral
|
|
</th>
|
|
<th className="text-left p-4 text-sm font-semibold text-gray-700">
|
|
Signup Date
|
|
</th>
|
|
<th className="text-left p-4 text-sm font-semibold text-gray-700">
|
|
Country
|
|
</th>
|
|
<th className="text-left p-4 text-sm font-semibold text-gray-700">
|
|
Last Earnings
|
|
</th>
|
|
<th className="text-left p-4 text-sm font-semibold text-gray-700">
|
|
Total Commission
|
|
</th>
|
|
<th className="text-left p-4 text-sm font-semibold text-gray-700">
|
|
Status
|
|
</th>
|
|
<th className="text-left p-4 text-sm font-semibold text-gray-700"></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{filteredReferrals.map((r, idx) => (
|
|
<tr
|
|
key={idx}
|
|
className="border-b border-gray-100 hover:bg-gray-50 transition-colors"
|
|
>
|
|
<td className="p-4">
|
|
<div className="flex items-center gap-3">
|
|
<div className="w-10 h-10 rounded-full bg-gradient-to-br from-indigo-500 to-purple-500 flex items-center justify-center text-white font-semibold">
|
|
{r.name.charAt(0)}
|
|
</div>
|
|
<div>
|
|
<div className="font-semibold text-gray-900">
|
|
{r.name}
|
|
</div>
|
|
<div className="text-sm text-gray-500">{r.email}</div>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td className="p-4">
|
|
<div className="flex items-center gap-2 text-gray-700">
|
|
<Calendar className="w-4 h-4 text-gray-400" />
|
|
<span className="text-sm">{r.signupDate}</span>
|
|
</div>
|
|
</td>
|
|
<td className="p-4">
|
|
<span className="text-sm text-gray-700">{r.country}</span>
|
|
</td>
|
|
<td className="p-4">
|
|
<div className="flex items-center gap-1">
|
|
<DollarSign className="w-4 h-4 text-green-600" />
|
|
<span className="font-semibold text-gray-900">
|
|
{r.earnings}
|
|
</span>
|
|
</div>
|
|
<div className="text-xs text-gray-500">{r.date}</div>
|
|
</td>
|
|
<td className="p-4">
|
|
<span className="font-semibold text-gray-900">
|
|
{r.totalCommission}
|
|
</span>
|
|
</td>
|
|
<td className="p-4">
|
|
<span
|
|
className={`inline-flex items-center gap-1 px-3 py-1 rounded-full text-xs font-semibold ${
|
|
r.status === "Active"
|
|
? "bg-green-100 text-green-700"
|
|
: "bg-yellow-100 text-yellow-700"
|
|
}`}
|
|
>
|
|
{r.status === "Active" ? (
|
|
<CheckCircle className="w-3 h-3" />
|
|
) : (
|
|
<Clock className="w-3 h-3" />
|
|
)}
|
|
{r.status}
|
|
</span>
|
|
</td>
|
|
<td className="p-4">
|
|
<button className="p-2 hover:bg-gray-100 rounded-lg transition-colors">
|
|
<MoreVertical className="w-5 h-5 text-gray-400" />
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
{/* Table Footer */}
|
|
<div className="p-4 border-t border-gray-100 flex flex-col sm:flex-row items-center justify-between gap-4">
|
|
<div className="text-xs sm:text-sm text-gray-600">
|
|
Showing{" "}
|
|
<span className="font-semibold">{filteredReferrals.length}</span>{" "}
|
|
of <span className="font-semibold">{referrals.length}</span>{" "}
|
|
referrals
|
|
</div>
|
|
<div className="flex gap-2">
|
|
<button className="px-3 sm:px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors text-xs sm:text-sm font-medium">
|
|
Previous
|
|
</button>
|
|
<button className="px-3 sm:px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors text-xs sm:text-sm font-medium">
|
|
Next
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Referrals;
|