"use client"; import type { ReactElement } from "react"; import { useState, useMemo } from "react"; import type { EntryStatus } from "@mosaic/shared"; import { EntryList } from "@/components/knowledge/EntryList"; import { EntryFilters } from "@/components/knowledge/EntryFilters"; import { ImportExportActions } from "@/components/knowledge"; import { mockEntries, mockTags } from "@/lib/api/knowledge"; import Link from "next/link"; import { Plus } from "lucide-react"; export default function KnowledgePage(): ReactElement { // TODO: Replace with real API call when backend is ready // const { data: entries, isLoading } = useQuery({ // queryKey: ["knowledge-entries"], // queryFn: fetchEntries, // }); const [isLoading] = useState(false); // Filter and sort state const [selectedStatus, setSelectedStatus] = useState("all"); const [selectedTag, setSelectedTag] = useState("all"); const [searchQuery, setSearchQuery] = useState(""); const [sortBy, setSortBy] = useState<"updatedAt" | "createdAt" | "title">("updatedAt"); const [sortOrder, setSortOrder] = useState<"asc" | "desc">("desc"); // Pagination state const [currentPage, setCurrentPage] = useState(1); const itemsPerPage = 10; // Client-side filtering and sorting const filteredAndSortedEntries = useMemo(() => { let filtered = [...mockEntries]; // Filter by status if (selectedStatus !== "all") { filtered = filtered.filter((entry) => entry.status === selectedStatus); } // Filter by tag if (selectedTag !== "all") { filtered = filtered.filter((entry) => entry.tags.some((tag: { slug: string }) => tag.slug === selectedTag) ); } // Filter by search query if (searchQuery.trim()) { const query = searchQuery.toLowerCase(); filtered = filtered.filter( (entry) => entry.title.toLowerCase().includes(query) || (entry.summary?.toLowerCase().includes(query) ?? false) || entry.tags.some((tag: { name: string }): boolean => tag.name.toLowerCase().includes(query) ) ); } // Sort entries filtered.sort((a, b) => { let comparison = 0; if (sortBy === "title") { comparison = a.title.localeCompare(b.title); } else if (sortBy === "createdAt") { comparison = new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime(); } else { // updatedAt comparison = new Date(a.updatedAt).getTime() - new Date(b.updatedAt).getTime(); } return sortOrder === "asc" ? comparison : -comparison; }); return filtered; }, [selectedStatus, selectedTag, searchQuery, sortBy, sortOrder]); // Pagination const totalPages = Math.ceil(filteredAndSortedEntries.length / itemsPerPage); const paginatedEntries = filteredAndSortedEntries.slice( (currentPage - 1) * itemsPerPage, currentPage * itemsPerPage ); // Reset to page 1 when filters change const handleFilterChange = (callback: () => void): void => { callback(); setCurrentPage(1); }; const handleSortChange = ( newSortBy: "updatedAt" | "createdAt" | "title", newSortOrder: "asc" | "desc" ): void => { setSortBy(newSortBy); setSortOrder(newSortOrder); setCurrentPage(1); }; return (
{/* Header */}

Knowledge Base

Documentation, guides, and knowledge entries

{/* Create button */} Create Entry
{/* Import/Export Actions */}
{ // TODO: Refresh the entry list when real API is connected // For now, this would trigger a refetch of the entries window.location.reload(); }} />
{/* Filters */} { handleFilterChange(() => { setSelectedStatus(status); }); }} onTagChange={(tag) => { handleFilterChange(() => { setSelectedTag(tag); }); }} onSearchChange={(query) => { handleFilterChange(() => { setSearchQuery(query); }); }} onSortChange={handleSortChange} /> {/* Entry list */}
); }