313 lines
12 KiB
Plaintext
313 lines
12 KiB
Plaintext
package views
|
|
|
|
import (
|
|
"whereismymoney/internal/models"
|
|
"fmt"
|
|
)
|
|
|
|
templ Settings(userName string, user models.User, categories []models.Category, bankAccounts []models.BankAccount) {
|
|
@Layout("Einstellungen - WhereIsMyMoney") {
|
|
<div class="min-h-screen bg-gray-50">
|
|
@Navigation(userName)
|
|
|
|
<div class="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
|
|
<div class="px-4 py-6 sm:px-0">
|
|
<div class="mb-8">
|
|
<h1 class="text-3xl font-bold text-gray-900">Einstellungen</h1>
|
|
<p class="mt-2 text-gray-600">Verwalte deine Kontoinformationen und App-Einstellungen</p>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
|
<!-- Benutzereinstellungen -->
|
|
<div class="lg:col-span-2">
|
|
<div class="bg-white shadow rounded-lg">
|
|
<div class="px-6 py-4 border-b border-gray-200">
|
|
<h2 class="text-lg font-medium text-gray-900">Benutzereinstellungen</h2>
|
|
</div>
|
|
<div class="px-6 py-4">
|
|
<form id="userSettingsForm" class="space-y-4">
|
|
<div>
|
|
<label for="username" class="block text-sm font-medium text-gray-700">Benutzername</label>
|
|
<input type="text" id="username" name="username" value={ user.Name } class="mt-1 w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-blue-500 focus:border-blue-500">
|
|
</div>
|
|
<div>
|
|
<label for="email" class="block text-sm font-medium text-gray-700">E-Mail</label>
|
|
<input type="email" id="email" name="email" value={ user.Email } readonly class="mt-1 w-full px-3 py-2 border border-gray-300 rounded-md bg-gray-50 text-gray-500 cursor-not-allowed" title="E-Mail-Adresse kann nicht geändert werden">
|
|
<p class="mt-1 text-xs text-gray-500">Die E-Mail-Adresse dient als eindeutige Benutzer-ID und kann nicht geändert werden.</p>
|
|
</div>
|
|
<div class="pt-4">
|
|
<button type="submit" class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500">
|
|
Speichern
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Passwort ändern -->
|
|
<div class="bg-white shadow rounded-lg mt-6">
|
|
<div class="px-6 py-4 border-b border-gray-200">
|
|
<h2 class="text-lg font-medium text-gray-900">Passwort ändern</h2>
|
|
</div>
|
|
<div class="px-6 py-4">
|
|
<form id="passwordForm" class="space-y-4">
|
|
<div>
|
|
<label for="current_password" class="block text-sm font-medium text-gray-700">Aktuelles Passwort</label>
|
|
<input type="password" id="current_password" name="current_password" class="mt-1 w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-blue-500 focus:border-blue-500">
|
|
</div>
|
|
<div>
|
|
<label for="new_password" class="block text-sm font-medium text-gray-700">Neues Passwort</label>
|
|
<input type="password" id="new_password" name="new_password" class="mt-1 w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-blue-500 focus:border-blue-500">
|
|
</div>
|
|
<div>
|
|
<label for="confirm_password" class="block text-sm font-medium text-gray-700">Passwort bestätigen</label>
|
|
<input type="password" id="confirm_password" name="confirm_password" class="mt-1 w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-blue-500 focus:border-blue-500">
|
|
</div>
|
|
<div class="pt-4">
|
|
<button type="submit" class="px-4 py-2 bg-red-600 text-white rounded-md hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500">
|
|
Passwort ändern
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Seitenleiste -->
|
|
<div class="space-y-6">
|
|
<!-- Kategorien verwalten -->
|
|
<div class="bg-white shadow rounded-lg">
|
|
<div class="px-6 py-4 border-b border-gray-200">
|
|
<h3 class="text-lg font-medium text-gray-900">Kategorien</h3>
|
|
</div>
|
|
<div class="px-6 py-4">
|
|
<div class="space-y-2 max-h-48 overflow-y-auto">
|
|
for _, category := range categories {
|
|
<div class="flex items-center justify-between p-2 hover:bg-gray-50 rounded">
|
|
<span class="text-sm">{ category.Icon } { category.Name }</span>
|
|
<button class="delete-category text-red-600 hover:text-red-800 text-sm" data-category-id={ fmt.Sprintf("%d", category.ID) }>
|
|
🗑️
|
|
</button>
|
|
</div>
|
|
}
|
|
</div>
|
|
<button onclick="showModal('categoryModal')" class="mt-4 w-full px-3 py-2 bg-gray-100 text-gray-700 rounded-md hover:bg-gray-200 text-sm">
|
|
+ Neue Kategorie
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Konten verwalten -->
|
|
<div class="bg-white shadow rounded-lg">
|
|
<div class="px-6 py-4 border-b border-gray-200">
|
|
<h3 class="text-lg font-medium text-gray-900">Bankkonten</h3>
|
|
</div>
|
|
<div class="px-6 py-4">
|
|
<div class="space-y-2 max-h-48 overflow-y-auto">
|
|
for _, account := range bankAccounts {
|
|
<div class="flex items-center justify-between p-2 hover:bg-gray-50 rounded">
|
|
<div class="text-sm">
|
|
<div class="font-medium">{ account.Name }</div>
|
|
<div class="text-gray-500">{ account.Bank }</div>
|
|
</div>
|
|
<button class="delete-account text-red-600 hover:text-red-800 text-sm" data-account-id={ fmt.Sprintf("%d", account.ID) }>
|
|
🗑️
|
|
</button>
|
|
</div>
|
|
}
|
|
</div>
|
|
<a href="/accounts" class="mt-4 w-full block px-3 py-2 bg-gray-100 text-gray-700 rounded-md hover:bg-gray-200 text-sm text-center">
|
|
Konten verwalten
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- App-Informationen -->
|
|
<div class="bg-white shadow rounded-lg">
|
|
<div class="px-6 py-4 border-b border-gray-200">
|
|
<h3 class="text-lg font-medium text-gray-900">App-Informationen</h3>
|
|
</div>
|
|
<div class="px-6 py-4 space-y-2 text-sm text-gray-600">
|
|
<div>Version: 1.0.0</div>
|
|
<div>Erstellt mit Go & Templ</div>
|
|
<div>© 2025 WhereIsMyMoney</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Kategorie Modal -->
|
|
<div id="categoryModal" class="fixed inset-0 bg-gray-600 bg-opacity-50 hidden z-50">
|
|
<div class="flex items-center justify-center min-h-screen px-4">
|
|
<div class="bg-white rounded-lg shadow-xl max-w-md w-full">
|
|
<form id="categoryForm" method="POST" action="/settings/categories">
|
|
<div class="px-6 py-4 border-b border-gray-200">
|
|
<h3 class="text-lg font-medium text-gray-900">Neue Kategorie erstellen</h3>
|
|
</div>
|
|
<div class="px-6 py-4 space-y-4">
|
|
<div>
|
|
<label for="category_name" class="block text-sm font-medium text-gray-700">Name</label>
|
|
<input type="text" id="category_name" name="name" required class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-blue-500 focus:border-blue-500" placeholder="z.B. Lebensmittel">
|
|
</div>
|
|
<div>
|
|
<label for="category_icon" class="block text-sm font-medium text-gray-700">Icon (Emoji)</label>
|
|
<input type="text" id="category_icon" name="icon" required class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-blue-500 focus:border-blue-500" placeholder="🛒" maxlength="2">
|
|
</div>
|
|
<div>
|
|
<label for="category_color" class="block text-sm font-medium text-gray-700">Farbe</label>
|
|
<input type="color" id="category_color" name="color" value="#3B82F6" class="w-full h-10 border border-gray-300 rounded-md focus:outline-none focus:ring-blue-500 focus:border-blue-500">
|
|
</div>
|
|
</div>
|
|
<div class="px-6 py-4 border-t border-gray-200 flex justify-end space-x-3">
|
|
<button type="button" onclick="hideModal('categoryModal')" class="px-4 py-2 text-sm font-medium text-gray-700 bg-gray-100 rounded-md hover:bg-gray-200">
|
|
Abbrechen
|
|
</button>
|
|
<button type="submit" class="px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-md hover:bg-blue-700">
|
|
Erstellen
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function showModal(modalId) {
|
|
document.getElementById(modalId).classList.remove('hidden');
|
|
}
|
|
|
|
function hideModal(modalId) {
|
|
document.getElementById(modalId).classList.add('hidden');
|
|
}
|
|
|
|
// Event Listeners für Delete-Buttons
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Delete Category Buttons
|
|
document.querySelectorAll('.delete-category').forEach(button => {
|
|
button.addEventListener('click', function() {
|
|
const categoryId = this.getAttribute('data-category-id');
|
|
deleteCategory(categoryId);
|
|
});
|
|
});
|
|
|
|
// Delete Account Buttons
|
|
document.querySelectorAll('.delete-account').forEach(button => {
|
|
button.addEventListener('click', function() {
|
|
const accountId = this.getAttribute('data-account-id');
|
|
deleteAccount(accountId);
|
|
});
|
|
});
|
|
});
|
|
|
|
function deleteCategory(categoryId) {
|
|
if (!confirm('Möchten Sie diese Kategorie wirklich löschen?')) {
|
|
return;
|
|
}
|
|
|
|
fetch(`/settings/categories/${categoryId}`, {
|
|
method: 'DELETE'
|
|
}).then(response => {
|
|
if (response.ok) {
|
|
location.reload();
|
|
} else {
|
|
alert('Fehler beim Löschen der Kategorie');
|
|
}
|
|
});
|
|
}
|
|
|
|
function deleteAccount(accountId) {
|
|
if (!confirm('Möchten Sie dieses Konto wirklich löschen?')) {
|
|
return;
|
|
}
|
|
|
|
fetch(`/settings/accounts/${accountId}`, {
|
|
method: 'DELETE'
|
|
}).then(response => {
|
|
if (response.ok) {
|
|
location.reload();
|
|
} else {
|
|
alert('Fehler beim Löschen des Kontos');
|
|
}
|
|
});
|
|
}
|
|
|
|
// Benutzereinstellungen speichern
|
|
document.getElementById('userSettingsForm').addEventListener('submit', async function(e) {
|
|
e.preventDefault();
|
|
|
|
// Nur den Benutzernamen senden, E-Mail wird ignoriert
|
|
const formObject = {
|
|
username: document.getElementById('username').value
|
|
};
|
|
|
|
try {
|
|
const response = await fetch('/settings/user', {
|
|
method: 'PUT',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(formObject)
|
|
});
|
|
|
|
if (response.ok) {
|
|
alert('Einstellungen gespeichert!');
|
|
} else {
|
|
alert('Fehler beim Speichern der Einstellungen');
|
|
}
|
|
} catch (error) {
|
|
alert('Fehler beim Speichern der Einstellungen');
|
|
}
|
|
});
|
|
|
|
// Passwort ändern
|
|
document.getElementById('passwordForm').addEventListener('submit', async function(e) {
|
|
e.preventDefault();
|
|
|
|
const newPassword = document.getElementById('new_password').value;
|
|
const confirmPassword = document.getElementById('confirm_password').value;
|
|
|
|
if (newPassword !== confirmPassword) {
|
|
alert('Die Passwörter stimmen nicht überein!');
|
|
return;
|
|
}
|
|
|
|
const formData = new FormData(this);
|
|
const formObject = {};
|
|
for (let [key, value] of formData.entries()) {
|
|
formObject[key] = value;
|
|
}
|
|
|
|
try {
|
|
const response = await fetch('/settings/password', {
|
|
method: 'PUT',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify(formObject)
|
|
});
|
|
|
|
if (response.ok) {
|
|
alert('Passwort erfolgreich geändert!');
|
|
this.reset();
|
|
} else {
|
|
const error = await response.text();
|
|
alert('Fehler: ' + error);
|
|
}
|
|
} catch (error) {
|
|
alert('Fehler beim Ändern des Passworts');
|
|
}
|
|
});
|
|
|
|
// Modal schließen beim Klick außerhalb
|
|
document.addEventListener('click', function(event) {
|
|
if (event.target.classList.contains('bg-opacity-50')) {
|
|
event.target.classList.add('hidden');
|
|
}
|
|
});
|
|
</script>
|
|
}
|
|
}
|