135 lines
4.2 KiB
TypeScript
135 lines
4.2 KiB
TypeScript
'use client';
|
|
|
|
import React, { useState } from 'react';
|
|
import { Building } from 'lucide-react';
|
|
import { Box } from '@/ui/Box';
|
|
import { Text } from '@/ui/Text';
|
|
import { Heading } from '@/ui/Heading';
|
|
import { Stack } from '@/ui/Stack';
|
|
import { Icon } from '@/ui/Icon';
|
|
import { Badge } from '@/ui/Badge';
|
|
import { SponsorshipRequestItem } from '@/ui/SponsorshipRequestItem';
|
|
|
|
export interface PendingRequestDTO {
|
|
id: string;
|
|
sponsorId: string;
|
|
sponsorName: string;
|
|
sponsorLogo?: string | undefined;
|
|
tier: string;
|
|
offeredAmount: number;
|
|
currency: string;
|
|
formattedAmount: string;
|
|
message?: string | undefined;
|
|
createdAt: string | Date;
|
|
platformFee: number;
|
|
netAmount: number;
|
|
}
|
|
|
|
interface PendingSponsorshipRequestsProps {
|
|
entityType: 'driver' | 'team' | 'race' | 'season';
|
|
entityId: string;
|
|
entityName: string;
|
|
requests: PendingRequestDTO[];
|
|
onAccept: (requestId: string) => Promise<void>;
|
|
onReject: (requestId: string, reason?: string) => Promise<void>;
|
|
isLoading?: boolean;
|
|
}
|
|
|
|
export function PendingSponsorshipRequests({
|
|
entityType,
|
|
requests,
|
|
onAccept,
|
|
onReject,
|
|
isLoading = false,
|
|
}: PendingSponsorshipRequestsProps) {
|
|
const [processingId, setProcessingId] = useState<string | null>(null);
|
|
const [rejectModalId, setRejectModalId] = useState<string | null>(null);
|
|
const [rejectReason, setRejectReason] = useState('');
|
|
|
|
const handleAccept = async (requestId: string) => {
|
|
setProcessingId(requestId);
|
|
try {
|
|
await onAccept(requestId);
|
|
} finally {
|
|
setProcessingId(null);
|
|
}
|
|
};
|
|
|
|
const handleReject = async (requestId: string) => {
|
|
setProcessingId(requestId);
|
|
try {
|
|
await onReject(requestId, rejectReason || undefined);
|
|
setRejectModalId(null);
|
|
setRejectReason('');
|
|
} finally {
|
|
setProcessingId(null);
|
|
}
|
|
};
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<Box textAlign="center" py={8}>
|
|
<Text color="text-gray-400" animate="pulse">Loading sponsorship requests...</Text>
|
|
</Box>
|
|
);
|
|
}
|
|
|
|
if (requests.length === 0) {
|
|
return (
|
|
<Box textAlign="center" py={8}>
|
|
<Box w="12" h="12" mx="auto" mb={3} rounded="full" bg="bg-iron-gray/50" display="flex" alignItems="center" justifyContent="center">
|
|
<Icon icon={Building} size={6} color="rgb(115, 115, 115)" />
|
|
</Box>
|
|
<Text color="text-gray-400" size="sm" block>No pending sponsorship requests</Text>
|
|
<Text color="text-gray-500" size="xs" mt={1} block>
|
|
When sponsors apply to sponsor this {entityType}, their requests will appear here. Sponsorships are attached to seasons, so you can change partners from season to season.
|
|
</Text>
|
|
</Box>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Stack gap={4}>
|
|
<Box display="flex" alignItems="center" justifyContent="between">
|
|
<Heading level={3}>Sponsorship Requests</Heading>
|
|
<Badge variant="primary">
|
|
{requests.length} pending
|
|
</Badge>
|
|
</Box>
|
|
|
|
<Stack gap={3}>
|
|
{requests.map((request) => (
|
|
<SponsorshipRequestItem
|
|
key={request.id}
|
|
sponsorName={request.sponsorName}
|
|
sponsorLogo={request.sponsorLogo}
|
|
tier={request.tier}
|
|
formattedAmount={request.formattedAmount}
|
|
netAmount={request.netAmount}
|
|
createdAt={typeof request.createdAt === 'string' ? new Date(request.createdAt) : request.createdAt}
|
|
message={request.message}
|
|
isProcessing={processingId === request.id}
|
|
isRejecting={rejectModalId === request.id}
|
|
rejectReason={rejectReason}
|
|
onAccept={() => handleAccept(request.id)}
|
|
onRejectClick={() => setRejectModalId(request.id)}
|
|
onRejectConfirm={() => handleReject(request.id)}
|
|
onRejectCancel={() => {
|
|
setRejectModalId(null);
|
|
setRejectReason('');
|
|
}}
|
|
onRejectReasonChange={setRejectReason}
|
|
/>
|
|
))}
|
|
</Stack>
|
|
|
|
<Box mt={4}>
|
|
<Text size="xs" color="text-gray-500" block>
|
|
<Text weight="bold" color="text-gray-400">Note:</Text> Accepting a request will activate the sponsorship.
|
|
The sponsor will be charged per season and you'll receive the payment minus 10% platform fee.
|
|
</Text>
|
|
</Box>
|
|
</Stack>
|
|
);
|
|
}
|