9 changed files with 406 additions and 1 deletions
@ -0,0 +1,64 @@ |
|||
class CalendarController < ApplicationController |
|||
before_action :authenticate_user! |
|||
|
|||
def month |
|||
@year = params[:year].to_i |
|||
@month = params[:month].to_i |
|||
|
|||
while @month < 1 |
|||
@month += 12 |
|||
@year -= 1 |
|||
end |
|||
while @month > 12 |
|||
@month -= 12 |
|||
@year += 1 |
|||
end |
|||
|
|||
first_of_month = Date.new(@year, @month, 1) |
|||
last_of_month = first_of_month.end_of_month |
|||
|
|||
@filter_typ = params[:typ] |
|||
@filter_art = params[:art] |
|||
|
|||
@entries = current_user.entries |
|||
.where(date: first_of_month..last_of_month) |
|||
@entries = @entries.where(praktikums_typ: @filter_typ) if @filter_typ.present? |
|||
@entries = @entries.where(entry_art: @filter_art) if @filter_art.present? |
|||
@entries = @entries.group_by { |e| e.date.to_date } |
|||
|
|||
|
|||
puts @entries |
|||
@days = (first_of_month..last_of_month).to_a |
|||
end |
|||
|
|||
def week |
|||
@year = params[:year].to_i |
|||
@week = params[:week].to_i |
|||
|
|||
while @month < 1 |
|||
@month += 12 |
|||
@year -= 1 |
|||
end |
|||
while @month > 12 |
|||
@month -= 12 |
|||
@year += 1 |
|||
end |
|||
|
|||
first = Date.commercial(@year, @week, 1) |
|||
last = Date.commercial(@year, @week, 7) |
|||
|
|||
@filter_typ = params[:typ] |
|||
@filter_art = params[:art] |
|||
|
|||
@entries = current_user.entries |
|||
.where(date: first..last) |
|||
@entries = @entries.where(praktikums_typ: @filter_typ) if @filter_typ.present? |
|||
@entries = @entries.where(entry_art: @filter_art) if @filter_art.present? |
|||
@entries = @entries.group_by{ |e| e.date.to_date } |
|||
|
|||
|
|||
|
|||
|
|||
@days = (first..last).to_a |
|||
end |
|||
end |
|||
@ -1,2 +1,16 @@ |
|||
module ApplicationHelper |
|||
def color_class_for(entry) |
|||
case entry.entry_art |
|||
when "Praktikum" |
|||
"bg-primary text-white" |
|||
when "Selbsterfahrung" |
|||
"bg-purple text-white" |
|||
when "Supervision" |
|||
"bg-warning text-dark" |
|||
when "Fortbildung" |
|||
"bg-success text-white" |
|||
else |
|||
"bg-secondary text-white" |
|||
end |
|||
end |
|||
end |
|||
@ -0,0 +1,110 @@ |
|||
<h1 class="mb-3">Kalender – <%= Date::MONTHNAMES[@month] %> <%= @year %></h1> |
|||
|
|||
<div class="row mb-3"> |
|||
<div class="col-md-6"> |
|||
<%= link_to "← Vorheriger Monat", calendar_month_path(@year, @month - 1, typ: @filter_typ, art: @filter_art), class: "btn btn-outline-primary" %> |
|||
<%= link_to "Nächster Monat →", calendar_month_path(@year, @month + 1, typ: @filter_typ, art: @filter_art), class: "btn btn-outline-primary ms-2" %> |
|||
</div> |
|||
|
|||
<div class="col-md-6 text-end"> |
|||
<%= form_with url: calendar_month_path(@year, @month), method: :get, local: true, class: "row g-2 justify-content-end" do %> |
|||
<div class="col-auto"> |
|||
<%= select_tag :typ, options_for_select(User::PRAKTIKUMSTYPEN, @filter_typ), include_blank: "Alle Typen", class: "form-select" %> |
|||
</div> |
|||
<div class="col-auto"> |
|||
<%= select_tag :art, options_for_select(User::ENTRY_ARTEN, @filter_art), include_blank: "Alle Arten", class: "form-select" %> |
|||
</div> |
|||
<div class="col-auto"> |
|||
<%= submit_tag "Filtern", class: "btn btn-outline-secondary" %> |
|||
</div> |
|||
<% end %> |
|||
</div> |
|||
</div> |
|||
|
|||
<table class="table table-bordered calendar-table"> |
|||
<thead class="table-light"> |
|||
<tr> |
|||
<% Date::ABBR_DAYNAMES.each do |day| %> |
|||
<th><%= day %></th> |
|||
<% end %> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
<% weeks = @days.in_groups_of(7, nil) %> |
|||
<% weeks.each do |week| %> |
|||
<tr> |
|||
<% week.each do |date| %> |
|||
<td class="day-cell |
|||
<%= 'bg-light' if date.blank? %> |
|||
<%= 'today' if date == Date.current %>" |
|||
data-date="<%= date %>" |
|||
data-label="<%= date&.strftime('%d.%m.%Y') %>"> |
|||
|
|||
<% if date %> |
|||
<div class="day-box"> |
|||
<div class="day-header"> |
|||
<span class="day-number"><%= date.day %></span> |
|||
|
|||
<%= link_to "+", |
|||
new_entry_path(date: date), |
|||
class: "btn btn-sm btn-success day-add", |
|||
title: "Eintrag hinzufügen", |
|||
onclick: "event.stopPropagation();" %> |
|||
</div> |
|||
|
|||
<div class="day-entries"> |
|||
<% (@entries[date.to_date] || []).each do |entry| %> |
|||
<%= link_to edit_entry_path(entry), |
|||
class: "day-entry text-decoration-none", |
|||
onclick: "event.stopPropagation();" do %> |
|||
<span class="badge <%= color_class_for(entry) %>"> |
|||
<%= entry.entry_art.capitalize %> |
|||
</span> |
|||
<span class="entry-time"> |
|||
<%= entry.hours %>h <%= entry.minutes %>min |
|||
</span> |
|||
<% end %> |
|||
<% end %> |
|||
</div> |
|||
</div> |
|||
<% end %> |
|||
</td> |
|||
|
|||
<% end %> |
|||
</tr> |
|||
<% end %> |
|||
</tbody> |
|||
</table> |
|||
|
|||
|
|||
|
|||
<!-- Tagesmodal --> |
|||
<div class="modal fade" id="dayEntriesModal" tabindex="-1" aria-hidden="true"> |
|||
<div class="modal-dialog modal-lg"> |
|||
<div class="modal-content"> |
|||
<div class="modal-header"> |
|||
<h5 class="modal-title">Einträge für <span id="modal-date-label"></span></h5> |
|||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button> |
|||
</div> |
|||
<div class="modal-body" id="modal-day-entries"></div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<script> |
|||
document.addEventListener("DOMContentLoaded", () => { |
|||
document.querySelectorAll(".day-cell").forEach(cell => { |
|||
cell.addEventListener("click", function () { |
|||
const date = this.dataset.date; |
|||
const label = this.dataset.label; |
|||
const entriesHtml = this.querySelector(".day-entries").innerHTML; |
|||
|
|||
document.getElementById("modal-date-label").textContent = label; |
|||
document.getElementById("modal-day-entries").innerHTML = entriesHtml; |
|||
|
|||
const modal = new bootstrap.Modal(document.getElementById("dayEntriesModal")); |
|||
modal.show(); |
|||
}); |
|||
}); |
|||
}); |
|||
</script> |
|||
@ -0,0 +1,75 @@ |
|||
<h1 class="mb-3">Kalender – Woche <%= @week %> / <%= @year %></h1> |
|||
|
|||
<div class="row mb-3"> |
|||
<div class="col-md-6"> |
|||
<%= link_to "← Vorherige Woche", calendar_week_path(@year, @week - 1, typ: @filter_typ, art: @filter_art), class: "btn btn-outline-primary" %> |
|||
<%= link_to "Nächste Woche →", calendar_week_path(@year, @week + 1, typ: @filter_typ, art: @filter_art), class: "btn btn-outline-primary ms-2" %> |
|||
</div> |
|||
|
|||
<div class="col-md-6 text-end"> |
|||
<%= form_with url: calendar_week_path(@year, @week), method: :get, local: true, class: "row g-2 justify-content-end" do %> |
|||
<div class="col-auto"> |
|||
<%= select_tag :typ, options_for_select(User::PRAKTIKUMSTYPEN, @filter_typ), include_blank: "Alle Typen", class: "form-select" %> |
|||
</div> |
|||
<div class="col-auto"> |
|||
<%= select_tag :art, options_for_select(User::ENTRY_ARTEN, @filter_art), include_blank: "Alle Arten", class: "form-select" %> |
|||
</div> |
|||
<div class="col-auto"> |
|||
<%= submit_tag "Filtern", class: "btn btn-outline-secondary" %> |
|||
</div> |
|||
<% end %> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="row"> |
|||
<% @days.each do |date| %> |
|||
<div class="col border p-2 day-cell" data-date="<%= date %>" data-label="<%= date.strftime('%A %d.%m.%Y') %>"> |
|||
<div class="fw-bold"><%= date.strftime("%a %d.%m.") %></div> |
|||
<div class="day-entries d-none"> |
|||
<% if @entries[date] %> |
|||
<% @entries[date].each do |entry| %> |
|||
<div class="mb-2"> |
|||
<span class="badge <%= color_class_for(entry) %>"><%= entry.entry_art.capitalize %></span> |
|||
<%= "#{entry.hours}h #{entry.minutes}min" %> |
|||
<%= link_to "✏️", edit_entry_path(entry), class: "btn btn-sm btn-outline-secondary ms-2" %> |
|||
</div> |
|||
<% end %> |
|||
<% else %> |
|||
<p class="text-muted small">Keine Einträge</p> |
|||
<% end %> |
|||
</div> |
|||
<%= link_to "+", new_entry_path(date: date), class: "btn btn-sm btn-success mt-1", onclick: "event.stopPropagation();" %> |
|||
</div> |
|||
<% end %> |
|||
</div> |
|||
|
|||
<!-- Tagesmodal (wie im Monat) --> |
|||
<div class="modal fade" id="dayEntriesModal" tabindex="-1" aria-hidden="true"> |
|||
<div class="modal-dialog modal-lg"> |
|||
<div class="modal-content"> |
|||
<div class="modal-header"> |
|||
<h5 class="modal-title">Einträge für <span id="modal-date-label"></span></h5> |
|||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button> |
|||
</div> |
|||
<div class="modal-body" id="modal-day-entries"></div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<script> |
|||
document.addEventListener("DOMContentLoaded", () => { |
|||
document.querySelectorAll(".day-cell").forEach(cell => { |
|||
cell.addEventListener("click", function () { |
|||
const date = this.dataset.date; |
|||
const label = this.dataset.label; |
|||
const entriesHtml = this.querySelector(".day-entries").innerHTML; |
|||
|
|||
document.getElementById("modal-date-label").textContent = label; |
|||
document.getElementById("modal-day-entries").innerHTML = entriesHtml; |
|||
|
|||
const modal = new bootstrap.Modal(document.getElementById("dayEntriesModal")); |
|||
modal.show(); |
|||
}); |
|||
}); |
|||
}); |
|||
</script> |
|||
Loading…
Reference in new issue