← back to Professional Directory

agents/web-agent/app/doctors/[slug]/page.tsx

94 lines

// /doctors/[slug] — individual professional public profile.

const PD_API = process.env.PD_API_BASE || 'http://127.0.0.1:9874';

async function getPro(id: string) {
  try {
    const r = await fetch(`${PD_API}/professionals?limit=1&min_confidence=0`, { next: { revalidate: 300 } });
    // /professionals is filter-shaped, not single-id. Single-fetch is /professionals/:npi.
    // We'll route by NPI in the URL slug; if it's a numeric id the pd-api detail route
    // doesn't currently support single-by-id — fall back to the search endpoint.
    return null;
  } catch { return null; }
}

async function getProByNpi(npi: string) {
  try {
    const r = await fetch(`${PD_API}/professionals/${npi}`, { next: { revalidate: 300 } });
    return r.ok ? await r.json() : null;
  } catch { return null; }
}

export default async function DoctorPage({ params }: { params: { slug: string } }) {
  const slug = String(params.slug || '');
  // Slug is the NPI (10 digits) or the pro id — we support both.
  const isNpi = /^\d{10}$/.test(slug);

  let pro: any = null;
  if (isNpi) pro = await getProByNpi(slug);

  if (!pro) {
    return (
      <section className="section">
        <h2>Doctor profile coming soon</h2>
        <p style={{ color: 'var(--ink-soft)' }}>
          Public physician profiles ship in Phase 2. For now, search by name to find a practice;
          NPI-based slugs will resolve once we wire the lookup.
        </p>
        <a href="/search" className="card" style={{ display: 'inline-block', padding: '12px 22px', background: 'var(--moss)', color: '#fff', borderRadius: 999, fontWeight: 600, letterSpacing: '0.04em', textTransform: 'uppercase', fontSize: 14 }}>
          Back to search →
        </a>
      </section>
    );
  }

  return (
    <section className="section" style={{ paddingTop: 56 }}>
      <div className="eyebrow">Professional</div>
      <h2>{titleCase(pro.full_name)}{pro.title ? `, ${pro.title}` : ''}</h2>
      <p style={{ color: 'var(--ink-soft)', fontSize: 17 }}>
        {pro.primary_specialty || 'Specialty TBD'}
        {pro.medical_school ? ` · ${pro.medical_school}` : ''}
        {pro.graduation_year ? ` · Class of ${pro.graduation_year}` : ''}
      </p>

      <div className="card-grid" style={{ marginTop: 32 }}>
        <div className="card">
          <span className="badge">License</span>
          <span className="name">{pro.license_status || 'Active'}</span>
          <span className="meta">CA License #{pro.license_number || '—'} · NPI {pro.npi_number}</span>
        </div>
        <div className="card">
          <span className="badge">Specialties</span>
          <span className="name">{pro.specialties?.length || 1} on file</span>
          <span className="meta">{(pro.specialties || []).slice(0, 4).join(' · ') || pro.primary_specialty || ''}</span>
        </div>
        <div className="card">
          <span className="badge">Profile</span>
          <span className="name">{pro.claim_status === 'verified' ? '✓ Verified' : 'Unclaimed'}</span>
          <span className="meta">{pro.claim_status === 'verified' ? 'Doctor manages this page' : 'Auto-generated from public records'}</span>
        </div>
      </div>

      <section style={{ marginTop: 56 }}>
        <div className="eyebrow">Reviews</div>
        <h2 style={{ marginTop: 14 }}>Patient ratings</h2>
        <p style={{ color: 'var(--ink-soft)' }}>Phase 3 — reviews + ratings UI coming.</p>
      </section>

      <section style={{ marginTop: 56, borderTop: '1px solid var(--line)', paddingTop: 56 }}>
        <h2>Is this you?</h2>
        <p style={{ maxWidth: 580, color: 'var(--ink-soft)' }}>
          Claim this profile to respond to reviews, message patients, and edit page content.
          Verify with your NPI + practice domain email.
        </p>
        <a href={`/account/claim?npi=${pro.npi_number}`} className="card" style={{ display: 'inline-block', padding: '12px 22px', textAlign: 'center', background: 'var(--moss)', color: '#fff', borderRadius: 999, fontWeight: 600, letterSpacing: '0.04em', textTransform: 'uppercase', fontSize: 14 }}>
          Claim this profile →
        </a>
      </section>
    </section>
  );
}

function titleCase(s: string) { return String(s || '').toLowerCase().replace(/\b\w/g, c => c.toUpperCase()); }