Files
goodgo-platform/apps/web/components/khu-cong-nghiep/listing-card.tsx
Ho Ngoc Hai 5810f0be56 feat(web): add industrial compare page, listing search, and Mapbox park map
- Add interactive Mapbox map to /khu-cong-nghiep landing page with park markers and popups
- Build compare page at /khu-cong-nghiep/so-sanh with recharts RadarChart and detailed comparison table
- Build listing search page at /khu-cong-nghiep/cho-thue with filters for property type, lease type, area, and price
- Add IndustrialListing types, API client functions, and React Query hooks

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-16 12:40:35 +07:00

96 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
import { Calendar, Eye, MapPin, Ruler } from 'lucide-react';
import { Badge } from '@/components/ui/badge';
import { Card, CardContent } from '@/components/ui/card';
import {
type IndustrialListingItem,
LEASE_TYPE_LABELS,
PROPERTY_TYPE_LABELS,
} from '@/lib/khu-cong-nghiep-api';
interface ListingCardProps {
listing: IndustrialListingItem;
}
export function IndustrialListingCard({ listing }: ListingCardProps) {
const priceText = listing.priceUsdM2
? `$${listing.priceUsdM2}/${listing.pricingUnit ?? 'm²/tháng'}`
: listing.totalLeasePrice
? `$${listing.totalLeasePrice.toLocaleString()}`
: 'Liên hệ';
const leaseTermText =
listing.minLeaseYears && listing.maxLeaseYears
? `${listing.minLeaseYears}${listing.maxLeaseYears} năm`
: listing.minLeaseYears
? `Từ ${listing.minLeaseYears} năm`
: null;
return (
<Card className="group h-full transition-shadow hover:shadow-lg">
<CardContent className="p-5">
{/* Header badges */}
<div className="mb-3 flex flex-wrap items-center gap-2">
<Badge variant="secondary" className="bg-blue-100 text-blue-800">
{PROPERTY_TYPE_LABELS[listing.propertyType]}
</Badge>
<Badge variant="outline">
{LEASE_TYPE_LABELS[listing.leaseType]}
</Badge>
</div>
{/* Title */}
<h3 className="mb-2 line-clamp-2 font-semibold text-foreground group-hover:text-primary">
{listing.title}
</h3>
{/* Park location */}
<div className="mb-3 flex items-center gap-1 text-sm text-muted-foreground">
<MapPin className="h-3.5 w-3.5 shrink-0" />
<a
href={`/khu-cong-nghiep/${listing.parkSlug}`}
className="line-clamp-1 hover:text-primary hover:underline"
>
{listing.parkName}
</a>
</div>
{/* Stats grid */}
<div className="mb-3 grid grid-cols-2 gap-3">
<div className="rounded-md bg-muted p-2">
<div className="flex items-center gap-1 text-xs text-muted-foreground">
<Ruler className="h-3 w-3" />
Diện tích
</div>
<div className="font-semibold">{listing.areaM2.toLocaleString()} m²</div>
</div>
<div className="rounded-md bg-muted p-2">
<div className="text-xs text-muted-foreground">Giá thuê</div>
<div className="font-semibold text-primary">{priceText}</div>
</div>
</div>
{/* Additional info */}
<div className="flex flex-wrap items-center gap-3 text-xs text-muted-foreground">
{listing.ceilingHeightM && (
<span>Cao trần: {listing.ceilingHeightM}m</span>
)}
{leaseTermText && (
<span className="flex items-center gap-1">
<Calendar className="h-3 w-3" />
{leaseTermText}
</span>
)}
{listing.viewCount > 0 && (
<span className="flex items-center gap-1">
<Eye className="h-3 w-3" />
{listing.viewCount}
</span>
)}
</div>
</CardContent>
</Card>
);
}