feat: [US-012] - Dashboard - list projects
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
a152383c91
commit
be4ecc482e
|
|
@ -0,0 +1,102 @@
|
||||||
|
import { createClient } from '@/lib/supabase/server'
|
||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
|
interface Project {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
updated_at: string
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatDate(dateString: string): string {
|
||||||
|
const date = new Date(dateString)
|
||||||
|
return date.toLocaleDateString('en-US', {
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'short',
|
||||||
|
day: 'numeric',
|
||||||
|
hour: '2-digit',
|
||||||
|
minute: '2-digit',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function DashboardPage() {
|
||||||
|
const supabase = await createClient()
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: { user },
|
||||||
|
} = await supabase.auth.getUser()
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data: projects, error } = await supabase
|
||||||
|
.from('projects')
|
||||||
|
.select('id, name, updated_at')
|
||||||
|
.eq('user_id', user.id)
|
||||||
|
.order('updated_at', { ascending: false })
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<div className="rounded-lg border border-red-200 bg-red-50 p-4 dark:border-red-800 dark:bg-red-900/20">
|
||||||
|
<p className="text-red-700 dark:text-red-400">
|
||||||
|
Failed to load projects. Please try again.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="mb-8">
|
||||||
|
<h1 className="text-2xl font-bold text-zinc-900 dark:text-zinc-50">
|
||||||
|
Your Projects
|
||||||
|
</h1>
|
||||||
|
<p className="mt-1 text-sm text-zinc-600 dark:text-zinc-400">
|
||||||
|
Select a project to open the flowchart editor
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{projects && projects.length > 0 ? (
|
||||||
|
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
|
||||||
|
{projects.map((project: Project) => (
|
||||||
|
<Link
|
||||||
|
key={project.id}
|
||||||
|
href={`/editor/${project.id}`}
|
||||||
|
className="group rounded-lg border border-zinc-200 bg-white p-6 transition-all hover:border-blue-300 hover:shadow-md dark:border-zinc-700 dark:bg-zinc-800 dark:hover:border-blue-600"
|
||||||
|
>
|
||||||
|
<h2 className="text-lg font-semibold text-zinc-900 group-hover:text-blue-600 dark:text-zinc-50 dark:group-hover:text-blue-400">
|
||||||
|
{project.name}
|
||||||
|
</h2>
|
||||||
|
<p className="mt-2 text-sm text-zinc-500 dark:text-zinc-400">
|
||||||
|
Last updated: {formatDate(project.updated_at)}
|
||||||
|
</p>
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="rounded-lg border-2 border-dashed border-zinc-300 bg-zinc-50 p-12 text-center dark:border-zinc-700 dark:bg-zinc-800/50">
|
||||||
|
<svg
|
||||||
|
className="mx-auto h-12 w-12 text-zinc-400 dark:text-zinc-500"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke="currentColor"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeLinejoin="round"
|
||||||
|
strokeWidth={1.5}
|
||||||
|
d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<h3 className="mt-4 text-lg font-medium text-zinc-900 dark:text-zinc-50">
|
||||||
|
No projects yet
|
||||||
|
</h3>
|
||||||
|
<p className="mt-2 text-sm text-zinc-500 dark:text-zinc-400">
|
||||||
|
Get started by creating your first visual novel project.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue