Update index.html

login
This commit is contained in:
quantumtaskai 2025-06-16 17:43:55 +05:30 committed by GitHub
parent c82904860b
commit 5ff2248ed9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -94,10 +94,16 @@
<p class="text-sm text-white">Last updated</p> <p class="text-sm text-white">Last updated</p>
<p class="font-semibold text-white">6:08:40 AM</p> <p class="font-semibold text-white">6:08:40 AM</p>
</div> </div>
<div class="flex items-center gap-4">
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<div class="w-2 h-2 bg-green-400 rounded-full animate-pulse"></div> <div class="w-2 h-2 bg-green-400 rounded-full animate-pulse"></div>
<span class="text-sm text-green-600 font-medium text-white">Online</span> <span class="text-sm text-green-600 font-medium text-white">Online</span>
</div> </div>
<button onclick="logout()" class="text-sm text-white/80 hover:text-white px-3 py-1 rounded-lg hover:bg-white/10 transition-colors">
<i class="fas fa-sign-out-alt mr-1"></i>
Logout
</button>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -323,6 +329,56 @@
</div> </div>
</div> </div>
<!-- Login Screen -->
<div id="loginScreen" class="fixed inset-0 bg-gradient-to-br from-blue-600 to-purple-700 flex items-center justify-center z-50">
<div class="bg-white rounded-2xl p-8 shadow-2xl max-w-md w-full mx-4">
<div class="text-center mb-8">
<div class="w-16 h-16 bg-blue-600 rounded-xl flex items-center justify-center mx-auto mb-4">
<i class="fas fa-ship text-white text-2xl"></i>
</div>
<h1 class="text-2xl font-bold text-gray-800">Trade Intelligence</h1>
<p class="text-gray-600">Please sign in to continue</p>
</div>
<form id="loginForm" onsubmit="handleLogin(event)">
<div class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Username</label>
<input
type="text"
id="username"
required
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none"
placeholder="Enter username"
/>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Password</label>
<input
type="password"
id="password"
required
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none"
placeholder="Enter password"
/>
</div>
<div id="loginError" class="hidden bg-red-50 border border-red-200 rounded-lg p-3 text-red-700 text-sm">
Invalid username or password
</div>
<button
type="submit"
class="w-full bg-blue-600 hover:bg-blue-700 text-white py-3 px-4 rounded-lg font-semibold transition-colors"
>
Sign In
</button>
</div>
</form>
</div>
</div>
<!-- Toast Notification Container --> <!-- Toast Notification Container -->
<div id="toastContainer" class="fixed top-4 right-4 z-50 space-y-2"> <div id="toastContainer" class="fixed top-4 right-4 z-50 space-y-2">
<!-- Toast notifications will be dynamically added here --> <!-- Toast notifications will be dynamically added here -->
@ -388,6 +444,93 @@
</div> </div>
<script> <script>
// n8n Authentication System
const N8N_AUTH_WEBHOOK = 'https://m8taq6tk.rpcld.cc/webhook/login';
function checkAuthentication() {
const isAuthenticated = localStorage.getItem('authenticated');
const loginScreen = document.getElementById('loginScreen');
if (isAuthenticated === 'true') {
loginScreen.style.display = 'none';
return true;
} else {
loginScreen.style.display = 'flex';
return false;
}
}
async function handleLogin(event) {
event.preventDefault();
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
const errorDiv = document.getElementById('loginError');
const submitButton = event.target.querySelector('button[type="submit"]');
// Show loading state
const originalButtonText = submitButton.innerHTML;
submitButton.disabled = true;
submitButton.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i>Signing In...';
try {
console.log('Attempting login with n8n webhook...');
const response = await fetch(N8N_AUTH_WEBHOOK, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
"username": username,
"password": password
})
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const result = await response.json();
console.log('Authentication response:', result);
if (result.success === true) {
// Successful login
localStorage.setItem('authenticated', 'true');
localStorage.setItem('currentUser', result.username || username);
document.getElementById('loginScreen').style.display = 'none';
errorDiv.classList.add('hidden');
// Show success message
showToast(`Welcome back, ${result.username || username}!`, 'success');
// Initialize dashboard
initializeDashboard();
} else {
// Failed login
errorDiv.textContent = result.message || 'Invalid username or password';
errorDiv.classList.remove('hidden');
document.getElementById('password').value = '';
}
} catch (error) {
console.error('Login error:', error);
errorDiv.textContent = 'Login failed. Please check your connection and try again.';
errorDiv.classList.remove('hidden');
document.getElementById('password').value = '';
} finally {
// Reset button state
submitButton.disabled = false;
submitButton.innerHTML = originalButtonText;
}
}
function logout() {
localStorage.removeItem('authenticated');
localStorage.removeItem('currentUser');
location.reload();
}
// Check if required dependencies are loaded // Check if required dependencies are loaded
if (typeof supabase === 'undefined') { if (typeof supabase === 'undefined') {
console.error('Supabase library not loaded'); console.error('Supabase library not loaded');
@ -787,6 +930,7 @@ async function parseQueryWithAI(naturalQuery) {
// Fallback to simple keyword-based parsing // Fallback to simple keyword-based parsing
const fallbackResult = parseQueryFallback(naturalQuery); const fallbackResult = parseQueryFallback(naturalQuery);
console.log('🔄 Local fallback parsing result:', fallbackResult); console.log('🔄 Local fallback parsing result:', fallbackResult);
console.log('🔄 Fallback filters:', fallbackResult.filters);
return fallbackResult; return fallbackResult;
} }
} }
@ -819,7 +963,8 @@ function parseQueryFallback(query) {
} }
} }
// Product/brand filters // Product/brand filters (only for buyer/seller tables)
if (table !== "gulfood") {
const products = ["pepsi", "cosmetic", "fmcg", "food", "beverage"]; const products = ["pepsi", "cosmetic", "fmcg", "food", "beverage"];
for (const product of products) { for (const product of products) {
if (lowerQuery.includes(product)) { if (lowerQuery.includes(product)) {
@ -828,6 +973,7 @@ function parseQueryFallback(query) {
break; break;
} }
} }
}
return { table, filters }; return { table, filters };
} }
@ -912,6 +1058,10 @@ async function performSearch(loadMore = false) {
// Reset pagination if new search // Reset pagination if new search
if (!loadMore || searchState.query !== query) { if (!loadMore || searchState.query !== query) {
searchState = { query, page: 0, hasMore: false, results: [] }; searchState = { query, page: 0, hasMore: false, results: [] };
// Clear cache for new searches to ensure fresh data
if (searchState.query !== query) {
clearCache();
}
} }
// Show results section, hide initial state and product mapping // Show results section, hide initial state and product mapping
@ -931,6 +1081,9 @@ async function performSearch(loadMore = false) {
try { try {
const ai = await parseQueryWithAI(query); const ai = await parseQueryWithAI(query);
console.log('🔍 Search query:', query);
console.log('🔍 AI parsing result:', ai);
let newResults = []; let newResults = [];
let totalCount = 0; let totalCount = 0;
@ -938,12 +1091,22 @@ async function performSearch(loadMore = false) {
const [buyerRes, sellerRes, gulfoodRes] = await Promise.all([ const [buyerRes, sellerRes, gulfoodRes] = await Promise.all([
fetchFrom("buyer", ai.filters, searchState.page), fetchFrom("buyer", ai.filters, searchState.page),
fetchFrom("seller", ai.filters, searchState.page), fetchFrom("seller", ai.filters, searchState.page),
fetchFrom("gulfood", ai.filters, searchState.page) fetchFrom("gulfood", [], searchState.page) // No filters for gulfood since it has different fields
]); ]);
newResults = [...buyerRes.data, ...sellerRes.data, ...gulfoodRes.data]; newResults = [...buyerRes.data, ...sellerRes.data, ...gulfoodRes.data];
totalCount = buyerRes.count + sellerRes.count + gulfoodRes.count; totalCount = buyerRes.count + sellerRes.count + gulfoodRes.count;
searchState.hasMore = buyerRes.hasMore || sellerRes.hasMore || gulfoodRes.hasMore; searchState.hasMore = buyerRes.hasMore || sellerRes.hasMore || gulfoodRes.hasMore;
} else if (ai.table === "gulfood") {
// For gulfood table, don't apply country/brand/category filters
const gulfoodFilters = ai.filters.filter(f =>
["company_name", "address", "phone_number", "mail_id", "website"].includes(f.field)
);
console.log('🔍 Gulfood filters:', gulfoodFilters);
const result = await fetchFrom(ai.table, gulfoodFilters, searchState.page);
newResults = result.data;
totalCount = result.count;
searchState.hasMore = result.hasMore;
} else { } else {
const result = await fetchFrom(ai.table, ai.filters, searchState.page); const result = await fetchFrom(ai.table, ai.filters, searchState.page);
newResults = result.data; newResults = result.data;
@ -1073,17 +1236,17 @@ let countrySuggestionsTimeout;
async function loadAllCountries() { async function loadAllCountries() {
try { try {
// Fetch unique countries from all tables // Fetch unique countries from buyer and seller tables only
const [buyerCountries, sellerCountries, gulfoodCountries] = await Promise.all([ // Gulfood table doesn't have a 'country' field - it uses 'address'
const [buyerCountries, sellerCountries] = await Promise.all([
client.from('buyer').select('country').not('country', 'is', null), client.from('buyer').select('country').not('country', 'is', null),
client.from('seller').select('country').not('country', 'is', null), client.from('seller').select('country').not('country', 'is', null)
client.from('gulfood').select('country').not('country', 'is', null)
]); ]);
const countrySet = new Set(); const countrySet = new Set();
// Add countries from all tables // Add countries from buyer and seller tables
[...(buyerCountries.data || []), ...(sellerCountries.data || []), ...(gulfoodCountries.data || [])] [...(buyerCountries.data || []), ...(sellerCountries.data || [])]
.forEach(item => { .forEach(item => {
if (item.country && item.country.trim()) { if (item.country && item.country.trim()) {
countrySet.add(item.country.trim()); countrySet.add(item.country.trim());
@ -1654,8 +1817,7 @@ async function handleCreateSubmit(event) {
} }
} }
// Initialize function initializeDashboard() {
document.addEventListener('DOMContentLoaded', function() {
try { try {
console.log('Initializing dashboard...'); console.log('Initializing dashboard...');
@ -1683,6 +1845,14 @@ document.addEventListener('DOMContentLoaded', function() {
console.error('Initialization error:', error); console.error('Initialization error:', error);
alert('Failed to initialize dashboard. Please refresh the page.'); alert('Failed to initialize dashboard. Please refresh the page.');
} }
}
// Initialize
document.addEventListener('DOMContentLoaded', function() {
// Check authentication first
if (checkAuthentication()) {
initializeDashboard();
}
}); });
</script> </script>