Spaces:
Sleeping
Sleeping
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Lead Qualification Analytics Dashboard</title> | |
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"> | |
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet"> | |
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> | |
<style> | |
body { | |
background-color: #f8f9fa; | |
padding-top: 2rem; | |
} | |
.header { | |
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
color: white; | |
padding: 2rem 0; | |
margin-bottom: 2rem; | |
} | |
.stats-card { | |
background: white; | |
padding: 1.5rem; | |
border-radius: 10px; | |
box-shadow: 0 0 10px rgba(0,0,0,0.1); | |
margin-bottom: 1rem; | |
text-align: center; | |
} | |
.stats-number { | |
font-size: 2.5rem; | |
font-weight: bold; | |
color: #007bff; | |
} | |
.stats-label { | |
color: #6c757d; | |
font-size: 1rem; | |
margin-top: 0.5rem; | |
} | |
.chart-container { | |
background: white; | |
padding: 2rem; | |
border-radius: 10px; | |
box-shadow: 0 0 10px rgba(0,0,0,0.1); | |
margin-bottom: 2rem; | |
} | |
.activity-list { | |
background: white; | |
padding: 2rem; | |
border-radius: 10px; | |
box-shadow: 0 0 10px rgba(0,0,0,0.1); | |
margin-bottom: 2rem; | |
} | |
.activity-item { | |
padding: 1rem; | |
border-bottom: 1px solid #e9ecef; | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
} | |
.activity-item:last-child { | |
border-bottom: none; | |
} | |
.activity-icon { | |
width: 40px; | |
height: 40px; | |
border-radius: 50%; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
color: white; | |
font-size: 1.2rem; | |
} | |
.activity-icon.click { | |
background: #28a745; | |
} | |
.activity-icon.search { | |
background: #007bff; | |
} | |
.activity-icon.visit { | |
background: #ffc107; | |
} | |
.activity-icon.email { | |
background: #6c757d; | |
} | |
.clear-data-btn { | |
background: #dc3545; | |
color: white; | |
border: none; | |
padding: 0.5rem 1rem; | |
border-radius: 5px; | |
cursor: pointer; | |
} | |
.clear-data-btn:hover { | |
background: #c82333; | |
} | |
.export-btn { | |
background: #28a745; | |
color: white; | |
border: none; | |
padding: 0.5rem 1rem; | |
border-radius: 5px; | |
cursor: pointer; | |
} | |
.export-btn:hover { | |
background: #218838; | |
} | |
.lead-score-card { | |
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
color: white; | |
padding: 2rem; | |
border-radius: 15px; | |
text-align: center; | |
margin-bottom: 2rem; | |
} | |
.lead-score-number { | |
font-size: 4rem; | |
font-weight: bold; | |
margin-bottom: 1rem; | |
} | |
.lead-score-label { | |
font-size: 1.2rem; | |
opacity: 0.9; | |
} | |
.lead-status { | |
padding: 0.5rem 1rem; | |
border-radius: 20px; | |
font-weight: bold; | |
margin-top: 1rem; | |
} | |
.lead-status.hot { | |
background: #dc3545; | |
} | |
.lead-status.warm { | |
background: #ffc107; | |
color: #212529; | |
} | |
.lead-status.cold { | |
background: #6c757d; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="container-fluid"> | |
<!-- Header --> | |
<div class="header"> | |
<div class="container"> | |
<div class="row align-items-center"> | |
<div class="col-md-8"> | |
<h1><i class="fas fa-chart-bar"></i> Lead Qualification Analytics Dashboard</h1> | |
<p class="mb-0">Track user behavior and lead qualification metrics</p> | |
</div> | |
<div class="col-md-4 text-end"> | |
<a href="/" class="btn btn-outline-light me-2"> | |
<i class="fas fa-home"></i> Home | |
</a> | |
<button class="btn btn-outline-light me-2" onclick="exportData()"> | |
<i class="fas fa-download"></i> Export | |
</button> | |
<button class="btn btn-light" onclick="clearData()"> | |
<i class="fas fa-trash"></i> Clear | |
</button> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="container"> | |
<!-- Lead Score Card --> | |
<div class="row mb-4"> | |
<div class="col-md-12"> | |
<div class="lead-score-card"> | |
<div class="lead-score-number" id="leadScore">0</div> | |
<div class="lead-score-label">Lead Qualification Score</div> | |
<div class="lead-status" id="leadStatus">Cold</div> | |
</div> | |
</div> | |
</div> | |
<!-- Action Buttons --> | |
<div class="row mb-4"> | |
<div class="col-md-6"> | |
<button class="clear-data-btn me-2" onclick="clearData()"> | |
<i class="fas fa-trash"></i> Clear All Data | |
</button> | |
<button class="export-btn" onclick="exportData()"> | |
<i class="fas fa-download"></i> Export Data | |
</button> | |
</div> | |
<div class="col-md-6 text-end"> | |
<small class="text-muted">Last updated: <span id="lastUpdated"></span></small> | |
</div> | |
</div> | |
<!-- Stats Cards --> | |
<div class="row mb-4"> | |
<div class="col-md-2"> | |
<div class="stats-card"> | |
<div class="stats-number" id="totalClicks">0</div> | |
<div class="stats-label">Total Clicks</div> | |
</div> | |
</div> | |
<div class="col-md-2"> | |
<div class="stats-card"> | |
<div class="stats-number" id="totalSearches">0</div> | |
<div class="stats-label">Total Searches</div> | |
</div> | |
</div> | |
<div class="col-md-2"> | |
<div class="stats-card"> | |
<div class="stats-number" id="uniqueProperties">0</div> | |
<div class="stats-label">Unique Properties</div> | |
</div> | |
</div> | |
<div class="col-md-2"> | |
<div class="stats-card"> | |
<div class="stats-number" id="totalViewTime">0s</div> | |
<div class="stats-label">Total View Time</div> | |
</div> | |
</div> | |
<div class="col-md-2"> | |
<div class="stats-card"> | |
<div class="stats-number" id="avgViewDuration">0s</div> | |
<div class="stats-label">Avg View Duration</div> | |
</div> | |
</div> | |
<div class="col-md-2"> | |
<div class="stats-card"> | |
<div class="stats-number" id="visitRequests">0</div> | |
<div class="stats-label">Visit Requests</div> | |
</div> | |
</div> | |
</div> | |
<!-- Charts Row --> | |
<div class="row mb-4"> | |
<div class="col-md-6"> | |
<div class="chart-container"> | |
<h5><i class="fas fa-chart-pie"></i> Property Type Preferences</h5> | |
<canvas id="propertyTypeChart"></canvas> | |
</div> | |
</div> | |
<div class="col-md-6"> | |
<div class="chart-container"> | |
<h5><i class="fas fa-chart-bar"></i> Price Range Preferences</h5> | |
<canvas id="priceRangeChart"></canvas> | |
</div> | |
</div> | |
</div> | |
<!-- Feature Preferences --> | |
<div class="row mb-4"> | |
<div class="col-md-12"> | |
<div class="chart-container"> | |
<h5><i class="fas fa-star"></i> Feature Preferences</h5> | |
<canvas id="featureChart"></canvas> | |
</div> | |
</div> | |
</div> | |
<!-- Detailed View Analytics --> | |
<div class="row mb-4"> | |
<div class="col-md-12"> | |
<div class="chart-container"> | |
<h5><i class="fas fa-clock"></i> Detailed View Analytics</h5> | |
<canvas id="viewDurationChart"></canvas> | |
</div> | |
</div> | |
</div> | |
<!-- Recent Activity --> | |
<div class="row"> | |
<div class="col-md-12"> | |
<div class="activity-list"> | |
<h5><i class="fas fa-history"></i> Recent Activity</h5> | |
<div id="activityList"> | |
<p class="text-muted">No activity recorded yet.</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script> | |
<script> | |
class LeadAnalyticsDashboard { | |
constructor() { | |
this.trackingData = this.loadTrackingData(); | |
this.init(); | |
} | |
loadTrackingData() { | |
const data = localStorage.getItem('userTrackingData'); | |
return data ? JSON.parse(data) : { | |
clickedProperties: [], | |
detailedViews: [], | |
searchHistory: [], | |
features: [], | |
priceRanges: [], | |
propertyTypes: [] | |
}; | |
} | |
init() { | |
this.updateStats(); | |
this.createCharts(); | |
this.displayRecentActivity(); | |
this.updateLastUpdated(); | |
this.updateLeadScore(); | |
this.generateInsights(); | |
} | |
updateStats() { | |
document.getElementById('totalClicks').textContent = this.trackingData.clickedProperties.length; | |
document.getElementById('totalSearches').textContent = this.trackingData.searchHistory.length; | |
// Unique properties clicked | |
const uniqueProperties = new Set(this.trackingData.clickedProperties.map(p => p.id)).size; | |
document.getElementById('uniqueProperties').textContent = uniqueProperties; | |
// Total view time | |
const totalViewTime = this.trackingData.detailedViews.reduce((sum, view) => sum + view.totalDuration, 0); | |
document.getElementById('totalViewTime').textContent = this.formatDuration(totalViewTime); | |
// Average view duration | |
if (this.trackingData.detailedViews.length > 0) { | |
const totalDuration = this.trackingData.detailedViews.reduce((sum, view) => sum + view.totalDuration, 0); | |
const totalViews = this.trackingData.detailedViews.reduce((sum, view) => sum + view.viewCount, 0); | |
const avgDuration = totalViews > 0 ? Math.round(totalDuration / totalViews) : 0; | |
document.getElementById('avgViewDuration').textContent = this.formatDuration(avgDuration); | |
} | |
// Visit requests (from localStorage or session) | |
const visitHistory = JSON.parse(localStorage.getItem('visitHistory') || '[]'); | |
document.getElementById('visitRequests').textContent = visitHistory.length; | |
} | |
generateInsights() { | |
const insights = this.analyzeUserBehavior(); | |
this.displayInsights(insights); | |
} | |
analyzeUserBehavior() { | |
const insights = { | |
preferredTypes: {}, | |
preferredPriceRanges: {}, | |
engagementLevel: 'low', | |
sessionDuration: 0, | |
topProperties: [], | |
recommendations: [] | |
}; | |
// Analyze property type preferences | |
this.trackingData.propertyTypes.forEach(type => { | |
insights.preferredTypes[type] = (insights.preferredTypes[type] || 0) + 1; | |
}); | |
// Analyze price range preferences | |
this.trackingData.priceRanges.forEach(range => { | |
insights.preferredPriceRanges[range] = (insights.preferredPriceRanges[range] || 0) + 1; | |
}); | |
// Calculate engagement level | |
const totalInteractions = this.trackingData.clickedProperties.length + this.trackingData.detailedViews.length; | |
const totalTime = this.trackingData.detailedViews.reduce((sum, view) => sum + view.totalDuration, 0); | |
if (totalInteractions >= 10 && totalTime >= 60) { | |
insights.engagementLevel = 'high'; | |
} else if (totalInteractions >= 5 && totalTime >= 30) { | |
insights.engagementLevel = 'medium'; | |
} | |
insights.sessionDuration = totalTime; | |
// Get top properties by engagement | |
insights.topProperties = this.trackingData.detailedViews | |
.sort((a, b) => b.totalDuration - a.totalDuration) | |
.slice(0, 3); | |
// Generate recommendations | |
insights.recommendations = this.generateRecommendations(); | |
return insights; | |
} | |
generateRecommendations() { | |
const recommendations = []; | |
const insights = this.analyzeUserBehavior(); | |
// Recommendation 1: Based on most viewed property type | |
const topType = Object.keys(insights.preferredTypes) | |
.sort((a, b) => insights.preferredTypes[b] - insights.preferredTypes[a])[0]; | |
if (topType) { | |
recommendations.push({ | |
type: 'property_type', | |
message: `You show strong interest in ${topType} properties. Consider exploring more ${topType} options.`, | |
priority: 'high' | |
}); | |
} | |
// Recommendation 2: Based on price range | |
const topPriceRange = Object.keys(insights.preferredPriceRanges) | |
.sort((a, b) => insights.preferredPriceRanges[b] - insights.preferredPriceRanges[a])[0]; | |
if (topPriceRange) { | |
recommendations.push({ | |
type: 'price_range', | |
message: `Your preferred price range is ${this.formatPriceRange(topPriceRange)}. Focus on properties in this range.`, | |
priority: 'medium' | |
}); | |
} | |
// Recommendation 3: Based on engagement | |
if (insights.engagementLevel === 'high') { | |
recommendations.push({ | |
type: 'engagement', | |
message: 'High engagement detected! You\'re ready for personalized recommendations and follow-up.', | |
priority: 'high' | |
}); | |
} else if (insights.engagementLevel === 'medium') { | |
recommendations.push({ | |
type: 'engagement', | |
message: 'Good engagement level. Consider scheduling property visits for interested properties.', | |
priority: 'medium' | |
}); | |
} | |
// Recommendation 4: Based on session duration | |
if (insights.sessionDuration < 30) { | |
recommendations.push({ | |
type: 'duration', | |
message: 'Short session duration. Consider providing more detailed property information.', | |
priority: 'low' | |
}); | |
} | |
return recommendations; | |
} | |
displayInsights(insights) { | |
// Create insights section if it doesn't exist | |
let insightsSection = document.getElementById('insightsSection'); | |
if (!insightsSection) { | |
insightsSection = document.createElement('div'); | |
insightsSection.id = 'insightsSection'; | |
insightsSection.className = 'row mb-4'; | |
insightsSection.innerHTML = ` | |
<div class="col-md-12"> | |
<div class="chart-container"> | |
<h5><i class="fas fa-lightbulb"></i> AI-Powered Insights & Recommendations</h5> | |
<div id="insightsContent"></div> | |
</div> | |
</div> | |
`; | |
// Insert after the charts row | |
const chartsRow = document.querySelector('.row.mb-4:nth-of-type(3)'); | |
if (chartsRow) { | |
chartsRow.parentNode.insertBefore(insightsSection, chartsRow.nextSibling); | |
} | |
} | |
const insightsContent = document.getElementById('insightsContent'); | |
let insightsHTML = ''; | |
// Display engagement summary | |
insightsHTML += ` | |
<div class="row mb-3"> | |
<div class="col-md-6"> | |
<div class="alert alert-info"> | |
<h6><i class="fas fa-chart-line"></i> Engagement Summary</h6> | |
<p><strong>Level:</strong> <span class="badge bg-${insights.engagementLevel === 'high' ? 'success' : insights.engagementLevel === 'medium' ? 'warning' : 'secondary'}">${insights.engagementLevel.toUpperCase()}</span></p> | |
<p><strong>Session Duration:</strong> ${this.formatDuration(insights.sessionDuration)}</p> | |
<p><strong>Total Interactions:</strong> ${this.trackingData.clickedProperties.length + this.trackingData.detailedViews.length}</p> | |
</div> | |
</div> | |
<div class="col-md-6"> | |
<div class="alert alert-success"> | |
<h6><i class="fas fa-star"></i> Top Property Types</h6> | |
${Object.entries(insights.preferredTypes) | |
.sort(([,a], [,b]) => b - a) | |
.slice(0, 3) | |
.map(([type, count]) => `<p><strong>${type}:</strong> ${count} interactions</p>`) | |
.join('')} | |
</div> | |
</div> | |
</div> | |
`; | |
// Display recommendations | |
insightsHTML += ` | |
<div class="row"> | |
<div class="col-md-12"> | |
<h6><i class="fas fa-recommendations"></i> AI Recommendations</h6> | |
${insights.recommendations.map(rec => ` | |
<div class="alert alert-${rec.priority === 'high' ? 'danger' : rec.priority === 'medium' ? 'warning' : 'info'}"> | |
<i class="fas fa-${rec.type === 'property_type' ? 'home' : rec.type === 'price_range' ? 'money-bill' : rec.type === 'engagement' ? 'chart-line' : 'clock'}"></i> | |
${rec.message} | |
</div> | |
`).join('')} | |
</div> | |
</div> | |
`; | |
// Display top properties | |
if (insights.topProperties.length > 0) { | |
insightsHTML += ` | |
<div class="row mt-3"> | |
<div class="col-md-12"> | |
<h6><i class="fas fa-trophy"></i> Most Engaged Properties</h6> | |
<div class="row"> | |
${insights.topProperties.map(prop => ` | |
<div class="col-md-4"> | |
<div class="card"> | |
<div class="card-body"> | |
<h6 class="card-title">${prop.propertyName.substring(0, 30)}...</h6> | |
<p class="card-text"> | |
<strong>Type:</strong> ${prop.propertyType}<br> | |
<strong>Price:</strong> ₹${this.formatPrice(prop.price)}<br> | |
<strong>Duration:</strong> ${this.formatDuration(prop.totalDuration)}<br> | |
<strong>Views:</strong> ${prop.viewCount} | |
</p> | |
</div> | |
</div> | |
</div> | |
`).join('')} | |
</div> | |
</div> | |
</div> | |
`; | |
} | |
insightsContent.innerHTML = insightsHTML; | |
} | |
createCharts() { | |
this.createPropertyTypeChart(); | |
this.createPriceRangeChart(); | |
this.createFeatureChart(); | |
this.createViewDurationChart(); | |
} | |
createPropertyTypeChart() { | |
const ctx = document.getElementById('propertyTypeChart').getContext('2d'); | |
const typeCounts = {}; | |
this.trackingData.propertyTypes.forEach(type => { | |
typeCounts[type] = (typeCounts[type] || 0) + 1; | |
}); | |
if (Object.keys(typeCounts).length === 0) { | |
ctx.canvas.style.display = 'none'; | |
return; | |
} | |
new Chart(ctx, { | |
type: 'doughnut', | |
data: { | |
labels: Object.keys(typeCounts), | |
datasets: [{ | |
data: Object.values(typeCounts), | |
backgroundColor: [ | |
'#FF6384', | |
'#36A2EB', | |
'#FFCE56', | |
'#4BC0C0', | |
'#9966FF', | |
'#FF9F40' | |
] | |
}] | |
}, | |
options: { | |
responsive: true, | |
plugins: { | |
legend: { | |
position: 'bottom' | |
} | |
} | |
} | |
}); | |
} | |
createPriceRangeChart() { | |
const ctx = document.getElementById('priceRangeChart').getContext('2d'); | |
const rangeCounts = {}; | |
this.trackingData.priceRanges.forEach(range => { | |
rangeCounts[range] = (rangeCounts[range] || 0) + 1; | |
}); | |
if (Object.keys(rangeCounts).length === 0) { | |
ctx.canvas.style.display = 'none'; | |
return; | |
} | |
const labels = { | |
'0-500000': 'Under ₹5L', | |
'500000-1000000': '₹5L - ₹10L', | |
'1000000-2000000': '₹10L - ₹20L', | |
'2000000-5000000': '₹20L - ₹50L', | |
'5000000-10000000': '₹50L - ₹1Cr', | |
'10000000+': 'Above ₹1Cr' | |
}; | |
new Chart(ctx, { | |
type: 'bar', | |
data: { | |
labels: Object.keys(rangeCounts).map(key => labels[key] || key), | |
datasets: [{ | |
label: 'Clicks', | |
data: Object.values(rangeCounts), | |
backgroundColor: '#007bff' | |
}] | |
}, | |
options: { | |
responsive: true, | |
scales: { | |
y: { | |
beginAtZero: true | |
} | |
} | |
} | |
}); | |
} | |
createFeatureChart() { | |
const ctx = document.getElementById('featureChart').getContext('2d'); | |
const featureCounts = {}; | |
this.trackingData.features.forEach(feature => { | |
featureCounts[feature] = (featureCounts[feature] || 0) + 1; | |
}); | |
if (Object.keys(featureCounts).length === 0) { | |
ctx.canvas.style.display = 'none'; | |
return; | |
} | |
// Sort by count and take top 10 | |
const sortedFeatures = Object.entries(featureCounts) | |
.sort(([,a], [,b]) => b - a) | |
.slice(0, 10); | |
new Chart(ctx, { | |
type: 'horizontalBar', | |
data: { | |
labels: sortedFeatures.map(([feature]) => feature), | |
datasets: [{ | |
label: 'Clicks', | |
data: sortedFeatures.map(([,count]) => count), | |
backgroundColor: '#28a745' | |
}] | |
}, | |
options: { | |
responsive: true, | |
scales: { | |
x: { | |
beginAtZero: true | |
} | |
} | |
} | |
}); | |
} | |
createViewDurationChart() { | |
const ctx = document.getElementById('viewDurationChart').getContext('2d'); | |
const detailedViews = this.trackingData.detailedViews; | |
if (detailedViews.length === 0) { | |
ctx.canvas.style.display = 'none'; | |
return; | |
} | |
// Sort by total duration and take top 10 | |
const sortedViews = detailedViews | |
.sort((a, b) => b.totalDuration - a.totalDuration) | |
.slice(0, 10); | |
new Chart(ctx, { | |
type: 'bar', | |
data: { | |
labels: sortedViews.map(view => view.propertyName.substring(0, 20) + '...'), | |
datasets: [{ | |
label: 'Total Duration (seconds)', | |
data: sortedViews.map(view => view.totalDuration), | |
backgroundColor: '#ff6384' | |
}, { | |
label: 'View Count', | |
data: sortedViews.map(view => view.viewCount), | |
backgroundColor: '#36a2eb' | |
}] | |
}, | |
options: { | |
responsive: true, | |
scales: { | |
y: { | |
beginAtZero: true | |
} | |
} | |
} | |
}); | |
} | |
displayRecentActivity() { | |
const container = document.getElementById('activityList'); | |
const allActivities = []; | |
// Add clicked properties | |
this.trackingData.clickedProperties.forEach(prop => { | |
allActivities.push({ | |
type: 'click', | |
text: `Clicked on ${prop.name}`, | |
timestamp: new Date(prop.timestamp), | |
price: prop.price, | |
propertyType: prop.type | |
}); | |
}); | |
// Add detailed views | |
this.trackingData.detailedViews.forEach(view => { | |
allActivities.push({ | |
type: 'detailed_view', | |
text: `Viewed ${view.propertyName} for ${this.formatDuration(view.totalDuration)}`, | |
timestamp: new Date(view.lastViewed), | |
price: view.price, | |
propertyType: view.propertyType, | |
viewCount: view.viewCount, | |
totalDuration: view.totalDuration | |
}); | |
}); | |
// Add searches | |
this.trackingData.searchHistory.forEach(search => { | |
allActivities.push({ | |
type: 'search', | |
text: `Searched for "${search.query}"`, | |
timestamp: new Date(search.timestamp), | |
filters: search.filters | |
}); | |
}); | |
// Add visit requests | |
const visitHistory = JSON.parse(localStorage.getItem('visitHistory') || '[]'); | |
visitHistory.forEach(visit => { | |
allActivities.push({ | |
type: 'visit', | |
text: `Requested visit for ${visit.propertyName}`, | |
timestamp: new Date(visit.timestamp), | |
propertyType: visit.propertyType | |
}); | |
}); | |
// Sort by timestamp (most recent first) | |
allActivities.sort((a, b) => b.timestamp - a.timestamp); | |
if (allActivities.length === 0) { | |
container.innerHTML = '<p class="text-muted">No activity recorded yet.</p>'; | |
return; | |
} | |
const activitiesHTML = allActivities.slice(0, 20).map(activity => { | |
let iconClass, icon; | |
if (activity.type === 'click') { | |
iconClass = 'click'; | |
icon = 'fas fa-mouse-pointer'; | |
} else if (activity.type === 'detailed_view') { | |
iconClass = 'visit'; | |
icon = 'fas fa-clock'; | |
} else if (activity.type === 'search') { | |
iconClass = 'search'; | |
icon = 'fas fa-search'; | |
} else { | |
iconClass = 'visit'; | |
icon = 'fas fa-calendar'; | |
} | |
return ` | |
<div class="activity-item"> | |
<div class="d-flex align-items-center"> | |
<div class="activity-icon ${iconClass} me-3"> | |
<i class="${icon}"></i> | |
</div> | |
<div> | |
<div class="fw-bold">${activity.text}</div> | |
<small class="text-muted">${activity.timestamp.toLocaleString()}</small> | |
${activity.price ? `<br><small class="text-primary">₹${this.formatPrice(activity.price)}</small>` : ''} | |
${activity.viewCount ? `<br><small class="text-success">Viewed ${activity.viewCount} times</small>` : ''} | |
</div> | |
</div> | |
</div> | |
`; | |
}).join(''); | |
container.innerHTML = activitiesHTML; | |
} | |
updateLastUpdated() { | |
const now = new Date(); | |
document.getElementById('lastUpdated').textContent = now.toLocaleString(); | |
} | |
updateLeadScore() { | |
// Calculate lead score based on user behavior | |
let score = 0; | |
// Points for clicks | |
score += this.trackingData.clickedProperties.length * 5; | |
// Points for detailed views | |
score += this.trackingData.detailedViews.length * 10; | |
// Points for searches | |
score += this.trackingData.searchHistory.length * 3; | |
// Points for visit requests | |
const visitHistory = JSON.parse(localStorage.getItem('visitHistory') || '[]'); | |
score += visitHistory.length * 15; | |
// Points for time spent | |
const totalViewTime = this.trackingData.detailedViews.reduce((sum, view) => sum + view.totalDuration, 0); | |
score += Math.min(totalViewTime / 60, 20); // Max 20 points for time | |
// Cap score at 100 | |
score = Math.min(score, 100); | |
document.getElementById('leadScore').textContent = Math.round(score); | |
// Update lead status | |
const statusElement = document.getElementById('leadStatus'); | |
statusElement.className = 'lead-status'; | |
if (score >= 70) { | |
statusElement.textContent = 'Hot Lead'; | |
statusElement.classList.add('hot'); | |
} else if (score >= 40) { | |
statusElement.textContent = 'Warm Lead'; | |
statusElement.classList.add('warm'); | |
} else { | |
statusElement.textContent = 'Cold Lead'; | |
statusElement.classList.add('cold'); | |
} | |
} | |
formatPrice(price) { | |
if (price >= 10000000) { | |
return (price / 10000000).toFixed(1) + 'Cr'; | |
} else if (price >= 100000) { | |
return (price / 100000).toFixed(1) + 'L'; | |
} else { | |
return price.toLocaleString(); | |
} | |
} | |
formatDuration(seconds) { | |
if (seconds < 60) { | |
return seconds + 's'; | |
} else if (seconds < 3600) { | |
const minutes = Math.floor(seconds / 60); | |
const remainingSeconds = seconds % 60; | |
return minutes + 'm ' + remainingSeconds + 's'; | |
} else { | |
const hours = Math.floor(seconds / 3600); | |
const minutes = Math.floor((seconds % 3600) / 60); | |
return hours + 'h ' + minutes + 'm'; | |
} | |
} | |
formatPriceRange(range) { | |
const ranges = { | |
'0-500000': 'Under ₹5L', | |
'500000-1000000': '₹5L - ₹10L', | |
'1000000-2000000': '₹10L - ₹20L', | |
'2000000-5000000': '₹20L - ₹50L', | |
'5000000-10000000': '₹50L - ₹1Cr', | |
'10000000+': 'Above ₹1Cr' | |
}; | |
return ranges[range] || range; | |
} | |
} | |
// Global functions for buttons | |
function clearData() { | |
if (confirm('Are you sure you want to clear all tracking data? This cannot be undone.')) { | |
localStorage.removeItem('userTrackingData'); | |
localStorage.removeItem('userSessionId'); | |
localStorage.removeItem('visitHistory'); | |
location.reload(); | |
} | |
} | |
function exportData() { | |
const trackingData = localStorage.getItem('userTrackingData'); | |
const visitHistory = localStorage.getItem('visitHistory'); | |
const exportData = { | |
tracking_data: trackingData ? JSON.parse(trackingData) : {}, | |
visit_history: visitHistory ? JSON.parse(visitHistory) : [], | |
export_timestamp: new Date().toISOString() | |
}; | |
const blob = new Blob([JSON.stringify(exportData, null, 2)], { type: 'application/json' }); | |
const url = URL.createObjectURL(blob); | |
const a = document.createElement('a'); | |
a.href = url; | |
a.download = 'lead_analytics_data.json'; | |
document.body.appendChild(a); | |
a.click(); | |
document.body.removeChild(a); | |
URL.revokeObjectURL(url); | |
} | |
// Initialize dashboard | |
document.addEventListener('DOMContentLoaded', () => { | |
new LeadAnalyticsDashboard(); | |
}); | |
</script> | |
</body> | |
</html> |