feat: add settings

This commit is contained in:
2025-06-13 19:18:31 -03:00
parent 28c77234d7
commit a1cc868f33
7 changed files with 342 additions and 26 deletions
+4 -2
View File
@@ -191,7 +191,8 @@
} }
/* Update main content spacing */ /* Update main content spacing */
#app-content { #app-content,
#settings-content {
padding-top: 20px; padding-top: 20px;
} }
@@ -214,7 +215,8 @@
justify-content: center; justify-content: center;
} }
.auth-form { .auth-form,
.settings-form {
min-width: 280px; min-width: 280px;
padding: 20px; padding: 20px;
} }
+31
View File
@@ -6,6 +6,7 @@
<title>Daily Calorie Tracker</title> <title>Daily Calorie Tracker</title>
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="auth.css"> <link rel="stylesheet" href="auth.css">
<link rel="stylesheet" href="settings.css">
</head> </head>
<body> <body>
<!-- Authentication Header --> <!-- Authentication Header -->
@@ -61,6 +62,7 @@
<div id="user-info" class="user-info hidden"> <div id="user-info" class="user-info hidden">
<div class="user-details"> <div class="user-details">
<span id="userName">Welcome, User!</span> <span id="userName">Welcome, User!</span>
<button id="settingsBtn" class="logout-btn">Settings</button>
<button id="logoutBtn" class="logout-btn">Logout</button> <button id="logoutBtn" class="logout-btn">Logout</button>
</div> </div>
</div> </div>
@@ -88,18 +90,22 @@
<div class="nutrition-summary" id="nutritionSummary"> <div class="nutrition-summary" id="nutritionSummary">
<div class="nutrition-item"> <div class="nutrition-item">
<div class="nutrition-value" id="proteinValue">0</div> <div class="nutrition-value" id="proteinValue">0</div>
<div class="nutrition-label hidden" id="proteinGoalText">of 190</div>
<div class="nutrition-label">Protein (g)</div> <div class="nutrition-label">Protein (g)</div>
</div> </div>
<div class="nutrition-item"> <div class="nutrition-item">
<div class="nutrition-value" id="fatValue">0</div> <div class="nutrition-value" id="fatValue">0</div>
<div class="nutrition-label hidden" id="fatGoalText">of 190</div>
<div class="nutrition-label">Fat (g)</div> <div class="nutrition-label">Fat (g)</div>
</div> </div>
<div class="nutrition-item"> <div class="nutrition-item">
<div class="nutrition-value" id="carboValue">0</div> <div class="nutrition-value" id="carboValue">0</div>
<div class="nutrition-label hidden" id="carboGoalText">of 190</div>
<div class="nutrition-label">Carbs (g)</div> <div class="nutrition-label">Carbs (g)</div>
</div> </div>
<div class="nutrition-item"> <div class="nutrition-item">
<div class="nutrition-value" id="fiberValue">0</div> <div class="nutrition-value" id="fiberValue">0</div>
<div class="nutrition-label hidden" id="fiberGoalText">of 190</div>
<div class="nutrition-label">Fiber (g)</div> <div class="nutrition-label">Fiber (g)</div>
</div> </div>
</div> </div>
@@ -183,6 +189,31 @@
</div> </div>
</main> </main>
<!-- Settings -->
<section id="settings-content" class="hidden">
<div class="container">
<h1>⚙️ Settings</h1>
<div class="date-display">Define your macros goal</div>
<form id="settingsForm" class="settings-form">
<div class="form-group">
<input type="number" id="proteinGoal" placeholder="Proteins in grams" required>
</div>
<div class="form-group">
<input type="number" id="fatGoal" placeholder="Fat in grams" required>
</div>
<div class="form-group">
<input type="number" id="carboGoal" placeholder="Carbo in grams" required>
</div>
<div class="form-group">
<input type="number" id="fiberGoal" placeholder="Fiber in grams" required>
</div>
<button type="submit" class="settings-btn">Save</button>
</form>
</div>
</section>
<script type="module" src="src/index.ts"></script> <script type="module" src="src/index.ts"></script>
</body> </body>
</html> </html>
+51
View File
@@ -0,0 +1,51 @@
.settings-form {
backdrop-filter: blur(10px);
border-radius: 10px;
padding: 25px;
min-width: 300px;
/* background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2); */
}
.settings-form .form-group {
margin-bottom: 15px;
}
.settings-form input {
width: 100%;
padding: 12px;
border-radius: 6px;
font-size: 1rem;
backdrop-filter: blur(10px);
box-sizing: border-box;
border: 1px solid #ccc;
}
.settings-form input::placeholder {
color: rgba(0, 0, 0, 0.7);
}
.settings-form input:focus {
outline: none;
border-color: #667eea;
}
.settings-btn {
width: 100%;
padding: 12px;
color: white;
background: #667eea;
border: 1px solid #667eea;
border-radius: 6px;
cursor: pointer;
font-size: 1rem;
font-weight: 600;
transition: all 0.3s ease;
backdrop-filter: blur(10px);
}
.settings-btn:hover {
background: #8d9de7;
border: 1px solid #8d9de7;
transform: translateY(-1px);
}
+56 -1
View File
@@ -1,5 +1,5 @@
import { Client, Account, Databases, Query } from 'appwrite'; import { Client, Account, Databases, Query } from 'appwrite';
import { FoodStorage } from './types'; import { FoodStorage, UserSettings } from './types';
// Initialize Appwrite client // Initialize Appwrite client
const client = new Client(); const client = new Client();
@@ -15,6 +15,7 @@ export const databases = new Databases(client);
// Configuration constants // Configuration constants
export const DATABASE_ID = '684b38db000fac8c781c'; // Replace with your database ID export const DATABASE_ID = '684b38db000fac8c781c'; // Replace with your database ID
export const FOOD_ENTRIES_COLLECTION_ID = '684b38e300336fc605dc'; // Replace with your collection ID export const FOOD_ENTRIES_COLLECTION_ID = '684b38e300336fc605dc'; // Replace with your collection ID
export const USER_SETTINGS_COLLECTION_ID = '684c75140026689fe603'; // Replace with your collection ID
// Auth helper functions // Auth helper functions
export class AppwriteAuth { export class AppwriteAuth {
@@ -98,6 +99,26 @@ export class AppwriteDB {
} }
} }
// Save food entry
static async saveUserSettings(userSettings: UserSettings) {
try {
const response = await databases.createDocument(
DATABASE_ID,
USER_SETTINGS_COLLECTION_ID,
'unique()',
{
...userSettings,
userId: (await account.get()).$id,
}
);
console.debug('User settings saved:', response);
return response;
} catch (error) {
console.error('Save user settings error:', error);
throw error;
}
}
// Get user's food entries for a specific date // Get user's food entries for a specific date
static async getFoodEntries(date: Date) { static async getFoodEntries(date: Date) {
try { try {
@@ -119,6 +140,40 @@ export class AppwriteDB {
} }
} }
// get user's settings
static async getUserSettings() {
try {
const user = await account.get();
const response = await databases.listDocuments(
DATABASE_ID,
USER_SETTINGS_COLLECTION_ID,
[
Query.equal('userId', user.$id),
]
);
console.debug('User settings retrieved:', response);
return response.documents;
} catch (error) {
console.error('Get user settings error:', error);
throw error;
}
}
static async deleteUserSettings(documentId: string) {
try {
await databases.deleteDocument(
DATABASE_ID,
USER_SETTINGS_COLLECTION_ID,
documentId
);
console.debug('User settings deleted:', documentId);
} catch (error) {
console.error('Delete user settings error:', error);
throw error;
}
}
// Delete food entry // Delete food entry
static async deleteFoodEntry(documentId: string) { static async deleteFoodEntry(documentId: string) {
try { try {
+21 -14
View File
@@ -12,19 +12,19 @@ export const foodDatabase: FoodItem[] = [
{ name: 'Frutas - Melão', info: { calories: 29, protein: 0.7, fat: 0, carbs: 7.5, fiber: 0.3 } }, { name: 'Frutas - Melão', info: { calories: 29, protein: 0.7, fat: 0, carbs: 7.5, fiber: 0.3 } },
{ name: 'Frutas - Uva', info: { calories: 53, protein: 0.7, fat: 0.2, carbs: 13.6, fiber: 0.9 } }, { name: 'Frutas - Uva', info: { calories: 53, protein: 0.7, fat: 0.2, carbs: 13.6, fiber: 0.9 } },
{ name: 'Vegetais - Agrião', info: { calories: 17, protein: 2.7, fat: 0.2, carbs: 2.3, fiber: 2.1 } }, { name: 'Verduras - Agrião', info: { calories: 17, protein: 2.7, fat: 0.2, carbs: 2.3, fiber: 2.1 } },
{ name: 'Vegetais - Brócolis (cozido)', info: { calories: 25, protein: 2.1, fat: 0.5, carbs: 4.4, fiber: 3.4 } }, { name: 'Verduras - Espinafre', info: { calories: 16, protein: 2, fat: 0.2, carbs: 2.6, fiber: 2.1 } },
{ name: 'Vegetais - Cenoura (cozida)', info: { calories: 30, protein: 0.8, fat: 0.2, carbs: 6.7, fiber: 2.6 } }, { name: 'Verduras - Rúcula', info: { calories: 13, protein: 1.8, fat: 0.1, carbs: 2.2, fiber: 1.7 } },
{ name: 'Vegetais - Couve flor (cozida)', info: { calories: 19, protein: 1.2, fat: 0.3, carbs: 3.9, fiber: 2.1 } },
{ name: 'Vegetais - Ervilha (cozida)', info: { calories: 88, protein: 7.5, fat: 0.5, carbs: 14.2, fiber: 9.7 } }, { name: 'Legumes - Abóbora Cabotian (crua)', info: { calories: 39, protein: 1.7, fat: 0.5, carbs: 8.4, fiber: 2.2 } },
{ name: 'Vegetais - Espinafre', info: { calories: 16, protein: 2, fat: 0.2, carbs: 2.6, fiber: 2.1 } }, { name: 'Legumes - Abóbora Cabotian (cozida)', info: { calories: 48, protein: 1.4, fat: 0.7, carbs: 10.8, fiber: 2.5 } },
{ name: 'Vegetais - Feijão preto (cozido)', info: { calories: 77, protein: 4.5, fat: 0.5, carbs: 14, fiber: 8.4 } }, { name: 'Legumes - Brócolis (cozido)', info: { calories: 25, protein: 2.1, fat: 0.5, carbs: 4.4, fiber: 3.4 } },
{ name: 'Vegetais - Lentilha (cozida)', info: { calories: 93, protein: 6.3, fat: 0.5, carbs: 16.3, fiber: 7.9 } }, { name: 'Legumes - Cenoura (cozida)', info: { calories: 30, protein: 0.8, fat: 0.2, carbs: 6.7, fiber: 2.6 } },
{ name: 'Vegetais - Mandioca (cozida)', info: { calories: 125, protein: 0.6, fat: 0.3, carbs: 30.1, fiber: 1.6 } }, { name: 'Legumes - Couve flor (cozida)', info: { calories: 19, protein: 1.2, fat: 0.3, carbs: 3.9, fiber: 2.1 } },
{ name: 'Vegetais - Pepino', info: { calories: 10, protein: 0.9, fat: 0, carbs: 2, fiber: 1.1 } }, { name: 'Legumes - Pepino', info: { calories: 10, protein: 0.9, fat: 0, carbs: 2, fiber: 1.1 } },
{ name: 'Vegetais - Rúcula', info: { calories: 13, protein: 1.8, fat: 0.1, carbs: 2.2, fiber: 1.7 } }, { name: 'Legumes - Tomate', info: { calories: 15, protein: 1.1, fat: 0.2, carbs: 3.1, fiber: 1.2 } },
{ name: 'Vegetais - Spirulina', info: { calories: 290, protein: 57.5, fat: 23.9, carbs: 7.7, fiber: 0 } },
{ name: 'Vegetais - Tomate', info: { calories: 15, protein: 1.1, fat: 0.2, carbs: 3.1, fiber: 1.2 } }, { name: 'Algas - Spirulina', info: { calories: 290, protein: 57.5, fat: 23.9, carbs: 7.7, fiber: 0 } },
{ name: 'Carboidratos - Batata doce (assada)', info: { calories: 90, protein: 2.0, fat: 0.1, carbs: 20.7, fiber: 3.3 } }, { name: 'Carboidratos - Batata doce (assada)', info: { calories: 90, protein: 2.0, fat: 0.1, carbs: 20.7, fiber: 3.3 } },
{ name: 'Carboidratos - Batata doce (cozida)', info: { calories: 77, protein: 0.6, fat: 0.1, carbs: 18.4, fiber: 2.2 } }, { name: 'Carboidratos - Batata doce (cozida)', info: { calories: 77, protein: 0.6, fat: 0.1, carbs: 18.4, fiber: 2.2 } },
@@ -32,6 +32,7 @@ export const foodDatabase: FoodItem[] = [
{ name: 'Carboidratos - Batata inglesa (assada)', info: { calories: 94, protein: 2.1, fat: 0.1, carbs: 21.8, fiber: 2.1 } }, { name: 'Carboidratos - Batata inglesa (assada)', info: { calories: 94, protein: 2.1, fat: 0.1, carbs: 21.8, fiber: 2.1 } },
{ name: 'Carboidratos - Batata inglesa (cozida)', info: { calories: 52, protein: 1.2, fat: 0, carbs: 11.9, fiber: 1.3 } }, { name: 'Carboidratos - Batata inglesa (cozida)', info: { calories: 52, protein: 1.2, fat: 0, carbs: 11.9, fiber: 1.3 } },
{ name: 'Carboidratos - Batata inglesa (crua)', info: { calories: 64, protein: 1.8, fat: 0, carbs: 14.7, fiber: 1.2 } }, { name: 'Carboidratos - Batata inglesa (crua)', info: { calories: 64, protein: 1.8, fat: 0, carbs: 14.7, fiber: 1.2 } },
{ name: 'Carboidratos - Mandioca (cozida)', info: { calories: 125, protein: 0.6, fat: 0.3, carbs: 30.1, fiber: 1.6 } },
{ name: 'Carboidratos - Pão Francês', info: { calories: 300, protein: 8, fat: 3.1, carbs: 58.6, fiber: 2.3 } }, { name: 'Carboidratos - Pão Francês', info: { calories: 300, protein: 8, fat: 3.1, carbs: 58.6, fiber: 2.3 } },
{ name: 'Carboidrados - Polenta (cozida)', info: { calories: 192, protein: 4.8, fat: 1.2, carbs: 40, fiber: 3.8 } }, { name: 'Carboidrados - Polenta (cozida)', info: { calories: 192, protein: 4.8, fat: 1.2, carbs: 40, fiber: 3.8 } },
@@ -47,6 +48,9 @@ export const foodDatabase: FoodItem[] = [
{ name: 'Grãos - Arroz integral (cozido)', info: { calories: 130, protein: 2.7, fat: 0.3, carbs: 28, fiber: 0.4 } }, { name: 'Grãos - Arroz integral (cozido)', info: { calories: 130, protein: 2.7, fat: 0.3, carbs: 28, fiber: 0.4 } },
{ name: 'Grãos - Aveia', info: { calories: 394, protein: 13.9, fat: 8.5, carbs: 66.6, fiber: 9.1 } }, { name: 'Grãos - Aveia', info: { calories: 394, protein: 13.9, fat: 8.5, carbs: 66.6, fiber: 9.1 } },
{ name: 'Grãos - Ervilha (cozida)', info: { calories: 88, protein: 7.5, fat: 0.5, carbs: 14.2, fiber: 9.7 } },
{ name: 'Grãos - Feijão preto (cozido)', info: { calories: 77, protein: 4.5, fat: 0.5, carbs: 14, fiber: 8.4 } },
{ name: 'Grãos - Lentilha (cozida)', info: { calories: 93, protein: 6.3, fat: 0.5, carbs: 16.3, fiber: 7.9 } },
{ name: 'Grãos - Grão de Bico (cozido)', info: { calories: 180, protein: 9.5, fat: 3, carbs: 30, fiber: 8.6 } }, { name: 'Grãos - Grão de Bico (cozido)', info: { calories: 180, protein: 9.5, fat: 3, carbs: 30, fiber: 8.6 } },
{ name: 'Grãos - Pão integral de forma', info: { calories: 253, protein: 9.4, fat: 3.7, carbs: 49.9, fiber: 6.9 } }, { name: 'Grãos - Pão integral de forma', info: { calories: 253, protein: 9.4, fat: 3.7, carbs: 49.9, fiber: 6.9 } },
{ name: 'Grãos - Pipoca c/óleo', info: { calories: 448, protein: 9.9, fat: 15.9, carbs: 70.3, fiber: 14.3 } }, { name: 'Grãos - Pipoca c/óleo', info: { calories: 448, protein: 9.9, fat: 15.9, carbs: 70.3, fiber: 14.3 } },
@@ -57,6 +61,7 @@ export const foodDatabase: FoodItem[] = [
{ name: 'Castanhas - Amendoin natural', info: { calories: 611, protein: 26, fat: 49, carbs: 16, fiber: 8.5 } }, { name: 'Castanhas - Amendoin natural', info: { calories: 611, protein: 26, fat: 49, carbs: 16, fiber: 8.5 } },
{ name: 'Castanhas - Castanha de Caju', info: { calories: 570, protein: 18.5, fat: 46.3, carbs: 29.1, fiber: 3.7 } }, { name: 'Castanhas - Castanha de Caju', info: { calories: 570, protein: 18.5, fat: 46.3, carbs: 29.1, fiber: 3.7 } },
{ name: 'Castanhas - Castanha do Pará', info: { calories: 643, protein: 14.5, fat: 63.5, carbs: 15.1, fiber: 7.9 } }, { name: 'Castanhas - Castanha do Pará', info: { calories: 643, protein: 14.5, fat: 63.5, carbs: 15.1, fiber: 7.9 } },
{ name: 'Sementes - Semente de Chia', info: { calories: 490, protein: 15.6, fat: 30.7, carbs: 43.8, fiber: 37.7 } }, { name: 'Sementes - Semente de Chia', info: { calories: 490, protein: 15.6, fat: 30.7, carbs: 43.8, fiber: 37.7 } },
{ name: 'Sementes - Semente de Linhaça', info: { calories: 495, protein: 14.1, fat: 32.3, carbs: 43.3, fiber: 33.5 } }, { name: 'Sementes - Semente de Linhaça', info: { calories: 495, protein: 14.1, fat: 32.3, carbs: 43.3, fiber: 33.5 } },
{ name: 'Sementes - Semente de Gergelim', info: { calories: 584, protein: 21.2, fat: 50.4, carbs: 21.6, fiber: 11.9 } }, { name: 'Sementes - Semente de Gergelim', info: { calories: 584, protein: 21.2, fat: 50.4, carbs: 21.6, fiber: 11.9 } },
@@ -67,5 +72,7 @@ export const foodDatabase: FoodItem[] = [
{ name: 'Lanches - Melado', info: { calories: 297, protein: 0, fat: 0, carbs: 76.6, fiber: 0 } }, { name: 'Lanches - Melado', info: { calories: 297, protein: 0, fat: 0, carbs: 76.6, fiber: 0 } },
{ name: 'Lanches - Pasta de Amendoim Growth', info: { calories: 544, protein: 27, fat: 33, carbs: 20, fiber: 8 } }, { name: 'Lanches - Pasta de Amendoim Growth', info: { calories: 544, protein: 27, fat: 33, carbs: 20, fiber: 8 } },
{ name: 'Lanches - Goma de Tapioca', info: { calories: 226, protein: 0, fat: 0, carbs: 57, fiber: 0 } }, { name: 'Lanches - Goma de Tapioca', info: { calories: 226, protein: 0, fat: 0, carbs: 57, fiber: 0 } },
{ name: 'Lanches - 70% Nibs Garoto', info: { calories: 544, protein: 8.4, fat: 40, carbs: 34, fiber: 0 } } { name: 'Lanches - 70% Nibs Garoto', info: { calories: 544, protein: 8.4, fat: 40, carbs: 34, fiber: 0 } },
{ name: 'Óleos - Azeite de Oliva EV', info: { calories: 844, protein: 0, fat: 100, carbs: 0, fiber: 0 } }
]; ];
+169 -7
View File
@@ -15,6 +15,7 @@ let currentUser: any | null = null;
const authSection = document.getElementById('auth-section'); const authSection = document.getElementById('auth-section');
const userInfo = document.getElementById('user-info'); const userInfo = document.getElementById('user-info');
const appContent = document.getElementById('app-content'); const appContent = document.getElementById('app-content');
const settingsContent = document.getElementById('settings-content');
const loadingOverlay = getDivById('loading-overlay'); const loadingOverlay = getDivById('loading-overlay');
const loginForm = document.getElementById('login-form'); const loginForm = document.getElementById('login-form');
const registerForm = document.getElementById('register-form'); const registerForm = document.getElementById('register-form');
@@ -114,6 +115,77 @@ async function handleLogin(e: SubmitEvent) {
} }
} }
async function processResponseItems<T, R>(
response: T[],
processItem: (item: T) => Promise<R>
): Promise<R[]> {
// Create promises for each item (but don't execute yet)
const promises = response.map(item => processItem(item));
// Execute all promises concurrently and wait for completion
const results = await Promise.all(promises);
return results;
}
// Example usage with API calls
interface ResponseItem {
id: string;
data: string;
}
async function fetchItemDetails(item: ResponseItem): Promise<any> {
const response = await fetch(`/api/items/${item.id}`);
return response.json();
}
// Main function that processes the response
async function handleResponse(response: ResponseItem[]): Promise<void> {
try {
// This creates and executes all promises concurrently
const results = await processResponseItems(response, fetchItemDetails);
console.log('All requests completed:', results);
} catch (error) {
console.error('One or more requests failed:', error);
}
}
async function handleSaveSettings(e: SubmitEvent) {
e.preventDefault();
showLoading();
try {
const proteinGoal = getInputById('proteinGoal').value;
const fatGoal = getInputById('fatGoal').value;
const carboGoal = getInputById('carboGoal').value;
const fiberGoal = getInputById('fiberGoal').value;
// Delete existing settings - keep only the new one
const documents = await AppwriteDB.getUserSettings();
const promises = [];
for (let i=0; i<documents.length; i++) {
// keep going from here, the promises
}
// Save to Appwrite
await AppwriteDB.saveUserSettings({
proteinGoal: parseInt(proteinGoal),
fatGoal: parseInt(fatGoal),
carboGoal: parseInt(carboGoal),
fiberGoal: parseInt(fiberGoal),
});
hideLoading();
handleSettings();
selectDate(selectedDate);
} catch (error) {
hideLoading();
console.error('Saving error:', error);
swal('Oh no!', 'Saving failed: ' + error.message, 'error');
}
}
async function handleLogout() { async function handleLogout() {
showLoading(); showLoading();
@@ -122,11 +194,52 @@ async function handleLogout() {
currentUser = null; currentUser = null;
showAuthForms(); showAuthForms();
clearAppData(); clearAppData();
hideLoading();
} catch (error) { } catch (error) {
hideLoading();
console.error('Logout error:', error); console.error('Logout error:', error);
swal('Oh no!', 'Logout failed: ' + error.message, 'error'); swal('Oh no!', 'Logout failed: ' + error.message, 'error');
} finally { }
hideLoading(); }
async function handleSettings() {
const showSettings = getButtonById('settingsBtn').textContent === 'Settings';
if (showSettings) {
showLoading();
try {
// Fetch goals from settings
const settings = await AppwriteDB.getUserSettings();
const hasGoals = Array.isArray(settings) && settings.length > 0;
if (hasGoals) {
const index = settings.length - 1;
getInputById('proteinGoal').value = settings[index].proteinGoal;
getInputById('fatGoal').value = settings[index].fatGoal;
getInputById('carboGoal').value = settings[index].carboGoal;
getInputById('fiberGoal').value = settings[index].fiberGoal;
} else {
getInputById('proteinGoal').value = '';
getInputById('fatGoal').value = '';
getInputById('carboGoal').value = '';
getInputById('fiberGoal').value = '';
}
getButtonById('settingsBtn').textContent = 'Back to App';
appContent?.classList.add('hidden');
settingsContent?.classList.remove('hidden');
hideLoading();
} catch (error) {
hideLoading();
console.error('Fetching settings failed:', error);
swal('Oh no!', 'Fetching settings failed: ' + error.message, 'error');
}
}
else {
appContent?.classList.remove('hidden');
settingsContent?.classList.add('hidden');
getButtonById('settingsBtn').textContent = 'Settings';
} }
} }
@@ -252,6 +365,8 @@ const setupEventListeners = () => {
document.getElementById('loginForm')?.addEventListener('submit', handleLogin); document.getElementById('loginForm')?.addEventListener('submit', handleLogin);
document.getElementById('registerForm')?.addEventListener('submit', handleRegister); document.getElementById('registerForm')?.addEventListener('submit', handleRegister);
document.getElementById('logoutBtn')?.addEventListener('click', handleLogout); document.getElementById('logoutBtn')?.addEventListener('click', handleLogout);
document.getElementById('settingsBtn')?.addEventListener('click', handleSettings);
document.getElementById('settingsForm')?.addEventListener('submit', handleSaveSettings);
} }
const addDeleteEvents = () => { const addDeleteEvents = () => {
@@ -341,6 +456,22 @@ const addFood = async () => {
// Update totals // Update totals
updateTotalCalories(); updateTotalCalories();
// Update total macros
const proteinDiv: HTMLElement = getDivById('proteinValue');
const fatDiv: HTMLElement = getDivById('fatValue');
const carboDiv: HTMLElement = getDivById('carboValue');
const fiberDiv: HTMLElement = getDivById('fiberValue');
const totalProtein: number = parseInt(proteinDiv.textContent ?? '0') + proportion.info.protein;
const totalFat: number = parseInt(fatDiv.textContent ?? '0') + proportion.info.fat;
const totalCarbs: number = parseInt(carboDiv.textContent ?? '0') + proportion.info.carbs;
const totalFiber: number = parseInt(fiberDiv.textContent ?? '0') + proportion.info.fiber;
proteinDiv.textContent = (Math.round(totalProtein * 10) / 10).toString();
fatDiv.textContent = (Math.round(totalFat * 10) / 10).toString();
carboDiv.textContent = (Math.round(totalCarbs * 10) / 10).toString();
fiberDiv.textContent = (Math.round(totalFiber * 10) / 10).toString();
// Reset form // Reset form
foodSelect.value = ''; foodSelect.value = '';
gramAmount.value = '100'; gramAmount.value = '100';
@@ -408,6 +539,41 @@ async function loadFoodEntries(date: Date) {
getDivById('fatValue').textContent = (Math.round(totalFat * 10) / 10).toString(); getDivById('fatValue').textContent = (Math.round(totalFat * 10) / 10).toString();
getDivById('carboValue').textContent = (Math.round(totalCarbs * 10) / 10).toString(); getDivById('carboValue').textContent = (Math.round(totalCarbs * 10) / 10).toString();
getDivById('fiberValue').textContent = (Math.round(totalFiber * 10) / 10).toString(); getDivById('fiberValue').textContent = (Math.round(totalFiber * 10) / 10).toString();
// Update goals
const settings = await AppwriteDB.getUserSettings();
const hasGoals = Array.isArray(settings) && settings.length > 0;
if (hasGoals) {
const index = settings.length - 1;
getDivById('proteinGoalText').classList.add('hidden');
if (parseInt(settings[index].proteinGoal) > 0) {
getDivById('proteinGoalText').textContent = `of ${settings[index].proteinGoal}`;
getDivById('proteinGoalText').classList.remove('hidden');
}
getDivById('fatGoalText').classList.add('hidden');
if (parseInt(settings[index].fatGoal) > 0) {
getDivById('fatGoalText').textContent = `of ${settings[index].fatGoal}`;
getDivById('fatGoalText').classList.remove('hidden');
}
getDivById('carboGoalText').classList.add('hidden');
if (parseInt(settings[index].carboGoal) > 0) {
getDivById('carboGoalText').textContent = `of ${settings[index].carboGoal}`;
getDivById('carboGoalText').classList.remove('hidden');
}
getDivById('fiberGoalText').classList.add('hidden');
if (parseInt(settings[index].fiberGoal) > 0) {
getDivById('fiberGoalText').textContent = `of ${settings[index].fiberGoal}`;
getDivById('fiberGoalText').classList.remove('hidden');
}
} else {
getDivById('proteinGoalText').classList.add('hidden');
getDivById('fatGoalText').classList.add('hidden');
getDivById('carboGoalText').classList.add('hidden');
getDivById('fiberGoalText').classList.add('hidden');
}
} catch (error) { } catch (error) {
console.error('Load food entries error:', error); console.error('Load food entries error:', error);
swal('Oh no!', 'Failed to load food entries: ' + error.message, 'error'); swal('Oh no!', 'Failed to load food entries: ' + error.message, 'error');
@@ -437,11 +603,7 @@ async function handleDeleteFood(documentId: string, row: HTMLTableRowElement) {
// Delete from Appwrite // Delete from Appwrite
await AppwriteDB.deleteFoodEntry(documentId); await AppwriteDB.deleteFoodEntry(documentId);
// Remove from table selectDate(selectedDate);
row.remove();
// Update totals
updateTotalCalories();
} catch (error) { } catch (error) {
console.error('Delete food error:', error); console.error('Delete food error:', error);
+8
View File
@@ -15,3 +15,11 @@ export type FoodStorage = {
time: string; time: string;
date: string; date: string;
}; };
export type UserSettings = {
id?: string;
proteinGoal: number;
fatGoal: number;
carboGoal: number;
fiberGoal: number;
};