Bläddra i källkod

Task #61: Implement Edit and Delete meal functionality with UI updates

FerRo988 4 dagar sedan
förälder
incheckning
29274037e5
2 ändrade filer med 266 tillägg och 0 borttagningar
  1. 65 0
      static/script.js
  2. 201 0
      static/style.css

+ 65 - 0
static/script.js

@@ -1044,11 +1044,76 @@ document.addEventListener('DOMContentLoaded', () => {
                         <span class="card-macro-lbl">Fat</span>
                     </div>
                 </div>
+                <div class="meal-card-actions">
+                    <button class="edit-meal-btn" data-id="${meal.id}" data-name="${meal.name}" title="Rename Meal">
+                        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"></path><path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"></path></svg>
+                    </button>
+                    <button class="delete-meal-btn" data-id="${meal.id}" title="Delete Meal">
+                        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"></path></svg>
+                    </button>
+                </div>
             `;
+
+            // Attach listeners to new buttons
+            card.querySelector('.edit-meal-btn').addEventListener('click', (e) => {
+                e.stopPropagation();
+                const newName = prompt('Enter new name for this meal:', meal.name);
+                if (newName && newName.trim() && newName !== meal.name) {
+                    renameMeal(meal.id, newName.trim());
+                }
+            });
+
+            card.querySelector('.delete-meal-btn').addEventListener('click', (e) => {
+                e.stopPropagation();
+                if (confirm(`Are you sure you want to delete "${meal.name}"?`)) {
+                    deleteMeal(meal.id);
+                }
+            });
+
             dashboardGrid.appendChild(card);
         });
     }
 
+    async function renameMeal(id, newName) {
+        try {
+            const token = localStorage.getItem('localFoodToken');
+            const response = await fetch(`/api/meals/${id}`, {
+                method: 'PUT',
+                headers: {
+                    'Content-Type': 'application/json',
+                    'Authorization': `Bearer ${token}`
+                },
+                body: JSON.stringify({ name: newName })
+            });
+
+            if (response.ok) {
+                loadSavedMeals(); // Refresh
+            } else {
+                alert('Failed to rename meal.');
+            }
+        } catch (err) {
+            console.error('Rename error:', err);
+        }
+    }
+
+    async function deleteMeal(id) {
+        try {
+            const token = localStorage.getItem('localFoodToken');
+            const response = await fetch(`/api/meals/${id}`, {
+                method: 'DELETE',
+                headers: { 'Authorization': `Bearer ${token}` }
+            });
+
+            if (response.ok) {
+                loadSavedMeals(); // Refresh
+            } else {
+                alert('Failed to delete meal.');
+            }
+        } catch (err) {
+            console.error('Delete error:', err);
+        }
+    }
+
     // Attach refresh helper
     window.refreshDashboard = loadSavedMeals;
 });

+ 201 - 0
static/style.css

@@ -1269,3 +1269,204 @@ textarea::placeholder {
     background: rgba(255, 255, 255, 0.05);
     border-color: var(--text-muted);
 }
+
+/* --- Dashboard Overlay --- */
+.dashboard-overlay {
+    position: absolute;
+    top: 0; left: 0; right: 0; bottom: 0;
+    background: rgba(13, 17, 23, 0.95);
+    backdrop-filter: blur(20px);
+    -webkit-backdrop-filter: blur(20px);
+    z-index: 50;
+    display: flex;
+    flex-direction: column;
+    animation: fadeIn 0.3s ease;
+}
+
+.dashboard-content {
+    height: 100%;
+    display: flex;
+    flex-direction: column;
+}
+
+.dashboard-header {
+    padding: 24px;
+    border-bottom: 1px solid var(--border-color);
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+}
+
+.dashboard-title-group {
+    display: flex;
+    align-items: center;
+    gap: 12px;
+}
+
+.dashboard-title-group h2 {
+    font-size: 1.25rem;
+    color: #f0f6fc;
+}
+
+.dashboard-body {
+    flex: 1;
+    overflow-y: auto;
+    padding: 24px;
+}
+
+.dashboard-grid {
+    display: grid;
+    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
+    gap: 20px;
+}
+
+.empty-meal-msg {
+    grid-column: 1 / -1;
+    text-align: center;
+    padding: 60px 20px;
+    color: var(--text-muted);
+    font-size: 1.1rem;
+    border: 2px dashed var(--border-color);
+    border-radius: 20px;
+}
+
+/* --- Meal Cards (#59) --- */
+@keyframes cardSlideIn {
+    from { opacity: 0; transform: translateY(20px); }
+    to   { opacity: 1; transform: translateY(0); }
+}
+
+.meal-card {
+    background: rgba(22, 27, 34, 0.6);
+    border: 1px solid rgba(48, 54, 61, 0.8);
+    border-radius: 18px;
+    padding: 20px;
+    display: flex;
+    flex-direction: column;
+    gap: 16px;
+    backdrop-filter: blur(12px);
+    -webkit-backdrop-filter: blur(12px);
+    transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1),
+                border-color 0.3s ease,
+                box-shadow 0.3s ease;
+    animation: cardSlideIn 0.4s ease both;
+    cursor: default;
+}
+
+.meal-card:hover {
+    transform: translateY(-6px);
+    border-color: rgba(88, 166, 255, 0.4);
+    box-shadow: 0 20px 40px -12px rgba(0, 0, 0, 0.5),
+                0 0 0 1px rgba(88, 166, 255, 0.1);
+}
+
+.meal-card-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: flex-start;
+    gap: 10px;
+}
+
+.meal-card-name {
+    font-size: 1.05rem;
+    font-weight: 700;
+    color: #f0f6fc;
+    line-height: 1.3;
+    flex: 1;
+}
+
+.meal-card-date {
+    font-size: 0.72rem;
+    color: var(--text-muted);
+    white-space: nowrap;
+    padding-top: 3px;
+}
+
+.meal-card-macros {
+    display: grid;
+    grid-template-columns: repeat(2, 1fr);
+    gap: 8px;
+}
+
+.card-macro {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    padding: 10px 8px;
+    border-radius: 12px;
+    border: 1px solid transparent;
+    gap: 2px;
+}
+
+.card-macro-val {
+    font-size: 1.1rem;
+    font-weight: 700;
+    line-height: 1;
+}
+
+.card-macro-lbl {
+    font-size: 0.65rem;
+    font-weight: 500;
+    text-transform: uppercase;
+    letter-spacing: 0.05em;
+    opacity: 0.8;
+}
+
+/* Color-coded macro badges */
+.card-macro.kcal {
+    background: rgba(251, 146, 60, 0.12);
+    border-color: rgba(251, 146, 60, 0.25);
+    color: #fb923c;
+}
+.card-macro.protein {
+    background: rgba(59, 130, 246, 0.12);
+    border-color: rgba(59, 130, 246, 0.25);
+    color: #60a5fa;
+}
+.card-macro.carbs {
+    background: rgba(34, 197, 94, 0.12);
+    border-color: rgba(34, 197, 94, 0.25);
+    color: #4ade80;
+}
+.card-macro.fat {
+    background: rgba(168, 85, 247, 0.12);
+    border-color: rgba(168, 85, 247, 0.25);
+    color: #c084fc;
+}
+
+/* --- Meal Card Actions (#61) --- */
+.meal-card-actions {
+    display: flex;
+    justify-content: flex-end;
+    gap: 10px;
+    margin-top: auto;
+    padding-top: 10px;
+    border-top: 1px solid rgba(255, 255, 255, 0.05);
+}
+
+.edit-meal-btn, .delete-meal-btn {
+    background: rgba(255, 255, 255, 0.05);
+    border: 1px solid rgba(255, 255, 255, 0.1);
+    color: var(--text-muted);
+    width: 32px;
+    height: 32px;
+    border-radius: 8px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    cursor: pointer;
+    transition: all 0.2s;
+}
+
+.edit-meal-btn:hover {
+    background: rgba(59, 130, 246, 0.15);
+    border-color: rgba(59, 130, 246, 0.3);
+    color: #60a5fa;
+}
+
+.delete-meal-btn:hover {
+    background: rgba(239, 68, 68, 0.15);
+    border-color: rgba(239, 68, 68, 0.3);
+    color: #f87171;
+}