Todos os blocos

Listing Grid

Responsive grid of property cards powered by the Garagem SDK. Supports filtering by city, neighborhood, business type, and pagination.

Instalar

npx shadcn@latest add https://sdk.garagem.site/r/listing-grid.json
Abrir no v0.dev

Dependências npm

@garagem-ai/site-sdklucide-react

Componentes shadcn (auto-instalados)

badgecard

Arquivos instalados

  • components/garagem/listing-grid.tsx
  • components/garagem/listing-card.tsx

Código fonte

listing-grid/listing-grid.tsx
import type { Listing, ListingFilters } from "@garagem-ai/site-sdk";
import { getListings } from "@garagem-ai/site-sdk";

import { cn } from "@/lib/utils";

import { ListingCard } from "../listing-card/listing-card";

export interface ListingGridProps {
  /** Garagem site ID to fetch listings from. */
  siteId: string;
  /** Filter criteria passed to `getListings`. */
  filters?: ListingFilters;
  /** Override the Garagem API base URL. */
  baseUrl?: string;
  /** Maximum items to display. Defaults to 12. */
  limit?: number;
  /** Grid column classes. Defaults to responsive 1/2/3 column grid. */
  gridClassName?: string;
  /** Pass-through className for the outer wrapper. */
  className?: string;
  /** Currency code for price formatting. Defaults to `BRL`. */
  currency?: string;
  /** BCP-47 locale for formatting. Defaults to `pt-BR`. */
  locale?: string;
  /** Custom link builder. Receives the listing and returns href. */
  getListingHref?: (listing: Listing) => string;
  /** Next.js caching hints. */
  next?: { revalidate?: number | false; tags?: string[] };
}

/**
 * Server component that fetches listings from the Garagem SDK and renders
 * them in a responsive grid of `<ListingCard>` components.
 *
 * Usage:
 * ```tsx
 * <ListingGrid siteId="my-site" filters={{ city: "São Paulo" }} />
 * ```
 */
export async function ListingGrid({
  siteId,
  filters,
  baseUrl,
  limit = 12,
  gridClassName,
  className,
  currency,
  locale,
  getListingHref,
  next,
}: ListingGridProps) {
  const { listings } = await getListings({
    siteId,
    baseUrl,
    filters: { ...filters, limit },
    next,
  });

  if (listings.length === 0) {
    return (
      <div className={cn("py-12 text-center text-muted-foreground", className)}>
        <p className="text-sm">Nenhum imóvel encontrado.</p>
      </div>
    );
  }

  return (
    <div
      className={cn(
        "grid gap-6",
        gridClassName ?? "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
        className
      )}
    >
      {listings.map((listing) => (
        <ListingCard
          key={listing.id}
          listing={listing}
          href={getListingHref?.(listing)}
          currency={currency}
          locale={locale}
        />
      ))}
    </div>
  );
}