Add multi-provider event discovery and improve sync UI
This commit is contained in:
@@ -45,6 +45,12 @@
|
||||
<span class="stat-label">Letzte Aktion</span>
|
||||
<strong id="sync-status">Noch kein Sync ausgefuehrt</strong>
|
||||
</div>
|
||||
<div class="stat-card wide">
|
||||
<span class="stat-label">Quellen</span>
|
||||
<div id="provider-summary" class="provider-summary">
|
||||
<span class="provider-chip">Noch keine Daten</span>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
</header>
|
||||
|
||||
@@ -104,6 +110,12 @@
|
||||
<option value="ticketed">Nur mit Ticket</option>
|
||||
<option value="open">Nur offen</option>
|
||||
</select>
|
||||
<select id="provider-filter">
|
||||
<option value="all">Alle Quellen</option>
|
||||
<option value="ticketmaster">Ticketmaster</option>
|
||||
<option value="bandsintown">Bandsintown</option>
|
||||
<option value="eventim">Eventim</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -9,8 +9,10 @@ const eventsEl = document.querySelector("#events");
|
||||
const notificationsEl = document.querySelector("#notifications");
|
||||
const watchForm = document.querySelector("#watch-form");
|
||||
const eventFilter = document.querySelector("#event-filter");
|
||||
const providerFilter = document.querySelector("#provider-filter");
|
||||
const syncButton = document.querySelector("#sync-button");
|
||||
const toastEl = document.querySelector("#toast");
|
||||
const providerSummaryEl = document.querySelector("#provider-summary");
|
||||
|
||||
function showToast(message) {
|
||||
toastEl.textContent = message;
|
||||
@@ -79,6 +81,51 @@ function renderStats() {
|
||||
document.querySelector("#ticket-count").textContent = state.events.filter(
|
||||
(event) => event.is_ticket_purchased
|
||||
).length;
|
||||
renderProviderSummary();
|
||||
}
|
||||
|
||||
function prettifyProviderName(value) {
|
||||
const names = {
|
||||
ticketmaster: "Ticketmaster",
|
||||
bandsintown: "Bandsintown",
|
||||
eventim: "Eventim",
|
||||
};
|
||||
|
||||
return names[value] || value;
|
||||
}
|
||||
|
||||
function getProviderClass(value) {
|
||||
const classes = {
|
||||
ticketmaster: "provider-ticketmaster",
|
||||
bandsintown: "provider-bandsintown",
|
||||
eventim: "provider-eventim",
|
||||
};
|
||||
|
||||
return classes[value] || "";
|
||||
}
|
||||
|
||||
function renderProviderSummary() {
|
||||
if (!state.events.length) {
|
||||
providerSummaryEl.innerHTML = '<span class="provider-chip">Noch keine Daten</span>';
|
||||
return;
|
||||
}
|
||||
|
||||
const counts = state.events.reduce((accumulator, event) => {
|
||||
const key = event.source || "unknown";
|
||||
accumulator[key] = (accumulator[key] || 0) + 1;
|
||||
return accumulator;
|
||||
}, {});
|
||||
|
||||
providerSummaryEl.innerHTML = Object.entries(counts)
|
||||
.sort((left, right) => right[1] - left[1])
|
||||
.map(
|
||||
([provider, count]) => `
|
||||
<span class="provider-chip ${getProviderClass(provider)}">
|
||||
${escapeHtml(prettifyProviderName(provider))}: ${count}
|
||||
</span>
|
||||
`
|
||||
)
|
||||
.join("");
|
||||
}
|
||||
|
||||
function renderWatchItems() {
|
||||
@@ -126,13 +173,21 @@ function getWatchNameById(id) {
|
||||
|
||||
function renderEvents() {
|
||||
const filterValue = eventFilter.value;
|
||||
const providerValue = providerFilter.value;
|
||||
const filteredEvents = state.events.filter((event) => {
|
||||
if (filterValue === "ticketed") {
|
||||
return event.is_ticket_purchased;
|
||||
if (!event.is_ticket_purchased) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (filterValue === "open") {
|
||||
return !event.is_ticket_purchased;
|
||||
if (filterValue === "open" && event.is_ticket_purchased) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (providerValue !== "all" && event.source !== providerValue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -153,6 +208,9 @@ function renderEvents() {
|
||||
<div class="pill-row">
|
||||
<span class="pill">${escapeHtml(getWatchNameById(event.watch_item_id))}</span>
|
||||
<span class="pill">${escapeHtml(event.city || "ohne Stadt")}</span>
|
||||
<span class="pill ${getProviderClass(event.source)}">
|
||||
${escapeHtml(prettifyProviderName(event.source))}
|
||||
</span>
|
||||
<span class="pill ${event.is_ticket_purchased ? "success" : "warning"}">
|
||||
${event.is_ticket_purchased ? "Ticket markiert" : "ohne Ticket"}
|
||||
</span>
|
||||
@@ -291,6 +349,7 @@ syncButton.addEventListener("click", async () => {
|
||||
});
|
||||
|
||||
eventFilter.addEventListener("change", renderEvents);
|
||||
providerFilter.addEventListener("change", renderEvents);
|
||||
|
||||
document.addEventListener("click", async (event) => {
|
||||
const button = event.target.closest("button[data-action]");
|
||||
|
||||
@@ -143,6 +143,12 @@ h1 {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.provider-summary {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.dashboard-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
@@ -324,6 +330,33 @@ button:hover,
|
||||
color: var(--danger);
|
||||
}
|
||||
|
||||
.provider-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 32px;
|
||||
padding: 0 12px;
|
||||
border-radius: 999px;
|
||||
background: rgba(46, 39, 30, 0.08);
|
||||
color: var(--text);
|
||||
font-family: var(--mono);
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
.provider-ticketmaster {
|
||||
background: rgba(36, 94, 63, 0.12);
|
||||
color: var(--success);
|
||||
}
|
||||
|
||||
.provider-bandsintown {
|
||||
background: rgba(194, 77, 44, 0.12);
|
||||
color: var(--primary-dark);
|
||||
}
|
||||
|
||||
.provider-eventim {
|
||||
background: rgba(86, 60, 153, 0.14);
|
||||
color: #4f3790;
|
||||
}
|
||||
|
||||
.muted {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user