Files
Moheeb ZaraandClaude Opus 4.8 543b1d65eb refactor(settings): decompose settings-client into panels (slice 7)
663-line settings-client.tsx → a 79-line orchestrator (activeTab + shared save
status) + settings/panels/{space,integrations,dues,webhooks}-panel.tsx each
owning its own form state + types.ts. Server-action calls and fields preserved
verbatim. tsc 0, build ok.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-08-04 06:14:24 -07:00

80 lines
2.9 KiB
TypeScript

'use client'
import { useState } from 'react'
import { PageTitle } from '@/components/ui/page-title'
import { SpacePanel } from './panels/space-panel'
import { IntegrationsPanel } from './panels/integrations-panel'
import { DuesPanel } from './panels/dues-panel'
import { WebhooksPanel } from './panels/webhooks-panel'
import type { Integration, SaveMessage, Space } from './types'
// Roles, tiers, areas, invites, and onboarding moved to the dedicated
// /customize hub. This page now owns space identity, visibility,
// integrations, and webhooks only.
interface Props {
space: Space
isAdmin: boolean
integrations: Integration[]
currentRole: string
}
export default function SettingsClient({ space, isAdmin, integrations }: Props) {
const [activeTab, setActiveTab] = useState<'space' | 'integrations' | 'dues' | 'webhooks'>('space')
const [saving, setSaving] = useState(false)
const [message, setMessage] = useState<SaveMessage>(null)
return (
<div className="min-h-screen bg-background">
{/* Header */}
<div className="bg-sidebar px-4 md:px-6 py-3 flex items-center">
<PageTitle>Settings & Admin</PageTitle>
</div>
<div className="flex">
{/* Main content */}
<div className="flex-1 p-4 md:p-6">
{/* Tabs */}
<div className="bg-card border-b border-border flex gap-4 md:gap-6 px-2 mb-6 rounded-t overflow-x-auto">
{(['space', 'integrations', 'dues', 'webhooks'] as const).map(tab => (
<button
key={tab}
onClick={() => setActiveTab(tab)}
className={`font-sans text-sm py-3 border-b-2 transition capitalize whitespace-nowrap ${
activeTab === tab ? 'border-primary text-primary' : 'border-transparent text-muted-foreground hover:text-foreground'
}`}
>
{tab.charAt(0).toUpperCase() + tab.slice(1)}
</button>
))}
</div>
{message && (
<div className={`mb-4 px-4 py-2 rounded text-sm font-sans ${
message.type === 'success' ? 'bg-green-50 text-green-700 border border-green-200' : 'bg-red-50 text-red-700 border border-red-200'
}`}>
{message.text}
</div>
)}
{activeTab === 'space' && (
<SpacePanel space={space} isAdmin={isAdmin} saving={saving} setSaving={setSaving} setMessage={setMessage} />
)}
{activeTab === 'integrations' && (
<IntegrationsPanel integrations={integrations} isAdmin={isAdmin} saving={saving} setSaving={setSaving} setMessage={setMessage} />
)}
{activeTab === 'dues' && (
<DuesPanel spaceId={space.id} />
)}
{activeTab === 'webhooks' && (
<WebhooksPanel space={space} isAdmin={isAdmin} saving={saving} setSaving={setSaving} setMessage={setMessage} />
)}
</div>
</div>
</div>
)
}