Files
BeWoPlaner/BeWoPlanerMobil/Views/Main/MultiBookingPartial.cshtml
Lyndon Jetten 3621ab8fc6 FaC:
- Rechte-Bug im Kalender behoben, der verhindert hat, dass man einen Termin mit Ressource und sich selbst in der   Mitarbeiterliste bearbeiten konnte.

MoK:
- Minuten/Stunden/Minuten&Stunden als Zeiterfassungseinheit wie im FaC implementiert
- Quittierungsbelegunterschriftenansicht verbessert
- Laden der Zeiterfassungseinträge effizienter gemacht
2023-05-02 13:03:46 +02:00

668 lines
32 KiB
Plaintext

@using BeWoPlanerMobil.Models
@using BS.Shared
@model BeWoPlanerMobil.Models.MainModel
<script>
$(document).ready(function () {
try {
$("#mb-hours-minutes-dropdown-btn").on("click",
function() {
$("#mb-hours-minutes-dropdown-btn").data("text", $("#mb-hours-minutes-dropdown-btn").text().replaceAll(/\s/g, ""));
});
$(".hours-minutes-link").on("click",
function() {
var previousText = $("#mb-hours-minutes-dropdown-btn").data("text");
var currentText = $(this).text().replaceAll(/\s/g, "");
if(previousText === currentText) {
return;
}
var buttonText = $(this).text();
$("#mb-hours-minutes-dropdown-btn").text(buttonText);
setInputFilter('mb-duration', 'mb-distance', 'mb-hours-minutes-dropdown-btn');
$.get('@Url.Action("ToggleDurationUnit")', { isInHoursMode: buttonText === "Stunden" });
calculateDuration(true, 'mb-start-time', 'mb-end-time', 'mb-duration', 'mb-hours-minutes-dropdown-btn', 'mb-start-date-picker', 'mb-end-date-picker', false, false);
});
} catch(error) {
showErrorPopup(error);
}
});
function addCostBearer2SupportConceptsToMultiBooking() {
try {
var selectedGroups = [];
var selectedSupportConcepts = [];
var scOidString = "";
var groupOidString = "";
$("#multi-booking-supportconcepts input:checked").each(function () {
selectedSupportConcepts.push($(this).attr("value"));
});
$("#multi-booking-groups input:checked").each(function () {
selectedGroups.push($(this).attr("value"));
});
for(var i = 0; i < selectedSupportConcepts.length; i++) {
scOidString += selectedSupportConcepts[i];
if(i < selectedSupportConcepts.length - 1) {
scOidString += ",";
}
}
for(var j = 0; j < selectedGroups.length; j++) {
groupOidString += selectedGroups[j];
if(j < selectedGroups.length - 1) {
groupOidString += ",";
}
}
$.get("@Url.Action("AddSupportConceptCostBearerRelationsToMultiBooking")", { pRelOids: scOidString, pGroupOids: groupOidString }).done(updateMultiBookingCb2ScList);
} catch(error) {
showErrorPopup(error);
}
}
function updateMultiBookingCb2ScList(result) {
try {
var list = $("#mb-selected-cb2sc-list");
if (isEmptyOrSpaces(result) || result === "SessionTimeout") {
window.location.href = getRedirectLink();
return;
}
var multiBookingSelectionObject = $.parseJSON(result);
var resultList = multiBookingSelectionObject.SelectedRelations;
list.empty();
$.each(resultList,
function (index, customListItem) {
var html =
'<div class="list-group-item" id="mb-relation-item-' + customListItem.Value + '">' +
'<div class="row">' +
'<div class="col">' +
'<span>' + customListItem.Text1 + '<br />' +
'<span class="' + customListItem.TextColor + '">' + customListItem.Text2 + '</span>' +
'</span>' +
'</div>' +
'<div class="col-auto my-auto">' +
'<button type="button" class="btn btn-primary" onclick="removeMultiBookingCb2ScRelation(' + customListItem.Value + ')">' +
'<span class="fas fa-times-circle"></span>' +
'</button>' +
'</div>' +
'</div>';
list.append(html);
});
updateMultiBookingGroupList(multiBookingSelectionObject);
} catch (error) {
showErrorPopup(error);
}
}
function updateMultiBookingGroupList(multiBookingSelectionObject) {
try {
var groupOids = multiBookingSelectionObject.GroupOids === undefined ? [] : multiBookingSelectionObject.GroupOids;
var relOids = [];
if (multiBookingSelectionObject.SelectedRelations !== undefined) {
for (var i = 0; i < multiBookingSelectionObject.SelectedRelations.length; i++) {
var oidStringValue = multiBookingSelectionObject.SelectedRelations[i].Value;
var oidIntValue = parseInt(oidStringValue, 10);
relOids.push(oidIntValue);
}
}
$("#multi-booking-supportconcepts input").each(function () {
var value = $(this).val();
$(this).prop("checked", isInArray(value, relOids));
});
$("#multi-booking-groups input").each(function () {
var value = $(this).val();
$(this).prop("checked", isInArray(value, groupOids));
});
if (relOids.length === 0 && groupOids.length === 0) {
deactivateMultiBookingForm();
} else {
activateMultiBookingForm();
}
} catch (error) {
showErrorPopup(error);
}
}
function removeMultiBookingCb2ScRelation(selectedCb2ScRelOid) {
try {
$("#mb-relation-item-" + selectedCb2ScRelOid).remove();
if ($("#mb-cb2sc-checkbox-" + selectedCb2ScRelOid).length) {
$("#mb-cb2sc-checkbox-" + selectedCb2ScRelOid).prop("checked", false);
}
if ($("#mb-selected-cb2sc-list").find(".list-group-item").length === 0) {
deactivateMultiBookingForm();
$("#multi-booking-supportconcepts input:checked").each(function () {
$(this).prop("checked", false);
});
}
$.get("@Url.Action("RemoveSupportConceptCostBearerRelationFromMultiBooking")", { pRelOid: selectedCb2ScRelOid }).done(function(result) {
updateMultiBookingGroupList($.parseJSON(result));
});
} catch (error) {
showErrorPopup(error);
}
}
function addEmployeeToMultiBooking() {
try {
var selectedEmployees = [];
var oidString = "";
$("#multi-booking-employee-selection-popup input:checked").each(function() {
var oid = $(this).val();
selectedEmployees.push(oid);
});
for(var i = 0; i < selectedEmployees.length; i++) {
oidString += selectedEmployees[i];
if(i < selectedEmployees.length - 1) {
oidString += ",";
}
}
$.get("@Url.Action("AddEmployeesToMultiBooking")", { pEmployeeOids: oidString }).done(function(numberOfSelectedEmployees) {
$("#multi-booking-selected-employees-count-badge").text(numberOfSelectedEmployees);
$("#multi-booking-create-button").prop("disabled", numberOfSelectedEmployees === "0" ? true : false);
});
} catch (error) {
showErrorPopup(error);
}
}
function deactivateMultiBookingForm() {
try {
$("#multi-booking-employees-button, #mb-category-select, #mb-leistung-select, #mb-start-date, #mb-end-date, #mb-start-time, #mb-end-time, #mb-duration, #mb-distance, textarea, #mb-reset-button, #mb-create-button, #mb-textbausteine-button, #mb-hours-minutes-dropdown-btn").prop("disabled", true);
} catch (error) {
showErrorPopup(error);
}
}
function activateMultiBookingForm() {
try {
$("#multi-booking-employees-button, #mb-category-select, #mb-leistung-select, #mb-start-date, #mb-end-date, #mb-start-time, #mb-end-time, #mb-duration, #mb-distance, textarea, #mb-reset-button, #mb-create-button, #mb-textbausteine-button, #mb-hours-minutes-dropdown-btn").prop("disabled", false);
} catch (error) {
showErrorPopup(error);
}
}
function submitMultiBookingForm() {
try {
showSpinner();
$.get("@Url.Action("MultiBookingHasSelectedSupportConcepts")").done(function(result1) {
$.get("@Url.Action("MultiBookingHasSelectedEmployees")").done(function (result2) {
var hasSupportConcepts = $.parseJSON(result1);
var hasEmployees = $.parseJSON(result2);
if (hasSupportConcepts && hasEmployees) {
validateForm($("#multiBookingForm"), "mb-");
} else {
hideSpinner();
var message = "";
if (!hasSupportConcepts && !hasEmployees) {
message = "Bitte wählen Sie mindestens einen Hilfeplan und Mitarbeiter aus.";
} else if(hasSupportConcepts && !hasEmployees) {
message = "Bitte wählen Sie mindestens einen Mitarbeiter aus.";
} else {
message = "Bitte wählen Sie mindestens einen Hilfeplan aus.";
}
showAlertMessageBoxWithoutCallback("Speichern nicht möglich", message);
}
});
});
} catch (error) {
showErrorPopup(error);
}
}
</script>
<div class="row">
<div class="col col-12">
@if(!(Model is null))
{
using(Html.BeginForm("CreateMultiBooking", "Main", FormMethod.Post, new { onreset = "serviceDescriptionSelectOnReset('mb-category-select', 'mb-leistung-select', 'textmodule-container', 'tree')", id = "multiBookingForm" }))
{
<div class="mt-3">
<!-- Hilfeplanauswahlbutton -->
<div class="form-row">
<div class="col-md">
<button type="button" class="btn btn-primary btn-block" data-toggle="modal" data-target="#multi-booking-popup" id="support-concepts-and-groups-button">Hilfepläne und Gruppen hinzufügen</button>
</div>
</div>
<!-- Hilfeplanauswahl -->
<div class="form-row">
<div class="col-md">
<div class="form-group my-1">
<div class="list-group" id="mb-selected-cb2sc-list">
@foreach(var selectedCb2ScRelation in Model.MultiBookingSelectionObject.SelectedRelations)
{
<div class="list-group-item" id="mb-relation-item-@selectedCb2ScRelation.Value">
<div class="row">
<div class="col">
<span>
@selectedCb2ScRelation.Text1
<br />
<span class="@selectedCb2ScRelation.TextColor">
@selectedCb2ScRelation.Text2
</span>
</span>
</div>
<div class="col-auto my-auto">
<button type="button" class="btn btn-primary" onclick="removeMultiBookingCb2ScRelation(@selectedCb2ScRelation.Value)">
<span class="fas fa-times-circle"></span>
</button>
</div>
</div>
</div>
}
</div>
</div>
</div>
</div>
<!-- Mitarbeiterauswahl -->
<div class="form-row">
<div class="col-md">
<div class="form-group mb-1">
<button type="button" class="btn btn-primary btn-block" data-toggle="modal" data-target="#multi-booking-employee-selection-popup" id="multi-booking-employees-button">
Mitarbeiter hinzufügen <span class="badge badge-light text-primary" id="multi-booking-selected-employees-count-badge">@Model.MultiBookingSelectedEmployees.Count</span>
</button>
</div>
</div>
</div>
<!-- Kategorie -->
<div class="form-row">
<div class="col-md">
<div class="form-group my-2">
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text prepend-input-group-text">
Kategorie
</div>
</div>
@Html.DropDownListFor(m => m.SelectedServiceCategoryOid, Model.ServiceCategoryListItems, new { onchange = "loadServiceDescriptions('mb-category-select', 'mb-leistung-select', 'textmodule-container', 'tree')", @class = "custom-select", Id = "mb-category-select" })
</div>
</div>
</div>
</div>
<!-- Leistung -->
<div class="form-row">
<div class="col-md">
<div class="form-group my-2">
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text prepend-input-group-text">
Leistung
</div>
</div>
<select class="custom-select" id="mb-leistung-select" name="ServiceDescription" onchange="setServiceDescription('mb-leistung-select')"></select>
</div>
</div>
</div>
</div>
<!-- Start- und Enddatum -->
<div class="form-row">
<div class="col-md">
<div class="form-group my-2">
<div class="input-group date" id="mb-start-date-picker" data-target-input="nearest">
<div class="input-group-prepend">
<div class="input-group-text prepend-input-group-text">
Startdatum
</div>
</div>
<input type="text" id="mb-start-date" name="Datum" class="form-control datetimepicker-input" data-target="#mb-start-date-picker" data-toggle="datetimepicker" value="@DateTime.Today.ToShortDateString()" />
<div class="input-group-append" data-target="#mb-start-date-picker" data-toggle="datetimepicker">
<div class="input-group-text">
<i class="fas fa-calendar-alt"></i>
</div>
</div>
</div>
</div>
</div>
@if(Model.IsEndDateVisible)
{
<div class="col-md">
<div class="form-group my-2">
<div class="input-group date" id="mb-end-date-picker" data-target-input="nearest">
<div class="input-group-prepend">
<div class="input-group-text prepend-input-group-text">
Enddatum
</div>
</div>
<input type="text" id="mb-end-date" name="Enddatum" class="form-control datetimepicker-input" data-target="#mb-end-date-picker" data-toggle="datetimepicker" value="@DateTime.Today.ToShortDateString()" />
<div class="input-group-append" data-target="#mb-end-date-picker" data-toggle="datetimepicker">
<div class="input-group-text">
<i class="fas fa-calendar-alt"></i>
</div>
</div>
</div>
</div>
</div>
}
</div>
<!-- Start- und Endzeit -->
<div class="form-row">
@{
var startTimeValue = Model.StartTimeToEdit;
var endTimeValue = Model.EndTimeToEdit;
var divisor = Model.SelectedDurationUnit == "Stunden" ? 60 : 1;
var durationValue = string.Empty;
if(Model.SetStartTimeToEndTimeAfterSave && !Model.IsInEditingMode)
{
startTimeValue = Model.NewStartTime;
endTimeValue = Model.NewEndTime;
if(Model.NewDuration.HasValue)
{
durationValue = (Model.NewDuration / divisor).ToString();
}
}
}
<div class="col-md">
<div class="form-group my-2">
<div class="input-group date" id="mb-start-time-picker" data-target-input="nearest">
<div class="input-group-prepend">
<div class="input-group-text sm-prepend-input-group-text">
Von
</div>
</div>
<input type="text" id="mb-start-time" name="Start" class="form-control datetimepicker-input" data-target="#mb-start-time-picker" value="@startTimeValue" />
<div class="input-group-append" data-target="#mb-start-time-picker" data-toggle="datetimepicker">
<div class="input-group-text">
<i class="fas fa-clock"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md">
<div class="form-group my-2">
<div class="input-group date" id="mb-end-time-picker" data-target-input="nearest">
<div class="input-group-prepend">
<div class="input-group-text sm-prepend-input-group-text">
Bis
</div>
</div>
<input type="text" id="mb-end-time" name="Ende" class="form-control datetimepicker-input" data-target="#mb-end-time-picker" value="@endTimeValue" />
<div class="input-group-append" data-target="#mb-end-time-picker" data-toggle="datetimepicker">
<div class="input-group-text">
<i class="fas fa-clock"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Dauer und Stunden/Minuten-Auswahl -->
<div class="form-row">
<div class="col-md">
<div class="form-group my-2">
<div class="input-group">
<div class="input-group-prepend">
@{
var labelText = Model.EinheitZeiterfassung == 1 ? "Dauer (h)" : "Dauer";
}
<div class="input-group-text prepend-input-group-text">
@labelText
</div>
</div>
<input type="text" class="form-control" id="mb-duration" name="Dauer" onchange="onDurationChange('mb-start-time', 'mb-end-time', 'mb-start-date', 'mb-end-date', 'mb-duration', 'mb-hours-minutes-dropdown-btn', 'mb-start-date-picker', 'mb-end-date-picker')" value="@durationValue">
@if(Model.IsZeiterfassungInStdMin)
{
<div class="input-group-append">
<button id="mb-hours-minutes-dropdown-btn" class="btn btn-outline-primary dropdown-toggle" type="button" data-toggle="dropdown">
@Model.SelectedDurationUnit
</button>
<div class="dropdown-menu">
<a class="dropdown-item hours-minutes-link" href="#">Minuten</a>
<a class="dropdown-item hours-minutes-link" href="#">Stunden</a>
</div>
</div>
}
</div>
</div>
</div>
</div>
<!-- Gefahrene Kilometer -->
@if(Model.ShowDistanceField)
{
<div class="form-row">
<div class="col-md">
<div class="form-group my-2">
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text">
Gefahrene Kilometer
</div>
</div>
<input type="text" class="form-control" id="mb-distance" name="Distanz" onchange="validateDistanceInput()">
</div>
</div>
</div>
</div>
}
<!-- Textbausteinebutton -->
@if(AbstractModel.HasRightToSeeTextModules)
{
<div class="form-row" id="textmodule-container">
<div class="col-md">
<button type="button" class="btn btn-primary form-control mt-3" data-toggle="modal" data-target="#textbausteine-popup" id="mb-textbausteine-button">Textbausteine</button>
</div>
</div>
}
<!-- Dokumentationsfelder -->
<div class="form-row">
<div class="col-md mt-3">
@if(Model.NumberOfDokuTypes == 0)
{
<div class="form-group">
<label for="mb-dokufeld">Dokumentation</label>
<textarea class="form-control" name="Dokumentation6" id="mb-dokufeld"></textarea>
</div>
}
else
{
<ul class="nav nav-tabs" role="tab-list">
@for(var i = 0; i < Model.Dokutypes.Length; i++)
{
var currentDokuType = Model.Dokutypes[i];
<li class="nav-item">
<a href="#mb-doku_@i" id="mb-doku_@i-tab" data-toggle="tab" role="tab" aria-controls="mb-doku_@i" class="nav-link@(i == 0 ? " active" : string.Empty)" aria-selected="true">
@currentDokuType.DisplayName
</a>
</li>
}
</ul>
<div class="tab-content" id="mb-dokufelderTab">
@for(var i = 0; i < Model.Dokutypes.Length; i++)
{
var textareaName = i + 1 < 1 ? "Dokumentation" : "Dokumentation" + (i + 1);
<div class="tab-pane show@(i == 0 ? " active" : string.Empty)" id="mb-doku_@i" role="tabpanel" aria-labelledby="mb-doku_@i-tab">
<textarea class="form-control doku-form-control" id="mb-doku-textarea-@i" name="@textareaName"></textarea>
</div>
}
</div>
}
</div>
</div>
</div>
}
<div class="d-flex bd-highlight mt-3">
<div class="mr-auto bd-highlight">
<!-- dient nur als Abstandshalter-->
</div>
<div class="ml-3 bd-highlight">
@using(Html.BeginForm("ResetEditingMode", "Main", FormMethod.Post))
{
<button type="submit" class="btn btn-primary" onclick="showSpinner()">Abbrechen</button>
}
</div>
<div class="ml-3 bd-highlight">
<button type="button" class="btn btn-primary" id="mb-create-button" onclick="submitMultiBookingForm()">Anlegen</button>
</div>
</div>
}
</div>
</div>
<!-- (Mehrfachbuchung) Hilfeplan- und Gruppenauswahl Popup -->
<div class="modal" data-backdrop="static" tabindex="-1" role="dialog" id="multi-booking-popup">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Gruppen und Hilfepläne für Gruppenbuchung</h5>
<button type="button" class="close" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<div class="modal-body">
<nav class="nav nav-pills nav-fill">
<a class="nav-item nav-link active" href="#multi-booking-supportconcepts" data-toggle="tab" role="tab">Hilfepläne</a>
<a class="nav-item nav-link" href="#multi-booking-groups" data-toggle="tab" role="tab">Gruppen</a>
</nav>
<div class="tab-content">
<div class="tab-pane show active" role="tabpanel" id="multi-booking-supportconcepts">
<ul class="list-group">
@foreach(var cb2Sc in Model.MultiBookingSupportConceptListObjects)
{
<li class="list-group-item">
@{
var timeSpanColorClass2 = cb2Sc.IsAboutToExpire ? "text-bewo-is-about-to-expire" : cb2Sc.ExpiresInThreeMonthsOrLess ? "text-bewo-expires-in-three-months" : "text-dark";
var wasSuccessful = long.TryParse(cb2Sc.CostBearer2SupportConceptOid, out var cb2ScOid);
var checkedValue = wasSuccessful ? Model.MultiBookingSelectedConceptCostBearerRelations.Any(a => a.CostBearer2SupportConceptOid.Equals(cb2ScOid)) : wasSuccessful;
}
<div class="custom-control custom-checkbox custom-control-inline">
<input type="checkbox"
@{ if(checkedValue) { @Html.Raw("checked=\"checked\"") ; } }
class="custom-control-input" id="mb-cb2sc-checkbox-@cb2Sc.CostBearer2SupportConceptOid" onchange="addCostBearer2SupportConceptsToMultiBooking()" name="mb-cb2sc-checkbox-@cb2Sc.CostBearer2SupportConceptOid" value="@cb2Sc.CostBearer2SupportConceptOid">
<label for="mb-cb2sc-checkbox-@cb2Sc.CostBearer2SupportConceptOid" class="custom-control-label">
<span class="justify-content-between mb-1 text-dark text-left">
@cb2Sc.NameAndDateOfBirth
</span>
<br />
<span class="mb-1 text-left @timeSpanColorClass2">
@cb2Sc.SupportConceptTimeSpan
</span>
</label>
</div>
</li>
}
</ul>
</div>
<div class="tab-pane show" role="tabpanel" id="multi-booking-groups">
<ul class="list-group">
@foreach(var group in Model.GroupOfPeopleListItems)
{
<li class="list-group-item">
@{
long groupOid;
var wasSuccessful = long.TryParse(group.Value, out groupOid);
var shouldBeChecked = wasSuccessful ? Model.MultiBookingSelectedGroupOfPeopleOids.Contains(groupOid) : wasSuccessful;
var attribute = shouldBeChecked ? "checked=\"checked\"" : string.Empty;
}
<div class="custom-control custom-checkbox custom-control-inline">
<input type="checkbox" @attribute class="custom-control-input" id="mb-group-checkbox-@group.Value" value="@group.Value" onchange="addCostBearer2SupportConceptsToMultiBooking()" />
<label for="mb-group-checkbox-@group.Value" class="custom-control-label">
@group.Text
</label>
</div>
</li>
}
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- (Mehrfachbuchung) Mitarbeiterauswahl Popup -->
<div class="modal" tabindex="-1" role="dialog" id="multi-booking-employee-selection-popup">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Mitarbeiter hinzufügen</h5>
<button type="button" class="close" data-dismiss="modal" onclick="resetSearch('mb-employee-search-input', 'employee-text')">
<span>&times;</span>
</button>
</div>
<div class="modal-body">
<div class="input-group mb-3">
<input class="form-control w-100" type="text" id="mb-employee-search-input" placeholder="Suchen..." oninput="listSearchOnChange('mb-employee-search-input', 'employee-text', 'employee-name-label')" />
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="button" onclick="resetSearch('mb-employee-search-input', 'employee-text')">
<span class="fas fa-times-circle"></span>
</button>
</div>
</div>
@foreach(var employee in Model.EmployeesForGroupAndMultiBooking)
{
var checkedValue = Model.MultiBookingSelectedEmployees.Contains(employee) ? "checked=\"checked\"" : string.Empty;
<div class="custom-control custom-checkbox employee-text">
<input type="checkbox" @checkedValue class="custom-control-input" id="multi-employee-@employee.EmployeeOid" onchange="addEmployeeToMultiBooking()" value="@employee.EmployeeOid" />
<label for="multi-employee-@employee.EmployeeOid" class="custom-control-label employee-name-label">@employee.DetailDescription</label>
</div>
}
</div>
</div>
</div>
</div>