← back to Stayclaim

src/components/home/FlagshipHome.tsx

236 lines

/**
 * WhoLivedThere — flagship home. Editorial, archive-first.
 * Hero: featured named historic houses with coordinates from Wikipedia.
 * Editorial rails: notable estates, recent newspaper mentions, latest permits.
 */
import Link from 'next/link';
import { unstable_cache } from 'next/cache';
import { pool } from '@/lib/db';
import { sisterSurfaces } from '@/lib/site';

export const dynamic = 'force-dynamic';

async function getFeaturedHouses(): Promise<Array<{ id: string; slug: string; title: string; description: string | null; lat: number; lon: number; source_url: string | null }>> {
  const { rows } = await pool.query(`
    SELECT DISTINCT ON (l.id) l.id, l.slug, l.title, l.description, l.latitude::float as lat, l.longitude::float as lon, pe.source_url
    FROM listing l
    LEFT JOIN place_event pe ON pe.listing_id = l.id AND pe.kind = 'named_estate'
    WHERE l.source = 'wikipedia_house' AND l.is_public = true AND l.latitude IS NOT NULL
    ORDER BY l.id, l.title
    LIMIT 12
  `);
  return rows;
}

const getCounts = unstable_cache(
  async () => {
    const { rows } = await pool.query<any>(`
      SELECT
        (SELECT count(*) FROM listing) as listings,
        (SELECT count(*) FROM permit) as permits,
        (SELECT count(*) FROM parcel) as parcels,
        (SELECT count(*) FROM place_event) as events,
        (SELECT count(*) FROM news_address_mention) as mentions
    `);
    return rows[0];
  },
  ['flagship-home-counts'],
  { revalidate: 600 },
);

async function getRecentNewspaperMentions() {
  const { rows } = await pool.query(`
    SELECT m.raw_address, m.context, n.paper_name, n.issue_date::text as issue_date, n.ia_url
    FROM news_address_mention m
    JOIN news_issue n ON n.id = m.issue_id
    WHERE m.context IS NOT NULL
    ORDER BY n.issue_date DESC NULLS LAST
    LIMIT 6
  `);
  return rows;
}

