"use strict"; function getCredentialsUsername(client) { return window.localStorage.getItem(`${CLIENT}/${client}/username`); } function getCredentialsPassword(client) { return window.localStorage.getItem(`${CLIENT}/${client}/password`); } function getBasicAuth(client) { return { 'Authorization': 'Basic ' + btoa(getCredentialsUsername(client) + ':' + getCredentialsPassword(client)), } } async function _get(client, path) { const res = await fetch(`${CLIENTS[client]['api']}${path}`, { method: 'GET', headers: {...getBasicAuth(client)}, }); const json = await res.json(); if (!res.ok) throw new ApiError(res.status, json['message']); return json; } async function get(client, path) { return (await _get(client, path))['data']; } async function getWineVarieties(client) { return Object.fromEntries((await get(client, '/wine/varieties')).map(item => [item['sortid'], item])); } async function getWineQualityLevels(client) { return Object.fromEntries((await get(client, '/wine/quality_levels')).map(item => [item['qualid'], item])); } async function getDeliverySchedules(client, filters, limit, offset) { const query = []; if (!!filters) query.push(`filters=${filters.join(',')}`); if (!!limit) query.push(`limit=${limit}`); if (!!offset) query.push(`offset=${offset}`); return await _get(client, `/delivery_schedules${!!query ? '?' : ''}${query.join('&')}`); } async function load(client) { const main = document.getElementById("access"); const form = main.getElementsByTagName("form")[0]; if (form) { const elements = form.getElementsByClassName('error'); for (const e of elements) form.removeChild(e); } try { window.WINE_VARIETIES = await getWineVarieties(client); window.WINE_QUALITY_LEVELS = await getWineQualityLevels(client); return true; } catch (e) { if (form) { window.localStorage.removeItem(`${CLIENT}/${client}/password`); const error = document.createElement('div'); error.className = 'error'; error.innerText = e.localizedMessage ?? ERROR_MESSAGES[e.message] ?? 'Unbekannter Fehler'; form.insertBefore(error, form.lastChild.previousSibling); } else { window.location.hash = `#/${client}/login`; } return false; } } async function init() { //await load(); render(); } async function updateOverview(client) { const [schedules] = await Promise.all([getDeliverySchedules(client, [`year=${getCurrentLastSeason()}`])]); const rows = []; const days = groupBy(schedules.data, 'date'); const now = new Date(); for (const [dateString, day] of Object.entries(days)) { const date = new Date(dateString); const row = document.createElement('div'); row.className = 'day'; if (now.getDate() === date.getDate()) row.classList.add('today'); row.innerHTML = `
${fmtDateWeekday(date)}${fmtDate(date)}
`; const container = document.createElement('div'); container.className = 'schedule-container'; for (const schedule of day) { const from = schedule.announcement_from !== null ? new Date(schedule.announcement_from) : null; const to = schedule.announcement_to !== null ? new Date(schedule.announcement_to) : null; const status = from === null && to === null ? 'Anmeldung offen' : from > now ? `Anmeldung ab ${fmtDateTime(from)}` : to > now ? `Anmeldung bis ${fmtDateTime(new Date(to - 1))}` : 'Anmeldefrist vorbei'; const link = document.createElement('a'); if (schedule.is_cancelled) link.className = 'cancelled'; link.innerHTML += `
${escapeHTML(schedule.branch.name)}${escapeHTML(schedule.description)}${status}
`; if (schedule.delivered_weight > 0) { link.innerHTML += ` ${fmtInt(schedule.delivered_weight)} kg / ${fmtInt(schedule.announced_weight)} kg (${fmtInt(Math.round(schedule.delivered_weight / schedule.announced_weight * 100))}%) `; } else if (schedule.max_weight !== null) { link.innerHTML += ` ${fmtInt(schedule.announced_weight)} kg / ${fmtInt(schedule.max_weight)} kg (${fmtInt(Math.round(schedule.announced_weight / schedule.max_weight * 100))}%) `; } else { link.innerHTML += `${fmtInt(schedule.announced_weight)} kg`; } container.append(link); } row.appendChild(container); rows.push(row); } const main = document.getElementsByTagName('main')[0]; main.replaceChildren(main.firstElementChild, ...rows); } function render() { const hash = window.location.hash; const main = document.getElementById("access"); const nav = document.getElementsByTagName("nav")[0].getElementsByTagName("ul")[0]; for (const li of nav.children) li.className = ''; let client = null; for (const id in CLIENTS) { if (hash.startsWith(`#/${id}/`) || hash === `#/${id}`) { client = id; } } if (client === null) { window.location.hash = `#/${Object.keys(CLIENTS)[0]}`; return; } nav.children[Object.keys(CLIENTS).indexOf(client)].className = 'active'; if ((!getCredentialsUsername(client) || !getCredentialsPassword(client)) && window.location.hash !== `#/${client}/login`) { window.location.hash = `#/${client}/login`; return; } if (hash === `#/${client}/login`) { main.className = 'login'; main.innerHTML = `

Anmelden

`; } else if (hash === `#/${client}`) { main.className = 'overview'; main.innerHTML = `

${CLIENTS[client].name}

`; updateOverview(client).then(); } else { window.location.hash = `#/${client}`; } } function update() { const hash = window.location.hash; let client = null; for (const id in CLIENTS) { if (hash.startsWith(`#/${id}/`) || hash === `#/${id}`) { client = id; } } if (document.hidden) { // do nothing } else { if (hash === `#/${client}`) { updateOverview(client).then(); } } } document.addEventListener('DOMContentLoaded', async () => { await init(); setInterval(update, 60_000); }); window.addEventListener('hashchange', () => { render(); }); window.addEventListener('pageshow', update) document.addEventListener('visibilitychange', update); function actionLogin(form) { window.localStorage.setItem(`${CLIENT}/${form.client.value}/username`, form.username.value); window.localStorage.setItem(`${CLIENT}/${form.client.value}/password`, form.password.value); load(form.client.value).then(success => { if (success) window.location.hash = `#/${form.client.value}`; }); return false; }