anycoder-dcd56b82 / index.html
Multimedix's picture
Upload folder using huggingface_hub
f013dd0 verified
raw
history blame
39.4 kB
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Haushaltsbuch Pro - Ausgaben & Einnahmen Tracker</title>
<!-- Chart.js -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<!-- Lucide Icons -->
<script src="https://unpkg.com/lucide@latest"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--primary: #6366f1;
--primary-dark: #4f46e5;
--secondary: #22d3ee;
--success: #10b981;
--danger: #ef4444;
--warning: #f59e0b;
--dark: #1e293b;
--light: #f8fafc;
--gray: #64748b;
--border: #e2e8f0;
--shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
color: var(--dark);
}
.container {
max-width: 1400px;
margin: 0 auto;
padding: 20px;
}
header {
background: rgba(255, 255, 255, 0.98);
border-radius: 20px;
padding: 25px 30px;
margin-bottom: 30px;
box-shadow: var(--shadow-lg);
backdrop-filter: blur(10px);
animation: slideDown 0.5s ease-out;
}
.header-content {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 20px;
}
.logo {
display: flex;
align-items: center;
gap: 15px;
}
.logo i {
width: 45px;
height: 45px;
background: linear-gradient(135deg, var(--primary), var(--secondary));
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
color: white;
}
.logo h1 {
font-size: 28px;
background: linear-gradient(135deg, var(--primary), var(--primary-dark));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.header-actions {
display: flex;
gap: 12px;
flex-wrap: wrap;
}
.btn {
padding: 10px 20px;
border: none;
border-radius: 10px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: inline-flex;
align-items: center;
gap: 8px;
white-space: nowrap;
}
.btn-primary {
background: linear-gradient(135deg, var(--primary), var(--primary-dark));
color: white;
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 10px 20px -5px rgba(99, 102, 241, 0.5);
}
.btn-secondary {
background: white;
color: var(--dark);
border: 2px solid var(--border);
}
.btn-secondary:hover {
background: var(--light);
border-color: var(--primary);
color: var(--primary);
}
.btn-success {
background: var(--success);
color: white;
}
.btn-danger {
background: var(--danger);
color: white;
}
.dashboard {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.stat-card {
background: rgba(255, 255, 255, 0.98);
padding: 25px;
border-radius: 15px;
box-shadow: var(--shadow);
transition: all 0.3s ease;
animation: fadeInUp 0.5s ease-out;
position: relative;
overflow: hidden;
}
.stat-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 4px;
height: 100%;
background: linear-gradient(135deg, var(--primary), var(--secondary));
}
.stat-card:hover {
transform: translateY(-5px);
box-shadow: var(--shadow-lg);
}
.stat-card.income::before {
background: var(--success);
}
.stat-card.expense::before {
background: var(--danger);
}
.stat-card.balance::before {
background: var(--warning);
}
.stat-label {
font-size: 13px;
color: var(--gray);
text-transform: uppercase;
letter-spacing: 1px;
margin-bottom: 8px;
display: flex;
align-items: center;
gap: 8px;
}
.stat-value {
font-size: 28px;
font-weight: 700;
color: var(--dark);
}
.main-content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 30px;
margin-bottom: 30px;
}
@media (max-width: 968px) {
.main-content {
grid-template-columns: 1fr;
}
}
.card {
background: rgba(255, 255, 255, 0.98);
border-radius: 20px;
padding: 30px;
box-shadow: var(--shadow-lg);
animation: fadeInUp 0.6s ease-out;
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 25px;
padding-bottom: 15px;
border-bottom: 2px solid var(--border);
}
.card-title {
font-size: 20px;
font-weight: 700;
color: var(--dark);
display: flex;
align-items: center;
gap: 10px;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
font-size: 14px;
font-weight: 600;
color: var(--dark);
margin-bottom: 8px;
}
input, select, textarea {
width: 100%;
padding: 12px 15px;
border: 2px solid var(--border);
border-radius: 10px;
font-size: 14px;
transition: all 0.3s ease;
background: white;
}
input:focus, select:focus, textarea:focus {
outline: none;
border-color: var(--primary);
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
}
.input-group {
display: flex;
gap: 10px;
}
.input-group input {
flex: 1;
}
.transaction-list {
max-height: 400px;
overflow-y: auto;
padding-right: 10px;
}
.transaction-list::-webkit-scrollbar {
width: 6px;
}
.transaction-list::-webkit-scrollbar-track {
background: var(--light);
border-radius: 10px;
}
.transaction-list::-webkit-scrollbar-thumb {
background: var(--gray);
border-radius: 10px;
}
.transaction-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px;
margin-bottom: 12px;
background: var(--light);
border-radius: 12px;
transition: all 0.3s ease;
animation: slideIn 0.3s ease-out;
}
.transaction-item:hover {
background: white;
box-shadow: 0 5px 15px -3px rgba(0, 0, 0, 0.1);
transform: translateX(5px);
}
.transaction-info {
flex: 1;
}
.transaction-category {
display: inline-block;
padding: 4px 10px;
background: var(--primary);
color: white;
border-radius: 20px;
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
margin-right: 10px;
}
.transaction-date {
font-size: 12px;
color: var(--gray);
margin-top: 5px;
}
.transaction-amount {
font-size: 18px;
font-weight: 700;
margin-right: 15px;
}
.transaction-amount.income {
color: var(--success);
}
.transaction-amount.expense {
color: var(--danger);
}
.delete-btn {
background: none;
border: none;
color: var(--danger);
cursor: pointer;
padding: 5px;
transition: all 0.3s ease;
}
.delete-btn:hover {
transform: scale(1.2);
}
.chart-container {
position: relative;
height: 300px;
margin-top: 20px;
}
.tabs {
display: flex;
gap: 10px;
margin-bottom: 20px;
border-bottom: 2px solid var(--border);
}
.tab {
padding: 12px 20px;
background: none;
border: none;
font-size: 14px;
font-weight: 600;
color: var(--gray);
cursor: pointer;
transition: all 0.3s ease;
position: relative;
}
.tab.active {
color: var(--primary);
}
.tab.active::after {
content: '';
position: absolute;
bottom: -2px;
left: 0;
right: 0;
height: 2px;
background: var(--primary);
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
animation: fadeIn 0.3s ease-out;
}
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(5px);
z-index: 1000;
animation: fadeIn 0.3s ease-out;
}
.modal.active {
display: flex;
align-items: center;
justify-content: center;
}
.modal-content {
background: white;
padding: 30px;
border-radius: 20px;
max-width: 500px;
width: 90%;
max-height: 80vh;
overflow-y: auto;
animation: slideUp 0.3s ease-out;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.modal-title {
font-size: 24px;
font-weight: 700;
color: var(--dark);
}
.close-modal {
background: none;
border: none;
font-size: 24px;
color: var(--gray);
cursor: pointer;
transition: all 0.3s ease;
}
.close-modal:hover {
color: var(--danger);
transform: rotate(90deg);
}
.file-input-wrapper {
position: relative;
overflow: hidden;
display: inline-block;
width: 100%;
}
.file-input-wrapper input[type=file] {
position: absolute;
left: -9999px;
}
.file-input-label {
display: block;
padding: 12px 20px;
background: var(--light);
border: 2px dashed var(--border);
border-radius: 10px;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
}
.file-input-label:hover {
background: white;
border-color: var(--primary);
}
.toast {
position: fixed;
bottom: 30px;
right: 30px;
padding: 15px 20px;
background: white;
border-radius: 10px;
box-shadow: var(--shadow-lg);
display: none;
align-items: center;
gap: 10px;
animation: slideInRight 0.3s ease-out;
z-index: 2000;
}
.toast.show {
display: flex;
}
.toast.success {
border-left: 4px solid var(--success);
}
.toast.error {
border-left: 4px solid var(--danger);
}
.toast.info {
border-left: 4px solid var(--primary);
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateX(-20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideInRight {
from {
transform: translateX(100%);
}
to {
transform: translateX(0);
}
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.footer {
text-align: center;
padding: 20px;
color: white;
font-size: 14px;
}
.footer a {
color: var(--secondary);
text-decoration: none;
font-weight: 600;
transition: all 0.3s ease;
}
.footer a:hover {
text-decoration: underline;
}
@media (max-width: 768px) {
.container {
padding: 10px;
}
.header-content {
flex-direction: column;
text-align: center;
}
.dashboard {
grid-template-columns: 1fr;
}
.card {
padding: 20px;
}
.modal-content {
padding: 20px;
}
}
</style>
</head>
<body>
<div class="container">
<header>
<div class="header-content">
<div class="logo">
<i data-lucide="wallet"></i>
<h1>Haushaltsbuch Pro</h1>
</div>
<div class="header-actions">
<button class="btn btn-secondary" onclick="openImportModal()">
<i data-lucide="upload" style="width: 16px; height: 16px;"></i>
CSV Import
</button>
<button class="btn btn-secondary" onclick="exportCSV()">
<i data-lucide="download" style="width: 16px; height: 16px;"></i>
CSV Export
</button>
<button class="btn btn-danger" onclick="clearAllData()">
<i data-lucide="trash-2" style="width: 16px; height: 16px;"></i>
Alle Daten löschen
</button>
</div>
</div>
</header>
<div class="dashboard">
<div class="stat-card income">
<div class="stat-label">
<i data-lucide="trending-up" style="width: 16px; height: 16px;"></i>
Gesamteinnahmen
</div>
<div class="stat-value" id="totalIncome">€0,00</div>
</div>
<div class="stat-card expense">
<div class="stat-label">
<i data-lucide="trending-down" style="width: 16px; height: 16px;"></i>
Gesamtausgaben
</div>
<div class="stat-value" id="totalExpense">€0,00</div>
</div>
<div class="stat-card balance">
<div class="stat-label">
<i data-lucide="balance" style="width: 16px; height: 16px;"></i>
Kontostand
</div>
<div class="stat-value" id="balance">€0,00</div>
</div>
</div>
<div class="main-content">
<div class="card">
<div class="card-header">
<h2 class="card-title">
<i data-lucide="plus-circle"></i>
Neue Transaktion
</h2>
</div>
<form id="transactionForm">
<div class="form-group">
<label for="type">Typ</label>
<select id="type" required>
<option value="">Bitte wählen</option>
<option value="income">Einnahme</option>
<option value="expense">Ausgabe</option>
</select>
</div>
<div class="form-group">
<label for="amount">Betrag (€)</label>
<input type="number" id="amount" step="0.01" min="0" placeholder="0,00" required>
</div>
<div class="form-group">
<label for="category">Kategorie</label>
<select id="category" required>
<option value="">Bitte wählen</option>
</select>
</div>
<div class="form-group">
<label for="description">Beschreibung</label>
<input type="text" id="description" placeholder="z.B. Lebensmittel, Gehalt, Miete" required>
</div>
<div class="form-group">
<label for="date">Datum</label>
<input type="date" id="date" required>
</div>
<button type="submit" class="btn btn-primary" style="width: 100%;">
<i data-lucide="save" style="width: 16px; height: 16px;"></i>
Transaktion speichern
</button>
</form>
</div>
<div class="card">
<div class="card-header">
<h2 class="card-title">
<i data-lucide="list"></i>
Letzte Transaktionen
</h2>
<button class="btn btn-secondary" onclick="refreshTransactions()">
<i data-lucide="refresh-cw" style="width: 16px; height: 16px;"></i>
</button>
</div>
<div class="transaction-list" id="transactionList">
<!-- Transactions will be added here -->
</div>
</div>
</div>
<div class="card">
<div class="card-header">
<h2 class="card-title">
<i data-lucide="bar-chart-2"></i>
Auswertungen
</h2>
</div>
<div class="tabs">
<button class="tab active" onclick="switchTab('monthly')">Monatlich</button>
<button class="tab" onclick="switchTab('category')">Nach Kategorie</button>
<button class="tab" onclick="switchTab('trend')">Trend</button>
</div>
<div class="tab-content active" id="monthly-tab">
<div class="chart-container">
<canvas id="monthlyChart"></canvas>
</div>
</div>
<div class="tab-content" id="category-tab">
<div class="chart-container">
<canvas id="categoryChart"></canvas>
</div>
</div>
<div class="tab-content" id="trend-tab">
<div class="chart-container">
<canvas id="trendChart"></canvas>
</div>
</div>
</div>
<footer class="footer">
<p>© 2024 Haushaltsbuch Pro | Gebaut mit <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">anycoder</a></p>
</footer>
</div>
<!-- Import Modal -->
<div class="modal" id="importModal">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">CSV Import</h3>
<button class="close-modal" onclick="closeImportModal()">×</button>
</div>
<div class="form-group">
<label>Wählen Sie eine CSV-Datei aus</label>
<div class="file-input-wrapper">
<input type="file" id="csvFile" accept=".csv" onchange="handleFileSelect(event)">
<label for="csvFile" class="file-input-label">
<i data-lucide="file-text" style="width: 24px; height: 24px; margin-bottom: 10px;"></i>
<div>Klicken Sie hier oder ziehen Sie eine Datei hierher</div>
<div style="font-size: 12px; color: var(--gray); margin-top: 5px;">
Format: Typ,Betrag,Kategorie,Beschreibung,Datum
</div>
</label>
</div>
</div>
<button class="btn btn-primary" onclick="importCSV()" style="width: 100%; margin-top: 20px;">
Importieren
</button>
</div>
</div>
<!-- Toast Notification -->
<div class="toast" id="toast">
<i data-lucide="check-circle" style="width: 20px; height: 20px;"></i>
<span id="toastMessage"></span>
</div>
<script>
// Initialize Lucide icons
lucide.createIcons();
// Data Management
let transactions = JSON.parse(localStorage.getItem('transactions')) || [];
let monthlyChart, categoryChart, trendChart;
// Categories
const incomeCategories = ['Gehalt', 'Nebeneinkommen', 'Investitionen', 'Geschenk', 'Rückerstattung', 'Sonstige'];
const expenseCategories = ['Lebensmittel', 'Miete', 'Transport', 'Unterhaltung', 'Rechnungen', 'Gesundheit', 'Kleidung', 'Bildung', 'Restaurants', 'Shopping', 'Sonstige'];
// Initialize
document.addEventListener('DOMContentLoaded', function() {
// Set today's date
document.getElementById('date').valueAsDate = new Date();
// Update categories based on type
document.getElementById('type').addEventListener('change', updateCategories);
// Form submission
document.getElementById('transactionForm').addEventListener('submit', addTransaction);
// Initial load
updateDashboard();
displayTransactions();
initializeCharts();
});
function updateCategories() {
const type = document.getElementById('type').value;
const categorySelect = document.getElementById('category');
categorySelect.innerHTML = '<option value="">Bitte wählen</option>';
const categories = type === 'income' ? incomeCategories : expenseCategories;
categories.forEach(cat => {
categorySelect.innerHTML += `<option value="${cat}">${cat}</option>`;
});
}
function addTransaction(e) {
e.preventDefault();
const transaction = {
id: Date.now(),
type: document.getElementById('type').value,
amount: parseFloat(document.getElementById('amount').value),
category: document.getElementById('category').value,
description: document.getElementById('description').value,
date: document.getElementById('date').value
};
transactions.unshift(transaction);
saveTransactions();
// Reset form
document.getElementById('transactionForm').reset();
document.getElementById('date').valueAsDate = new Date();
// Update UI
updateDashboard();
displayTransactions();
updateCharts();
showToast('Transaktion erfolgreich hinzugefügt!', 'success');
}
function deleteTransaction(id) {
if (confirm('Möchten Sie diese Transaktion wirklich löschen?')) {
transactions = transactions.filter(t => t.id !== id);
saveTransactions();
updateDashboard();
displayTransactions();
updateCharts();
showToast('Transaktion gelöscht', 'info');
}
}
function saveTransactions() {
localStorage.setItem('transactions', JSON.stringify(transactions));
}
function updateDashboard() {
const income = transactions
.filter(t => t.type === 'income')
.reduce((sum, t) => sum + t.amount, 0);
const expense = transactions
.filter(t => t.type === 'expense')
.reduce((sum, t) => sum + t.amount, 0);
const balance = income - expense;
document.getElementById('totalIncome').textContent = formatCurrency(income);
document.getElementById('totalExpense').textContent = formatCurrency(expense);
document.getElementById('balance').textContent = formatCurrency(balance);
// Update balance color
const balanceElement = document.getElementById('balance');
if (balance < 0) {
balanceElement.style.color = 'var(--danger)';
} else if (balance > 0) {
balanceElement.style.color = 'var(--success)';
}
}
function displayTransactions() {
const listElement = document.getElementById('transactionList');
const recentTransactions = transactions.slice(0, 10);
if (recentTransactions.length === 0) {
listElement.innerHTML = '<div style="text-align: center; color: var(--gray); padding: 40px;">Keine Transaktionen vorhanden</div>';
return;
}
listElement.innerHTML = recentTransactions.map(t => `
<div class="transaction-item">
<div class="transaction-info">
<span class="transaction-category" style="background: ${t.type === 'income' ? 'var(--success)' : 'var(--danger)'}">
${t.category}
</span>
<div style="font-weight: 600; margin-top: 5px;">${t.description}</div>
<div class="transaction-date">${formatDate(t.date)}</div>
</div>
<div class="transaction-amount ${t.type}">
${t.type === 'income' ? '+' : '-'}${formatCurrency(t.amount)}
</div>
<button class="delete-btn" onclick="deleteTransaction(${t.id})">
<i data-lucide="trash-2" style="width: 18px; height: 18px;"></i>
</button>
</div>
`).join('');
// Re-initialize icons
lucide.createIcons();
}
function initializeCharts() {
// Monthly Chart
const monthlyCtx = document.getElementById('monthlyChart').getContext('2d');
monthlyChart = new Chart(monthlyCtx, {
type: 'bar',
data: {
labels: [],
datasets: [{
label: 'Einnahmen',
data: [],
backgroundColor: 'rgba(16, 185, 129, 0.8)',
borderRadius: 8
}, {
label: 'Ausgaben',
data: [],
backgroundColor: 'rgba(239, 68, 68, 0.8)',
borderRadius: 8
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'top',
}
},
scales: {
y: {
beginAtZero: true,
ticks: {
callback: function(value) {
return '€' + value.toLocaleString('de-DE');
}
}
}
}
}
});
// Category Chart
const categoryCtx = document.getElementById('categoryChart').getContext('2d');
categoryChart = new Chart(categoryCtx, {
type: 'doughnut',
data: {
labels: [],
datasets: [{
data: [],
backgroundColor: [
'#6366f1', '#8b5cf6', '#ec4899', '#f43f5e',
'#ef4444', '#f97316', '#f59e0b', '#eab308',
'#84cc16', '#22c55e', '#10b981', '#14b8a6'
],
borderWidth: 0
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'right',
}
}
}
});
// Trend Chart
const trendCtx = document.getElementById('trendChart').getContext('2d');
trendChart = new Chart(trendCtx, {
type: 'line',
data: {
labels: [],
datasets: [{
label: 'Kontostand',
data: [],
borderColor: '#6366f1',
backgroundColor: 'rgba(99, 102, 241, 0.1)',
tension: 0.4,
fill: true
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
}
},
scales: {
y: {
beginAtZero: false,
ticks: {
callback: function(value) {
return '€' + value.toLocaleString('de-DE');
}
}
}
}
}
});
updateCharts();
}
function updateCharts() {
// Update Monthly Chart
const monthlyData = getMonthlyData();
monthlyChart.data.labels = monthlyData.labels;
monthlyChart.data.datasets[0].data = monthlyData.income;
monthlyChart.data.datasets[1].data = monthlyData.expense;
monthlyChart.update();
// Update Category Chart
const categoryData = getCategoryData();
categoryChart.data.labels = categoryData.labels;
categoryChart.data.datasets[0].data = categoryData.data;
categoryChart.update();
// Update Trend Chart
const trendData = getTrendData();
trendChart.data.labels = trendData.labels;
trendChart.data.datasets[0].data = trendData.balance;
trendChart.update();
}
function getMonthlyData() {
const last6Months = [];
const incomeData = [];
const expenseData = [];
for (let i = 5; i >= 0; i--) {
const date = new Date();
date.setMonth(date.getMonth() - i);
const monthKey = date.toISOString().slice(0, 7);
const monthTransactions = transactions.filter(t => t.date.startsWith(monthKey));
const income = monthTransactions
.filter(t => t.type === 'income')
.reduce((sum, t) => sum + t.amount, 0);
const expense = monthTransactions
.filter(t => t.type === 'expense')
.reduce((sum, t) => sum + t.amount, 0);
const monthName = date.toLocaleDateString('de-DE', { month: 'long', year: 'numeric' });
last6Months.push(monthName);
incomeData.push(income);
expenseData.push(expense);
}
return {
labels: last6Months,
income: incomeData,
expense: expenseData
};
}
function getCategoryData() {
const categoryTotals = {};
transactions
.filter(t => t.type === 'expense')
.forEach(t => {
categoryTotals[t.category] = (categoryTotals[t.category] || 0) + t.amount;
});
return {
labels: Object.keys(categoryTotals),
data: Object.values(categoryTotals)
};
}
function getTrendData() {
const sortedTransactions = [...transactions].sort((a, b) => new Date(a.date) - new Date(b.date));
const labels = [];
const balanceData = [];
let runningBalance = 0;
sortedTransactions.forEach(t => {
if (t.type === 'income') {
runningBalance += t.amount;
} else {
runningBalance -= t.amount;
}
labels.push(formatDate(t.date));
balanceData.push(runningBalance);
});
return {
labels: labels.slice(-30), // Last 30 transactions
balance: balanceData.slice(-30)
};
}
function switchTab(tabName) {
// Update tabs
document.querySelectorAll('.tab').forEach(tab => tab.classList.remove('active'));
event.target.classList.add('active');
// Update content
document.querySelectorAll('.tab-content').forEach(content => content.classList.remove('active'));
document.getElementById(`${tabName}-tab`).classList.add('active');
}
function refreshTransactions() {
displayTransactions();
showToast('Transaktionen aktualisiert', 'info');
}
function openImportModal() {
document.getElementById('importModal').classList.add('active');
}
function closeImportModal() {
document.getElementById('importModal').classList.remove('active');
}
function handleFileSelect(event) {
const file = event.target.files[0];
if (file) {
const fileName = file.name;
document.querySelector('.file-input-label div').textContent = fileName;
}
}
function importCSV() {
const fileInput = document.getElementById('csvFile');
const file = fileInput.files[0];
if (!file) {
showToast('Bitte wählen Sie eine Datei aus', 'error');
return;
}
const reader = new FileReader();
reader.onload = function(e) {
try {
const lines = e.target.result.split('\n');
const newTransactions = [];
lines.forEach((line, index) => {
if (index === 0 || !line.trim()) return; // Skip header or empty lines
const parts = line.split(',');
if (parts.length >= 5) {
const transaction = {
id: Date.now() + index,
type: parts[0].trim(),
amount: parseFloat(parts[1].trim()),
category: parts[2].trim(),
description: parts[3].trim(),
date: parts[4].trim()
};
if (transaction.type && !isNaN(transaction.amount) && transaction.category && transaction.description && transaction.date) {
newTransactions.push(transaction);
}
}
});
if (newTransactions.length > 0) {
transactions = [...newTransactions, ...transactions];
saveTransactions();
updateDashboard();
displayTransactions();
updateCharts();
closeImportModal();
showToast(`${newTransactions.length} Transaktionen importiert`, 'success');
} else {
showToast('Keine gültigen Transaktionen in der Datei