Affiliate module: fix referral approval lifecycle and settings reads
This commit is contained in:
@@ -5,6 +5,7 @@ import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Copy, CheckCircle, Activity, DollarSign, ChevronRight, Clock, Info, Wallet, CreditCard } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { formatPrice, getCurrencySettings } from '@/lib/currency';
|
||||
|
||||
// Affiliate types
|
||||
@@ -14,6 +15,16 @@ interface AffiliateProfile {
|
||||
commission_rate: number;
|
||||
custom_commission_rate: number | null;
|
||||
global_commission_rate: number;
|
||||
total_earnings: number;
|
||||
pending_earnings: number;
|
||||
}
|
||||
|
||||
interface PaginatedReferrals {
|
||||
referrals: AffiliateReferral[];
|
||||
total: number;
|
||||
page: number;
|
||||
limit: number;
|
||||
total_pages: number;
|
||||
}
|
||||
|
||||
interface AffiliateReferral {
|
||||
@@ -130,13 +141,14 @@ export default function AffiliateDashboard() {
|
||||
});
|
||||
|
||||
// Fetch referrals
|
||||
const { data: referrals, isLoading: isLoadingReferrals } = useQuery<AffiliateReferral[]>({
|
||||
const { data: referralsResponse, isLoading: isLoadingReferrals } = useQuery<PaginatedReferrals>({
|
||||
queryKey: ['affiliate-referrals'],
|
||||
queryFn: async () => {
|
||||
return await api.get<AffiliateReferral[]>('/account/affiliate/referrals');
|
||||
return await api.get<PaginatedReferrals>('/account/affiliate/referrals?limit=5');
|
||||
},
|
||||
enabled: !!profile && profile.status === 'active'
|
||||
});
|
||||
const referrals = referralsResponse?.referrals || [];
|
||||
|
||||
// Fetch payout history
|
||||
const { data: payouts = [], isLoading: isLoadingPayouts } = useQuery<AffiliatePayout[]>({
|
||||
@@ -248,11 +260,8 @@ export default function AffiliateDashboard() {
|
||||
setTimeout(() => setCopied(false), 2000);
|
||||
};
|
||||
|
||||
const approvedReferrals = (referrals || []).filter((r: any) => r.status === 'approved');
|
||||
const pendingReferrals = (referrals || []).filter((r: any) => r.status === 'pending');
|
||||
|
||||
const totalEarnings = approvedReferrals.reduce((sum: number, r: any) => sum + parseFloat(r.commission_amount), 0);
|
||||
const pendingEarnings = pendingReferrals.reduce((sum: number, r: any) => sum + parseFloat(r.commission_amount), 0);
|
||||
const totalEarnings = profile.total_earnings || 0;
|
||||
const pendingEarnings = profile.pending_earnings || 0;
|
||||
|
||||
const handleSavePayment = () => {
|
||||
if (!selectedMethod) {
|
||||
@@ -443,7 +452,17 @@ export default function AffiliateDashboard() {
|
||||
|
||||
{/* Referrals */}
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold mb-4">Recent Referrals</h3>
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h3 className="text-lg font-semibold">Recent Referrals</h3>
|
||||
{referralsResponse && referralsResponse.total > 5 && (
|
||||
<Link
|
||||
to="/my-account/affiliate/referrals"
|
||||
className="text-sm font-medium text-primary hover:opacity-80 flex items-center transition-opacity"
|
||||
>
|
||||
View All <ChevronRight className="w-4 h-4 ml-1" />
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{isLoadingReferrals ? (
|
||||
<div className="text-center py-8 text-gray-500">Loading referrals...</div>
|
||||
@@ -463,13 +482,12 @@ export default function AffiliateDashboard() {
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="font-medium text-gray-900">Order #{ref.order_id}</span>
|
||||
<span className={`inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium ${
|
||||
ref.status === 'approved'
|
||||
<span className={`inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium ${ref.status === 'approved'
|
||||
? 'bg-green-100 text-green-800'
|
||||
: ref.status === 'pending'
|
||||
? 'bg-yellow-100 text-yellow-800'
|
||||
: 'bg-red-100 text-red-800'
|
||||
}`}>
|
||||
? 'bg-yellow-100 text-yellow-800'
|
||||
: 'bg-red-100 text-red-800'
|
||||
}`}>
|
||||
{ref.status}
|
||||
</span>
|
||||
</div>
|
||||
@@ -527,11 +545,10 @@ export default function AffiliateDashboard() {
|
||||
<div key={payout.id} className="bg-white p-4 rounded-lg border">
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className={`p-2 rounded-lg ${
|
||||
payout.status === 'completed'
|
||||
<div className={`p-2 rounded-lg ${payout.status === 'completed'
|
||||
? 'bg-green-100 text-green-600'
|
||||
: 'bg-yellow-100 text-yellow-600'
|
||||
}`}>
|
||||
}`}>
|
||||
<Wallet className="w-5 h-5" />
|
||||
</div>
|
||||
<div>
|
||||
@@ -544,11 +561,10 @@ export default function AffiliateDashboard() {
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<span className={`inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium ${
|
||||
payout.status === 'completed'
|
||||
<span className={`inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium ${payout.status === 'completed'
|
||||
? 'bg-green-100 text-green-800'
|
||||
: 'bg-yellow-100 text-yellow-800'
|
||||
}`}>
|
||||
}`}>
|
||||
{payout.status}
|
||||
</span>
|
||||
<div className="text-xs text-gray-400 mt-1">
|
||||
@@ -605,11 +621,10 @@ export default function AffiliateDashboard() {
|
||||
setSelectedMethod(method);
|
||||
setPaymentFormData({});
|
||||
}}
|
||||
className={`px-4 py-2 rounded-lg border text-sm transition-colors ${
|
||||
selectedMethod === method
|
||||
className={`px-4 py-2 rounded-lg border text-sm transition-colors ${selectedMethod === method
|
||||
? 'bg-purple-100 border-purple-500 text-purple-700'
|
||||
: 'bg-white border-gray-200 hover:bg-gray-50'
|
||||
}`}
|
||||
}`}
|
||||
>
|
||||
{PAYMENT_METHOD_LABELS[method] || method}
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user