Files
thrilltrack-explorer/src/components/manufacturers/ManufacturerCard.tsx
pac7 bf7dd93d9e Update image sources to use environment variables for dynamic image hosting
Updates image URLs across various components and pages to dynamically fetch images using Cloudflare's image hosting service, configured via environment variables. Also updates the theme provider import for Sonner toasts and modifies the Supabase upload function to use a configurable Supabase URL.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: f1469493-0a69-4efc-91bd-478d1879573a
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7cdf4e95-3f41-4180-b8e3-8ef56d032c0e/f1469493-0a69-4efc-91bd-478d1879573a/HYhVkSk
2025-10-07 14:10:00 +00:00

152 lines
6.3 KiB
TypeScript

import { Factory, MapPin, Star, Globe, FerrisWheel, Ruler, Hammer, Building2 } from 'lucide-react';
import { useNavigate } from 'react-router-dom';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Company } from '@/types/database';
interface ManufacturerCardProps {
company: Company;
}
export function ManufacturerCard({ company }: ManufacturerCardProps) {
const navigate = useNavigate();
const handleClick = () => {
const basePath = company.company_type === 'designer' ? '/designers' : '/manufacturers';
navigate(`${basePath}/${company.slug}/`);
};
const getCompanyIcon = (type: string) => {
switch (type) {
case 'manufacturer': return <Factory className="w-5 h-5" />;
case 'operator': return <FerrisWheel className="w-5 h-5" />;
case 'designer': return <Ruler className="w-5 h-5" />;
case 'contractor': return <Hammer className="w-5 h-5" />;
default: return <Building2 className="w-5 h-5" />;
}
};
const formatCompanyType = (type: string) => {
return type.split('_').map(word =>
word.charAt(0).toUpperCase() + word.slice(1)
).join(' ');
};
return (
<Card
className="group overflow-hidden border-border/50 bg-gradient-to-br from-card via-card to-card/80 hover:shadow-xl hover:shadow-primary/10 transition-all duration-300 cursor-pointer active:scale-[0.98] md:hover:scale-[1.02]"
onClick={handleClick}
>
{/* Logo/Image Section */}
<div className="aspect-video relative bg-gradient-to-br from-primary/20 via-primary/10 to-transparent overflow-hidden">
{(company.card_image_url || company.card_image_id) ? (
<img
src={company.card_image_url || `https://imagedelivery.net/${import.meta.env.VITE_CLOUDFLARE_ACCOUNT_HASH}/${company.card_image_id}/public`}
alt={company.name}
className="w-full h-full object-cover group-hover:scale-110 transition-transform duration-500"
/>
) : (
<>
<div className="absolute inset-0 bg-gradient-to-t from-background/80 via-transparent to-transparent" />
{/* Company Type Badge */}
<div className="absolute top-2 right-2 md:top-3 md:right-3 z-10">
<Badge variant="outline" className="bg-background/80 backdrop-blur-sm text-xs">
{formatCompanyType(company.company_type)}
</Badge>
</div>
{/* Logo Display */}
<div className="absolute inset-0 flex items-center justify-center">
{company.logo_url ? (
<div className="w-16 h-16 md:w-20 md:h-20 bg-background/90 rounded-xl overflow-hidden shadow-lg backdrop-blur-sm border border-border/50">
<img
src={company.logo_url}
alt={`${company.name} logo`}
className="w-full h-full object-contain p-2"
/>
</div>
) : (
<div className="w-16 h-16 md:w-20 md:h-20 bg-background/90 rounded-xl shadow-lg backdrop-blur-sm border border-border/50 flex items-center justify-center">
{getCompanyIcon(company.company_type)}
</div>
)}
</div>
</>
)}
</div>
<CardContent className="p-3 md:p-4 space-y-2 md:space-y-3">
{/* Company Name */}
<h3 className="text-base md:text-lg font-semibold group-hover:text-primary transition-colors line-clamp-2 min-h-[2.5rem] md:min-h-[3rem]">
{company.name}
</h3>
{/* Description */}
{company.description && (
<p className="text-xs md:text-sm text-muted-foreground line-clamp-2">
{company.description}
</p>
)}
{/* Company Info */}
<div className="flex flex-wrap gap-x-3 md:gap-x-4 gap-y-1 text-xs md:text-sm">
{company.founded_year && (
<div className="flex items-center gap-1">
<span className="text-muted-foreground">Founded:</span>
<span className="font-medium">{company.founded_year}</span>
</div>
)}
{company.headquarters_location && (
<div className="flex items-center gap-1 min-w-0">
<MapPin className="w-3 h-3 text-muted-foreground shrink-0" />
<span className="text-muted-foreground truncate">
{company.headquarters_location}
</span>
</div>
)}
</div>
{/* Rating */}
{company.average_rating > 0 && (
<div className="flex items-center gap-1">
<Star className="w-3.5 h-3.5 md:w-4 md:h-4 fill-yellow-400 text-yellow-400" />
<span className="text-xs md:text-sm font-medium">{company.average_rating.toFixed(1)}</span>
{company.review_count > 0 && (
<span className="text-xs text-muted-foreground">({company.review_count})</span>
)}
</div>
)}
{/* Stats Display */}
<div className="flex flex-wrap gap-x-3 md:gap-x-4 gap-y-1 text-xs md:text-sm">
{(company as any).ride_count > 0 && (
<div className="flex items-center gap-1">
<FerrisWheel className="w-3 h-3 text-muted-foreground" />
<span className="font-medium">{(company as any).ride_count}</span>
<span className="text-muted-foreground">rides</span>
</div>
)}
{(company as any).coaster_count > 0 && (
<div className="flex items-center gap-1">
<span className="text-muted-foreground"></span>
<span className="font-medium">{(company as any).coaster_count}</span>
<span className="text-muted-foreground">coasters</span>
</div>
)}
{(company as any).model_count > 0 && (
<div className="flex items-center gap-1">
<span className="text-muted-foreground"></span>
<span className="font-medium">{(company as any).model_count}</span>
<span className="text-muted-foreground">models</span>
</div>
)}
</div>
</CardContent>
</Card>
);
}