- builder: draft/published/closed status banners; creating a form now
lands on its edit page so Publish is immediately visible; a
members-only form shows a "no public link" note instead of a dead URL
- member-facing forms: /my-forms list + /my-forms/[id] fill
(MemberFillClient), "Forms" sidebar item for all members. Fixes the
long-standing gap where members-only forms had no fill surface
- starter templates: lib/form-templates.ts + a picker on /forms/new
(Liability waiver, Membership application, Event RSVP, Photo release,
Blank) that seeds builder state (no table)
- forms-client relabels members-only forms (was showing a misleading
/f/<space>/<slug> that always 404s for members-only)
- docs corrected per the audit pass: DATABASE_SCHEMA / DB_SCHEMA_MAP /
ARCHITECTURE / API_REFERENCE now reflect migrations 014-029, per-space
slug, /f/[space]/[slug], getPublicForm({space,slug}), invite roles;
HANDOFF pass-19 added with residual gaps
337 tests; build verified (Compiled successfully, exit 0). No deploy.
55 lines
1.5 KiB
TypeScript
55 lines
1.5 KiB
TypeScript
import { notFound, redirect } from 'next/navigation'
|
|
import { createClient } from '@/lib/supabase/server'
|
|
import { PageHeader, PageTitle } from '@/components/ui/page-title'
|
|
import { parseFormSchema } from '@/lib/forms-schema'
|
|
import { MemberFillClient } from '@/components/forms/member-fill-client'
|
|
|
|
export const dynamic = 'force-dynamic'
|
|
|
|
export default async function MemberFillPage({
|
|
params,
|
|
}: {
|
|
params: Promise<{ id: string }>
|
|
}) {
|
|
const { id } = await params
|
|
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')
|
|
.eq('user_id', user.id)
|
|
.in('status', ['current', 'unverified', 'late'])
|
|
.single()
|
|
if (!member) redirect('/login')
|
|
|
|
const { data: form } = await supabase
|
|
.from('forms')
|
|
.select('id, title, description, kind, legal_text, schema, status, space_id')
|
|
.eq('id', id)
|
|
.eq('space_id', member.space_id)
|
|
.eq('status', 'published')
|
|
.maybeSingle()
|
|
if (!form) notFound()
|
|
|
|
return (
|
|
<>
|
|
<PageHeader>
|
|
<PageTitle>{form.title}</PageTitle>
|
|
</PageHeader>
|
|
<div className="mx-auto max-w-2xl p-4 md:p-8">
|
|
<MemberFillClient
|
|
formId={form.id}
|
|
description={form.description}
|
|
kind={form.kind}
|
|
legalText={form.legal_text}
|
|
fields={parseFormSchema(form.schema)}
|
|
/>
|
|
</div>
|
|
</>
|
|
)
|
|
}
|