MLS Sheet

The printable MLS sheet of a listing (Panda /mls/<id>/sheet, linked by the panda listing detail): Back to Listing / Print toolbar, photo + price + address header, General, Location, Rooms, Financial, Additional and…

Complete widgetClient component@pandaidx/widgets 1.14.1

Anatomy

Every piece of MLS Sheet as it nests in code. A root holds the data and state; its parts and hooks only work inside it. MlsSheetCompliance must render in every layout (MLS and consent rules).

<PandaProvider>Mounted once in app/layout.tsx
<MlsSheet />complete widget

The printable MLS sheet of a listing (Panda /mls/<id>/sheet, linked by the panda listing detail): Back to Listing / Print toolbar, photo +…

<MlsSheetRoot>Holds the data and state its parts and hooks read
<MlsSheetCompliance />required

Required: the Listing by <office> courtesy line, the feed's disclaimer and the accuracy / consumer-use notices.

<MlsSheetPrint />

Print button (window.print()), hidden when printing.

</MlsSheetRoot>
</PandaProvider>

Installation

  1. 1
    npm install <tarball or @pandaidx/widgets>
    Terminal
    npm install https://github.com/pandaidx/panda-widgets/releases/download/v1.14.1/pandaidx-widgets-1.14.1.tgz
  2. 2
    import "@pandaidx/widgets/styles.css" in app/layout.tsx
  3. 3
    Wrap the site in <PandaProvider publicKey apiUrl preset theme> (app/layout.tsx)
  4. 4
    In each page (Server Component) call the widget's server loader, then render the widget with its data
  5. 5
    Allow the images: next.config images.remotePatterns [{ protocol: "https", hostname: "**" }] (listing and blog photos come from several CDNs)

Usage

MlsSheet
// app/(print)/mls/[listingId]/sheet/page.tsx (no site chrome)
import { notFound } from "next/navigation"
import { MlsSheet } from "@pandaidx/widgets/client"
import { fetchListingSheet } from "@pandaidx/widgets/server"
export default async function ListingSheetPage({ params }: { params: Promise<{ listingId: string }> }) {
const { listingId } = await params
const data = await fetchListingSheet({ publicKey: process.env.NEXT_PUBLIC_PANDA_PUBLIC_KEY!, apiUrl: process.env.NEXT_PUBLIC_PANDA_API_URL, listingId })
if (!data) notFound()
return <MlsSheet listing={data.listing} application={data.application} />
}

Examples

Your own printable sheet from the typed data (branded header, two columns of fields, compliance at the bottom)

MlsSheet
// app/(print)/mls/[listingId]/sheet/page.tsx (Server Component, no site chrome)
import { notFound } from "next/navigation"
import { MlsSheetRoot, MlsSheetCompliance, MlsSheetPrint } from "@pandaidx/widgets/client"
import { getListingSheet } from "@pandaidx/widgets/server"
export default async function SheetPage({ params }: { params: Promise<{ listingId: string }> }) {
const { listingId } = await params
const data = await getListingSheet({ publicKey: process.env.NEXT_PUBLIC_PANDA_PUBLIC_KEY!, apiUrl: process.env.NEXT_PUBLIC_PANDA_API_URL, listingId })
if (!data) notFound()
const { sheet } = data
return (
<MlsSheetRoot className="mx-auto max-w-4xl p-8">
<header className="flex items-end justify-between border-b pb-4">
<div><h1>{sheet.address}</h1><p>{sheet.price} · MLS# {sheet.mlsNumber}</p></div>
<MlsSheetPrint />
</header>
{sheet.sections.map((section) => (
<section key={section.id} data-mls-sheet-section className="mt-6">
<h2>{section.title}</h2>
<dl className="grid grid-cols-2 gap-x-8 gap-y-1">
{section.fields.map((field) => <div key={field.key}><dt className="inline font-semibold">{field.label}: </dt><dd className="inline">{field.value}</dd></div>)}
</dl>
</section>
))}
<footer className="mt-8"><p>Prepared by {sheet.preparedBy.name}</p><MlsSheetCompliance compliance={sheet.compliance} /></footer>
</MlsSheetRoot>
)
}

API reference

MlsSheet

The printable MLS sheet of a listing (Panda /mls/<id>/sheet, linked by the panda listing detail): Back to Listing / Print toolbar, photo + price + address header, General, Location, Rooms, Financial, Additional and Remarks sections, and the "Prepared by" footer with the site logo and the MLS disclaimer. Public fields only. Render it on a page without the site header/footer.

Import from @pandaidx/widgets/client

PropTypeDefaultDescription
listing*object—Listing with the sheet fields.
application*object—Public application (prepared-by name, logo).
preset"default" | "template1"—Preset for this widget only (defaults to the provider preset).
variant"default" | "template1"—Deprecated alias of preset.
themeobject—Token overrides for this widget only, merged over the provider theme (same shape as PandaProvider.theme).

Parts

<MlsSheetCompliance />required

Required: the Listing by <office> courtesy line, the feed's disclaimer and the accuracy / consumer-use notices. Pass compliance={sheet.compliance}.

<MlsSheetPrint />

Print button (window.print()), hidden when printing. label or your own children.

Server data

Loaders run in a Server Component and come from @pandaidx/widgets/server. Typed data is for a page you design yourself, rendered inside the root.

fetchListingSheet()widget loader

Listing (GET /v1/listings/:id?view=sheet: the detail fields plus the sheet's public RESO fields) + public application; null when the listing does not exist (call notFound()). Returns ListingDetailData | null → listing, application

getListingSheet()typed data

Typed printable sheet for a page you design yourself: sheet = { title, address, price, mlsNumber, status, forSale, photo, photos, sections: [{ id, title, fields: [{ key, label, value, href? }] }], preparedBy: { name, logo, phone, email }, compliance } built from the public RESO fields (empty fields left out; the field mapping and labels live in the kernel, so a fix reaches every site) + the raw listing / application. Render it inside <MlsSheetRoot> and keep <MlsSheetCompliance compliance={sheet.compliance} />: publishing requires it. Use MlsSheet for the Panda sheet as is.