feat: add editing capability
This commit is contained in:
@@ -149,6 +149,10 @@
|
|||||||
<div class="search-results" id="searchResults">
|
<div class="search-results" id="searchResults">
|
||||||
<!-- Results will be populated here -->
|
<!-- Results will be populated here -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Hidden inputs for state -->
|
||||||
|
<input type="hidden" id="foodIdToUpdate">
|
||||||
|
<input type="hidden" id="foodTimeToUpdate">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -156,6 +160,7 @@
|
|||||||
<input type="number" id="gramAmount" min="1" step="1" value="100">
|
<input type="number" id="gramAmount" min="1" step="1" value="100">
|
||||||
</div>
|
</div>
|
||||||
<button class="add-btn" id="add-food-btn">Add Food</button>
|
<button class="add-btn" id="add-food-btn">Add Food</button>
|
||||||
|
<button class="cancel-btn" id="cancel-food-btn">Cancel</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="display-none" id="food-preview">
|
<div class="display-none" id="food-preview">
|
||||||
<div class="nutrition-summary">
|
<div class="nutrition-summary">
|
||||||
|
|||||||
@@ -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
|
// Save food entry
|
||||||
static async saveUserSettings(userSettings: UserSettings) {
|
static async saveUserSettings(userSettings: UserSettings) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
+3
-3
@@ -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: '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: '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: '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
|
// Dairy
|
||||||
{ name: 'Iogurte, natural, desnatado', info: { calories: 41, protein: 3.8, fat: 0.3, carbs: 5.8, fiber: 0, category: 'dairy', alkaline: true } },
|
{ 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: '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: '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: '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: '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: 'proteins', 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 } },
|
||||||
{ name: 'Morango, cru', info: { calories: 30, protein: 0.9, fat: 0.3, carbs: 6.8, fiber: 1.7, category: 'proteins', alkaline: true } },
|
|
||||||
];
|
];
|
||||||
|
|||||||
+103
-9
@@ -285,6 +285,14 @@ function hideLoading() {
|
|||||||
loadingOverlay.classList.add('hidden');
|
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
|
// Clear application data
|
||||||
function clearAppData() {
|
function clearAppData() {
|
||||||
getDivById('caloriesCounter').textContent = '0';
|
getDivById('caloriesCounter').textContent = '0';
|
||||||
@@ -301,6 +309,7 @@ function clearAppData() {
|
|||||||
totalCaloriesToday = 0;
|
totalCaloriesToday = 0;
|
||||||
totalGramsToday = 0;
|
totalGramsToday = 0;
|
||||||
totalAlkalineToday = 0;
|
totalAlkalineToday = 0;
|
||||||
|
getButtonById('cancel-food-btn').style.display = 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
const getFoodData = (grams: number, foodData: FoodItem): FoodItem => {
|
const getFoodData = (grams: number, foodData: FoodItem): FoodItem => {
|
||||||
@@ -322,7 +331,7 @@ const getFoodData = (grams: number, foodData: FoodItem): FoodItem => {
|
|||||||
const getFoodItemByName = (foodName: string): FoodItem => {
|
const getFoodItemByName = (foodName: string): FoodItem => {
|
||||||
const foodDataSearch: FoodItem[] = foodDatabase.filter(f => f.name === foodName);
|
const foodDataSearch: FoodItem[] = foodDatabase.filter(f => f.name === foodName);
|
||||||
if (foodDataSearch.length === 0) {
|
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];
|
return foodDataSearch[0];
|
||||||
}
|
}
|
||||||
@@ -366,7 +375,11 @@ const setupEventListeners = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
getButtonById('add-food-btn').addEventListener('click', () => {
|
getButtonById('add-food-btn').addEventListener('click', () => {
|
||||||
addFood();
|
if (getButtonById('add-food-btn').innerHTML === 'Add Food') {
|
||||||
|
addFood();
|
||||||
|
} else {
|
||||||
|
updateFood();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
getButtonById('next-month-btn').addEventListener('click', () => {
|
getButtonById('next-month-btn').addEventListener('click', () => {
|
||||||
@@ -388,6 +401,10 @@ const setupEventListeners = () => {
|
|||||||
toggleAuthForms();
|
toggleAuthForms();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
getButtonById('cancel-food-btn').addEventListener('click', () => {
|
||||||
|
clearEditing();
|
||||||
|
});
|
||||||
|
|
||||||
// Auth forms
|
// Auth forms
|
||||||
document.getElementById('loginForm')?.addEventListener('submit', handleLogin);
|
document.getElementById('loginForm')?.addEventListener('submit', handleLogin);
|
||||||
document.getElementById('registerForm')?.addEventListener('submit', handleRegister);
|
document.getElementById('registerForm')?.addEventListener('submit', handleRegister);
|
||||||
@@ -545,6 +562,38 @@ function selectFood(food: FoodItem) {
|
|||||||
previewCalories(food);
|
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
|
// Hide search results
|
||||||
function hideSearchResults() {
|
function hideSearchResults() {
|
||||||
searchResults.classList.remove('show');
|
searchResults.classList.remove('show');
|
||||||
@@ -584,9 +633,7 @@ function editCardHandler(e: Event) {
|
|||||||
const foodId = card.getAttribute('data-food-id');
|
const foodId = card.getAttribute('data-food-id');
|
||||||
|
|
||||||
if (foodId) {
|
if (foodId) {
|
||||||
// FIXME: Implement edit functionality
|
setFoodToEdit(foodId);
|
||||||
// handleEditFood(foodId);
|
|
||||||
window.alert('Edit functionality is not implemented yet.');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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
|
// Add food to the log
|
||||||
const addFood = async () => {
|
const addFood = async () => {
|
||||||
if (!currentUser) {
|
if (!currentUser) {
|
||||||
@@ -634,7 +731,7 @@ const addFood = async () => {
|
|||||||
const gramAmount = getInputById('gramAmount');
|
const gramAmount = getInputById('gramAmount');
|
||||||
|
|
||||||
if (!selectedFood || !gramAmount.value) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1090,6 +1187,3 @@ function editFood(id: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
(window as any).selectFood = selectFood;
|
(window as any).selectFood = selectFood;
|
||||||
(window as any).toggleCard = toggleCard;
|
|
||||||
(window as any).editFood = editFood;
|
|
||||||
(window as any).deleteFood = deleteFood;
|
|
||||||
|
|||||||
@@ -402,7 +402,7 @@ h1 {
|
|||||||
|
|
||||||
.add-food-form {
|
.add-food-form {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 2fr 1fr auto;
|
grid-template-columns: 2fr 1fr 1fr auto;
|
||||||
gap: 15px;
|
gap: 15px;
|
||||||
align-items: end;
|
align-items: end;
|
||||||
}
|
}
|
||||||
@@ -467,6 +467,24 @@ label {
|
|||||||
box-shadow: 0 5px 15px rgba(76, 175, 80, 0.3);
|
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 {
|
.food-table-section {
|
||||||
background: white;
|
background: white;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
|
|||||||
Reference in New Issue
Block a user