Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | 1x 4x 4x 4x 4x 4x 4x | import { Link } from 'react-router-dom'
import { ArrowRight, Calendar } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { motion } from 'framer-motion'
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@core/components/ui/card'
import { useCurrencyFormatter } from '@core/hooks/useCurrencyFormatter'
import type { EventResponseDto } from '@fundraising/types'
interface PublicEventCardProps {
event: EventResponseDto
index: number
}
export const PublicEventCard = ({ event, index }: PublicEventCardProps) => {
const { t } = useTranslation('common')
const { formatCurrency } = useCurrencyFormatter()
const raised = event.raised || 0
const goal = event.goalAmount || 1
const progress = Math.min(100, Math.round((raised / goal) * 100))
return (
<motion.div
initial={{ opacity: 0, y: 50 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-100px' }}
transition={{ duration: 0.5, delay: index * 0.1 }}
>
<Link to={`/${event.slug || event.id}`} className="group block h-full">
<Card
className="h-full border-0 shadow-lg hover:shadow-2xl transition-all duration-500 overflow-hidden relative group-hover:-translate-y-2"
style={{
backgroundColor:
'hsl(var(--landing-card-glass-bg) / var(--landing-card-glass-alpha))',
borderColor:
'hsl(var(--landing-card-glass-border) / var(--landing-card-glass-border-alpha))',
}}
>
{/* Glow Effect on Hover */}
<div
className="absolute inset-0 opacity-0 group-hover:opacity-100 transition-opacity duration-500 pointer-events-none"
style={{
background:
'linear-gradient(to bottom right, hsl(var(--landing-hero-gradient-primary) / 0.1), transparent)',
}}
/>
<CardHeader className="relative z-10">
<div className="flex justify-between items-start mb-4">
<div
className={`px-3 py-1 rounded-full text-xs font-bold uppercase tracking-wider ${
event.status === 'active' || event.status === 'ACTIVE'
? 'bg-green-600 text-white dark:bg-green-500'
: 'bg-gray-200 text-gray-800 dark:bg-gray-700 dark:text-gray-200'
}`}
>
{event.status
? t(
`admin_events.status.${event.status.toLowerCase()}`,
event.status,
)
: 'DRAFT'}
</div>
<ArrowRight className="w-5 h-5 text-muted-foreground/50 group-hover:text-primary group-hover:translate-x-1 transition-all" />
</div>
<CardTitle className="text-2xl font-bold group-hover:text-primary transition-colors">
{event.name}
</CardTitle>
<CardDescription className="flex items-center gap-2 pt-2 text-base">
<Calendar className="h-4 w-4" />
{event.date
? new Date(event.date).toLocaleDateString(undefined, {
dateStyle: 'long',
})
: t('root_landing.event_card.upcoming', 'Upcoming Event')}
</CardDescription>
</CardHeader>
<CardContent className="space-y-6 relative z-10 pb-8">
<div className="space-y-3">
<div className="flex justify-between items-end">
<div className="flex flex-col">
<span className="text-sm text-muted-foreground font-medium uppercase tracking-wide">
{t('root_landing.event_card.raised', 'Raised')}
</span>
<span className="text-2xl font-bold text-foreground">
{formatCurrency(raised)}
</span>
</div>
<div className="text-right">
<span className="text-sm font-bold text-primary">
{progress}%
</span>
</div>
</div>
{/* Custom Progress Bar */}
<div className="h-3 w-full bg-secondary/20 rounded-full overflow-hidden backdrop-blur-sm">
<motion.div
initial={{ width: 0 }}
whileInView={{ width: `${progress}%` }}
transition={{ duration: 1.5, ease: 'easeOut' }}
className="h-full bg-gradient-to-r from-primary to-primary/80 relative"
>
<div className="absolute inset-0 bg-white/20 animate-pulse" />
</motion.div>
</div>
<div className="flex justify-between text-xs text-muted-foreground">
<span>
{t('root_landing.event_card.goal_of', {
amount: formatCurrency(event.goalAmount),
defaultValue: `of ${formatCurrency(event.goalAmount)} goal`,
})}
</span>
</div>
</div>
</CardContent>
</Card>
</Link>
</motion.div>
)
}
|