mirror of
https://github.com/trevor1969/teatracker.git
synced 2026-08-09 10:41:59 +00:00
Clean app.js: Remove all merge conflicts and duplicate classes
Co-authored-by: trevor1969 <trevor1969@users.noreply.github.com>
This commit is contained in:
317
app.js
317
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 {
|
||||
<button class="btn btn-primary add-first-tea-btn">➕ Tee hinzufügen</button>
|
||||
</div>
|
||||
`;
|
||||
// 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;
|
||||
|
||||
Reference in New Issue
Block a user