import { createClient } from "@supabase/supabase-js";
import Header from "@/components/Header";
import Footer from "@/components/Footer";
import SidebarAdStack from "@/components/SidebarAdStack";
import ObfuscatedEmail from "@/components/ObfuscatedEmail";
export const dynamic = "force-dynamic";
export const revalidate = 600;
export const metadata = {
title: "Our team — AV Beat",
description: "Meet the AV Beat team — editorial staff plus accounts and support, covering pro AV, live production, and display tech.",
};
interface Persona {
slug: string;
name: string;
bio: string | null;
beat: string | null;
avatar_url: string | null;
}
interface OpsPersona {
id: string;
display_name: string;
role: string;
email: string | null;
phone: string | null;
extension: string | null;
avatar_url: string | null;
}
export default async function TeamPage() {
const sb = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
db: { schema: (process.env.NEXT_PUBLIC_SUPABASE_SCHEMA || "bb") as "public" },
auth: { persistSession: false },
}
);
const { data } = await sb
.from("ai_personas")
.select("slug, name, bio, beat, avatar_url")
.eq("active", true);
const raw = (data || []) as Persona[];
const team = [
...raw.filter((p) => p.slug === "ryan-salazar"),
...raw
.filter((p) => p.slug !== "ryan-salazar")
.sort((a, b) => a.name.localeCompare(b.name)),
];
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, avatar_url")
.eq("active", true)
.in("id", ["chloe", "jeff", "riley", "brian", "avery"]);
const ops = (opsData || []) as OpsPersona[];
const displayBeat = (p: Persona) =>
p.slug === "ryan-salazar" ? "Founder / Editor-in-Chief" : p.beat?.replace(/-/g, " ") ?? "";
const formatPhone = (raw: string): string => {
const digits = raw.replace(/[^0-9]/g, "");
const local = digits.startsWith("1") && digits.length === 11 ? digits.slice(1) : digits;
if (local.length !== 10) return raw;
return `(${local.slice(0, 3)}) ${local.slice(3, 6)}-${local.slice(6)}`;
};
const editorialEmail = (p: Persona): { user: string; domain: string } | null => {
if (!p.slug) return null;
return { user: p.slug.replace(/-/g, "."), domain: "avbeat.com" };
};
const splitEmail = (email: string): { user: string; domain: string } | null => {
const at = email.indexOf("@");
if (at <= 0) return null;
return { user: email.slice(0, at), domain: email.slice(at + 1) };
};
const tableWrap = "overflow-x-auto rounded-xl border border-[#1a1f2a] bg-[#0b0f17]";
const tableClass = "w-full min-w-[640px] text-sm text-left border-collapse";
const thClass =
"px-4 py-3 text-[10px] font-mono uppercase tracking-[0.14em] text-[#93C5FD] bg-[#141a25] border-b border-[#1a1f2a] whitespace-nowrap";
const tdClass = "px-4 py-4 align-top border-b border-[#1a1f2a] text-[#aab1bd]";
const trHover = "hover:bg-[#111827]/60 transition-colors";
return (
Editorial
{team.length} {team.length === 1 ? "writer" : "writers"}
| Name |
Role |
Focus |
Contact |
{team.map((p) => {
const e = editorialEmail(p);
return (
|
{p.name}
|
{(p.beat || p.slug === "ryan-salazar") && (
{displayBeat(p)}
)}
|
{p.bio ? (
{p.bio}
) : (
—
)}
|
|
);
})}
{ops.length > 0 && (
Accounts & support
{ops.length} {ops.length === 1 ? "contact" : "contacts"}
For billing, accounts receivable, vendor onboarding, sales, and
general support questions — these are the people to reach.
)}
);
}