feat: show weekday in overview and edit pages

refs #33
This commit is contained in:
Max Hohlfeld 2025-07-03 20:15:56 +02:00
parent 45cf6dda10
commit b42540ac2f
12 changed files with 61 additions and 26 deletions

7
Cargo.lock generated
View File

@ -941,6 +941,7 @@ dependencies = [
"iana-time-zone", "iana-time-zone",
"js-sys", "js-sys",
"num-traits", "num-traits",
"pure-rust-locales",
"serde", "serde",
"wasm-bindgen", "wasm-bindgen",
"windows-link", "windows-link",
@ -2643,6 +2644,12 @@ dependencies = [
"cc", "cc",
] ]
[[package]]
name = "pure-rust-locales"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1190fd18ae6ce9e137184f207593877e70f39b015040156b1e05081cdfe3733a"
[[package]] [[package]]
name = "quick-xml" name = "quick-xml"
version = "0.37.5" version = "0.37.5"

View File

@ -14,7 +14,7 @@ argon2 = { version = "0.5.0", features = [ "std"]}
anyhow = "1.0.71" anyhow = "1.0.71"
actix-session = { version = "0.10.1", features = ["cookie-session"] } actix-session = { version = "0.10.1", features = ["cookie-session"] }
actix-identity = "0.8.0" actix-identity = "0.8.0"
chrono = { version = "0.4.33", features = ["serde", "now"] } chrono = { version = "0.4.33", features = ["serde", "now", "unstable-locales"] }
actix-files = "0.6.5" actix-files = "0.6.5"
futures-util = "0.3.30" futures-util = "0.3.30"
serde_json = "1.0.114" serde_json = "1.0.114"

View File

@ -9,7 +9,7 @@ use crate::{
utils::{ utils::{
event_planning_template::generate_vehicles_assigned_and_available, event_planning_template::generate_vehicles_assigned_and_available,
ApplicationError, ApplicationError,
DateTimeFormat::{DayMonthYear, DayMonthYearHourMinute, HourMinute}, DateTimeFormat::{DayMonthYearHourMinute, HourMinute, WeekdayDayMonthYear},
TemplateResponse, TemplateResponse,
}, },
}; };

View File

@ -4,7 +4,7 @@ use serde::Deserialize;
use crate::{ use crate::{
filters, filters,
utils::DateTimeFormat::{DayMonth, DayMonthYear, DayMonthYearHourMinute, HourMinute}, utils::DateTimeFormat::{DayMonthHourMinute, HourMinute, WeekdayDayMonth, WeekdayDayMonthYear},
}; };
use brass_db::models::{Role, User}; use brass_db::models::{Role, User};

View File

@ -10,7 +10,9 @@ use crate::{
generate_availability_assignment_list, generate_status_whether_staff_is_required, generate_availability_assignment_list, generate_status_whether_staff_is_required,
generate_vehicles_assigned_and_available, generate_vehicles_assigned_and_available,
}, },
ApplicationError, TemplateResponse, ApplicationError,
DateTimeFormat::{DayMonthYearHourMinute, HourMinute, WeekdayDayMonthYear},
TemplateResponse,
}, },
}; };
use brass_db::models::{Availability, AvailabilityAssignmentState, Event, Role, User, Vehicle}; use brass_db::models::{Availability, AvailabilityAssignmentState, Event, Role, User, Vehicle};

View File

@ -3,7 +3,10 @@ use chrono::{Days, NaiveDateTime};
use chrono::{NaiveDate, NaiveTime}; use chrono::{NaiveDate, NaiveTime};
use serde::Deserialize; use serde::Deserialize;
use crate::{filters, utils::DateTimeFormat::{DayMonthYear, HourMinute, YearMonthDayTHourMinute}}; use crate::{
filters,
utils::DateTimeFormat::{HourMinute, WeekdayDayMonthYear, YearMonthDayTHourMinute},
};
use brass_db::models::{Clothing, Location, Role, User}; use brass_db::models::{Clothing, Location, Role, User};
pub mod delete; pub mod delete;

View File

