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 | 1x 1x 14x 2x 2x 14x 14x 14x 34x 14x 14x 14x 34x 34x 34x 34x 34x 34x 34x 11x 11x 11x 11x 11x 34x 34x 34x 34x 34x 34x 34x 34x 34x 34x 34x 34x 22x 22x 77x 77x 77x 77x 22x 22x 34x 34x 34x | 'use client';
import { Check, Sparkles } from 'lucide-react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { trackEvent } from '@/lib/analytics/track';
import { formatPrice, type Currency } from '@/lib/validations/package';
import type { Package } from '@/types/database';
interface PackageListProps {
packages: Package[];
profileId: string;
}
export function PackageList({ packages, profileId }: PackageListProps) {
const handlePackageView = (packageId: string) => {
trackEvent(profileId, 'package_view', { package_id: packageId });
};
return (
<div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
{packages.map((pkg) => (
<PackageCard key={pkg.id} package={pkg} onView={() => handlePackageView(pkg.id)} />
))}
</div>
);
}
interface PackageCardProps {
package: Package;
onView: () => void;
}
function PackageCard({ package: pkg, onView }: PackageCardProps) {
// Parse features from JSON
const features: string[] = Array.isArray(pkg.features) ? (pkg.features as string[]) : [];
return (
<Card
className={`relative h-full ${pkg.is_featured ? 'border-primary' : ''}`}
onMouseEnter={onView}
>
{/* Featured Badge */}
{pkg.is_featured && (
<div className="absolute -top-3 left-1/2 -translate-x-1/2">
<span className="inline-flex items-center gap-1 rounded-full bg-primary px-3 py-1 text-xs font-medium text-primary-foreground">
<Sparkles className="h-3 w-3" />
Popular
</span>
</div>
)}
<CardHeader className={pkg.is_featured ? 'pt-8' : ''}>
<CardTitle className="text-lg">{pkg.title}</CardTitle>
{pkg.description && <p className="text-sm text-muted-foreground">{pkg.description}</p>}
</CardHeader>
<CardContent className="space-y-4">
{/* Price */}
<div>
<span className="text-3xl font-bold">
{formatPrice(pkg.price, pkg.currency as Currency)}
</span>
{pkg.duration && <span className="text-muted-foreground"> / {pkg.duration}</span>}
</div>
{/* Features */}
{features.length > 0 && (
<ul className="space-y-2">
{features.map((feature, index) => (
<li key={index} className="flex items-start gap-2 text-sm">
<Check className="mt-0.5 h-4 w-4 shrink-0 text-primary" />
<span>{feature}</span>
</li>
))}
</ul>
)}
</CardContent>
</Card>
);
}
|