added design
This commit is contained in:
parent
8869419e3f
commit
4785ef2aaa
4 changed files with 890 additions and 49 deletions
|
|
@ -162,3 +162,7 @@ button:focus-visible {
|
||||||
@apply bg-background text-foreground;
|
@apply bg-background text-foreground;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,569 @@
|
||||||
// src/pages/dashboard/Earnings.tsx
|
import React, { useState } from "react";
|
||||||
import ChartEarnings from "@/components/ChartEarnings";
|
import {
|
||||||
import React from "react";
|
DollarSign,
|
||||||
|
TrendingUp,
|
||||||
|
Calendar,
|
||||||
|
CreditCard,
|
||||||
|
Download,
|
||||||
|
ArrowUpRight,
|
||||||
|
ArrowDownRight,
|
||||||
|
Wallet,
|
||||||
|
Clock,
|
||||||
|
CheckCircle,
|
||||||
|
X,
|
||||||
|
AlertCircle,
|
||||||
|
} from "lucide-react";
|
||||||
|
import {
|
||||||
|
XAxis,
|
||||||
|
YAxis,
|
||||||
|
CartesianGrid,
|
||||||
|
Tooltip,
|
||||||
|
ResponsiveContainer,
|
||||||
|
Area,
|
||||||
|
AreaChart,
|
||||||
|
} from "recharts";
|
||||||
|
|
||||||
const Earnings: React.FC = () => {
|
const Earnings: React.FC = () => {
|
||||||
|
const [timeframe, setTimeframe] = useState<"7d" | "30d" | "90d" | "1y">(
|
||||||
|
"30d"
|
||||||
|
);
|
||||||
|
const [showPayoutModal, setShowPayoutModal] = useState(false);
|
||||||
|
const [payoutAmount, setPayoutAmount] = useState("890");
|
||||||
|
const [isProcessing, setIsProcessing] = useState(false);
|
||||||
|
|
||||||
|
const earningsData = [
|
||||||
|
{ date: "Sep 1", amount: 120 },
|
||||||
|
{ date: "Sep 5", amount: 180 },
|
||||||
|
{ date: "Sep 10", amount: 240 },
|
||||||
|
{ date: "Sep 15", amount: 210 },
|
||||||
|
{ date: "Sep 20", amount: 290 },
|
||||||
|
{ date: "Sep 25", amount: 350 },
|
||||||
|
{ date: "Sep 30", amount: 450 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const transactionData = [
|
||||||
|
{
|
||||||
|
type: "Commission",
|
||||||
|
amount: "$120",
|
||||||
|
date: "Sep 28, 2025",
|
||||||
|
status: "Completed",
|
||||||
|
ref: "REF-4521",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "Bonus",
|
||||||
|
amount: "$50",
|
||||||
|
date: "Sep 25, 2025",
|
||||||
|
status: "Completed",
|
||||||
|
ref: "BONUS-892",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "Commission",
|
||||||
|
amount: "$85",
|
||||||
|
date: "Sep 22, 2025",
|
||||||
|
status: "Completed",
|
||||||
|
ref: "REF-4489",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "Commission",
|
||||||
|
amount: "$95",
|
||||||
|
date: "Sep 18, 2025",
|
||||||
|
status: "Pending",
|
||||||
|
ref: "REF-4455",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "Commission",
|
||||||
|
amount: "$100",
|
||||||
|
date: "Sep 15, 2025",
|
||||||
|
status: "Completed",
|
||||||
|
ref: "REF-4421",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const stats = [
|
||||||
|
{
|
||||||
|
label: "Total Earnings",
|
||||||
|
value: "$12,450",
|
||||||
|
change: "+12.5%",
|
||||||
|
trend: "up",
|
||||||
|
icon: DollarSign,
|
||||||
|
color: "from-green-500 to-emerald-600",
|
||||||
|
bgColor: "bg-green-50",
|
||||||
|
textColor: "text-green-600",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "This Month",
|
||||||
|
value: "$2,340",
|
||||||
|
change: "+8.2%",
|
||||||
|
trend: "up",
|
||||||
|
icon: TrendingUp,
|
||||||
|
color: "from-blue-500 to-indigo-600",
|
||||||
|
bgColor: "bg-blue-50",
|
||||||
|
textColor: "text-blue-600",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Pending Payout",
|
||||||
|
value: "$450",
|
||||||
|
change: "Oct 15",
|
||||||
|
trend: "neutral",
|
||||||
|
icon: Clock,
|
||||||
|
color: "from-orange-500 to-amber-600",
|
||||||
|
bgColor: "bg-orange-50",
|
||||||
|
textColor: "text-orange-600",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Available Balance",
|
||||||
|
value: "$890",
|
||||||
|
change: "Ready now",
|
||||||
|
trend: "neutral",
|
||||||
|
icon: Wallet,
|
||||||
|
color: "from-purple-500 to-pink-600",
|
||||||
|
bgColor: "bg-purple-50",
|
||||||
|
textColor: "text-purple-600",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const handlePayoutRequest = () => {
|
||||||
|
setIsProcessing(true);
|
||||||
|
setTimeout(() => {
|
||||||
|
setIsProcessing(false);
|
||||||
|
setShowPayoutModal(false);
|
||||||
|
alert(
|
||||||
|
"Payout request submitted successfully! You'll receive confirmation via email."
|
||||||
|
);
|
||||||
|
}, 2000);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="min-h-screen bg-gray-50 p-6">
|
||||||
<h1 className="text-2xl font-semibold mb-6">Earnings</h1>
|
<div className="max-w-7xl mx-auto">
|
||||||
<div className="bg-white p-6 rounded-lg shadow">
|
{/* Header */}
|
||||||
<ChartEarnings />
|
<div className="mb-8 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
|
||||||
<div className="mt-6">
|
<div>
|
||||||
<p>
|
<h1 className="text-3xl font-bold text-gray-900 mb-2">Earnings</h1>
|
||||||
Next Payout: <strong>Oct 15, 2025</strong>
|
<p className="text-gray-600">
|
||||||
</p>
|
Track your affiliate performance and payouts
|
||||||
<p>
|
</p>
|
||||||
Estimated Amount: <strong>$450</strong>
|
</div>
|
||||||
</p>
|
<div className="flex gap-3">
|
||||||
|
<button className="px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors flex items-center gap-2">
|
||||||
|
<Download className="w-5 h-5 text-gray-600" />
|
||||||
|
Export
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => setShowPayoutModal(true)}
|
||||||
|
className="px-6 py-2 bg-gradient-to-r from-indigo-600 to-purple-600 text-white rounded-lg hover:from-indigo-700 hover:to-purple-700 transition-all shadow-md flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<CreditCard className="w-5 h-5" />
|
||||||
|
Request Payout
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Stats Grid */}
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
|
||||||
|
{stats.map((stat, idx) => (
|
||||||
|
<div
|
||||||
|
key={idx}
|
||||||
|
className="bg-white rounded-xl shadow-sm border border-gray-100 p-6 hover:shadow-md transition-shadow"
|
||||||
|
>
|
||||||
|
<div className="flex items-center justify-between mb-4">
|
||||||
|
<div
|
||||||
|
className={`${stat.bgColor} w-12 h-12 rounded-lg flex items-center justify-center`}
|
||||||
|
>
|
||||||
|
<stat.icon className={`w-6 h-6 ${stat.textColor}`} />
|
||||||
|
</div>
|
||||||
|
{stat.trend !== "neutral" && (
|
||||||
|
<div
|
||||||
|
className={`flex items-center gap-1 ${
|
||||||
|
stat.trend === "up" ? "text-green-600" : "text-red-600"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{stat.trend === "up" ? (
|
||||||
|
<ArrowUpRight className="w-4 h-4" />
|
||||||
|
) : (
|
||||||
|
<ArrowDownRight className="w-4 h-4" />
|
||||||
|
)}
|
||||||
|
<span className="text-sm font-semibold">{stat.change}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="text-3xl font-bold text-gray-900 mb-1">
|
||||||
|
{stat.value}
|
||||||
|
</div>
|
||||||
|
<div className="text-sm text-gray-600">{stat.label}</div>
|
||||||
|
{stat.trend === "neutral" && (
|
||||||
|
<div className="text-xs text-gray-500 mt-1">{stat.change}</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Next Payout Card */}
|
||||||
|
<div className="bg-gradient-to-r from-indigo-600 to-purple-600 rounded-xl p-6 mb-8 shadow-lg">
|
||||||
|
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-4">
|
||||||
|
<div className="flex items-start gap-4">
|
||||||
|
<div className="w-14 h-14 bg-white bg-opacity-20 backdrop-blur-sm rounded-xl flex items-center justify-center">
|
||||||
|
<Calendar className="w-7 h-7 text-white" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="text-indigo-100 text-sm mb-1">
|
||||||
|
Next Scheduled Payout
|
||||||
|
</div>
|
||||||
|
<div className="text-3xl font-bold text-white mb-2">
|
||||||
|
October 15, 2025
|
||||||
|
</div>
|
||||||
|
<div className="text-indigo-100 text-sm">
|
||||||
|
Your earnings will be processed automatically
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="bg-white bg-opacity-20 backdrop-blur-sm rounded-xl p-4 text-center md:text-right">
|
||||||
|
<div className="text-indigo-100 text-sm mb-1">
|
||||||
|
Estimated Amount
|
||||||
|
</div>
|
||||||
|
<div className="text-4xl font-bold text-white">$450</div>
|
||||||
|
<div className="text-indigo-100 text-xs mt-1">
|
||||||
|
+ pending approvals
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-8">
|
||||||
|
{/* Chart Section */}
|
||||||
|
<div className="lg:col-span-2 bg-white rounded-xl shadow-sm border border-gray-100 p-6">
|
||||||
|
<div className="flex items-center justify-between mb-6">
|
||||||
|
<div>
|
||||||
|
<h2 className="text-xl font-semibold text-gray-900">
|
||||||
|
Earnings Overview
|
||||||
|
</h2>
|
||||||
|
<p className="text-sm text-gray-600 mt-1">
|
||||||
|
Your performance over time
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
{(["7d", "30d", "90d", "1y"] as const).map((period) => (
|
||||||
|
<button
|
||||||
|
key={period}
|
||||||
|
onClick={() => setTimeframe(period)}
|
||||||
|
className={`px-3 py-1.5 rounded-lg text-sm font-medium transition-colors ${
|
||||||
|
timeframe === period
|
||||||
|
? "bg-indigo-600 text-white"
|
||||||
|
: "bg-gray-100 text-gray-600 hover:bg-gray-200"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{period}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ResponsiveContainer width="100%" height={300}>
|
||||||
|
<AreaChart data={earningsData}>
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="colorAmount" x1="0" y1="0" x2="0" y2="1">
|
||||||
|
<stop offset="5%" stopColor="#6366f1" stopOpacity={0.3} />
|
||||||
|
<stop offset="95%" stopColor="#6366f1" stopOpacity={0} />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<CartesianGrid strokeDasharray="3 3" stroke="#f0f0f0" />
|
||||||
|
<XAxis
|
||||||
|
dataKey="date"
|
||||||
|
stroke="#9ca3af"
|
||||||
|
style={{ fontSize: "12px" }}
|
||||||
|
/>
|
||||||
|
<YAxis stroke="#9ca3af" style={{ fontSize: "12px" }} />
|
||||||
|
<Tooltip
|
||||||
|
contentStyle={{
|
||||||
|
backgroundColor: "#fff",
|
||||||
|
border: "1px solid #e5e7eb",
|
||||||
|
borderRadius: "8px",
|
||||||
|
boxShadow: "0 4px 6px rgba(0,0,0,0.1)",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Area
|
||||||
|
type="monotone"
|
||||||
|
dataKey="amount"
|
||||||
|
stroke="#6366f1"
|
||||||
|
strokeWidth={3}
|
||||||
|
fill="url(#colorAmount)"
|
||||||
|
/>
|
||||||
|
</AreaChart>
|
||||||
|
</ResponsiveContainer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Payment Methods */}
|
||||||
|
<div className="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
|
||||||
|
<h2 className="text-xl font-semibold text-gray-900 mb-4">
|
||||||
|
Payment Method
|
||||||
|
</h2>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<div className="p-4 border-2 border-indigo-600 rounded-lg bg-indigo-50">
|
||||||
|
<div className="flex items-center gap-3 mb-2">
|
||||||
|
<div className="w-10 h-10 bg-indigo-600 rounded-lg flex items-center justify-center">
|
||||||
|
<CreditCard className="w-5 h-5 text-white" />
|
||||||
|
</div>
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="font-semibold text-gray-900">PayPal</div>
|
||||||
|
<div className="text-sm text-gray-600">
|
||||||
|
john@example.com
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<CheckCircle className="w-5 h-5 text-indigo-600" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button className="w-full p-4 border-2 border-dashed border-gray-300 rounded-lg text-gray-600 hover:border-indigo-600 hover:text-indigo-600 transition-colors font-medium">
|
||||||
|
+ Add Payment Method
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-6 pt-6 border-t border-gray-100">
|
||||||
|
<h3 className="font-semibold text-gray-900 mb-3">Quick Stats</h3>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-sm text-gray-600">
|
||||||
|
Total Transactions
|
||||||
|
</span>
|
||||||
|
<span className="font-semibold text-gray-900">142</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-sm text-gray-600">Avg. Commission</span>
|
||||||
|
<span className="font-semibold text-gray-900">$87.68</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-sm text-gray-600">Success Rate</span>
|
||||||
|
<span className="font-semibold text-green-600">98.2%</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Transaction History */}
|
||||||
|
<div className="bg-white rounded-xl shadow-sm border border-gray-100">
|
||||||
|
<div className="p-6 border-b border-gray-100">
|
||||||
|
<h2 className="text-xl font-semibold text-gray-900">
|
||||||
|
Recent Transactions
|
||||||
|
</h2>
|
||||||
|
<p className="text-sm text-gray-600 mt-1">
|
||||||
|
Your latest earnings and payouts
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="divide-y divide-gray-100">
|
||||||
|
{transactionData.map((transaction, idx) => (
|
||||||
|
<div key={idx} className="p-6 hover:bg-gray-50 transition-colors">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<div
|
||||||
|
className={`w-12 h-12 rounded-xl flex items-center justify-center ${
|
||||||
|
transaction.type === "Bonus"
|
||||||
|
? "bg-purple-100"
|
||||||
|
: "bg-green-100"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<DollarSign
|
||||||
|
className={`w-6 h-6 ${
|
||||||
|
transaction.type === "Bonus"
|
||||||
|
? "text-purple-600"
|
||||||
|
: "text-green-600"
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="font-semibold text-gray-900">
|
||||||
|
{transaction.type}
|
||||||
|
</div>
|
||||||
|
<div className="text-sm text-gray-600">
|
||||||
|
{transaction.date}
|
||||||
|
</div>
|
||||||
|
<div className="text-xs text-gray-500 mt-1">
|
||||||
|
{transaction.ref}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="text-right">
|
||||||
|
<div className="text-2xl font-bold text-gray-900">
|
||||||
|
{transaction.amount}
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
className={`inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs font-semibold mt-1 ${
|
||||||
|
transaction.status === "Completed"
|
||||||
|
? "bg-green-100 text-green-700"
|
||||||
|
: "bg-yellow-100 text-yellow-700"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{transaction.status === "Completed" ? (
|
||||||
|
<CheckCircle className="w-3 h-3" />
|
||||||
|
) : (
|
||||||
|
<Clock className="w-3 h-3" />
|
||||||
|
)}
|
||||||
|
{transaction.status}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="p-6 border-t border-gray-100 text-center">
|
||||||
|
<button className="text-indigo-600 hover:text-indigo-700 font-semibold text-sm">
|
||||||
|
View All Transactions →
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Payout Request Modal */}
|
||||||
|
{showPayoutModal && (
|
||||||
|
<div className="fixed inset-0 bg-black/20 bg-opacity-50 flex items-center justify-center z-50 p-4">
|
||||||
|
<div className="bg-white rounded-2xl shadow-2xl h-[80vh] overflow-y-auto max-w-md w-full animate-fade-in">
|
||||||
|
{/* Modal Header */}
|
||||||
|
<div className="flex items-center justify-between p-6 border-b border-gray-100">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="w-12 h-12 bg-gradient-to-br from-indigo-500 to-purple-500 rounded-xl flex items-center justify-center">
|
||||||
|
<Wallet className="w-6 h-6 text-white" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="text-xl font-bold text-gray-900">
|
||||||
|
Request Payout
|
||||||
|
</h3>
|
||||||
|
<p className="text-sm text-gray-600">
|
||||||
|
Withdraw your earnings
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={() => setShowPayoutModal(false)}
|
||||||
|
className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
|
||||||
|
>
|
||||||
|
<X className="w-5 h-5 text-gray-600" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Modal Body */}
|
||||||
|
<div className="p-6 space-y-5">
|
||||||
|
{/* Available Balance */}
|
||||||
|
<div className="bg-gradient-to-br from-green-50 to-emerald-50 border border-green-200 rounded-xl p-4">
|
||||||
|
<div className="text-sm text-green-700 mb-1">
|
||||||
|
Available Balance
|
||||||
|
</div>
|
||||||
|
<div className="text-3xl font-bold text-green-900">$890.00</div>
|
||||||
|
<div className="text-xs text-green-600 mt-1">
|
||||||
|
Ready for withdrawal
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Amount Input */}
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Withdrawal Amount
|
||||||
|
</label>
|
||||||
|
<div className="relative">
|
||||||
|
<DollarSign className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
value={payoutAmount}
|
||||||
|
onChange={(e) => setPayoutAmount(e.target.value)}
|
||||||
|
placeholder="0.00"
|
||||||
|
max="890"
|
||||||
|
className="w-full pl-10 pr-20 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-transparent outline-none text-lg font-semibold"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
onClick={() => setPayoutAmount("890")}
|
||||||
|
className="absolute right-2 top-1/2 transform -translate-y-1/2 px-3 py-1 bg-indigo-600 text-white text-sm rounded-md hover:bg-indigo-700 transition-colors"
|
||||||
|
>
|
||||||
|
Max
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-gray-500 mt-1">
|
||||||
|
Minimum withdrawal: $50.00
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Payment Method */}
|
||||||
|
<div>
|
||||||
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||||
|
Payment Method
|
||||||
|
</label>
|
||||||
|
<div className="p-4 border-2 border-indigo-600 rounded-lg bg-indigo-50">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="w-10 h-10 bg-indigo-600 rounded-lg flex items-center justify-center">
|
||||||
|
<CreditCard className="w-5 h-5 text-white" />
|
||||||
|
</div>
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="font-semibold text-gray-900">PayPal</div>
|
||||||
|
<div className="text-sm text-gray-600">
|
||||||
|
john@example.com
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<CheckCircle className="w-5 h-5 text-indigo-600" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Processing Info */}
|
||||||
|
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4 flex gap-3">
|
||||||
|
<AlertCircle className="w-5 h-5 text-blue-600 flex-shrink-0 mt-0.5" />
|
||||||
|
<div className="text-sm text-blue-700">
|
||||||
|
<p className="font-medium mb-1">Processing Time</p>
|
||||||
|
<p className="text-blue-600">
|
||||||
|
Payouts are typically processed within 24-48 hours on
|
||||||
|
business days.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Summary */}
|
||||||
|
<div className="bg-gray-50 rounded-lg p-4 space-y-2">
|
||||||
|
<div className="flex justify-between text-sm">
|
||||||
|
<span className="text-gray-600">Withdrawal Amount</span>
|
||||||
|
<span className="font-semibold text-gray-900">
|
||||||
|
${payoutAmount}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between text-sm">
|
||||||
|
<span className="text-gray-600">Processing Fee</span>
|
||||||
|
<span className="font-semibold text-gray-900">$0.00</span>
|
||||||
|
</div>
|
||||||
|
<div className="border-t border-gray-200 pt-2 flex justify-between">
|
||||||
|
<span className="font-semibold text-gray-900">
|
||||||
|
You'll Receive
|
||||||
|
</span>
|
||||||
|
<span className="text-xl font-bold text-indigo-600">
|
||||||
|
${payoutAmount}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Modal Footer */}
|
||||||
|
<div className="p-6 border-t border-gray-100 flex gap-3">
|
||||||
|
<button
|
||||||
|
onClick={() => setShowPayoutModal(false)}
|
||||||
|
className="flex-1 px-4 py-3 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors font-semibold text-gray-700"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={handlePayoutRequest}
|
||||||
|
disabled={
|
||||||
|
isProcessing ||
|
||||||
|
Number(payoutAmount) < 50 ||
|
||||||
|
Number(payoutAmount) > 890
|
||||||
|
}
|
||||||
|
className="flex-1 px-4 py-3 bg-gradient-to-r from-indigo-600 to-purple-600 text-white rounded-lg hover:from-indigo-700 hover:to-purple-700 transition-all font-semibold disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
|
||||||
|
>
|
||||||
|
{isProcessing ? (
|
||||||
|
<>
|
||||||
|
<div className="w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin"></div>
|
||||||
|
Processing...
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>Confirm Request</>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,57 +1,347 @@
|
||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
|
import {
|
||||||
|
Users,
|
||||||
|
DollarSign,
|
||||||
|
TrendingUp,
|
||||||
|
Link2,
|
||||||
|
Copy,
|
||||||
|
Search,
|
||||||
|
Filter,
|
||||||
|
Download,
|
||||||
|
Calendar,
|
||||||
|
CheckCircle,
|
||||||
|
Clock,
|
||||||
|
MoreVertical,
|
||||||
|
} from "lucide-react";
|
||||||
|
|
||||||
interface Referral {
|
interface Referral {
|
||||||
name: string;
|
name: string;
|
||||||
|
email: string;
|
||||||
date: string;
|
date: string;
|
||||||
earnings: string;
|
earnings: string;
|
||||||
status: "Active" | "Pending";
|
status: "Active" | "Pending";
|
||||||
|
signupDate: string;
|
||||||
|
totalCommission: string;
|
||||||
|
country: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const referrals: Referral[] = [
|
const referrals: Referral[] = [
|
||||||
{ name: "John Doe", date: "2025-09-20", earnings: "$50", status: "Active" },
|
{
|
||||||
|
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",
|
name: "Jane Smith",
|
||||||
|
email: "jane@example.com",
|
||||||
date: "2025-09-18",
|
date: "2025-09-18",
|
||||||
earnings: "$20",
|
earnings: "$20",
|
||||||
status: "Pending",
|
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 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 (
|
return (
|
||||||
<div>
|
<div className="min-h-screen bg-gray-50 p-6">
|
||||||
<h1 className="text-2xl font-semibold mb-6">Referrals</h1>
|
<div className="max-w-7xl mx-auto">
|
||||||
<div className="bg-white p-4 rounded-lg shadow">
|
{/* Header */}
|
||||||
<table className="w-full">
|
<div className="mb-8">
|
||||||
<thead>
|
<h1 className="text-3xl font-bold text-gray-900 mb-2">Referrals</h1>
|
||||||
<tr className="border-b text-left">
|
<p className="text-gray-600">
|
||||||
<th className="p-2">Name</th>
|
Track and manage your affiliate referrals
|
||||||
<th className="p-2">Date</th>
|
</p>
|
||||||
<th className="p-2">Earnings</th>
|
</div>
|
||||||
<th className="p-2">Status</th>
|
|
||||||
</tr>
|
{/* Stats Grid */}
|
||||||
</thead>
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
|
||||||
<tbody>
|
{stats.map((stat, idx) => (
|
||||||
{referrals.map((r, idx) => (
|
<div
|
||||||
<tr key={idx} className="border-b">
|
key={idx}
|
||||||
<td className="p-2">{r.name}</td>
|
className="bg-white rounded-xl shadow-sm border border-gray-100 p-6 hover:shadow-md transition-shadow"
|
||||||
<td className="p-2">{r.date}</td>
|
>
|
||||||
<td className="p-2">{r.earnings}</td>
|
<div className="flex items-center justify-between mb-4">
|
||||||
<td className="p-2">
|
<div
|
||||||
<span
|
className={`${stat.color} w-12 h-12 rounded-lg flex items-center justify-center`}
|
||||||
className={`px-2 py-1 rounded-full text-sm ${
|
>
|
||||||
r.status === "Active"
|
<stat.icon className="w-6 h-6 text-white" />
|
||||||
? "bg-green-100 text-green-600"
|
</div>
|
||||||
: "bg-yellow-100 text-yellow-600"
|
</div>
|
||||||
}`}
|
<div className="text-3xl font-bold text-gray-900 mb-1">
|
||||||
|
{stat.value}
|
||||||
|
</div>
|
||||||
|
<div className="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-6 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-5 h-5 text-white" />
|
||||||
|
<h3 className="text-lg font-semibold text-white">
|
||||||
|
Your Referral Link
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<p className="text-indigo-100 text-sm mb-4">
|
||||||
|
Share this link to earn commissions
|
||||||
|
</p>
|
||||||
|
<div className="flex gap-3">
|
||||||
|
<div className="flex-1 bg-white bg-opacity-20 backdrop-blur-sm rounded-lg px-4 py-3 text-white font-mono text-sm">
|
||||||
|
{referralLink}
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={handleCopy}
|
||||||
|
className="bg-white text-indigo-600 px-6 py-3 rounded-lg font-semibold hover:bg-gray-50 transition-all flex items-center gap-2 shadow-md"
|
||||||
|
>
|
||||||
|
{copied ? (
|
||||||
|
<>
|
||||||
|
<CheckCircle className="w-5 h-5" />
|
||||||
|
Copied!
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Copy className="w-5 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-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-xl font-semibold text-gray-900">
|
||||||
|
Referral List
|
||||||
|
</h2>
|
||||||
|
<div className="flex gap-3">
|
||||||
|
<div className="relative flex-1 sm:flex-initial">
|
||||||
|
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 w-5 h-5 text-gray-400" />
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Search referrals..."
|
||||||
|
value={searchTerm}
|
||||||
|
onChange={(e) => setSearchTerm(e.target.value)}
|
||||||
|
className="pl-10 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"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button className="px-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors flex items-center gap-2">
|
||||||
|
<Filter className="w-5 h-5 text-gray-600" />
|
||||||
|
<span className="hidden sm:inline">Filter</span>
|
||||||
|
</button>
|
||||||
|
<button className="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-5 h-5" />
|
||||||
|
<span className="hidden sm:inline">Export</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Table */}
|
||||||
|
<div className="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"
|
||||||
>
|
>
|
||||||
{r.status}
|
<td className="p-4">
|
||||||
</span>
|
<div className="flex items-center gap-3">
|
||||||
</td>
|
<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">
|
||||||
</tr>
|
{r.name.charAt(0)}
|
||||||
))}
|
</div>
|
||||||
</tbody>
|
<div>
|
||||||
</table>
|
<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 items-center justify-between">
|
||||||
|
<div className="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-4 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors text-sm font-medium">
|
||||||
|
Previous
|
||||||
|
</button>
|
||||||
|
<button className="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors text-sm font-medium">
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -302,7 +302,7 @@ const Signup: React.FC = () => {
|
||||||
<p className="text-gray-600 text-sm">
|
<p className="text-gray-600 text-sm">
|
||||||
Already have an account?{" "}
|
Already have an account?{" "}
|
||||||
<a
|
<a
|
||||||
href="#"
|
href="/login"
|
||||||
className="text-indigo-600 hover:text-indigo-700 font-semibold"
|
className="text-indigo-600 hover:text-indigo-700 font-semibold"
|
||||||
>
|
>
|
||||||
Sign in
|
Sign in
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue