From 0c206dbfbbce32b4dc2a8078bbc9cbb16cc194aa Mon Sep 17 00:00:00 2001 From: Matt Date: Thu, 28 May 2026 09:52:42 +0200 Subject: [PATCH] feat(admin/ui): enterprise inquiries pipeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add /enterprise page wired to /admin/enterprise/inquiries. Sales-style pipeline: pending → contacted → converted | declined, with an inline + mutation.mutate(e.target.value as EnterpriseInquiryStatus) + } + disabled={mutation.isPending} + className={`text-[10px] px-1.5 py-1 rounded border ${ + STATUS_TONE[inquiry.status] + } font-medium`} + > + {STATUSES.map((s) => ( + + ))} + + + + {new Date(inquiry.created_at).toLocaleDateString()} + + + ); +} + +function StatusToggle({ + value, + onChange, +}: { + value: StatusFilter; + onChange: (v: StatusFilter) => void; +}) { + const options: { value: StatusFilter; label: string }[] = [ + { value: "pending", label: "Pending" }, + { value: "contacted", label: "Contacted" }, + { value: "converted", label: "Converted" }, + { value: "declined", label: "Declined" }, + { value: "all", label: "All" }, + ]; + return ( +
+ {options.map((opt) => ( + + ))} +
+ ); +} + diff --git a/admin/src/components/layout/Sidebar.tsx b/admin/src/components/layout/Sidebar.tsx index 4a616acd..14084d59 100644 --- a/admin/src/components/layout/Sidebar.tsx +++ b/admin/src/components/layout/Sidebar.tsx @@ -7,6 +7,7 @@ import { NavLink } from "react-router-dom"; import { Activity, BarChart3, + Briefcase, Building2, Cloud, Cog, @@ -66,6 +67,7 @@ const GROUPS: NavGroup[] = [ { to: "/users", label: "Users", icon: Users }, { to: "/organizations", label: "Organizations", icon: Building2 }, { to: "/plans", label: "Plans & Billing", icon: CreditCard }, + { to: "/enterprise", label: "Enterprise", icon: Briefcase }, ], }, { diff --git a/admin/src/lib/api/client/admin/enterprise.ts b/admin/src/lib/api/client/admin/enterprise.ts new file mode 100644 index 00000000..4b66fe81 --- /dev/null +++ b/admin/src/lib/api/client/admin/enterprise.ts @@ -0,0 +1,41 @@ +// /admin/enterprise/inquiries — sales-pipeline triage. + +import { Request } from "@/lib/api/client"; +import type { + EnterpriseInquiry, + UpdateEnterpriseInquiryRequest, +} from "@/lib/api/models/admin"; + +export function listEnterpriseInquiries( + status?: string, + limit = 50, +): Promise<{ data: EnterpriseInquiry[] }> { + const usp = new URLSearchParams(); + if (status) usp.set("status", status); + usp.set("limit", String(limit)); + return Request({ + method: "GET", + url: `/admin/enterprise/inquiries?${usp.toString()}`, + authorization: true, + }); +} + +export function getEnterpriseInquiry(id: string): Promise { + return Request({ + method: "GET", + url: `/admin/enterprise/inquiries/${id}`, + authorization: true, + }); +} + +export function updateEnterpriseInquiry( + id: string, + body: UpdateEnterpriseInquiryRequest, +): Promise { + return Request({ + method: "PATCH", + url: `/admin/enterprise/inquiries/${id}`, + authorization: true, + data: body, + }); +} diff --git a/admin/src/lib/api/models/admin.ts b/admin/src/lib/api/models/admin.ts index 535dbf76..56f8a3d1 100644 --- a/admin/src/lib/api/models/admin.ts +++ b/admin/src/lib/api/models/admin.ts @@ -323,6 +323,35 @@ export interface ProvisioningJobCreate { }; } +// /admin/enterprise/inquiries — sales pipeline for "talk to us" +// requests submitted from the marketing site. + +export type EnterpriseInquiryStatus = + | "pending" + | "contacted" + | "converted" + | "declined"; + +export interface EnterpriseInquiry { + id: string; + company_name: string; + contact_name: string; + contact_email: string; + estimated_volume?: number | null; + team_size?: number | null; + notes: string; + status: EnterpriseInquiryStatus; + created_at: string; + processed_at?: string | null; + processed_by?: string | null; +} + +export interface UpdateEnterpriseInquiryRequest { + status?: EnterpriseInquiryStatus; + assigned_to?: string; + notes?: string; +} + // /admin/campaigns/* — platform-wide campaign admin (force-stop runaway // campaigns, inspect engagement counters per campaign). diff --git a/admin/src/main.tsx b/admin/src/main.tsx index 36ecd5e0..964e5adb 100644 --- a/admin/src/main.tsx +++ b/admin/src/main.tsx @@ -39,6 +39,7 @@ import UsersPage from "@/app/dashboard/UsersPage"; import UserDetailPage from "@/app/dashboard/UserDetailPage"; import WarmupPage from "@/app/dashboard/WarmupPage"; import CampaignsPage from "@/app/dashboard/CampaignsPage"; +import EnterprisePage from "@/app/dashboard/EnterprisePage"; import { AnalyticsPage, MailboxesPage, @@ -91,6 +92,7 @@ const router = createBrowserRouter([ { path: "plans", element: }, { path: "warmup", element: }, { path: "campaigns", element: }, + { path: "enterprise", element: }, { path: "analytics", element: }, { path: "audit", element: }, {