|
@@ -479,9 +479,17 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
<div class="macro-tag">Fat: <span>${item.fat_g}g</span></div>
|
|
<div class="macro-tag">Fat: <span>${item.fat_g}g</span></div>
|
|
|
<div class="macro-tag">Carb: <span>${item.carbs_g}g</span></div>
|
|
<div class="macro-tag">Carb: <span>${item.carbs_g}g</span></div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <div class="food-item-footer">
|
|
|
|
|
+ <button class="details-btn" data-id="${item.id}">📊 Details</button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="details-panel" id="details-${item.id}">
|
|
|
|
|
+ <!-- Populated on demand -->
|
|
|
|
|
+ </div>
|
|
|
`;
|
|
`;
|
|
|
|
|
|
|
|
- foodEl.addEventListener('click', () => {
|
|
|
|
|
|
|
+ // Click on the header/name area auto-fills the chat
|
|
|
|
|
+ foodEl.querySelector('.food-item-header').addEventListener('click', (e) => {
|
|
|
|
|
+ e.stopPropagation();
|
|
|
userInput.value = `Can you build a meal around ${item.name} (${item.calories} cal, ${item.protein_g}g protein)?`;
|
|
userInput.value = `Can you build a meal around ${item.name} (${item.calories} cal, ${item.protein_g}g protein)?`;
|
|
|
userInput.focus();
|
|
userInput.focus();
|
|
|
userInput.style.height = 'auto'; // Reset
|
|
userInput.style.height = 'auto'; // Reset
|
|
@@ -490,6 +498,13 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
searchInput.value = '';
|
|
searchInput.value = '';
|
|
|
clearSearchBtn.style.display = 'none';
|
|
clearSearchBtn.style.display = 'none';
|
|
|
});
|
|
});
|
|
|
|
|
+
|
|
|
|
|
+ // Click on the details button toggles the panel
|
|
|
|
|
+ foodEl.querySelector('.details-btn').addEventListener('click', (e) => {
|
|
|
|
|
+ e.stopPropagation();
|
|
|
|
|
+ const panel = document.getElementById(`details-${item.id}`);
|
|
|
|
|
+ toggleFoodDetails(item.id, panel, e.target);
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
searchDropdown.appendChild(foodEl);
|
|
searchDropdown.appendChild(foodEl);
|
|
|
});
|
|
});
|
|
@@ -502,6 +517,70 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+ const toggleFoodDetails = async (foodId, panel, btn) => {
|
|
|
|
|
+ const isExpanded = panel.classList.contains('expanded');
|
|
|
|
|
+
|
|
|
|
|
+ if (isExpanded) {
|
|
|
|
|
+ panel.classList.remove('expanded');
|
|
|
|
|
+ btn.textContent = '📊 Details';
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // If not loaded yet, fetch from API
|
|
|
|
|
+ if (panel.innerHTML.trim() === '') {
|
|
|
|
|
+ panel.innerHTML = '<div class="search-loading">Loading details...</div>';
|
|
|
|
|
+ panel.classList.add('expanded'); // Show loading state
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const token = localStorage.getItem('localFoodToken');
|
|
|
|
|
+ const response = await fetch(`/api/food/${foodId}`, {
|
|
|
|
|
+ headers: { 'Authorization': `Bearer ${token}` }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ if (!response.ok) throw new Error("Failed to fetch details");
|
|
|
|
|
+
|
|
|
|
|
+ const data = await response.json();
|
|
|
|
|
+ renderFoodDetails(panel, data);
|
|
|
|
|
+ } catch (err) {
|
|
|
|
|
+ console.error(err);
|
|
|
|
|
+ panel.innerHTML = '<div class="search-empty">Error loading details.</div>';
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ panel.classList.add('expanded');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ btn.textContent = '✖ Close';
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const renderFoodDetails = (panel, data) => {
|
|
|
|
|
+ panel.innerHTML = `
|
|
|
|
|
+ <div class="nutrient-section">
|
|
|
|
|
+ <div class="nutrient-section-title">Extended Nutrition</div>
|
|
|
|
|
+ <div class="nutrient-grid">
|
|
|
|
|
+ <div class="nutrient-item"><span class="nutrient-label">Fiber</span><span class="nutrient-value">${data.extended.fiber_g}g</span></div>
|
|
|
|
|
+ <div class="nutrient-item"><span class="nutrient-label">Sugar</span><span class="nutrient-value">${data.extended.sugar_g}g</span></div>
|
|
|
|
|
+ <div class="nutrient-item"><span class="nutrient-label">Cholesterol</span><span class="nutrient-value">${data.extended.cholesterol_mg}mg</span></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="nutrient-section">
|
|
|
|
|
+ <div class="nutrient-section-title">Vitamins</div>
|
|
|
|
|
+ <div class="nutrient-grid">
|
|
|
|
|
+ <div class="nutrient-item"><span class="nutrient-label">Vitamin A</span><span class="nutrient-value">${data.vitamins.vitamin_a_iu}IU</span></div>
|
|
|
|
|
+ <div class="nutrient-item"><span class="nutrient-label">Vitamin C</span><span class="nutrient-value">${data.vitamins.vitamin_c_mg}mg</span></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="nutrient-section">
|
|
|
|
|
+ <div class="nutrient-section-title">Minerals</div>
|
|
|
|
|
+ <div class="nutrient-grid">
|
|
|
|
|
+ <div class="nutrient-item"><span class="nutrient-label">Calcium</span><span class="nutrient-value">${data.minerals.calcium_mg}mg</span></div>
|
|
|
|
|
+ <div class="nutrient-item"><span class="nutrient-label">Iron</span><span class="nutrient-value">${data.minerals.iron_mg}mg</span></div>
|
|
|
|
|
+ <div class="nutrient-item"><span class="nutrient-label">Potassium</span><span class="nutrient-value">${data.minerals.potassium_mg}mg</span></div>
|
|
|
|
|
+ <div class="nutrient-item"><span class="nutrient-label">Sodium</span><span class="nutrient-value">${data.minerals.sodium_mg}mg</span></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ `;
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
const handleSearchInput = debounce((e) => {
|
|
const handleSearchInput = debounce((e) => {
|
|
|
const query = e.target.value.trim();
|
|
const query = e.target.value.trim();
|
|
|
if (query.length > 0) {
|
|
if (query.length > 0) {
|