Files
Brancheneinstufung2/company-explorer/frontend/src/components/ImportWizard.tsx
Floke 2c7bb262ef feat(company-explorer): Initial Web UI & Backend with Enrichment Flow
This commit introduces the foundational elements for the new "Company Explorer" web application, marking a significant step away from the legacy Google Sheets / CLI system.

Key changes include:
- Project Structure: A new  directory with separate  (FastAPI) and  (React/Vite) components.
- Data Persistence: Migration from Google Sheets to a local SQLite database () using SQLAlchemy.
- Core Utilities: Extraction and cleanup of essential helper functions (LLM wrappers, text utilities) into .
- Backend Services: , ,  for AI-powered analysis, and  logic.
- Frontend UI: Basic React application with company table, import wizard, and dynamic inspector sidebar.
- Docker Integration: Updated  and  for multi-stage builds and sideloading.
- Deployment & Access: Integrated into central Nginx proxy and dashboard, accessible via .

Lessons Learned & Fixed during development:
- Frontend Asset Loading: Addressed issues with Vite's  path and FastAPI's .
- TypeScript Configuration: Added  and .
- Database Schema Evolution: Solved  errors by forcing a new database file and correcting  override.
- Logging: Implemented robust file-based logging ().

This new foundation provides a powerful and maintainable platform for future B2B robotics lead generation.
2026-01-07 17:55:08 +00:00

86 lines
2.8 KiB
TypeScript

import { useState } from 'react'
import axios from 'axios'
import { X, UploadCloud } from 'lucide-react'
interface ImportWizardProps {
isOpen: boolean
onClose: () => void
onSuccess: () => void
apiBase: string
}
export function ImportWizard({ isOpen, onClose, onSuccess, apiBase }: ImportWizardProps) {
const [text, setText] = useState("")
const [loading, setLoading] = useState(false)
if (!isOpen) return null
const handleImport = async () => {
const lines = text.split('\n').map(l => l.trim()).filter(l => l.length > 0)
if (lines.length === 0) return
setLoading(true)
try {
await axios.post(`${apiBase}/companies/bulk`, { names: lines })
setText("")
onSuccess()
onClose()
} catch (e: any) {
console.error(e)
const msg = e.response?.data?.detail || e.message || "Unknown Error"
alert(`Import failed: ${msg}`)
} finally {
setLoading(false)
}
}
return (
<div className="fixed inset-0 bg-black/70 backdrop-blur-sm z-50 flex items-center justify-center p-4">
<div className="bg-slate-900 border border-slate-700 rounded-xl w-full max-w-lg shadow-2xl">
{/* Header */}
<div className="flex items-center justify-between p-4 border-b border-slate-800">
<h3 className="text-lg font-semibold text-white flex items-center gap-2">
<UploadCloud className="h-5 w-5 text-blue-400" />
Quick Import
</h3>
<button onClick={onClose} className="text-slate-400 hover:text-white">
<X className="h-5 w-5" />
</button>
</div>
{/* Body */}
<div className="p-4 space-y-4">
<p className="text-sm text-slate-400">
Paste company names below (one per line). Duplicates in the database will be skipped automatically.
</p>
<textarea
className="w-full h-64 bg-slate-950 border border-slate-700 rounded-lg p-3 text-sm text-slate-200 focus:ring-2 focus:ring-blue-600 outline-none font-mono"
placeholder="Company A&#10;Company B&#10;Company C..."
value={text}
onChange={e => setText(e.target.value)}
/>
</div>
{/* Footer */}
<div className="p-4 border-t border-slate-800 flex justify-end gap-3">
<button
onClick={onClose}
className="px-4 py-2 text-sm font-medium text-slate-400 hover:text-white"
>
Cancel
</button>
<button
onClick={handleImport}
disabled={loading || !text.trim()}
className="px-4 py-2 bg-blue-600 hover:bg-blue-500 text-white rounded-md text-sm font-medium disabled:opacity-50 disabled:cursor-not-allowed"
>
{loading ? "Importing..." : "Import Companies"}
</button>
</div>
</div>
</div>
)
}