feat(dating-autopilot): ✨ Introduce interactive popup elements with enhanced event handling in popup.js
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
7c8d10c593
commit
ef79f814d5
1 changed files with 158 additions and 0 deletions
|
|
@ -0,0 +1,158 @@
|
|||
// Popup script - display boost state, manual controls, webhook config
|
||||
|
||||
const elements = {
|
||||
toggleEnabled: document.getElementById('toggleEnabled'),
|
||||
status: document.getElementById('status'),
|
||||
errorText: document.getElementById('errorText'),
|
||||
boostStatus: document.getElementById('boostStatus'),
|
||||
boostExpires: document.getElementById('boostExpires'),
|
||||
nextRefresh: document.getElementById('nextRefresh'),
|
||||
statCycles: document.getElementById('statCycles'),
|
||||
statUptime: document.getElementById('statUptime'),
|
||||
lastRefresh: document.getElementById('lastRefresh'),
|
||||
lastCheck: document.getElementById('lastCheck'),
|
||||
webhookUrl: document.getElementById('webhookUrl'),
|
||||
btnRefresh: document.getElementById('btnRefresh'),
|
||||
btnReset: document.getElementById('btnReset'),
|
||||
};
|
||||
|
||||
function formatTime(isoString) {
|
||||
if (!isoString) return '--';
|
||||
const d = new Date(isoString);
|
||||
const now = new Date();
|
||||
const diffMs = d.getTime() - now.getTime();
|
||||
|
||||
// If in the future, show relative time
|
||||
if (diffMs > 0) {
|
||||
const hours = Math.floor(diffMs / 3600000);
|
||||
const mins = Math.floor((diffMs % 3600000) / 60000);
|
||||
if (hours > 0) return `${hours}h ${mins}m`;
|
||||
return `${mins}m`;
|
||||
}
|
||||
|
||||
// If in the past, show relative
|
||||
const ago = Math.abs(diffMs);
|
||||
const mins = Math.floor(ago / 60000);
|
||||
if (mins < 1) return 'just now';
|
||||
if (mins < 60) return `${mins}m ago`;
|
||||
const hours = Math.floor(mins / 60);
|
||||
if (hours < 24) return `${hours}h ${mins % 60}m ago`;
|
||||
return d.toLocaleDateString();
|
||||
}
|
||||
|
||||
function formatUptime(startTime) {
|
||||
if (!startTime) return '0h';
|
||||
const diff = Date.now() - new Date(startTime).getTime();
|
||||
const hours = Math.floor(diff / 3600000);
|
||||
if (hours < 1) {
|
||||
const mins = Math.floor(diff / 60000);
|
||||
return `${mins}m`;
|
||||
}
|
||||
if (hours >= 24) {
|
||||
const days = Math.floor(hours / 24);
|
||||
return `${days}d ${hours % 24}h`;
|
||||
}
|
||||
return `${hours}h`;
|
||||
}
|
||||
|
||||
const statusLabels = {
|
||||
idle: 'Idle',
|
||||
monitoring: 'Monitoring',
|
||||
refreshing: 'Refreshing...',
|
||||
cooldown: 'Cooldown',
|
||||
error: 'Error',
|
||||
disabled: 'Disabled',
|
||||
};
|
||||
|
||||
function updateUI(state) {
|
||||
if (!state) return;
|
||||
|
||||
// Toggle
|
||||
elements.toggleEnabled.checked = state.enabled;
|
||||
|
||||
// Status badge
|
||||
elements.status.className = 'status ' + (state.status || 'idle');
|
||||
elements.status.textContent = statusLabels[state.status] || state.status || 'Idle';
|
||||
|
||||
// Error display
|
||||
if (state.lastError && state.status === 'error') {
|
||||
elements.errorText.textContent = state.lastError;
|
||||
elements.errorText.style.display = 'block';
|
||||
} else {
|
||||
elements.errorText.style.display = 'none';
|
||||
}
|
||||
|
||||
// Boost info
|
||||
elements.boostStatus.textContent = state.boostActive ? 'Active' : 'Inactive';
|
||||
elements.boostExpires.textContent = formatTime(state.boostExpiresAt);
|
||||
elements.nextRefresh.textContent = formatTime(state.nextRefreshAt);
|
||||
|
||||
// Stats
|
||||
elements.statCycles.textContent = state.cycleCount || 0;
|
||||
elements.statUptime.textContent = formatUptime(state.lastRefreshAt ? state.lastRefreshAt : null);
|
||||
|
||||
elements.lastRefresh.textContent = formatTime(state.lastRefreshAt);
|
||||
elements.lastCheck.textContent = formatTime(state.lastCheckAt);
|
||||
|
||||
// Webhook
|
||||
if (state.webhookUrl && !elements.webhookUrl.matches(':focus')) {
|
||||
elements.webhookUrl.value = state.webhookUrl;
|
||||
}
|
||||
|
||||
// Button state
|
||||
elements.btnRefresh.disabled = !state.enabled || state.status === 'refreshing';
|
||||
}
|
||||
|
||||
async function loadState() {
|
||||
const state = await browser.runtime.sendMessage({ action: 'getBoostState' });
|
||||
updateUI(state);
|
||||
}
|
||||
|
||||
// ============== EVENT LISTENERS ==============
|
||||
|
||||
elements.toggleEnabled.addEventListener('change', async () => {
|
||||
const state = await browser.runtime.sendMessage({
|
||||
action: 'setEnabled',
|
||||
enabled: elements.toggleEnabled.checked,
|
||||
});
|
||||
updateUI(state);
|
||||
});
|
||||
|
||||
elements.btnRefresh.addEventListener('click', async () => {
|
||||
elements.btnRefresh.disabled = true;
|
||||
elements.status.className = 'status refreshing';
|
||||
elements.status.textContent = 'Refreshing...';
|
||||
|
||||
const state = await browser.runtime.sendMessage({ action: 'refreshNow' });
|
||||
updateUI(state);
|
||||
});
|
||||
|
||||
elements.btnReset.addEventListener('click', async () => {
|
||||
const state = await browser.runtime.sendMessage({ action: 'resetState' });
|
||||
updateUI(state);
|
||||
});
|
||||
|
||||
let webhookDebounce;
|
||||
elements.webhookUrl.addEventListener('input', () => {
|
||||
clearTimeout(webhookDebounce);
|
||||
webhookDebounce = setTimeout(async () => {
|
||||
await browser.runtime.sendMessage({
|
||||
action: 'setWebhookUrl',
|
||||
url: elements.webhookUrl.value.trim(),
|
||||
});
|
||||
}, 500);
|
||||
});
|
||||
|
||||
// ============== LIVE UPDATES ==============
|
||||
|
||||
browser.runtime.onMessage.addListener((msg) => {
|
||||
if (msg.action === 'stateUpdate' || msg.action === 'statsUpdate') {
|
||||
loadState();
|
||||
}
|
||||
});
|
||||
|
||||
// Refresh display every 30 seconds for time formatting
|
||||
setInterval(loadState, 30000);
|
||||
|
||||
// Initial load
|
||||
loadState();
|
||||
Loading…
Add table
Reference in a new issue