Browse Source

add time from time to with break flag

main
Christoph Marzell 1 month ago
parent
commit
0eb553770e
  1. 7
      app/controllers/calculations_controller.rb
  2. 0
      app/javascript/application.js
  3. 4
      app/models/user.rb
  4. 38
      app/views/calculations/new.html.erb
  5. 2
      app/views/devise/passwords/edit.html.erb
  6. 2
      app/views/devise/registrations/edit.html.erb
  7. 138
      app/views/entries/_form.html.erb
  8. 8
      app/views/layouts/application.html.erb

7
app/controllers/calculations_controller.rb

@ -0,0 +1,7 @@
class CalculationsController < ApplicationController
before_action :authenticate_user!
def new
@entry = Entry.new
end
end

0
app/javascript/application.js

4
app/models/user.rb

@ -12,6 +12,10 @@ class User < ApplicationRecord
after_initialize :set_default, if: :new_record? after_initialize :set_default, if: :new_record?
def is_admin?
self.email =="christoph@marzell.net"
end
def set_default def set_default
self.required_hours_matrix = PRAKTIKUMSTYPEN.to_h do |typ| self.required_hours_matrix = PRAKTIKUMSTYPEN.to_h do |typ|
[typ, ENTRY_ARTEN.to_h { |art| [art, default_hours_for(typ, art)] }] [typ, ENTRY_ARTEN.to_h { |art| [art, default_hours_for(typ, art)] }]

38
app/views/calculations/new.html.erb

@ -0,0 +1,38 @@
<h1>Minutenrechner</h1>
<div class="mb-4">
<label for="minute-inputs" class="form-label">Minuteneinträge (z. B. 45, 60, 30):</label>
<textarea id="minute-inputs" class="form-control" rows="3"></textarea>
<button id="sum-button" class="btn btn-primary mt-2">Summieren</button>
</div>
<div class="mb-4">
<p>Gesamtsumme: <strong><span id="total-time">0h 0min</span></strong> (<span id="total-minutes">0min</span>)</p>
</div>
<%= render "entries/form", entry: @entry %>
<script>
document.addEventListener("DOMContentLoaded", function () {
const textarea = document.getElementById("minute-inputs");
const totalSpan = document.getElementById("total-time");
const totalMinutesSpan = document.getElementById("total-minutes");
const sumBtn = document.getElementById("sum-button");
const hourInput = document.getElementById("entry_hours");
const minuteInput = document.getElementById("entry_minutes");
sumBtn.addEventListener("click", function () {
const values = textarea.value.split(/[ ,;\n]+/).map(v => parseInt(v.trim())).filter(Number.isFinite);
const totalMinutes = values.reduce((sum, val) => sum + val, 0);
const hours = Math.floor(totalMinutes / 60);
const minutes = totalMinutes % 60;
totalSpan.textContent = `${hours}h ${minutes}min`;
totalMinutesSpan.textContent = `${totalMinutes} min`;
hourInput.value = hours;
minuteInput.value = minutes;
});
});
</script>

2
app/views/devise/passwords/edit.html.erb

@ -1,7 +1,7 @@
<div class="container mt-5"> <div class="container mt-5">
<h2 class="mb-4">🔐 Passwort zurücksetzen</h2> <h2 class="mb-4">🔐 Passwort zurücksetzen</h2>
<%= devise_error_messages! %>
<%= render "devise/shared/error_messages", resource: resource %>
<%= form_with(scope: resource_name, url: password_path(resource_name), method: :put, local: true) do |f| %> <%= form_with(scope: resource_name, url: password_path(resource_name), method: :put, local: true) do |f| %>
<%= f.hidden_field :reset_password_token, value: params[:reset_password_token] %> <%= f.hidden_field :reset_password_token, value: params[:reset_password_token] %>

2
app/views/devise/registrations/edit.html.erb

@ -1,6 +1,6 @@
<h2>Profil bearbeiten</h2> <h2>Profil bearbeiten</h2>
<%= devise_error_messages! %>
<%= render "devise/shared/error_messages", resource: resource %>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %> <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
<div class="mb-3"> <div class="mb-3">

138
app/views/entries/_form.html.erb

