feat: add editing capability

This commit is contained in:
2025-09-04 12:51:43 -03:00
parent 07eba9b64a
commit 261528f329
5 changed files with 150 additions and 13 deletions
+5
View File
@@ -149,6 +149,10 @@
<div class="search-results" id="searchResults">
<!-- Results will be populated here -->
</div>
<!-- Hidden inputs for state -->
<input type="hidden" id="foodIdToUpdate">
<input type="hidden" id="foodTimeToUpdate">
</div>
</div>
<div class="form-group">
@@ -156,6 +160,7 @@
<input type="number" id="gramAmount" min="1" step="1" value="100">
</div>
<button class="add-btn" id="add-food-btn">Add Food</button>
<button class="cancel-btn" id="cancel-food-btn">Cancel</button>
</div>
<div class="display-none" id="food-preview">
<div class="nutrition-summary">
+20
View File
@@ -98,6 +98,26 @@ export class AppwriteDB {
}
}
// Upadte food entry
static async updateFoodEntry(documentId: string, entryData: Partial<FoodStorage>) {
try {
const response = await databases.updateDocument(
DATABASE_ID,
FOOD_ENTRIES_COLLECTION_ID,
documentId,
{
...entryData,
userId: (await account.get()).$id,
}
);
console.debug('Food entry updated:', response);
return response;
} catch (error) {
console.error('Update food entry error:', error);
throw error;
}
}
// Save food entry
static async saveUserSettings(userSettings: UserSettings) {
try {
+3 -3
View File
@@ -88,6 +88,7 @@ export const foodDatabase: FoodItem[] = [
{ name: 'Melão', info: { calories: 29, protein: 0.7, fat: 0, carbs: 7.5, fiber: 0.3, category: 'fruits', alkaline: true } },
{ name: 'Uva', info: { calories: 53, protein: 0.7, fat: 0.2, carbs: 13.6, fiber: 0.9, category: 'fruits', alkaline: true } },
{ name: 'Goiaba, branca, com casca, crua', info: { calories: 52, protein: 0.9, fat: 0.5, carbs: 12.4, fiber: 6.3, category: 'fruits', alkaline: true } },
{ name: 'Morango, cru', info: { calories: 30, protein: 0.9, fat: 0.3, carbs: 6.8, fiber: 1.7, category: 'fruits', alkaline: true } },
// Dairy
{ name: 'Iogurte, natural, desnatado', info: { calories: 41, protein: 3.8, fat: 0.3, carbs: 5.8, fiber: 0, category: 'dairy', alkaline: true } },
@@ -117,7 +118,6 @@ export const foodDatabase: FoodItem[] = [
{ name: 'Couve flor, cozida', info: { calories: 19, protein: 1.2, fat: 0.3, carbs: 3.9, fiber: 2.1, category: 'carbs (low)', alkaline: true } },
{ name: 'Pepino', info: { calories: 10, protein: 0.9, fat: 0, carbs: 2, fiber: 1.1, category: 'carbs (low)', alkaline: true } },
{ name: 'Chuchu, cozido', info: { calories: 19, protein: 0.4, fat: 0, carbs: 4.9, fiber: 1.0, category: 'carbs (low)', alkaline: true } },
{ name: 'Cogumelo Paris, in natura', info: { calories: 17, protein: 4.9, fat: 0, carbs: 1, fiber: 1.7, category: 'proteins', alkaline: true } },
{ name: 'Milho, verde, enlatado, drenado', info: { calories: 98, protein: 3.2, fat: 2.4, carbs: 17.1, fiber: 4.6, category: 'proteins', alkaline: true } },
{ name: 'Morango, cru', info: { calories: 30, protein: 0.9, fat: 0.3, carbs: 6.8, fiber: 1.7, category: 'proteins', alkaline: true } },
{ name: 'Cogumelo Paris, in natura', info: { calories: 17, protein: 4.9, fat: 0, carbs: 1, fiber: 1.7, category: 'carbs (low)', alkaline: true } },
{ name: 'Milho, verde, enlatado, drenado', info: { calories: 98, protein: 3.2, fat: 2.4, carbs: 17.1, fiber: 4.6, category: 'carbs (low)', alkaline: true } },
];
+103 -9
View File
@@ -285,6 +285,14 @@ function hideLoading() {
loadingOverlay.classList.add('hidden');
}
function clearEditing() {
searchInput.value = '';
getInputById('gramAmount').value = '100';
showFoodPreview(false);
getButtonById('add-food-btn').innerHTML = 'Add Food';
selectedFood = null;
}
// Clear application data
function clearAppData() {
getDivById('caloriesCounter').textContent = '0';
@@ -301,6 +309,7 @@ function clearAppData() {
totalCaloriesToday = 0;
totalGramsToday = 0;
totalAlkalineToday = 0;
getButtonById('cancel-food-btn').style.display = 'none';
}
const getFoodData = (grams: number, foodData: FoodItem): FoodItem => {
@@ -322,7 +331,7 @@ const getFoodData = (grams: number, foodData: FoodItem): FoodItem => {
const getFoodItemByName = (foodName: string): FoodItem => {
const foodDataSearch: FoodItem[] = foodDatabase.filter(f => f.name === foodName);
if (foodDataSearch.length === 0) {
throw new Error(`Food not found for name ${name}`);
throw new Error(`Food not found for name ${foodName}`);
}
return foodDataSearch[0];
}
@@ -366,7 +375,11 @@ const setupEventListeners = () => {
});
getButtonById('add-food-btn').addEventListener('click', () => {
addFood();
if (getButtonById('add-food-btn').innerHTML === 'Add Food') {
addFood();
} else {
updateFood();
}
});
getButtonById('next-month-btn').addEventListener('click', () => {
@@ -388,6 +401,10 @@ const setupEventListeners = () => {
toggleAuthForms();
});
getButtonById('cancel-food-btn').addEventListener('click', () => {
clearEditing();
});
// Auth forms
document.getElementById('loginForm')?.addEventListener('submit', handleLogin);
document.getElementById('registerForm')?.addEventListener('submit', handleRegister);
@@ -545,6 +562,38 @@ function selectFood(food: FoodItem) {
previewCalories(food);
}
async function setFoodToEdit(foodId: string) {
showLoading();
try {
// get food item
const entries = await AppwriteDB.getFoodEntries(selectedDate);
const foodToEdit = entries.filter(entry => entry.$id === foodId);
if (foodToEdit.length === 0) {
swal('Hey!', 'Unable to get food entry from server', 'error');
return;
}
// set the selected food name and quantity
const foodData: FoodItem = getFoodItemByName(foodToEdit[0].name);
selectedFood = foodData;
searchInput.value = foodToEdit[0].name;
getInputById('gramAmount').value = foodToEdit[0].grams;
previewCalories(foodData)
getButtonById('add-food-btn').innerHTML = 'Save Food';
getInputById('foodIdToUpdate').value = foodId;
getInputById('foodTimeToUpdate').value = foodToEdit[0].time;
hideLoading();
} catch (error) {
console.error('Set food to edit error:', error);
swal('Oh no!', 'Failed to load food entry: ' + error.message, 'error');
} finally {
hideLoading();
}
}
// Hide search results
function hideSearchResults() {
searchResults.classList.remove('show');
@@ -584,9 +633,7 @@ function editCardHandler(e: Event) {
const foodId = card.getAttribute('data-food-id');
if (foodId) {
// FIXME: Implement edit functionality
// handleEditFood(foodId);
window.alert('Edit functionality is not implemented yet.');
setFoodToEdit(foodId);
}
}
@@ -624,6 +671,56 @@ const updateCurrentDate = () => {
});
}
const updateFood = async () => {
if (!currentUser) {
swal('Hey!', 'Please log in to add food entries.', 'info');
return;
}
const gramAmount = getInputById('gramAmount');
if (!selectedFood || !gramAmount.value) {
swal('Hey!', 'Please select a food item and enter the amount', 'error');
return;
}
showLoading();
try {
const foodId = getInputById('foodIdToUpdate').value;
const grams: number = parseFloat(gramAmount.value);
const foodData: FoodItem = getFoodItemByName(selectedFood.name);
// Current date, with timezone
const date = new Date(selectedDate.getTime() - (selectedDate.getTimezoneOffset() * 60000)).toISOString();
// Calculate nutrition for the amount
const proportion: FoodItem = getFoodData(grams, foodData);
const entry: FoodStorage = {
name: selectedFood.name,
grams: grams,
calories: proportion.info.calories,
protein: proportion.info.protein,
fat: proportion.info.fat,
carbs: proportion.info.carbs,
fiber: proportion.info.fiber,
date: date.split('T')[0],
alkaline: selectedFood.info.alkaline,
time: getInputById('foodTimeToUpdate').value,
};
// Save to Appwrite
await AppwriteDB.updateFoodEntry(foodId, entry);
clearEditing();
selectDate(selectedDate);
} catch (error) {
console.error('Update food error:', error);
swal('Oh no!', 'Failed to update food entry: ' + error.message, 'error');
} finally {
hideLoading();
}
}
// Add food to the log
const addFood = async () => {
if (!currentUser) {
@@ -634,7 +731,7 @@ const addFood = async () => {
const gramAmount = getInputById('gramAmount');
if (!selectedFood || !gramAmount.value) {
swal('Hey!', 'Please select a food item and enter amount', 'error');
swal('Hey!', 'Please select a food item and enter the amount', 'error');
return;
}
@@ -1090,6 +1187,3 @@ function editFood(id: string) {
}
(window as any).selectFood = selectFood;
(window as any).toggleCard = toggleCard;
(window as any).editFood = editFood;
(window as any).deleteFood = deleteFood;
+19 -1
View File
@@ -402,7 +402,7 @@ h1 {
.add-food-form {
display: grid;
grid-template-columns: 2fr 1fr auto;
grid-template-columns: 2fr 1fr 1fr auto;
gap: 15px;
align-items: end;
}
@@ -467,6 +467,24 @@ label {
box-shadow: 0 5px 15px rgba(76, 175, 80, 0.3);
}
.cancel-btn {
padding: 17px 25px;
background: linear-gradient(135deg, #757575, #616161);
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 1rem;
font-weight: 600;
transition: all 0.3s ease;
height: fit-content;
}
.cancel-btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(76, 175, 80, 0.3);
}
.food-table-section {
background: white;
border-radius: 6px;