"use client" import { useState, useEffect } from "react" import { useRouter, useParams } from "next/navigation" import Link from "next/link" import { getCollection, addHanziToCollection, removeHanziFromCollection, removeMultipleHanziFromCollection, searchHanziForCollection, parseHanziList, deleteCollection, } from "@/actions/collections" type Hanzi = { id: string simplified: string pinyin: string | null meaning: string | null orderIndex: number } type Collection = { id: string name: string description: string | null isPublic: boolean isGlobal: boolean createdBy: string | null hanziCount: number hanzi: Hanzi[] } export default function CollectionDetailPage() { const router = useRouter() const params = useParams() const collectionId = params.id as string const [collection, setCollection] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) // Selection mode const [selectionMode, setSelectionMode] = useState(false) const [selectedHanziIds, setSelectedHanziIds] = useState>(new Set()) // Add hanzi modal const [showAddModal, setShowAddModal] = useState(false) const [addTab, setAddTab] = useState<"search" | "paste">("search") // Search state const [searchQuery, setSearchQuery] = useState("") const [searchResults, setSearchResults] = useState< Array<{ id: string simplified: string pinyin: string | null meaning: string | null inCollection: boolean }> >([]) const [searchLoading, setSearchLoading] = useState(false) const [searchSelectedIds, setSearchSelectedIds] = useState>(new Set()) // Paste state const [pasteInput, setPasteInput] = useState("") const [parseResult, setParseResult] = useState<{ valid: boolean found: Array<{ id: string; simplified: string; pinyin: string | null }> notFound: string[] duplicates: string[] } | null>(null) const [actionLoading, setActionLoading] = useState(false) const [actionError, setActionError] = useState(null) useEffect(() => { loadCollection() }, [collectionId]) const loadCollection = async () => { setLoading(true) setError(null) try { const result = await getCollection(collectionId) if (result.success && result.data) { setCollection(result.data) } else { setError(result.message || "Failed to load collection") } } catch (err) { setError(err instanceof Error ? err.message : "An error occurred") } finally { setLoading(false) } } const handleSearch = async () => { if (!searchQuery.trim()) return setSearchLoading(true) try { const result = await searchHanziForCollection(searchQuery, collectionId, 50, 0) if (result.success && result.data) { setSearchResults(result.data.hanzi) } } catch (err) { console.error("Search failed:", err) } finally { setSearchLoading(false) } } const handleParseList = async () => { if (!pasteInput.trim()) { setActionError("Please enter hanzi list") return } setActionLoading(true) setActionError(null) try { const result = await parseHanziList(pasteInput) if (result.success && result.data) { setParseResult(result.data) if (!result.data.valid) { setActionError(`${result.data.notFound.length} hanzi not found in database`) } } else { setActionError(result.message || "Failed to parse hanzi list") } } catch (err) { setActionError(err instanceof Error ? err.message : "An error occurred") } finally { setActionLoading(false) } } const handleAddSelectedFromSearch = async () => { if (searchSelectedIds.size === 0) return setActionLoading(true) setActionError(null) try { const result = await addHanziToCollection(collectionId, Array.from(searchSelectedIds)) if (result.success) { setShowAddModal(false) setSearchQuery("") setSearchResults([]) setSearchSelectedIds(new Set()) await loadCollection() } else { setActionError(result.message || "Failed to add hanzi") } } catch (err) { setActionError(err instanceof Error ? err.message : "An error occurred") } finally { setActionLoading(false) } } const handleAddFromPaste = async () => { if (!parseResult || !parseResult.valid) { setActionError("Please preview and fix any errors first") return } setActionLoading(true) setActionError(null) try { const hanziIds = parseResult.found.map((h) => h.id) const result = await addHanziToCollection(collectionId, hanziIds) if (result.success) { setShowAddModal(false) setPasteInput("") setParseResult(null) await loadCollection() } else { setActionError(result.message || "Failed to add hanzi") } } catch (err) { setActionError(err instanceof Error ? err.message : "An error occurred") } finally { setActionLoading(false) } } const handleRemoveSingle = async (hanziId: string) => { if (!confirm("Remove this hanzi from the collection?")) return setActionLoading(true) try { const result = await removeHanziFromCollection(collectionId, hanziId) if (result.success) { await loadCollection() } } catch (err) { console.error("Remove failed:", err) } finally { setActionLoading(false) } } const handleRemoveSelected = async () => { if (selectedHanziIds.size === 0) return if (!confirm(`Remove ${selectedHanziIds.size} hanzi from the collection?`)) return setActionLoading(true) try { const result = await removeMultipleHanziFromCollection(collectionId, Array.from(selectedHanziIds)) if (result.success) { setSelectionMode(false) setSelectedHanziIds(new Set()) await loadCollection() } } catch (err) { console.error("Remove failed:", err) } finally { setActionLoading(false) } } const handleDeleteCollection = async () => { if (!confirm("Delete this collection? This action cannot be undone.")) return setActionLoading(true) try { const result = await deleteCollection(collectionId) if (result.success) { router.push("/collections") } else { setActionError(result.message || "Failed to delete collection") } } catch (err) { setActionError(err instanceof Error ? err.message : "An error occurred") } finally { setActionLoading(false) } } if (loading) { return (

Loading...

) } if (error || !collection) { return (

{error || "Collection not found"}

Back to Collections
) } const canModify = !collection.isGlobal return (

{collection.name}

{collection.isGlobal && ( HSK )} {collection.isPublic && !collection.isGlobal && ( Public )}
{collection.description && (

{collection.description}

)}

{collection.hanziCount} hanzi

{canModify && (
{collection.hanziCount > 0 && ( )}
)}
{selectionMode && selectedHanziIds.size > 0 && (
{selectedHanziIds.size} selected
)} {actionError && (
{actionError}
)} {/* Hanzi Grid */} {collection.hanzi.length === 0 ? (

This collection is empty. Add some hanzi to get started.

{canModify && ( )}
) : (
{collection.hanzi.map((hanzi) => (
{selectionMode && ( { const newSet = new Set(selectedHanziIds) if (e.target.checked) { newSet.add(hanzi.id) } else { newSet.delete(hanzi.id) } setSelectedHanziIds(newSet) }} className="absolute top-2 left-2" /> )} {!selectionMode && canModify && ( )}
{hanzi.simplified}
{hanzi.pinyin && (
{hanzi.pinyin}
)} {hanzi.meaning && (
{hanzi.meaning}
)}
))}
)}
{/* Add Hanzi Modal */} {showAddModal && (

Add Hanzi

{actionError && (
{actionError}
)} {addTab === "search" ? (
setSearchQuery(e.target.value)} onKeyPress={(e) => e.key === "Enter" && handleSearch()} placeholder="Search by character, pinyin, or meaning..." className="flex-1 px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white" />
{searchSelectedIds.size > 0 && (
{searchSelectedIds.size} selected
)} {searchResults.length > 0 && (
{searchResults.map((hanzi) => ( ))}
)}
) : (