diff options
Diffstat (limited to 'app/views/recipes')
-rw-r--r-- | app/views/recipes/_table.html.erb | 32 | ||||
-rw-r--r-- | app/views/recipes/show.html.erb | 108 |
2 files changed, 140 insertions, 0 deletions
diff --git a/app/views/recipes/_table.html.erb b/app/views/recipes/_table.html.erb new file mode 100644 index 0000000..a42a0b9 --- /dev/null +++ b/app/views/recipes/_table.html.erb @@ -0,0 +1,32 @@ +<div class="table-responsive"> + <table class="table table-sm align-middle mb-0"> + <thead class="table-light"> + <tr> + <th>Fertilizer product</th> + <th class="text-muted">Component</th> + <th class="text-end">Qty (kg)</th> + <th class="text-end">Per portion (kg)</th> + </tr> + </thead> + <tbody> + <% pcount = [[portions.to_i, 2].max, 10].min %> + <% recipe&.each do |component, kg| %> + <% prod_name = commercial_name_for(component) %> + <tr> + <td><strong><%= prod_name %></strong></td> + <td class="text-muted"><small><%= component.name %></small></td> + <td class="text-end fw-semibold"><%= fmt_kg(kg) %></td> + <td class="text-end"><%= fmt_kg(kg / pcount.to_f) %></td> + </tr> + <% end %> + <% if recipe.blank? %> + <tr><td colspan="4" class="text-center text-muted">No supplementation required.</td></tr> + <% end %> + </tbody> + </table> +</div> + +<div class="card-footer small text-muted"> + Volume: <%= number_with_delimiter(volume) %> L — + Portions: <%= pcount %> +</div> diff --git a/app/views/recipes/show.html.erb b/app/views/recipes/show.html.erb new file mode 100644 index 0000000..180fdae --- /dev/null +++ b/app/views/recipes/show.html.erb @@ -0,0 +1,108 @@ +<!-- app/views/recipes/show.html.erb --> +<%# Controls header %> +<div class="card shadow my-4"> + <div class="card-header d-flex flex-wrap gap-2 justify-content-between align-items-center"> + <h5 class="mb-0">Ferti© Recipe</h5> + + <div class="d-flex flex-wrap gap-2 align-items-center"> + <%= form_with url: ferti_recipe_path, method: :get, local: true, class: "d-flex flex-wrap gap-2 align-items-center", id: "recipe-form" do %> + <div class="d-flex align-items-center gap-2"> + <label class="mb-0 small text-nowrap" for="volume_select">Volume</label> + <select id="volume_select" name="volume" class="form-select form-select-sm"> + <% options = [["100 000 L", 100_000], ["200 000 L", 200_000], ["300 000 L", 300_000]] %> + <% current_volume = (params[:volume].presence || 100_000).to_i %> + <% options.each do |label, val| %> + <option value="<%= val %>" <%= 'selected' if val == current_volume %>><%= label %></option> + <% end %> + </select> + </div> + + <div class="vr" style="height: 24px;"></div> + + <div class="d-flex align-items-center gap-2"> + <label class="mb-0 small text-nowrap" for="portions_input">Portions</label> + <input id="portions_input" type="number" min="2" max="10" step="1" + class="form-control form-control-sm" value="<%= params[:portions].presence || 2 %>"> + </div> + <% end %> + + <%= link_to "Back", root_path, class: "btn btn-sm btn-secondary" %> + </div> + </div> + + <div class="table-responsive"> + <table class="table table-sm align-middle mb-0" id="recipe-table"> + <thead class="table-light"> + <tr> + <th>Product</th> + <th class="text-muted">Fertilizer</th> + <th class="text-end">Qty (kg)</th> + <th class="text-end">Per portion (kg)</th> + </tr> + </thead> + <tbody> + <% @recipe.each do |component, kg| %> + <% prod_name = commercial_name_for(component) %> + <tr data-total-kg="<%= kg %>"> + <td><strong><%= prod_name %></strong></td> + <td class="text-muted"><small><%= component.name %></small></td> + <td class="text-end fw-semibold"><%= fmt_kg(kg) %></td> + <td class="text-end per-portion-cell"><%= fmt_kg(kg / (params[:portions].presence || 2).to_f) %></td> + </tr> + <% end %> + <% if @recipe.blank? %> + <tr><td colspan="4" class="text-center text-muted">No supplementation required.</td></tr> + <% end %> + </tbody> + </table> + </div> + + <div class="card-footer small text-muted"> + Recipe based on latest measurement: <%= @latest.measured_on %> + </div> +</div> + +<%# Tiny vanilla JS: auto-submit on volume change; live per-portion update %> +<script> + (function() { + const form = document.getElementById('recipe-form'); + const volumeSelect = document.getElementById('volume_select'); + const portionsInput = document.getElementById('portions_input'); + const rows = document.querySelectorAll('#recipe-table tbody tr[data-total-kg]'); + + function clampPortions(n) { + n = parseInt(n || 2, 10); + if (isNaN(n)) n = 2; + return Math.min(10, Math.max(2, n)); + } + + function updatePerPortion() { + const n = clampPortions(portionsInput.value); + portionsInput.value = n; + rows.forEach(row => { + const total = parseFloat(row.getAttribute('data-total-kg') || '0'); + const cell = row.querySelector('.per-portion-cell'); + const per = (n > 0) ? (total / n) : 0; + cell.textContent = formatKg(per); + }); + } + + function formatKg(v) { + // match Rails number_with_precision(... precision: 2, strip zeros-ish) + const s = (Math.round(v * 100) / 100).toFixed(2); + return s.replace(/\.00$/, '').replace(/(\.\d)0$/, '$1'); + } + + volumeSelect.addEventListener('change', () => { + // submit with selected volume, keeping portions as a query param + const portions = clampPortions(portionsInput.value); + const url = new URL(form.action, window.location.origin); + url.searchParams.set('volume', volumeSelect.value); + url.searchParams.set('portions', portions); + window.location.assign(url.toString()); + }); + + portionsInput.addEventListener('input', updatePerPortion); + updatePerPortion(); + })(); +</script> |