@ -1,6 +1,9 @@
use std::fmt::Display; use std::fmt::Display;
use chrono::{NaiveDate, NaiveDateTime, NaiveTime}; use chrono::{
format::{DelayedFormat, StrftimeItems},
NaiveDate, NaiveDateTime, NaiveTime,
};
use maud::html; use maud::html;
use tracing::trace; use tracing::trace;
@ -83,7 +86,8 @@ pub fn fmt_date(v: &NaiveDate, format: DateTimeFormat) -> askama::Result<String>
"formatting naivedate into string with format" "formatting naivedate into string with format"
); );
Ok(v.format(format_string).to_string()) Ok(v.format_localized(format_string, chrono::Locale::de_DE)
.to_string())
} }
pub fn fmt_datetime(v: &NaiveDateTime, format: DateTimeFormat) -> askama::Result<String> { pub fn fmt_datetime(v: &NaiveDateTime, format: DateTimeFormat) -> askama::Result<String> {
@ -93,7 +97,15 @@ pub fn fmt_datetime(v: &NaiveDateTime, format: DateTimeFormat) -> askama::Result
"formatting naivedatetime into string with format" "formatting naivedatetime into string with format"
); );
Ok(v.format(format_string).to_string()) let locale = chrono::Locale::de_DE;
let out = DelayedFormat::new_with_locale(
Some(v.date()),
Some(v.time()),
StrftimeItems::new_with_locale(format_string, locale),
locale,
);
Ok(out.to_string())
} }
pub fn fmt_time(v: &NaiveTime, format: DateTimeFormat) -> askama::Result<String> { pub fn fmt_time(v: &NaiveTime, format: DateTimeFormat) -> askama::Result<String> {

View File

@ -4,7 +4,10 @@ pub enum DateTimeFormat {
DayMonthYear, DayMonthYear,
DayMonthYearHourMinute, DayMonthYearHourMinute,
YearMonthDayTHourMinute, YearMonthDayTHourMinute,
HourMinute /// equivalent to %R,
HourMinute,
WeekdayDayMonth,
WeekdayDayMonthYear,
} }
impl From<DateTimeFormat> for &'static str { impl From<DateTimeFormat> for &'static str {
@ -15,7 +18,9 @@ impl From<DateTimeFormat> for &'static str {
DateTimeFormat::DayMonthYear => "%d.%m.%Y", DateTimeFormat::DayMonthYear => "%d.%m.%Y",
DateTimeFormat::DayMonthYearHourMinute => "%d.%m.%Y %H:%M", DateTimeFormat::DayMonthYearHourMinute => "%d.%m.%Y %H:%M",
DateTimeFormat::YearMonthDayTHourMinute => "%Y-%m-%dT%H:%M", DateTimeFormat::YearMonthDayTHourMinute => "%Y-%m-%dT%H:%M",
DateTimeFormat::HourMinute => "%H:%M" // equivalent to %R, DateTimeFormat::HourMinute => "%H:%M",
DateTimeFormat::WeekdayDayMonth => "%A, %d.%m.",
DateTimeFormat::WeekdayDayMonthYear => "%A, %d.%m.%Y",
} }
} }
} }

View File

@ -5,8 +5,8 @@
<div class="container"> <div class="container">
{% let is_edit = id.is_some() %} {% let is_edit = id.is_some() %}
<form method="post" action="/availability/{% if is_edit %}edit/{{ id.unwrap() }}{% else %}new{% endif %}"> <form method="post" action="/availability/{% if is_edit %}edit/{{ id.unwrap() }}{% else %}new{% endif %}">
<h1 class="title">{% if is_edit %}Bearbeite{% else %}Neue{% endif %} Vefügbarkeit für den {{ <h1 class="title">{% if is_edit %}Bearbeite{% else %}Neue{% endif %} Vefügbarkeit für {{
date|fmt_date(DayMonthYear) }}</h1> date|fmt_date(WeekdayDayMonthYear) }}</h1>
<input type="hidden" name="startdate" value="{{ date }}"> <input type="hidden" name="startdate" value="{{ date }}">
<input type="hidden" name="enddate" value="{{ enddate.as_ref().unwrap_or(date) }}" id="enddate"> <input type="hidden" name="enddate" value="{{ enddate.as_ref().unwrap_or(date) }}" id="enddate">
@ -23,8 +23,9 @@
<p class="help">noch mögliche Zeiträume:</p> <p class="help">noch mögliche Zeiträume:</p>
<div class="tags help"> <div class="tags help">
{% for (s, e) in slot_suggestions %} {% for (s, e) in slot_suggestions %}
<span class="tag">{{ s|fmt_datetime(DayMonthYearHourMinute) }} - <span class="tag">
{{ e|fmt_datetime(DayMonthYearHourMinute) }}</span> {{ s|fmt_datetime(DayMonthHourMinute) }} Uhr - {{ e|fmt_datetime(DayMonthHourMinute) }} Uhr
</span>
{% endfor %} {% endfor %}
</div> </div>
{% endif %} {% endif %}
@ -34,7 +35,7 @@
_='on change put the value of me into #et _='on change put the value of me into #et
then if (value of the previous <input/>) is greater than (value of me) then if (value of the previous <input/>) is greater than (value of me)
then set the value of #enddate to "{{ datetomorrow }}" then set the value of #enddate to "{{ datetomorrow }}"
then put "{{ datetomorrow|fmt_date(DayMonth) }}" into #ed then put "{{ datetomorrow|fmt_date(WeekdayDayMonth) }}" into #ed
then set checked of #radionextday to true then set checked of #radionextday to true
end' /> end' />
</div> </div>
@ -52,13 +53,13 @@
<label class="radio"> <label class="radio">
<input type="radio" name="isovernight" {{ is_overnight|invert|ref|cond_show("checked")|safe }} <input type="radio" name="isovernight" {{ is_overnight|invert|ref|cond_show("checked")|safe }}
_='on click set the value of #enddate to "{{ date }}" _='on click set the value of #enddate to "{{ date }}"
then put "{{ date|fmt_date(DayMonth) }}" into #ed'> then put "{{ date|fmt_date(WeekdayDayMonth) }}" into #ed'>
am selben Tag am selben Tag
</label> </label>
<label class="radio ml-3"> <label class="radio ml-3">
<input type="radio" id="radionextday" name="isovernight" {{ is_overnight|cond_show("checked")|safe }} <input type="radio" id="radionextday" name="isovernight" {{ is_overnight|cond_show("checked")|safe }}
_='on click set the value of #enddate to "{{ datetomorrow }}" _='on click set the value of #enddate to "{{ datetomorrow }}"
then put "{{ datetomorrow|fmt_date(DayMonth) }}" into #ed'> then put "{{ datetomorrow|fmt_date(WeekdayDayMonth) }}" into #ed'>
am Tag darauf am Tag darauf
</label> </label>
</div> </div>
@ -82,9 +83,12 @@
</svg> </svg>
{% let start_time = start.unwrap_or(NaiveTime::from_hms_opt(10, 0, 0).unwrap()) %} {% let start_time = start.unwrap_or(NaiveTime::from_hms_opt(10, 0, 0).unwrap()) %}
{% let end_time = end.unwrap_or(NaiveTime::from_hms_opt(20, 0, 0).unwrap()) %} {% let end_time = end.unwrap_or(NaiveTime::from_hms_opt(20, 0, 0).unwrap()) %}
verfügbar von {{ date|fmt_date(DayMonth) }} <span id="st">{{ start_time|fmt_time(HourMinute) }}</span> Uhr verfügbar von {{ date|fmt_date(WeekdayDayMonth) }}
bis <span id="ed">{{ enddate.as_ref().unwrap_or(date)|fmt_date(DayMonth) }}</span> <span id="st">{{ start_time|fmt_time(HourMinute) }}</span>
<span id="et">{{ end_time|fmt_time(HourMinute) }}</span> Uhr Uhr bis
<span id="ed">{{ enddate.as_ref().unwrap_or(date)|fmt_date(WeekdayDayMonth) }}</span>
<span id="et">{{ end_time|fmt_time(HourMinute) }}</span>
Uhr
</p> </p>
</div> </div>
</div> </div>

