Carte d'annonce (Card)
type Property = {
id: string
uri: { fr: string; en?: string }
title: { fr: string; en?: string }
type: 'house' | 'apartment' | 'land' | string
offer_type: 'sale' | 'rental' | string
bedrooms: number | null
financial: { transaction: { price: { amount: number; currency: 'EUR' } } }
location: { city: string; postal_code: string }
images: { url: string; ordinal: number }[]
}
export function ListingCard({ p }: { p: Property }) {
const cover = p.images.find((img) => img.ordinal === 0) ?? p.images[0]
return (
<article className="rounded-xl border p-4">
{cover && <img src={cover.url} alt={p.title.fr} className="rounded-lg" />}
<h3 className="mt-2 font-semibold">{p.title.fr}</h3>
<p className="text-sm text-gray-600">{p.location.city} · {p.location.postal_code}</p>
<p className="text-blue-600 font-bold">
{p.financial.transaction.price.amount.toLocaleString('fr-FR')} €
</p>
</article>
)
}Bonnes pratiques
- Utiliser <Image /> de next/image pour les photos (lazy loading, srcset)
- Memoize les filtres avec useMemo
- Charger la carte interactive uniquement côté client (next/dynamic, ssr: false)
- Injecter JSON-LD RealEstateListing sur la fiche détail