Files
vendoo/extension/popup.js
T
Masterluke77andGitHub 6f48827f4d Vendoo 1.41.2 – Git Ignore Boundary & Module Tracking Hotfix (#18)
* docs: prepare Vendoo 1.41.2 git-ignore boundary hotfix

* fix: track native source modules with root-anchored runtime ignores
2026-07-09 17:09:00 +02:00

130 lines
6.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const browserApi = globalThis.browser || null;
const chromeApi = globalThis.chrome || null;
const $ = selector => document.querySelector(selector);
const state = { queue: [], current: 0, serverUrl: 'http://localhost:8124' };
function sendMessage(message) {
if (browserApi) return browserApi.runtime.sendMessage(message);
return new Promise((resolve, reject) => {
chromeApi.runtime.sendMessage(message, response => {
const error = chromeApi.runtime.lastError;
if (error) reject(new Error(error.message)); else resolve(response);
});
});
}
function storageGet(keys) {
if (browserApi) return browserApi.storage.local.get(keys);
return new Promise(resolve => chromeApi.storage.local.get(keys, resolve));
}
function storageSet(values) {
if (browserApi) return browserApi.storage.local.set(values);
return new Promise(resolve => chromeApi.storage.local.set(values, resolve));
}
function openTab(url) {
if (browserApi) return browserApi.tabs.create({ url });
return chromeApi.tabs.create({ url });
}
async function ensureServerPermission(url) {
const parsed = new URL(url);
const origin = `${parsed.protocol}//${parsed.host}/*`;
const permissions = browserApi?.permissions || chromeApi?.permissions;
if (!permissions) return true;
if (browserApi) {
if (await permissions.contains({ origins: [origin] })) return true;
return permissions.request({ origins: [origin] });
}
return new Promise(resolve => permissions.contains({ origins: [origin] }, has => has ? resolve(true) : permissions.request({ origins: [origin] }, resolve)));
}
async function api(path, method = 'GET', body) {
const response = await sendMessage({ type: 'api', serverUrl: state.serverUrl, path, method, body });
if (!response?.ok) throw new Error(response?.data?.error || response?.error || 'Server nicht erreichbar');
return response.data;
}
function setConnection(ok, text) {
const chip = $('#connection-chip');
chip.className = `connection-chip ${ok ? 'ok' : 'error'}`;
chip.querySelector('span').textContent = text;
}
async function imageData(filename) {
if (!filename) return '';
const url = `${state.serverUrl}/uploads/${String(filename).split('/').map(encodeURIComponent).join('/')}`;
const response = await sendMessage({ type: 'fetch-image', url });
return response?.ok ? response.dataUrl : '';
}
function formatDate(value) {
const date = new Date(String(value || '').replace(' ', 'T') + 'Z');
return Number.isNaN(date.getTime()) ? '' : date.toLocaleString('de-DE', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' });
}
async function renderCurrent() {
const listing = state.queue[state.current];
$('#listing-card').classList.toggle('hidden', !listing);
$('#empty-card').classList.toggle('hidden', !!listing);
if (!listing) return;
$('#listing-title').textContent = listing.title || 'Ohne Titel';
$('#listing-meta').textContent = [listing.size, listing.color, listing.condition].filter(Boolean).join(' · ') || 'Noch keine Eigenschaften';
$('#listing-sku').textContent = listing.sku || `VD-${String(listing.id).padStart(4, '0')}`;
$('#listing-price').textContent = listing.price ? `${Number(listing.price).toFixed(2).replace('.', ',')} €` : '';
$('#listing-created').textContent = formatDate(listing.created_at);
const src = await imageData(listing.photos?.[0]);
const image = $('#listing-image');
if (src) { image.src = src; image.classList.remove('hidden'); } else { image.removeAttribute('src'); image.classList.add('hidden'); }
}
async function loadQueue() {
try {
const data = await api('/api/extension/queue?platform=vinted');
state.queue = data.queue || [];
state.current = Math.min(state.current, Math.max(0, state.queue.length - 1));
setConnection(true, 'Verbunden');
$('#queue-state').textContent = state.queue.length ? 'Bereit zur Übertragung' : 'Queue leer';
$('#queue-count').textContent = `${state.queue.length} / ${data.total || state.queue.length}`;
$('#queue-progress-fill').style.width = `${data.total ? ((data.total - state.queue.length) / data.total) * 100 : 0}%`;
await renderCurrent();
} catch (error) {
setConnection(false, 'Offline');
$('#queue-state').textContent = error.message;
$('#listing-card').classList.add('hidden');
$('#empty-card').classList.remove('hidden');
}
}
async function init() {
const settings = await storageGet(['serverUrl', 'provider', 'language']);
state.serverUrl = String(settings.serverUrl || 'http://localhost:8124').replace(/\/$/, '');
$('#server-url').value = state.serverUrl;
if (settings.provider) $('#provider').value = settings.provider;
if (settings.language) $('#language').value = settings.language;
await loadQueue();
}
function openUrl(url) { openTab(url); }
$('#settings-toggle').addEventListener('click', () => { $('#dashboard-view').classList.add('hidden'); $('#settings-view').classList.remove('hidden'); });
$('#back-dashboard').addEventListener('click', () => { $('#settings-view').classList.add('hidden'); $('#dashboard-view').classList.remove('hidden'); });
$('#save-settings').addEventListener('click', async () => {
state.serverUrl = $('#server-url').value.trim().replace(/\/$/, '');
if (!await ensureServerPermission(state.serverUrl)) throw new Error('Zugriff auf die Serveradresse wurde nicht erlaubt.');
await storageSet({ serverUrl: state.serverUrl, provider: $('#provider').value, language: $('#language').value });
$('#settings-view').classList.add('hidden'); $('#dashboard-view').classList.remove('hidden');
await loadQueue();
});
$('#next-listing').addEventListener('click', async () => { if (state.queue.length) state.current = (state.current + 1) % state.queue.length; await renderCurrent(); });
$('#fill-listing').addEventListener('click', async () => {
const listing = state.queue[state.current];
if (!listing) return;
await storageSet({ pendingFillListingId: listing.id });
openUrl('https://www.vinted.de/items/new');
window.close();
});
$('#prepare-images').addEventListener('click', () => openUrl(`${state.serverUrl}/#publish`));
$('#open-queue').addEventListener('click', () => openUrl(`${state.serverUrl}/#publish`));
$('#open-app').addEventListener('click', () => openUrl(state.serverUrl));
$('#empty-open-app').addEventListener('click', () => openUrl(state.serverUrl));
init();