mirror of
https://github.com/thecyberlearn/supa-tid.git
synced 2026-08-18 10:13:03 +00:00
Update index.html
This commit is contained in:
parent
ca1fbaba57
commit
95f70b8454
253
index.html
253
index.html
@ -6,7 +6,6 @@
|
|||||||
<title>Trade Intelligence - AI Trade Management</title>
|
<title>Trade Intelligence - AI Trade Management</title>
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
<script>
|
<script>
|
||||||
// Configure Tailwind for proper styling
|
|
||||||
tailwind.config = {
|
tailwind.config = {
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
@ -85,14 +84,14 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h1 class="text-lg font-bold text-white">Trade Intelligence</h1>
|
<h1 class="text-lg font-bold text-white">Trade Intelligence</h1>
|
||||||
<p class="text-sm text-white">Victor AI Agent</p>
|
<p class="text-sm text-white">AI Trade Intelligence</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="hidden md:flex items-center gap-6">
|
<div class="hidden md:flex items-center gap-6">
|
||||||
<div class="text-right">
|
<div class="text-right">
|
||||||
<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" id="lastUpdated"></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center gap-4">
|
<div class="flex items-center gap-4">
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
@ -444,8 +443,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// n8n Authentication System
|
// Authentication System
|
||||||
const N8N_AUTH_WEBHOOK = 'https://m8taq6tk.rpcld.cc/webhook/login';
|
const AUTH_WEBHOOK = 'https://m8taq6tk.rpcld.cc/webhook/login';
|
||||||
|
|
||||||
function checkAuthentication() {
|
function checkAuthentication() {
|
||||||
const isAuthenticated = localStorage.getItem('authenticated');
|
const isAuthenticated = localStorage.getItem('authenticated');
|
||||||
@ -474,9 +473,7 @@ async function handleLogin(event) {
|
|||||||
submitButton.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i>Signing In...';
|
submitButton.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i>Signing In...';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log('Attempting login with n8n webhook...');
|
const response = await fetch(AUTH_WEBHOOK, {
|
||||||
|
|
||||||
const response = await fetch(N8N_AUTH_WEBHOOK, {
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
@ -493,7 +490,6 @@ async function handleLogin(event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
console.log('Authentication response:', result);
|
|
||||||
|
|
||||||
if (result.success === true) {
|
if (result.success === true) {
|
||||||
// Successful login
|
// Successful login
|
||||||
@ -514,7 +510,6 @@ async function handleLogin(event) {
|
|||||||
document.getElementById('password').value = '';
|
document.getElementById('password').value = '';
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Login error:', error);
|
|
||||||
errorDiv.textContent = 'Login failed. Please check your connection and try again.';
|
errorDiv.textContent = 'Login failed. Please check your connection and try again.';
|
||||||
errorDiv.classList.remove('hidden');
|
errorDiv.classList.remove('hidden');
|
||||||
document.getElementById('password').value = '';
|
document.getElementById('password').value = '';
|
||||||
@ -533,12 +528,10 @@ function logout() {
|
|||||||
|
|
||||||
// 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');
|
|
||||||
alert('Failed to load Supabase. Please refresh the page.');
|
alert('Failed to load Supabase. Please refresh the page.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof APP_CONFIG === 'undefined') {
|
if (typeof APP_CONFIG === 'undefined') {
|
||||||
console.error('APP_CONFIG not loaded');
|
|
||||||
alert('Configuration not loaded. Please check config.js');
|
alert('Configuration not loaded. Please check config.js');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -549,6 +542,99 @@ const tableFields = {
|
|||||||
gulfood: ["company_name", "address", "phone_number", "mail_id", "website"]
|
gulfood: ["company_name", "address", "phone_number", "mail_id", "website"]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Validate and normalize AI-generated filters
|
||||||
|
function validateAndNormalizeFilters(filters) {
|
||||||
|
if (!filters || !Array.isArray(filters)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return filters.map(filter => {
|
||||||
|
// Ensure filter has required properties
|
||||||
|
if (!filter || typeof filter !== 'object') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normalize filter structure
|
||||||
|
const normalizedFilter = {
|
||||||
|
field: filter.field || 'all',
|
||||||
|
operator: filter.operator || 'ilike',
|
||||||
|
value: filter.value || ''
|
||||||
|
};
|
||||||
|
|
||||||
|
// If the value doesn't have % wildcards, add them
|
||||||
|
if (normalizedFilter.operator === 'ilike' && normalizedFilter.value &&
|
||||||
|
!normalizedFilter.value.startsWith('%') && !normalizedFilter.value.endsWith('%')) {
|
||||||
|
normalizedFilter.value = `%${normalizedFilter.value}%`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalizedFilter;
|
||||||
|
}).filter(filter => filter !== null); // Remove invalid filters
|
||||||
|
}
|
||||||
|
|
||||||
|
// Smart filter function for cross-table compatibility
|
||||||
|
function filterForTable(filters, tableName) {
|
||||||
|
const validFields = tableFields[tableName];
|
||||||
|
|
||||||
|
return filters.filter(filter => {
|
||||||
|
// Always include fields that exist in this table
|
||||||
|
if (validFields.includes(filter.field)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle cross-table company name searches
|
||||||
|
if (filter.field === 'buyer' && tableName === 'seller') {
|
||||||
|
// Map buyer field to seller field
|
||||||
|
filter.field = 'seller';
|
||||||
|
return true;
|
||||||
|
} else if (filter.field === 'seller' && tableName === 'buyer') {
|
||||||
|
// Map seller field to buyer field
|
||||||
|
filter.field = 'buyer';
|
||||||
|
return true;
|
||||||
|
} else if ((filter.field === 'buyer' || filter.field === 'seller') && tableName === 'gulfood') {
|
||||||
|
// Map buyer/seller field to company_name for gulfood
|
||||||
|
filter.field = 'company_name';
|
||||||
|
return true;
|
||||||
|
} else if (filter.field === 'company_name' && (tableName === 'buyer' || tableName === 'seller')) {
|
||||||
|
// Map company_name to appropriate field for buyer/seller tables
|
||||||
|
filter.field = tableName;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle generic company searches - create appropriate company name filter for each table
|
||||||
|
const companySearchFields = ['company', 'name', 'business_name', 'firm', 'entity', 'all'];
|
||||||
|
if (companySearchFields.includes(filter.field)) {
|
||||||
|
if (tableName === 'buyer') {
|
||||||
|
filter.field = 'buyer';
|
||||||
|
return true;
|
||||||
|
} else if (tableName === 'seller') {
|
||||||
|
filter.field = 'seller';
|
||||||
|
return true;
|
||||||
|
} else if (tableName === 'gulfood') {
|
||||||
|
filter.field = 'company_name';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CRITICAL: Handle when AI generates 'all' field for specific company searches
|
||||||
|
// This ensures we search ALL tables when looking for a specific company
|
||||||
|
if (filter.field === 'all') {
|
||||||
|
if (tableName === 'buyer') {
|
||||||
|
filter.field = 'buyer';
|
||||||
|
return true;
|
||||||
|
} else if (tableName === 'seller') {
|
||||||
|
filter.field = 'seller';
|
||||||
|
return true;
|
||||||
|
} else if (tableName === 'gulfood') {
|
||||||
|
filter.field = 'company_name';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exclude incompatible fields
|
||||||
|
return false;
|
||||||
|
}).map(filter => ({...filter})); // Clone to avoid modifying original
|
||||||
|
}
|
||||||
|
|
||||||
let editContext = { id: null, table: null };
|
let editContext = { id: null, table: null };
|
||||||
|
|
||||||
// Simple cache implementation
|
// Simple cache implementation
|
||||||
@ -740,7 +826,6 @@ async function submitModalEdit() {
|
|||||||
|
|
||||||
const { error } = await client.from(editContext.table).update(update).eq("id", editContext.id);
|
const { error } = await client.from(editContext.table).update(update).eq("id", editContext.id);
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error('Update error:', error);
|
|
||||||
showToast("Update failed: " + error.message, 'error');
|
showToast("Update failed: " + error.message, 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -754,15 +839,10 @@ async function submitModalEdit() {
|
|||||||
performSearch();
|
performSearch();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Submit edit error:', error);
|
|
||||||
showToast("Update failed: " + error.message, 'error');
|
showToast("Update failed: " + error.message, 'error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Event listener moved to DOMContentLoaded
|
|
||||||
|
|
||||||
|
|
||||||
function renderRecord(r) {
|
function renderRecord(r) {
|
||||||
const fields = tableFields[r.__table];
|
const fields = tableFields[r.__table];
|
||||||
const tableColors = {
|
const tableColors = {
|
||||||
@ -866,20 +946,17 @@ function renderRecord(r) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function parseQueryWithAI(naturalQuery) {
|
async function parseQueryWithAI(naturalQuery) {
|
||||||
// Check if n8n is configured
|
// Check if webhook is configured
|
||||||
if (!APP_CONFIG.useN8n || APP_CONFIG.n8nWebhookUrl === 'YOUR_N8N_WEBHOOK_URL_HERE') {
|
if (!APP_CONFIG.useWebhook || APP_CONFIG.webhookUrl === 'YOUR_WEBHOOK_URL_HERE') {
|
||||||
console.log('🔄 n8n not configured, using fallback parsing');
|
|
||||||
return parseQueryFallback(naturalQuery);
|
return parseQueryFallback(naturalQuery);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log('🤖 Parsing query with n8n AI:', naturalQuery);
|
|
||||||
|
|
||||||
// Add timeout and better error handling
|
// Add timeout and better error handling
|
||||||
const controller = new AbortController();
|
const controller = new AbortController();
|
||||||
const timeoutId = setTimeout(() => controller.abort(), 15000); // 15 second timeout for n8n
|
const timeoutId = setTimeout(() => controller.abort(), 15000); // 15 second timeout
|
||||||
|
|
||||||
const response = await fetch(APP_CONFIG.n8nWebhookUrl, {
|
const response = await fetch(APP_CONFIG.webhookUrl, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
@ -904,33 +981,27 @@ async function parseQueryWithAI(naturalQuery) {
|
|||||||
|
|
||||||
const result = await response.json();
|
const result = await response.json();
|
||||||
|
|
||||||
// Handle n8n response format
|
// Handle webhook response format
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
console.log('✅ n8n AI parsing successful:', result);
|
|
||||||
if (result.fallback) {
|
|
||||||
console.log('ℹ️ Used fallback logic in n8n');
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
table: result.table,
|
table: result.table,
|
||||||
filters: result.filters
|
filters: result.filters
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
throw new Error(result.error || 'n8n workflow failed');
|
throw new Error(result.error || 'webhook failed');
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.name === 'AbortError') {
|
if (error.name === 'AbortError') {
|
||||||
console.warn('⚠️ n8n AI parsing timeout, using local fallback');
|
// Timeout occurred
|
||||||
} else if (error.message.includes('Failed to fetch')) {
|
} else if (error.message.includes('Failed to fetch')) {
|
||||||
console.warn('⚠️ Cannot reach n8n webhook, using local fallback. Check your n8n workflow is active.');
|
// Network error
|
||||||
} else {
|
} else {
|
||||||
console.warn('⚠️ n8n AI parsing failed, using local fallback:', error.message);
|
// Other error
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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('🔄 Fallback filters:', fallbackResult.filters);
|
|
||||||
return fallbackResult;
|
return fallbackResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -951,6 +1022,15 @@ function parseQueryFallback(query) {
|
|||||||
// Extract potential filters
|
// Extract potential filters
|
||||||
const filters = [];
|
const filters = [];
|
||||||
|
|
||||||
|
// Extract company names from "find" queries
|
||||||
|
if (lowerQuery.includes("find")) {
|
||||||
|
const companyNameMatch = query.match(/find\s+(.+)/i);
|
||||||
|
if (companyNameMatch) {
|
||||||
|
const companyName = companyNameMatch[1].trim();
|
||||||
|
filters.push({ field: "all", operator: "ilike", value: `%${companyName}%` });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Country filters
|
// Country filters
|
||||||
const countries = ["india", "uk", "united kingdom", "usa", "united states", "uae", "china", "germany", "france", "italy"];
|
const countries = ["india", "uk", "united kingdom", "usa", "united states", "uae", "china", "germany", "france", "italy"];
|
||||||
for (const country of countries) {
|
for (const country of countries) {
|
||||||
@ -984,7 +1064,6 @@ async function fetchFrom(table, filters, page = 0, pageSize = 100) {
|
|||||||
// Check cache first
|
// Check cache first
|
||||||
const cachedResult = getCachedResult(cacheKey);
|
const cachedResult = getCachedResult(cacheKey);
|
||||||
if (cachedResult) {
|
if (cachedResult) {
|
||||||
console.log('Using cached result for:', table);
|
|
||||||
return cachedResult;
|
return cachedResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1016,7 +1095,6 @@ async function fetchFrom(table, filters, page = 0, pageSize = 100) {
|
|||||||
const { data, error, count } = await q;
|
const { data, error, count } = await q;
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error('Supabase error:', error);
|
|
||||||
throw new Error(`Database query failed: ${error.message}`);
|
throw new Error(`Database query failed: ${error.message}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1031,7 +1109,6 @@ async function fetchFrom(table, filters, page = 0, pageSize = 100) {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error in fetchFrom:', error);
|
|
||||||
throw new Error(`Failed to fetch ${table} data: ${error.message}`);
|
throw new Error(`Failed to fetch ${table} data: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1081,34 +1158,68 @@ 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);
|
// CRITICAL: Validate and normalize filters before processing
|
||||||
|
const validatedFilters = validateAndNormalizeFilters(ai.filters);
|
||||||
|
|
||||||
|
// BULLETPROOF: Detect specific company name searches and ensure comprehensive search
|
||||||
|
const isSpecificCompanySearch = query.toLowerCase().includes('find') &&
|
||||||
|
validatedFilters.some(f => f.field === 'all' || f.field === 'company_name' || f.field === 'buyer' || f.field === 'seller' ||
|
||||||
|
(f.value && f.value.length > 10 && /[A-Z]/.test(f.value))); // Long value with capitals likely a company name
|
||||||
|
|
||||||
|
if (isSpecificCompanySearch && ai.table === 'all') {
|
||||||
|
// Find the company search value
|
||||||
|
const companyFilter = validatedFilters.find(f =>
|
||||||
|
f.field === 'all' || f.field === 'company_name' || f.field === 'buyer' || f.field === 'seller' ||
|
||||||
|
(f.value && f.value.length > 10)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (companyFilter) {
|
||||||
|
const companyValue = companyFilter.value;
|
||||||
|
|
||||||
|
// Remove the original filter and add comprehensive filters for all tables
|
||||||
|
const otherFilters = validatedFilters.filter(f => f !== companyFilter);
|
||||||
|
|
||||||
|
// Add filters for all company name fields
|
||||||
|
validatedFilters.length = 0; // Clear array
|
||||||
|
validatedFilters.push(
|
||||||
|
...otherFilters,
|
||||||
|
{ field: 'buyer', operator: 'ilike', value: companyValue },
|
||||||
|
{ field: 'seller', operator: 'ilike', value: companyValue },
|
||||||
|
{ field: 'company_name', operator: 'ilike', value: companyValue }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let newResults = [];
|
let newResults = [];
|
||||||
let totalCount = 0;
|
let totalCount = 0;
|
||||||
|
|
||||||
if (ai.table === "all") {
|
if (ai.table === "all") {
|
||||||
|
// Smart filter distribution for cross-table search
|
||||||
|
const buyerFilters = filterForTable(validatedFilters, "buyer");
|
||||||
|
const sellerFilters = filterForTable(validatedFilters, "seller");
|
||||||
|
const gulfoodFilters = filterForTable(validatedFilters, "gulfood");
|
||||||
|
|
||||||
const [buyerRes, sellerRes, gulfoodRes] = await Promise.all([
|
const [buyerRes, sellerRes, gulfoodRes] = await Promise.all([
|
||||||
fetchFrom("buyer", ai.filters, searchState.page),
|
fetchFrom("buyer", buyerFilters, searchState.page),
|
||||||
fetchFrom("seller", ai.filters, searchState.page),
|
fetchFrom("seller", sellerFilters, searchState.page),
|
||||||
fetchFrom("gulfood", [], searchState.page) // No filters for gulfood since it has different fields
|
fetchFrom("gulfood", gulfoodFilters, searchState.page)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
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") {
|
} else if (ai.table === "gulfood") {
|
||||||
// For gulfood table, don't apply country/brand/category filters
|
// For gulfood table, filter compatible fields only
|
||||||
const gulfoodFilters = ai.filters.filter(f =>
|
const gulfoodFilters = filterForTable(validatedFilters, "gulfood");
|
||||||
["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);
|
const result = await fetchFrom(ai.table, gulfoodFilters, searchState.page);
|
||||||
newResults = result.data;
|
newResults = result.data;
|
||||||
totalCount = result.count;
|
totalCount = result.count;
|
||||||
searchState.hasMore = result.hasMore;
|
searchState.hasMore = result.hasMore;
|
||||||
} else {
|
} else {
|
||||||
const result = await fetchFrom(ai.table, ai.filters, searchState.page);
|
// For buyer/seller tables, filter compatible fields only
|
||||||
|
const tableFilters = filterForTable(validatedFilters, ai.table);
|
||||||
|
const result = await fetchFrom(ai.table, tableFilters, searchState.page);
|
||||||
newResults = result.data;
|
newResults = result.data;
|
||||||
totalCount = result.count;
|
totalCount = result.count;
|
||||||
searchState.hasMore = result.hasMore;
|
searchState.hasMore = result.hasMore;
|
||||||
@ -1152,7 +1263,6 @@ async function performSearch(loadMore = false) {
|
|||||||
searchState.page++;
|
searchState.page++;
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Search error:', e);
|
|
||||||
showErrorMessage(`Search failed: ${e.message}`);
|
showErrorMessage(`Search failed: ${e.message}`);
|
||||||
} finally {
|
} finally {
|
||||||
// Hide loading state on search button
|
// Hide loading state on search button
|
||||||
@ -1254,9 +1364,7 @@ async function loadAllCountries() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
allCountries = Array.from(countrySet).sort();
|
allCountries = Array.from(countrySet).sort();
|
||||||
console.log('Loaded countries:', allCountries);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading countries:', error);
|
|
||||||
// Fallback to common countries
|
// Fallback to common countries
|
||||||
allCountries = [
|
allCountries = [
|
||||||
'India', 'United Kingdom', 'United States', 'UAE', 'China',
|
'India', 'United Kingdom', 'United States', 'UAE', 'China',
|
||||||
@ -1390,7 +1498,6 @@ async function performProductMatching() {
|
|||||||
count: count || 0
|
count: count || 0
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Buyer fetch error:', error);
|
|
||||||
throw new Error(`Failed to fetch buyers: ${error.message}`);
|
throw new Error(`Failed to fetch buyers: ${error.message}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1418,7 +1525,6 @@ async function performProductMatching() {
|
|||||||
count: count || 0
|
count: count || 0
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Seller fetch error:', error);
|
|
||||||
throw new Error(`Failed to fetch sellers: ${error.message}`);
|
throw new Error(`Failed to fetch sellers: ${error.message}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1463,7 +1569,6 @@ async function performProductMatching() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Product mapping error:', error);
|
|
||||||
const errorMessage = error.message || 'Unknown error occurred';
|
const errorMessage = error.message || 'Unknown error occurred';
|
||||||
|
|
||||||
document.getElementById("buyersList").innerHTML = `
|
document.getElementById("buyersList").innerHTML = `
|
||||||
@ -1638,7 +1743,6 @@ function exportResults() {
|
|||||||
|
|
||||||
showToast(`Exported ${searchState.results.length} records successfully`, 'success');
|
showToast(`Exported ${searchState.results.length} records successfully`, 'success');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Export error:', error);
|
|
||||||
showToast('Export failed: ' + error.message, 'error');
|
showToast('Export failed: ' + error.message, 'error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1648,8 +1752,6 @@ function quickSearch(type) {
|
|||||||
if (searchInput) {
|
if (searchInput) {
|
||||||
searchInput.value = type;
|
searchInput.value = type;
|
||||||
performSearch();
|
performSearch();
|
||||||
} else {
|
|
||||||
console.error('Search input not found');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1681,7 +1783,6 @@ async function deleteRecord(btn) {
|
|||||||
try {
|
try {
|
||||||
const card = btn.closest("[data-id]");
|
const card = btn.closest("[data-id]");
|
||||||
if (!card) {
|
if (!card) {
|
||||||
console.error('Could not find card element');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1689,7 +1790,6 @@ async function deleteRecord(btn) {
|
|||||||
const id = card.dataset.id;
|
const id = card.dataset.id;
|
||||||
|
|
||||||
if (!table || !id) {
|
if (!table || !id) {
|
||||||
console.error('Missing table or id data');
|
|
||||||
showToast("Could not delete: missing record information", 'error');
|
showToast("Could not delete: missing record information", 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1698,7 +1798,6 @@ async function deleteRecord(btn) {
|
|||||||
|
|
||||||
const { error } = await client.from(table).delete().eq("id", id);
|
const { error } = await client.from(table).delete().eq("id", id);
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error('Delete error:', error);
|
|
||||||
showToast("Delete failed: " + error.message, 'error');
|
showToast("Delete failed: " + error.message, 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1711,7 +1810,6 @@ async function deleteRecord(btn) {
|
|||||||
performSearch();
|
performSearch();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Delete record error:', error);
|
|
||||||
showToast("Delete failed: " + error.message, 'error');
|
showToast("Delete failed: " + error.message, 'error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1792,17 +1890,12 @@ async function handleCreateSubmit(event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Attempting to insert into table:', table);
|
|
||||||
console.log('Data to insert:', data);
|
|
||||||
|
|
||||||
const { data: result, error } = await client.from(table).insert([data]);
|
const { data: result, error } = await client.from(table).insert([data]);
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error('Create error details:', error);
|
|
||||||
showToast("Create failed: " + (error.message || JSON.stringify(error)), 'error');
|
showToast("Create failed: " + (error.message || JSON.stringify(error)), 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('Insert successful:', result);
|
|
||||||
showToast("Record created successfully!", 'success');
|
showToast("Record created successfully!", 'success');
|
||||||
clearCache();
|
clearCache();
|
||||||
closeCreateModal();
|
closeCreateModal();
|
||||||
@ -1812,20 +1905,30 @@ async function handleCreateSubmit(event) {
|
|||||||
performSearch();
|
performSearch();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Create record error:', error);
|
|
||||||
showToast("Create failed: " + (error.message || JSON.stringify(error)), 'error');
|
showToast("Create failed: " + (error.message || JSON.stringify(error)), 'error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateLastUpdated() {
|
||||||
|
const now = new Date();
|
||||||
|
const timeString = now.toLocaleTimeString('en-US', {
|
||||||
|
hour12: true,
|
||||||
|
hour: 'numeric',
|
||||||
|
minute: '2-digit',
|
||||||
|
second: '2-digit'
|
||||||
|
});
|
||||||
|
const lastUpdatedElement = document.getElementById('lastUpdated');
|
||||||
|
if (lastUpdatedElement) {
|
||||||
|
lastUpdatedElement.textContent = timeString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function initializeDashboard() {
|
function initializeDashboard() {
|
||||||
try {
|
try {
|
||||||
console.log('Initializing dashboard...');
|
|
||||||
|
|
||||||
// Check if required elements exist
|
// Check if required elements exist
|
||||||
const searchInput = document.getElementById('searchInput');
|
const searchInput = document.getElementById('searchInput');
|
||||||
|
|
||||||
if (!searchInput) {
|
if (!searchInput) {
|
||||||
console.error('Search input not found');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1839,10 +1942,11 @@ function initializeDashboard() {
|
|||||||
// Load countries for suggestions
|
// Load countries for suggestions
|
||||||
loadAllCountries();
|
loadAllCountries();
|
||||||
|
|
||||||
console.log('Dashboard initialized successfully');
|
// Update last updated time
|
||||||
|
updateLastUpdated();
|
||||||
|
setInterval(updateLastUpdated, 1000);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Initialization error:', error);
|
|
||||||
alert('Failed to initialize dashboard. Please refresh the page.');
|
alert('Failed to initialize dashboard. Please refresh the page.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1891,6 +1995,5 @@ input:focus, select:focus, button:focus {
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user