Code: Select all
// ============================================Code: Select all
// FIXED: checkAndUpdateAchievements function - Fixed achievement checkingCode: Select all
// ============================================Code: Select all
function checkAndUpdateAchievements() {Code: Select all
if (!appState.profile) return;Code: Select all
Code: Select all
const achievements = appState.profile.achievements || {};Code: Select all
let newAchievements = [];Code: Select all
Code: Select all
ACHIEVEMENTS.forEach(achievement => {Code: Select all
if (!achievements[achievement.id] || !achievements[achievement.id].unlocked) {Code: Select all
if (achievement.condition(appState.profile, appState.todayData, appState.historicalData)) {Code: Select all
if (!achievements[achievement.id]) {Code: Select all
achievements[achievement.id] = {Code: Select all
unlocked: true,Code: Select all
unlockedAt: new Date().toISOString()Code: Select all
};Code: Select all
newAchievements.push(achievement);Code: Select all
}Code: Select all
}Code: Select all
}Code: Select all
});Code: Select all
Code: Select all
appState.profile.achievements = achievements;Code: Select all
Code: Select all
// Show animations for new achievementsCode: Select all
if (newAchievements.length > 0) {Code: Select all
// Show first achievement immediatelyCode: Select all
showAchievementUnlock(newAchievements[0]);Code: Select all
Code: Select all
// Show remaining achievements with delayCode: Select all
for (let i = 1; i < newAchievements.length; i++) {Code: Select all
setTimeout(() => {Code: Select all
showAchievementUnlock(newAchievements[i]);Code: Select all
}, i * 4500);Code: Select all
}Code: Select all
Code: Select all
saveAllData();Code: Select all
}Code: Select all
}Code: Select all
// ============================================Code: Select all
// FIXED: addDrink function - Fixed to properly trigger achievementsCode: Select all
// ============================================Code: Select all
function addDrink(type, amount) {Code: Select all
const drink = BEVERAGES[type];Code: Select all
if (!drink) return;Code: Select all
Code: Select all
const waterContent = Math.round(amount * drink.waterContent / 100);Code: Select all
Code: Select all
const drinkRecord = {Code: Select all
type,Code: Select all
amount,Code: Select all
waterContent,Code: Select all
timestamp: new Date().toISOString(),Code: Select all
time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })Code: Select all
};Code: Select all
Code: Select all
appState.todayData.consumed += waterContent;Code: Select all
if (!appState.todayData.drinks) appState.todayData.drinks = [];Code: Select all
appState.todayData.drinks.push(drinkRecord);Code: Select all
Code: Select all
// Check if goal is reachedCode: Select all
const goalReached = !appState.todayData.completed && appState.todayData.consumed >= appState.todayData.goal;Code: Select all
if (goalReached) {Code: Select all
appState.todayData.completed = true;Code: Select all
showNotification("🎉 Daily goal achieved! Great work!", "success");Code: Select all
}Code: Select all
Code: Select all
// Save data immediatelyCode: Select all
saveAllData();Code: Select all
Code: Select all
// Update UICode: Select all
updateDashboard();Code: Select all
updateStatistics();Code: Select all
updateTimeProgress();Code: Select all
showNotification(`Added ${amount}ml of ${drink.name} (${waterContent}ml water)`, "success");Code: Select all
Code: Select all
// Check achievements AFTER updating UI and saving dataCode: Select all
// This ensures the hydrated_beginner achievement triggers when goal is reachedCode: Select all
checkAndUpdateAchievements();Code: Select all
}Code: Select all
// ============================================Code: Select all
// FIXED: adjustHeight and adjustWeight functions - Fixed to save dataCode: Select all
// ============================================Code: Select all
function adjustHeight(change) {Code: Select all
const input = document.getElementById('heightInput');Code: Select all
let value = parseInt(input.value) + change;Code: Select all
Code: Select all
if (appState.unitSystem === 'metric') {Code: Select all
value = Math.max(100, Math.min(250, value));Code: Select all
} else {Code: Select all
value = Math.max(39, Math.min(98, value));Code: Select all
}Code: Select all
Code: Select all
input.value = value;Code: Select all
updateHeightFromInput();Code: Select all
}Code: Select all
function adjustWeight(change) {Code: Select all
const input = document.getElementById('weightInput');Code: Select all
let value = parseInt(input.value) + change;Code: Select all
Code: Select all
if (appState.unitSystem === 'metric') {Code: Select all
value = Math.max(30, Math.min(200, value));Code: Select all
} else {Code: Select all
value = Math.max(66, Math.min(440, value));Code: Select all
}Code: Select all
Code: Select all
input.value = value;Code: Select all
updateWeightFromInput();Code: Select all
}Code: Select all
// ============================================Code: Select all
// FIXED: updateHeightFromInput and updateWeightFromInput - Fixed to save dataCode: Select all
// ============================================Code: Select all
function updateHeightFromInput() {Code: Select all
const input = document.getElementById('heightInput');Code: Select all
let value = parseInt(input.value);Code: Select all
Code: Select all
if (isNaN(value)) {Code: Select all
value = appState.unitSystem === 'metric' ? 170 : 67;Code: Select all
}Code: Select all
Code: Select all
if (appState.unitSystem === 'metric') {Code: Select all
value = Math.max(100, Math.min(250, value));Code: Select all
} else {Code: Select all
value = Math.max(39, Math.min(98, value));Code: Select all
}Code: Select all
Code: Select all
input.value = value;Code: Select all
document.getElementById('heightValue').textContent = value;Code: Select all
Code: Select all
// Update the ruler positionCode: Select all
updateRuler('heightRuler', value);Code: Select all
Code: Select all
// Save to profile (converting if necessary)Code: Select all
if (appState.unitSystem === 'metric') {Code: Select all
appState.profile.height = value;Code: Select all
} else {Code: Select all
// Convert inches to cm for storageCode: Select all
appState.profile.height = Math.round(value * 2.54);Code: Select all
}Code: Select all
Code: Select all
// Save dataCode: Select all
saveAllData();Code: Select all
}Code: Select all
function updateWeightFromInput() {Code: Select all
const input = document.getElementById('weightInput');Code: Select all
let value = parseInt(input.value);Code: Select all
Code: Select all
if (isNaN(value)) {Code: Select all
value = appState.unitSystem === 'metric' ? 70 : 154;Code: Select all
}Code: Select all
Code: Select all
if (appState.unitSystem === 'metric') {Code: Select all
value = Math.max(30, Math.min(200, value));Code: Select all
} else {Code: Select all
value = Math.max(66, Math.min(440, value));Code: Select all
}Code: Select all
Code: Select all
input.value = value;Code: Select all
document.getElementById('weightValue').textContent = value;Code: Select all
updateRuler('weightRuler', value);Code: Select all
Code: Select all
// Save to profile (converting if necessary)Code: Select all
if (appState.unitSystem === 'metric') {Code: Select all
appState.profile.weight = value;Code: Select all
} else {Code: Select all
// Convert lbs to kg for storageCode: Select all
appState.profile.weight = Math.round(value / 2.20462);Code: Select all
}Code: Select all
Code: Select all
// Save dataCode: Select all
saveAllData();Code: Select all
}Code: Select all
// ============================================Code: Select all
// REST OF THE CODE REMAINS THE SAME (unchanged parts)Code: Select all
// ============================================Code: Select all
const BEVERAGES = {Code: Select all
water: {Code: Select all
name: "Water",Code: Select all
icon: "fa-tint",Code: Select all
color: "#4fd1ff",Code: Select all
waterContent: 100,Code: Select all
description: "Pure hydration - no additives"Code: Select all
},Code: Select all
sparkling_water: {Code: Select all
name: "Sparkling Water",Code: Select all
icon: "fa-glass-water",Code: Select all
color: "#6b7cff",Code: Select all
waterContent: 100,Code: Select all
description: "Carbonated water - same hydration"Code: Select all
},Code: Select all
herbal_tea: {Code: Select all
name: "Herbal Tea",Code: Select all
icon: "fa-mug-hot",Code: Select all
color: "#ffb84d",Code: Select all
waterContent: 99,Code: Select all
description: "No caffeine - excellent hydration"Code: Select all
},Code: Select all
green_tea: {Code: Select all
name: "Green Tea",Code: Select all
icon: "fa-leaf",Code: Select all
color: "#4dff88",Code: Select all
waterContent: 99,Code: Select all
description: "Antioxidants - minimal caffeine"Code: Select all
},Code: Select all
black_coffee: {Code: Select all
name: "Black Coffee",Code: Select all
icon: "fa-coffee",Code: Select all
color: "#8B4513",Code: Select all
waterContent: 98,Code: Select all
description: "Caffeine reduces hydration by 15%"Code: Select all
},Code: Select all
milk: {Code: Select all
name: "Milk",Code: Select all
icon: "fa-cow",Code: Select all
color: "#ffffff",Code: Select all
waterContent: 87,Code: Select all
description: "Contains nutrients - good hydration"Code: Select all
},Code: Select all
fruit_juice: {Code: Select all
name: "Fruit Juice",Code: Select all
icon: "fa-apple-alt",Code: Select all
color: "#ff6b6b",Code: Select all
waterContent: 88,Code: Select all
description: "Natural sugars - moderate hydration"Code: Select all
},Code: Select all
sports_drink: {Code: Select all
name: "Sports Drink",Code: Select all
icon: "fa-bolt",Code: Select all
color: "#ff4d6d",Code: Select all
waterContent: 94,Code: Select all
description: "Electrolytes - good for exercise"Code: Select all
},Code: Select all
soda: {Code: Select all
name: "Soda",Code: Select all
icon: "fa-glass-whiskey",Code: Select all
color: "#ff4757",Code: Select all
waterContent: 90,Code: Select all
description: "High sugar - poor hydration"Code: Select all
},Code: Select all
smoothie: {Code: Select all
name: "Smoothie",Code: Select all
icon: "fa-blender",Code: Select all
color: "#9d4edd",Code: Select all
waterContent: 85,Code: Select all
description: "Nutrient-rich - good hydration"Code: Select all
}Code: Select all
};Code: Select all
const HYDRATION_TIPS = [Code: Select all
"Start your day with a glass of water to kickstart metabolism",Code: Select all
"Drink water 30 minutes before meals for better digestion",Code: Select all
"Your body is about 60% water - keep it replenished!",Code: Select all
"Dehydration can reduce cognitive performance by up to 30%",Code: Select all
"Carry a reusable water bottle to stay hydrated on the go",Code: Select all
"Eat water-rich foods like watermelon, cucumber, and oranges",Code: Select all
"Listen to your body - thirst is a sign you're already dehydrated",Code: Select all
"Alcohol and caffeine can dehydrate you - balance with water",Code: Select all
"Stay hydrated during exercise to maintain performance",Code: Select all
"Proper hydration helps regulate body temperature"Code: Select all
];Code: Select all
const ACTIVITY_LEVELS = {Code: Select all
sedentary: 1.0,Code: Select all
light: 1.2,Code: Select all
moderate: 1.4,Code: Select all
active: 1.6,Code: Select all
athlete: 1.8Code: Select all
};Code: Select all
let appState = {Code: Select all
profile: null,Code: Select all
todayData: null,Code: Select all
historicalData: {},Code: Select all
settings: {},Code: Select all
selectedDrink: null,Code: Select all
selectedAmount: 250,Code: Select all
currentChartType: 'weekly',Code: Select all
currentPieType: 'today',Code: Select all
currentMonth: new Date().getMonth(),Code: Select all
currentYear: new Date().getFullYear(),Code: Select all
dataVersion: 5,Code: Select all
unitSystem: 'metric'Code: Select all
};Code: Select all
let trendChart = null;Code: Select all
let distributionChart = null;Code: Select all
function quickAddDrink(type, amount) {Code: Select all
addDrink(type, amount);Code: Select all
}Code: Select all
function setGoalPercentage(percentage) {Code: Select all
const goal = appState.profile.dailyGoal;Code: Select all
const targetAmount = Math.round((goal * percentage) / 100);Code: Select all
Code: Select all
if (appState.todayData.consumed < targetAmount) {Code: Select all
const needed = targetAmount - appState.todayData.consumed;Code: Select all
if (needed > 0) {Code: Select all
addDrink('water', needed);Code: Select all
}Code: Select all
}Code: Select all
Code: Select all
updateHydrationLevels();Code: Select all
}Code: Select all
function updateHydrationLevels() {Code: Select all
if (!appState.todayData || !appState.profile) return;Code: Select all
Code: Select all
const consumed = appState.todayData.consumed || 0;Code: Select all
const goal = appState.todayData.goal || appState.profile.dailyGoal || 2000;Code: Select all
const progress = Math.min(Math.round((consumed / goal) * 100), 100);Code: Select all
Code: Select all
const hydrationLevels = document.querySelectorAll('.hydration-level');Code: Select all
hydrationLevels.forEach(level => level.classList.remove('active'));Code: Select all
Code: Select all
if (progress >= 87.5) {Code: Select all
hydrationLevels[4].classList.add('active');Code: Select all
} else if (progress >= 62.5) {Code: Select all
hydrationLevels[3].classList.add('active');Code: Select all
} else if (progress >= 37.5) {Code: Select all
hydrationLevels[2].classList.add('active');Code: Select all
} else if (progress >= 12.5) {Code: Select all
hydrationLevels[1].classList.add('active');Code: Select all
} else {Code: Select all
hydrationLevels[0].classList.add('active');Code: Select all
}Code: Select all
}Code: Select all
function checkAndUpdateStreak() {Code: Select all
const today = new Date();Code: Select all
const yesterday = new Date(today);Code: Select all
yesterday.setDate(yesterday.getDate() - 1);Code: Select all
const yesterdayStr = yesterday.toDateString();Code: Select all
Code: Select all
const yesterdayData = appState.historicalData[yesterdayStr];Code: Select all
Code: Select all
if (yesterdayData) {Code: Select all
if (yesterdayData.completed) {Code: Select all
appState.profile.currentStreak = (appState.profile.currentStreak || 0) + 1;Code: Select all
appState.profile.bestStreak = Math.max(appState.profile.bestStreak || 0, appState.profile.currentStreak);Code: Select all
} else {Code: Select all
appState.profile.currentStreak = 0;Code: Select all
}Code: Select all
}Code: Select all
}Code: Select all
function updateDashboard() {Code: Select all
if (!appState.todayData) return;Code: Select all
Code: Select all
const consumed = appState.todayData.consumed || 0;Code: Select all
const goal = appState.todayData.goal || appState.profile?.dailyGoal || 2000;Code: Select all
const progress = Math.min(Math.round((consumed / goal) * 100), 100);Code: Select all
Code: Select all
document.getElementById('progressFill').style.width = `${progress}%`;Code: Select all
document.getElementById('progressText').textContent = `${progress}%`;Code: Select all
document.getElementById('waterLevel').style.height = `${progress}%`;Code: Select all
document.getElementById('consumedDisplay').textContent = `${consumed.toLocaleString()} ml`;Code: Select all
document.getElementById('goalDisplay').textContent = `of ${goal.toLocaleString()} ml goal`;Code: Select all
document.getElementById('drinksCount').textContent = appState.todayData.drinks?.length || 0;Code: Select all
document.getElementById('streakCount').textContent = appState.profile?.currentStreak || 0;Code: Select all
Code: Select all
const todayDrinks = appState.todayData.drinks || [];Code: Select all
const todayBest = todayDrinks.length > 0 ? Math.max(...todayDrinks.map(d => d.amount)) : 0;Code: Select all
document.getElementById('todayBest').textContent = `${todayBest}ml`;Code: Select all
Code: Select all
updateHydrationLevels();Code: Select all
updateQuickStats();Code: Select all
updateRecentActivity();Code: Select all
updateHydrationTip();Code: Select all
Code: Select all
if (appState.profile?.name) {Code: Select all
document.getElementById('userName').textContent = appState.profile.name;Code: Select all
}Code: Select all
}Code: Select all
function updateQuickStats() {Code: Select all
if (!appState.todayData || !appState.historicalData) return;Code: Select all
Code: Select all
const last7Days = getLastNDays(7);Code: Select all
const daysWithData = last7Days.filter(d => d && d.consumed > 0);Code: Select all
const weeklyTotal = daysWithData.reduce((sum, day) => sum + (day?.consumed || 0), 0);Code: Select all
const weekAvg = daysWithData.length > 0 ? Math.round(weeklyTotal / daysWithData.length) : 0;Code: Select all
document.getElementById('weekAvg').textContent = `${weekAvg}ml`;Code: Select all
Code: Select all
const last30Days = getLastNDays(30);Code: Select all
const monthlyTotal = last30Days.reduce((sum, day) => sum + (day?.consumed || 0), 0);Code: Select all
document.getElementById('monthTotal').textContent = `${Math.round(monthlyTotal / 1000)}L`;Code: Select all
Code: Select all
const goalDays = last30Days.filter(d => d?.completed).length;Code: Select all
const goalPercent = last30Days.length > 0 ? Math.round((goalDays / last30Days.length) * 100) : 0;Code: Select all
document.getElementById('goalDays').textContent = `${goalPercent}%`;Code: Select all
Code: Select all
document.getElementById('bestStreak').textContent = appState.profile?.bestStreak || 0;Code: Select all
}Code: Select all
function getLastNDays(n) {Code: Select all
const days = [];Code: Select all
for (let i = 0; i < n; i++) {Code: Select all
const date = new Date();Code: Select all
date.setDate(date.getDate() - i);Code: Select all
const dateStr = date.toDateString();Code: Select all
days.push(appState.historicalData[dateStr]);Code: Select all
}Code: Select all
return days;Code: Select all
}Code: Select all
function getLastNDaysData(n) {Code: Select all
const days = [];Code: Select all
for (let i = 0; i < n; i++) {Code: Select all
const date = new Date();Code: Select all
date.setDate(date.getDate() - i);Code: Select all
const dateStr = date.toDateString();Code: Select all
days.push(appState.historicalData[dateStr]);Code: Select all
}Code: Select all
return days;Code: Select all
}Code: Select all
function updateHydrationTip() {Code: Select all
const tip = HYDRATION_TIPS[Math.floor(Math.random() * HYDRATION_TIPS.length)];Code: Select all
document.getElementById('hydrationTip').textContent = tip;Code: Select all
}Code: Select all
function selectGender(gender) {Code: Select all
if (!appState.profile) return;Code: Select all
appState.profile.gender = gender;Code: Select all
Code: Select all
document.querySelectorAll('.gender-option').forEach(option => {Code: Select all
option.classList.remove('active');Code: Select all
if (option.dataset.gender === gender) {Code: Select all
option.classList.add('active');Code: Select all
}Code: Select all
});Code: Select all
Code: Select all
saveAllData();Code: Select all
}Code: Select all
function selectActivityLevel(level) {Code: Select all
if (!appState.profile) return;Code: Select all
appState.profile.activityLevel = level;Code: Select all
Code: Select all
document.querySelectorAll('.activity-level').forEach(item => {Code: Select all
item.classList.remove('active');Code: Select all
if (item.dataset.level === level) {Code: Select all
item.classList.add('active');Code: Select all
}Code: Select all
});Code: Select all
}Code: Select all
function updateGreetingMessage() {Code: Select all
const hour = new Date().getHours();Code: Select all
let greeting = "Stay Hydrated, Stay Healthy";Code: Select all
Code: Select all
if (hour < 12) greeting = "Good morning! Stay hydrated today";Code: Select all
else if (hour < 18) greeting = "Good afternoon! Keep drinking water";Code: Select all
else greeting = "Good evening! Finish your hydration goal";Code: Select all
Code: Select all
document.getElementById('greetingMessage').textContent = greeting;Code: Select all
}
Mobile version