diff --git a/App.tsx b/App.tsx index 59b6383..f99578d 100644 --- a/App.tsx +++ b/App.tsx @@ -10,8 +10,10 @@ import { ReportDisplay } from './components/ReportDisplay'; import { PrintableReport } from './components/PrintableReport'; import { DownloadIcon, EyeIcon, CogIcon } from './components/Icons'; import { ApiKeySetup } from './components/ApiKeySetup'; +import { AdminCategories } from './components/AdminCategories'; const App: React.FC = () => { + const [viewMode, setViewMode] = useState<'analysis' | 'admin'>('analysis'); const [file, setFile] = useState(null); const [apiKey, setApiKey] = useState(''); const [endpoint, setEndpoint] = useState(''); @@ -202,13 +204,22 @@ const App: React.FC = () => {
{isLoading && } -
+
setViewMode(viewMode === 'admin' ? 'analysis' : 'admin')} + isAdminView={viewMode === 'admin'} + />
{!isConfigLoaded ? (
+ ) : viewMode === 'admin' ? ( + ) : (!hasKey || showSetup) ? ( setShowSetup(false) : undefined} /> ) : !reportsData ? ( diff --git a/components/AdminCategories.tsx b/components/AdminCategories.tsx new file mode 100644 index 0000000..79d42dc --- /dev/null +++ b/components/AdminCategories.tsx @@ -0,0 +1,173 @@ +import React, { useState, useEffect } from 'react'; + +export interface Category { + id: string; + name: string; + description: string; +} + +export const AdminCategories: React.FC = () => { + const [categories, setCategories] = useState([]); + const [isLoading, setIsLoading] = useState(true); + const [isEditing, setIsEditing] = useState(null); + const [formData, setFormData] = useState({ name: '', description: '' }); + + useEffect(() => { + fetchCategories(); + }, []); + + const fetchCategories = async () => { + setIsLoading(true); + try { + const res = await fetch('/api/categories'); + const data = await res.json(); + setCategories(data); + } catch (e) { + console.error('Error fetching categories:', e); + } finally { + setIsLoading(false); + } + }; + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + if (!formData.name) return; + + const method = isEditing ? 'PUT' : 'POST'; + const body = isEditing ? { ...formData, id: isEditing.id } : formData; + + try { + await fetch('/api/categories', { + method, + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(body) + }); + setIsEditing(null); + setFormData({ name: '', description: '' }); + fetchCategories(); + } catch (e) { + console.error('Error saving category:', e); + } + }; + + const handleEdit = (cat: Category) => { + setIsEditing(cat); + setFormData({ name: cat.name, description: cat.description }); + }; + + const handleDelete = async (id: string) => { + if (!confirm('Tem certeza que deseja excluir esta categoria?')) return; + try { + await fetch(`/api/categories?id=${id}`, { method: 'DELETE' }); + fetchCategories(); + } catch (e) { + console.error('Error deleting category:', e); + } + }; + + const handleCancel = () => { + setIsEditing(null); + setFormData({ name: '', description: '' }); + }; + + if (isLoading) { + return
Carregando categorias...
; + } + + return ( +
+
+

Gerenciar Categorias de Materiais

+

Cadastre os tipos de laudos (Ex: Aços, Parafusos, Tintas) que serão suportados pelo sistema de Normas e IA.

+
+ +
+

+ {isEditing ? 'Editar Categoria' : 'Nova Categoria'} +

+
+
+ + setFormData({ ...formData, name: e.target.value })} + placeholder="Ex: Aços Estruturais, Fixadores, Tintas Industriais" + className="w-full rounded-lg border-slate-300 dark:border-slate-600 bg-white dark:bg-slate-700 px-4 py-2 text-slate-900 dark:text-white focus:ring-blue-500 focus:border-blue-500 outline-none" + /> +
+
+ +