123 lines
3.4 KiB
TypeScript
123 lines
3.4 KiB
TypeScript
import { createClient } from '@/lib/supabase/server'
|
|
import { notFound } from 'next/navigation'
|
|
import Link from 'next/link'
|
|
import FlowchartEditor from './FlowchartEditor'
|
|
import type { FlowchartData } from '@/types/flowchart'
|
|
|
|
type PageProps = {
|
|
params: Promise<{ projectId: string }>
|
|
}
|
|
|
|
export default async function EditorPage({ params }: PageProps) {
|
|
const { projectId } = await params
|
|
const supabase = await createClient()
|
|
|
|
const {
|
|
data: { user },
|
|
} = await supabase.auth.getUser()
|
|
|
|
if (!user) {
|
|
return null
|
|
}
|
|
|
|
// Fetch user's display name for presence
|
|
const { data: profile } = await supabase
|
|
.from('profiles')
|
|
.select('display_name')
|
|
.eq('id', user.id)
|
|
.single()
|
|
|
|
const userDisplayName = profile?.display_name || user.email || 'Anonymous'
|
|
|
|
// Try to load as owner first
|
|
const { data: ownedProject } = await supabase
|
|
.from('projects')
|
|
.select('id, name, flowchart_data')
|
|
.eq('id', projectId)
|
|
.eq('user_id', user.id)
|
|
.single()
|
|
|
|
let project = ownedProject
|
|
let isOwner = true
|
|
|
|
// If not the owner, check if the user is a collaborator
|
|
if (!project) {
|
|
// RLS on projects allows collaborators to SELECT shared projects
|
|
const { data: collab } = await supabase
|
|
.from('project_collaborators')
|
|
.select('id, role')
|
|
.eq('project_id', projectId)
|
|
.eq('user_id', user.id)
|
|
.single()
|
|
|
|
if (!collab) {
|
|
notFound()
|
|
}
|
|
|
|
const { data: sharedProject } = await supabase
|
|
.from('projects')
|
|
.select('id, name, flowchart_data')
|
|
.eq('id', projectId)
|
|
.single()
|
|
|
|
if (!sharedProject) {
|
|
notFound()
|
|
}
|
|
|
|
project = sharedProject
|
|
isOwner = false
|
|
}
|
|
|
|
const rawData = project.flowchart_data || {}
|
|
const flowchartData: FlowchartData = {
|
|
nodes: rawData.nodes || [],
|
|
edges: rawData.edges || [],
|
|
characters: rawData.characters || [],
|
|
variables: rawData.variables || [],
|
|
}
|
|
|
|
// Migration flag: if the raw data doesn't have characters/variables arrays,
|
|
// the project was created before these features existed and may need auto-migration
|
|
const needsMigration = !rawData.characters && !rawData.variables
|
|
|
|
return (
|
|
<div className="flex h-screen flex-col">
|
|
<header className="flex items-center justify-between border-b border-zinc-200 bg-white px-4 py-3 dark:border-zinc-700 dark:bg-zinc-900">
|
|
<div className="flex items-center gap-4">
|
|
<Link
|
|
href="/dashboard"
|
|
className="text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-zinc-50"
|
|
>
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
className="h-5 w-5"
|
|
viewBox="0 0 20 20"
|
|
fill="currentColor"
|
|
>
|
|
<path
|
|
fillRule="evenodd"
|
|
d="M9.707 16.707a1 1 0 01-1.414 0l-6-6a1 1 0 010-1.414l6-6a1 1 0 011.414 1.414L5.414 9H17a1 1 0 110 2H5.414l4.293 4.293a1 1 0 010 1.414z"
|
|
clipRule="evenodd"
|
|
/>
|
|
</svg>
|
|
</Link>
|
|
<h1 className="text-lg font-semibold text-zinc-900 dark:text-zinc-50">
|
|
{project.name}
|
|
</h1>
|
|
</div>
|
|
</header>
|
|
|
|
<div className="flex-1">
|
|
<FlowchartEditor
|
|
projectId={project.id}
|
|
userId={user.id}
|
|
userDisplayName={userDisplayName}
|
|
isOwner={isOwner}
|
|
initialData={flowchartData}
|
|
needsMigration={needsMigration}
|
|
/>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|