Clean app.js: Remove all merge conflicts and duplicate classes

Co-authored-by: trevor1969 <trevor1969@users.noreply.github.com>
This commit is contained in:
Vibe Nuage Agent
2026-06-06 12:47:37 +00:00
parent 23c83ef4d1
commit ee6c690645

317
app.js
View File

@ -1,91 +1,14 @@
// Local File Storage // TeeTracker - Main Application
// Version 4.0: Local file storage in data/ directory
// ============================================
// Configuration
// ============================================ // ============================================
class LocalFileStorage { const STORAGE_KEY_TEAS = 'teatracker_teas';
constructor() { const STORAGE_KEY_ENTRIES = 'teatracker_entries';
this.basePath = DATA_DIRECTORY; const DATA_DIRECTORY = 'data/';
this.connected = false;
this.lastError = null;
}
async testConnection() {
try {
// Try to create a test file
const testFile = this.basePath + 'test_connection.txt';
const response = await fetch(testFile, {
method: 'PUT',
body: 'test'
});
if (response.ok) {
// Clean up test file
await fetch(testFile, { method: 'DELETE' });
this.connected = true;
this.lastError = null;
return true;
} else {
this.connected = false;
this.lastError = `HTTP Error: ${response.status}`;
return false;
}
} catch (error) {
this.connected = false;
this.lastError = error.message;
console.log('Local file storage not available:', error.message);
return false;
}
}
async loadFile(filename) {
try {
const url = this.basePath + filename;
const response = await fetch(url, {
method: 'GET'
});
if (response.ok) {
const text = await response.text();
return text.trim() === '' ? [] : (text ? JSON.parse(text) : null);
} else if (response.status === 404) {
return null;
}
return null;
} catch (error) {
console.log(`Error loading ${filename}:`, error.message);
return null;
}
}
async saveFile(filename, data) {
try {
const url = this.basePath + filename;
const response = await fetch(url, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data, null, 2)
});
return response.ok;
} catch (error) {
console.log(`Error saving ${filename}:`, error.message);
return false;
}
}
async fileExists(filename) {
try {
const url = this.basePath + filename;
const response = await fetch(url, {
method: 'HEAD'
});
return response.ok;
} catch (error) {
return false;
}
}
}
=======
// ============================================ // ============================================
// Local File Storage // Local File Storage
// ============================================ // ============================================
@ -166,8 +89,6 @@ class LocalFileStorage {
async saveFile(filename, data) { async saveFile(filename, data) {
try { try {
// First ensure the data directory exists by trying to create it
// Note: We can't actually create directories via fetch, but we can try to save the file
const url = this.basePath + filename; const url = this.basePath + filename;
// Try with PUT first (standard for creating/updating files) // Try with PUT first (standard for creating/updating files)
@ -217,8 +138,6 @@ class LocalFileStorage {
} }
async ensureDirectory() { async ensureDirectory() {
// Try to create a placeholder file to ensure directory exists
// This works on servers that support PUT for file creation
try { try {
const placeholder = this.basePath + '.gitkeep'; const placeholder = this.basePath + '.gitkeep';
const response = await fetch(placeholder, { const response = await fetch(placeholder, {
@ -233,104 +152,6 @@ class LocalFileStorage {
return false; return false;
} }
} }
}TeeTracker - Main Application
// Version 4.0: Local file storage in data/ directory
// ============================================
// Configuration
// ============================================
const STORAGE_KEY_TEAS = 'teatracker_teas';
const STORAGE_KEY_ENTRIES = 'teatracker_entries';
const DATA_DIRECTORY = 'data/';
// ============================================
// Local File Storage
// ============================================
class LocalFileStorage {
constructor() {
this.basePath = DATA_DIRECTORY;
this.connected = false;
this.lastError = null;
}
async testConnection() {
try {
// Try to create a test file
const testFile = this.basePath + 'test_connection.txt';
const response = await fetch(testFile, {
method: 'PUT',
body: 'test'
});
if (response.ok) {
// Clean up test file
await fetch(testFile, { method: 'DELETE' });
this.connected = true;
this.lastError = null;
return true;
} else {
this.connected = false;
this.lastError = `HTTP Error: ${response.status}`;
return false;
}
} catch (error) {
this.connected = false;
this.lastError = error.message;
console.log('Local file storage not available:', error.message);
return false;
}
}
async loadFile(filename) {
try {
const url = this.basePath + filename;
const response = await fetch(url, {
method: 'GET'
});
if (response.ok) {
const text = await response.text();
return text.trim() === '' ? [] : (text ? JSON.parse(text) : null);
} else if (response.status === 404) {
return null;
}
return null;
} catch (error) {
console.log(`Error loading ${filename}:`, error.message);
return null;
}
}
async saveFile(filename, data) {
try {
const url = this.basePath + filename;
const response = await fetch(url, {
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data, null, 2)
});
return response.ok;
} catch (error) {
console.log(`Error saving ${filename}:`, error.message);
return false;
}
}
async fileExists(filename) {
try {
const url = this.basePath + filename;
const response = await fetch(url, {
method: 'HEAD'
});
return response.ok;
} catch (error) {
return false;
}
}
} }
// ============================================ // ============================================
@ -374,7 +195,6 @@ class TeeTracker {
// ============================================ // ============================================
async initStorage() { async initStorage() {
// Test if file storage is available
this.useFileStorage = await this.fileStorage.testConnection(); this.useFileStorage = await this.fileStorage.testConnection();
this.updateSyncStatus(); this.updateSyncStatus();
} }
@ -385,18 +205,14 @@ class TeeTracker {
try { try {
if (this.useFileStorage) { if (this.useFileStorage) {
// Try to ensure data directory exists
await this.fileStorage.ensureDirectory(); await this.fileStorage.ensureDirectory();
// Try to load from file storage first
const teas = await this.fileStorage.loadFile('teas.json'); const teas = await this.fileStorage.loadFile('teas.json');
const entries = await this.fileStorage.loadFile('entries.json'); const entries = await this.fileStorage.loadFile('entries.json');
// Always load from localStorage as backup
const localTeas = localStorage.getItem(STORAGE_KEY_TEAS); const localTeas = localStorage.getItem(STORAGE_KEY_TEAS);
const localEntries = localStorage.getItem(STORAGE_KEY_ENTRIES); const localEntries = localStorage.getItem(STORAGE_KEY_ENTRIES);
// Load from file storage if available, otherwise use local data
if (teas && Array.isArray(teas)) { if (teas && Array.isArray(teas)) {
this.teas = teas.map(tea => ({ this.teas = teas.map(tea => ({
...tea, ...tea,
@ -437,12 +253,10 @@ class TeeTracker {
this.entries = []; this.entries = [];
} }
// If we loaded from file storage, save to localStorage as backup
if ((teas || entries) && (localTeas === null || localEntries === null)) { if ((teas || entries) && (localTeas === null || localEntries === null)) {
this.saveToLocalStorage(); this.saveToLocalStorage();
} }
} else { } else {
// Load from localStorage only
this.loadFromLocalStorage(); this.loadFromLocalStorage();
} }
} catch (error) { } catch (error) {
@ -487,11 +301,9 @@ class TeeTracker {
try { try {
if (this.useFileStorage) { if (this.useFileStorage) {
// Save to file storage
const teasSaved = await this.fileStorage.saveFile('teas.json', this.teas); const teasSaved = await this.fileStorage.saveFile('teas.json', this.teas);
const entriesSaved = await this.fileStorage.saveFile('entries.json', this.entries); const entriesSaved = await this.fileStorage.saveFile('entries.json', this.entries);
// Also save locally as backup
this.saveToLocalStorage(); this.saveToLocalStorage();
if (teasSaved && entriesSaved) { if (teasSaved && entriesSaved) {
@ -500,7 +312,6 @@ class TeeTracker {
this.showToast('Lokale Speicherung erfolgreich, Dateispeicherung fehlgeschlagen', 'warning'); this.showToast('Lokale Speicherung erfolgreich, Dateispeicherung fehlgeschlagen', 'warning');
} }
} else { } else {
// Save only locally
this.saveToLocalStorage(); this.saveToLocalStorage();
} }
} catch (error) { } catch (error) {
@ -529,18 +340,10 @@ class TeeTracker {
} }
} }
// ============================================
// Generate unique ID
// ============================================
generateId() { generateId() {
return Date.now().toString(36) + Math.random().toString(36).substr(2); return Date.now().toString(36) + Math.random().toString(36).substr(2);
} }
// ============================================
// Get data by ID
// ============================================
getTeaById(id) { getTeaById(id) {
return this.teas.find(tea => tea.id === id); return this.teas.find(tea => tea.id === id);
} }
@ -549,10 +352,6 @@ class TeeTracker {
return this.teas.findIndex(tea => tea.id === id); return this.teas.findIndex(tea => tea.id === id);
} }
// ============================================
// Tea Management
// ============================================
addTea(tea) { addTea(tea) {
const newTea = { const newTea = {
id: this.generateId(), id: this.generateId(),
@ -592,10 +391,6 @@ class TeeTracker {
return false; return false;
} }
// ============================================
// Entry Management
// ============================================
addEntry(entry) { addEntry(entry) {
const newEntry = { const newEntry = {
id: this.generateId(), id: this.generateId(),
@ -622,10 +417,6 @@ class TeeTracker {
return false; return false;
} }
// ============================================
// Statistics
// ============================================
getTotalCups() { getTotalCups() {
return this.entries.reduce((sum, entry) => sum + entry.amount, 0); return this.entries.reduce((sum, entry) => sum + entry.amount, 0);
} }
@ -743,28 +534,21 @@ class TeeTracker {
return days.size; return days.size;
} }
// ============================================
// Initialization
// ============================================
init() { init() {
// Ensure data directory exists by attempting to save
this.saveData().catch(() => {}); this.saveData().catch(() => {});
} }
setupEventListeners() { setupEventListeners() {
// Tab navigation
document.querySelectorAll('.tab-button').forEach(button => { document.querySelectorAll('.tab-button').forEach(button => {
button.addEventListener('click', () => { button.addEventListener('click', () => {
this.switchTab(button.dataset.tab); this.switchTab(button.dataset.tab);
}); });
}); });
// Event delegation for tea card buttons (edit and delete) // Event delegation for tea card buttons
const teasList = document.getElementById('teas-list'); const teasList = document.getElementById('teas-list');
if (teasList) { if (teasList) {
teasList.addEventListener('click', (e) => { teasList.addEventListener('click', (e) => {
// Edit button
const editBtn = e.target.closest('.tea-edit-btn'); const editBtn = e.target.closest('.tea-edit-btn');
if (editBtn) { if (editBtn) {
const teaId = editBtn.dataset.teaId; const teaId = editBtn.dataset.teaId;
@ -772,7 +556,6 @@ class TeeTracker {
return; return;
} }
// Delete button
const deleteBtn = e.target.closest('.tea-delete-btn'); const deleteBtn = e.target.closest('.tea-delete-btn');
if (deleteBtn) { if (deleteBtn) {
const teaId = deleteBtn.dataset.teaId; const teaId = deleteBtn.dataset.teaId;
@ -782,13 +565,11 @@ class TeeTracker {
}); });
} }
// Add tea button
const addTeaBtn = document.getElementById('add-tea-btn'); const addTeaBtn = document.getElementById('add-tea-btn');
if (addTeaBtn) { if (addTeaBtn) {
addTeaBtn.addEventListener('click', () => this.openTeaModal()); addTeaBtn.addEventListener('click', () => this.openTeaModal());
} }
// Tea modal
const teaModal = document.getElementById('tea-modal'); const teaModal = document.getElementById('tea-modal');
if (teaModal) { if (teaModal) {
teaModal.addEventListener('click', (e) => { teaModal.addEventListener('click', (e) => {
@ -796,31 +577,26 @@ class TeeTracker {
}); });
} }
// Tea form
const teaForm = document.getElementById('tea-form'); const teaForm = document.getElementById('tea-form');
if (teaForm) { if (teaForm) {
teaForm.addEventListener('submit', (e) => this.handleTeaFormSubmit(e)); teaForm.addEventListener('submit', (e) => this.handleTeaFormSubmit(e));
} }
// Cancel tea button
const cancelTeaBtn = document.getElementById('cancel-tea-btn'); const cancelTeaBtn = document.getElementById('cancel-tea-btn');
if (cancelTeaBtn) { if (cancelTeaBtn) {
cancelTeaBtn.addEventListener('click', () => this.closeTeaModal()); cancelTeaBtn.addEventListener('click', () => this.closeTeaModal());
} }
// Track form
const trackForm = document.getElementById('track-form'); const trackForm = document.getElementById('track-form');
if (trackForm) { if (trackForm) {
trackForm.addEventListener('submit', (e) => this.handleTrackFormSubmit(e)); trackForm.addEventListener('submit', (e) => this.handleTrackFormSubmit(e));
} }
// Stats period filter
const statsPeriod = document.getElementById('stats-period'); const statsPeriod = document.getElementById('stats-period');
if (statsPeriod) { if (statsPeriod) {
statsPeriod.addEventListener('change', () => this.updateStats()); statsPeriod.addEventListener('change', () => this.updateStats());
} }
// Export/Import/Clear data buttons
const exportBtn = document.getElementById('export-data'); const exportBtn = document.getElementById('export-data');
if (exportBtn) { if (exportBtn) {
exportBtn.addEventListener('click', () => this.exportData()); exportBtn.addEventListener('click', () => this.exportData());
@ -836,7 +612,6 @@ class TeeTracker {
clearBtn.addEventListener('click', () => this.showClearDataConfirm()); clearBtn.addEventListener('click', () => this.showClearDataConfirm());
} }
// Import modal
const importModal = document.getElementById('import-modal'); const importModal = document.getElementById('import-modal');
if (importModal) { if (importModal) {
importModal.addEventListener('click', (e) => { importModal.addEventListener('click', (e) => {
@ -859,7 +634,6 @@ class TeeTracker {
importDataBtn.addEventListener('click', () => this.handleImportData()); importDataBtn.addEventListener('click', () => this.handleImportData());
} }
// Confirm modal
const confirmModal = document.getElementById('confirm-modal'); const confirmModal = document.getElementById('confirm-modal');
if (confirmModal) { if (confirmModal) {
confirmModal.addEventListener('click', (e) => { confirmModal.addEventListener('click', (e) => {
@ -877,12 +651,10 @@ class TeeTracker {
confirmBtn.addEventListener('click', () => this.confirmAction()); confirmBtn.addEventListener('click', () => this.confirmAction());
} }
// Background settings
this.setupBackgroundListeners(); this.setupBackgroundListeners();
} }
setupTimerListeners() { setupTimerListeners() {
// Timer controls
const startTimerBtn = document.getElementById('start-timer'); const startTimerBtn = document.getElementById('start-timer');
const pauseTimerBtn = document.getElementById('pause-timer'); const pauseTimerBtn = document.getElementById('pause-timer');
const resetTimerBtn = document.getElementById('reset-timer'); const resetTimerBtn = document.getElementById('reset-timer');
@ -907,38 +679,29 @@ class TeeTracker {
} }
setupBackgroundListeners() { setupBackgroundListeners() {
// Background image upload
const bgUpload = document.getElementById('bg-image-upload'); const bgUpload = document.getElementById('bg-image-upload');
if (bgUpload) { if (bgUpload) {
bgUpload.addEventListener('change', (e) => this.handleBackgroundUpload(e)); bgUpload.addEventListener('change', (e) => this.handleBackgroundUpload(e));
} }
// Background enable toggle
const bgEnabled = document.getElementById('bg-enabled'); const bgEnabled = document.getElementById('bg-enabled');
if (bgEnabled) { if (bgEnabled) {
bgEnabled.addEventListener('change', () => this.toggleBackground()); bgEnabled.addEventListener('change', () => this.toggleBackground());
} }
// Save background button
const saveBgBtn = document.getElementById('save-bg'); const saveBgBtn = document.getElementById('save-bg');
if (saveBgBtn) { if (saveBgBtn) {
saveBgBtn.addEventListener('click', () => this.saveBackgroundSettings()); saveBgBtn.addEventListener('click', () => this.saveBackgroundSettings());
} }
// Remove background button
const removeBgBtn = document.getElementById('remove-bg'); const removeBgBtn = document.getElementById('remove-bg');
if (removeBgBtn) { if (removeBgBtn) {
removeBgBtn.addEventListener('click', () => this.removeBackground()); removeBgBtn.addEventListener('click', () => this.removeBackground());
} }
// Load saved background settings
this.loadBackgroundSettings(); this.loadBackgroundSettings();
} }
// ============================================
// Background Functions
// ============================================
handleBackgroundUpload(e) { handleBackgroundUpload(e) {
const file = e.target.files[0]; const file = e.target.files[0];
if (!file) return; if (!file) return;
@ -1008,10 +771,6 @@ class TeeTracker {
} }
} }
// ============================================
// Timer Functions
// ============================================
startTimer() { startTimer() {
if (this.timerRunning) return; if (this.timerRunning) return;
@ -1045,7 +804,6 @@ class TeeTracker {
pauseTimer() { pauseTimer() {
if (!this.timerRunning) return; if (!this.timerRunning) return;
clearInterval(this.timer); clearInterval(this.timer);
this.timerRunning = false; this.timerRunning = false;
this.timerPaused = true; this.timerPaused = true;
@ -1094,10 +852,6 @@ class TeeTracker {
} }
} }
// ============================================
// Data Export/Import
// ============================================
exportData() { exportData() {
const data = { const data = {
teas: this.teas, teas: this.teas,
@ -1137,7 +891,6 @@ class TeeTracker {
const data = JSON.parse(textarea.value); const data = JSON.parse(textarea.value);
if (data.teas && data.entries) { if (data.teas && data.entries) {
// Merge or replace data
if (confirm('Sollen die importierten Daten die bestehenden ersetzen?')) { if (confirm('Sollen die importierten Daten die bestehenden ersetzen?')) {
this.teas = data.teas.map(tea => ({ this.teas = data.teas.map(tea => ({
...tea, ...tea,
@ -1145,7 +898,6 @@ class TeeTracker {
})); }));
this.entries = data.entries; this.entries = data.entries;
} else { } else {
// Merge data
this.teas = [...this.teas, ...data.teas.map(tea => ({ this.teas = [...this.teas, ...data.teas.map(tea => ({
...tea, ...tea,
organic: tea.organic !== undefined ? tea.organic : false organic: tea.organic !== undefined ? tea.organic : false
@ -1177,8 +929,6 @@ class TeeTracker {
const message = 'Möchtest du wirklich ALLE Daten löschen? Dieser Vorgang kann nicht rückgängig gemacht werden!'; const message = 'Möchtest du wirklich ALLE Daten löschen? Dieser Vorgang kann nicht rückgängig gemacht werden!';
document.getElementById('confirm-message').textContent = message; document.getElementById('confirm-message').textContent = message;
document.getElementById('confirm-modal').classList.add('active'); document.getElementById('confirm-modal').classList.add('active');
// Set action type
this.tempConfirmAction = 'clearData'; this.tempConfirmAction = 'clearData';
} }
@ -1195,11 +945,9 @@ class TeeTracker {
this.teas = []; this.teas = [];
this.entries = []; this.entries = [];
// Clear localStorage
localStorage.removeItem(STORAGE_KEY_TEAS); localStorage.removeItem(STORAGE_KEY_TEAS);
localStorage.removeItem(STORAGE_KEY_ENTRIES); localStorage.removeItem(STORAGE_KEY_ENTRIES);
// Clear file storage if available
if (this.useFileStorage) { if (this.useFileStorage) {
await this.fileStorage.saveFile('teas.json', []); await this.fileStorage.saveFile('teas.json', []);
await this.fileStorage.saveFile('entries.json', []); await this.fileStorage.saveFile('entries.json', []);
@ -1211,10 +959,6 @@ class TeeTracker {
this.updateSettingsStats(); this.updateSettingsStats();
} }
// ============================================
// Tab Navigation
// ============================================
switchTab(tabId) { switchTab(tabId) {
document.querySelectorAll('.tab-button').forEach(button => { document.querySelectorAll('.tab-button').forEach(button => {
button.classList.toggle('active', button.dataset.tab === tabId); button.classList.toggle('active', button.dataset.tab === tabId);
@ -1273,10 +1017,6 @@ class TeeTracker {
} }
} }
// ============================================
// Dashboard
// ============================================
updateDashboard() { updateDashboard() {
const totalCups = document.getElementById('total-cups'); const totalCups = document.getElementById('total-cups');
const todayCups = document.getElementById('today-cups'); const todayCups = document.getElementById('today-cups');
@ -1329,10 +1069,6 @@ class TeeTracker {
}).join(''); }).join('');
} }
// ============================================
// Tea List
// ============================================
renderTeasList() { renderTeasList() {
const container = document.getElementById('teas-list'); const container = document.getElementById('teas-list');
if (!container) return; if (!container) return;
@ -1346,7 +1082,6 @@ class TeeTracker {
<button class="btn btn-primary add-first-tea-btn"> Tee hinzufügen</button> <button class="btn btn-primary add-first-tea-btn"> Tee hinzufügen</button>
</div> </div>
`; `;
// Add event listener for the add button
const addBtn = container.querySelector('.add-first-tea-btn'); const addBtn = container.querySelector('.add-first-tea-btn');
if (addBtn) { if (addBtn) {
addBtn.addEventListener('click', () => this.openTeaModal()); addBtn.addEventListener('click', () => this.openTeaModal());
@ -1418,10 +1153,6 @@ class TeeTracker {
`).join(''); `).join('');
} }
// ============================================
// Tea Modal
// ============================================
openTeaModal(teaId = null) { openTeaModal(teaId = null) {
const modal = document.getElementById('tea-modal'); const modal = document.getElementById('tea-modal');
const form = document.getElementById('tea-form'); const form = document.getElementById('tea-form');
@ -1439,12 +1170,10 @@ class TeeTracker {
document.getElementById('tea-organic').checked = tea.organic || false; document.getElementById('tea-organic').checked = tea.organic || false;
document.getElementById('tea-image-preview-img').src = tea.image || ''; document.getElementById('tea-image-preview-img').src = tea.image || '';
document.getElementById('tea-image-preview').style.display = tea.image ? 'block' : 'none'; document.getElementById('tea-image-preview').style.display = tea.image ? 'block' : 'none';
this.renderStarRating(tea.rating || 3, 'tea-rating'); this.renderStarRating(tea.rating || 3, 'tea-rating');
this.currentTeaId = tea.id; this.currentTeaId = tea.id;
} }
} else { } else {
// New tea
form.reset(); form.reset();
document.getElementById('tea-color').value = '#8B4513'; document.getElementById('tea-color').value = '#8B4513';
document.getElementById('tea-organic').checked = false; document.getElementById('tea-organic').checked = false;
@ -1477,8 +1206,6 @@ class TeeTracker {
const color = document.getElementById('tea-color').value; const color = document.getElementById('tea-color').value;
const organic = document.getElementById('tea-organic').checked; const organic = document.getElementById('tea-organic').checked;
const image = document.getElementById('tea-image-preview').src || ''; const image = document.getElementById('tea-image-preview').src || '';
// Get rating from star rating
const rating = this.getStarRating('tea-rating'); const rating = this.getStarRating('tea-rating');
if (!name || !type) { if (!name || !type) {
@ -1489,11 +1216,9 @@ class TeeTracker {
const teaData = { name, type, brand, description, color, organic, rating, image }; const teaData = { name, type, brand, description, color, organic, rating, image };
if (id) { if (id) {
// Update existing tea
this.updateTea(id, teaData); this.updateTea(id, teaData);
this.showToast('Tee-Sorte erfolgreich aktualisiert!', 'success'); this.showToast('Tee-Sorte erfolgreich aktualisiert!', 'success');
} else { } else {
// Add new tea
this.addTea(teaData); this.addTea(teaData);
this.showToast('Tee-Sorte erfolgreich hinzugefügt!', 'success'); this.showToast('Tee-Sorte erfolgreich hinzugefügt!', 'success');
} }
@ -1578,7 +1303,6 @@ class TeeTracker {
const message = `Möchtest du wirklich die Tee-Sorte "${tea ? tea.name : 'Unbekannt'}" löschen? Alle damit verbundenen Einträge werden ebenfalls gelöscht!`; const message = `Möchtest du wirklich die Tee-Sorte "${tea ? tea.name : 'Unbekannt'}" löschen? Alle damit verbundenen Einträge werden ebenfalls gelöscht!`;
document.getElementById('confirm-message').textContent = message; document.getElementById('confirm-message').textContent = message;
document.getElementById('confirm-modal').classList.add('active'); document.getElementById('confirm-modal').classList.add('active');
this.tempConfirmAction = 'deleteTea'; this.tempConfirmAction = 'deleteTea';
this.currentTeaId = teaId; this.currentTeaId = teaId;
} }
@ -1610,10 +1334,6 @@ class TeeTracker {
this.currentTeaId = null; this.currentTeaId = null;
} }
// ============================================
// Track Form
// ============================================
renderTrackForm() { renderTrackForm() {
const teaSelect = document.getElementById('track-tea'); const teaSelect = document.getElementById('track-tea');
const today = new Date().toISOString().split('T')[0]; const today = new Date().toISOString().split('T')[0];
@ -1662,7 +1382,6 @@ class TeeTracker {
this.showToast('Tee-Konsum erfolgreich getrackt!', 'success'); this.showToast('Tee-Konsum erfolgreich getrackt!', 'success');
this.resetTrackForm(); this.resetTrackForm();
this.updateDashboard(); this.updateDashboard();
this.updateStats(); this.updateStats();
this.renderTrackRecentEntries(); this.renderTrackRecentEntries();
@ -1716,12 +1435,7 @@ class TeeTracker {
}).join(''); }).join('');
} }
// ============================================
// Charts
// ============================================
initCharts() { initCharts() {
// Check if Chart.js is loaded
if (typeof Chart === 'undefined') { if (typeof Chart === 'undefined') {
console.log('Chart.js not loaded, skipping charts initialization'); console.log('Chart.js not loaded, skipping charts initialization');
return; return;
@ -1739,7 +1453,6 @@ class TeeTracker {
const labels = Object.keys(typeCounts); const labels = Object.keys(typeCounts);
const data = Object.values(typeCounts); const data = Object.values(typeCounts);
// Define colors for each tea type
const typeColors = { const typeColors = {
'Schwarztee': '#8B4513', 'Schwarztee': '#8B4513',
'Grüntee': '#228B22', 'Grüntee': '#228B22',
@ -1800,7 +1513,6 @@ class TeeTracker {
const labels = Object.keys(dailyCounts).sort(); const labels = Object.keys(dailyCounts).sort();
const data = labels.map(date => dailyCounts[date] || 0); const data = labels.map(date => dailyCounts[date] || 0);
// Format dates for display
const formattedLabels = labels.map(date => { const formattedLabels = labels.map(date => {
const d = new Date(date); const d = new Date(date);
return d.toLocaleDateString('de-DE', { weekday: 'short', day: 'numeric' }); return d.toLocaleDateString('de-DE', { weekday: 'short', day: 'numeric' });
@ -1850,15 +1562,9 @@ class TeeTracker {
}); });
} }
// ============================================
// Statistics
// ============================================
updateStats() { updateStats() {
const period = document.getElementById('stats-period')?.value || 'all'; const period = document.getElementById('stats-period')?.value || 'all';
this.renderDetailedStats(period); this.renderDetailedStats(period);
// Update charts
this.createTeaTypeChart(); this.createTeaTypeChart();
this.createDailyChart(); this.createDailyChart();
} }
@ -1900,7 +1606,6 @@ class TeeTracker {
calculateAveragePerDay(period) { calculateAveragePerDay(period) {
const entries = this.getEntriesByPeriod(period); const entries = this.getEntriesByPeriod(period);
if (entries.length === 0) return 0; if (entries.length === 0) return 0;
const totalCups = this.getCupsByPeriod(period); const totalCups = this.getCupsByPeriod(period);
const days = this.countUniqueDays(entries); const days = this.countUniqueDays(entries);
return days > 0 ? totalCups / days : 0; return days > 0 ? totalCups / days : 0;
@ -1918,10 +1623,6 @@ class TeeTracker {
return teaIds.size; return teaIds.size;
} }
// ============================================
// Toast Notifications
// ============================================
showToast(message, type = 'info') { showToast(message, type = 'info') {
const toastContainer = document.getElementById('toast-container'); const toastContainer = document.getElementById('toast-container');
if (!toastContainer) return; if (!toastContainer) return;