← back to Stayclaim

src/app/promote/page.tsx

78 lines

import Link from 'next/link';
import type { Metadata } from 'next';
import { searchListings } from '@/lib/db';
import { BreadcrumbArchive } from '@/components/BreadcrumbArchive';
import { NodeCard } from '@/components/NodeCard';
import { FREE_FOREVER } from '@/lib/flags';
import { RetiredFeatureNotice } from '@/components/RetiredFeatureNotice';

export const runtime = 'nodejs';
export const dynamic = 'force-dynamic';

export const metadata: Metadata = {
  robots: { index: false, follow: false },
};

const SLUG_RE = /^[a-z0-9-]+$/i;
const isHttpUrl = (u: unknown): u is string =>
  typeof u === 'string' && /^https?:\/\//i.test(u.trim());

export default async function PromoteIndex() {
  if (FREE_FOREVER) {
    return (
      <RetiredFeatureNotice
        title="Promotion has been retired"
      />
    );
  }
  let recent: Awaited<ReturnType<typeof searchListings>> = [];
  try {
    recent = await searchListings({ limit: 6 });
  } catch {
    recent = [];
  }

  return (
    <>
      <div className="max-w-6xl mx-auto px-6 pt-6">
        <BreadcrumbArchive items={[{ label: 'Archive', href: '/' }, { label: 'Promote a listing' }]} />
      </div>

      <header className="max-w-6xl mx-auto px-6 py-12 border-b border-ink/10">
        <p className="text-xs uppercase tracking-[0.15em] text-ink/50 mb-2">Sponsored placements</p>
        <h1 className="font-display text-5xl md:text-6xl text-ink tracking-[-0.02em] leading-[1.02] max-w-4xl">
          Put your current listing on top of the record.
        </h1>
        <p className="mt-4 font-display italic text-xl text-ink/70 max-w-prose">
          Walled off from editorial. Logo of source (Zillow / Redfin / Airbnb). $29/mo flat.
        </p>
      </header>

      <section className="max-w-6xl mx-auto px-6 py-10">
        <h2 className="font-display text-3xl text-ink tracking-[-0.01em] mb-6">
          Pick the address you&rsquo;re promoting
        </h2>
        <p className="text-sm text-ink/60 mb-8 max-w-prose leading-relaxed">
          Choose an existing record. We&rsquo;ll verify ownership or agent representation before the placement goes
          live. If your address isn&rsquo;t in the archive yet, <Link href="/browse" className="underline-offset-2 hover:underline text-coral">submit it first</Link>.
        </p>
        <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
          {recent
            .filter(l => typeof l.slug === 'string' && SLUG_RE.test(l.slug))
            .map(l => (
              <NodeCard
                key={l.id}
                kind="address"
                href={`/promote/${encodeURIComponent(l.slug)}`}
                title={l.title}
                subtitle={l.address_line1 ?? l.city ?? undefined}
                imageUrl={isHttpUrl(l.hero_image) ? l.hero_image : undefined}
                eyebrow="Promote this address"
              />
            ))}
        </div>
      </section>
    </>
  );
}