summaryrefslogtreecommitdiff
path: root/app/views/recipes/show.html.erb
diff options
context:
space:
mode:
authorMarius Peter <marius.peter@tutanota.com>2025-08-24 20:29:54 +0200
committerMarius Peter <marius.peter@tutanota.com>2025-08-24 20:29:54 +0200
commit52b044d6a4278c229992404ad5801769c2d13363 (patch)
treeb30b34da58f26117c035391d09366b190350b1e3 /app/views/recipes/show.html.erb
First commit.
Vive le Castel Peter !
Diffstat (limited to 'app/views/recipes/show.html.erb')
-rw-r--r--app/views/recipes/show.html.erb108
1 files changed, 108 insertions, 0 deletions
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>
Copyright 2019--2025 Marius PETER