// Copyright © 2026 Olaf Kolkman // SPDX-License-Identifier: GPL-3.0-or-later (() => { const profileForm = document.querySelector('#profile-form'); const passwordForm = document.querySelector('#password-form'); const mastodonForm = document.querySelector('#mastodon-form'); const profileLogoutButton = document.querySelector('#logout-button'); const accessToken = localStorage.getItem('linklogAccessToken'); const defaultMastodonInstance = 'mastodon.social'; const defaultPostPrefix = 'From my #LinkLog: '; function authHeaders(includeJson = false) { return { ...(includeJson ? {'Content-Type': 'application/json'} : {}), ...(accessToken ? {Authorization: `Bearer ${accessToken}`} : {}), }; } function setStatus(selector, message, isError = false) { const status = document.querySelector(selector); status.textContent = message; status.style.color = isError ? '#b91c1c' : '#166534'; } async function loadProfile() { const response = await fetch('/api/user/me', {headers: authHeaders()}); if (!response.ok) throw new Error('Could not load profile'); const profile = await response.json(); document.querySelector('#username').textContent = profile.username || ''; document.querySelector('#email').value = profile.email || ''; document.querySelector('#bio').value = profile.bio || ''; const avatarPreview = document.querySelector('#avatar-preview'); if (profile.avatar_url) { avatarPreview.src = profile.avatar_url; avatarPreview.classList.remove('hidden'); } if (profile.is_admin) { document.querySelector('#auth-admin-link')?.classList.remove('hidden'); } profileLogoutButton.classList.remove('hidden'); } async function loadMastodonConfig() { const response = await fetch('/api/user/plugins/mastodon', {headers: authHeaders()}); if (!response.ok) throw new Error('Could not load Mastodon settings'); const config = await response.json(); document.querySelector('#mastodon-instance').value = config.instance || defaultMastodonInstance; document.querySelector('#mastodon-access-token').value = config.access_token || ''; document.querySelector('#mastodon-post-prefix').value = config.post_prefix || defaultPostPrefix; } profileForm.addEventListener('submit', async (event) => { event.preventDefault(); const formData = new FormData(profileForm); formData.delete('avatar'); const response = await fetch('/api/user/me', { method: 'PUT', headers: authHeaders(true), body: JSON.stringify(Object.fromEntries(formData)), }); setStatus('#profile-status', response.ok ? 'Profile saved.' : 'Could not save profile.', !response.ok); }); document.querySelector('#avatar-file').addEventListener('change', async (event) => { const file = event.target.files[0]; if (!file) return; const formData = new FormData(); formData.append('avatar', file); const response = await fetch('/api/user/avatar', { method: 'POST', headers: authHeaders(), body: formData, }); if (!response.ok) { setStatus('#profile-status', 'Could not upload avatar.', true); return; } const data = await response.json(); const avatarPreview = document.querySelector('#avatar-preview'); avatarPreview.src = data.avatar_url; avatarPreview.classList.remove('hidden'); setStatus('#profile-status', 'Avatar uploaded.'); }); mastodonForm.addEventListener('submit', async (event) => { event.preventDefault(); const formData = new FormData(mastodonForm); const response = await fetch('/api/user/plugins/mastodon', { method: 'PUT', headers: authHeaders(true), body: JSON.stringify(Object.fromEntries(formData)), }); setStatus('#mastodon-status', response.ok ? 'Mastodon settings saved.' : 'Could not save Mastodon settings.', !response.ok); }); passwordForm.addEventListener('submit', async (event) => { event.preventDefault(); const response = await fetch('/api/user/password', { method: 'PUT', headers: authHeaders(true), body: JSON.stringify(Object.fromEntries(new FormData(passwordForm))), }); const status = document.querySelector('#password-status'); status.textContent = response.ok ? 'Password changed.' : 'Could not change password.'; status.style.color = response.ok ? '#94e2d5' : '#f38ba8'; if (response.ok) passwordForm.reset(); }); Promise.all([loadProfile(), loadMastodonConfig()]).catch((error) => { setStatus('#profile-status', accessToken ? error.message : 'Please sign in first.', true); }); })();