Prevent invalid event durations in calendar (#14545)

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
Philip Allgaier 2022-12-06 13:23:04 +01:00 committed by GitHub
parent 745753c526
commit ff64dc2631
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 72 additions and 2 deletions

View File

@ -1,7 +1,13 @@
import "@material/mwc-button";
import { mdiClose } from "@mdi/js";
import { ComboBoxLitRenderer } from "@vaadin/combo-box/lit";
import { addDays, addHours, startOfHour } from "date-fns/esm";
import {
addDays,
addHours,
addMilliseconds,
differenceInMilliseconds,
startOfHour,
} from "date-fns/esm";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit";
import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one";
@ -35,6 +41,8 @@ class DialogCalendarEventEditor extends LitElement {
@state() private _error?: string;
@state() private _info?: string;
@state() private _params?: CalendarEventDetailDialogParams;
@state() private _calendars: Calendar[] = [];
@ -57,6 +65,7 @@ class DialogCalendarEventEditor extends LitElement {
public showDialog(params: CalendarEventEditDialogParams): void {
this._error = undefined;
this._info = undefined;
this._params = params;
this._calendars = params.calendars;
this._calendarId = params.calendarId || this._calendars[0].entity_id;
@ -120,6 +129,14 @@ class DialogCalendarEventEditor extends LitElement {
${this._error
? html`<ha-alert alert-type="error">${this._error}</ha-alert>`
: ""}
${this._info
? html`<ha-alert
alert-type="info"
dismissable
@alert-dismissed-clicked=${this._clearInfo}
>${this._info}</ha-alert
>`
: ""}
<ha-textfield
class="summary"
@ -260,6 +277,10 @@ class DialogCalendarEventEditor extends LitElement {
}
);
private _clearInfo() {
this._info = undefined;
}
private _handleSummaryChanged(ev) {
this._summary = ev.target.value;
}
@ -277,9 +298,30 @@ class DialogCalendarEventEditor extends LitElement {
}
private _startDateChanged(ev: CustomEvent) {
// Store previous event duration
const duration = differenceInMilliseconds(this._dtend!, this._dtstart!);
this._dtstart = new Date(
ev.detail.value + "T" + this._dtstart!.toISOString().split("T")[1]
);
// Prevent that the end time can be before the start time. Try to keep the
// duration the same.
if (this._dtend! <= this._dtstart!) {
const newEnd = addMilliseconds(this._dtstart, duration);
// en-CA locale used for date format YYYY-MM-DD
// en-GB locale used for 24h time format HH:MM:SS
this._dtend = new Date(
`${newEnd.toLocaleDateString("en-CA", {
timeZone: this.hass.config.time_zone,
})}T${newEnd.toLocaleTimeString("en-GB", {
timeZone: this.hass.config.time_zone,
})}`
);
this._info = this.hass.localize(
"ui.components.calendar.event.end_auto_adjusted"
);
}
}
private _endDateChanged(ev: CustomEvent) {
@ -289,9 +331,28 @@ class DialogCalendarEventEditor extends LitElement {
}
private _startTimeChanged(ev: CustomEvent) {
// Store previous event duration
const duration = differenceInMilliseconds(this._dtend!, this._dtstart!);
this._dtstart = new Date(
this._dtstart!.toISOString().split("T")[0] + "T" + ev.detail.value
);
// Prevent that the end time can be before the start time. Try to keep the
// duration the same.
if (this._dtend! <= this._dtstart!) {
const newEnd = addMilliseconds(new Date(this._dtstart), duration);
this._dtend = new Date(
`${newEnd.toLocaleDateString("en-CA", {
timeZone: this.hass.config.time_zone,
})}T${newEnd.toLocaleTimeString("en-GB", {
timeZone: this.hass.config.time_zone,
})}`
);
this._info = this.hass.localize(
"ui.components.calendar.event.end_auto_adjusted"
);
}
}
private _endTimeChanged(ev: CustomEvent) {
@ -337,6 +398,13 @@ class DialogCalendarEventEditor extends LitElement {
return;
}
if (this._dtend! <= this._dtstart!) {
this._error = this.hass.localize(
"ui.components.calendar.event.invalid_duration"
);
return;
}
this._submitting = true;
try {
await createCalendarEvent(

View File

@ -642,7 +642,9 @@
"all_day": "All Day",
"start": "Start",
"end": "End",
"not_all_required_fields": "Not all required fields are filled in.",
"invalid_duration": "The duration of the event is not valid. Please check start and end date.",
"not_all_required_fields": "Not all required fields are filled in",
"end_auto_adjusted": "Event end was adjusted to prevent negative duration",
"confirm_delete": {
"delete": "Delete Event",
"delete_this": "Delete Only This Event",