import { useEffect, useState } from 'react' import axios from 'axios' import { X, Bot, Tag, Target, Users, Plus, Trash2, Save, Flag, Check, Ban } from 'lucide-react' import clsx from 'clsx' interface RoboticsSettingsProps { isOpen: boolean onClose: () => void apiBase: string } type ReportedMistake = { id: number; company_id: number; company: { name: string }; // Assuming company name is eagerly loaded field_name: string; wrong_value: string | null; corrected_value: string | null; source_url: string | null; quote: string | null; user_comment: string | null; status: 'PENDING' | 'APPROVED' | 'REJECTED'; created_at: string; updated_at: string; } export function RoboticsSettings({ isOpen, onClose, apiBase }: RoboticsSettingsProps) { const [activeTab, setActiveTab] = useState<'robotics' | 'industries' | 'roles' | 'mistakes'>( localStorage.getItem('roboticsSettingsActiveTab') as 'robotics' | 'industries' | 'roles' | 'mistakes' || 'robotics' ) const [roboticsCategories, setRoboticsCategories] = useState([]) const [industries, setIndustries] = useState([]) const [jobRoles, setJobRoles] = useState([]) const [reportedMistakes, setReportedMistakes] = useState([]) const [currentMistakeStatusFilter, setCurrentMistakeStatusFilter] = useState("PENDING"); const [isLoading, setIsLoading] = useState(false); const fetchAllData = async () => { setIsLoading(true); try { const [resRobotics, resIndustries, resJobRoles, resMistakes] = await Promise.all([ axios.get(`${apiBase}/robotics/categories`), axios.get(`${apiBase}/industries`), axios.get(`${apiBase}/job_roles`), axios.get(`${apiBase}/mistakes?status=${currentMistakeStatusFilter}`), ]); setRoboticsCategories(resRobotics.data); setIndustries(resIndustries.data); setJobRoles(resJobRoles.data); setReportedMistakes(resMistakes.data.items); } catch (e) { console.error("Failed to fetch settings data:", e); alert("Fehler beim Laden der Settings. Siehe Konsole."); } finally { setIsLoading(false); } }; useEffect(() => { if (isOpen) { fetchAllData(); } }, [isOpen]); useEffect(() => { localStorage.setItem('roboticsSettingsActiveTab', activeTab); }, [activeTab]); const handleUpdateRobotics = async (id: number, description: string, reasoning: string) => { setIsLoading(true); try { await axios.put(`${apiBase}/robotics/categories/${id}`, { description, reasoning_guide: reasoning }); fetchAllData(); } catch (e) { alert("Update failed"); console.error(e); } finally { setIsLoading(false); } } const handleUpdateMistakeStatus = async (mistakeId: number, newStatus: 'APPROVED' | 'REJECTED') => { setIsLoading(true); try { await axios.put(`${apiBase}/mistakes/${mistakeId}`, { status: newStatus }); fetchAllData(); // Refresh all data, including mistakes } catch (e) { alert("Failed to update mistake status"); console.error(e); } finally { setIsLoading(false); } }; const handleAddJobRole = async () => { setIsLoading(true); try { await axios.post(`${apiBase}/job_roles`, { pattern: "New Pattern", role: "Operativer Entscheider" }); fetchAllData(); } catch (e) { alert("Failed to add job role"); console.error(e); } finally { setIsLoading(false); } } const handleDeleteJobRole = async (id: number) => { setIsLoading(true); try { await axios.delete(`${apiBase}/job_roles/${id}`); fetchAllData(); } catch (e) { alert("Failed to delete job role"); console.error(e); } finally { setIsLoading(false); } } if (!isOpen) return null return (
{/* Header */}

Settings & Classification Logic

Define how AI evaluates leads and matches roles.

{/* Tab Nav */}
{[ { id: 'robotics', label: 'Robotics Potential', icon: Bot }, { id: 'industries', label: 'Industry Focus', icon: Target }, { id: 'roles', label: 'Job Role Mapping', icon: Users }, { id: 'mistakes', label: 'Reported Mistakes', icon: Flag }, ].map(t => ( ))}
{/* Content */}
{isLoading &&
Loading...
}
{roboticsCategories.map(cat => ( ))}

Industry Verticals (Synced from Notion)

{industries.map(ind => (
{ind.notion_id && (
SYNCED
)}

{ind.name}

{ind.status_notion && {ind.status_notion}}
{ind.is_focus ? "Focus" : "Standard"}

{ind.description || "No definition"}

Whale >{ind.whale_threshold || "-"}
Min Req{ind.min_requirement || "-"}
Unit{ind.scraper_search_term || "-"}
Product{roboticsCategories.find(c => c.id === ind.primary_category_id)?.name || "-"}
{ind.scraper_keywords &&
Keywords:{ind.scraper_keywords}
} {ind.standardization_logic &&
Standardization:{ind.standardization_logic}
}
))}

Job Title Mapping Patterns

{jobRoles.map(role => ( ))} {jobRoles.length === 0 && ()}
Job Title Pattern (Regex/Text)Mapped Role
No patterns defined yet.

Reported Data Mistakes

Filter:
{reportedMistakes.length > 0 ? ( reportedMistakes.map(mistake => ( )) ) : ( )}
Company Field Wrong Value Corrected Value Source / Quote / Comment Status Actions
{mistake.company.name} {mistake.field_name} {mistake.wrong_value || '-'} {mistake.corrected_value || '-'} {mistake.source_url && Source} {mistake.quote &&

"{mistake.quote}"

} {mistake.user_comment &&

Comment: {mistake.user_comment}

}
{mistake.status} {mistake.status === "PENDING" && (
)}
No reported mistakes found.
) } function CategoryCard({ category, onSave }: { category: any, onSave: any }) { const [desc, setDesc] = useState(category.description) const [guide, setGuide] = useState(category.reasoning_guide) const [isDirty, setIsDirty] = useState(false) useEffect(() => { setIsDirty(desc !== category.description || guide !== category.reasoning_guide) }, [desc, guide]) return (
{category.name}