diff options
author | Marius Peter <dev@marius-peter.com> | 2025-09-08 21:21:56 +0200 |
---|---|---|
committer | Marius Peter <dev@marius-peter.com> | 2025-09-08 21:21:56 +0200 |
commit | 7116826b854188604e21e2a613ac6672b6fd81f3 (patch) | |
tree | 33150bf2e04e69b8e1fa7d37901d2643b1955534 /app/views/dashboard/_nutrient_profile_allocator.html.erb | |
parent | 8ba568ae0ebe715b5da453681eb141886f1977a8 (diff) |
Create Target and nutrient target table on dashboard.
Diffstat (limited to 'app/views/dashboard/_nutrient_profile_allocator.html.erb')
-rw-r--r-- | app/views/dashboard/_nutrient_profile_allocator.html.erb | 187 |
1 files changed, 0 insertions, 187 deletions
diff --git a/app/views/dashboard/_nutrient_profile_allocator.html.erb b/app/views/dashboard/_nutrient_profile_allocator.html.erb deleted file mode 100644 index d402ace..0000000 --- a/app/views/dashboard/_nutrient_profile_allocator.html.erb +++ /dev/null @@ -1,187 +0,0 @@ -<%# Props: nutrient_profiles: ActiveRecord::Relation<NutrientProfile> %> -<%# Fallback if controller didn't set @nutrient_profiles yet %> -<% profiles = (local_assigns[:nutrient_profiles] || []).presence || [] %> - -<%# We'll render a form purely for structure (no real submit yet) %> -<%= form_with url: "#", method: :post, local: true, html: { id: "np-mix-form", "data-controller": "np-mix" } do %> - <div class="card shadow"> - <div class="card-body"> - - <div class="d-flex justify-content-between align-items-center mb-2"> - <div class="small text-muted"> - Choisissez des <strong>profils de croissance</strong> et répartissez-les pour totaliser <strong>100%</strong>. - </div> - <div> - Somme : <span id="np-mix-sum" class="badge bg-secondary">0%</span> - </div> - </div> - - <div id="np-mix-rows" class="vstack gap-2"> - <%# Rows are injected by JS from the template below, including defaults %> - </div> - - <div class="mt-3 d-flex gap-2"> - <button type="button" class="btn btn-outline-primary" id="np-mix-add"> - + Ajouter un profil - </button> - - <%# Placeholder "save" button for later backend wiring; disabled until total == 100 %> - <button type="submit" class="btn btn-success ms-auto" id="np-mix-save" disabled> - Enregistrer (à venir) - </button> - </div> - </div> - </div> - - <%# --- Hidden template for a single row --- %> - <template id="np-mix-row-template"> - <div class="np-mix-row d-flex align-items-center gap-2 border rounded p-2"> - <button type="button" class="btn btn-outline-danger btn-sm np-mix-delete" aria-label="Supprimer la ligne"> - Suppr. - </button> - - <div class="flex-grow-1"> - <select name="mix[items][][profile_id]" class="form-select form-select-sm np-mix-select" required> - <% if profiles.any? %> - <% profiles.each do |p| %> - <option value="<%= p.id %>"><%= p.name %></option> - <% end %> - <% else %> - <%# If no collection provided yet, at least show placeholders to demo the UI %> - <option value="">-- Sélectionner un profil --</option> - <option value="gen-croissance">Générique croissance</option> - <option value="tomate-cycle">Tomate (cycle entier)</option> - <option value="gen-floraison">Générique floraison</option> - <% end %> - </select> - </div> - - <div class="input-group input-group-sm" style="max-width: 140px;"> - <input type="number" - name="mix[items][][percentage]" - class="form-control text-end np-mix-percent" - min="0" max="100" step="1" value="0" required> - <span class="input-group-text">%</span> - </div> - </div> - </template> - - <%# --- Defaults to inject on load --- %> - <script type="application/json" id="np-mix-defaults"> - { - "items": [ - { "name": "G\u00E9n\u00E9rique croissance", "percent": 50 }, - { "name": "Tomate (cycle entier)", "percent": 30 }, - { "name": "G\u00E9n\u00E9rique floraison", "percent": 20 } - ] - } - </script> - - <%# --- Tiny inline JS to keep this self-contained (no Stimulus required) --- %> - <script> - (() => { - const rowsContainer = document.getElementById('np-mix-rows'); - const addBtn = document.getElementById('np-mix-add'); - const saveBtn = document.getElementById('np-mix-save'); - const sumBadge = document.getElementById('np-mix-sum'); - const tpl = document.getElementById('np-mix-row-template'); - const defaultsJSON = document.getElementById('np-mix-defaults')?.textContent || "{}"; - const defaults = JSON.parse(defaultsJSON); - - function currentSum() { - return Array.from(rowsContainer.querySelectorAll('.np-mix-percent')) - .reduce((acc, el) => acc + (parseFloat(el.value) || 0), 0); - } - - function refreshSum() { - const sum = currentSum(); - sumBadge.textContent = `${sum}%`; - sumBadge.classList.remove('bg-secondary','bg-danger','bg-success','bg-warning'); - - if (sum === 100) { - sumBadge.classList.add('bg-success'); - saveBtn?.removeAttribute('disabled'); - } else if (sum > 100) { - sumBadge.classList.add('bg-danger'); - saveBtn?.setAttribute('disabled', 'disabled'); - } else { - sumBadge.classList.add('bg-warning'); - saveBtn?.setAttribute('disabled', 'disabled'); - } - } - - function setSelectByName(selectEl, targetName) { - // Try to match by visible name; fall back to first option. - const options = Array.from(selectEl.options); - const found = options.find(o => o.text.trim().toLowerCase() === String(targetName || '').trim().toLowerCase()); - if (found) { - selectEl.value = found.value; - } - } - - function installRow({ name = null, percent = 0 } = {}) { - const node = tpl.content.firstElementChild.cloneNode(true); - - // Hook up events - node.querySelector('.np-mix-delete').addEventListener('click', () => { - node.remove(); - refreshSum(); - }); - - const selectEl = node.querySelector('.np-mix-select'); - const percentEl = node.querySelector('.np-mix-percent'); - - // Default selection (by name) and percent - if (name) setSelectByName(selectEl, name); - percentEl.value = percent; - - // Input events - selectEl.addEventListener('change', () => { /* reserved for later linkage */ }); - percentEl.addEventListener('input', () => { - // Clamp and refresh - let v = parseFloat(percentEl.value); - if (isNaN(v)) v = 0; - v = Math.max(0, Math.min(100, Math.round(v))); - percentEl.value = v; - refreshSum(); - }); - - rowsContainer.appendChild(node); - } - - // Init with three defaults - const items = (defaults && defaults.items) ? defaults.items : []; - if (items.length) { - items.forEach(it => installRow({ name: it.name, percent: it.percent })); - } else { - // Fallback: create three blank rows - for (let i = 0; i < 3; i++) installRow(); - } - refreshSum(); - - // Add new blank row - addBtn.addEventListener('click', () => { - installRow({ name: null, percent: 0 }); - refreshSum(); - // Scroll to the new row on mobile for better UX - rowsContainer.lastElementChild?.scrollIntoView({ behavior: 'smooth', block: 'center' }); - }); - - // Prevent real submit for now (frontend only) - document.getElementById('np-mix-form')?.addEventListener('submit', (e) => { - e.preventDefault(); - // Later: wire to Turbo/JSON post. For now just a gentle nudge. - saveBtn.textContent = 'Enregistrer (backend à venir)'; - saveBtn.blur(); - }); - })(); - </script> - - <style> - /* Small touch targets & tidy spacing on mobile */ - @media (max-width: 576px) { - .np-mix-row { padding: .5rem; } - .np-mix-row .btn { padding: .25rem .5rem; } - } - </style> -<% end %> |