feat: combine availability finished
This commit is contained in:
parent
6995599a81
commit
85fdd41c6b
@ -6,9 +6,10 @@ use sqlx::PgPool;
|
||||
|
||||
use crate::endpoints::availability::NewOrEditAvailabilityTemplate;
|
||||
use crate::models::{
|
||||
find_free_time_slots, only_one_availability_exists_and_is_whole_day, Availability, User,
|
||||
find_free_time_slots, only_one_availability_exists_and_is_whole_day, Availability, AvailabilityTime, User
|
||||
};
|
||||
use crate::utils::ApplicationError;
|
||||
use crate::{END_OF_DAY, START_OF_DAY};
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct AvailabilityNewQuery {
|
||||
@ -27,20 +28,25 @@ pub async fn get(
|
||||
Availability::read_by_user_and_date(pool.get_ref(), user.id, &query.date).await?;
|
||||
let free_slots = find_free_time_slots(&availabilities_from_user);
|
||||
|
||||
let user_can_create_availabillity =
|
||||
!(only_one_availability_exists_and_is_whole_day(&availabilities_from_user)
|
||||
|| free_slots.len() == 0);
|
||||
let user_can_create_availabillity = availabilities_from_user.len() == 0
|
||||
|| !only_one_availability_exists_and_is_whole_day(&availabilities_from_user)
|
||||
|| free_slots.len() > 0;
|
||||
|
||||
if !user_can_create_availabillity {
|
||||
return Ok(HttpResponse::BadRequest().finish());
|
||||
}
|
||||
|
||||
let time_selection = if query.whole_day.unwrap_or(true) {
|
||||
AvailabilityTime::WholeDay
|
||||
} else {
|
||||
AvailabilityTime::Temporarily(START_OF_DAY, END_OF_DAY)
|
||||
};
|
||||
|
||||
let template = NewOrEditAvailabilityTemplate {
|
||||
user: user.into_inner(),
|
||||
date: query.date,
|
||||
whole_day_selected: query.whole_day.unwrap_or(true),
|
||||
time_selection,
|
||||
id: None,
|
||||
time: None,
|
||||
comment: None,
|
||||
slot_suggestions: free_slots,
|
||||
};
|
||||
|
@ -71,10 +71,15 @@ async fn get(
|
||||
|
||||
let availabilities_from_user =
|
||||
Availability::read_by_user_and_date(pool.get_ref(), user.id, &date).await?;
|
||||
println!("{availabilities_from_user:#?}");
|
||||
|
||||
let user_can_create_availabillity =
|
||||
!(only_one_availability_exists_and_is_whole_day(&availabilities_from_user)
|
||||
|| find_free_time_slots(&availabilities_from_user).len() == 0);
|
||||
let user_can_create_availabillity = availabilities_from_user.len() == 0
|
||||
|| !only_one_availability_exists_and_is_whole_day(&availabilities_from_user)
|
||||
|| find_free_time_slots(&availabilities_from_user).len() > 0;
|
||||
|
||||
println!("{} || {} || {} = {user_can_create_availabillity}", availabilities_from_user.len() == 0,
|
||||
!only_one_availability_exists_and_is_whole_day(&availabilities_from_user),
|
||||
find_free_time_slots(&availabilities_from_user).len() > 0);
|
||||
|
||||
let mut events_and_assignments = Vec::new();
|
||||
for e in Event::read_all_by_date_and_area_including_location(
|
||||
|
@ -33,8 +33,6 @@ pub async fn get(
|
||||
return Err(ApplicationError::Unauthorized);
|
||||
}
|
||||
|
||||
let whole_day_selected = query.whole_day.unwrap_or(availability.time == AvailabilityTime::WholeDay);
|
||||
|
||||
let suggestions = if let AvailabilityTime::Temporarily(start, end) = availability.time {
|
||||
let availabilities = Availability::read_by_user_and_date(
|
||||
pool.get_ref(),
|
||||
@ -51,14 +49,20 @@ pub async fn get(
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
let time_selection = if query.whole_day.unwrap_or(availability.time == AvailabilityTime::WholeDay) {
|
||||
AvailabilityTime::WholeDay
|
||||
} else {
|
||||
availability.time.clone()
|
||||
};
|
||||
|
||||
println!("{:?}", availability.time);
|
||||
let template = NewOrEditAvailabilityTemplate {
|
||||
user: user.into_inner(),
|
||||
date: availability.date,
|
||||
id: Some(path.id),
|
||||
time: Some(availability.time),
|
||||
time_selection,
|
||||
comment: availability.comment.as_deref(),
|
||||
slot_suggestions: suggestions,
|
||||
whole_day_selected
|
||||
};
|
||||
|
||||
Ok(HttpResponse::Ok().body(template.render()?))
|
||||
|
@ -2,7 +2,7 @@ use chrono::{NaiveDate, NaiveTime};
|
||||
use rinja::Template;
|
||||
|
||||
use crate::filters;
|
||||
use crate::models::{AvailabilityTime, Role, User};
|
||||
use crate::models::{Availability, AvailabilityChangeset, AvailabilityTime, Role, User};
|
||||
|
||||
pub mod delete;
|
||||
pub mod get_new;
|
||||
@ -17,8 +17,30 @@ struct NewOrEditAvailabilityTemplate<'a> {
|
||||
user: User,
|
||||
date: NaiveDate,
|
||||
id: Option<i32>,
|
||||
time: Option<AvailabilityTime>,
|
||||
whole_day_selected: bool,
|
||||
time_selection: AvailabilityTime,
|
||||
comment: Option<&'a str>,
|
||||
slot_suggestions: Vec<(NaiveTime, NaiveTime)>,
|
||||
}
|
||||
|
||||
fn find_adjacend_availability<'a>(
|
||||
changeset: &AvailabilityChangeset,
|
||||
availability_id_to_be_updated: Option<i32>,
|
||||
existing_availabilities: &'a [Availability],
|
||||
) -> Option<&'a Availability> {
|
||||
let AvailabilityTime::Temporarily(changeset_start, changeset_end) = changeset.time else {
|
||||
return None;
|
||||
};
|
||||
|
||||
for a in existing_availabilities
|
||||
.iter()
|
||||
.filter(|a| availability_id_to_be_updated.is_none_or(|id| a.id != id))
|
||||
{
|
||||
if let AvailabilityTime::Temporarily(start, end) = a.time {
|
||||
if start == changeset_end || end == changeset_start {
|
||||
return Some(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
use actix_web::{http::header::LOCATION, web, HttpResponse, Responder};
|
||||
use chrono::{NaiveDate, NaiveTime};
|
||||
use garde::Validate;
|
||||
use serde::Deserialize;
|
||||
use sqlx::PgPool;
|
||||
|
||||
use crate::{
|
||||
models::{Availability, User},
|
||||
endpoints::availability::find_adjacend_availability,
|
||||
models::{Availability, AvailabilityChangeset, AvailabilityContext, AvailabilityTime, User},
|
||||
utils::{self, ApplicationError},
|
||||
};
|
||||
|
||||
@ -22,16 +24,43 @@ pub async fn post(
|
||||
pool: web::Data<PgPool>,
|
||||
form: web::Form<AvailabillityForm>,
|
||||
) -> Result<impl Responder, ApplicationError> {
|
||||
// TODO: create and validate changeset
|
||||
//Availability::create(
|
||||
// pool.get_ref(),
|
||||
// user.id,
|
||||
// form.date,
|
||||
// form.from,
|
||||
// form.till,
|
||||
// form.comment.clone(),
|
||||
//)
|
||||
//.await?;
|
||||
let existing_availabilities =
|
||||
Availability::read_by_user_and_date(pool.get_ref(), user.id, &form.date).await?;
|
||||
let context = AvailabilityContext {
|
||||
existing_availabilities: existing_availabilities.clone(),
|
||||
};
|
||||
|
||||
let time = if form.from.is_some() && form.till.is_some() {
|
||||
AvailabilityTime::Temporarily(form.from.unwrap(), form.till.unwrap())
|
||||
} else {
|
||||
AvailabilityTime::WholeDay
|
||||
};
|
||||
|
||||
let mut changeset = AvailabilityChangeset {
|
||||
time,
|
||||
comment: form.comment.clone(),
|
||||
};
|
||||
|
||||
if let Err(e) = changeset.validate_with(&context) {
|
||||
return Ok(HttpResponse::BadRequest().body(e.to_string()));
|
||||
};
|
||||
|
||||
if let Some(a) = find_adjacend_availability(&changeset, None, &existing_availabilities) {
|
||||
let (changeset_start, changeset_end) = changeset.time.time_tuple_opt().unwrap();
|
||||
let (adjacent_start, adjacent_end) = changeset.time.time_tuple_opt().unwrap();
|
||||
|
||||
if adjacent_end == changeset_start {
|
||||
changeset.time = AvailabilityTime::Temporarily(adjacent_start, changeset_end);
|
||||
}
|
||||
|
||||
if adjacent_start == changeset_end {
|
||||
changeset.time = AvailabilityTime::Temporarily(changeset_start, adjacent_end);
|
||||
}
|
||||
|
||||
Availability::update(pool.get_ref(), a.id, changeset).await?;
|
||||
} else {
|
||||
Availability::create(pool.get_ref(), user.id, form.date, changeset).await?;
|
||||
}
|
||||
|
||||
let url = utils::get_return_url_for_date(&form.date);
|
||||
Ok(HttpResponse::Found()
|
||||
|
@ -3,7 +3,7 @@ use garde::Validate;
|
||||
use sqlx::PgPool;
|
||||
|
||||
use crate::{
|
||||
endpoints::{availability::post_new::AvailabillityForm, IdPath},
|
||||
endpoints::{availability::{find_adjacend_availability, post_new::AvailabillityForm}, IdPath},
|
||||
models::{Availability, AvailabilityChangeset, AvailabilityContext, AvailabilityTime, User},
|
||||
utils::{self, ApplicationError},
|
||||
};
|
||||
@ -44,22 +44,7 @@ pub async fn post(
|
||||
return Ok(HttpResponse::BadRequest().body(e.to_string()));
|
||||
};
|
||||
|
||||
let mut adjacent = None;
|
||||
if let AvailabilityTime::Temporarily(changeset_start, changeset_end) = changeset.time {
|
||||
for a in existing_availabilities
|
||||
.iter()
|
||||
.filter(|a| a.id != availability.id)
|
||||
{
|
||||
if let AvailabilityTime::Temporarily(start, end) = a.time {
|
||||
if start == changeset_end || end == changeset_start {
|
||||
adjacent = Some(a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(a) = adjacent {
|
||||
if let Some(a) = find_adjacend_availability(&changeset, Some(availability.id), &existing_availabilities) {
|
||||
let (changeset_start, changeset_end) = changeset.time.time_tuple_opt().unwrap();
|
||||
let (adjacent_start, adjacent_end) = changeset.time.time_tuple_opt().unwrap();
|
||||
|
||||
|
@ -34,7 +34,7 @@ fn time_is_not_already_made_available(
|
||||
return Err(garde::Error::new("cant create a availability while an other availability for the whole day is already present"));
|
||||
}
|
||||
|
||||
if find_free_time_slots(&context.existing_availabilities).len() == 0 {
|
||||
if context.existing_availabilities.len() > 0 && find_free_time_slots(&context.existing_availabilities).len() == 0 {
|
||||
return Err(garde::Error::new(
|
||||
"cant create a availability as every time slot is already filled",
|
||||
));
|
||||
@ -71,7 +71,7 @@ pub fn find_free_time_slots(availabilities: &[Availability]) -> Vec<(NaiveTime,
|
||||
if times.len() == 0 {
|
||||
return Vec::new();
|
||||
}
|
||||
//println!("zeiten {times:?}");
|
||||
println!("zeiten {times:?}");
|
||||
|
||||
times.sort();
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
{% endif %}
|
||||
|
||||
<input type="hidden" name="date" value="{{ date }}">
|
||||
{% let whole_day_selected = time_selection == AvailabilityTime::WholeDay %}
|
||||
|
||||
<div class="field is-horizontal">
|
||||
<div class="field-label">
|
||||
@ -46,25 +47,21 @@
|
||||
<label class="label">Von - Bis</label>
|
||||
</div>
|
||||
<div class="field-body">
|
||||
{% let times = ("00:00".to_string(), "23:59".to_string()) -%}
|
||||
{% if let Some(times) = time -%}
|
||||
{% if let AvailabilityTime::Temporarily(start, end) = times -%}
|
||||
{% let times = (start.to_string(), end.to_string()) -%}
|
||||
{% endif -%}
|
||||
{% endif -%}
|
||||
{% let times = time_selection.time_tuple() -%}
|
||||
<div class="field">
|
||||
<input class="input" type="time" id="from" name="from" value='{{ times.0 }}' {{
|
||||
<input class="input" type="time" id="from" name="from" value='{{ times.0.format("%R") }}' {{
|
||||
whole_day_selected|cond_show("disabled") }} {{ whole_day_selected|invert|ref|cond_show("required") }}>
|
||||
|
||||
{% if slot_suggestions.len() > 0 %}
|
||||
<p class="help">noch mögliche Zeiträume:</p>
|
||||
<div class="tags help">
|
||||
{% for (s, e) in slot_suggestions %}
|
||||
<span class="tag">{{ s }} - {{ e }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="field">
|
||||
<input class="input" type="time" id="till" name="till" value='{{ times.1 }}' {{
|
||||
<input class="input" type="time" id="till" name="till" value='{{ times.1.format("%R") }}' {{
|
||||
whole_day_selected|cond_show("disabled") }} {{ whole_day_selected|invert|ref|cond_show("required") }}>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user