mirror of
https://github.com/thecyberlearn/Victor-AI-Hub.git
synced 2026-08-18 09:53:04 +00:00
1245 lines
51 KiB
HTML
1245 lines
51 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Trade Intelligence - AI Trade Management</title>
|
||
<script src="https://cdn.tailwindcss.com"></script>
|
||
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
||
|
||
<style>
|
||
body {
|
||
font-family: 'Plus Jakarta Sans', sans-serif;
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
min-height: 100vh;
|
||
}
|
||
|
||
.card-hover {
|
||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||
}
|
||
|
||
.card-hover:hover {
|
||
transform: translateY(-4px);
|
||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
@keyframes fadeIn {
|
||
from { opacity: 0; transform: translateY(20px); }
|
||
to { opacity: 1; transform: translateY(0); }
|
||
}
|
||
|
||
.fade-in {
|
||
animation: fadeIn 0.4s ease-out;
|
||
}
|
||
|
||
.custom-scrollbar::-webkit-scrollbar {
|
||
width: 4px;
|
||
}
|
||
|
||
.custom-scrollbar::-webkit-scrollbar-track {
|
||
background: rgba(255, 255, 255, 0.1);
|
||
border-radius: 2px;
|
||
}
|
||
|
||
.custom-scrollbar::-webkit-scrollbar-thumb {
|
||
background: rgba(255, 255, 255, 0.3);
|
||
border-radius: 2px;
|
||
}
|
||
|
||
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
|
||
background: rgba(255, 255, 255, 0.5);
|
||
}
|
||
|
||
.loading-skeleton {
|
||
background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
|
||
background-size: 200% 100%;
|
||
animation: loading 1.5s infinite;
|
||
}
|
||
|
||
@keyframes loading {
|
||
0% { background-position: 200% 0; }
|
||
100% { background-position: -200% 0; }
|
||
}
|
||
|
||
@keyframes slideUp {
|
||
from { opacity: 0; transform: translateY(20px); }
|
||
to { opacity: 1; transform: translateY(0); }
|
||
}
|
||
|
||
@keyframes fadeLine {
|
||
from { opacity: 0; }
|
||
to { opacity: 1; }
|
||
}
|
||
|
||
.animate-slide-up {
|
||
animation: slideUp 0.4s ease-out;
|
||
}
|
||
|
||
.animate-fade {
|
||
animation: fadeLine 0.6s ease-in;
|
||
}
|
||
|
||
.toast {
|
||
position: fixed;
|
||
bottom: 1rem;
|
||
right: 1rem;
|
||
z-index: 9999;
|
||
max-width: 24rem;
|
||
width: 100%;
|
||
animation: slideUp 0.3s ease-out;
|
||
}
|
||
|
||
@media (max-width: 640px) {
|
||
.toast {
|
||
left: 1rem;
|
||
right: 1rem;
|
||
max-width: none;
|
||
}
|
||
}
|
||
/* Mobile-specific styles */
|
||
@media (max-width: 768px) {
|
||
.mobile-stats-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 0.5rem;
|
||
}
|
||
}
|
||
|
||
/* Collapsible styles */
|
||
.collapsible-content {
|
||
max-height: 0;
|
||
overflow: hidden;
|
||
transition: max-height 0.3s ease;
|
||
}
|
||
|
||
.collapsible-content.open {
|
||
max-height: 200px;
|
||
}
|
||
</style>
|
||
</head>
|
||
|
||
<body>
|
||
<!-- Navigation Header -->
|
||
<nav class="bg-white shadow-sm border-b sticky top-0 z-50">
|
||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||
<div class="flex justify-between items-center py-4">
|
||
<div class="flex items-center gap-3">
|
||
<button onclick="goHome()" class="w-10 h-10 bg-indigo-100 rounded-lg flex items-center justify-center hover:bg-indigo-200 transition-colors">
|
||
<i class="fas fa-home text-indigo-600"></i>
|
||
</button>
|
||
<div class="w-10 h-10 bg-blue-600 rounded-xl flex items-center justify-center shadow-lg">
|
||
<i class="fas fa-ship text-white text-lg"></i>
|
||
</div>
|
||
<div>
|
||
<h1 class="text-lg font-bold text-gray-800">Trade Intelligence</h1>
|
||
<p class="text-sm text-gray-500">Victor AI Agent</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="hidden md:flex items-center gap-6">
|
||
<div class="text-right">
|
||
<p class="text-sm text-gray-500">Last updated</p>
|
||
<p class="font-semibold text-gray-800" id="lastUpdated">Just now</p>
|
||
</div>
|
||
<div class="flex items-center gap-2">
|
||
<div class="w-2 h-2 bg-green-400 rounded-full animate-pulse"></div>
|
||
<span class="text-sm text-green-600 font-medium">Online</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
|
||
<!-- Main Content -->
|
||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6 bg-gray-50 min-h-screen">
|
||
|
||
<!-- Header Section -->
|
||
<div class="text-center mb-8">
|
||
<h1 class="text-3xl lg:text-4xl font-bold text-gray-800 mb-4">AI Trade Intelligence</h1>
|
||
<p class="text-xl text-gray-600 max-w-2xl mx-auto">
|
||
Find exporters, importers, and trade data from around the world. Search our comprehensive database of companies with natural language commands.
|
||
</p>
|
||
</div>
|
||
|
||
<!-- Search Command Center -->
|
||
<div class="bg-white rounded-2xl p-6 mb-8 shadow-lg border border-gray-200">
|
||
<div class="flex items-center gap-3 mb-4">
|
||
<div class="w-10 h-10 bg-blue-600 rounded-lg flex items-center justify-center">
|
||
<i class="fas fa-brain text-white"></i>
|
||
</div>
|
||
<h2 class="text-xl font-bold text-gray-800">Trade AI Command</h2>
|
||
</div>
|
||
|
||
<div class="flex flex-col sm:flex-row gap-3">
|
||
<div class="flex-1">
|
||
<input
|
||
id="query"
|
||
type="text"
|
||
placeholder="Ask AI: 'find exporter from india', 'find importer from uk', 'find gulfood data'"
|
||
class="w-full px-4 py-3 rounded-xl border border-gray-300 bg-white text-gray-800 placeholder-gray-500 focus:border-blue-400 focus:ring-2 focus:ring-blue-400/50 outline-none transition-all"
|
||
/>
|
||
</div>
|
||
<button
|
||
onclick="callWorkflow()"
|
||
class="w-full sm:w-auto bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-xl font-semibold transition-all flex items-center justify-center gap-2 min-w-[120px]"
|
||
id="searchBtn"
|
||
>
|
||
<i class="fas fa-search"></i>
|
||
<span>Search</span>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Quick Commands -->
|
||
<div class="mt-4 flex flex-wrap gap-2">
|
||
<span class="text-sm text-gray-500 mr-2">Quick searches:</span>
|
||
<button onclick="setQuickSearch('find exporter from india')" class="text-xs bg-blue-100 hover:bg-blue-200 text-blue-700 px-3 py-1 rounded-full transition-colors">
|
||
Exporters from India
|
||
</button>
|
||
<button onclick="setQuickSearch('find importer from uk')" class="text-xs bg-blue-100 hover:bg-blue-200 text-blue-700 px-3 py-1 rounded-full transition-colors">
|
||
UK Importers
|
||
</button>
|
||
<button onclick="setQuickSearch('find gulfood data')" class="text-xs bg-blue-100 hover:bg-blue-200 text-blue-700 px-3 py-1 rounded-full transition-colors">
|
||
Gulfood Exhibition
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- CRUD Command Section -->
|
||
<div class="hidden lg:block bg-white rounded-2xl p-6 mb-8 shadow-lg border border-gray-200 fade-up">
|
||
<div class="flex items-center gap-3 mb-4">
|
||
<div class="w-10 h-10 bg-blue-600 rounded-lg flex items-center justify-center">
|
||
<i class="fas fa-terminal text-white"></i>
|
||
</div>
|
||
<h2 class="text-xl font-bold text-gray-800">Create / Update / Delete</h2>
|
||
</div>
|
||
|
||
<div class="flex flex-col sm:flex-row gap-3">
|
||
<div class="flex-1">
|
||
<input
|
||
id="crudCommand"
|
||
type="text"
|
||
placeholder="e.g., Create importer TechCorp from India email info@techcorp.com"
|
||
class="w-full px-4 py-3 rounded-xl border border-gray-300 bg-white text-gray-800 placeholder-gray-500 focus:border-blue-400 focus:ring-2 focus:ring-blue-400/50 outline-none transition-all"
|
||
/>
|
||
</div>
|
||
<button
|
||
onclick="callCrudOperation()"
|
||
class="w-full sm:w-auto bg-blue-600 hover:bg-blue-700 text-white px-6 py-3 rounded-xl font-semibold transition-all flex items-center justify-center gap-2 min-w-[120px]"
|
||
id="crudBtn"
|
||
>
|
||
<i class="fas fa-terminal"></i>
|
||
<span>Execute</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Mobile Stats Cards (visible only on mobile) -->
|
||
<div class="lg:hidden mb-6">
|
||
<div class="mobile-stats-grid">
|
||
<div class="bg-white rounded-xl p-3 shadow-sm border border-gray-200 text-center">
|
||
<div class="w-8 h-8 bg-blue-100 rounded-lg flex items-center justify-center mx-auto mb-2">
|
||
<i class="fas fa-search text-blue-600"></i>
|
||
</div>
|
||
<p class="text-xs text-gray-500 mb-1">Total Searches</p>
|
||
<p class="text-sm font-bold text-gray-800" id="mobileSearches">0</p>
|
||
</div>
|
||
|
||
<div class="bg-white rounded-xl p-3 shadow-sm border border-gray-200 text-center">
|
||
<div class="w-8 h-8 bg-green-100 rounded-lg flex items-center justify-center mx-auto mb-2">
|
||
<i class="fas fa-chart-line text-green-600"></i>
|
||
</div>
|
||
<p class="text-xs text-gray-500 mb-1">Results Found</p>
|
||
<p class="text-sm font-bold text-gray-800" id="mobileResults">0</p>
|
||
</div>
|
||
|
||
<div class="bg-white rounded-xl p-3 shadow-sm border border-gray-200 text-center">
|
||
<div class="w-8 h-8 bg-purple-100 rounded-lg flex items-center justify-center mx-auto mb-2">
|
||
<i class="fas fa-globe text-purple-600"></i>
|
||
</div>
|
||
<p class="text-xs text-gray-500 mb-1">Countries</p>
|
||
<p class="text-sm font-bold text-gray-800">150+</p>
|
||
</div>
|
||
|
||
<div class="bg-white rounded-xl p-3 shadow-sm border border-gray-200 text-center">
|
||
<div class="w-8 h-8 bg-orange-100 rounded-lg flex items-center justify-center mx-auto mb-2">
|
||
<i class="fas fa-bolt text-orange-600"></i>
|
||
</div>
|
||
<p class="text-xs text-gray-500 mb-1">Response Time</p>
|
||
<p class="text-sm font-bold text-gray-800" id="mobileResponseTime">0ms</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Mobile Collapsible CRUD Section -->
|
||
<div class="lg:hidden mb-6">
|
||
<div class="bg-white rounded-xl shadow-sm border border-gray-200">
|
||
<button
|
||
id="mobileCrudToggle"
|
||
onclick="toggleMobileCrud()"
|
||
class="w-full p-4 flex items-center justify-between text-left"
|
||
>
|
||
<div class="flex items-center gap-3">
|
||
<div class="w-10 h-10 bg-purple-100 rounded-lg flex items-center justify-center">
|
||
<i class="fas fa-terminal text-purple-600 text-lg"></i>
|
||
</div>
|
||
<div>
|
||
<h3 class="font-semibold text-gray-800">Create / Update / Delete</h3>
|
||
<p class="text-xs text-gray-500">Execute CRUD operations</p>
|
||
</div>
|
||
</div>
|
||
<i class="fas fa-chevron-down text-gray-400 transition-transform" id="crudChevron"></i>
|
||
</button>
|
||
|
||
<div id="mobileCrudContent" class="collapsible-content">
|
||
<div class="px-4 pb-4">
|
||
<div class="flex flex-col gap-3">
|
||
<input
|
||
id="mobileCrudCommand"
|
||
type="text"
|
||
placeholder="e.g., Create importer TechCorp from India email info@techcorp.com"
|
||
class="w-full px-4 py-3 rounded-xl border border-gray-300 focus:border-purple-500 focus:ring-2 focus:ring-purple-200 outline-none transition-all text-sm"
|
||
/>
|
||
<button
|
||
onclick="callMobileCrudOperation()"
|
||
class="w-full bg-purple-600 hover:bg-purple-700 text-white px-6 py-3 rounded-xl font-semibold transition-all flex items-center justify-center gap-2"
|
||
id="mobileCrudBtn"
|
||
>
|
||
<i class="fas fa-terminal"></i>
|
||
<span>Execute</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Stats Dashboard -->
|
||
<div class="hidden lg:grid grid grid-cols-2 lg:grid-cols-4 gap-4 mb-8">
|
||
<div class="bg-white rounded-xl p-4 shadow-lg border border-gray-200">
|
||
<div class="text-center">
|
||
<div class="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center mx-auto mb-2">
|
||
<i class="fas fa-search text-blue-600"></i>
|
||
</div>
|
||
<div class="text-2xl font-bold text-gray-800" id="totalSearches">0</div>
|
||
<div class="text-sm text-gray-500">Total Searches</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="bg-white rounded-xl p-4 shadow-lg border border-gray-200">
|
||
<div class="text-center">
|
||
<div class="w-10 h-10 bg-green-100 rounded-lg flex items-center justify-center mx-auto mb-2">
|
||
<i class="fas fa-chart-line text-green-600"></i>
|
||
</div>
|
||
<div class="text-2xl font-bold text-gray-800" id="totalResults">0</div>
|
||
<div class="text-sm text-gray-500">Results Found</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="bg-white rounded-xl p-4 shadow-lg border border-gray-200">
|
||
<div class="text-center">
|
||
<div class="w-10 h-10 bg-purple-100 rounded-lg flex items-center justify-center mx-auto mb-2">
|
||
<i class="fas fa-globe text-purple-600"></i>
|
||
</div>
|
||
<div class="text-2xl font-bold text-gray-800">150+</div>
|
||
<div class="text-sm text-gray-500">Countries</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="bg-white rounded-xl p-4 shadow-lg border border-gray-200">
|
||
<div class="text-center">
|
||
<div class="w-10 h-10 bg-orange-100 rounded-lg flex items-center justify-center mx-auto mb-2">
|
||
<i class="fas fa-bolt text-orange-600"></i>
|
||
</div>
|
||
<div class="text-2xl font-bold text-gray-800" id="responseTime">0ms</div>
|
||
<div class="text-sm text-gray-500">Response Time</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Main Content Grid -->
|
||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||
|
||
<!-- Results Section -->
|
||
<div class="lg:col-span-2">
|
||
<!-- Results will show here -->
|
||
<div id="resultsSection" class="hidden">
|
||
<div class="bg-white rounded-2xl p-6 shadow-lg border border-gray-200">
|
||
<div class="flex items-center justify-between mb-6">
|
||
<h3 class="text-xl font-bold text-gray-800">Search Results</h3>
|
||
<div class="flex items-center gap-2">
|
||
<p id="resultsCount" class="text-sm text-gray-600"></p>
|
||
<button onclick="exportResults()" class="text-sm bg-gray-100 hover:bg-gray-200 text-gray-700 px-3 py-2 rounded-lg transition-colors flex items-center gap-2">
|
||
<i class="fas fa-download text-xs"></i>
|
||
Export
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="results" class="grid grid-cols-1 gap-4 custom-scrollbar max-h-dvh overflow-y-auto"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Empty State -->
|
||
<div id="emptyState" class="bg-white rounded-2xl p-8 shadow-lg border border-gray-200">
|
||
<div class="text-center">
|
||
<div class="w-20 h-20 bg-blue-100 rounded-full flex items-center justify-center mx-auto mb-6">
|
||
<i class="fas fa-ship text-blue-600 text-2xl"></i>
|
||
</div>
|
||
<h3 class="text-xl font-semibold text-gray-800 mb-3">Start Your Trade Search</h3>
|
||
<p class="text-gray-600 mb-6">Enter your search query above to find exporters, importers, and trade data from our comprehensive database.</p>
|
||
|
||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4 text-sm">
|
||
<div class="bg-gray-50 p-4 rounded-lg border border-gray-200">
|
||
<h4 class="font-medium text-gray-800 mb-2">🚢 Find Exporters</h4>
|
||
<p class="text-gray-600">Search by country, product, or company name</p>
|
||
</div>
|
||
<div class="bg-gray-50 p-4 rounded-lg border border-gray-200">
|
||
<h4 class="font-medium text-gray-800 mb-2">📦 Find Importers</h4>
|
||
<p class="text-gray-600">Discover potential buyers worldwide</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- AI Actions Panel -->
|
||
<div class="space-y-6">
|
||
|
||
<!-- Quick Actions -->
|
||
<div class="bg-white rounded-2xl p-6 shadow-lg border border-gray-200">
|
||
<h3 class="text-lg font-bold text-gray-800 mb-4">Quick Actions</h3>
|
||
<div class="space-y-3">
|
||
<button onclick="quickSearch('all importers')" class="w-full p-3 bg-blue-600 hover:bg-blue-700 rounded-lg text-white font-medium transition-colors flex items-center gap-3">
|
||
<i class="fas fa-search"></i>
|
||
<span>All Importers</span>
|
||
</button>
|
||
<button onclick="quickSearch('all exporters')" class="w-full p-3 bg-green-600 hover:bg-green-700 rounded-lg text-white font-medium transition-colors flex items-center gap-3">
|
||
<i class="fas fa-ship"></i>
|
||
<span>All Exporters</span>
|
||
</button>
|
||
<button onclick="quickSearch('gulfood data')" class="w-full p-3 bg-orange-600 hover:bg-orange-700 rounded-lg text-white font-medium transition-colors flex items-center gap-3">
|
||
<i class="fas fa-globe"></i>
|
||
<span>Gulfood Data</span>
|
||
</button>
|
||
<button onclick="clearResults()" class="w-full p-3 bg-gray-600 hover:bg-gray-700 rounded-lg text-white font-medium transition-colors flex items-center gap-3">
|
||
<i class="fas fa-broom"></i>
|
||
<span>Clear Results</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Trade Insights -->
|
||
<div class="bg-white rounded-2xl p-6 shadow-lg border border-gray-200">
|
||
<h3 class="text-lg font-bold text-gray-800 mb-4">Trade Insights</h3>
|
||
<div class="space-y-4">
|
||
<div class="bg-blue-50 rounded-lg p-3 border border-blue-200">
|
||
<h4 class="font-medium text-blue-700 mb-1">Database Size</h4>
|
||
<p class="text-sm text-blue-600">50K+ companies across 150+ countries</p>
|
||
</div>
|
||
<div class="bg-green-50 rounded-lg p-3 border border-green-200">
|
||
<h4 class="font-medium text-green-700 mb-1">Data Freshness</h4>
|
||
<p class="text-sm text-green-600">Updated weekly with new trade data</p>
|
||
</div>
|
||
<div class="bg-orange-50 rounded-lg p-3 border border-orange-200">
|
||
<h4 class="font-medium text-orange-700 mb-1">AI Powered</h4>
|
||
<p class="text-sm text-orange-600">Natural language search capabilities</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Recent Searches -->
|
||
<div class="bg-white rounded-2xl p-6 shadow-lg border border-gray-200">
|
||
<h3 class="text-lg font-bold text-gray-800 mb-4">Recent Activity</h3>
|
||
<div class="space-y-3 custom-scrollbar max-h-48 overflow-y-auto" id="recentActivity">
|
||
<div class="flex items-start gap-3 p-2 bg-gray-50 rounded-lg">
|
||
<div class="w-6 h-6 bg-blue-100 rounded flex items-center justify-center flex-shrink-0 mt-1">
|
||
<i class="fas fa-search text-blue-600 text-xs"></i>
|
||
</div>
|
||
<div class="flex-1 min-w-0">
|
||
<p class="text-sm text-gray-800">Start searching to see activity</p>
|
||
<p class="text-xs text-gray-500">Your recent searches will appear here</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- AI Response Modal -->
|
||
<div id="aiModal" class="hidden fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center p-4">
|
||
<div class="bg-white rounded-2xl max-w-2xl w-full max-h-[80vh] overflow-hidden">
|
||
<div class="p-6 border-b border-gray-200">
|
||
<div class="flex items-center justify-between">
|
||
<div class="flex items-center gap-3">
|
||
<div class="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center">
|
||
<i class="fas fa-robot text-blue-600"></i>
|
||
</div>
|
||
<h3 class="text-lg font-bold text-gray-800">Trade AI Response</h3>
|
||
</div>
|
||
<button onclick="closeAIModal()" class="text-gray-400 hover:text-gray-600">
|
||
<i class="fas fa-times"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="p-6 overflow-y-auto custom-scrollbar" id="aiResponse">
|
||
<!-- AI response content will be loaded here -->
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// Navigation function
|
||
function goHome() {
|
||
if (confirm('Return to AI Services Hub?')) {
|
||
alert('Navigating to AI Services Hub...\n\nIn production, this would load: index.html');
|
||
}
|
||
}
|
||
|
||
// Global variables
|
||
let totalSearchCount = 0;
|
||
let totalResultCount = 0;
|
||
let currentSearchData = [];
|
||
|
||
// Initialize
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
updateLastUpdated();
|
||
initializeEventListeners();
|
||
});
|
||
|
||
function initializeEventListeners() {
|
||
document.getElementById('query').addEventListener('keypress', function(e) {
|
||
if (e.key === 'Enter') {
|
||
callWorkflow();
|
||
}
|
||
});
|
||
|
||
document.getElementById('crudCommand').addEventListener('keypress', function(e) {
|
||
if (e.key === 'Enter') {
|
||
callCrudOperation();
|
||
}
|
||
});
|
||
}
|
||
|
||
function updateLastUpdated() {
|
||
document.getElementById('lastUpdated').textContent = new Date().toLocaleTimeString();
|
||
}
|
||
|
||
function setQuickSearch(query) {
|
||
document.getElementById('query').value = query;
|
||
callWorkflow();
|
||
}
|
||
|
||
function quickSearch(type) {
|
||
const queries = {
|
||
'all importers': 'find all importers',
|
||
'all exporters': 'find all exporters',
|
||
'gulfood data': 'find gulfood data'
|
||
};
|
||
|
||
if (queries[type]) {
|
||
document.getElementById('query').value = queries[type];
|
||
callWorkflow();
|
||
}
|
||
}
|
||
|
||
// Enhanced search function
|
||
async function callWorkflow() {
|
||
const query = document.getElementById('query').value.trim();
|
||
if (!query) {
|
||
showToast('Please enter a search query', 'warning');
|
||
return;
|
||
}
|
||
|
||
const searchBtn = document.getElementById('searchBtn');
|
||
const results = document.getElementById('results');
|
||
const resultsSection = document.getElementById('resultsSection');
|
||
const resultsCount = document.getElementById('resultsCount');
|
||
const emptyState = document.getElementById('emptyState');
|
||
|
||
// Show loading state
|
||
searchBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Searching...';
|
||
searchBtn.disabled = true;
|
||
resultsSection.classList.add('hidden');
|
||
emptyState.classList.add('hidden');
|
||
|
||
// Show loading skeleton
|
||
results.innerHTML = Array(6).fill().map(() => `
|
||
<div class="bg-gray-50 rounded-lg p-4 border border-gray-200">
|
||
<div class="animate-pulse">
|
||
<div class="flex items-center gap-3 mb-3">
|
||
<div class="w-8 h-6 bg-gray-200 rounded"></div>
|
||
<div class="h-5 bg-gray-200 rounded flex-1"></div>
|
||
</div>
|
||
<div class="space-y-2">
|
||
<div class="h-4 bg-gray-200 rounded w-3/4"></div>
|
||
<div class="h-4 bg-gray-200 rounded w-1/2"></div>
|
||
<div class="h-4 bg-gray-200 rounded w-2/3"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
`).join('');
|
||
resultsSection.classList.remove('hidden');
|
||
|
||
const startTime = Date.now();
|
||
|
||
try {
|
||
console.log('Making API request with query:', query);
|
||
|
||
const response = await fetch(`https://thecyberlearn.app.n8n.cloud/webhook/search-airtable?query=${encodeURIComponent(query)}`, {
|
||
method: 'GET',
|
||
headers: { 'Accept': 'application/json' }
|
||
});
|
||
|
||
console.log('Response status:', response.status);
|
||
|
||
if (!response.ok) {
|
||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||
}
|
||
|
||
const data = await response.json();
|
||
console.log('API Response:', data);
|
||
|
||
const responseTime = Date.now() - startTime;
|
||
|
||
// Process the API response
|
||
let cards = '';
|
||
let resultCount = 0;
|
||
|
||
if (data && Array.isArray(data) && data.length > 0) {
|
||
const apiData = data[0];
|
||
console.log('Processing API data:', apiData);
|
||
|
||
if (apiData.success && apiData.content) {
|
||
const messageContent = apiData.content.originalMessage || apiData.content.message;
|
||
console.log('Message content:', messageContent);
|
||
|
||
if (messageContent) {
|
||
const companies = parseApiResponse(messageContent);
|
||
resultCount = companies.length;
|
||
currentSearchData = companies;
|
||
|
||
companies.forEach((company, index) => {
|
||
cards += generateCompanyCard(company, index + 1);
|
||
});
|
||
}
|
||
}
|
||
} else if (data && data.success && data.content) {
|
||
// Handle single object response
|
||
const messageContent = data.content.originalMessage || data.content.message;
|
||
|
||
if (messageContent) {
|
||
const companies = parseApiResponse(messageContent);
|
||
resultCount = companies.length;
|
||
currentSearchData = companies;
|
||
|
||
companies.forEach((company, index) => {
|
||
cards += generateCompanyCard(company, index + 1);
|
||
});
|
||
}
|
||
}
|
||
|
||
// Update UI
|
||
updateStats(resultCount, responseTime);
|
||
addToRecentActivity(query, resultCount);
|
||
resultsCount.textContent = `Found ${resultCount} companies matching "${query}"`;
|
||
|
||
if (cards && resultCount > 0) {
|
||
results.innerHTML = cards;
|
||
resultsSection.classList.remove('hidden');
|
||
showToast(`Found ${resultCount} companies!`, 'success');
|
||
} else {
|
||
results.innerHTML = `
|
||
<div class="bg-white rounded-lg p-8 text-center border border-gray-200">
|
||
<div class="text-4xl mb-3">😔</div>
|
||
<p class="text-gray-600 font-semibold">No results found</p>
|
||
<p class="text-gray-500 text-sm mt-2">Try a different search term</p>
|
||
</div>`;
|
||
resultsSection.classList.remove('hidden');
|
||
showToast('No results found. Try a different search term.', 'warning');
|
||
}
|
||
|
||
} catch (error) {
|
||
console.error('Search error:', error);
|
||
|
||
let errorMessage = 'Search failed';
|
||
let errorDetail = 'Please check your connection and try again';
|
||
|
||
if (error.message.includes('401')) {
|
||
errorMessage = 'Authentication Error';
|
||
errorDetail = 'API authentication failed. Please contact support.';
|
||
} else if (error.message.includes('404')) {
|
||
errorMessage = 'Service Not Found';
|
||
errorDetail = 'The search service is currently unavailable.';
|
||
} else if (error.message.includes('Failed to fetch')) {
|
||
errorMessage = 'Connection Error';
|
||
errorDetail = 'Please check your internet connection.';
|
||
}
|
||
|
||
results.innerHTML = `
|
||
<div class="bg-red-50 border border-red-200 rounded-lg p-6 text-center">
|
||
<div class="text-red-600 text-2xl mb-3">⚠️</div>
|
||
<p class="text-red-700 font-semibold">${errorMessage}</p>
|
||
<p class="text-red-600 text-sm mt-2">${errorDetail}</p>
|
||
<button onclick="location.reload()" class="mt-4 bg-red-600 hover:bg-red-700 text-white px-4 py-2 rounded-lg text-sm transition-colors">
|
||
Refresh Page
|
||
</button>
|
||
</div>`;
|
||
resultsSection.classList.remove('hidden');
|
||
showToast(errorMessage, 'error');
|
||
} finally {
|
||
searchBtn.innerHTML = '<i class="fas fa-search"></i> <span>Search</span>';
|
||
searchBtn.disabled = false;
|
||
}
|
||
}
|
||
|
||
// CRUD operation function
|
||
async function callCrudOperation() {
|
||
const command = document.getElementById('crudCommand').value.trim();
|
||
if (!command) {
|
||
showToast('Please enter a CRUD command', 'warning');
|
||
return;
|
||
}
|
||
|
||
const crudBtn = document.getElementById('crudBtn');
|
||
crudBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Executing...';
|
||
crudBtn.disabled = true;
|
||
|
||
try {
|
||
const response = await fetch(`https://thecyberlearn.app.n8n.cloud/webhook/search-airtable?query=${encodeURIComponent(command)}`, {
|
||
method: 'GET',
|
||
headers: { 'Accept': 'application/json' }
|
||
});
|
||
|
||
if (!response.ok) {
|
||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||
}
|
||
|
||
const result = await response.json();
|
||
console.log('CRUD result:', result);
|
||
|
||
const raw = result?.content?.originalMessage || result?.content?.message || '✅ Operation completed.';
|
||
const clean = raw
|
||
.replace(/<[^>]*>/g, '')
|
||
.replace(/\*\*/g, '')
|
||
.replace(/Complete dataset returned.*included/gi, '')
|
||
.trim();
|
||
|
||
const operation = result?.operation || 'info';
|
||
const success = result?.success !== false;
|
||
|
||
// Show result in modal
|
||
showAIModal(`
|
||
<div class="space-y-4">
|
||
<h4 class="text-lg font-semibold text-gray-800">
|
||
${success ? '✅' : '❌'} CRUD Operation Result
|
||
</h4>
|
||
<div class="bg-${success ? 'green' : 'red'}-50 border border-${success ? 'green' : 'red'}-200 p-4 rounded-lg">
|
||
<p class="text-${success ? 'green' : 'red'}-700">${clean}</p>
|
||
</div>
|
||
</div>
|
||
`);
|
||
|
||
// Show toast notification
|
||
if (success) {
|
||
showToast('Operation completed successfully!', 'success');
|
||
} else {
|
||
showToast('Operation failed. Check the details.', 'error');
|
||
}
|
||
|
||
document.getElementById('crudCommand').value = '';
|
||
addToRecentActivity(command, 0, 'CRUD');
|
||
|
||
} catch (error) {
|
||
console.error('CRUD error:', error);
|
||
showAIModal(`
|
||
<div class="space-y-4">
|
||
<h4 class="text-lg font-semibold text-gray-800">❌ Operation Failed</h4>
|
||
<div class="bg-red-50 border border-red-200 p-4 rounded-lg">
|
||
<p class="text-red-700">Error: ${error.message}</p>
|
||
</div>
|
||
</div>
|
||
`);
|
||
showToast('CRUD operation failed', 'error');
|
||
} finally {
|
||
crudBtn.innerHTML = '<i class="fas fa-terminal"></i> <span>Execute</span>';
|
||
crudBtn.disabled = false;
|
||
}
|
||
}
|
||
|
||
// Fixed Parse API response function
|
||
function parseApiResponse(responseText) {
|
||
let companies = [];
|
||
|
||
try {
|
||
// Clean up the text and remove markdown/HTML formatting
|
||
let cleanText = responseText
|
||
.replace(/<[^>]*>/g, '') // Remove HTML tags
|
||
.replace(/\*\*/g, '') // Remove bold markdown
|
||
.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1') // Convert markdown links to plain text
|
||
.replace(/`([^`]+)`/g, '$1') // Remove code formatting
|
||
.replace(/🔍.*?🚢/g, '') // Remove search header with ship emoji
|
||
.replace(/🔍.*?📦/g, '') // Remove search header with package emoji
|
||
.replace(/📊.*?────+/g, '') // Remove stats line
|
||
.replace(/💡.*$/gm, '') // Remove suggestions
|
||
.trim();
|
||
|
||
console.log('Cleaned text:', cleanText.substring(0, 500));
|
||
|
||
// Split by numbered company entries (1. 2. 3. etc.)
|
||
const splitPattern = /\b(\d+)\.\s+/;
|
||
const parts = cleanText.split(splitPattern);
|
||
|
||
// Extract company blocks (every 3rd element after split)
|
||
const companyBlocks = [];
|
||
for (let i = 2; i < parts.length; i += 2) {
|
||
if (parts[i] && parts[i].trim()) {
|
||
companyBlocks.push(parts[i].trim());
|
||
}
|
||
}
|
||
|
||
console.log('Company blocks found:', companyBlocks.length);
|
||
|
||
companyBlocks.forEach((block, index) => {
|
||
if (!block || block.trim().length === 0) return;
|
||
|
||
console.log(`Processing block ${index + 1}:`, block.substring(0, 200));
|
||
|
||
const lines = block.split('\n').map(line => line.trim()).filter(line => line.length > 0);
|
||
|
||
// Extract company name (first line)
|
||
const companyName = lines[0] || '';
|
||
|
||
// Extract phone numbers (look for ☎️ emoji followed by numbers)
|
||
const phoneMatches = block.match(/☎️\s*([\d\s\-\(\)\.E\+]+)/g) || [];
|
||
const phone = phoneMatches[0] ? phoneMatches[0].replace(/☎️\s*/, '').trim() : '';
|
||
|
||
// Extract emails (look for 📧 emoji followed by email)
|
||
const emailMatches = block.match(/📧\s*([^\s\n]+@[^\s\n]+)/g) || [];
|
||
const email = emailMatches[0] ? emailMatches[0].replace(/📧\s*/, '').trim() : '';
|
||
|
||
// Fixed website extraction
|
||
const websiteMatches = block.match(/🔗\s*(https?:\/\/[^\s\n]+)/g) || [];
|
||
const website = websiteMatches[0] ? websiteMatches[0].replace(/🔗\s*/, '').replace(/\/$/, '') : '';
|
||
|
||
// Extract location (look for 📍 emoji followed by location)
|
||
const locationMatches = block.match(/📍\s*([^\n🔗📧☎️📦🏷️]+)/g) || [];
|
||
let location = 'Unknown';
|
||
|
||
if (locationMatches.length > 0) {
|
||
location = locationMatches[0].replace(/📍\s*/, '').trim();
|
||
}
|
||
|
||
// Fallback location detection
|
||
if (location === 'Unknown' || location.length < 2) {
|
||
if (block.includes('United Kingdom')) location = 'United Kingdom';
|
||
else if (block.includes('India')) location = 'India';
|
||
else if (block.includes('USA') || block.includes('United States')) location = 'USA';
|
||
else if (block.includes('UAE') || block.includes('Dubai')) location = 'UAE';
|
||
else if (block.includes('China')) location = 'China';
|
||
}
|
||
|
||
// Extract products (look for 📦 emoji)
|
||
const productMatches = block.match(/📦\s*([^\n🏷️]+)/g) || [];
|
||
const products = [];
|
||
|
||
productMatches.forEach(match => {
|
||
const productText = match.replace(/📦\s*/, '').trim();
|
||
const productList = productText.split(/[,&]/).map(p => p.trim()).filter(p => p.length > 0);
|
||
products.push(...productList);
|
||
});
|
||
|
||
// Extract brands (look for 🏷️ emoji)
|
||
const brandMatches = block.match(/🏷️\s*([^\n]+)/g) || [];
|
||
const brands = [];
|
||
|
||
brandMatches.forEach(match => {
|
||
const brandText = match.replace(/🏷️\s*/, '').trim();
|
||
const brandList = brandText.split(/[,&]/).map(b => b.trim()).filter(b => b.length > 0);
|
||
brands.push(...brandList);
|
||
});
|
||
|
||
// Combine products and brands
|
||
const allProducts = [...products, ...brands].slice(0, 8);
|
||
|
||
if (companyName && companyName.length > 0) {
|
||
companies.push({
|
||
name: companyName,
|
||
phone: phone,
|
||
email: email,
|
||
website: website,
|
||
address: location,
|
||
products: allProducts
|
||
});
|
||
}
|
||
});
|
||
|
||
console.log('Final parsed companies:', companies);
|
||
|
||
} catch (error) {
|
||
console.error('Error parsing API response:', error);
|
||
console.log('Raw response text:', responseText);
|
||
}
|
||
|
||
return companies;
|
||
}
|
||
|
||
// Generate company card
|
||
function generateCompanyCard(company, index) {
|
||
const location = company.address?.toLowerCase() || '';
|
||
let flagHtml = '';
|
||
|
||
if (location.includes('india')) {
|
||
flagHtml = '<div class="w-8 h-6 bg-gradient-to-b from-orange-400 via-white to-green-500 rounded border border-gray-300 relative"><div class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-4 h-4 border-2 border-blue-800 rounded-full"></div></div>';
|
||
} else if (location.includes('united kingdom') || location.includes('uk')) {
|
||
flagHtml = '<div class="w-8 h-6 bg-blue-800 rounded border border-gray-300 relative"><div class="absolute inset-0 bg-gradient-to-br from-red-600 via-white to-red-600" style="clip-path: polygon(0 0, 100% 0, 0 100%)"></div><div class="absolute inset-0 bg-gradient-to-bl from-red-600 via-white to-red-600" style="clip-path: polygon(100% 0, 100% 100%, 0 100%)"></div><div class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-1 h-full bg-red-600"></div><div class="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-full h-1 bg-red-600"></div></div>';
|
||
} else if (location.includes('usa') || location.includes('united states')) {
|
||
flagHtml = '<div class="w-8 h-6 bg-red-600 rounded border border-gray-300 relative"><div class="absolute top-0 left-0 w-3 h-3 bg-blue-800"></div><div class="absolute top-1 left-0 w-full h-0.5 bg-white"></div><div class="absolute top-2 left-0 w-full h-0.5 bg-white"></div></div>';
|
||
} else if (location.includes('uae') || location.includes('dubai')) {
|
||
flagHtml = '<div class="w-8 h-6 bg-gradient-to-b from-green-600 via-white via-black to-red-600 rounded border border-gray-300"></div>';
|
||
} else if (location.includes('china')) {
|
||
flagHtml = '<div class="w-8 h-6 bg-red-600 rounded border border-gray-300 relative"><div class="absolute top-1 left-1 text-yellow-400 text-xs">⭐</div></div>';
|
||
} else {
|
||
flagHtml = '<div class="w-8 h-6 bg-gray-300 rounded border border-gray-300 flex items-center justify-center text-xs">🌍</div>';
|
||
}
|
||
|
||
return `
|
||
<div class="bg-white rounded-lg p-4 border border-gray-200 hover:shadow-md transition-all duration-300 card-hover">
|
||
<div class="flex items-center gap-3 mb-3">
|
||
${flagHtml}
|
||
<h3 class="text-base font-bold text-blue-700 hover:text-blue-800 cursor-pointer line-clamp-2">${company.name}</h3>
|
||
</div>
|
||
|
||
<div class="space-y-2 text-sm text-gray-700">
|
||
${company.phone ? `
|
||
<div class="flex items-center gap-2">
|
||
<i class="fas fa-phone text-green-600 w-4"></i>
|
||
<span class="break-all">${company.phone}</span>
|
||
</div>
|
||
` : ''}
|
||
|
||
${company.email ? `
|
||
<div class="flex items-center gap-2">
|
||
<i class="fas fa-envelope text-blue-600 w-4"></i>
|
||
<a href="mailto:${company.email}" class="text-blue-600 hover:text-blue-800 break-all">${company.email}</a>
|
||
</div>
|
||
` : ''}
|
||
|
||
${company.website ? `
|
||
<div class="flex items-center gap-2">
|
||
<i class="fas fa-globe text-purple-600 w-4"></i>
|
||
<a href="${company.website}" class="text-blue-600 hover:text-blue-800 underline break-all" target="_blank" rel="noopener">${company.website}</a>
|
||
</div>
|
||
` : ''}
|
||
|
||
${company.address ? `
|
||
<div class="flex items-start gap-2">
|
||
<i class="fas fa-map-marker-alt text-red-600 w-4 mt-0.5"></i>
|
||
<span class="text-gray-600">${company.address}</span>
|
||
</div>
|
||
` : ''}
|
||
</div>
|
||
|
||
${company.products && company.products.length > 0 ? `
|
||
<div class="mt-3 flex flex-wrap gap-1">
|
||
${company.products.slice(0, 3).map(product => `
|
||
<span class="bg-blue-50 text-blue-700 px-2 py-1 rounded-full text-xs font-medium">${product}</span>
|
||
`).join('')}
|
||
${company.products.length > 3 ? `
|
||
<span class="bg-gray-100 text-gray-600 px-2 py-1 rounded-full text-xs font-medium">+${company.products.length - 3} more</span>
|
||
` : ''}
|
||
</div>
|
||
` : ''}
|
||
|
||
<div class="mt-3 pt-3 border-t border-gray-100 flex gap-2">
|
||
<button onclick="viewCompanyDetails('${company.name.replace(/'/g, "\\'")}', ${index})" class="flex-1 bg-blue-600 text-white py-2 px-3 rounded-lg hover:bg-blue-700 transition-colors text-xs">
|
||
View Details
|
||
</button>
|
||
<button onclick="saveCompany('${company.name.replace(/'/g, "\\'")}', ${index})" class="px-3 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors text-xs">
|
||
<i class="fas fa-bookmark"></i>
|
||
</button>
|
||
<button onclick="shareCompany('${company.name.replace(/'/g, "\\'")}', ${index})" class="px-3 py-2 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors text-xs">
|
||
<i class="fas fa-share"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
// Update stats
|
||
function updateStats(resultCount, responseTime) {
|
||
totalSearchCount++;
|
||
totalResultCount += resultCount;
|
||
|
||
// Desktop stats
|
||
document.getElementById('totalSearches').textContent = totalSearchCount;
|
||
document.getElementById('totalResults').textContent = totalResultCount;
|
||
document.getElementById('responseTime').textContent = responseTime + 'ms';
|
||
|
||
// Mobile stats
|
||
document.getElementById('mobileSearches').textContent = totalSearchCount;
|
||
document.getElementById('mobileResults').textContent = totalResultCount;
|
||
document.getElementById('mobileResponseTime').textContent = responseTime + 'ms';
|
||
|
||
updateLastUpdated();
|
||
}
|
||
|
||
// Add to recent activity
|
||
function addToRecentActivity(query, resultCount, type = 'Search') {
|
||
const recentActivity = document.getElementById('recentActivity');
|
||
const time = new Date().toLocaleTimeString();
|
||
|
||
// Clear the default message if it exists
|
||
if (recentActivity.children.length === 1 && recentActivity.textContent.includes('Start searching')) {
|
||
recentActivity.innerHTML = '';
|
||
}
|
||
|
||
const activityItem = document.createElement('div');
|
||
activityItem.className = 'flex items-start gap-3 p-2 bg-gray-50 rounded-lg fade-in';
|
||
|
||
const icon = type === 'CRUD' ? 'fa-terminal' : 'fa-search';
|
||
const color = type === 'CRUD' ? 'purple' : 'blue';
|
||
|
||
activityItem.innerHTML = `
|
||
<div class="w-6 h-6 bg-${color}-100 rounded flex items-center justify-center flex-shrink-0 mt-1">
|
||
<i class="fas ${icon} text-${color}-600 text-xs"></i>
|
||
</div>
|
||
<div class="flex-1 min-w-0">
|
||
<p class="text-sm text-gray-800 truncate">${query}</p>
|
||
<p class="text-xs text-gray-500">${time} • ${type === 'CRUD' ? 'Operation' : resultCount + ' results'}</p>
|
||
</div>
|
||
`;
|
||
|
||
// Insert at the beginning and remove old items
|
||
recentActivity.insertBefore(activityItem, recentActivity.firstChild);
|
||
while (recentActivity.children.length > 5) {
|
||
recentActivity.removeChild(recentActivity.lastChild);
|
||
}
|
||
}
|
||
|
||
// Export functionality
|
||
function exportResults() {
|
||
if (currentSearchData.length === 0) {
|
||
showToast('No data to export', 'warning');
|
||
return;
|
||
}
|
||
|
||
const headers = ['Company Name', 'Phone', 'Email', 'Website', 'Address', 'Products'];
|
||
const csvContent = [
|
||
headers.join(','),
|
||
...currentSearchData.map(company => [
|
||
`"${company.name}"`,
|
||
`"${company.phone || ''}"`,
|
||
`"${company.email || ''}"`,
|
||
`"${company.website || ''}"`,
|
||
`"${company.address || ''}"`,
|
||
`"${(company.products || []).join('; ')}"`
|
||
].join(','))
|
||
].join('\n');
|
||
|
||
const blob = new Blob([csvContent], { type: 'text/csv' });
|
||
const url = window.URL.createObjectURL(blob);
|
||
const a = document.createElement('a');
|
||
a.href = url;
|
||
a.download = `trade_search_results_${new Date().toISOString().split('T')[0]}.csv`;
|
||
a.click();
|
||
window.URL.revokeObjectURL(url);
|
||
|
||
showToast('CSV file downloaded successfully!', 'success');
|
||
}
|
||
|
||
// Clear results
|
||
function clearResults() {
|
||
document.getElementById('resultsSection').classList.add('hidden');
|
||
document.getElementById('emptyState').classList.remove('hidden');
|
||
currentSearchData = [];
|
||
showToast('Results cleared', 'info');
|
||
}
|
||
|
||
// Company interaction functions
|
||
function viewCompanyDetails(companyName, index) {
|
||
const company = currentSearchData[index - 1];
|
||
if (company) {
|
||
showAIModal(`
|
||
<div class="space-y-4">
|
||
<h4 class="text-xl font-bold text-gray-800">${company.name}</h4>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
${company.phone ? `
|
||
<div class="bg-green-50 p-3 rounded-lg border border-green-200">
|
||
<h5 class="font-medium text-green-700">Phone</h5>
|
||
<p class="text-green-600">${company.phone}</p>
|
||
</div>
|
||
` : ''}
|
||
${company.email ? `
|
||
<div class="bg-blue-50 p-3 rounded-lg border border-blue-200">
|
||
<h5 class="font-medium text-blue-700">Email</h5>
|
||
<p class="text-blue-600">${company.email}</p>
|
||
</div>
|
||
` : ''}
|
||
${company.website ? `
|
||
<div class="bg-purple-50 p-3 rounded-lg border border-purple-200">
|
||
<h5 class="font-medium text-purple-700">Website</h5>
|
||
<p class="text-purple-600">${company.website}</p>
|
||
</div>
|
||
` : ''}
|
||
${company.address ? `
|
||
<div class="bg-gray-50 p-3 rounded-lg border border-gray-200">
|
||
<h5 class="font-medium text-gray-700">Location</h5>
|
||
<p class="text-gray-600">${company.address}</p>
|
||
</div>
|
||
` : ''}
|
||
</div>
|
||
${company.products && company.products.length > 0 ? `
|
||
<div class="bg-blue-50 p-3 rounded-lg border border-blue-200">
|
||
<h5 class="font-medium text-blue-700 mb-2">Products & Services</h5>
|
||
<div class="flex flex-wrap gap-2">
|
||
${company.products.map(product => `
|
||
<span class="bg-blue-100 text-blue-800 px-2 py-1 rounded-full text-sm">${product}</span>
|
||
`).join('')}
|
||
</div>
|
||
</div>
|
||
` : ''}
|
||
</div>
|
||
`);
|
||
}
|
||
}
|
||
|
||
function saveCompany(companyName, index) {
|
||
showToast(`${companyName} saved to favorites!`, 'success');
|
||
}
|
||
|
||
function shareCompany(companyName, index) {
|
||
const company = currentSearchData[index - 1];
|
||
if (navigator.share && company) {
|
||
navigator.share({
|
||
title: company.name,
|
||
text: `Check out this company: ${company.name}`,
|
||
url: window.location.href
|
||
});
|
||
} else {
|
||
const shareText = `${company.name}\n${company.email || ''}\n${company.phone || ''}`;
|
||
navigator.clipboard.writeText(shareText).then(() => {
|
||
showToast('Company info copied to clipboard!', 'success');
|
||
});
|
||
}
|
||
}
|
||
|
||
// Toast notification system
|
||
function showToast(message, type = 'info') {
|
||
const colors = {
|
||
success: 'bg-green-100 border-green-300 text-green-800',
|
||
error: 'bg-red-100 border-red-300 text-red-800',
|
||
warning: 'bg-yellow-100 border-yellow-300 text-yellow-800',
|
||
info: 'bg-blue-100 border-blue-300 text-blue-800'
|
||
};
|
||
|
||
const icons = {
|
||
success: 'fa-check-circle',
|
||
error: 'fa-times-circle',
|
||
warning: 'fa-exclamation-triangle',
|
||
info: 'fa-info-circle'
|
||
};
|
||
|
||
const toast = document.createElement('div');
|
||
toast.className = `toast ${colors[type]} border rounded-lg shadow-lg p-4`;
|
||
toast.innerHTML = `
|
||
<div class="flex items-center gap-3">
|
||
<i class="fas ${icons[type]} text-lg"></i>
|
||
<span class="font-medium">${message}</span>
|
||
<button onclick="this.parentElement.parentElement.remove()" class="ml-auto text-lg hover:opacity-70">×</button>
|
||
</div>
|
||
`;
|
||
|
||
document.body.appendChild(toast);
|
||
setTimeout(() => toast.remove(), 5000);
|
||
}
|
||
|
||
// Modal functions
|
||
function showAIModal(content) {
|
||
document.getElementById('aiResponse').innerHTML = content;
|
||
document.getElementById('aiModal').classList.remove('hidden');
|
||
}
|
||
|
||
function closeAIModal() {
|
||
document.getElementById('aiModal').classList.add('hidden');
|
||
}
|
||
|
||
// Mobile CRUD toggle function
|
||
function toggleMobileCrud() {
|
||
const content = document.getElementById('mobileCrudContent');
|
||
const chevron = document.getElementById('crudChevron');
|
||
|
||
if (content.classList.contains('open')) {
|
||
content.classList.remove('open');
|
||
chevron.style.transform = 'rotate(0deg)';
|
||
} else {
|
||
content.classList.add('open');
|
||
chevron.style.transform = 'rotate(180deg)';
|
||
}
|
||
}
|
||
|
||
// Mobile CRUD operation function
|
||
async function callMobileCrudOperation() {
|
||
const command = document.getElementById('mobileCrudCommand').value.trim();
|
||
if (!command) {
|
||
showToast('Please enter a CRUD command', 'warning');
|
||
return;
|
||
}
|
||
|
||
const crudBtn = document.getElementById('mobileCrudBtn');
|
||
crudBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Executing...';
|
||
crudBtn.disabled = true;
|
||
|
||
try {
|
||
// Use your existing CRUD logic here
|
||
const response = await fetch(`https://thecyberlearn.app.n8n.cloud/webhook/search-airtable?query=${encodeURIComponent(command)}`, {
|
||
method: 'GET',
|
||
headers: { 'Accept': 'application/json' }
|
||
});
|
||
|
||
if (!response.ok) {
|
||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||
}
|
||
|
||
const result = await response.json();
|
||
console.log('Mobile CRUD result:', result);
|
||
|
||
const raw = result?.content?.originalMessage || result?.content?.message || '✅ Operation completed.';
|
||
const clean = raw.replace(/<[^>]*>/g, '').replace(/\*\*/g, '').trim();
|
||
|
||
showToast('Operation completed successfully!', 'success');
|
||
document.getElementById('mobileCrudCommand').value = '';
|
||
|
||
// Auto-collapse after successful operation
|
||
document.getElementById('mobileCrudContent').classList.remove('open');
|
||
document.getElementById('crudChevron').style.transform = 'rotate(0deg)';
|
||
|
||
} catch (error) {
|
||
console.error('Mobile CRUD error:', error);
|
||
showToast('CRUD operation failed', 'error');
|
||
} finally {
|
||
crudBtn.innerHTML = '<i class="fas fa-terminal"></i> <span>Execute</span>';
|
||
crudBtn.disabled = false;
|
||
}
|
||
}
|
||
|
||
// Make functions globally available
|
||
window.callWorkflow = callWorkflow;
|
||
window.callCrudOperation = callCrudOperation;
|
||
window.setQuickSearch = setQuickSearch;
|
||
window.quickSearch = quickSearch;
|
||
window.exportResults = exportResults;
|
||
window.clearResults = clearResults;
|
||
window.viewCompanyDetails = viewCompanyDetails;
|
||
window.saveCompany = saveCompany;
|
||
window.shareCompany = shareCompany;
|
||
window.showAIModal = showAIModal;
|
||
window.closeAIModal = closeAIModal;
|
||
window.showToast = showToast;
|
||
window.goHome = goHome;
|
||
window.toggleMobileCrud = toggleMobileCrud;
|
||
window.callMobileCrudOperation = callMobileCrudOperation;
|
||
</script>
|
||
</body>
|
||
</html> |