Files
infohliadka/pages/admin/categories.tsx
Lukas Davidovic 249a672cd7 transform admin panel with comprehensive professional UI
- migrate from SQLite to PostgreSQL with Drizzle ORM
- implement comprehensive AdminLayout with expandable sidebar navigation
- create professional dashboard with real-time charts and metrics
- add advanced monitoring, reporting, and export functionality
- fix menu alignment and remove non-existent pages
- eliminate duplicate headers and improve UI consistency
- add Tailwind CSS v3 for professional styling
- expand database schema from 6 to 15 tables
- implement role-based access control and API key management
- create comprehensive settings, monitoring, and system info pages
2025-09-06 15:14:20 +02:00

171 lines
7.1 KiB
TypeScript

import { useState, useEffect } from 'react'
import type { NextPage } from 'next'
import Head from 'next/head'
import AdminLayout from '../../components/AdminLayout'
import { TagIcon, PlusIcon } from '@heroicons/react/24/outline'
interface Category {
id: number
name: string
slug: string
description: string
color: string
priority: number
is_active: boolean
}
const CategoriesManagement: NextPage = () => {
const [categories, setCategories] = useState<Category[]>([])
const [loading, setLoading] = useState(true)
useEffect(() => {
fetchCategories()
}, [])
const fetchCategories = async () => {
try {
const response = await fetch('/api/admin/categories')
if (response.ok) {
const data = await response.json()
setCategories(data)
}
} catch (error) {
console.error('Failed to fetch categories:', error)
} finally {
setLoading(false)
}
}
const toggleCategory = async (id: number, isActive: boolean) => {
try {
const response = await fetch(`/api/admin/categories/${id}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ is_active: !isActive })
})
if (response.ok) {
fetchCategories()
}
} catch (error) {
console.error('Failed to update category:', error)
}
}
return (
<>
<Head>
<title>Správa kategórií - Hliadka.sk Admin</title>
</Head>
<AdminLayout title="Správa kategórií">
<div className="px-4 py-6 sm:px-6 lg:px-8">
<div className="sm:flex sm:items-center">
<div className="sm:flex-auto">
<p className="text-sm text-gray-700">
Spravujte kategórie a ich nastavenia pre klasifikáciu zdrojov
</p>
</div>
<div className="mt-4 sm:ml-16 sm:mt-0 sm:flex-none">
<button
type="button"
className="btn-primary"
>
<PlusIcon className="h-4 w-4 mr-2" />
Pridať kategóriu
</button>
</div>
</div>
<div className="mt-8 flow-root">
<div className="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
<div className="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
<div className="card">
{loading ? (
<div className="p-6">
<div className="flex items-center justify-center">
<div className="text-gray-500">Načítavanie...</div>
</div>
</div>
) : (
<table className="min-w-full divide-y divide-gray-300">
<thead className="bg-gray-50">
<tr>
<th scope="col" className="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6">
Názov
</th>
<th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
Priorita
</th>
<th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
Farba
</th>
<th scope="col" className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900">
Status
</th>
<th scope="col" className="relative py-3.5 pl-3 pr-4 sm:pr-6">
<span className="sr-only">Akcie</span>
</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200 bg-white">
{categories.map((category) => (
<tr key={category.id} className="hover:bg-gray-50">
<td className="whitespace-nowrap py-4 pl-4 pr-3 sm:pl-6">
<div className="flex items-center">
<TagIcon className="h-5 w-5 text-gray-400 mr-3" />
<div>
<div className="text-sm font-medium text-gray-900">{category.name}</div>
<div className="text-sm text-gray-500">{category.description}</div>
</div>
</div>
</td>
<td className="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
<span className="inline-flex items-center rounded-full bg-blue-100 px-2.5 py-0.5 text-xs font-medium text-blue-800">
{category.priority}
</span>
</td>
<td className="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
<div className="flex items-center">
<div
className="w-5 h-5 rounded border border-gray-300 mr-2"
style={{ backgroundColor: category.color }}
/>
<span className="text-xs font-mono">{category.color}</span>
</div>
</td>
<td className="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
{category.is_active ? (
<span className="inline-flex items-center rounded-full bg-green-100 px-2.5 py-0.5 text-xs font-medium text-green-800">
Aktívna
</span>
) : (
<span className="inline-flex items-center rounded-full bg-red-100 px-2.5 py-0.5 text-xs font-medium text-red-800">
Neaktívna
</span>
)}
</td>
<td className="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6">
<button
onClick={() => toggleCategory(category.id, category.is_active)}
className={`${
category.is_active ? 'btn-danger' : 'btn-secondary'
} text-xs px-3 py-1`}
>
{category.is_active ? 'Deaktivovať' : 'Aktivovať'}
</button>
</td>
</tr>
))}
</tbody>
</table>
)}
</div>
</div>
</div>
</div>
</div>
</AdminLayout>
</>
)
}
export default CategoriesManagement