team page: add Accounts & Support section with Chloe + Riley

Pulls from pulsedesk.personas (ops staff) and renders them as a second
section below the editorial team. Shows role, email, phone + ext.
Filtered to the company-wide RMP roles only (Chloe Delgado / Accounting,
Riley Park / Support) — not property-specific personas. Avatars fall
back to initials block until proper photos are added.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ryan Salazar
2026-05-28 14:11:54 +00:00
parent ed764b1bbe
commit 73b599f8be

View File

@@ -7,8 +7,8 @@ export const dynamic = "force-dynamic";
export const revalidate = 600;
export const metadata = {
title: "Editorial team — Broadcast Beat",
description: "Meet the Broadcast Beat editorial team — staff journalists covering broadcast, streaming, and post-production beats.",
title: "Our team — Broadcast Beat",
description: "Meet the Broadcast Beat team — editorial staff plus accounts and support, covering broadcast, streaming, and post-production.",
};
interface Persona {
@@ -19,6 +19,15 @@ interface Persona {
avatar_url: string | null;
}
interface OpsPersona {
id: string;
display_name: string;
role: string;
email: string | null;
phone: string | null;
extension: string | null;
}
export default async function TeamPage() {
const sb = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
@@ -41,9 +50,31 @@ export default async function TeamPage() {
.sort((a, b) => a.name.localeCompare(b.name)),
];
// Operations staff — pulsedesk personas (accounts receivable, support).
// Only the company-wide RMP roles, not property-specific auto-attendants.
const sbOps = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{ db: { schema: "pulsedesk" as "public" }, auth: { persistSession: false } }
);
const { data: opsData } = await sbOps
.from("personas")
.select("id, display_name, role, email, phone, extension")
.eq("active", true)
.in("id", ["chloe", "riley"]);
const ops = (opsData || []) as OpsPersona[];
const displayBeat = (p: Persona) =>
p.slug === "ryan-salazar" ? "FOUNDER / EDITOR-IN-CHIEF" : p.beat?.replace(/-/g, " ");
const initials = (name: string) =>
name
.split(" ")
.filter(Boolean)
.slice(0, 2)
.map((w) => w.charAt(0).toUpperCase())
.join("");
return (
<div className="min-h-screen bg-background">
<Header />
@@ -84,6 +115,46 @@ export default async function TeamPage() {
</li>
))}
</ul>
{ops.length > 0 && (
<>
<header className="mt-12 mb-6 border-b border-[#252525] pb-4">
<h2 className="font-serif text-2xl md:text-3xl font-bold tracking-tight">Accounts &amp; support</h2>
<p className="mt-2 text-[#9ca3af] text-sm">
For billing, accounts receivable, vendor onboarding, and general support questions these are the people to reach.
</p>
</header>
<ul className="grid grid-cols-1 md:grid-cols-2 gap-5">
{ops.map((p) => (
<li key={p.id} className="rounded border border-[#252525] bg-[#0b0f17] p-5 flex gap-4 hover:border-[var(--color-text-info,#60a5fa)]/60 transition-colors">
<div className="w-16 h-16 rounded-full border border-[#252525] flex-shrink-0 bg-[#1a1a1a] flex items-center justify-center font-serif font-bold text-xl text-[#60a5fa]">
{initials(p.display_name)}
</div>
<div className="flex-1 min-w-0">
<h3 className="font-serif text-lg font-semibold">{p.display_name}</h3>
<div className="text-[10px] font-mono uppercase tracking-wider text-[var(--color-text-info,#60a5fa)] mt-0.5">
{p.role}
</div>
<div className="text-xs text-[#9ca3af] mt-2 space-y-0.5">
{p.email && (
<div>
<a href={`mailto:${p.email}`} className="hover:text-[#60a5fa]">{p.email}</a>
</div>
)}
{p.phone && (
<div>
<a href={`tel:${p.phone.replace(/[^\d+]/g, '')}`} className="hover:text-[#60a5fa]">
{p.phone}{p.extension ? ` ext. ${p.extension}` : ''}
</a>
</div>
)}
</div>
</div>
</li>
))}
</ul>
</>
)}
</main>
<aside className="mt-10 lg:mt-0" aria-label="Advertisements">