@codejoy/random-learner
Version:
A comprehensive interview preparation and learning companion with AI-powered questions, mock interviews, skill assessments, and company-specific question sets for technical job interviews
1,082 lines (919 loc) • 37.6 kB
HTML
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Company Question Sets - Random Learner</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
color: #333;
}
.container {
max-width: 1200px;
margin: 0 auto;
background: white;
border-radius: 20px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
padding: 30px;
text-align: center;
}
.header h1 {
font-size: 2.5em;
margin-bottom: 10px;
}
.header p {
font-size: 1.1em;
opacity: 0.9;
}
.content {
padding: 30px;
}
/* Loading State */
.loading {
text-align: center;
padding: 60px;
color: #666;
}
.loading::after {
content: '';
width: 30px;
height: 30px;
border: 3px solid #667eea;
border-top: 3px solid transparent;
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 20px auto;
display: block;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Stats Overview */
.stats-overview {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin-bottom: 40px;
}
.stat-card {
background: #f8f9fa;
border-radius: 15px;
padding: 25px;
text-align: center;
border-left: 5px solid #667eea;
}
.stat-value {
font-size: 2.5em;
font-weight: bold;
color: #667eea;
margin-bottom: 10px;
}
.stat-label {
color: #666;
font-size: 0.9em;
}
/* Company Grid */
.companies-section {
margin-bottom: 40px;
}
.section-title {
font-size: 1.8em;
color: #333;
margin-bottom: 25px;
display: flex;
align-items: center;
}
.section-title::before {
content: '';
width: 4px;
height: 30px;
background: linear-gradient(135deg, #667eea, #764ba2);
margin-right: 15px;
border-radius: 2px;
}
.companies-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 25px;
}
.company-card {
background: #f8f9fa;
border-radius: 15px;
padding: 25px;
border-left: 5px solid #667eea;
transition: all 0.3s ease;
position: relative;
}
.company-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
}
.company-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 15px;
}
.company-name {
font-size: 1.4em;
font-weight: bold;
color: #333;
}
.company-status {
padding: 4px 12px;
border-radius: 12px;
font-size: 0.8em;
font-weight: bold;
text-transform: uppercase;
}
.status-available {
background: #d4edda;
color: #155724;
}
.status-empty {
background: #f8d7da;
color: #721c24;
}
.status-downloading {
background: #fff3cd;
color: #856404;
}
.company-description {
color: #666;
margin-bottom: 20px;
line-height: 1.5;
}
.company-stats {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 15px;
margin-bottom: 20px;
}
.company-stat {
text-align: center;
padding: 10px;
background: white;
border-radius: 8px;
}
.company-stat-value {
font-size: 1.5em;
font-weight: bold;
color: #667eea;
}
.company-stat-label {
font-size: 0.8em;
color: #666;
}
.company-actions {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.action-btn {
padding: 10px 20px;
border: none;
border-radius: 8px;
font-size: 0.9em;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
flex: 1;
min-width: 120px;
}
.btn-primary {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
}
.btn-secondary {
background: #6c757d;
color: white;
}
.btn-success {
background: #28a745;
color: white;
}
.btn-danger {
background: #dc3545;
color: white;
}
.action-btn:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
}
.action-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
/* Download Progress */
.download-progress {
display: none;
margin-top: 15px;
padding: 15px;
background: white;
border-radius: 10px;
border: 2px solid #667eea;
}
.progress-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.progress-title {
font-weight: bold;
color: #333;
}
.progress-percentage {
font-weight: bold;
color: #667eea;
}
.progress-bar {
height: 8px;
background: #e9ecef;
border-radius: 4px;
overflow: hidden;
margin-bottom: 10px;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #667eea, #764ba2);
width: 0%;
transition: width 0.3s ease;
}
.progress-message {
font-size: 0.9em;
color: #666;
}
/* Download History */
.download-history {
margin-bottom: 40px;
}
.history-table {
width: 100%;
border-collapse: collapse;
background: #f8f9fa;
border-radius: 10px;
overflow: hidden;
}
.history-table th,
.history-table td {
padding: 12px 15px;
text-align: left;
border-bottom: 1px solid #e9ecef;
}
.history-table th {
background: #667eea;
color: white;
font-weight: bold;
}
.history-table tr:hover {
background: #e9ecef;
}
.status-success {
color: #28a745;
font-weight: bold;
}
.status-failed {
color: #dc3545;
font-weight: bold;
}
/* Global Actions */
.global-actions {
text-align: center;
padding: 30px;
background: #f8f9fa;
border-radius: 15px;
margin-top: 30px;
}
.global-actions h3 {
margin-bottom: 20px;
color: #333;
}
.global-btn {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border: none;
padding: 15px 30px;
border-radius: 25px;
font-size: 1.1em;
font-weight: bold;
cursor: pointer;
margin: 0 10px;
transition: all 0.3s ease;
}
.global-btn:hover {
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(102, 126, 234, 0.3);
}
.global-btn.danger {
background: #dc3545;
}
.global-btn.secondary {
background: #6c757d;
}
/* Responsive Design */
@media (max-width: 768px) {
.companies-grid {
grid-template-columns: 1fr;
}
.stats-overview {
grid-template-columns: repeat(2, 1fr);
}
.company-stats {
grid-template-columns: 1fr;
}
.company-actions {
flex-direction: column;
}
.action-btn {
min-width: auto;
}
}
/* Modal Styles */
.modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.5);
}
.modal-content {
background-color: white;
margin: 5% auto;
padding: 30px;
border-radius: 15px;
width: 90%;
max-width: 600px;
max-height: 80vh;
overflow-y: auto;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 2px solid #f0f0f0;
}
.modal-title {
font-size: 1.5em;
color: #333;
}
.close-btn {
background: none;
border: none;
font-size: 1.5em;
cursor: pointer;
color: #666;
}
.close-btn:hover {
color: #333;
}
/* AI Configuration */
.ai-config {
background: #f8f9fa;
border-radius: 10px;
padding: 20px;
margin-bottom: 20px;
}
.ai-status {
display: flex;
align-items: center;
margin-bottom: 15px;
}
.status-indicator {
width: 12px;
height: 12px;
border-radius: 50%;
margin-right: 10px;
}
.status-connected {
background: #28a745;
}
.status-disconnected {
background: #dc3545;
}
.ai-provider {
font-weight: bold;
color: #333;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🏢 Company Question Sets</h1>
<p>Download and manage AI-generated interview questions for specific companies</p>
</div>
<div class="content">
<!-- Loading State -->
<div class="loading" id="loading">
Loading company question sets...
</div>
<!-- Main Content -->
<div id="main-content" style="display: none;">
<!-- Stats Overview -->
<div class="stats-overview" id="stats-overview">
<!-- Stats will be populated by JavaScript -->
</div>
<!-- AI Configuration Status -->
<div class="ai-config" id="ai-config">
<div class="ai-status">
<div class="status-indicator" id="ai-status-indicator"></div>
<span class="ai-provider" id="ai-provider">Checking AI connection...</span>
</div>
<p id="ai-description">AI is required to download company-specific question sets.</p>
</div>
<!-- Companies Section -->
<div class="companies-section">
<h2 class="section-title">🏢 Available Companies</h2>
<div class="companies-grid" id="companies-grid">
<!-- Company cards will be populated by JavaScript -->
</div>
</div>
<!-- Download History -->
<div class="download-history">
<h2 class="section-title">📈 Recent Downloads</h2>
<table class="history-table" id="history-table">
<thead>
<tr>
<th>Company</th>
<th>Questions</th>
<th>Duration</th>
<th>Status</th>
<th>Date</th>
</tr>
</thead>
<tbody id="history-tbody">
<!-- History will be populated by JavaScript -->
</tbody>
</table>
</div>
<!-- Global Actions -->
<div class="global-actions">
<h3>🛠️ Management Actions</h3>
<button class="global-btn" id="download-all-btn">📥 Download All Companies</button>
<button class="global-btn secondary" id="export-all-btn">📤 Export All Questions</button>
<button class="global-btn danger" id="clear-all-btn">🗑️ Clear All Questions</button>
<button class="global-btn secondary" onclick="closeWindow()">✖️ Close</button>
</div>
</div>
</div>
</div>
<!-- Company Details Modal -->
<div id="company-modal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title" id="modal-company-name">Company Details</h3>
<button class="close-btn" onclick="closeModal()">×</button>
</div>
<div id="modal-content">
<!-- Modal content will be populated by JavaScript -->
</div>
</div>
</div>
<script>
const { ipcRenderer } = require('electron');
let companyData = {};
let downloadStats = {};
let aiStatus = { connected: false, provider: 'none' };
let activeDownloads = new Set();
// Initialize the interface
async function initializeInterface() {
try {
console.log('Initializing company questions interface...');
// Load data
await loadCompanyData();
await checkAIStatus();
// Display content
displayStats();
displayCompanies();
displayDownloadHistory();
// Setup event listeners
setupEventListeners();
// Show main content
document.getElementById('loading').style.display = 'none';
document.getElementById('main-content').style.display = 'block';
} catch (error) {
console.error('Failed to initialize interface:', error);
showError('Failed to load company question sets');
}
}
// Load company data
async function loadCompanyData() {
try {
companyData = await ipcRenderer.invoke('get-company-question-summary');
downloadStats = await ipcRenderer.invoke('get-company-download-stats');
console.log('Company data loaded:', companyData);
} catch (error) {
console.error('Failed to load company data:', error);
throw error;
}
}
// Check AI status
async function checkAIStatus() {
try {
const settings = await ipcRenderer.invoke('get-settings');
const aiEnabled = settings.questionSettings?.useAI || settings.questionSettings?.useOpenAI;
if (aiEnabled) {
const provider = settings.aiProvider || 'openai';
const apiKey = provider === 'gemini' ? settings.geminiApiKey : settings.openaiApiKey;
if (apiKey) {
aiStatus = { connected: true, provider: provider };
} else {
aiStatus = { connected: false, provider: provider, reason: 'No API key configured' };
}
} else {
aiStatus = { connected: false, provider: 'none', reason: 'AI not enabled' };
}
updateAIStatus();
} catch (error) {
console.error('Failed to check AI status:', error);
aiStatus = { connected: false, provider: 'unknown', reason: 'Connection check failed' };
updateAIStatus();
}
}
// Update AI status display
function updateAIStatus() {
const indicator = document.getElementById('ai-status-indicator');
const provider = document.getElementById('ai-provider');
const description = document.getElementById('ai-description');
if (aiStatus.connected) {
indicator.className = 'status-indicator status-connected';
provider.textContent = `${aiStatus.provider.toUpperCase()} Connected`;
description.textContent = 'AI is ready to generate company-specific questions.';
} else {
indicator.className = 'status-indicator status-disconnected';
provider.textContent = `AI Not Available`;
description.textContent = `${aiStatus.reason || 'AI connection required'}. Please configure AI in settings.`;
}
}
// Display stats
function displayStats() {
const container = document.getElementById('stats-overview');
container.innerHTML = '';
const totalCompanies = Object.keys(companyData).length;
const availableCompanies = Object.values(companyData).filter(c => c.isAvailable).length;
const totalQuestions = Object.values(companyData).reduce((sum, c) => sum + c.totalQuestions, 0);
const totalDownloads = downloadStats.totalDownloads || 0;
const stats = [
{ label: 'Total Companies', value: totalCompanies },
{ label: 'Available Sets', value: availableCompanies },
{ label: 'Total Questions', value: totalQuestions },
{ label: 'Downloads', value: totalDownloads }
];
stats.forEach(stat => {
const card = document.createElement('div');
card.className = 'stat-card';
card.innerHTML = `
<div class="stat-value">${stat.value}</div>
<div class="stat-label">${stat.label}</div>
`;
container.appendChild(card);
});
}
// Display companies
function displayCompanies() {
const container = document.getElementById('companies-grid');
container.innerHTML = '';
Object.entries(companyData).forEach(([companyKey, company]) => {
const card = document.createElement('div');
card.className = 'company-card';
card.dataset.company = companyKey;
const status = company.isAvailable ? 'available' : 'empty';
const statusText = company.isAvailable ? 'Available' : 'No Questions';
const questionTypes = Object.entries(company.questionTypes || {})
.map(([type, count]) => `${type}: ${count}`)
.join(', ') || 'None';
const lastUpdated = company.lastUpdated
? new Date(company.lastUpdated).toLocaleDateString()
: 'Never';
card.innerHTML = `
<div class="company-header">
<div class="company-name">${company.name}</div>
<div class="company-status status-${status}">${statusText}</div>
</div>
<div class="company-description">${company.description}</div>
<div class="company-stats">
<div class="company-stat">
<div class="company-stat-value">${company.totalQuestions}</div>
<div class="company-stat-label">Questions</div>
</div>
<div class="company-stat">
<div class="company-stat-value">${Object.keys(company.questionTypes || {}).length}</div>
<div class="company-stat-label">Types</div>
</div>
</div>
<div class="company-actions">
<button class="action-btn btn-primary" onclick="downloadCompanyQuestions('${companyKey}')"
${!aiStatus.connected ? 'disabled' : ''}>
📥 Download
</button>
<button class="action-btn btn-secondary" onclick="viewCompanyDetails('${companyKey}')">
👁️ View
</button>
${company.isAvailable ? `
<button class="action-btn btn-success" onclick="exportCompanyQuestions('${companyKey}')">
📤 Export
</button>
<button class="action-btn btn-danger" onclick="deleteCompanyQuestions('${companyKey}')">
🗑️ Delete
</button>
` : ''}
</div>
<div class="download-progress" id="progress-${companyKey}">
<div class="progress-header">
<div class="progress-title">Downloading Questions...</div>
<div class="progress-percentage" id="percentage-${companyKey}">0%</div>
</div>
<div class="progress-bar">
<div class="progress-fill" id="fill-${companyKey}"></div>
</div>
<div class="progress-message" id="message-${companyKey}">Preparing download...</div>
</div>
`;
container.appendChild(card);
});
}
// Display download history
function displayDownloadHistory() {
const tbody = document.getElementById('history-tbody');
tbody.innerHTML = '';
const history = downloadStats.downloadHistory || [];
if (history.length === 0) {
tbody.innerHTML = '<tr><td colspan="5" style="text-align: center; color: #666;">No downloads yet</td></tr>';
return;
}
history.forEach(download => {
const row = document.createElement('tr');
const duration = Math.round(download.duration / 1000);
const date = new Date(download.endTime).toLocaleString();
const status = download.success ? 'Success' : 'Failed';
const statusClass = download.success ? 'status-success' : 'status-failed';
row.innerHTML = `
<td>${companyData[download.company]?.name || download.company}</td>
<td>${download.questionsGenerated}</td>
<td>${duration}s</td>
<td class="${statusClass}">${status}</td>
<td>${date}</td>
`;
tbody.appendChild(row);
});
}
// Download company questions
async function downloadCompanyQuestions(companyKey) {
if (!aiStatus.connected) {
alert('AI connection required. Please configure AI in settings first.');
return;
}
if (activeDownloads.has(companyKey)) {
alert('Download already in progress for this company.');
return;
}
try {
activeDownloads.add(companyKey);
// Show progress
const progressDiv = document.getElementById(`progress-${companyKey}`);
progressDiv.style.display = 'block';
// Disable download button
const card = document.querySelector(`[data-company="${companyKey}"]`);
const downloadBtn = card.querySelector('.btn-primary');
downloadBtn.disabled = true;
downloadBtn.textContent = '⏳ Downloading...';
// Start download
const result = await ipcRenderer.invoke('download-company-questions', companyKey);
if (result.success) {
alert(`Successfully downloaded ${result.questionsGenerated} questions for ${result.company}!`);
// Reload data and refresh display
await loadCompanyData();
displayStats();
displayCompanies();
displayDownloadHistory();
} else {
throw new Error(result.error || 'Download failed');
}
} catch (error) {
console.error('Download failed:', error);
alert(`Failed to download questions: ${error.message}`);
// Hide progress
const progressDiv = document.getElementById(`progress-${companyKey}`);
progressDiv.style.display = 'none';
// Re-enable button
const card = document.querySelector(`[data-company="${companyKey}"]`);
const downloadBtn = card.querySelector('.btn-primary');
downloadBtn.disabled = false;
downloadBtn.textContent = '📥 Download';
} finally {
activeDownloads.delete(companyKey);
}
}
// Update download progress
function updateDownloadProgress(companyKey, progress) {
const fillElement = document.getElementById(`fill-${companyKey}`);
const percentageElement = document.getElementById(`percentage-${companyKey}`);
const messageElement = document.getElementById(`message-${companyKey}`);
if (fillElement) fillElement.style.width = `${progress.progress}%`;
if (percentageElement) percentageElement.textContent = `${Math.round(progress.progress)}%`;
if (messageElement) messageElement.textContent = progress.message;
}
// View company details
function viewCompanyDetails(companyKey) {
const company = companyData[companyKey];
if (!company) return;
document.getElementById('modal-company-name').textContent = company.name;
const questionTypesList = Object.entries(company.questionTypes || {})
.map(([type, count]) => `<li><strong>${type}:</strong> ${count} questions</li>`)
.join('');
const lastUpdated = company.lastUpdated
? new Date(company.lastUpdated).toLocaleString()
: 'Never';
document.getElementById('modal-content').innerHTML = `
<div style="margin-bottom: 20px;">
<h4>Description</h4>
<p>${company.description}</p>
</div>
<div style="margin-bottom: 20px;">
<h4>Statistics</h4>
<ul>
<li><strong>Total Questions:</strong> ${company.totalQuestions}</li>
<li><strong>Last Updated:</strong> ${lastUpdated}</li>
<li><strong>Status:</strong> ${company.isAvailable ? 'Available' : 'No questions'}</li>
</ul>
</div>
${questionTypesList ? `
<div style="margin-bottom: 20px;">
<h4>Question Types</h4>
<ul>${questionTypesList}</ul>
</div>
` : ''}
<div style="text-align: center; margin-top: 30px;">
<button class="action-btn btn-primary" onclick="downloadCompanyQuestions('${companyKey}')"
${!aiStatus.connected ? 'disabled' : ''}>
📥 Download Questions
</button>
${company.isAvailable ? `
<button class="action-btn btn-success" onclick="exportCompanyQuestions('${companyKey}'); closeModal();">
📤 Export Questions
</button>
` : ''}
</div>
`;
document.getElementById('company-modal').style.display = 'block';
}
// Export company questions
async function exportCompanyQuestions(companyKey) {
try {
const data = await ipcRenderer.invoke('export-company-questions', companyKey);
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${companyKey}-questions-${new Date().toISOString().split('T')[0]}.json`;
a.click();
URL.revokeObjectURL(url);
} catch (error) {
console.error('Export failed:', error);
alert('Failed to export questions: ' + error.message);
}
}
// Delete company questions
async function deleteCompanyQuestions(companyKey) {
const company = companyData[companyKey];
if (!company) return;
if (confirm(`Are you sure you want to delete all ${company.totalQuestions} questions for ${company.name}? This action cannot be undone.`)) {
try {
await ipcRenderer.invoke('delete-company-questions', companyKey);
// Reload data and refresh display
await loadCompanyData();
displayStats();
displayCompanies();
alert(`Successfully deleted questions for ${company.name}.`);
} catch (error) {
console.error('Delete failed:', error);
alert('Failed to delete questions: ' + error.message);
}
}
}
// Setup event listeners
function setupEventListeners() {
// Global actions
document.getElementById('download-all-btn').addEventListener('click', downloadAllCompanies);
document.getElementById('export-all-btn').addEventListener('click', exportAllQuestions);
document.getElementById('clear-all-btn').addEventListener('click', clearAllQuestions);
// Listen for download progress updates
ipcRenderer.on('download-progress', (event, companyKey, progress) => {
updateDownloadProgress(companyKey, progress);
});
// Modal close on outside click
document.getElementById('company-modal').addEventListener('click', (e) => {
if (e.target.id === 'company-modal') {
closeModal();
}
});
}
// Download all companies
async function downloadAllCompanies() {
if (!aiStatus.connected) {
alert('AI connection required. Please configure AI in settings first.');
return;
}
const companies = Object.keys(companyData);
if (confirm(`This will download questions for all ${companies.length} companies. This may take several minutes. Continue?`)) {
for (const companyKey of companies) {
if (!activeDownloads.has(companyKey)) {
try {
await downloadCompanyQuestions(companyKey);
// Small delay between downloads
await new Promise(resolve => setTimeout(resolve, 2000));
} catch (error) {
console.error(`Failed to download ${companyKey}:`, error);
}
}
}
}
}
// Export all questions
async function exportAllQuestions() {
try {
const allData = {};
for (const [companyKey, company] of Object.entries(companyData)) {
if (company.isAvailable) {
allData[companyKey] = await ipcRenderer.invoke('export-company-questions', companyKey);
}
}
const exportData = {
exportedAt: new Date(),
companies: allData,
totalCompanies: Object.keys(allData).length,
totalQuestions: Object.values(allData).reduce((sum, data) => sum + data.totalQuestions, 0)
};
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 = `all-company-questions-${new Date().toISOString().split('T')[0]}.json`;
a.click();
URL.revokeObjectURL(url);
} catch (error) {
console.error('Export all failed:', error);
alert('Failed to export all questions: ' + error.message);
}
}
// Clear all questions
async function clearAllQuestions() {
const totalQuestions = Object.values(companyData).reduce((sum, c) => sum + c.totalQuestions, 0);
if (confirm(`Are you sure you want to delete ALL ${totalQuestions} company questions? This action cannot be undone.`)) {
try {
await ipcRenderer.invoke('clear-all-company-questions');
// Reload data and refresh display
await loadCompanyData();
displayStats();
displayCompanies();
displayDownloadHistory();
alert('Successfully cleared all company questions.');
} catch (error) {
console.error('Clear all failed:', error);
alert('Failed to clear questions: ' + error.message);
}
}
}
// Close modal
function closeModal() {
document.getElementById('company-modal').style.display = 'none';
}
// Close window
function closeWindow() {
window.close();
}
// Show error
function showError(message) {
document.getElementById('loading').innerHTML = `
<h3 style="color: #dc3545;">⚠️ Error</h3>
<p>${message}</p>
<button class="action-btn btn-primary" onclick="closeWindow()">Close</button>
`;
}
// Initialize when page loads
document.addEventListener('DOMContentLoaded', initializeInterface);
</script>
</body>
</html>