|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>π€ AI Lead Analysis Dashboard</title> |
|
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"> |
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"> |
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> |
|
<style> |
|
:root { |
|
--primary-color: #2563eb; |
|
--secondary-color: #7c3aed; |
|
--accent-color: #059669; |
|
--success-color: #10b981; |
|
--warning-color: #f59e0b; |
|
--danger-color: #ef4444; |
|
--light-color: #f8fafc; |
|
--dark-color: #1e293b; |
|
--info-color: #0ea5e9; |
|
} |
|
|
|
* { |
|
margin: 0; |
|
padding: 0; |
|
box-sizing: border-box; |
|
} |
|
|
|
body { |
|
font-family: 'Inter', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; |
|
background: #f1f5f9; |
|
color: var(--dark-color); |
|
line-height: 1.6; |
|
min-height: 100vh; |
|
} |
|
|
|
.main-container { |
|
max-width: 1400px; |
|
margin: 0 auto; |
|
padding: 20px; |
|
} |
|
|
|
|
|
.hero-header { |
|
background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%); |
|
color: white; |
|
border-radius: 20px; |
|
padding: 40px; |
|
margin-bottom: 30px; |
|
text-align: center; |
|
box-shadow: 0 20px 40px rgba(37, 99, 235, 0.2); |
|
} |
|
|
|
.hero-header h1 { |
|
font-size: 3rem; |
|
font-weight: 700; |
|
margin-bottom: 15px; |
|
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2); |
|
} |
|
|
|
.hero-header p { |
|
font-size: 1.3rem; |
|
margin-bottom: 25px; |
|
opacity: 0.95; |
|
} |
|
|
|
.ai-badge { |
|
background: rgba(255, 255, 255, 0.2); |
|
color: white; |
|
padding: 12px 25px; |
|
border-radius: 50px; |
|
font-size: 1.1rem; |
|
font-weight: 600; |
|
display: inline-block; |
|
backdrop-filter: blur(10px); |
|
border: 1px solid rgba(255, 255, 255, 0.3); |
|
} |
|
|
|
|
|
.card { |
|
background: white; |
|
border-radius: 16px; |
|
padding: 30px; |
|
margin-bottom: 25px; |
|
box-shadow: 0 4px 25px rgba(0, 0, 0, 0.08); |
|
border: 1px solid #e2e8f0; |
|
transition: all 0.3s ease; |
|
} |
|
|
|
.card:hover { |
|
transform: translateY(-2px); |
|
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12); |
|
} |
|
|
|
.card h3 { |
|
color: var(--dark-color); |
|
font-weight: 600; |
|
margin-bottom: 20px; |
|
font-size: 1.5rem; |
|
display: flex; |
|
align-items: center; |
|
gap: 10px; |
|
} |
|
|
|
.card h4 { |
|
color: var(--primary-color); |
|
font-weight: 600; |
|
margin-bottom: 15px; |
|
font-size: 1.2rem; |
|
} |
|
|
|
|
|
.form-control { |
|
border: 2px solid #e2e8f0; |
|
border-radius: 12px; |
|
padding: 15px; |
|
font-size: 1rem; |
|
transition: all 0.3s ease; |
|
background: white; |
|
color: var(--dark-color); |
|
} |
|
|
|
.form-control:focus { |
|
border-color: var(--primary-color); |
|
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1); |
|
outline: none; |
|
} |
|
|
|
.form-label { |
|
color: var(--dark-color); |
|
font-weight: 600; |
|
margin-bottom: 8px; |
|
font-size: 1rem; |
|
} |
|
|
|
|
|
.btn { |
|
border-radius: 12px; |
|
padding: 12px 25px; |
|
font-weight: 600; |
|
font-size: 1rem; |
|
transition: all 0.3s ease; |
|
border: none; |
|
cursor: pointer; |
|
display: inline-flex; |
|
align-items: center; |
|
gap: 8px; |
|
} |
|
|
|
.btn-primary { |
|
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); |
|
color: white; |
|
} |
|
|
|
.btn-primary:hover { |
|
transform: translateY(-2px); |
|
box-shadow: 0 8px 20px rgba(37, 99, 235, 0.3); |
|
} |
|
|
|
.btn-success { |
|
background: var(--success-color); |
|
color: white; |
|
} |
|
|
|
.btn-success:hover { |
|
background: #059669; |
|
transform: translateY(-2px); |
|
} |
|
|
|
.btn-warning { |
|
background: var(--warning-color); |
|
color: white; |
|
} |
|
|
|
.btn-info { |
|
background: var(--info-color); |
|
color: white; |
|
} |
|
|
|
.btn-danger { |
|
background: var(--danger-color); |
|
color: white; |
|
} |
|
|
|
.btn-outline-purple { |
|
background: transparent; |
|
border: 2px solid var(--secondary-color); |
|
color: var(--secondary-color); |
|
} |
|
|
|
.btn-outline-purple:hover { |
|
background: var(--secondary-color); |
|
border-color: var(--secondary-color); |
|
color: white; |
|
transform: translateY(-2px); |
|
} |
|
|
|
.btn-secondary { |
|
background: #6c757d; |
|
color: white; |
|
} |
|
|
|
.btn-outline-success { |
|
background: transparent; |
|
border: 2px solid var(--success-color); |
|
color: var(--success-color); |
|
} |
|
|
|
.btn-outline-success:hover { |
|
background: var(--success-color); |
|
color: white; |
|
transform: translateY(-2px); |
|
} |
|
|
|
.btn-outline-info { |
|
background: transparent; |
|
border: 2px solid var(--info-color); |
|
color: var(--info-color); |
|
} |
|
|
|
.btn-outline-info:hover { |
|
background: var(--info-color); |
|
color: white; |
|
transform: translateY(-2px); |
|
} |
|
|
|
.btn-outline-warning { |
|
background: transparent; |
|
border: 2px solid var(--warning-color); |
|
color: var(--warning-color); |
|
} |
|
|
|
.btn-outline-warning:hover { |
|
background: var(--warning-color); |
|
color: white; |
|
transform: translateY(-2px); |
|
} |
|
|
|
|
|
.metric-card { |
|
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); |
|
color: white; |
|
border-radius: 16px; |
|
padding: 25px; |
|
text-align: center; |
|
transition: transform 0.3s ease; |
|
} |
|
|
|
.metric-card:hover { |
|
transform: translateY(-3px); |
|
} |
|
|
|
.metric-value { |
|
font-size: 2.5rem; |
|
font-weight: 700; |
|
margin-bottom: 8px; |
|
} |
|
|
|
.metric-label { |
|
font-size: 1rem; |
|
opacity: 0.9; |
|
font-weight: 500; |
|
} |
|
|
|
|
|
.alert { |
|
border: none; |
|
border-radius: 12px; |
|
padding: 20px; |
|
margin-bottom: 20px; |
|
font-weight: 500; |
|
} |
|
|
|
.alert-success { |
|
background: linear-gradient(135deg, #d1fae5, #a7f3d0); |
|
color: #065f46; |
|
border-left: 4px solid var(--success-color); |
|
} |
|
|
|
.alert-info { |
|
background: linear-gradient(135deg, #dbeafe, #bfdbfe); |
|
color: #1e40af; |
|
border-left: 4px solid var(--info-color); |
|
} |
|
|
|
.alert-warning { |
|
background: linear-gradient(135deg, #fef3c7, #fde68a); |
|
color: #92400e; |
|
border-left: 4px solid var(--warning-color); |
|
} |
|
|
|
.alert-danger { |
|
background: linear-gradient(135deg, #fee2e2, #fca5a5); |
|
color: #991b1b; |
|
border-left: 4px solid var(--danger-color); |
|
} |
|
|
|
|
|
.email-section { |
|
background: white; |
|
border: 2px solid #e2e8f0; |
|
border-radius: 16px; |
|
padding: 30px; |
|
margin-bottom: 30px; |
|
} |
|
|
|
.email-section h3 { |
|
color: var(--dark-color); |
|
margin-bottom: 25px; |
|
font-weight: 600; |
|
} |
|
|
|
.email-section .form-control { |
|
background: #f8fafc; |
|
border: 2px solid #e2e8f0; |
|
color: var(--dark-color); |
|
} |
|
|
|
.email-section .form-control::placeholder { |
|
color: #64748b; |
|
} |
|
|
|
.email-section .form-control:focus { |
|
background: white; |
|
border-color: var(--primary-color); |
|
} |
|
|
|
|
|
.timeline { |
|
background: #f8fafc; |
|
border-radius: 12px; |
|
padding: 20px; |
|
} |
|
|
|
.timeline-item { |
|
background: white; |
|
border: 1px solid #e2e8f0; |
|
border-radius: 8px; |
|
padding: 15px; |
|
margin-bottom: 10px; |
|
color: var(--dark-color); |
|
font-weight: 500; |
|
} |
|
|
|
|
|
.property-item { |
|
background: white; |
|
border: 1px solid #e2e8f0; |
|
border-radius: 12px; |
|
padding: 20px; |
|
transition: all 0.3s ease; |
|
} |
|
|
|
.property-item:hover { |
|
transform: translateY(-2px); |
|
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1); |
|
border-color: var(--primary-color); |
|
} |
|
|
|
.property-name { |
|
font-weight: 600; |
|
color: var(--primary-color); |
|
margin-bottom: 10px; |
|
font-size: 1.1rem; |
|
} |
|
|
|
.property-details { |
|
color: var(--dark-color); |
|
font-size: 0.95rem; |
|
} |
|
|
|
.property-details span { |
|
font-weight: 600; |
|
color: var(--secondary-color); |
|
} |
|
|
|
|
|
.multi-ai-box { |
|
background: linear-gradient(135deg, #f0f9ff, #e0f2fe); |
|
border: 2px solid #0ea5e9; |
|
border-radius: 16px; |
|
padding: 25px; |
|
margin: 20px 0; |
|
} |
|
|
|
.multi-ai-box h6 { |
|
color: var(--info-color); |
|
font-weight: 600; |
|
margin-bottom: 15px; |
|
} |
|
|
|
.multi-ai-box ul { |
|
margin: 0; |
|
padding-left: 20px; |
|
} |
|
|
|
.multi-ai-box li { |
|
color: var(--dark-color); |
|
margin-bottom: 5px; |
|
font-weight: 500; |
|
} |
|
|
|
|
|
.loading { |
|
text-align: center; |
|
padding: 60px; |
|
background: white; |
|
border-radius: 16px; |
|
margin: 20px 0; |
|
} |
|
|
|
.loading i { |
|
font-size: 3rem; |
|
color: var(--primary-color); |
|
animation: spin 1s linear infinite; |
|
} |
|
|
|
.loading h3 { |
|
color: var(--dark-color); |
|
margin: 20px 0 10px 0; |
|
} |
|
|
|
.loading p { |
|
color: #64748b; |
|
} |
|
|
|
@keyframes spin { |
|
0% { transform: rotate(0deg); } |
|
100% { transform: rotate(360deg); } |
|
} |
|
|
|
|
|
.hidden { |
|
display: none; |
|
} |
|
|
|
|
|
.search-section { |
|
background: white; |
|
border-radius: 16px; |
|
padding: 30px; |
|
margin-bottom: 30px; |
|
border: 2px solid #e2e8f0; |
|
} |
|
|
|
.search-form { |
|
display: flex; |
|
gap: 20px; |
|
align-items: end; |
|
justify-content: center; |
|
flex-wrap: wrap; |
|
} |
|
|
|
|
|
@media (max-width: 768px) { |
|
.hero-header h1 { |
|
font-size: 2rem; |
|
} |
|
|
|
.hero-header p { |
|
font-size: 1.1rem; |
|
} |
|
|
|
.search-form { |
|
flex-direction: column; |
|
align-items: stretch; |
|
} |
|
|
|
.metric-value { |
|
font-size: 2rem; |
|
} |
|
} |
|
|
|
|
|
.status-badge { |
|
padding: 8px 16px; |
|
border-radius: 50px; |
|
font-weight: 600; |
|
font-size: 0.9rem; |
|
text-transform: uppercase; |
|
letter-spacing: 0.5px; |
|
} |
|
|
|
.status-hot { |
|
background: linear-gradient(135deg, #fee2e2, #fca5a5); |
|
color: #991b1b; |
|
} |
|
|
|
.status-warm { |
|
background: linear-gradient(135deg, #fef3c7, #fde68a); |
|
color: #92400e; |
|
} |
|
|
|
.status-cold { |
|
background: linear-gradient(135deg, #f1f5f9, #cbd5e1); |
|
color: #475569; |
|
} |
|
|
|
|
|
.progress { |
|
height: 12px; |
|
border-radius: 6px; |
|
background-color: #e2e8f0; |
|
overflow: hidden; |
|
} |
|
|
|
.progress-bar { |
|
background: linear-gradient(90deg, var(--success-color), var(--accent-color)); |
|
border-radius: 6px; |
|
transition: width 0.6s ease; |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<div class="main-container"> |
|
|
|
<div class="hero-header"> |
|
<h1><i class="fas fa-robot"></i> AI Lead Analysis Dashboard</h1> |
|
<p>Advanced Customer Behavior Analytics with Multi-AI Recommendations</p> |
|
<div class="ai-badge"> |
|
<i class="fas fa-brain"></i> Powered by Multiple AI Models |
|
</div> |
|
<div class="mt-4"> |
|
<a href="/email-automation" class="btn btn-light btn-lg"> |
|
<i class="fas fa-envelope-open-text me-2"></i> |
|
Email Automation Dashboard |
|
</a> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="search-section"> |
|
<h3><i class="fas fa-search"></i> Customer Analysis</h3> |
|
<div class="search-form"> |
|
<div class="form-group"> |
|
<label for="customerId" class="form-label">Customer ID:</label> |
|
<input type="number" id="customerId" class="form-control" value="144" min="1" placeholder="Enter Customer ID" style="width: 200px;"> |
|
</div> |
|
<div class="form-group"> |
|
<button type="button" class="btn btn-primary" onclick="analyzeCustomer()"> |
|
<i class="fas fa-chart-line"></i> Analyze Customer |
|
</button> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div id="loadingSection" class="loading hidden"> |
|
<i class="fas fa-spinner"></i> |
|
<h3>Analyzing Customer Data...</h3> |
|
<p>Please wait while we process the information with AI models</p> |
|
</div> |
|
|
|
|
|
<div id="analysisResults" class="hidden"> |
|
|
|
<div class="card"> |
|
<h3><i class="fas fa-user-check"></i> Lead Qualification Status</h3> |
|
<div class="row"> |
|
<div class="col-md-8"> |
|
<div id="leadStatus"></div> |
|
</div> |
|
<div class="col-md-4"> |
|
<div class="metric-card"> |
|
<div class="metric-value" id="leadScore">0</div> |
|
<div class="metric-label">Lead Score</div> |
|
</div> |
|
</div> |
|
</div> |
|
<div id="leadFactors" class="mt-4"></div> |
|
<div id="conversionDetails" class="mt-4"></div> |
|
</div> |
|
|
|
|
|
<div class="row mb-4"> |
|
<div class="col-md-3"> |
|
<div class="metric-card"> |
|
<div class="metric-value" id="totalViews">0</div> |
|
<div class="metric-label">Total Views</div> |
|
</div> |
|
</div> |
|
<div class="col-md-3"> |
|
<div class="metric-card"> |
|
<div class="metric-value" id="totalDuration">0h 0m</div> |
|
<div class="metric-label">Total Duration</div> |
|
</div> |
|
</div> |
|
<div class="col-md-3"> |
|
<div class="metric-card"> |
|
<div class="metric-value" id="engagementScore">0</div> |
|
<div class="metric-label">Engagement Score</div> |
|
</div> |
|
</div> |
|
<div class="col-md-3"> |
|
<div class="metric-card"> |
|
<div class="metric-value" id="conversionProbability">0%</div> |
|
<div class="metric-label">Conversion Probability</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="card"> |
|
<h3><i class="fas fa-home"></i> Property Preferences & Analysis</h3> |
|
<div class="row"> |
|
<div class="col-md-4"> |
|
<h4><i class="fas fa-tags"></i> Preferred Types</h4> |
|
<div id="propertyPreferences"></div> |
|
</div> |
|
<div class="col-md-4"> |
|
<h4><i class="fas fa-clock"></i> Viewing Patterns</h4> |
|
<div id="viewingPatterns"></div> |
|
</div> |
|
<div class="col-md-4"> |
|
<h4><i class="fas fa-chart-line"></i> Activity Timeline</h4> |
|
<div id="activityTimeline"></div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="card"> |
|
<h3><i class="fas fa-money-bill-wave"></i> Price Analysis</h3> |
|
<div id="priceAnalysis"></div> |
|
</div> |
|
|
|
|
|
<div class="card"> |
|
<h3><i class="fas fa-brain"></i> Multi-AI Recommendations Engine</h3> |
|
<div class="row"> |
|
<div class="col-md-6"> |
|
<div class="form-group mb-3"> |
|
<label for="multiAiEmail" class="form-label">Email Address for Multi-AI Recommendations:</label> |
|
<input type="email" id="multiAiEmail" class="form-control" value="[email protected]"> |
|
</div> |
|
<div class="form-group mb-3"> |
|
<label for="emailCount" class="form-label">Number of AI Emails to Send:</label> |
|
<select id="emailCount" class="form-control"> |
|
<option value="5">5 Emails</option> |
|
<option value="10" selected>10 Emails</option> |
|
<option value="15">15 Emails</option> |
|
</select> |
|
</div> |
|
</div> |
|
<div class="col-md-6"> |
|
<div class="multi-ai-box"> |
|
<h6><i class="fas fa-info-circle"></i> Multi-AI Features:</h6> |
|
<ul> |
|
<li>π‘ Property-based recommendations</li> |
|
<li>π° Price-based matching</li> |
|
<li>π Location-based suggestions</li> |
|
<li>π Similarity-based findings</li> |
|
<li>π§ Behavioral analysis recommendations</li> |
|
<li>β Premium properties collection</li> |
|
<li>π΅ Budget-friendly options</li> |
|
<li>π Trending properties</li> |
|
<li>π¨βπ©βπ§βπ¦ Family-oriented properties</li> |
|
<li>πΌ Investment opportunities</li> |
|
</ul> |
|
</div> |
|
</div> |
|
</div> |
|
<div class="row mt-3"> |
|
<div class="col-12"> |
|
<button type="button" class="btn btn-primary btn-lg me-3" onclick="sendMultiAIRecommendations()"> |
|
<i class="fas fa-robot"></i> Send Multi-AI Recommendations |
|
</button> |
|
<button type="button" class="btn btn-success me-3" onclick="getChromaDBRecommendations()"> |
|
<i class="fas fa-database"></i> Get ChromaDB Recommendations |
|
</button> |
|
<button type="button" class="btn btn-info" onclick="fetchAllProperties()"> |
|
<i class="fas fa-download"></i> Fetch All Properties to ChromaDB |
|
</button> |
|
</div> |
|
</div> |
|
|
|
|
|
<div id="multiAiResults" class="mt-4"></div> |
|
|
|
|
|
<div id="chromaDbResults" class="mt-4"></div> |
|
</div> |
|
|
|
|
|
<div class="card"> |
|
<h3><i class="fas fa-envelope"></i> Comprehensive Email Testing & Analysis Suite</h3> |
|
<div class="row"> |
|
<div class="col-md-6"> |
|
<div class="form-group mb-3"> |
|
<label for="testEmail" class="form-label">Test Email Address:</label> |
|
<input type="email" id="testEmail" class="form-control" value="[email protected]"> |
|
<small class="text-muted">All emails will be sent to this address</small> |
|
</div> |
|
|
|
|
|
<h6><i class="fas fa-envelope"></i> Core Email Functions:</h6> |
|
<div class="d-flex gap-2 flex-wrap mb-3"> |
|
<button type="button" class="btn btn-success btn-sm" onclick="testSendGridConnection()"> |
|
<i class="fas fa-wifi"></i> Test SendGrid |
|
</button> |
|
<button type="button" class="btn btn-warning btn-sm" onclick="previewAllEmailContent()"> |
|
<i class="fas fa-eye"></i> Preview 10 Emails |
|
</button> |
|
</div> |
|
|
|
|
|
<h6><i class="fas fa-chart-line"></i> Analysis & Status:</h6> |
|
<div class="d-flex gap-2 flex-wrap mb-3"> |
|
<button type="button" class="btn btn-info btn-sm" onclick="getEmailAnalysisBasis()"> |
|
<i class="fas fa-search-plus"></i> Show Analysis Basis |
|
</button> |
|
<button type="button" class="btn btn-secondary btn-sm" onclick="getEmailStatus()"> |
|
<i class="fas fa-chart-bar"></i> Email Status |
|
</button> |
|
</div> |
|
</div> |
|
<div class="col-md-6"> |
|
|
|
<h6><i class="fas fa-rocket"></i> Main Email Actions:</h6> |
|
<div class="d-flex gap-2 flex-wrap mb-2"> |
|
<button type="button" class="btn btn-primary" onclick="testAll10Emails()"> |
|
<i class="fas fa-envelope-open-text"></i> Send All 10 AI Emails |
|
</button> |
|
</div> |
|
<div class="alert alert-info mb-3"> |
|
<small><strong>π§ Multi-AI Email System:</strong> Each email uses a different AI model to retrieve personalized properties from ChromaDB based on your analysis.</small> |
|
</div> |
|
|
|
|
|
<h6><i class="fas fa-database"></i> Property Management:</h6> |
|
<div class="d-flex gap-2 flex-wrap mb-2"> |
|
<button type="button" class="btn btn-info btn-sm" onclick="checkChromaDBStatus()"> |
|
<i class="fas fa-heartbeat"></i> Check ChromaDB Status |
|
</button> |
|
<button type="button" class="btn btn-success btn-sm" onclick="fetchAllProperties()"> |
|
<i class="fas fa-download"></i> Fetch Properties |
|
</button> |
|
</div> |
|
<div class="d-flex gap-2 flex-wrap mb-4"> |
|
<button type="button" class="btn btn-secondary btn-sm" onclick="getChromaDBRecommendations()"> |
|
<i class="fas fa-search"></i> Test Recommendations |
|
</button> |
|
</div> |
|
|
|
|
|
<h6><i class="fas fa-folder-open"></i> Saved Emails:</h6> |
|
<div class="d-flex gap-2 flex-wrap mb-3"> |
|
<button type="button" class="btn btn-warning btn-sm" onclick="listSavedEmails()"> |
|
<i class="fas fa-folder-open"></i> View Saved Emails |
|
</button> |
|
</div> |
|
|
|
<div class="alert alert-warning mb-3"> |
|
<small><strong>π SendGrid Limit Solution:</strong> When SendGrid limits are exceeded, emails are automatically saved to your local <code>./saved_emails/</code> folder. Click "View Saved Emails" to see and open them.</small> |
|
</div> |
|
|
|
<h6>Email Configuration:</h6> |
|
<div class="timeline"> |
|
<div class="timeline-item"> |
|
<strong>From:</strong> [email protected] |
|
</div> |
|
<div class="timeline-item"> |
|
<strong>To:</strong> [email protected] |
|
</div> |
|
<div class="timeline-item"> |
|
<strong>2:00 PM Daily</strong> - Peak time recommendations |
|
</div> |
|
<div class="timeline-item"> |
|
<strong>6:00 PM Daily</strong> - Evening opportunities |
|
</div> |
|
<div class="timeline-item"> |
|
<strong>Every Hour</strong> - System test emails |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="card"> |
|
<h3><i class="fas fa-user-chart"></i> Customer Analysis & Email Dashboard</h3> |
|
|
|
|
|
<div class="row mb-4"> |
|
<div class="col-md-6"> |
|
<h5><i class="fas fa-chart-line"></i> Customer Tracking Analysis</h5> |
|
<div id="customerAnalysis" class="alert alert-info"> |
|
<p><i class="fas fa-info-circle"></i> Customer analysis will appear here after analyzing a customer.</p> |
|
</div> |
|
</div> |
|
<div class="col-md-6"> |
|
<h5><i class="fas fa-robot"></i> AI Analysis Results</h5> |
|
<div id="aiAnalysisResults" class="alert alert-success"> |
|
<p><i class="fas fa-brain"></i> AI analysis results will appear here.</p> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="row mb-4"> |
|
<div class="col-12"> |
|
<h5><i class="fas fa-envelope-open"></i> Email Preview Center</h5> |
|
<div class="d-flex gap-2 flex-wrap mb-3"> |
|
<button type="button" class="btn btn-primary" onclick="previewAllEmails()"> |
|
<i class="fas fa-eye"></i> Preview All 5 Emails |
|
</button> |
|
<button type="button" class="btn btn-success" onclick="previewNewPropertiesEmail()"> |
|
<i class="fas fa-home"></i> New Properties |
|
</button> |
|
<button type="button" class="btn btn-info" onclick="previewRecommendationsEmail()"> |
|
<i class="fas fa-lightbulb"></i> Recommendations |
|
</button> |
|
<button type="button" class="btn btn-warning" onclick="previewPeakTimeEmail()"> |
|
<i class="fas fa-clock"></i> Peak Time |
|
</button> |
|
<button type="button" class="btn btn-secondary" onclick="previewBehavioralEmail()"> |
|
<i class="fas fa-user-cog"></i> Behavioral |
|
</button> |
|
</div> |
|
<div id="emailPreviewContainer" class="border rounded p-3" style="min-height: 200px; background-color: #f8f9fa;"> |
|
<p class="text-muted text-center"><i class="fas fa-envelope"></i> Select an email type above to preview</p> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="row mb-3"> |
|
<div class="col-md-3"> |
|
<div class="metric-card"> |
|
<div class="metric-value" id="totalEmails">0</div> |
|
<div class="metric-label">Total Emails</div> |
|
</div> |
|
</div> |
|
<div class="col-md-3"> |
|
<div class="metric-card"> |
|
<div class="metric-value" id="successEmails">0</div> |
|
<div class="metric-label">Successful</div> |
|
</div> |
|
</div> |
|
<div class="col-md-3"> |
|
<div class="metric-card"> |
|
<div class="metric-value" id="failedEmails">0</div> |
|
<div class="metric-label">Failed</div> |
|
</div> |
|
</div> |
|
<div class="col-md-3"> |
|
<div class="metric-card"> |
|
<div class="metric-value" id="scheduledEmails">0</div> |
|
<div class="metric-label">Scheduled</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="d-flex gap-2 flex-wrap"> |
|
<button type="button" class="btn btn-success" onclick="testAllEmailTypes()"> |
|
<i class="fas fa-play"></i> Test All Email Types |
|
</button> |
|
<button type="button" class="btn btn-warning" onclick="clearEmailLogs()"> |
|
<i class="fas fa-trash"></i> Clear Logs |
|
</button> |
|
<button type="button" class="btn btn-primary" onclick="sendAllIntendedEmails()"> |
|
<i class="fas fa-paper-plane"></i> Send All Intended Emails |
|
</button> |
|
<button type="button" class="btn btn-danger" onclick="sendMultiAIEmails()"> |
|
<i class="fas fa-robot"></i> Send 10 AI Emails |
|
</button> |
|
</div> |
|
</div> |
|
|
|
|
|
<div class="card"> |
|
<h3><i class="fas fa-list"></i> Email Activity Logs</h3> |
|
<div id="emailLogs"></div> |
|
</div> |
|
|
|
|
|
<div class="card"> |
|
<h3><i class="fas fa-eye"></i> Properties Viewed - Detailed Analysis</h3> |
|
<div class="row" id="propertiesViewed"></div> |
|
</div> |
|
|
|
|
|
<div class="card"> |
|
<h3><i class="fas fa-robot"></i> AI-Powered Property Recommendations</h3> |
|
<div class="alert alert-info"> |
|
<h6><i class="fas fa-lightbulb"></i> Personalized Recommendations</h6> |
|
<div id="aiRecommendations"></div> |
|
</div> |
|
<div id="propertyRecommendations"></div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<script> |
|
let currentCustomerId = 144; |
|
let analysisData = null; |
|
|
|
async function analyzeCustomer() { |
|
const customerId = document.getElementById('customerId').value; |
|
if (!customerId) { |
|
showError('Please enter a Customer ID'); |
|
return; |
|
} |
|
|
|
currentCustomerId = customerId; |
|
|
|
// Show loading |
|
document.getElementById('loadingSection').classList.remove('hidden'); |
|
document.getElementById('analysisResults').classList.add('hidden'); |
|
|
|
try { |
|
const response = await fetch(`/api/lead-analysis/${customerId}`); |
|
const data = await response.json(); |
|
|
|
if (data.success) { |
|
analysisData = data.data; |
|
displayAnalysis(data.data); |
|
loadEmailLogs(); |
|
} else { |
|
showError('Analysis failed: ' + (data.error || 'Unknown error')); |
|
} |
|
} catch (error) { |
|
showError('Error analyzing customer: ' + error.message); |
|
} finally { |
|
document.getElementById('loadingSection').classList.add('hidden'); |
|
document.getElementById('analysisResults').classList.remove('hidden'); |
|
} |
|
} |
|
|
|
function displayAnalysis(data) { |
|
// Lead Status |
|
const leadQual = data.lead_qualification; |
|
document.getElementById('leadStatus').innerHTML = ` |
|
<div class="status-badge status-${leadQual.lead_status.toLowerCase()}"> |
|
${leadQual.lead_status} |
|
</div> |
|
<p class="mt-3">${leadQual.status_description}</p> |
|
<div class="progress mt-3"> |
|
<div class="progress-bar" style="width: ${leadQual.lead_score}%"></div> |
|
</div> |
|
<small class="text-muted mt-2">${leadQual.lead_score}/${leadQual.max_possible_score} points</small> |
|
`; |
|
|
|
document.getElementById('leadScore').textContent = leadQual.lead_score; |
|
|
|
// Key Metrics |
|
const summary = data.summary; |
|
document.getElementById('totalViews').textContent = summary.total_views; |
|
document.getElementById('totalDuration').textContent = formatDuration(summary.total_duration); |
|
document.getElementById('engagementScore').textContent = Math.round(summary.engagement_score); |
|
|
|
const conversionProb = data.analytics.conversion_probability; |
|
document.getElementById('conversionProbability').textContent = Math.round(conversionProb.final_probability) + '%'; |
|
|
|
// Property Preferences |
|
const analytics = data.analytics; |
|
document.getElementById('propertyPreferences').innerHTML = ` |
|
<ul class="list-unstyled"> |
|
${analytics.preferred_property_types.map(type => `<li><i class="fas fa-check-circle text-success"></i> ${type}</li>`).join('')} |
|
</ul> |
|
`; |
|
|
|
// Update Customer Analysis Section |
|
displayCustomerAnalysis(data); |
|
|
|
// Display other sections |
|
displayViewingPatterns(analytics.viewing_patterns); |
|
displayActivityTimeline(analytics.lead_timeline); |
|
displayPriceAnalysis(analytics.price_preferences); |
|
displayPropertiesViewed(data.properties); |
|
displayAIRecommendations(analytics); |
|
} |
|
|
|
function displayCustomerAnalysis(data) { |
|
const analytics = data.analytics; |
|
const summary = data.summary; |
|
|
|
// Customer Tracking Analysis |
|
document.getElementById('customerAnalysis').innerHTML = ` |
|
<div class="row"> |
|
<div class="col-md-6"> |
|
<h6><i class="fas fa-eye"></i> Viewing Behavior</h6> |
|
<ul class="list-unstyled small"> |
|
<li><strong>Total Views:</strong> ${summary.total_views}</li> |
|
<li><strong>Total Duration:</strong> ${formatDuration(summary.total_duration)}</li> |
|
<li><strong>Engagement Score:</strong> ${Math.round(summary.engagement_score)}%</li> |
|
<li><strong>Peak Time:</strong> ${analytics.viewing_patterns.peak_viewing_time}</li> |
|
</ul> |
|
</div> |
|
<div class="col-md-6"> |
|
<h6><i class="fas fa-home"></i> Property Preferences</h6> |
|
<ul class="list-unstyled small"> |
|
<li><strong>Preferred Types:</strong> ${analytics.preferred_property_types.join(', ')}</li> |
|
<li><strong>Price Range:</strong> $${analytics.price_preferences.min_price.toLocaleString()} - $${analytics.price_preferences.max_price.toLocaleString()}</li> |
|
<li><strong>Avg Price:</strong> $${analytics.price_preferences.avg_price.toLocaleString()}</li> |
|
<li><strong>Conversion Probability:</strong> ${Math.round(analytics.conversion_probability.final_probability)}%</li> |
|
</ul> |
|
</div> |
|
</div> |
|
`; |
|
|
|
// AI Analysis Results |
|
document.getElementById('aiAnalysisResults').innerHTML = ` |
|
<div class="row"> |
|
<div class="col-md-6"> |
|
<h6><i class="fas fa-brain"></i> AI Insights</h6> |
|
<ul class="list-unstyled small"> |
|
<li><strong>Lead Status:</strong> ${data.lead_qualification.lead_status}</li> |
|
<li><strong>Lead Score:</strong> ${data.lead_qualification.lead_score}/${data.lead_qualification.max_possible_score}</li> |
|
<li><strong>Behavior Pattern:</strong> ${analytics.viewing_patterns.peak_viewing_time} Active</li> |
|
<li><strong>Decision Stage:</strong> ${data.lead_qualification.lead_status}</li> |
|
</ul> |
|
</div> |
|
<div class="col-md-6"> |
|
<h6><i class="fas fa-chart-line"></i> Recommendations</h6> |
|
<ul class="list-unstyled small"> |
|
<li><i class="fas fa-check text-success"></i> Send new properties matching preferences</li> |
|
<li><i class="fas fa-check text-success"></i> Schedule viewings during peak time</li> |
|
<li><i class="fas fa-check text-success"></i> Focus on ${analytics.preferred_property_types[0]} properties</li> |
|
<li><i class="fas fa-check text-success"></i> Target price range: $${analytics.price_preferences.min_price.toLocaleString()}-${analytics.price_preferences.max_price.toLocaleString()}</li> |
|
</ul> |
|
</div> |
|
</div> |
|
`; |
|
} |
|
|
|
function displayViewingPatterns(patterns) { |
|
const patternsHtml = ` |
|
<div class="d-flex flex-column gap-2"> |
|
<div><strong>Peak Time:</strong> ${patterns.peak_viewing_time}</div> |
|
<div><strong>Morning Views:</strong> ${patterns.morning_views}</div> |
|
<div><strong>Afternoon Views:</strong> ${patterns.afternoon_views}</div> |
|
<div><strong>Evening Views:</strong> ${patterns.evening_views}</div> |
|
</div> |
|
`; |
|
document.getElementById('viewingPatterns').innerHTML = patternsHtml; |
|
} |
|
|
|
function displayActivityTimeline(timeline) { |
|
const timelineHtml = timeline.slice(0, 5).map(item => ` |
|
<div class="border rounded p-2 mb-2"> |
|
<div><strong>${item.property_name}</strong></div> |
|
<small class="text-muted">${item.views} views β’ ${new Date(item.date).toLocaleDateString()}</small> |
|
</div> |
|
`).join(''); |
|
document.getElementById('activityTimeline').innerHTML = timelineHtml; |
|
} |
|
|
|
function displayPriceAnalysis(pricePrefs) { |
|
const priceHtml = ` |
|
<div class="row"> |
|
<div class="col-md-3"> |
|
<div class="text-center"> |
|
<div class="h4 text-primary">βΉ${formatPrice(pricePrefs.avg_price)}</div> |
|
<small>Average Price</small> |
|
</div> |
|
</div> |
|
<div class="col-md-3"> |
|
<div class="text-center"> |
|
<div class="h4 text-success">βΉ${formatPrice(pricePrefs.min_price)}</div> |
|
<small>Min Price</small> |
|
</div> |
|
</div> |
|
<div class="col-md-3"> |
|
<div class="text-center"> |
|
<div class="h4 text-warning">βΉ${formatPrice(pricePrefs.max_price)}</div> |
|
<small>Max Price</small> |
|
</div> |
|
</div> |
|
<div class="col-md-3"> |
|
<div class="text-center"> |
|
<div class="h4 text-info">βΉ${formatPrice(pricePrefs.price_range)}</div> |
|
<small>Price Range</small> |
|
</div> |
|
</div> |
|
</div> |
|
`; |
|
document.getElementById('priceAnalysis').innerHTML = priceHtml; |
|
} |
|
|
|
function displayPropertiesViewed(properties) { |
|
const propertiesHtml = properties.slice(0, 6).map(prop => ` |
|
<div class="col-md-4 mb-3"> |
|
<div class="property-item"> |
|
<div class="property-name">${prop.propertyName}</div> |
|
<div class="property-details"> |
|
<div><span>Type:</span> ${prop.propertyTypeName}</div> |
|
<div><span>Price:</span> βΉ${formatPrice(prop.price)}</div> |
|
<div><span>Views:</span> ${prop.viewCount}</div> |
|
<div><span>Engagement:</span> ${Math.round(prop.engagement_score)}</div> |
|
</div> |
|
</div> |
|
</div> |
|
`).join(''); |
|
document.getElementById('propertiesViewed').innerHTML = propertiesHtml; |
|
} |
|
|
|
function displayAIRecommendations(analytics) { |
|
const recommendationsHtml = ` |
|
<div class="row"> |
|
<div class="col-md-6"> |
|
<h6>AI Recommendations:</h6> |
|
<ul> |
|
${analytics.recommendations.map(rec => `<li>${rec}</li>`).join('')} |
|
</ul> |
|
</div> |
|
<div class="col-md-6"> |
|
<h6>Risk Assessment:</h6> |
|
<div><strong>Risk Level:</strong> ${analytics.risk_assessment.risk_level}</div> |
|
<div><strong>Opportunity Score:</strong> ${Math.round(analytics.opportunity_score)}</div> |
|
</div> |
|
</div> |
|
`; |
|
document.getElementById('aiRecommendations').innerHTML = recommendationsHtml; |
|
} |
|
|
|
// Multi-AI Functions |
|
async function sendMultiAIRecommendations() { |
|
const customerId = document.getElementById('customerId').value; |
|
const email = document.getElementById('multiAiEmail').value; |
|
const emailCount = document.getElementById('emailCount').value; |
|
|
|
if (!customerId) { |
|
showError('Please enter a customer ID first'); |
|
return; |
|
} |
|
|
|
try { |
|
showSuccess('π€ Starting Multi-AI recommendation process...'); |
|
|
|
const response = await fetch(`/api/multi-ai-recommendations/${customerId}`, { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json', |
|
}, |
|
body: JSON.stringify({ |
|
email: email, |
|
email_count: parseInt(emailCount) |
|
}) |
|
}); |
|
|
|
const result = await response.json(); |
|
|
|
if (result.success) { |
|
displayMultiAIResults(result); |
|
showSuccess(`β
Successfully sent ${result.total_sent} AI recommendation emails!`); |
|
} else { |
|
showError(`Failed to send multi-AI recommendations: ${result.error}`); |
|
} |
|
} catch (error) { |
|
console.error('Error sending multi-AI recommendations:', error); |
|
showError('Error sending multi-AI recommendations. Please try again.'); |
|
} |
|
} |
|
|
|
function displayMultiAIResults(result) { |
|
const resultsHtml = ` |
|
<div class="alert alert-success"> |
|
<h5><i class="fas fa-check-circle"></i> Multi-AI Recommendations Results</h5> |
|
<div class="row"> |
|
<div class="col-md-6"> |
|
<p><strong>Customer ID:</strong> ${result.customer_id}</p> |
|
<p><strong>Recipient:</strong> ${result.recipient_email}</p> |
|
<p><strong>Total Sent:</strong> ${result.total_sent} emails</p> |
|
<p><strong>Total Failed:</strong> ${result.total_failed} emails</p> |
|
</div> |
|
<div class="col-md-6"> |
|
<p><strong>AI Insights:</strong></p> |
|
<ul> |
|
<li>Personality: ${result.ai_insights?.personality_type || 'Analytical'}</li> |
|
<li>Urgency: ${result.ai_insights?.urgency_level || 'Medium'}</li> |
|
<li>Decision Style: ${result.ai_insights?.decision_making_style || 'Data-driven'}</li> |
|
</ul> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<div class="row"> |
|
<div class="col-md-6"> |
|
<h6><i class="fas fa-check"></i> Successfully Sent Emails:</h6> |
|
${result.sent_emails.map(email => ` |
|
<div class="alert alert-success"> |
|
<strong>${email.type}:</strong> ${email.subject} |
|
<br><small>Recommendations: ${email.recommendations_count}</small> |
|
</div> |
|
`).join('')} |
|
</div> |
|
<div class="col-md-6"> |
|
<h6><i class="fas fa-exclamation-triangle"></i> Failed Emails:</h6> |
|
${result.failed_emails.length > 0 ? result.failed_emails.map(email => ` |
|
<div class="alert alert-warning"> |
|
<strong>${email.type}:</strong> ${email.error} |
|
</div> |
|
`).join('') : '<div class="alert alert-success">No failed emails!</div>'} |
|
</div> |
|
</div> |
|
`; |
|
|
|
document.getElementById('multiAiResults').innerHTML = resultsHtml; |
|
} |
|
|
|
async function getChromaDBRecommendations() { |
|
const customerId = document.getElementById('customerId').value; |
|
|
|
if (!customerId) { |
|
showError('Please enter a customer ID first'); |
|
return; |
|
} |
|
|
|
try { |
|
showSuccess('π Getting ChromaDB recommendations...'); |
|
|
|
const response = await fetch(`/api/chromadb-recommendations/${customerId}`); |
|
const result = await response.json(); |
|
|
|
if (result.success) { |
|
displayChromaDBResults(result); |
|
showSuccess('β
ChromaDB recommendations loaded successfully!'); |
|
} else { |
|
showError(`Failed to get ChromaDB recommendations: ${result.error}`); |
|
} |
|
} catch (error) { |
|
console.error('Error getting ChromaDB recommendations:', error); |
|
showError('Error getting ChromaDB recommendations. Please try again.'); |
|
} |
|
} |
|
|
|
function displayChromaDBResults(result) { |
|
const resultsHtml = ` |
|
<div class="alert alert-info"> |
|
<h5><i class="fas fa-database"></i> ChromaDB Recommendations Results</h5> |
|
<p><strong>Total Recommendations:</strong> ${result.total_recommendations}</p> |
|
<p><strong>Customer ID:</strong> ${result.customer_id}</p> |
|
</div> |
|
|
|
<div class="row"> |
|
${Object.entries(result.recommendations).map(([type, recs]) => ` |
|
<div class="col-md-4"> |
|
<div class="card"> |
|
<div class="card-header"> |
|
<h6><i class="fas fa-star"></i> ${type.replace('_', ' ').toUpperCase()}</h6> |
|
</div> |
|
<div class="card-body"> |
|
${recs.slice(0, 3).map(rec => ` |
|
<div class="property-item mb-2"> |
|
<div class="property-name">${rec.property_name || 'Property'}</div> |
|
<div class="property-details"> |
|
<span>Price:</span> βΉ${formatPrice(rec.price || 0)}<br> |
|
<span>Type:</span> ${rec.property_type || 'N/A'}<br> |
|
<span>AI Score:</span> ${(rec.ai_score || 0).toFixed(2)} |
|
</div> |
|
${rec.ai_explanation ? `<small class="text-muted">${rec.ai_explanation}</small>` : ''} |
|
</div> |
|
`).join('')} |
|
${recs.length > 3 ? `<small class="text-muted">... and ${recs.length - 3} more</small>` : ''} |
|
</div> |
|
</div> |
|
</div> |
|
`).join('')} |
|
</div> |
|
`; |
|
|
|
document.getElementById('chromaDbResults').innerHTML = resultsHtml; |
|
} |
|
|
|
async function fetchAllProperties() { |
|
try { |
|
showSuccess('π₯ Starting property fetch to ChromaDB...'); |
|
|
|
const response = await fetch('/api/fetch-all-properties?workers=10&page_size=100&max_pages=10'); |
|
const result = await response.json(); |
|
|
|
if (result.success) { |
|
showSuccess(`β
Successfully fetched ${result.total_properties} properties to ChromaDB!`); |
|
} else { |
|
showError(`Failed to fetch properties: ${result.error}`); |
|
} |
|
} catch (error) { |
|
console.error('Error fetching properties:', error); |
|
showError('Error fetching properties. Please try again.'); |
|
} |
|
} |
|
|
|
// Email Functions |
|
async function sendTestEmail() { |
|
const email = document.getElementById('testEmail').value; |
|
if (!email) { |
|
showError('Please enter an email address'); |
|
return; |
|
} |
|
|
|
try { |
|
const response = await fetch('/api/test-email', { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json' |
|
}, |
|
body: JSON.stringify({ |
|
customer_id: currentCustomerId, |
|
email_type: 'test_email', |
|
recipient_email: email |
|
}) |
|
}); |
|
|
|
const data = await response.json(); |
|
|
|
if (data.success) { |
|
showSuccess('Test email sent successfully!'); |
|
loadEmailLogs(); |
|
} else { |
|
showError('Email send failed: ' + (data.error || 'Unknown error')); |
|
} |
|
} catch (error) { |
|
showError('Error sending email: ' + error.message); |
|
} |
|
} |
|
|
|
async function testEmailTriggers() { |
|
try { |
|
const response = await fetch(`/api/test-automated-emails/${currentCustomerId}`, { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json' |
|
} |
|
}); |
|
|
|
const data = await response.json(); |
|
|
|
if (data.success) { |
|
showSuccess('Email triggers test successful!'); |
|
loadEmailLogs(); |
|
} else { |
|
showError('Email triggers test failed: ' + (data.error || 'Unknown error')); |
|
} |
|
} catch (error) { |
|
showError('Error testing email triggers: ' + error.message); |
|
} |
|
} |
|
|
|
async function sendDirectTestEmail() { |
|
const recipient = document.getElementById('testEmail').value; |
|
if (!recipient) { |
|
showError('Please enter a test email address'); |
|
return; |
|
} |
|
|
|
try { |
|
const response = await fetch('/api/test-email-simple', { |
|
method: 'GET' |
|
}); |
|
|
|
const data = await response.json(); |
|
|
|
if (data.success) { |
|
showSuccess('Direct test email sent successfully!'); |
|
loadEmailLogs(); |
|
} else { |
|
showError('Direct test email failed: ' + (data.error || 'Unknown error')); |
|
} |
|
} catch (error) { |
|
showError('Error sending direct test email: ' + error.message); |
|
} |
|
} |
|
|
|
// Email Preview Functions |
|
async function previewAllEmails() { |
|
if (!analysisData) { |
|
showError('Please analyze a customer first to preview emails'); |
|
return; |
|
} |
|
|
|
document.getElementById('emailPreviewContainer').innerHTML = '<div class="text-center"><i class="fas fa-spinner fa-spin"></i> Loading all email previews...</div>'; |
|
|
|
try { |
|
const response = await fetch(`/api/email-automation/${currentCustomerId}`, { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json' |
|
}, |
|
body: JSON.stringify({ |
|
email: '[email protected]', |
|
email_type: 'all' |
|
}) |
|
}); |
|
|
|
const data = await response.json(); |
|
|
|
if (data.success) { |
|
displayEmailPreviews(data.results, 'All 5 Email Types'); |
|
} else { |
|
showError('Failed to preview emails: ' + (data.error || 'Unknown error')); |
|
} |
|
} catch (error) { |
|
showError('Error previewing emails: ' + error.message); |
|
} |
|
} |
|
|
|
async function previewNewPropertiesEmail() { |
|
if (!analysisData) { |
|
showError('Please analyze a customer first to preview emails'); |
|
return; |
|
} |
|
|
|
document.getElementById('emailPreviewContainer').innerHTML = '<div class="text-center"><i class="fas fa-spinner fa-spin"></i> Loading new properties email preview...</div>'; |
|
|
|
try { |
|
const response = await fetch(`/api/email-automation/${currentCustomerId}`, { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json' |
|
}, |
|
body: JSON.stringify({ |
|
email: '[email protected]', |
|
email_type: 'new_properties' |
|
}) |
|
}); |
|
|
|
const data = await response.json(); |
|
|
|
if (data.success) { |
|
displayEmailPreviews(data.results, 'New Properties Email'); |
|
} else { |
|
showError('Failed to preview new properties email: ' + (data.error || 'Unknown error')); |
|
} |
|
} catch (error) { |
|
showError('Error previewing new properties email: ' + error.message); |
|
} |
|
} |
|
|
|
async function previewRecommendationsEmail() { |
|
if (!analysisData) { |
|
showError('Please analyze a customer first to preview emails'); |
|
return; |
|
} |
|
|
|
document.getElementById('emailPreviewContainer').innerHTML = '<div class="text-center"><i class="fas fa-spinner fa-spin"></i> Loading recommendations email preview...</div>'; |
|
|
|
try { |
|
const response = await fetch(`/api/email-automation/${currentCustomerId}`, { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json' |
|
}, |
|
body: JSON.stringify({ |
|
email: '[email protected]', |
|
email_type: 'recommendations' |
|
}) |
|
}); |
|
|
|
const data = await response.json(); |
|
|
|
if (data.success) { |
|
displayEmailPreviews(data.results, 'AI Recommendations Email'); |
|
} else { |
|
showError('Failed to preview recommendations email: ' + (data.error || 'Unknown error')); |
|
} |
|
} catch (error) { |
|
showError('Error previewing recommendations email: ' + error.message); |
|
} |
|
} |
|
|
|
async function previewPeakTimeEmail() { |
|
if (!analysisData) { |
|
showError('Please analyze a customer first to preview emails'); |
|
return; |
|
} |
|
|
|
document.getElementById('emailPreviewContainer').innerHTML = '<div class="text-center"><i class="fas fa-spinner fa-spin"></i> Loading peak time email preview...</div>'; |
|
|
|
try { |
|
const response = await fetch(`/api/email-automation/${currentCustomerId}`, { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json' |
|
}, |
|
body: JSON.stringify({ |
|
email: '[email protected]', |
|
email_type: 'peak_time' |
|
}) |
|
}); |
|
|
|
const data = await response.json(); |
|
|
|
if (data.success) { |
|
displayEmailPreviews(data.results, 'Peak Time Engagement Email'); |
|
} else { |
|
showError('Failed to preview peak time email: ' + (data.error || 'Unknown error')); |
|
} |
|
} catch (error) { |
|
showError('Error previewing peak time email: ' + error.message); |
|
} |
|
} |
|
|
|
async function previewBehavioralEmail() { |
|
if (!analysisData) { |
|
showError('Please analyze a customer first to preview emails'); |
|
return; |
|
} |
|
|
|
document.getElementById('emailPreviewContainer').innerHTML = '<div class="text-center"><i class="fas fa-spinner fa-spin"></i> Loading behavioral email preview...</div>'; |
|
|
|
try { |
|
const response = await fetch(`/api/test-automated-emails/${currentCustomerId}`, { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json' |
|
} |
|
}); |
|
|
|
const data = await response.json(); |
|
|
|
if (data.success) { |
|
displayBehavioralEmailPreview(data, 'Behavioral Trigger Email'); |
|
} else { |
|
showError('Failed to preview behavioral email: ' + (data.error || 'Unknown error')); |
|
} |
|
} catch (error) { |
|
showError('Error previewing behavioral email: ' + error.message); |
|
} |
|
} |
|
|
|
function displayEmailPreviews(results, title) { |
|
let html = `<h5><i class="fas fa-envelope"></i> ${title} Preview</h5>`; |
|
|
|
if (results && results.length > 0) { |
|
results.forEach((result, index) => { |
|
html += ` |
|
<div class="card mb-3"> |
|
<div class="card-header d-flex justify-content-between align-items-center"> |
|
<h6 class="mb-0"> |
|
<i class="fas fa-envelope"></i> ${result.type ? result.type.replace('_', ' ').toUpperCase() : 'Email'} ${index + 1} |
|
</h6> |
|
<span class="badge ${result.success ? 'bg-success' : 'bg-danger'}"> |
|
${result.success ? 'SUCCESS' : 'FAILED'} |
|
</span> |
|
</div> |
|
<div class="card-body"> |
|
${result.success ? ` |
|
<div class="row"> |
|
<div class="col-md-6"> |
|
<h6>Email Details:</h6> |
|
<ul class="list-unstyled"> |
|
<li><strong>Type:</strong> ${result.type || 'N/A'}</li> |
|
<li><strong>Properties Count:</strong> ${result.properties_count || 0}</li> |
|
<li><strong>Recommendations Count:</strong> ${result.recommendations_count || 0}</li> |
|
<li><strong>Peak Time:</strong> ${result.peak_time || 'N/A'}</li> |
|
<li><strong>Engagement Level:</strong> ${result.engagement_level || 'N/A'}</li> |
|
</ul> |
|
</div> |
|
<div class="col-md-6"> |
|
<h6>AI Insights:</h6> |
|
<ul class="list-unstyled"> |
|
<li><strong>Personality Type:</strong> ${result.ai_insights?.personality_type || 'N/A'}</li> |
|
<li><strong>Decision Style:</strong> ${result.ai_insights?.decision_making_style || 'N/A'}</li> |
|
<li><strong>Urgency Level:</strong> ${result.ai_insights?.urgency_level || 'N/A'}</li> |
|
<li><strong>Peak Activity:</strong> ${result.ai_insights?.peak_time || 'N/A'}</li> |
|
</ul> |
|
</div> |
|
</div> |
|
<div class="mt-3"> |
|
<h6>Email Content Preview:</h6> |
|
${result.html_content ? ` |
|
<div class="email-preview-container" style="max-height: 400px; overflow-y: auto; border: 1px solid #ddd; border-radius: 8px; padding: 15px; background: white;"> |
|
<div class="email-preview-header mb-3"> |
|
<strong>Subject:</strong> ${result.subject || 'N/A'}<br> |
|
<strong>Properties:</strong> ${result.recommendations_count || 0} recommendations<br> |
|
<strong>AI Insights:</strong> ${result.ai_insights ? ` |
|
Personality: ${result.ai_insights.personality_type || 'N/A'} | |
|
Urgency: ${result.ai_insights.urgency_level || 'N/A'} | |
|
Peak Time: ${result.ai_insights.peak_activity || 'N/A'} |
|
` : 'N/A'} |
|
</div> |
|
<div class="email-content-preview"> |
|
${result.html_content} |
|
</div> |
|
</div> |
|
` : ` |
|
<div class="alert alert-light"> |
|
<small>This email would be sent to the customer based on their tracking data and AI analysis. The content is personalized based on their viewing behavior, preferences, and engagement patterns.</small> |
|
</div> |
|
`} |
|
</div> |
|
` : ` |
|
<div class="alert alert-danger"> |
|
<strong>Error:</strong> ${result.error || 'Unknown error occurred'} |
|
</div> |
|
`} |
|
</div> |
|
</div> |
|
`; |
|
}); |
|
} else { |
|
html += '<div class="alert alert-warning">No email previews available</div>'; |
|
} |
|
|
|
document.getElementById('emailPreviewContainer').innerHTML = html; |
|
} |
|
|
|
function displayBehavioralEmailPreview(data, title) { |
|
let html = `<h5><i class="fas fa-envelope"></i> ${title} Preview</h5>`; |
|
|
|
html += ` |
|
<div class="card"> |
|
<div class="card-header"> |
|
<h6 class="mb-0"> |
|
<i class="fas fa-user-cog"></i> Behavioral Trigger Email |
|
</h6> |
|
</div> |
|
<div class="card-body"> |
|
<div class="row"> |
|
<div class="col-md-6"> |
|
<h6>Trigger Details:</h6> |
|
<ul class="list-unstyled"> |
|
<li><strong>Trigger Type:</strong> ${data.trigger_type || 'Behavioral'}</li> |
|
<li><strong>Customer ID:</strong> ${data.customer_id || currentCustomerId}</li> |
|
<li><strong>Status:</strong> ${data.success ? 'SUCCESS' : 'FAILED'}</li> |
|
</ul> |
|
</div> |
|
<div class="col-md-6"> |
|
<h6>Analysis Basis:</h6> |
|
<ul class="list-unstyled"> |
|
<li><strong>Viewing Behavior:</strong> Based on customer's property viewing patterns</li> |
|
<li><strong>Engagement Level:</strong> ${analysisData?.summary?.engagement_score || 'N/A'}%</li> |
|
<li><strong>Peak Time:</strong> ${analysisData?.analytics?.viewing_patterns?.peak_viewing_time || 'N/A'}</li> |
|
</ul> |
|
</div> |
|
</div> |
|
<div class="mt-3"> |
|
<h6>Email Content Preview:</h6> |
|
<div class="alert alert-light"> |
|
<small>This behavioral email is triggered based on the customer's activity patterns and engagement level. It provides personalized recommendations and follow-up actions based on their browsing behavior.</small> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
`; |
|
|
|
document.getElementById('emailPreviewContainer').innerHTML = html; |
|
} |
|
|
|
async function loadEmailLogs() { |
|
try { |
|
const response = await fetch('/api/list-emails'); |
|
const data = await response.json(); |
|
|
|
if (data.success) { |
|
const emails = data.emails || []; |
|
|
|
// Update email dashboard metrics (fixed values, no continuous updates) |
|
document.getElementById('totalEmails').textContent = emails.length; |
|
document.getElementById('successEmails').textContent = emails.filter(e => e.success !== false).length; |
|
document.getElementById('failedEmails').textContent = emails.filter(e => e.success === false).length; |
|
document.getElementById('scheduledEmails').textContent = emails.filter(e => e.email_type === 'scheduled').length; |
|
|
|
document.getElementById('emailLogs').innerHTML = ` |
|
${emails.slice(0, 5).map(email => ` |
|
<div class="alert ${email.success !== false ? 'alert-success' : 'alert-danger'}"> |
|
<div class="d-flex justify-content-between"> |
|
<strong>${email.filename || 'Email Log'}</strong> |
|
<small>${new Date(email.created || Date.now()).toLocaleString()}</small> |
|
</div> |
|
<div>Size: ${email.size ? (email.size/1024).toFixed(1) + ' KB' : 'N/A'}</div> |
|
</div> |
|
`).join('')} |
|
${emails.length === 0 ? '<div class="alert alert-info">No email logs found</div>' : ''} |
|
`; |
|
} else { |
|
document.getElementById('emailLogs').innerHTML = '<div class="alert alert-danger">Failed to load email logs</div>'; |
|
} |
|
} catch (error) { |
|
document.getElementById('emailLogs').innerHTML = '<div class="alert alert-danger">Error loading email logs</div>'; |
|
} |
|
} |
|
|
|
async function testAllEmailTypes() { |
|
showSuccess('Testing all email types... This may take a moment.'); |
|
// Implementation for testing all email types |
|
} |
|
|
|
async function clearEmailLogs() { |
|
if (confirm('Are you sure you want to clear all email logs?')) { |
|
showSuccess('Email logs cleared successfully!'); |
|
loadEmailLogs(); |
|
} |
|
} |
|
|
|
async function sendAllIntendedEmails() { |
|
showSuccess('Sending all intended emails...'); |
|
// Implementation for sending all intended emails |
|
} |
|
|
|
async function sendMultiAIEmails() { |
|
showSuccess('Starting Multi-AI email campaign...'); |
|
// Implementation for sending multi-AI emails |
|
} |
|
|
|
// New Email Testing Functions |
|
async function testSendGridConnection() { |
|
try { |
|
showSuccess('Testing SendGrid connection...'); |
|
const response = await fetch('/api/test-sendgrid-connection'); |
|
const result = await response.json(); |
|
|
|
if (result.success) { |
|
showSuccess(`β
SendGrid connection successful: ${result.message}`); |
|
document.getElementById('multiAiResults').innerHTML = ` |
|
<div class="alert alert-success"> |
|
<h5><i class="fas fa-check-circle"></i> SendGrid Connection Test</h5> |
|
<p><strong>Status:</strong> Connected β
</p> |
|
<p><strong>Details:</strong> ${JSON.stringify(result.details, null, 2)}</p> |
|
<p><strong>Timestamp:</strong> ${result.timestamp}</p> |
|
</div> |
|
`; |
|
} else { |
|
showError(`β SendGrid connection failed: ${result.error}`); |
|
} |
|
} catch (error) { |
|
showError(`β Error testing SendGrid: ${error.message}`); |
|
} |
|
} |
|
|
|
async function getEmailAnalysisBasis() { |
|
try { |
|
const customerId = document.getElementById('customerId').value || 144; |
|
showSuccess('Getting email analysis basis...'); |
|
|
|
const response = await fetch(`/api/email-analysis-basis/${customerId}`); |
|
const result = await response.json(); |
|
|
|
if (result.success) { |
|
document.getElementById('multiAiResults').innerHTML = ` |
|
<div class="alert alert-info"> |
|
<h5><i class="fas fa-search-plus"></i> Email Analysis Basis for Customer ${customerId}</h5> |
|
<div class="row"> |
|
<div class="col-md-6"> |
|
<h6>Customer Preferences:</h6> |
|
<pre>${JSON.stringify(result.analysis_basis.customer_preferences, null, 2)}</pre> |
|
</div> |
|
<div class="col-md-6"> |
|
<h6>Email Triggers:</h6> |
|
${Object.entries(result.email_triggers).map(([type, trigger]) => |
|
`<p><strong>${type}:</strong> ${trigger}</p>` |
|
).join('')} |
|
</div> |
|
</div> |
|
<div class="row mt-3"> |
|
<div class="col-12"> |
|
<h6>AI Insights Summary:</h6> |
|
<p><strong>Engagement Level:</strong> ${result.analysis_basis.engagement_level}</p> |
|
<p><strong>Conversion Probability:</strong> ${(result.analysis_basis.conversion_probability * 100).toFixed(1)}%</p> |
|
</div> |
|
</div> |
|
</div> |
|
`; |
|
showSuccess('β
Email analysis basis retrieved successfully'); |
|
} else { |
|
showError(`β Failed to get analysis basis: ${result.error}`); |
|
} |
|
} catch (error) { |
|
showError(`β Error getting analysis basis: ${error.message}`); |
|
} |
|
} |
|
|
|
async function previewAllEmailContent() { |
|
try { |
|
const customerId = document.getElementById('customerId').value || 144; |
|
showSuccess('Previewing all 10 email contents...'); |
|
|
|
const response = await fetch(`/api/email-content-preview/${customerId}`); |
|
const result = await response.json(); |
|
|
|
if (result.success) { |
|
let previewHtml = ` |
|
<div class="alert alert-warning"> |
|
<h5><i class="fas fa-file-alt"></i> All 10 Email Content Previews</h5> |
|
<p><strong>Total Emails:</strong> ${result.total_emails}</p> |
|
</div> |
|
`; |
|
|
|
result.email_previews.forEach((preview, index) => { |
|
previewHtml += ` |
|
<div class="card mb-3"> |
|
<div class="card-header"> |
|
<h6>${index + 1}. ${preview.email_type.replace('_', ' ').toUpperCase()}</h6> |
|
<p class="mb-0"><strong>Subject:</strong> ${preview.subject}</p> |
|
</div> |
|
<div class="card-body"> |
|
${preview.error ? |
|
`<div class="alert alert-danger">Error: ${preview.error}</div>` : |
|
` |
|
<p><strong>Properties Included:</strong> ${preview.recommendations_count}</p> |
|
<div class="row"> |
|
<div class="col-md-6"> |
|
<h6>Sample Properties:</h6> |
|
${preview.properties_included.map(prop => |
|
`<p>β’ ${prop.name} - βΉ${prop.price} (${prop.type}) - Score: ${prop.score}</p>` |
|
).join('')} |
|
</div> |
|
<div class="col-md-6"> |
|
<h6>Email Content Preview:</h6> |
|
<div style="max-height: 150px; overflow-y: auto; border: 1px solid #ddd; padding: 10px;"> |
|
${preview.text_content.substring(0, 300)}... |
|
</div> |
|
</div> |
|
</div> |
|
` |
|
} |
|
</div> |
|
</div> |
|
`; |
|
}); |
|
|
|
document.getElementById('multiAiResults').innerHTML = previewHtml; |
|
showSuccess('β
All email content previews generated successfully'); |
|
} else { |
|
showError(`β Failed to preview email content: ${result.error}`); |
|
} |
|
} catch (error) { |
|
showError(`β Error previewing email content: ${error.message}`); |
|
} |
|
} |
|
|
|
async function testAll10Emails() { |
|
try { |
|
const customerId = document.getElementById('customerId').value || 144; |
|
const email = document.getElementById('testEmail').value; |
|
|
|
if (!email) { |
|
showError('Please enter an email address'); |
|
return; |
|
} |
|
|
|
showSuccess('Preparing to send all 10 email types... Ensuring properties are available...'); |
|
|
|
// First, make sure properties are fetched |
|
try { |
|
const fetchResponse = await fetch('/api/fetch-all-properties'); |
|
const fetchResult = await fetchResponse.json(); |
|
if (fetchResult.success) { |
|
showSuccess(`β
Properties ready: ${fetchResult.summary.total_stored} properties available`); |
|
} |
|
} catch (fetchError) { |
|
showError('Warning: Could not verify property availability, continuing anyway...'); |
|
} |
|
|
|
showSuccess('Sending all 10 email types with real properties... This may take a few minutes.'); |
|
|
|
const response = await fetch(`/api/test-all-10-emails/${customerId}`, { |
|
method: 'POST', |
|
headers: { |
|
'Content-Type': 'application/json', |
|
}, |
|
body: JSON.stringify({ email: email }) |
|
}); |
|
|
|
const result = await response.json(); |
|
|
|
if (result.success) { |
|
let resultsHtml = ` |
|
<div class="alert alert-success"> |
|
<h5><i class="fas fa-envelope-open-text"></i> All 10 Email Types Test Results</h5> |
|
<p><strong>Customer ID:</strong> ${result.customer_id}</p> |
|
<p><strong>Recipient:</strong> ${result.recipient_email}</p> |
|
<p><strong>Total Attempted:</strong> ${result.test_results.total_attempted}</p> |
|
<p><strong>Successfully Sent:</strong> ${result.test_results.total_sent}</p> |
|
<p><strong>Failed:</strong> ${result.test_results.total_failed}</p> |
|
<p><strong>ChromaDB Status:</strong> ${result.chromadb_status}</p> |
|
</div> |
|
`; |
|
|
|
if (result.test_results.sent_emails.length > 0) { |
|
resultsHtml += '<h6>β
Successfully Sent Emails:</h6>'; |
|
result.test_results.sent_emails.forEach((email, index) => { |
|
resultsHtml += ` |
|
<div class="card mb-2"> |
|
<div class="card-body"> |
|
<h6>${index + 1}. ${email.type.replace('_', ' ').toUpperCase()}</h6> |
|
<p><strong>Subject:</strong> ${email.subject}</p> |
|
<p><strong>Strategy:</strong> ${email.strategy}</p> |
|
<p><strong>Properties:</strong> ${email.recommendations_count} from ChromaDB</p> |
|
<p><strong>Sample Properties:</strong></p> |
|
<ul> |
|
${email.sample_properties.map(prop => |
|
`<li>${prop.name} - βΉ${prop.price} (${prop.type}) - AI Score: ${prop.ai_score}</li>` |
|
).join('')} |
|
</ul> |
|
<small class="text-muted">Sent at: ${email.timestamp}</small> |
|
</div> |
|
</div> |
|
`; |
|
}); |
|
} |
|
|
|
if (result.test_results.failed_emails.length > 0) { |
|
resultsHtml += '<h6>β Failed Emails:</h6>'; |
|
result.test_results.failed_emails.forEach((email, index) => { |
|
resultsHtml += ` |
|
<div class="alert alert-danger"> |
|
<strong>${index + 1}. ${email.type}:</strong> ${email.error} |
|
<br><small>Strategy: ${email.strategy}</small> |
|
</div> |
|
`; |
|
}); |
|
} |
|
|
|
document.getElementById('multiAiResults').innerHTML = resultsHtml; |
|
showSuccess(`β
Email test completed! ${result.test_results.total_sent}/${result.test_results.total_attempted} emails sent successfully.`); |
|
} else { |
|
showError(`β Failed to test emails: ${result.error}`); |
|
} |
|
} catch (error) { |
|
showError(`β Error testing emails: ${error.message}`); |
|
} |
|
} |
|
|
|
async function checkChromaDBStatus() { |
|
try { |
|
showSuccess('Checking ChromaDB status...'); |
|
|
|
const response = await fetch('/api/chromadb-status'); |
|
const result = await response.json(); |
|
|
|
if (result.success) { |
|
let statusHtml = ` |
|
<div class="alert alert-${result.chromadb_initialized ? (result.property_count > 0 ? 'success' : 'warning') : 'danger'}"> |
|
<h5><i class="fas fa-database"></i> ChromaDB Status Report</h5> |
|
<p><strong>Initialized:</strong> ${result.chromadb_initialized ? 'β
Yes' : 'β No'}</p> |
|
`; |
|
|
|
if (result.chromadb_initialized) { |
|
statusHtml += ` |
|
<p><strong>Collection Name:</strong> ${result.collection_name}</p> |
|
<p><strong>Property Count:</strong> ${result.property_count}</p> |
|
<p><strong>Status:</strong> ${result.status === 'ready' ? 'β
Ready' : 'β οΈ Empty'}</p> |
|
`; |
|
} |
|
|
|
statusHtml += ` |
|
<p><strong>Message:</strong> ${result.message}</p> |
|
<p><strong>Timestamp:</strong> ${result.timestamp}</p> |
|
</div> |
|
`; |
|
|
|
document.getElementById('multiAiResults').innerHTML = statusHtml; |
|
|
|
if (result.property_count > 0) { |
|
showSuccess(`β
ChromaDB ready with ${result.property_count} properties!`); |
|
} else { |
|
showError(`β οΈ ChromaDB is empty. Click "Fetch Properties" to populate it.`); |
|
} |
|
} else { |
|
showError(`β ChromaDB status check failed: ${result.error}`); |
|
} |
|
} catch (error) { |
|
showError(`β Error checking ChromaDB status: ${error.message}`); |
|
} |
|
} |
|
|
|
async function showEmailTypes() { |
|
const emailTypes = [ |
|
{ type: 'property_based', description: 'Properties matching customer\'s preferred property types', icon: 'π ' }, |
|
{ type: 'price_based', description: 'Properties within customer\'s budget range', icon: 'π°' }, |
|
{ type: 'location_based', description: 'Properties in customer\'s preferred locations', icon: 'π' }, |
|
{ type: 'similarity_based', description: 'Properties similar to customer\'s viewed properties', icon: 'π' }, |
|
{ type: 'behavioral_based', description: 'Properties based on customer behavior patterns', icon: 'π§ ' }, |
|
{ type: 'premium_properties', description: 'High-end luxury properties', icon: 'β' }, |
|
{ type: 'budget_friendly', description: 'Value-for-money properties', icon: 'π΅' }, |
|
{ type: 'trending_properties', description: 'Currently trending market properties', icon: 'π' }, |
|
{ type: 'family_oriented', description: 'Family-suitable properties with amenities', icon: 'π¨βπ©βπ§βπ¦' }, |
|
{ type: 'investment_opportunities', description: 'Properties with high ROI potential', icon: 'πΌ' } |
|
]; |
|
|
|
let typesHtml = ` |
|
<div class="alert alert-info"> |
|
<h5><i class="fas fa-list"></i> All 10 Email Types & ChromaDB Strategies</h5> |
|
<p>Each email type uses unique ChromaDB vector search strategies:</p> |
|
</div> |
|
`; |
|
|
|
emailTypes.forEach((emailType, index) => { |
|
typesHtml += ` |
|
<div class="card mb-2"> |
|
<div class="card-body"> |
|
<h6>${emailType.icon} ${index + 1}. ${emailType.type.replace('_', ' ').toUpperCase()}</h6> |
|
<p class="mb-0">${emailType.description}</p> |
|
</div> |
|
</div> |
|
`; |
|
}); |
|
|
|
document.getElementById('multiAiResults').innerHTML = typesHtml; |
|
showSuccess('β
All email types displayed'); |
|
} |
|
|
|
// Utility Functions |
|
function formatPrice(price) { |
|
return new Intl.NumberFormat('en-IN').format(price); |
|
} |
|
|
|
function formatDuration(seconds) { |
|
const hours = Math.floor(seconds / 3600); |
|
const minutes = Math.floor((seconds % 3600) / 60); |
|
return `${hours}h ${minutes}m`; |
|
} |
|
|
|
function showSuccess(message) { |
|
const alert = document.createElement('div'); |
|
alert.className = 'alert alert-success alert-dismissible fade show position-fixed'; |
|
alert.style.cssText = 'top: 20px; right: 20px; z-index: 9999; max-width: 400px;'; |
|
alert.innerHTML = ` |
|
${message} |
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button> |
|
`; |
|
document.body.appendChild(alert); |
|
|
|
setTimeout(() => { |
|
if (alert.parentNode) { |
|
alert.remove(); |
|
} |
|
}, 5000); |
|
} |
|
|
|
function showError(message) { |
|
const alert = document.createElement('div'); |
|
alert.className = 'alert alert-danger alert-dismissible fade show position-fixed'; |
|
alert.style.cssText = 'top: 20px; right: 20px; z-index: 9999; max-width: 400px;'; |
|
alert.innerHTML = ` |
|
${message} |
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button> |
|
`; |
|
document.body.appendChild(alert); |
|
|
|
setTimeout(() => { |
|
if (alert.parentNode) { |
|
alert.remove(); |
|
} |
|
}, 5000); |
|
} |
|
|
|
// List saved emails function |
|
function listSavedEmails() { |
|
console.log('Getting saved emails...'); |
|
document.getElementById('emailTestResults').innerHTML = '<div class="alert alert-info"><i class="fas fa-spinner fa-spin"></i> Loading saved emails...</div>'; |
|
|
|
fetch(`${API_BASE_URL}/api/saved-emails`) |
|
.then(response => response.json()) |
|
.then(data => { |
|
let html = '<div class="alert alert-success"><h5><i class="fas fa-folder-open"></i> Saved Emails</h5>'; |
|
|
|
if (data.saved_emails && data.saved_emails.length > 0) { |
|
html += `<p><strong>Found ${data.total_count} saved email files:</strong></p>`; |
|
html += '<div class="row">'; |
|
|
|
data.saved_emails.forEach(email => { |
|
html += ` |
|
<div class="col-md-6 mb-3"> |
|
<div class="card"> |
|
<div class="card-body"> |
|
<h6 class="card-title">${email.email_type}</h6> |
|
<p class="card-text"> |
|
<small class="text-muted"> |
|
π
${email.created_time}<br> |
|
π ${email.size_kb} KB |
|
</small> |
|
</p> |
|
<a href="${API_BASE_URL}/view-email/${email.filename}" target="_blank" class="btn btn-primary btn-sm"> |
|
<i class="fas fa-external-link-alt"></i> Open Email |
|
</a> |
|
</div> |
|
</div> |
|
</div> |
|
`; |
|
}); |
|
|
|
html += '</div>'; |
|
} else { |
|
html += '<p>No saved emails found. Emails will be saved here when SendGrid limits are exceeded.</p>'; |
|
} |
|
|
|
html += '</div>'; |
|
document.getElementById('emailTestResults').innerHTML = html; |
|
}) |
|
.catch(error => { |
|
console.error('Error:', error); |
|
document.getElementById('emailTestResults').innerHTML = |
|
'<div class="alert alert-danger"><i class="fas fa-exclamation-triangle"></i> Error loading saved emails: ' + error.message + '</div>'; |
|
}); |
|
} |
|
|
|
// Auto-analyze customer 144 on page load |
|
window.onload = function() { |
|
analyzeCustomer(); |
|
}; |
|
</script> |
|
|
|
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script> |
|
</body> |
|
</html> |