// Global state management
const state = {
searchResults: [],
recentSearches: [],
user: null,
isLoading: false,
notifications: []
};
// Initialize the application
document.addEventListener('DOMContentLoaded', function() {
initializeApp();
setupEventListeners();
loadRecentSearches();
checkUserSession();
});
// Initialize application
function initializeApp() {
// Initialize tooltips
initTooltips();
// Load saved preferences
loadPreferences();
// Start activity monitoring
startActivityMonitoring();
// Initialize web components
initializeComponents();
}
// Setup event listeners
function setupEventListeners() {
// Search form submission
const searchForm = document.getElementById('searchForm');
if (searchForm) {
searchForm.addEventListener('submit', handleSearchSubmit);
}
// Keyboard shortcuts
document.addEventListener('keydown', handleKeyboardShortcuts);
// Window resize handler
window.addEventListener('resize', handleWindowResize);
// Online/offline detection
window.addEventListener('online', handleOnlineStatus);
window.addEventListener('offline', handleOfflineStatus);
}
// Handle search form submission
async function handleSearchSubmit(e) {
e.preventDefault();
const formData = new FormData(e.target);
const searchParams = {
firstName: formData.get('firstName'),
lastName: formData.get('lastName'),
dob: formData.get('dob'),
phone: formData.get('phone'),
email: formData.get('email'),
address: formData.get('address')
};
// Validate required fields
if (!searchParams.firstName && !searchParams.lastName && !searchParams.phone && !searchParams.email) {
showNotification('Please enter at least one search parameter', 'warning');
return;
}
// Show loading state
setLoadingState(true);
try {
// Perform search
const results = await performSearch(searchParams);
// Store results
state.searchResults = results;
// Add to recent searches
addToRecentSearches(searchParams, results);
// Show results modal
displaySearchResults(results);
// Show success notification
showNotification(`Found ${results.length} result(s)`, 'success');
} catch (error) {
console.error('Search error:', error);
showNotification('Search failed. Please try again.', 'error');
} finally {
setLoadingState(false);
}
}
// Perform actual search
async function performSearch(params) {
// Simulate API call with mock data
await new Promise(resolve => setTimeout(resolve, 1500));
// Generate mock results based on search parameters
const mockResults = generateMockResults(params);
// In a real implementation, this would be an actual API call:
// const response = await fetch('/api/skip-trace/search', {
// method: 'POST',
// headers: { 'Content-Type': 'application/json' },
// body: JSON.stringify(params)
// });
// return response.json();
return mockResults;
}
// Generate mock search results
function generateMockResults(params) {
const results = [];
const numResults = Math.floor(Math.random() * 5) + 1;
for (let i = 0; i < numResults; i++) {
const confidence = Math.floor(Math.random() * 40) + 60;
const hasAssets = Math.random() > 0.5;
results.push({
id: `result-${Date.now()}-${i}`,
fullName: `${params.firstName || 'John'} ${params.lastName || 'Doe'} ${i > 0 ? ` (${i + 1})` : ''}`,
firstName: params.firstName || 'John',
lastName: params.lastName || 'Doe',
age: Math.floor(Math.random() * 50) + 25,
confidence: confidence,
confidenceLevel: confidence >= 85 ? 'high' : confidence >= 70 ? 'medium' : 'low',
emails: [
`${(params.firstName || 'john').toLowerCase()}.${(params.lastName || 'doe').toLowerCase()}${i}@email.com`,
`${(params.firstName || 'john').toLowerCase()}.${(params.lastName || 'doe').toLowerCase()}${i}@gmail.com`
],
phones: [
`(${Math.floor(Math.random() * 900) + 100}) ${Math.floor(Math.random() * 900) + 100}-${Math.floor(Math.random() * 9000) + 1000}`,
`+1 ${Math.floor(Math.random() * 900) + 100}-${Math.floor(Math.random() * 900) + 100}-${Math.floor(Math.random() * 9000) + 1000}`
],
addresses: [
{
street: `${Math.floor(Math.random() * 9999) + 1} Main St`,
city: 'Los Angeles',
state: 'CA',
zip: `${Math.floor(Math.random() * 90000) + 10000}`,
fullAddress: `${Math.floor(Math.random() * 9999) + 1} Main St, Los Angeles, CA ${Math.floor(Math.random() * 90000) + 10000}`
}
],
assets: hasAssets ? [
{
type: 'Property',
value: Math.floor(Math.random() * 1000000) + 200000,
address: `${Math.floor(Math.random() * 9999) + 1} Oak Ave, Beverly Hills, CA`,
description: 'Residential Property'
},
{
type: 'Vehicle',
value: Math.floor(Math.random() * 50000) + 15000,
description: `${['Honda', 'Toyota', 'Ford', 'BMW'][Math.floor(Math.random() * 4)]} ${2020 - Math.floor(Math.random() * 5)}`
}
] : [],
dataSources: ['Enformion', 'People Data Labs', 'Google'].slice(0, Math.floor(Math.random() * 3) + 1),
lastUpdated: new Date().toISOString(),
verified: confidence >= 85
});
}
return results;
}
// Display search results in modal
function displaySearchResults(results) {
const searchModal = document.getElementById('searchModal');
const resultsContainer = document.getElementById('searchResults');
if (!searchModal || !resultsContainer) return;
// Clear previous results
resultsContainer.innerHTML = '';
if (results.length === 0) {
resultsContainer.innerHTML = `
`;
} else {
results.forEach((result, index) => {
const resultElement = createResultElement(result, index);
resultsContainer.appendChild(resultElement);
});
}
// Show modal
searchModal.classList.remove('hidden');
// Re-initialize feather icons
feather.replace();
}
// Create result element
function createResultElement(result, index) {
const div = document.createElement('div');
div.className = 'search-result-item fade-in';
div.style.animationDelay = `${index * 0.1}s`;
const confidenceClass = `confidence-${result.confidenceLevel}`;
const confidenceColor = result.confidenceLevel === 'high' ? 'green' :
result.confidenceLevel === 'medium' ? 'yellow' : 'red';
div.innerHTML = `
${result.fullName}
Age: ${result.age} • ID: ${result.id}
${result.confidence}% confidence
${result.verified ? '' : ''}
Contact Information
${result.emails.map(email => `
${email}
`).join('')}
${result.phones.map(phone => `
${phone}
`).join('')}
Address
${result.addresses.map(addr => `
${addr.fullAddress}
`).join('')}
${result.assets.length > 0 ? `
Discovered Assets
${result.assets.map(asset => `
${asset.type}: $${asset.value.toLocaleString()}
${asset.description}
`).join('')}
` : ''}
${result.dataSources.map(source => `
${source}
`).join('')}
`;
return div;
}
// Modal functions
function showSearchModal() {
const modal = document.getElementById('searchModal');
if (modal) modal.classList.remove('hidden');
}
function closeSearchModal() {
const modal = document.getElementById('searchModal');
if (modal) modal.classList.add('hidden');
}
function showBatchUpload() {
const modal = document.getElementById('batchModal');
if (modal) modal.classList.remove('hidden');
}
function closeBatchModal() {
const modal = document.getElementById('batchModal');
if (modal) modal.classList.add('hidden');
}
function showAnalytics() {
const modal = document.getElementById('analyticsModal');
if (modal) modal.classList.remove('hidden');
}
function closeAnalyticsModal() {
const modal = document.getElementById('analyticsModal');
if (modal) modal.classList.add('hidden');
}
function showAdvancedFilters() {
showNotification('Advanced filters coming soon!', 'info');
}
// Utility functions
function clearForm() {
const form = document.getElementById('searchForm');
if (form) form.reset();
}
function downloadTemplate() {
const csvContent = 'first_name,last_name,dob,phone,email,address\nJohn,Doe,1980-01-01,555-1234,john@example.com,123 Main St, City, State ZIP';
const blob = new Blob([csvContent], { type: 'text/csv' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'skip-trace-template.csv';
a.click();
URL.revokeObjectURL(url);
showNotification('Template downloaded successfully', 'success');
}
function exportResults() {
if (state.searchResults.length === 0) {
showNotification('No results to export', 'warning');
return;
}
// Create CSV content
const headers = ['Name', 'Confidence', 'Emails', 'Phones', 'Addresses', 'Assets'];
const rows = state.searchResults.map(result => [
result.fullName,
`${result.confidence}%`,
result.emails.join('; '),
result.phones.join('; '),
result.addresses.map(a => a.fullAddress).join('; '),
result.assets.map(a => `${a.type}: $${a.value}`).join('; ')
]);
const csvContent = [headers, ...rows].map(row => row.map(cell => `"${cell}"`).join(',')).join('\n');
// Download CSV
const blob = new Blob([csvContent], { type: 'text/csv' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `skip-trace-results-${new Date().toISOString().split('T')[0]}.csv`;
a.click();
URL.revokeObjectURL(url);
showNotification('Results exported successfully', 'success');
}
function exportSingleResult(resultId) {
const result = state.searchResults.find(r => r.id === resultId);
if (!result) return;
// Similar to exportResults but for single result
showNotification(`Exporting result for ${result.fullName}`, 'info');
}
function viewFullReport(resultId) {
const result = state.searchResults.find(r => r.id === resultId);
if (!result) return;
showNotification(`Generating full report for ${result.fullName}`, 'info');
// In a real implementation, this would generate a detailed PDF report
}
// Notification system
function showNotification(message, type = 'info') {
const notification = document.createElement('div');
notification.className = 'notification';
const colors = {
success: 'text-green-400 border-green-500',
error: 'text-red-400 border-red-500',
warning: 'text-yellow-400 border-yellow-500',
info: 'text-blue-400 border-blue-500'
};
const icons = {
success: 'check-circle',
error: 'x-circle',
warning: 'alert-triangle',
info: 'info'
};
notification.innerHTML = `
${message}
`;
document.body.appendChild(notification);
// Re-initialize feather icons
feather.replace();
// Auto remove after 5 seconds
setTimeout(() => {
notification.style.animation = 'slideOutRight 0.3s ease-out';
setTimeout(() => {
if (notification.parentNode) {
notification.parentNode.removeChild(notification);
}
}, 300);
}, 5000);
}
// Loading state management
function setLoadingState(loading) {
state.isLoading = loading;
const submitButton = document.querySelector('button[type="submit"]');
if (submitButton) {
if (loading) {
submitButton.disabled = true;
submitButton.innerHTML = 'Searching...';
} else {
submitButton.disabled = false;
submitButton.innerHTML = 'Search';
feather.replace();
}
}
}
// Recent searches management
function addToRecentSearches(params, results) {
const search = {
params,
resultCount: results.length,
timestamp: new Date().toISOString(),
id: Date.now().toString()
};
state.recentSearches.unshift(search);
state.recentSearches = state.recentSearches.slice(0, 10); // Keep only last 10
saveRecentSearches();
updateRecentSearchesUI();
}
function loadRecentSearches() {
const saved = localStorage.getItem('recentSearches');
if (saved) {
state.recentSearches = JSON.parse(saved);
updateRecentSearchesUI();
}
}
function saveRecentSearches() {
localStorage.setItem('recentSearches', JSON.stringify(state.recentSearches));
}
function updateRecentSearchesUI() {
const container = document.getElementById('recentSearches');
if (!container) return;
if (state.recentSearches.length === 0) {
container.innerHTML = 'No recent searches
';
return;
}
container.innerHTML = state.recentSearches.slice(0, 3).map(search => {
const timeAgo = getTimeAgo(new Date(search.timestamp));
const name = search.params.firstName || search.params.lastName ||
search.params.email || search.params.phone || 'Unknown';
return `
${name}
${timeAgo} • ${search.resultCount} results
`;
}).join('');
feather.replace();
}
function repeatSearch(searchId) {
const search = state.recentSearches.find(s => s.id === searchId);
if (!search) return;
// Populate form with previous search parameters
Object.entries(search.params).forEach(([key, value]) => {
const input = document.getElementById(key);
if (input) input.value = value || '';
});
// Trigger search
document.getElementById('searchForm').dispatchEvent(new Event('submit'));
}
// Utility functions
function getTimeAgo(date) {
const seconds = Math.floor((new Date() - date) / 1000);
let interval = seconds / 31536000;
if (interval > 1) return Math.floor(interval) + ' years ago';
interval = seconds / 2592000;
if (interval > 1) return Math.floor(interval) + ' months ago';
interval = seconds / 86400;
if (interval > 1) return Math.floor(interval) + ' days ago';
interval = seconds / 3600;
if (interval > 1) return Math.floor(interval) + ' hours ago';
interval = seconds / 60;
if (interval > 1) return Math.floor(interval) + ' minutes ago';
return 'Just now';
}
// Keyboard shortcuts
function handleKeyboardShortcuts(e) {
// Ctrl/Cmd + K for search
if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
e.preventDefault();
document.getElementById('firstName')?.focus();
}
// Escape to close modals
if (e.key === 'Escape') {
closeSearchModal();
closeBatchModal();
closeAnalyticsModal();
}
}
// Window resize handler
function handleWindowResize() {
// Handle responsive layout adjustments
if (window.innerWidth < 768) {
// Mobile adjustments
}
}
// Online/offline handlers
function handleOnlineStatus() {
showNotification('Connection restored', 'success');
}
function handleOfflineStatus() {
showNotification('Connection lost. Some features may be unavailable.', 'warning');
}
// User session management
function checkUserSession() {
const token = localStorage.getItem('authToken');
if (!token) {
// Redirect to login or show guest mode
console.log('No user session found');
}
}
// Activity monitoring
function startActivityMonitoring() {
let lastActivity = Date.now();
['mousedown', 'keydown', 'scroll', 'touchstart'].forEach(event => {
document.addEventListener(event, () => {
lastActivity = Date.now();
});
});
// Check for inactivity every minute
setInterval(() => {
if (Date.now() - lastActivity > 30 * 60 * 1000) { // 30 minutes
showNotification('Session about to expire due to inactivity', 'warning');
}
}, 60000);
}
// Preferences management
function loadPreferences() {
const preferences = localStorage.getItem('userPreferences');
if (preferences) {
const prefs = JSON.parse(preferences);
// Apply preferences
if (prefs.theme) {
document.documentElement.className = prefs.theme;
}
}
}
// Tooltip initialization
function initTooltips() {
// Initialize tooltips if using a tooltip library
console.log('Tooltips initialized');
}
// Web component initialization
function initializeComponents() {
// Initialize any web components
console.log('Web components initialized');
}
// Export functions for global access
window.showSearchModal = showSearchModal;
window.closeSearchModal = closeSearchModal;
window.showBatchUpload = showBatchUpload;
window.closeBatchModal = closeBatchModal;
window.showAnalytics = showAnalytics;
window.closeAnalyticsModal = closeAnalyticsModal;
window.showAdvancedFilters = showAdvancedFilters;
window.clearForm = clearForm;
window.downloadTemplate = downloadTemplate;
window.exportResults = exportResults;
window.exportSingleResult = exportSingleResult;
window.viewFullReport = viewFullReport;
window.repeatSearch = repeatSearch;