feat: add settings
This commit is contained in:
@@ -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
@@ -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>
|
||||||
|
|||||||
@@ -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
@@ -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 {
|
||||||
|
|||||||
+22
-15
@@ -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 } },
|
||||||
|
|
||||||
@@ -44,9 +45,12 @@ export const foodDatabase: FoodItem[] = [
|
|||||||
{ name: 'Proteínas - Soja em Pó Growth', info: { calories: 400, protein: 86.7, fat: 5, carbs: 3.3, fiber: 0 } },
|
{ name: 'Proteínas - Soja em Pó Growth', info: { calories: 400, protein: 86.7, fat: 5, carbs: 3.3, fiber: 0 } },
|
||||||
{ name: 'Proteínas - Sobrecoxa s/pele (cozida)', info: { calories: 245, protein: 24.9, fat: 15.4, carbs: 0, fiber: 0 } },
|
{ name: 'Proteínas - Sobrecoxa s/pele (cozida)', info: { calories: 245, protein: 24.9, fat: 15.4, carbs: 0, fiber: 0 } },
|
||||||
{ name: 'Proteínas - Tofu', info: { calories: 65, protein: 6.5, fat: 4, carbs: 2, fiber: 0.75 } },
|
{ name: 'Proteínas - Tofu', info: { calories: 65, protein: 6.5, fat: 4, carbs: 2, fiber: 0.75 } },
|
||||||
|
|
||||||
{ 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 } }
|
||||||
];
|
];
|
||||||
|
|||||||
+170
-8
@@ -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';
|
||||||
@@ -407,7 +538,42 @@ async function loadFoodEntries(date: Date) {
|
|||||||
getDivById('proteinValue').textContent = (Math.round(totalProtein * 10) / 10).toString();
|
getDivById('proteinValue').textContent = (Math.round(totalProtein * 10) / 10).toString();
|
||||||
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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user