website refactor
This commit is contained in:
165
apps/website/ui/SponsorshipRequestItem.tsx
Normal file
165
apps/website/ui/SponsorshipRequestItem.tsx
Normal file
@@ -0,0 +1,165 @@
|
||||
|
||||
|
||||
import { Building, Check, Clock, DollarSign, MessageCircle, X } from 'lucide-react';
|
||||
import React from 'react';
|
||||
import { Badge } from './Badge';
|
||||
import { Button } from './Button';
|
||||
import { Heading } from './Heading';
|
||||
import { Icon } from './Icon';
|
||||
import { Image } from './Image';
|
||||
import { Text } from './Text';
|
||||
|
||||
interface SponsorshipRequestItemProps {
|
||||
sponsorName: string;
|
||||
sponsorLogo?: string;
|
||||
tier: string;
|
||||
formattedAmount: string;
|
||||
netAmount: number;
|
||||
createdAt: Date;
|
||||
message?: string;
|
||||
isProcessing: boolean;
|
||||
isRejecting: boolean;
|
||||
rejectReason: string;
|
||||
onAccept: () => void;
|
||||
onRejectClick: () => void;
|
||||
onRejectConfirm: () => void;
|
||||
onRejectCancel: () => void;
|
||||
onRejectReasonChange: (reason: string) => void;
|
||||
}
|
||||
|
||||
export function SponsorshipRequestItem({
|
||||
sponsorName,
|
||||
sponsorLogo,
|
||||
tier,
|
||||
formattedAmount,
|
||||
netAmount,
|
||||
createdAt,
|
||||
message,
|
||||
isProcessing,
|
||||
isRejecting,
|
||||
rejectReason,
|
||||
onAccept,
|
||||
onRejectClick,
|
||||
onRejectConfirm,
|
||||
onRejectCancel,
|
||||
onRejectReasonChange,
|
||||
}: SponsorshipRequestItemProps) {
|
||||
return (
|
||||
<Box rounded="lg" border borderColor="border-charcoal-outline" bg="bg-deep-graphite/70" p={4}>
|
||||
{/* Reject Modal */}
|
||||
{isRejecting && (
|
||||
<Box mb={4} p={4} rounded="lg" bg="bg-iron-gray/50" border borderColor="border-red-500/30">
|
||||
<Heading level={4} mb={2}>
|
||||
Reject sponsorship from {sponsorName}?
|
||||
</Heading>
|
||||
<Box
|
||||
as="textarea"
|
||||
value={rejectReason}
|
||||
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => onRejectReasonChange(e.target.value)}
|
||||
placeholder="Optional: Provide a reason for rejection..."
|
||||
rows={2}
|
||||
p={3}
|
||||
py={2}
|
||||
bg="bg-iron-gray/80"
|
||||
color="text-white"
|
||||
border
|
||||
borderColor="border-charcoal-outline"
|
||||
rounded="lg"
|
||||
fullWidth
|
||||
style={{ resize: 'none' }}
|
||||
className="text-sm placeholder:text-gray-500 focus:ring-2 focus:ring-red-500 mb-3"
|
||||
/>
|
||||
<Box display="flex" gap={2}>
|
||||
<Button variant="secondary" onClick={onRejectCancel} size="sm">
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
variant="danger"
|
||||
onClick={onRejectConfirm}
|
||||
disabled={isProcessing}
|
||||
size="sm"
|
||||
>
|
||||
{isProcessing ? 'Rejecting...' : 'Confirm Reject'}
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<Box display="flex" alignItems="start" justifyContent="between" gap={4}>
|
||||
<Box display="flex" alignItems="start" gap={3} flexGrow={1}>
|
||||
{/* Sponsor Logo */}
|
||||
<Box display="flex" h="12" w="12" alignItems="center" justifyContent="center" rounded="lg" bg="bg-iron-gray/50" flexShrink={0}>
|
||||
{sponsorLogo ? (
|
||||
<Image src={sponsorLogo} alt={sponsorName} width={32} height={32} objectFit="contain" />
|
||||
) : (
|
||||
<Icon icon={Building} size={6} color="rgb(156, 163, 175)" />
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<Box flexGrow={1} minWidth="0">
|
||||
<Box display="flex" alignItems="center" gap={2} mb={1}>
|
||||
<Heading level={4} truncate>
|
||||
{sponsorName}
|
||||
</Heading>
|
||||
<Badge variant={tier === 'main' ? 'primary' : 'default'}>
|
||||
{tier === 'main' ? 'Main Sponsor' : 'Secondary'}
|
||||
</Badge>
|
||||
</Box>
|
||||
|
||||
{/* Offer Details */}
|
||||
<Box display="flex" flexWrap="wrap" gap={3} mb={2}>
|
||||
<Box display="flex" alignItems="center" gap={1}>
|
||||
<Icon icon={DollarSign} size={3} color="rgb(16, 185, 129)" />
|
||||
<Text weight="semibold" color="text-performance-green" size="xs">{formattedAmount}</Text>
|
||||
</Box>
|
||||
<Box display="flex" alignItems="center" gap={1}>
|
||||
<Text color="text-gray-500" size="xs">Net: ${(netAmount / 100).toFixed(2)}</Text>
|
||||
</Box>
|
||||
<Box display="flex" alignItems="center" gap={1}>
|
||||
<Icon icon={Clock} size={3} color="rgb(156, 163, 175)" />
|
||||
<Text color="text-gray-500" size="xs">
|
||||
{createdAt.toLocaleDateString('en-US', {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
})}
|
||||
</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Message */}
|
||||
{message && (
|
||||
<Box display="flex" alignItems="start" gap={1.5} p={2} bg="bg-iron-gray/30" rounded>
|
||||
<Icon icon={MessageCircle} size={3} color="rgb(156, 163, 175)" flexShrink={0} mt={0.5} />
|
||||
<Text size="xs" color="text-gray-400" lineClamp={2}>{message}</Text>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{/* Actions */}
|
||||
{!isRejecting && (
|
||||
<Box display="flex" gap={2} flexShrink={0}>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={onAccept}
|
||||
disabled={isProcessing}
|
||||
size="sm"
|
||||
icon={<Icon icon={Check} size={3} />}
|
||||
>
|
||||
{isProcessing ? 'Accepting...' : 'Accept'}
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={onRejectClick}
|
||||
disabled={isProcessing}
|
||||
size="sm"
|
||||
icon={<Icon icon={X} size={3} />}
|
||||
>
|
||||
Reject
|
||||
</Button>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user