const settingsState = {
accounts: [],
activeAccount: null,
dashboard: null,
auth: null,
continuous: null,
};
const ACTIVE_ACCOUNT_STORAGE_KEY = 'telegramScraper.activeAccount';
async function api(path, options = {}) {
const response = await fetch(path, {
headers: { 'Content-Type': 'application/json' },
...options,
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || 'Request failed');
}
return data;
}
function showToast(message, type = 'info') {
let root = document.getElementById('toast-root');
if (!root) {
root = document.createElement('div');
root.id = 'toast-root';
root.className = 'toast-root';
document.body.appendChild(root);
}
const toast = document.createElement('div');
toast.className = `toast toast-${type}`;
toast.textContent = message;
root.appendChild(toast);
window.setTimeout(() => {
toast.classList.add('toast-hide');
window.setTimeout(() => toast.remove(), 250);
}, 3600);
}
function confirmAction(message) {
return new Promise((resolve) => {
let settled = false;
const done = (value) => {
if (settled) return;
settled = true;
if (dialog.open) dialog.close();
resolve(value);
};
let dialog = document.getElementById('confirm-dialog');
if (!dialog) {
dialog = document.createElement('dialog');
dialog.id = 'confirm-dialog';
dialog.className = 'confirm-dialog';
dialog.innerHTML =
'
Confirm
' +
'
' +
'
' +
'' +
'' +
'
';
document.body.appendChild(dialog);
}
dialog.querySelector('.confirm-dialog-message').textContent = message;
dialog.querySelector('[data-confirm-ok]').onclick = () => done(true);
dialog.querySelector('[data-confirm-cancel]').onclick = () => done(false);
dialog.onclose = () => done(false);
if (!dialog.open) dialog.showModal();
});
}
function setHealthState(el, ok, warnOnly = false) {
el.classList.remove('is-ok', 'is-warn', 'is-dim');
el.classList.add(ok ? 'is-ok' : warnOnly ? 'is-dim' : 'is-warn');
}
function downloadJson(filename, payload) {
const blob = new Blob([JSON.stringify(payload, null, 2) + '\n'], {
type: 'application/json',
});
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = filename;
document.body.appendChild(link);
link.click();
link.remove();
URL.revokeObjectURL(url);
}
function displayTime(value) {
if (!value) return '-';
const date = new Date(value);
if (Number.isNaN(date.getTime())) return String(value).replace('T', ' ').replace('+00:00', ' UTC');
return date.toLocaleString(undefined, {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
});
}
function isAccountAuthorized(auth) {
const status = auth?.auth_status || auth || {};
return (
auth?.phase === 'authorized' ||
auth?.status === 'authorized' ||
status.status === 'ready' ||
status.status === 'authorized'
);
}
function accountLabel(account) {
return account?.label || account?.id || 'No account';
}
function setActiveAccount(accountId) {
settingsState.activeAccount = accountId || null;
if (accountId) {
localStorage.setItem(ACTIVE_ACCOUNT_STORAGE_KEY, accountId);
} else {
localStorage.removeItem(ACTIVE_ACCOUNT_STORAGE_KEY);
}
}
function chooseInitialAccount() {
const requested = new URLSearchParams(window.location.search).get('account');
if (requested && settingsState.accounts.some((account) => account.id === requested)) {
return requested;
}
const saved = localStorage.getItem(ACTIVE_ACCOUNT_STORAGE_KEY);
if (saved && settingsState.accounts.some((account) => account.id === saved)) {
return saved;
}
return settingsState.accounts[0]?.id || null;
}
function renderAccountList() {
const root = document.getElementById('settings-account-list');
root.innerHTML = '';
if (!settingsState.accounts.length) {
root.innerHTML = '