DB, Collections, Search
This commit is contained in:
159
src/app/(app)/collections/page.tsx
Normal file
159
src/app/(app)/collections/page.tsx
Normal file
@@ -0,0 +1,159 @@
|
||||
import { auth } from "@/lib/auth"
|
||||
import { redirect } from "next/navigation"
|
||||
import { getUserCollections, getGlobalCollections } from "@/actions/collections"
|
||||
import Link from "next/link"
|
||||
|
||||
export default async function CollectionsPage() {
|
||||
const session = await auth()
|
||||
|
||||
if (!session?.user) {
|
||||
redirect("/login")
|
||||
}
|
||||
|
||||
const [userCollectionsResult, globalCollectionsResult] = await Promise.all([
|
||||
getUserCollections(),
|
||||
getGlobalCollections(),
|
||||
])
|
||||
|
||||
const userCollections = userCollectionsResult.success ? userCollectionsResult.data || [] : []
|
||||
const globalCollections = globalCollectionsResult.success
|
||||
? globalCollectionsResult.data || []
|
||||
: []
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 dark:bg-gray-900">
|
||||
<nav className="bg-white dark:bg-gray-800 shadow">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="flex justify-between h-16 items-center">
|
||||
<div className="flex items-center space-x-8">
|
||||
<Link href="/dashboard">
|
||||
<h1 className="text-xl font-bold text-gray-900 dark:text-white cursor-pointer">
|
||||
MemoHanzi <span className="text-sm font-normal text-gray-500">记汉字</span>
|
||||
</h1>
|
||||
</Link>
|
||||
<Link
|
||||
href="/collections"
|
||||
className="text-sm text-gray-900 dark:text-gray-200 font-medium"
|
||||
>
|
||||
Collections
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
<div className="flex justify-between items-center mb-8">
|
||||
<div>
|
||||
<h2 className="text-3xl font-bold text-gray-900 dark:text-white mb-2">Collections</h2>
|
||||
<p className="text-gray-600 dark:text-gray-400">
|
||||
Organize your hanzi into collections for learning
|
||||
</p>
|
||||
</div>
|
||||
<Link
|
||||
href="/collections/new"
|
||||
className="bg-blue-600 text-white px-6 py-2 rounded-lg hover:bg-blue-700"
|
||||
>
|
||||
Create Collection
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* User Collections */}
|
||||
<section className="mb-12">
|
||||
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4">
|
||||
My Collections
|
||||
</h3>
|
||||
|
||||
{userCollections.length === 0 ? (
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow p-8 text-center">
|
||||
<p className="text-gray-600 dark:text-gray-400 mb-4">
|
||||
You don't have any collections yet.
|
||||
</p>
|
||||
<Link
|
||||
href="/collections/new"
|
||||
className="inline-block bg-blue-600 text-white px-6 py-2 rounded-lg hover:bg-blue-700"
|
||||
>
|
||||
Create Your First Collection
|
||||
</Link>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{userCollections.map((collection) => (
|
||||
<Link
|
||||
key={collection.id}
|
||||
href={`/collections/${collection.id}`}
|
||||
className="bg-white dark:bg-gray-800 rounded-lg shadow p-6 hover:shadow-lg transition-shadow"
|
||||
>
|
||||
<h4 className="text-xl font-semibold text-gray-900 dark:text-white mb-2">
|
||||
{collection.name}
|
||||
</h4>
|
||||
{collection.description && (
|
||||
<p className="text-gray-600 dark:text-gray-400 text-sm mb-4 line-clamp-2">
|
||||
{collection.description}
|
||||
</p>
|
||||
)}
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-2xl font-bold text-blue-600 dark:text-blue-400">
|
||||
{collection.hanziCount}
|
||||
</span>
|
||||
<span className="text-sm text-gray-500 dark:text-gray-400">
|
||||
{collection.isPublic ? "Public" : "Private"}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-xs text-gray-500 dark:text-gray-400 mt-2">
|
||||
Created {new Date(collection.createdAt).toLocaleDateString()}
|
||||
</p>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
|
||||
{/* Global Collections (HSK) */}
|
||||
<section>
|
||||
<h3 className="text-2xl font-semibold text-gray-900 dark:text-white mb-4">
|
||||
HSK Collections
|
||||
</h3>
|
||||
|
||||
{globalCollections.length === 0 ? (
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow p-8 text-center">
|
||||
<p className="text-gray-600 dark:text-gray-400">
|
||||
No HSK collections available yet. Ask an admin to create them.
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{globalCollections.map((collection) => (
|
||||
<Link
|
||||
key={collection.id}
|
||||
href={`/collections/${collection.id}`}
|
||||
className="bg-white dark:bg-gray-800 rounded-lg shadow p-6 hover:shadow-lg transition-shadow border-2 border-green-200 dark:border-green-700"
|
||||
>
|
||||
<div className="flex items-center mb-2">
|
||||
<h4 className="text-xl font-semibold text-gray-900 dark:text-white">
|
||||
{collection.name}
|
||||
</h4>
|
||||
<span className="ml-2 text-xs bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200 px-2 py-1 rounded">
|
||||
HSK
|
||||
</span>
|
||||
</div>
|
||||
{collection.description && (
|
||||
<p className="text-gray-600 dark:text-gray-400 text-sm mb-4 line-clamp-2">
|
||||
{collection.description}
|
||||
</p>
|
||||
)}
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-2xl font-bold text-green-600 dark:text-green-400">
|
||||
{collection.hanziCount}
|
||||
</span>
|
||||
<span className="text-sm text-gray-500 dark:text-gray-400">hanzi</span>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user