2026-06-14 11:58:04 +02:00

276 lines
11 KiB
HTML

<!-- OnlyPrompt - Settings page:
- User preferences with tabs for profile, security, and notifications -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OnlyPrompt - Settings</title>
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/base.css">
<link rel="stylesheet" href="../css/sidebar.css">
<link rel="stylesheet" href="../css/login.css">
<link rel="stylesheet" href="../css/topbar.css">
<link rel="stylesheet" href="../css/settings.css">
<script src="../js/profile-shared.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
</head>
<body>
<a class="skip-link" href="#main-content">Skip to main content</a>
<div class="layout">
<div id="sidebar-container"></div>
<div class="page-body">
<div id="topbar-container"></div>
<main class="settings-main" id="main-content" tabindex="-1">
<div class="settings-container">
<div class="settings-header">
<h1>Settings</h1>
<p>Manage your account preferences and profile.</p>
</div>
<!-- Tabs -->
<div class="settings-tabs" role="tablist" aria-label="Settings sections">
<button type="button" class="tab-btn active" data-tab="profile" id="profileTabButton" role="tab" aria-selected="true" aria-controls="profileTab">Profile</button>
<button type="button" class="tab-btn" data-tab="security" id="securityTabButton" role="tab" aria-selected="false" aria-controls="securityTab">Security</button>
<button type="button" class="tab-btn" data-tab="notifications" id="notificationsTabButton" role="tab" aria-selected="false" aria-controls="notificationsTab">Notifications</button>
</div>
<!-- Tab Content: Profile -->
<div id="profileTab" class="tab-content active" role="tabpanel" aria-labelledby="profileTabButton">
<form class="settings-form" id="profileSettingsForm">
<div class="form-group">
<label for="avatar">Profile Picture</label>
<div class="avatar-upload">
<img src="../images/content/cat.png" alt="Profile picture preview" class="settings-avatar" id="avatarPreview">
<input type="file" id="avatarUpload" accept="image/png, image/jpeg">
<button type="button" class="upload-btn" aria-controls="avatarUpload">Upload new</button>
</div>
</div>
<div class="form-group">
<label for="displayName">Display Name</label>
<input type="text" id="displayName" placeholder="Display name">
</div>
<div class="form-group">
<label for="username">Username</label>
<input type="text" id="username" placeholder="username" required>
</div>
<div class="form-group">
<label for="bio">Bio</label>
<textarea id="bio" rows="3" placeholder="Tell us about yourself..."></textarea>
</div>
<div class="form-group">
<label for="email">Email Address</label>
<input type="email" id="email" placeholder="your@email.com" readonly>
</div>
<div class="form-actions">
<button type="submit" class="save-btn">Save Changes</button>
<p id="profileSaveStatus" role="status" aria-live="polite"></p>
</div>
</form>
</div>
<!-- Tab Content: Security -->
<div id="securityTab" class="tab-content" role="tabpanel" aria-labelledby="securityTabButton" hidden>
<form class="settings-form">
<div class="form-group">
<label for="currentPw">Current Password</label>
<input type="password" id="currentPw" placeholder="Enter current password">
</div>
<div class="form-group">
<label for="newPw">New Password</label>
<input type="password" id="newPw" placeholder="Enter new password">
</div>
<div class="form-group">
<label for="confirmPw">Confirm New Password</label>
<input type="password" id="confirmPw" placeholder="Confirm new password">
</div>
<div class="form-group">
<label class="checkbox-label">
<input type="checkbox" id="twoFactor"> Enable Two-Factor Authentication
</label>
</div>
<div class="form-actions">
<button type="submit" class="save-btn">Update Password</button>
</div>
</form>
</div>
<!-- Tab Content: Notifications (erweitert) -->
<div id="notificationsTab" class="tab-content" role="tabpanel" aria-labelledby="notificationsTabButton" hidden>
<form class="settings-form">
<div class="form-group">
<label class="checkbox-label">
<input type="checkbox" id="notifLikes"> When someone likes my prompt
</label>
</div>
<div class="form-group">
<label class="checkbox-label">
<input type="checkbox" id="notifSaves"> When someone saves my prompt
</label>
</div>
<div class="form-group">
<label class="checkbox-label">
<input type="checkbox" id="notifMessages"> New message received
</label>
</div>
<div class="form-group">
<label class="checkbox-label">
<input type="checkbox" id="notifFollowers"> New follower
</label>
</div>
<div class="form-group">
<label class="checkbox-label">
<input type="checkbox" id="notifPurchases"> Prompt purchase (paid prompts)
</label>
</div>
<div class="form-group">
<label class="checkbox-label">
<input type="checkbox" id="notifComments"> Comment on my prompt
</label>
</div>
<div class="form-actions">
<button type="submit" class="save-btn">Save Preferences</button>
</div>
</form>
</div>
</div>
</main>
</div>
</div>
<script>
// Tab switching
const tabBtns = document.querySelectorAll('.tab-btn');
const tabContents = document.querySelectorAll('.tab-content');
tabBtns.forEach(btn => {
btn.addEventListener('click', () => {
const tabId = btn.getAttribute('data-tab');
tabBtns.forEach(b => {
b.classList.remove('active');
b.setAttribute('aria-selected', 'false');
});
btn.classList.add('active');
btn.setAttribute('aria-selected', 'true');
tabContents.forEach(content => {
content.classList.remove('active');
content.hidden = true;
});
const selectedTab = document.getElementById(`${tabId}Tab`);
selectedTab.classList.add('active');
selectedTab.hidden = false;
});
});
let currentAvatarUrl = '';
let currentSlug = '';
function setProfileForm(profile) {
document.getElementById('displayName').value = profile.displayName || '';
document.getElementById('username').value = profile.user?.userName || '';
document.getElementById('email').value = profile.user?.email || '';
document.getElementById('bio').value = profile.bio || '';
currentAvatarUrl = profile.avatarUrl || '../images/content/cat.png';
currentSlug = profile.slug || profile.user?.userName || '';
avatarPreview.src = currentAvatarUrl;
}
async function loadProfileSettings() {
try {
const profile = await window.loadCurrentProfile();
setProfileForm(profile);
} catch (error) {
document.getElementById('profileSaveStatus').textContent = 'Profile could not be loaded.';
}
}
// Avatar preview and save as data URL
const avatarUpload = document.getElementById('avatarUpload');
const avatarPreview = document.getElementById('avatarPreview');
if (avatarUpload) {
avatarUpload.addEventListener('change', function(e) {
const file = e.target.files[0];
if (file && (file.type === 'image/png' || file.type === 'image/jpeg')) {
const reader = new FileReader();
reader.onload = function(ev) {
currentAvatarUrl = ev.target.result;
avatarPreview.src = currentAvatarUrl;
};
reader.readAsDataURL(file);
}
});
}
document.getElementById('profileSettingsForm').addEventListener('submit', async (e) => {
e.preventDefault();
const status = document.getElementById('profileSaveStatus');
status.textContent = 'Saving...';
try {
const userName = document.getElementById('username').value.trim();
const response = await fetch('/api/v1/profiles', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
credentials: 'same-origin',
body: JSON.stringify({
displayName: document.getElementById('displayName').value.trim(),
userName,
slug: userName || currentSlug,
bio: document.getElementById('bio').value.trim(),
avatarUrl: currentAvatarUrl,
specialities: null,
isPublic: true
})
});
if (response.status === 401) {
location.href = '/login';
return;
}
if (!response.ok) throw new Error('Profile could not be saved.');
const savedProfile = await window.loadCurrentProfile(true);
window.setCurrentProfile(savedProfile);
setProfileForm(savedProfile);
status.textContent = 'Saved.';
} catch (error) {
status.textContent = error.message;
}
});
// Demo form submits for forms that are not connected yet
document.querySelectorAll('.settings-form:not(#profileSettingsForm)').forEach(form => {
form.addEventListener('submit', (e) => {
e.preventDefault();
alert('Settings saved (demo)');
});
});
// Fetch sidebar and topbar
fetch('/sidebar.html')
.then(r => r.text())
.then(data => {
document.getElementById('sidebar-container').innerHTML = data;
document.querySelectorAll('#sidebar-container .sidebar a').forEach(link => {
link.classList.remove('active');
link.removeAttribute('aria-current');
});
const settingsLink = document.querySelector('#sidebar-container a[href="settings.html"]');
if (settingsLink) {
settingsLink.classList.add('active');
settingsLink.setAttribute('aria-current', 'page');
}
});
fetch('/topbar.html')
.then(r => r.text())
.then(data => document.getElementById('topbar-container').innerHTML = data);
loadProfileSettings();
</script>
</body>
</html>