const loginLink = document.querySelector("#login-link"); const logoutButton = document.querySelector("#logout-button"); const userChip = document.querySelector("#user-chip"); const loggedOutPanel = document.querySelector("#logged-out-panel"); const appPanel = document.querySelector("#app-panel"); const linksSection = document.querySelector("#links-section"); const form = document.querySelector("#shorten-form"); const input = document.querySelector("#url"); const button = document.querySelector("#submit-button"); const alertBox = document.querySelector("#alert"); const result = document.querySelector("#result"); const shortUrl = document.querySelector("#short-url"); const longUrl = document.querySelector("#long-url"); const copyButton = document.querySelector("#copy-button"); const refreshButton = document.querySelector("#refresh-button"); const linksList = document.querySelector("#links-list"); const emptyState = document.querySelector("#empty-state"); const template = document.querySelector("#link-template"); let currentUser = null; async function api(path, options = {}) { const response = await fetch(path, { ...options, headers: { "Content-Type": "application/json", ...(options.headers || {}), }, }); if (response.status === 204) { return null; } const payload = await response.json().catch(() => ({})); if (!response.ok) { throw new Error(payload.error || "Die Anfrage ist fehlgeschlagen."); } return payload; } function showError(message) { alertBox.textContent = message; alertBox.hidden = false; } function clearError() { alertBox.textContent = ""; alertBox.hidden = true; } function setLoading(isLoading) { button.disabled = isLoading; button.textContent = isLoading ? "Kürze..." : "Kürzen"; } function setAuthenticated(user) { currentUser = user.authenticated ? user : null; if (currentUser) { userChip.textContent = currentUser.email ? `${currentUser.username} · ${currentUser.email}` : currentUser.username; userChip.hidden = false; logoutButton.hidden = false; loginLink.hidden = true; loggedOutPanel.hidden = true; appPanel.hidden = false; linksSection.hidden = false; loadLinks(); } else { userChip.hidden = true; logoutButton.hidden = true; loginLink.hidden = false; loggedOutPanel.hidden = false; appPanel.hidden = true; linksSection.hidden = true; } } async function loadMe() { const user = await api("/api/me"); setAuthenticated(user); } async function loadLinks() { if (!currentUser) return; linksList.innerHTML = ""; emptyState.hidden = true; try { const links = await api("/api/links"); emptyState.hidden = links.length !== 0; links.forEach(renderLink); } catch (error) { showError(error.message); } } function renderLink(link) { const node = template.content.cloneNode(true); const card = node.querySelector(".link-card"); const short = node.querySelector(".link-short"); const long = node.querySelector(".link-long"); const form = node.querySelector(".edit-form"); const editInput = node.querySelector(".edit-input"); const saveButton = node.querySelector(".save-button"); const copyButton = node.querySelector(".copy-link-button"); const deleteButton = node.querySelector(".delete-button"); short.href = link.short_url; short.textContent = link.short_url; long.textContent = link.long_url; editInput.value = link.long_url; form.addEventListener("submit", async (event) => { event.preventDefault(); clearError(); saveButton.disabled = true; saveButton.textContent = "Speichere..."; try { const updated = await api(`/api/links/${encodeURIComponent(link.code)}`, { method: "PUT", body: JSON.stringify({ url: editInput.value.trim() }), }); long.textContent = updated.long_url; editInput.value = updated.long_url; saveButton.textContent = "Gespeichert"; setTimeout(() => { saveButton.textContent = "Speichern"; }, 1200); } catch (error) { showError(error.message); saveButton.textContent = "Speichern"; } finally { saveButton.disabled = false; } }); copyButton.addEventListener("click", async () => { await copyToClipboard(link.short_url, copyButton); }); deleteButton.addEventListener("click", async () => { const ok = confirm("Diesen Kurzlink wirklich löschen?"); if (!ok) return; clearError(); try { await api(`/api/links/${encodeURIComponent(link.code)}`, { method: "DELETE" }); card.remove(); if (!linksList.children.length) emptyState.hidden = false; } catch (error) { showError(error.message); } }); linksList.appendChild(node); } async function copyToClipboard(value, targetButton) { try { await navigator.clipboard.writeText(value); const old = targetButton.textContent; targetButton.textContent = "Kopiert!"; setTimeout(() => { targetButton.textContent = old; }, 1500); } catch { showError("Kopieren ist fehlgeschlagen. Bitte kopiere den Link manuell."); } } form.addEventListener("submit", async (event) => { event.preventDefault(); clearError(); result.hidden = true; setLoading(true); try { const payload = await api("/api/shorten", { method: "POST", body: JSON.stringify({ url: input.value.trim() }), }); shortUrl.textContent = payload.short_url; shortUrl.href = payload.short_url; longUrl.textContent = payload.long_url; result.hidden = false; copyButton.textContent = "Kopieren"; input.value = ""; await loadLinks(); } catch (error) { showError(error.message); } finally { setLoading(false); } }); copyButton.addEventListener("click", async () => { await copyToClipboard(shortUrl.href, copyButton); }); refreshButton.addEventListener("click", loadLinks); logoutButton.addEventListener("click", async () => { await fetch("/auth/logout", { method: "POST" }); window.location.href = "/"; }); loadMe().catch((error) => { console.error(error); });