Files
hackerspace.sh/app/(app)/settings/page.tsx
T
Moheeb Zara 1f61029f32 feat(billing): P1f Stripe UI — admin config panel + member dues card
Settings: StripeBillingPanel (admin) — mode, publishable key, write-only
secret/webhook secret, per-tier price ids, grace days; shows the
per-space webhook URL + which events to subscribe + Portal-activation
reminder. /me: DuesCard — status from getMyBilling, 'Pay dues'
(startDuesCheckout redirect) when not active, 'Manage billing'
(startBillingPortal) when a customer exists. Self-contained client
components; settings page composes the panel after SettingsClient.
2026-05-17 03:38:00 -07:00

40 lines
1.3 KiB
TypeScript

import { createClient } from '@/lib/supabase/server'
import SettingsClient from './settings-client'
import { StripeBillingPanel } from '@/components/settings/stripe-billing-panel'
import { redirect } from 'next/navigation'
export default async function SettingsPage() {
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) redirect('/login')
const { data: member } = await supabase
.from('space_members').select('space_id, role').eq('user_id', user.id).in('status', ['current', 'unverified', 'late']).single()
if (!member) redirect('/login')
// Settings is admin-only. Gate on the server BEFORE fetching space config
// and integration state so non-admins never receive it. Board/treasurer
// use /customize for the things they can change.
const isAdmin = member.role === 'admin'
if (!isAdmin) redirect('/dashboard')
const { data: space } = await supabase
.from('spaces').select('*').eq('id', member.space_id).single()
const { data: integrations } = await supabase
.from('integrations').select('*').eq('space_id', member.space_id)
return (
<>
<SettingsClient
space={space}
isAdmin={isAdmin}
integrations={integrations ?? []}
currentRole={member.role}
/>
<StripeBillingPanel spaceId={member.space_id} />
</>
)
}