feat: universal zero-hallucination dynamic web scraper engine & instant tag edit mode
This commit is contained in:
@@ -4,13 +4,15 @@ import { Globe, Bot, Sparkles, CheckCircle2, ShieldCheck, Tag, X, Loader2, Datab
|
||||
import confetti from 'canvas-confetti';
|
||||
|
||||
export const CompanyScannerModal = () => {
|
||||
const { isCompanyScannerOpen, setIsCompanyScannerOpen, userProfile, scanCompanyWebsite } = useApp();
|
||||
const { isCompanyScannerOpen, setIsCompanyScannerOpen, userProfile, scanCompanyWebsite, updateCompanyCapabilities } = useApp();
|
||||
|
||||
const [urlInput, setUrlInput] = useState(userProfile.website || 'https://www.tanriverdimedikal.com.tr');
|
||||
const [isScanning, setIsScanning] = useState(false);
|
||||
const [scanStep, setScanStep] = useState(0);
|
||||
const [scanSuccess, setScanSuccess] = useState(false);
|
||||
|
||||
const [newProductInput, setNewProductInput] = useState('');
|
||||
|
||||
if (!isCompanyScannerOpen) return null;
|
||||
|
||||
const handleStartScan = async (e) => {
|
||||
@@ -21,8 +23,8 @@ export const CompanyScannerModal = () => {
|
||||
setScanSuccess(false);
|
||||
setScanStep(1);
|
||||
|
||||
setTimeout(() => setScanStep(2), 800);
|
||||
setTimeout(() => setScanStep(3), 1600);
|
||||
setTimeout(() => setScanStep(2), 600);
|
||||
setTimeout(() => setScanStep(3), 1200);
|
||||
|
||||
const capabilities = await scanCompanyWebsite(urlInput);
|
||||
setIsScanning(false);
|
||||
@@ -34,8 +36,28 @@ export const CompanyScannerModal = () => {
|
||||
|
||||
const handleRemoveSector = (indexToRemove) => {
|
||||
if (!caps?.extractedSectors) return;
|
||||
const updatedSectors = caps.extractedSectors.filter((_, idx) => idx !== indexToRemove);
|
||||
scanCompanyWebsite(userProfile.website || urlInput);
|
||||
const updated = caps.extractedSectors.filter((_, idx) => idx !== indexToRemove);
|
||||
updateCompanyCapabilities({ extractedSectors: updated });
|
||||
};
|
||||
|
||||
const handleRemoveProduct = (indexToRemove) => {
|
||||
if (!caps?.extractedProducts) return;
|
||||
const updated = caps.extractedProducts.filter((_, idx) => idx !== indexToRemove);
|
||||
updateCompanyCapabilities({ extractedProducts: updated });
|
||||
};
|
||||
|
||||
const handleRemoveCert = (indexToRemove) => {
|
||||
if (!caps?.extractedCertifications) return;
|
||||
const updated = caps.extractedCertifications.filter((_, idx) => idx !== indexToRemove);
|
||||
updateCompanyCapabilities({ extractedCertifications: updated });
|
||||
};
|
||||
|
||||
const handleAddCustomProduct = (e) => {
|
||||
e.preventDefault();
|
||||
if (!newProductInput.trim() || !caps) return;
|
||||
const updated = [...(caps.extractedProducts || []), newProductInput.trim()];
|
||||
updateCompanyCapabilities({ extractedProducts: updated });
|
||||
setNewProductInput('');
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -163,27 +185,62 @@ export const CompanyScannerModal = () => {
|
||||
</span>
|
||||
<div className="space-y-1.5">
|
||||
{caps.extractedSectors?.map((s, i) => (
|
||||
<div key={i} className="flex items-center justify-between text-xs font-bold text-blue-900 bg-blue-100/70 border border-blue-200 px-2.5 py-1.5 rounded-lg">
|
||||
<div key={i} className="flex items-center justify-between text-xs font-bold text-blue-900 bg-blue-100/70 border border-blue-200 px-2.5 py-1.5 rounded-lg group">
|
||||
<span>{s}</span>
|
||||
<span className="text-[10px] text-blue-600 bg-white px-1.5 py-0.5 rounded-md font-semibold">Doğrulandı</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleRemoveSector(i)}
|
||||
className="text-blue-400 hover:text-red-600 transition-colors p-0.5"
|
||||
title="Sektörü Kaldır"
|
||||
>
|
||||
<X className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Products */}
|
||||
<div className="bg-slate-50 p-4 rounded-xl border border-slate-200 space-y-2 md:col-span-2">
|
||||
<div className="bg-slate-50 p-4 rounded-xl border border-slate-200 space-y-3 md:col-span-2">
|
||||
<span className="font-bold text-xs text-slate-800 uppercase tracking-wider flex items-center gap-1.5 justify-between">
|
||||
<span className="flex items-center gap-1.5">
|
||||
<Bot className="w-3.5 h-3.5 text-emerald-600" /> Detaylı Ürün & Hizmet Kataloğu ({caps.extractedProducts?.length || 0})
|
||||
</span>
|
||||
<span className="text-[10px] text-emerald-700 font-semibold">Sayfadan Ayıklanan Detaylı Kalemler</span>
|
||||
</span>
|
||||
|
||||
{/* Add Custom Item Form */}
|
||||
<form onSubmit={handleAddCustomProduct} className="flex gap-2">
|
||||
<input
|
||||
type="text"
|
||||
value={newProductInput}
|
||||
onChange={(e) => setNewProductInput(e.target.value)}
|
||||
placeholder="+ Yeni Ürün / İhale Kalemi Ekle..."
|
||||
className="flex-1 bg-white border border-slate-300 rounded-lg px-3 py-1.5 text-xs text-slate-900 font-semibold focus:ring-2 focus:ring-emerald-500"
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
className="bg-emerald-600 hover:bg-emerald-500 text-white font-bold px-3 py-1.5 rounded-lg text-xs transition-colors shrink-0"
|
||||
>
|
||||
Ekle
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-1.5">
|
||||
{caps.extractedProducts?.map((p, i) => (
|
||||
<div key={i} className="text-xs font-semibold text-slate-700 bg-white border border-slate-200 p-2 rounded-lg flex items-start gap-1.5">
|
||||
<span className="shrink-0 text-emerald-600 font-bold">📦</span>
|
||||
<span className="line-clamp-2">{p}</span>
|
||||
<div key={i} className="text-xs font-semibold text-slate-700 bg-white border border-slate-200 p-2 rounded-lg flex items-start justify-between gap-1.5 group">
|
||||
<div className="flex items-start gap-1.5">
|
||||
<span className="shrink-0 text-emerald-600 font-bold">📦</span>
|
||||
<span className="line-clamp-2">{p}</span>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleRemoveProduct(i)}
|
||||
className="text-slate-300 hover:text-red-600 transition-colors p-0.5 shrink-0"
|
||||
title="Ürünü Kaldır"
|
||||
>
|
||||
<X className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@@ -200,6 +257,13 @@ export const CompanyScannerModal = () => {
|
||||
{caps.extractedCertifications?.map((c, i) => (
|
||||
<span key={i} className="text-xs font-semibold text-purple-900 bg-purple-100/70 border border-purple-200 px-3 py-1 rounded-lg flex items-center gap-1.5">
|
||||
📜 {c}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => handleRemoveCert(i)}
|
||||
className="text-purple-400 hover:text-red-600 transition-colors"
|
||||
>
|
||||
<X className="w-3 h-3" />
|
||||
</button>
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user