feat(agency): refactor agency sidebar to make clients selectable top-level items that render a dedicated client-management view instead of using inline collapsible accordions

This commit is contained in:
2026-06-08 14:13:17 -07:00
parent 00f269822b
commit f8c73f27de

View File

@@ -346,11 +346,6 @@ function SectionHeader({ children }: { children: React.ReactNode }) {
export default function AgencyDashboard() { export default function AgencyDashboard() {
const { workspace } = useParams(); const { workspace } = useParams();
const [activeTab, setActiveTab] = useState("find_clients"); const [activeTab, setActiveTab] = useState("find_clients");
const [clientOpen, setClientOpen] = useState<string | null>("apex");
const toggleClient = (id: string) => {
setClientOpen(clientOpen === id ? null : id);
};
return ( return (
<div <div
@@ -463,108 +458,22 @@ export default function AgencyDashboard() {
<NavItem icon={Icons.FileText} label="Proposals & Contracts" /> <NavItem icon={Icons.FileText} label="Proposals & Contracts" />
<NavItem icon={Icons.Users} label="Contacts" /> <NavItem icon={Icons.Users} label="Contacts" />
<SectionHeader>Delivery (Projects)</SectionHeader> <SectionHeader>Clients</SectionHeader>
{/* Nested Client Hub: Apex Plumbing */} <div onClick={() => setActiveTab("client_apex")}>
<div style={{ marginBottom: 4 }}> <NavItem
<button icon={Icons.Folder}
onClick={() => toggleClient("apex")} label="Apex Plumbing"
style={{ active={activeTab === "client_apex"}
display: "flex", />
alignItems: "center",
justifyContent: "space-between",
width: "100%",
padding: "7px 10px",
borderRadius: 6,
background: "transparent",
color: "#1a1a1a",
fontWeight: 600,
fontSize: "13px",
border: "none",
cursor: "pointer",
}}
>
<div style={{ display: "flex", alignItems: "center", gap: 8 }}>
<Icons.Folder />
Apex Plumbing
</div>
<span
style={{
color: "#a09a90",
transform:
clientOpen === "apex" ? "rotate(180deg)" : "rotate(0deg)",
transition: "transform 0.15s",
}}
>
<Icons.ChevronDown />
</span>
</button>
{clientOpen === "apex" && (
<div
style={{
marginTop: 2,
display: "flex",
flexDirection: "column",
}}
>
<NavItem inset label="Projects (Live)" badge="1" />
<NavItem inset label="Infrastructure (Hosting)" />
<NavItem inset label="Secrets Manager" />
<NavItem inset label="Client Contacts" />
</div>
)}
</div> </div>
{/* Nested Client Hub: Barton Creek */} <div onClick={() => setActiveTab("client_barton")}>
<div style={{ marginBottom: 4 }}> <NavItem
<button icon={Icons.Folder}
onClick={() => toggleClient("barton")} label="Barton Creek HVAC"
style={{ active={activeTab === "client_barton"}
display: "flex", />
alignItems: "center",
justifyContent: "space-between",
width: "100%",
padding: "7px 10px",
borderRadius: 6,
background: "transparent",
color: "#1a1a1a",
fontWeight: 600,
fontSize: "13px",
border: "none",
cursor: "pointer",
}}
>
<div style={{ display: "flex", alignItems: "center", gap: 8 }}>
<Icons.Folder />
Barton Creek HVAC
</div>
<span
style={{
color: "#a09a90",
transform:
clientOpen === "barton" ? "rotate(180deg)" : "rotate(0deg)",
transition: "transform 0.15s",
}}
>
<Icons.ChevronDown />
</span>
</button>
{clientOpen === "barton" && (
<div
style={{
marginTop: 2,
display: "flex",
flexDirection: "column",
}}
>
<NavItem inset label="Projects (Live)" />
<NavItem inset label="Infrastructure (Hosting)" />
<NavItem inset label="Secrets Manager" />
<NavItem inset label="Client Contacts" />
</div>
)}
</div> </div>
<SectionHeader>Finance & Ops</SectionHeader> <SectionHeader>Finance & Ops</SectionHeader>
@@ -578,6 +487,183 @@ export default function AgencyDashboard() {
{/* ── MAIN CONTENT AREA ── */} {/* ── MAIN CONTENT AREA ── */}
<div style={{ flex: 1, overflowY: "auto" }}> <div style={{ flex: 1, overflowY: "auto" }}>
{activeTab === "find_clients" && <FindClientsView />} {activeTab === "find_clients" && <FindClientsView />}
{activeTab === "client_apex" && <ClientView name="Apex Plumbing" />}
{activeTab === "client_barton" && (
<ClientView name="Barton Creek HVAC" />
)}
</div>
</div>
);
}
// ── CLIENT VIEW (Projects, Infra, Secrets) ──
function ClientView({ name }: { name: string }) {
return (
<div style={{ padding: "40px 56px", maxWidth: 1100, margin: "0 auto" }}>
{/* Header */}
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "flex-start",
marginBottom: 32,
}}
>
<div>
<div
style={{
fontSize: "11px",
fontWeight: 600,
color: "#a09a90",
textTransform: "uppercase",
letterSpacing: "0.04em",
marginBottom: 6,
}}
>
Client
</div>
<h1
style={{
fontSize: "28px",
fontWeight: 600,
color: "#1a1a1a",
letterSpacing: "-0.02em",
margin: "0 0 8px",
}}
>
{name}
</h1>
<p style={{ color: "#6b6560", fontSize: "15px", margin: 0 }}>
Manage projects, infrastructure, and secrets for this client.
</p>
</div>
<button
style={{
padding: "8px 16px",
background: "var(--accent)",
color: "#fff",
borderRadius: 8,
fontWeight: 500,
fontSize: "13px",
border: "none",
cursor: "pointer",
boxShadow: "0 2px 8px var(--accent-glow)",
display: "flex",
alignItems: "center",
gap: 6,
}}
>
<span style={{ fontSize: 16, lineHeight: 0 }}>+</span> New project
</button>
</div>
{/* Tabs */}
<div
style={{
display: "flex",
gap: 24,
borderBottom: "1px solid #eae6de",
marginBottom: 24,
}}
>
{["Projects", "Infrastructure", "Secrets Vault", "Contacts"].map(
(tab, i) => (
<div
key={tab}
style={{
paddingBottom: 12,
fontSize: "14px",
fontWeight: i === 0 ? 600 : 500,
color: i === 0 ? "#1a1a1a" : "#6b6560",
borderBottom:
i === 0 ? "2px solid var(--accent)" : "2px solid transparent",
cursor: "pointer",
}}
>
{tab}
</div>
),
)}
</div>
{/* Projects Grid */}
<div style={{ display: "grid", gridTemplateColumns: "1fr", gap: 16 }}>
<div
style={{
background: "#fff",
border: "1px solid #eae6de",
borderRadius: 12,
padding: "20px 24px",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
boxShadow: "0 2px 8px rgba(0,0,0,0.02)",
}}
>
<div style={{ display: "flex", alignItems: "center", gap: 16 }}>
<div
style={{
width: 40,
height: 40,
borderRadius: 8,
background: "#f6f4f0",
display: "grid",
placeItems: "center",
color: "#1a1a1a",
fontWeight: 600,
fontSize: 16,
}}
>
{name.charAt(0)}
</div>
<div>
<h3
style={{
fontSize: "16px",
fontWeight: 600,
color: "#1a1a1a",
margin: "0 0 4px",
}}
>
Customer Portal
</h3>
<div
style={{
fontSize: "13px",
color: "#6b6560",
display: "flex",
alignItems: "center",
gap: 6,
}}
>
<span
style={{
display: "inline-block",
width: 6,
height: 6,
borderRadius: "50%",
background: "#2e7d32",
}}
/>
Live on {name.toLowerCase().replace(/[^a-z0-9]/g, "")}.vibn.app
</div>
</div>
</div>
<button
style={{
padding: "6px 12px",
border: "1px solid #eae6de",
background: "transparent",
borderRadius: 6,
fontSize: "13px",
fontWeight: 500,
color: "#1a1a1a",
cursor: "pointer",
}}
>
Open Builder
</button>
</div>
</div> </div>
</div> </div>
); );