-
Notifications
You must be signed in to change notification settings - Fork 7
feat: implement admin category dashboard #202
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
31c8855
c82d135
7539fd0
71e18cd
f9f8b79
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
import withAdmin from '@/components/common/HOC/authAdmin' | ||
import AdminTreeNavigation from '@/components/admin/AdminTreeNavigation' | ||
import { CustomPagination } from '@/components/common/CustomPagination' | ||
import { usePage } from '@/components/hooks/usePage' | ||
import { useListAllNodes } from '@/src/api/generated' | ||
import { useNextTranslation } from '@/src/hooks/i18n' | ||
import { Breadcrumb, Card, Badge } from 'flowbite-react' | ||
import { HiHome, HiOutlineCollection } from 'react-icons/hi' | ||
import React, { useMemo, useState } from 'react' | ||
|
||
export default withAdmin(CategoriesPage) | ||
function CategoriesPage() { | ||
const { t } = useNextTranslation() | ||
const [page, setPage] = usePage() | ||
const [limit] = useState<number>(20) | ||
|
||
const { data: nodesData } = useListAllNodes({ | ||
page: page || 1, | ||
limit: limit, | ||
|
||
sort: ['category'], | ||
}) | ||
|
||
const categoriesData = useMemo(() => { | ||
if (!nodesData?.nodes) return [] | ||
|
||
const categoryMap = new Map<string, number>() | ||
nodesData.nodes.forEach((node) => { | ||
const category = node.category || 'Uncategorized' | ||
categoryMap.set(category, (categoryMap.get(category) || 0) + 1) | ||
}) | ||
|
||
return Array.from(categoryMap.entries()) | ||
.map(([category, count]) => ({ category, count })) | ||
.sort((a, b) => b.count - a.count) | ||
}, [nodesData?.nodes]) | ||
|
||
const totalPages = Math.ceil((nodesData?.total || 0) / limit) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The pagination logic is incorrect. The totalPages calculation is based on total nodes, but the displayed data is categories. This will show incorrect pagination when the number of categories differs from the number of nodes. Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||
|
||
return ( | ||
<div className="p-4"> | ||
<Breadcrumb className="py-4"> | ||
<Breadcrumb.Item href="/" icon={HiHome} className="dark"> | ||
{t('Home')} | ||
</Breadcrumb.Item> | ||
<Breadcrumb.Item href="/admin" className="dark"> | ||
{t('Admin Dashboard')} | ||
</Breadcrumb.Item> | ||
<Breadcrumb.Item href="#" className="dark"> | ||
{t('Category Management')} | ||
</Breadcrumb.Item> | ||
</Breadcrumb> | ||
|
||
<h1 className="text-2xl font-bold text-gray-200 mb-6"> | ||
{t('Category Management')} | ||
</h1> | ||
|
||
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6"> | ||
<div className="lg:col-span-1"> | ||
<AdminTreeNavigation /> | ||
</div> | ||
|
||
<div className="lg:col-span-3"> | ||
<Card className="bg-gray-800 border-gray-700"> | ||
<div className="flex items-center justify-between mb-4"> | ||
<h2 className="text-xl font-semibold text-gray-200"> | ||
{t('Node Categories Overview')} | ||
</h2> | ||
<Badge color="info" icon={HiOutlineCollection}> | ||
{categoriesData.length} {t('categories')} | ||
</Badge> | ||
</div> | ||
|
||
<div className="space-y-4"> | ||
{categoriesData.map(({ category, count }) => ( | ||
<div | ||
key={category} | ||
className="flex items-center justify-between p-4 bg-gray-700 rounded-lg hover:bg-gray-600 transition-colors" | ||
> | ||
<div className="flex items-center space-x-3"> | ||
<HiOutlineCollection className="h-5 w-5 text-blue-400" /> | ||
<span className="text-lg font-medium text-gray-200"> | ||
{category} | ||
</span> | ||
</div> | ||
<Badge color="purple" size="sm"> | ||
{count} {t('nodes')} | ||
</Badge> | ||
</div> | ||
))} | ||
</div> | ||
|
||
{categoriesData.length === 0 && ( | ||
<div className="text-center py-8"> | ||
<HiOutlineCollection className="h-12 w-12 text-gray-400 mx-auto mb-4" /> | ||
<p className="text-gray-400"> | ||
{t('No categories found')} | ||
</p> | ||
</div> | ||
)} | ||
|
||
{totalPages > 1 && ( | ||
<div className="py-8"> | ||
<CustomPagination | ||
currentPage={page || 1} | ||
totalPages={totalPages} | ||
onPageChange={setPage} | ||
/> | ||
</div> | ||
)} | ||
</Card> | ||
</div> | ||
</div> | ||
</div> | ||
) | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -32,7 +32,6 @@ function AdminDashboard() { | |||||
<h1 className="text-2xl font-bold text-gray-200 mb-6"> | ||||||
{t('Admin Dashboard')} | ||||||
</h1> | ||||||
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6"> | ||||||
<div className="lg:col-span-1"> | ||||||
<AdminTreeNavigation /> | ||||||
|
@@ -72,6 +71,13 @@ function AdminDashboard() { | |||||
<HiOutlineCollection className="h-8 w-8 mr-3" /> | ||||||
<span>{t('Manage All Nodes')}</span> | ||||||
</Link> | ||||||
<Link | ||||||
href="/admin/categories" | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The href path '/admin/categories' is inconsistent with the file path 'pages/admin/categories.tsx'. This will result in a 404 error when users click the link.
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||
className="bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg p-4 flex items-center transition-colors" | ||||||
> | ||||||
<HiOutlineCollection className="h-8 w-8 mr-3" /> | ||||||
<span>{t('Category Management')}</span> | ||||||
</Link> | ||||||
</div> | ||||||
</div> | ||||||
</div> | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The category calculation processes all nodes on every page, which is inefficient. Consider fetching category data directly from the API or implementing server-side aggregation to avoid processing large datasets on the client.
Copilot uses AI. Check for mistakes.