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