View File

@ -7,7 +7,7 @@
{% if let Some(name) = name %} {% if let Some(name) = name %}
<h1 class="title">Event '{{ name }}' bearbeiten</h1> <h1 class="title">Event '{{ name }}' bearbeiten</h1>
{% else %} {% else %}
<h1 class="title">Neues Event anlegen für den {{ date|fmt_date(DayMonthYear) }}</h1> <h1 class="title">Neues Event anlegen für {{ date|fmt_date(WeekdayDayMonthYear) }}</h1>
{% endif %} {% endif %}
<input type="hidden" name="date" value="{{ date }}"> <input type="hidden" name="date" value="{{ date }}">

View File

@ -15,11 +15,12 @@
</div> </div>
<div class="cell"> <div class="cell">
<p><b>Datum:</b> {{ event.start.format("%d.%m.%Y") }}</p> <p><b>Datum:</b> {{ event.start|fmt_datetime(WeekdayDayMonthYear) }}</p>
</div> </div>
<div class="cell"> <div class="cell">
<p><b>Uhrzeit:</b> {{ event.start.format("%R") }} Uhr - {{ event.end.format("%d.%m.%Y %R") }} Uhr</p> <p><b>Uhrzeit:</b> {{ event.start|fmt_datetime(HourMinute) }} Uhr - {{
event.end|fmt_datetime(DayMonthYearHourMinute) }} Uhr</p>
</div> </div>
<div class="cell is-col-span-2"> <div class="cell is-col-span-2">
@ -31,7 +32,8 @@
</div> </div>
<div class="cell"> <div class="cell">
<p><b>Führungsassistent benötigt:</b> {% if event.voluntary_fuehrungsassistent %}ja{% else %}nein{% endif %}</p> <p><b>Führungsassistent benötigt:</b> {% if event.voluntary_fuehrungsassistent %}ja{% else %}nein{% endif %}
</p>
</div> </div>
<div class="cell is-col-span-2"> <div class="cell is-col-span-2">

View File

@ -99,7 +99,7 @@
<div class="level"> <div class="level">
<div class="level-left"> <div class="level-left">
<h3 class="title is-3"> <h3 class="title is-3">
Events am {{ date|fmt_date(DayMonthYear) }} Events am {{ date|fmt_date(WeekdayDayMonthYear) }}
</h3> </h3>
</div> </div>
{% if user.role == Role::Admin || user.role == Role::AreaManager && (selected_area.is_none() || {% if user.role == Role::Admin || user.role == Role::AreaManager && (selected_area.is_none() ||
@ -227,7 +227,7 @@
<div class="level"> <div class="level">
<div class="level-left"> <div class="level-left">
<h3 class="title is-3"> <h3 class="title is-3">
Verfügbarkeiten am {{ date|fmt_date(DayMonthYear) }} Verfügbarkeiten am {{ date|fmt_date(WeekdayDayMonthYear) }}
</h3> </h3>
</div> </div>
{% if selected_area.is_none() || selected_area.unwrap() == user.area_id %} {% if selected_area.is_none() || selected_area.unwrap() == user.area_id %}