export default async function FlagshipHome() {
  const [houses, counts, mentions] = await Promise.all([
    getFeaturedHouses(),
    getCounts(),
    getRecentNewspaperMentions(),
  ]);

  return (
    <>
      {/* MASTHEAD — magazine-style typography */}
      <section className="border-b border-ink/15 bg-sand">
        <div className="max-w-7xl mx-auto px-6 py-16 md:py-24">
          <div className="flex flex-col md:flex-row items-baseline justify-between gap-6 mb-8">
            <p className="text-[10px] uppercase tracking-[0.25em] text-moss font-mono">
              ◢ The Archive · Vol. I · {new Date().getFullYear()}
            </p>
            <p className="text-[10px] uppercase tracking-[0.15em] text-ink/40 font-mono tabular-nums">
              {Number(counts?.listings ?? 0).toLocaleString()} addresses · {Number(counts?.permits ?? 0).toLocaleString()} permits · {Number(counts?.parcels ?? 0).toLocaleString()} parcels
            </p>
          </div>
          <h1 className="font-display text-[14vw] md:text-[10rem] leading-[0.85] tracking-[-0.04em] text-ink">
            Every<br/>
            <span className="italic text-moss">address</span><br/>
            has a story.
          </h1>
          <p className="mt-10 font-display italic text-2xl md:text-3xl text-ink/65 max-w-3xl leading-tight">
            Look up the full history of any house — who lived there, what was built and when, what the archives say.
          </p>

          <form action="/search" className="mt-12 flex flex-col sm:flex-row gap-3 max-w-3xl">
            <input
              type="search"
              name="q"
              placeholder="600 N Bedford Drive · Pickfair · APN 4328-018-001 · Mary Pickford"
              className="flex-1 border-2 border-ink/20 bg-white px-5 py-4 text-base font-sans focus:outline-none focus:border-moss tracking-tight"
            />
            <button type="submit" className="bg-ink text-sand px-8 py-4 text-xs uppercase tracking-[0.2em] hover:bg-moss transition font-mono">
              Search the archive
            </button>
          </form>
        </div>
      </section>

      {/* FEATURED ESTATES — editorial gallery */}
      {houses.length > 0 && (
        <section className="bg-ink text-sand py-20">
          <div className="max-w-7xl mx-auto px-6">
            <div className="flex items-baseline justify-between mb-12 flex-wrap gap-4">
              <div>
                <p className="text-[10px] uppercase tracking-[0.25em] text-coral font-mono mb-2">Featured estates</p>
                <h2 className="font-display text-5xl md:text-7xl tracking-[-0.02em] leading-[0.95]">
                  The named houses<br/>
                  <span className="italic text-coral/80">of Beverly Hills.</span>
                </h2>
              </div>
              <p className="text-sm text-sand/55 max-w-md leading-relaxed font-display italic">
                Pickfair. Greystone. Falcon Lair. Each one mapped, with the original Wikipedia article a click away.
              </p>
            </div>
            <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
              {houses.map(h => (
                <Link
                  key={h.id}
                  href={`/address/${h.slug}`}
                  className="block border border-sand/15 bg-ink/50 hover:border-coral hover:bg-ink/80 transition group p-7"
                >
                  <p className="font-mono text-[10px] uppercase tracking-[0.2em] text-coral/80 mb-3">Named estate</p>
                  <h3 className="font-display text-3xl text-sand tracking-[-0.005em] leading-tight group-hover:text-coral transition">
                    {h.title}
                  </h3>
                  {h.description && (
                    <p className="mt-3 text-sm text-sand/65 leading-relaxed">{h.description.slice(0, 140)}</p>
                  )}
                  <p className="mt-5 font-mono text-[10px] tabular-nums text-sand/40">
                    {h.lat.toFixed(4)}, {h.lon.toFixed(4)}
                  </p>
                  {h.source_url && (
                    <p className="mt-1 font-mono text-[10px] uppercase tracking-wider text-coral/70">
                      via Wikipedia ↗
                    </p>
                  )}
                </Link>
              ))}
            </div>
          </div>
        </section>
      )}

      {/* IN THE NEWSPAPER — full-OCR-text mentions */}
      {mentions.length > 0 && (
        <section className="bg-sand py-20 border-t border-ink/10">
          <div className="max-w-7xl mx-auto px-6">
            <div className="mb-10">
              <p className="text-[10px] uppercase tracking-[0.25em] text-moss font-mono mb-2">In the newspapers</p>
              <h2 className="font-display text-5xl md:text-6xl tracking-[-0.02em] leading-[0.95] text-ink">
                {Number(counts?.mentions ?? 0).toLocaleString()} address mentions<br/>
                <span className="italic text-ink/60">from 1873 onward.</span>
              </h2>
            </div>
            <div className="grid grid-cols-1 md:grid-cols-2 gap-x-12 gap-y-8">
              {mentions.map((m, i) => (
                <a
                  key={i}
                  href={/^https?:\/\//i.test(m.ia_url ?? '') ? m.ia_url : '#'}
                  target="_blank"
                  rel="noreferrer noopener"
                  className="border-l-4 border-moss pl-5 hover:border-coral transition group"
                >
                  <p className="font-mono text-[10px] uppercase tracking-[0.15em] text-ink/45">
                    {m.paper_name} · {m.issue_date}
                  </p>
                  <p className="font-display text-2xl text-ink mt-1 group-hover:text-coral transition">
                    {m.raw_address}
                  </p>
                  <p className="mt-2 text-sm italic text-ink/65 leading-relaxed">
                    &ldquo;{m.context.slice(0, 200)}{m.context.length > 200 ? '…' : ''}&rdquo;
                  </p>
                  <p className="mt-2 font-mono text-[10px] uppercase tracking-wider text-moss group-hover:text-coral">
                    view scanned page on Internet Archive ↗
                  </p>
                </a>
              ))}
            </div>
          </div>
        </section>
      )}

      {/* INDEX OF SOURCES — minimalist list */}
      <section className="bg-ink/95 text-sand py-16 border-t border-sand/10">
        <div className="max-w-7xl mx-auto px-6">
          <p className="text-[10px] uppercase tracking-[0.25em] text-coral font-mono mb-2">Backed by</p>
          <h2 className="font-display text-4xl md:text-5xl tracking-[-0.02em] mb-10">Eleven primary sources.</h2>
          <ul className="grid grid-cols-2 md:grid-cols-3 gap-x-10 gap-y-3 font-mono text-xs text-sand/70 uppercase tracking-wider">
            <li>LA County Assessor (9.6M parcels)</li>
            <li>LADBS Building Permits (1.5M)</li>
            <li>LADBS Mechanical / Electrical</li>
            <li>LA Bureau of Engineering (626K)</li>
            <li>LA Code Enforcement (839K cases)</li>
            <li>LAHD Eviction / Foreclosure</li>
            <li>Beverly Hills + Pasadena + SM</li>
            <li>WeHo Film Permits</li>
            <li>LA Active Businesses (619K)</li>
            <li>LA Historic-Cultural Monuments</li>
            <li>Internet Archive newspapers</li>
            <li>Wikipedia + UCLA archives</li>
          </ul>
          <p className="mt-12 max-w-3xl text-sm text-sand/55 leading-relaxed">
            Every fact in the archive carries its own citation. Click any &ldquo;source ↗&rdquo; link
            on any address page to view the actual government record, scanned newspaper page, or finding aid.
          </p>
          <Link href="/admin/sources" className="inline-block mt-8 text-xs uppercase tracking-[0.2em] font-mono text-coral hover:underline">
            Full source registry →
          </Link>
        </div>
      </section>

      {/* SISTER SURFACES */}
      <section className="bg-sand py-16 border-t border-ink/15">
        <div className="max-w-7xl mx-auto px-6">
          <p className="text-[10px] uppercase tracking-[0.25em] text-ink/45 font-mono mb-6">Also part of the archive</p>
          <div className="grid md:grid-cols-2 gap-6">
            {sisterSurfaces('flagship').map(s => (
              <a
                key={s.domain}
                href={`https://${s.domain}${s.primaryCta.href}`}
                className="block border-2 border-ink/15 hover:border-ink p-8 group transition bg-white/50"
              >
                <p className="font-mono text-[10px] uppercase tracking-[0.25em] text-ink/45">{s.domain}</p>
                <h3 className="font-display text-3xl text-ink mt-2 tracking-[-0.01em] group-hover:text-moss transition">
                  {s.brandName}
                </h3>
                <p className="font-display italic text-lg text-ink/65 mt-1">{s.tagline}</p>
                <p className="mt-4 font-mono text-[11px] uppercase tracking-[0.15em] text-moss">
                  {s.primaryCta.label} →
                </p>
              </a>
            ))}
          </div>
        </div>
      </section>
    </>
  );
}