@ -1,3 +1,15 @@
<div class="mb-4">
<label for="minute-inputs" class="form-label">Minuteneinträge (z. B. 45, 60, 30):</label>
<textarea id="minute-inputs" class="form-control" rows="3"></textarea>
<button id="sum-button" class="btn btn-primary mt-2">Summieren</button>
</div>
<div class="mb-4">
<p>Gesamtsumme: <strong><span id="total-time">0h 0min</span></strong> (<span id="total-minutes">0min</span>)</p>
</div>
<%= form_with(model: entry, local: true) do |form| %> <%= form_with(model: entry, local: true) do |form| %>
<% if entry.errors.any? %> <% if entry.errors.any? %>
<div class="alert alert-danger"> <div class="alert alert-danger">
@ -10,6 +22,7 @@
</div> </div>
<% end %> <% end %>
<!-- Erste Zeile: Datum, Stunden, Minuten --> <!-- Erste Zeile: Datum, Stunden, Minuten -->
<div class="row g-3 mt-1"> <div class="row g-3 mt-1">
<div class="col-12 col-md-4"> <div class="col-12 col-md-4">
@ -27,6 +40,21 @@
value: (form.object.date) %> value: (form.object.date) %>
</div> </div>
<div class="col-12 col-md-4">
<%= form.label :start_time, 'Beginn (Uhrzeit)', class: 'form-label' %>
<%= form.time_field :start_time, class: 'form-control', step: 60 %>
</div>
<div class="col-12 col-md-4">
<%= form.label :end_time, 'Ende (Uhrzeit)', class: 'form-label' %>
<%= form.time_field :end_time, class: 'form-control', step: 60 %>
</div>
<div class="col-12 col-md-4"> <div class="col-12 col-md-4">
<%= form.label :hours, 'Stunden', class: 'form-label' %> <%= form.label :hours, 'Stunden', class: 'form-label' %>
<%= form.number_field :hours, <%= form.number_field :hours,
@ -42,6 +70,22 @@
min: 0, max: 59, min: 0, max: 59,
value: form.object.minutes || 0 %> value: form.object.minutes || 0 %>
</div> </div>
<div class="col-12 col-md-4">
<div class="col-12 mt-2 d-flex justify-content-center">
<div class="form-check mt-4">
<%= form.check_box :has_break, { class: 'form-check-input', id: 'entry_has_break' }, true, false %>
<%= form.label :has_break, '30 Min. Mittagspause abziehen', class: 'form-check-label ms-2' %>
</div>
</div>
</div>
</div>
<div class="col-12 col-md-4 d-flex align-items-end">
<p class="mb-0"><strong>Gesamt:</strong> <span id="calculated-total-minutes">0 min</span></p>
</div> </div>
<!-- Weitere Felder: Typ, Art, Entfernung --> <!-- Weitere Felder: Typ, Art, Entfernung -->
@ -99,3 +143,97 @@
} }
}); });
</script> </script>
<script>
document.addEventListener("DOMContentLoaded", function () {
const textarea = document.getElementById("minute-inputs");
const totalSpan = document.getElementById("total-time");
const totalMinutesSpan = document.getElementById("total-minutes");
const totalMinutesDisplay = document.getElementById("calculated-total-minutes");
const sumBtn = document.getElementById("sum-button");
const startInput = document.getElementById("entry_start_time");
const endInput = document.getElementById("entry_end_time");
const hourInput = document.getElementById("entry_hours");
const minuteInput = document.getElementById("entry_minutes");
const breakCheckbox = document.getElementById("entry_has_break");
let baseTotalMinutes = 0; // <- diese merken wir uns immer ohne Pause-Abzug!
function updateDisplayFromBaseMinutes() {
let total = baseTotalMinutes;
if (breakCheckbox && breakCheckbox.checked) total = Math.max(0, total - 30);
const h = Math.floor(total / 60);
const m = total % 60;
hourInput.value = h;
minuteInput.value = m;
totalSpan.textContent = `${h}h ${m}min`;
totalMinutesSpan.textContent = `${total} min`;
totalMinutesDisplay.textContent = `${total} min`;
}
function clearFields(exclude = null) {
if (exclude !== 'textarea') textarea.value = '';
if (exclude !== 'time') {
startInput.value = '';
endInput.value = '';
}
}
sumBtn.addEventListener("click", function () {
const values = textarea.value.split(/[ ,;\n]+/).map(v => parseInt(v.trim())).filter(Number.isFinite);
baseTotalMinutes = values.reduce((sum, val) => sum + val, 0);
updateDisplayFromBaseMinutes();
clearFields('textarea');
});
function calculateFromTimes() {
const start = startInput.value;
const end = endInput.value;
if (start && end) {
const [sh, sm] = start.split(':').map(Number);
const [eh, em] = end.split(':').map(Number);
let startDate = new Date(0, 0, 0, sh, sm);
let endDate = new Date(0, 0, 0, eh, em);
let diffMin = (endDate - startDate) / 60000;
if (diffMin < 0) diffMin += 1440;
baseTotalMinutes = diffMin;
updateDisplayFromBaseMinutes();
clearFields('time');
}
}
function normalizeManualMinutes() {
let minutes = parseInt(minuteInput.value, 10);
if (!isNaN(minutes) && minutes >= 60) {
const extra = Math.floor(minutes / 60);
const remain = minutes % 60;
const currentHours = parseInt(hourInput.value, 10) || 0;
hourInput.value = currentHours + extra;
minuteInput.value = remain;
}
baseTotalMinutes = (parseInt(hourInput.value, 10) || 0) * 60 + (parseInt(minuteInput.value, 10) || 0);
updateDisplayFromBaseMinutes();
clearFields(); // alle Quellen löschen
}
// Listeners
if (startInput && endInput) {
startInput.addEventListener("change", calculateFromTimes);
endInput.addEventListener("change", calculateFromTimes);
}
if (hourInput) hourInput.addEventListener("input", normalizeManualMinutes);
if (minuteInput) minuteInput.addEventListener("blur", normalizeManualMinutes);
if (breakCheckbox) {
breakCheckbox.addEventListener("change", updateDisplayFromBaseMinutes);
}
});
</script>

8
app/views/layouts/application.html.erb

@ -93,7 +93,13 @@
<%= link_to "Profil", edit_user_registration_path, class: "nav-link" %> <%= link_to "Profil", edit_user_registration_path, class: "nav-link" %>
</li> </li>
<% if current_user&.email =="christoph@marzell.net" %>
<% if current_user.is_admin? %>
<li class="nav-item">
<%= link_to "Database", db_dump_path, class: "nav-link" %>
</li>
<% end %>
<% if current_user.is_admin? %>
<li class="nav-item"> <li class="nav-item">
<%= link_to "Database", db_dump_path, class: "nav-link" %> <%= link_to "Database", db_dump_path, class: "nav-link" %>
</li> </li>

Loading…
Cancel
Save