import { useState } from 'react' import { Link, useNavigate } from 'react-router-dom' import ContactModal from './ContactModal' import { useComparison } from '../contexts/ComparisonContext' import type { Property } from '../types/property' import HeartButton from './HeartButton' // ── Badge helpers ───────────────────────────────────────────────────────────── function isNew(createdAt: string | null): boolean { if (!createdAt) return false return Date.now() - new Date(createdAt).getTime() < 7 * 24 * 60 * 60 * 1000 } // ── Helpers ─────────────────────────────────────────────────────────────────── function formatPrice(price: string): string { return new Intl.NumberFormat('pt-BR', { style: 'currency', currency: 'BRL', minimumFractionDigits: 0, maximumFractionDigits: 0, }).format(parseFloat(price)) } // ── Icons ───────────────────────────────────────────────────────────────────── function BedIcon() { return ( ) } function BathIcon() { return ( ) } function AreaIcon() { return ( ) } function CarIcon() { return ( ) } function ChevronIcon({ dir }: { dir: 'left' | 'right' }) { return ( {dir === 'left' ? : } ) } // ── Photo carousel (fade + lazy load) ──────────────────────────────────────── interface Photo { url: string alt_text?: string } function SlideImage({ src, alt }: { src: string; alt: string }) { const [loaded, setLoaded] = useState(false) return ( <> {/* Skeleton mostrado até a imagem carregar */} {!loaded && (
)} {alt} setLoaded(true)} className={`w-full h-full object-cover transition-opacity duration-500 ${loaded ? 'opacity-100' : 'opacity-0'}`} draggable={false} /> ) } function PhotoCarousel({ photos, title, isNew: showNew, isFeatured }: { photos: Photo[] title: string isNew?: boolean isFeatured?: boolean }) { const slides = photos.length > 0 ? photos : [{ url: '/placeholder-property.jpg', alt_text: title }] const [current, setCurrent] = useState(0) function prev(e: React.MouseEvent) { e.preventDefault() e.stopPropagation() setCurrent(i => (i - 1 + slides.length) % slides.length) } function next(e: React.MouseEvent) { e.preventDefault() e.stopPropagation() setCurrent(i => (i + 1) % slides.length) } function handleKeyDown(e: React.KeyboardEvent) { if (slides.length <= 1) return if (e.key === 'ArrowLeft') setCurrent(i => (i - 1 + slides.length) % slides.length) if (e.key === 'ArrowRight') setCurrent(i => (i + 1) % slides.length) } return (
{/* Slides com fade */} {slides.map((photo, i) => (
))} {/* Status badges */}
{isFeatured && ( ⭐ Destaque )} {showNew && ( Novo )}
{/* Prev / Next — visible on mobile, hover-only on desktop */} {slides.length > 1 && ( <> )} {/* Dots — with larger touch area */} {slides.length > 1 && (
{slides.map((_, i) => ( ))}
)}
) } // ── Row card ────────────────────────────────────────────────────────────────── export default function PropertyRowCard({ property }: { property: Property }) { const isVenda = property.type === 'venda' const navigate = useNavigate() const { isInComparison, add, remove, properties: comparisonItems } = useComparison() const inComparison = isInComparison(property.id) const comparisonFull = comparisonItems.length >= 3 const [contactOpen, setContactOpen] = useState(false) const showNew = isNew(property.created_at) return (
{/* ── Carousel (top on mobile, left on desktop) ──────────────── */}
{/* Listing type badge */}
{isVenda ? 'Venda' : 'Aluguel'}
{/* Subtype badge */} {property.subtype && (
{property.subtype.name}
)} {/* Heart */}
{/* ── Overlay link (covers entire card) ──────────────────────── */} {/* ── Info (right) ─────────────────────────────────────────────── */}
navigate(`/imoveis/${property.slug}`)}> {/* Title + code */}

{property.title}

{property.code && ( #{property.code} )}
{/* Location */} {(property.city || property.neighborhood) && (

{[property.neighborhood?.name, property.city?.name].filter(Boolean).join(', ')}

)} {/* Price */}

{formatPrice(property.price)} {!isVenda && ( /mês )}

{(property.condo_fee || property.iptu_anual) && (
{property.condo_fee && parseFloat(property.condo_fee) > 0 && ( Cond. {formatPrice(property.condo_fee)}/mês )} {property.iptu_anual && parseFloat(property.iptu_anual) > 0 && ( IPTU {formatPrice(String(parseFloat(property.iptu_anual) / 12))}/mês )}
)} {/* Stats */}
{property.bedrooms} quartos {property.bathrooms} banheiros {property.area_m2} m² {property.parking_spots > 0 && ( {property.parking_spots} vaga{property.parking_spots !== 1 ? 's' : ''} )}
{/* CTAs — primary / secondary / ghost hierarchy */}
e.stopPropagation()} className="rounded-lg px-3 py-1.5 text-xs font-semibold bg-brand text-white hover:bg-accentHover transition-colors" > Ver detalhes {(!comparisonFull || inComparison) ? ( ) : ( Comparar )}
{contactOpen && ( setContactOpen(false)} /> )}
) }