diff --git a/app.js b/app.js index fc826fb..64c8575 100644 --- a/app.js +++ b/app.js @@ -20,7 +20,14 @@ class TeaTracker { // Load data from localStorage loadTeas() { const data = localStorage.getItem(STORAGE_KEY_TEAS); - return data ? JSON.parse(data) : []; + if (!data) return []; + + const teas = JSON.parse(data); + // Migrate existing teas to add organic field if missing + return teas.map(tea => ({ + ...tea, + organic: tea.organic !== undefined ? tea.organic : false + })); } loadEntries() { @@ -64,6 +71,7 @@ class TeaTracker { brand: tea.brand || '', description: tea.description || '', color: tea.color || '#8B4513', + organic: tea.organic || false, createdAt: new Date().toISOString() }; this.teas.push(newTea); @@ -139,20 +147,14 @@ class TeaTracker { .reduce((sum, entry) => sum + entry.amount, 0); } - getWeekCups() { - const now = new Date(); - const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000); - - return this.entries - .filter(entry => new Date(entry.date) >= weekAgo) - .reduce((sum, entry) => sum + entry.amount, 0); - } - getCupsByPeriod(period) { const now = new Date(); let startDate; switch (period) { + case 'today': + startDate = new Date(now.getFullYear(), now.getMonth(), now.getDate()); + break; case 'week': startDate = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000); break; @@ -174,6 +176,47 @@ class TeaTracker { .reduce((sum, entry) => sum + entry.amount, 0); } + getWeekCups() { + const now = new Date(); + const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000); + + return this.entries + .filter(entry => new Date(entry.date) >= weekAgo) + .reduce((sum, entry) => sum + entry.amount, 0); + } + + getEntriesByPeriod(period) { + const now = new Date(); + let startDate; + + switch (period) { + case 'today': + startDate = new Date(now.getFullYear(), now.getMonth(), now.getDate()); + break; + case 'week': + startDate = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000); + break; + case 'month': + startDate = new Date(now.getFullYear(), now.getMonth() - 1, now.getDate()); + break; + case 'year': + startDate = new Date(now.getFullYear() - 1, now.getMonth(), now.getDate()); + break; + case 'all': + startDate = new Date(0); + break; + default: + startDate = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000); + } + + return this.entries.filter(entry => new Date(entry.date) >= startDate); + } + + getCupsByPeriod(period) { + const entries = this.getEntriesByPeriod(period); + return entries.reduce((sum, entry) => sum + entry.amount, 0); + } + getCupsByTeaType(period = 'all') { const entries = this.getEntriesByPeriod(period); const typeCounts = {}; @@ -389,7 +432,7 @@ class TeaTracker { return `
-
${tea ? tea.name : 'Unbekannter Tee'}
+
${tea ? tea.name : 'Unbekannter Tee'} ${tea && tea.organic ? '🌱' : ''}
${formattedDate} ${formattedTime ? `um ${formattedTime}` : ''}
${entry.amount} Tasse${entry.amount > 1 ? 'n' : ''}
@@ -420,7 +463,7 @@ class TeaTracker {
-

${tea.name}

+

${tea.name} ${tea.organic ? '🌱' : ''}

${tea.type}
@@ -463,7 +506,7 @@ class TeaTracker {
-

${tea.name}

+

${tea.name} ${tea.organic ? '🌱' : ''}

${tea.type}
@@ -477,6 +520,42 @@ class TeaTracker { `).join(''); } + // Render recent entries on track page + renderTrackRecentEntries() { + const container = document.getElementById('track-recent-entries'); + const recentEntries = [...this.entries] + .sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt)) + .slice(0, 10); + + if (recentEntries.length === 0) { + container.innerHTML = ` +
+
📝
+
Keine Einträge vorhanden
+
Fange an, deinen Tee-Konsum zu tracken!
+
+ `; + return; + } + + container.innerHTML = recentEntries.map(entry => { + const tea = this.getTeaById(entry.teaId); + const date = new Date(entry.date); + const formattedDate = date.toLocaleDateString('de-DE'); + const formattedTime = entry.time ? entry.time.substring(0, 5) : ''; + + return ` +
+
+
${tea ? tea.name : 'Unbekannter Tee'} ${tea && tea.organic ? '🌱' : ''}
+
${formattedDate} ${formattedTime ? `um ${formattedTime}` : ''}
+
+
${entry.amount} Tasse${entry.amount > 1 ? 'n' : ''}
+
+ `; + }).join(''); + } + openTeaModal(teaId = null) { const modal = document.getElementById('tea-modal'); const form = document.getElementById('tea-form'); @@ -492,6 +571,7 @@ class TeaTracker { document.getElementById('tea-brand').value = tea.brand || ''; document.getElementById('tea-description').value = tea.description || ''; document.getElementById('tea-color').value = tea.color || '#8B4513'; + document.getElementById('tea-organic').checked = tea.organic || false; deleteBtn.style.display = 'inline-flex'; this.currentTeaId = tea.id; } @@ -508,6 +588,7 @@ class TeaTracker { closeTeaModal() { document.getElementById('tea-modal').classList.remove('active'); + document.getElementById('tea-form').reset(); this.currentTeaId = null; } @@ -519,7 +600,8 @@ class TeaTracker { type: document.getElementById('tea-type').value, brand: document.getElementById('tea-brand').value.trim(), description: document.getElementById('tea-description').value.trim(), - color: document.getElementById('tea-color').value + color: document.getElementById('tea-color').value, + organic: document.getElementById('tea-organic').checked }; const teaId = document.getElementById('tea-id').value; @@ -602,9 +684,12 @@ class TeaTracker { } else { teaSelect.innerHTML = '' + this.teas.map(tea => - `` + `` ).join(''); } + + // Render recent entries + this.renderTrackRecentEntries(); } handleTrackFormSubmit(e) { @@ -638,6 +723,7 @@ class TeaTracker { // Update UI this.updateDashboard(); this.updateStats(); + this.renderTrackRecentEntries(); } resetTrackForm() { diff --git a/index.html b/index.html index 9714d79..94ad78d 100644 --- a/index.html +++ b/index.html @@ -110,6 +110,11 @@
+ +
+

Letzte Einträge

+
+
@@ -119,6 +124,7 @@
+
+ +
+
diff --git a/styles.css b/styles.css index 539452e..41de6a6 100644 --- a/styles.css +++ b/styles.css @@ -378,6 +378,45 @@ header p { min-height: 80px; } +/* Checkbox Styling */ +.checkbox-group { + display: flex; + align-items: center; + gap: 10px; +} + +.checkbox-group label { + display: flex; + align-items: center; + gap: 10px; + cursor: pointer; + font-weight: normal; + color: var(--text-color); +} + +.checkbox-group input[type="checkbox"] { + width: 20px; + height: 20px; + cursor: pointer; + accent-color: var(--primary-color); +} + +/* Recent tracked section */ +.recent-tracked { + background-color: var(--card-bg); + border-radius: var(--border-radius); + padding: 20px; + box-shadow: var(--box-shadow); + margin-top: 30px; +} + +.recent-tracked h3 { + margin-bottom: 15px; + color: var(--text-color); + border-bottom: 2px solid var(--primary-light); + padding-bottom: 10px; +} + .form-actions { display: flex; gap: 15px; @@ -763,3 +802,16 @@ header p { margin-right: 10px; border: 2px solid #ddd; } + +/* Organic Badge */ +.organic-badge { + display: inline-block; + font-size: 0.9em; + margin-left: 5px; + color: var(--success-color); + cursor: help; +} + +.organic-badge:hover { + transform: scale(1.1); +}