{"version":3,"file":"app-425961a4.f584a1446b2fc034d810.bundle.js","mappings":"AAGA","sources":["webpack://lernplattform-admin-frontend/./src/resources/dialogs/email-prompt/email-prompt.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/from-to-dates-dialog/from-to-dates-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/invitation-create-dialog/invitation-create-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/layout-container-preview-dialog/layout-container-preview-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/lecture-settings-dialog/lecture-settings-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/manage-attendance-dialog/manage-attendance-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/manage-attendance-intervals-dialog/manage-attendance-intervals-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/media-library-upload-dialog/media-library-upload-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/media-select-dialog/media-select-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/media-share-dialog/media-share-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/media-share-table-dialog/media-share-table-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/operation-status-dialog/operation-status-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/pdf-generated-dialog/pdf-generated-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/picture-preview-dialog/picture-preview-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/points-explanation-dialog/points-explanation-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/provider-media-select-dialog/provider-media-select-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/question-preview-dialog/question-preview-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/questions-import-dialog/questions-import-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/quiz-template-create-dialog/quiz-template-create-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/quiz-template-edit-dialog/quiz-template-edit-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/scorm-preview-dialog/scorm-preview-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/send-message-to-students-dialog/send-message-to-students-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/show-distinar-qr-code-dialog/show-distinar-qr-code-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/show-students-dialog/show-students-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/single-rating-dialog/single-rating-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/start-quick-quiz-dialog/start-quick-quiz-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/start-template-quiz-dialog/start-template-quiz-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/student-import-dialog/student-import-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/transfer-invitation-warning-dialog/transfer-invitation-warning-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/video-preview-dialog/video-preview-dialog.html","webpack://lernplattform-admin-frontend/./src/resources/dialogs/email-prompt/email-prompt.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/from-to-dates-dialog/from-to-dates-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/invitation-create-dialog/invitation-create-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/layout-container-preview-dialog/layout-container-preview-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/lecture-settings-dialog/lecture-settings-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/manage-attendance-dialog/manage-attendance-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/manage-attendance-intervals-dialog/manage-attendance-intervals-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/media-library-upload-dialog/media-library-upload-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/media-select-dialog/media-select-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/media-share-dialog/media-share-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/media-share-table-dialog/media-share-table-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/operation-status-dialog/operation-status-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/pdf-generated-dialog/pdf-generated-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/picture-preview-dialog/picture-preview-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/points-explanation-dialog/points-explanation-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/provider-media-select-dialog/provider-media-select-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/question-preview-dialog/question-preview-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/questions-import-dialog/questions-import-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/quiz-template-create-dialog/quiz-template-create-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/quiz-template-edit-dialog/quiz-template-edit-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/scorm-preview-dialog/scorm-preview-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/send-message-to-students-dialog/send-message-to-students-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/show-distinar-qr-code-dialog/show-distinar-qr-code-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/show-students-dialog/show-students-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/single-rating-dialog/single-rating-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/start-quick-quiz-dialog/start-quick-quiz-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/start-template-quiz-dialog/start-template-quiz-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/student-import-dialog/student-import-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/transfer-invitation-warning-dialog/transfer-invitation-warning-dialog.ts","webpack://lernplattform-admin-frontend/./src/resources/dialogs/video-preview-dialog/video-preview-dialog.ts"],"sourcesContent":["// Module\nvar code = \"<template> <form submit.trigger=\\\"ok()\\\"> <div class=\\\"card\\\"> <div if.to-view=\\\"model.titleTk\\\" class=\\\"card-header\\\"> <h1 class=\\\"card-title\\\">${model.titleTk | t}</h1> </div> <div class=\\\"card-body\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\">${model.labelTk | t}</label> <input class=\\\"form-control\\\" type=\\\"email\\\" required=\\\"true\\\" t.to-view=\\\"'[placeholder]'+model.placeholderTk\\\" value.two-way=\\\"value\\\" attach-focus> </div> </div> <div class=\\\"card-footer text-right\\\"> <button type=\\\"submit\\\" class=\\\"btn btn-primary\\\" t=\\\"globals.save\\\"></button> <button class=\\\"btn btn-secondary\\\" click.trigger=\\\"controller.cancel()\\\" t=\\\"globals.cancel\\\"></button> </div> </div> </form> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <form submit.trigger=\\\"ok()\\\"> <div class=\\\"card\\\"> <div class=\\\"card-header\\\"> <h2 class=\\\"card-title\\\" t=\\\"dialogs.fromToDates.title\\\"></h2> </div> <div class=\\\"card-body\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"globals.from\\\"></label> <date-input value.two-way=\\\"value.fromDate\\\" click.trigger=\\\"resetErrorTkByKey('from')\\\" is-invalid.to-view=\\\"!!errorTks.from\\\" mode=\\\"date\\\"></date-input> <div if.to-view=\\\"errorTks.fromDate\\\" class=\\\"invalid-feedback d-flex\\\" t=\\\"${errorTks.fromDate}\\\"></div> </div> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"globals.to\\\"></label> <date-input value.two-way=\\\"value.toDate\\\" click.trigger=\\\"resetErrorTkByKey('to')\\\" is-invalid.to-view=\\\"!!errorTks.to\\\" mode=\\\"date\\\"></date-input> <div if.to-view=\\\"errorTks.toDate\\\" class=\\\"invalid-feedback d-flex\\\" t=\\\"${errorTks.toDate}\\\"></div> </div> </div> <div class=\\\"card-footer text-right\\\"> <button type=\\\"submit\\\" class=\\\"btn btn-primary\\\" t=\\\"globals.select\\\"></button> <button class=\\\"btn btn-secondary\\\" click.trigger=\\\"controller.cancel()\\\" t=\\\"globals.cancel\\\"></button> </div> </div> </form> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"invitation-create-dialog\\\"> <div class=\\\"card invitation-create-dialog__card\\\"> <div class=\\\"card-header\\\"> <div class=\\\"flex-column align-items-start\\\"> <h3 class=\\\"card-title\\\" t=\\\"dialogs.invitationCreate.createInvitation\\\"></h3> <small class=\\\"mb-0 ${ freeCodesUntilFormatted ? 'text-success' : 'text-danger' }\\\" t=\\\"dialogs.invitationCreate.${ freeCodesUntilFormatted ? 'freeUntil' : 'chargeable' }\\\" t-params.to-view=\\\"{ date: freeCodesUntilFormatted }\\\"></small> </div> <info-icon t=\\\"[info-text]dialogs.invitationCreate.infoText\\\" class=\\\"ml-auto\\\"></info-icon> </div> <div class=\\\"card-body\\\"> <div if.to-view=\\\"value.previouslyAddedData\\\" class=\\\"row\\\"> <div class=\\\"col-md-12\\\"> <div class=\\\"alert alert-info\\\"> <label class=\\\"form-label\\\" t=\\\"dialogs.invitationCreate.previouslyAdded\\\"></label> <ul class=\\\"list-unstyled mb-0\\\"> <li>${value.previouslyAddedData.firstname}</li> <li>${value.previouslyAddedData.lastname}</li> <li>${value.previouslyAddedData.email}</li> <li>${dateService.formatDate(value.previouslyAddedData.birthdate)}</li> <li repeat.for=\\\"courseAndCourseGroup of value.previouslyAddedData.courseAndCourseGroups\\\">${courseAndCourseGroup.courseTitle} - ${courseAndCourseGroup.courseGroupName}</li> </ul> </div> </div> </div> <div if.to-view=\\\"(value.metadata.email || value.metadata.phoneNumber) && !existingUserApplied && existingUser\\\" class=\\\"row\\\"> <div class=\\\"col-md-12\\\"> <div class=\\\"alert alert-info\\\"> <label if.to-view=\\\"checkForExistingUserInProgress\\\" class=\\\"form-label\\\" t=\\\"dialogs.invitationCreate.checkForExistingUserInProgress\\\"></label> <button if.to-view=\\\"!checkForExistingUserInProgress && existingUser\\\" class=\\\"btn btn-primary\\\" click.trigger=\\\"applyExistingUser()\\\" t=\\\"dialogs.invitationCreate.applyExistingUser\\\"></button> </div> </div> </div> <h5 class=\\\"required-label\\\" t=\\\"dialogs.invitationCreate.contact\\\"></h5> <div class=\\\"row\\\"> <div class.to-view=\\\"inviteBySmsEnabled ? 'col-md-6' : 'col-md-12'\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"dialogs.invitationCreate.email\\\"></label> <input type=\\\"mail\\\" ref=\\\"inputEmailDomElement\\\" disabled.to-view=\\\"!!model.studentId\\\" blur.trigger=\\\"checkForExistingUserByMail()\\\" input.trigger=\\\"handleEmailInput()\\\" class=\\\"form-control ${ errorTks.email ? 'is-invalid' : '' }\\\" value.two-way=\\\"value.metadata.email\\\"> <div if.to-view=\\\"errorTks.email\\\" class=\\\"invalid-feedback\\\" t=\\\"${errorTks.email}\\\"></div> </div> </div> <div if.to-view=\\\"inviteBySmsEnabled\\\" class=\\\"col-md-6\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"dialogs.invitationCreate.mobileNumber\\\"></label> <phone-input ref=\\\"inputPhoneNumberDomElement\\\" calling-codes.to-view=\\\"availableCallingCodes\\\" disabled.to-view=\\\"!!model.studentId\\\" blur.trigger=\\\"checkForExistingUserByPhoneNumber()\\\" input.trigger=\\\"handlePhoneInput()\\\" is-invalid.to-view=\\\"!!errorTks.phoneNumber\\\" placeholder-tk=\\\"dialogs.invitationCreate.mobileNumber\\\" value.two-way=\\\"value.metadata.phoneNumber\\\"></phone-input> <div if.to-view=\\\"errorTks.phoneNumber\\\" class=\\\"invalid-feedback\\\" t=\\\"${errorTks.phoneNumber}\\\"></div> </div> </div> </div> <template if.to-view=\\\"inviteBySmsEnabled\\\"> <div class=\\\"row mb-4\\\"> <div class=\\\"col-md-12\\\"> <label class=\\\"form-label\\\" t=\\\"dialogs.invitationCreate.importantNotificationsTitle\\\"></label> <small class=\\\"form-text text-muted\\\" t=\\\"dialogs.invitationCreate.importantNotificationsDescription\\\"></small> </div> </div> <div class=\\\"row mb-5\\\"> <div class=\\\"col-md-6\\\"> <div class=\\\"custom-control custom-radio\\\"> <input class=\\\"custom-control-input\\\" type=\\\"radio\\\" disabled.to-view=\\\"!value.metadata.email\\\" id=\\\"invitationCreateDialogImportantNotificationsRadio1\\\" name=\\\"invitationCreateDialogImportantNotificationsRadio\\\" model.bind=\\\"NotificationMethod.Email\\\" checked.two-way=\\\"value.metadata.importantNotificationMethod\\\"> <label class=\\\"custom-control-label\\\" for=\\\"invitationCreateDialogImportantNotificationsRadio1\\\" t=\\\"dialogs.invitationCreate.email\\\"></label> </div> </div> <div class=\\\"col-md-6\\\"> <div class=\\\"custom-control custom-radio\\\"> <input class=\\\"custom-control-input\\\" type=\\\"radio\\\" disabled.to-view=\\\"!value.metadata.phoneNumber\\\" id=\\\"invitationCreateDialogImportantNotificationsRadio2\\\" name=\\\"invitationCreateDialogImportantNotificationsRadio\\\" model.bind=\\\"NotificationMethod.Sms\\\" checked.two-way=\\\"value.metadata.importantNotificationMethod\\\"> <label class=\\\"custom-control-label\\\" for=\\\"invitationCreateDialogImportantNotificationsRadio2\\\" t=\\\"dialogs.invitationCreate.mobileNumber\\\"></label> </div> </div> <div if.to-view=\\\"errorTks.importantNotificationMethod\\\" class=\\\"invalid-feedback d-block col-md-12\\\" t=\\\"${errorTks.importantNotificationMethod}\\\"></div> </div> </template> <hr class=\\\"mt-1 mb-5\\\"/> <h5 t=\\\"dialogs.invitationCreate.personalData\\\"></h5> <div class=\\\"row\\\"> <div class=\\\"col-md-6\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label required-label\\\" t=\\\"globals.firstname\\\"></label> <input type=\\\"text\\\" input.trigger=\\\"resetErrorTkByKey('firstname')\\\" class=\\\"form-control ${ errorTks.firstname ? 'is-invalid' : '' }\\\" value.two-way=\\\"value.metadata.firstname\\\"> <div if.to-view=\\\"errorTks.firstname\\\" class=\\\"invalid-feedback\\\" t=\\\"${errorTks.firstname}\\\"></div> </div> </div> <div class=\\\"col-md-6\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label required-label\\\" t=\\\"globals.lastname\\\"></label> <input type=\\\"text\\\" input.trigger=\\\"resetErrorTkByKey('lastname')\\\" class=\\\"form-control ${ errorTks.lastname ? 'is-invalid' : '' }\\\" value.two-way=\\\"value.metadata.lastname\\\"> <div if.to-view=\\\"errorTks.lastname\\\" class=\\\"invalid-feedback\\\" t=\\\"${errorTks.lastname}\\\"></div> </div> </div> </div> <div class=\\\"row\\\"> <div class=\\\"col-md-6\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"globals.state\\\"></label> <select focus.trigger=\\\"resetErrorTkByKey('state')\\\" class=\\\"custom-select ${ errorTks.state ? 'is-invalid' : '' }\\\" value.two-way=\\\"value.metadata.address.state\\\"> <option model.bind=\\\"''\\\" t=\\\"globals.select\\\"></option> <option repeat.for=\\\"state of states\\\" model.bind=\\\"state.key\\\" t=\\\"${state.nameTk}\\\"> </option> </select> <div if.to-view=\\\"errorTks.state\\\" class=\\\"invalid-feedback\\\" t=\\\"${errorTks.state}\\\"></div> </div> </div> <div class=\\\"col-md-6\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"globals.birthdate\\\"></label> <date-input click.trigger=\\\"resetErrorTkByKey('birthdate')\\\" mode=\\\"date\\\" can-clear.to-view=\\\"true\\\" value.two-way=\\\"value.metadata.birthdate\\\" is-invalid.to-view=\\\"!!errorTks.birthdate\\\"></date-input> <div if.to-view=\\\"errorTks.birthdate\\\" class=\\\"invalid-feedback d-block\\\" t=\\\"${errorTks.birthdate}\\\"></div> </div> </div> </div> <hr class=\\\"mt-1 mb-5\\\"/> <h5 t=\\\"globals.courses\\\"></h5> <course-and-group-select class=\\\"mt-2\\\" exam-date.two-way=\\\"examDate\\\" unavailable-course-ids.to-view=\\\"unavailableCourseIds\\\" add-course-and-group-clicked.trigger=\\\"addCourseAndGroup($event)\\\" error-tk.two-way=\\\"errorTks.courseGroup\\\"></course-and-group-select> <label class=\\\"form-label mt-3\\\" t=\\\"dialogs.invitationCreate.addedCourses\\\"></label> <div class=\\\"invitation-create-dialog__course-and-group-list-scrollbox\\\"> <course-and-group-list-item repeat.for=\\\"selectedCourseAndGroup of value.selectedCoursesAndGroups\\\" class=\\\"mt-2\\\" remove-course-and-group-clicked.trigger=\\\"removeCourseAndGroup($event)\\\" course.to-view=\\\"selectedCourseAndGroup.course\\\" course-group.to-view=\\\"selectedCourseAndGroup.courseGroup\\\"></course-and-group-list-item> <small if.to-view=\\\"!value.selectedCoursesAndGroups.length\\\" class=\\\"form-text text-muted\\\" t=\\\"dialogs.invitationCreate.noCoursesSelected\\\"></small> </div> </div> <div class=\\\"card-footer\\\"> <div class=\\\"row\\\"> <div class=\\\"col-md-5 d-flex align-items-end\\\"> <div if.to-view=\\\"!model.studentId\\\" class=\\\"form-group mb-0\\\"> <label class=\\\"custom-control custom-checkbox custom-control-inline\\\"> <input type=\\\"checkbox\\\" class=\\\"custom-control-input\\\" checked.bind=\\\"createAdditionalInvitations\\\"> <span class=\\\"custom-control-label text-nowrap\\\" t=\\\"dialogs.invitationCreate.createAdditionalInvitations\\\"></span> </label> </div> </div> <div class=\\\"col-md-7 text-right\\\"> <button-standard class=\\\"d-inline-block\\\" disabled.to-view=\\\"!value.selectedCoursesAndGroups.length || loading\\\" t=\\\"[btnText]dialogs.invitationCreate.sendInvitation\\\" click.delegate=\\\"createInvitation()\\\" btn-color=\\\"primary\\\"></button-standard> <button-standard t=\\\"[btnText]globals.cancel\\\" class=\\\"d-inline-block\\\" click.trigger=\\\"value.previouslyAddedData ? ok() : cancel()\\\" btn-color=\\\"secondary\\\"></button-standard> </div> </div> </div> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <div class=\\\"layout-container-preview-dialog ${ hasIntrinsicSize ? 'layout-container-preview-dialog--intrinsic' : '' } ${ isCard && hasVerticalLayout ? 'layout-container-preview-dialog--vertical-card' : '' } ${ isCard && !hasVerticalLayout ? 'layout-container-preview-dialog--horizontal-card' : '' }\\\"> <info-icon class=\\\"layout-container-preview-dialog__info-message\\\" t=\\\"[info-text]pages.content-editor.previewInfoMessage\\\"></info-icon> <preview-layout-container if.to-view=\\\"!isCard\\\" class=\\\"layout-container-preview-dialog__layout-container\\\" layout-container.to-view=\\\"layoutContainer\\\" block.to-view=\\\"block\\\" click.trigger=\\\"close()\\\"></preview-layout-container> <div class=\\\"layout-container-preview-dialog__layout-container\\\"> <preview-clipboard-card-layout-container if.to-view=\\\"isCard\\\" layout-container-id.to-view=\\\"layoutContainer.id\\\" click.trigger=\\\"close()\\\"></preview-clipboard-card-layout-container> </div> </div> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"lecture-settings-dialog\\\"> <form submit.trigger=\\\"ok()\\\" novalidate> <div class=\\\"card\\\"> <div class=\\\"card-header\\\"> <span t=\\\"dialogs.lectureSettings.title\\\"></span> </div> <div class=\\\"card-body lecture-settings-dialog__content\\\"> <div class=\\\"lecture-settings-dialog__side-bar\\\"> <div repeat.for=\\\"item of settingsAreaItems\\\" class=\\\"lecture-settings-dialog__settings-area-item ${ item.area === selectedSettingsArea ? 'lecture-settings-dialog__settings-area-item--selected' : '' }\\\" click.delegate=\\\"selectSettingsArea(item)\\\"> <span t=\\\"${item.textTk}\\\"></span> <i class=\\\"fe ${item.icon}\\\"></i> </div> </div> <div class=\\\"lecture-settings-dialog__settings\\\"> <div if.to-view=\\\"selectedSettingsArea === SettingsArea.General\\\" class=\\\"lecture-settings-dialog__general-settings\\\"> <div class=\\\"form-group col-12\\\"> <div class=\\\"row\\\"> <div class=\\\"form-group col-12\\\"> <label class=\\\"form-label\\\" t=\\\"globals.date\\\"></label> <date-input value.two-way=\\\"value.plannedDateFrom\\\" is-invalid.to-view=\\\"missingDate\\\" mode=\\\"date\\\"></date-input> <div if.to-view=\\\"missingDate\\\" class=\\\"text-danger small\\\" t=\\\"dialogs.lectureSettings.missingDate\\\"></div> </div> </div> <div class=\\\"row\\\"> <div class=\\\"form-group col-6\\\"> <label class=\\\"form-label\\\" t=\\\"globals.from\\\"></label> <date-input mode=\\\"time\\\" value.two-way=\\\"eventStartTimeString\\\"></date-input> </div> <div class=\\\"form-group col-6\\\"> <label class=\\\"form-label\\\" t=\\\"globals.to\\\"></label> <date-input mode=\\\"time\\\" value.two-way=\\\"eventEndTimeString\\\" is-invalid.to-view=\\\"endTimeBeforeStartTime\\\"></date-input> <div if.to-view=\\\"endTimeBeforeStartTime\\\" class=\\\"text-danger small\\\" t=\\\"utils.validation.endTimeBeforeStartTime\\\"></div> </div> </div> <div class=\\\"row\\\"> <div class=\\\"form-group col-12\\\"> <label class=\\\"form-label\\\" t=\\\"dialogs.lectureSettings.labels.title\\\"></label> <input type=\\\"text\\\" required value.two-way=\\\"value.title\\\" class=\\\"form-control\\\" maxlength=\\\"255\\\"> </div> </div> <div class=\\\"row\\\"> <div class=\\\"form-group col-12\\\"> <label class=\\\"form-label\\\" t=\\\"dialogs.lectureSettings.labels.text\\\"></label> <textarea type=\\\"text\\\" required value.two-way=\\\"value.description\\\" class=\\\"form-control lecture-settings-dialog__textarea\\\"></textarea> </div> </div> </div> </div> <div if.to-view=\\\"selectedSettingsArea === SettingsArea.Devices\\\"> <audio-input-select selected.two-way=\\\"selectedMicrophone\\\" disabled.to-view=\\\"!hasActiveMeeting\\\"></audio-input-select> <video-input-select selected.two-way=\\\"selectedCamera\\\" disabled.to-view=\\\"!hasActiveMeeting\\\"></video-input-select> <audio-output-select if.to-view=\\\"supportsOutputDevice\\\" selected.two-way=\\\"selectedAudioOutput\\\" disabled.to-view=\\\"!hasActiveMeeting\\\"></audio-output-select> </div> </div> </div> <div class=\\\"card-footer text-right\\\"> <button type=\\\"submit\\\" class=\\\"btn btn-primary\\\" t=\\\"globals.save\\\"></button> <button class=\\\"btn btn-secondary\\\" click.trigger=\\\"controller.cancel()\\\" t=\\\"globals.cancel\\\"></button> </div> </div> </form> <loading-overlay visible.to-view=\\\"loading\\\"></loading-overlay> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <form submit.trigger=\\\"ok()\\\"> <div class=\\\"card\\\"> <div class=\\\"card-header\\\"> <div class=\\\"card-title\\\" t=\\\"dialogs.manageAttendance.title\\\" t-params.to-view=\\\"{nickname: model.user.nickname}\\\"></div> </div> <div class=\\\"card-body\\\"> <div class=\\\"row\\\"> <div class=\\\"col-md-12\\\"> <div class=\\\"form-group\\\"> <div class=\\\"form-group mb-0\\\"> <h3 class=\\\"form-label\\\" t=\\\"dialogs.manageAttendance.attended\\\"></h3> </div> <label class=\\\"custom-control custom-checkbox custom-control-inline form-check\\\"> <input type=\\\"checkbox\\\" class=\\\"custom-control-input form-check-input\\\" checked.bind=\\\"value.attended\\\"> <span class=\\\"custom-control-label\\\" t=\\\"dialogs.manageAttendance.markStudentAttended\\\"></span> </label> </div> <div class=\\\"form-group\\\"> <div class=\\\"form-group mb-0\\\"> <h3 class=\\\"form-label\\\" t=\\\"dialogs.manageAttendance.note\\\"></h3> </div> <div class=\\\"form-group\\\"> <textarea type=\\\"text\\\" attach-focus class=\\\"form-control\\\" value.two-way=\\\"value.note\\\"></textarea> </div> </div> </div> </div> </div> <div class=\\\"card-footer text-right\\\"> <button type=\\\"submit\\\" class=\\\"btn btn-primary\\\" t=\\\"globals.save\\\"></button> <button class=\\\"btn btn-secondary\\\" click.trigger=\\\"controller.cancel()\\\" t=\\\"globals.cancel\\\"></button> </div> </div> </form> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <form> <div class=\\\"card\\\"> <div class=\\\"card-header justify-content-between\\\"> <h3 class=\\\"card-title\\\" t=\\\"dialogs.manageAttendanceIntervals.title\\\" t-params.to-view=\\\"{nickname: model.user.nickname}\\\"></h3> <button class=\\\"btn btn-secondary text-right ml-4\\\" click.trigger=\\\"ok()\\\"><i class=\\\"fe fe-x\\\"></i></button> </div> <div class=\\\"card-body\\\"> <div class=\\\"row\\\"> <div class=\\\"col-md-12\\\"> <div class=\\\"alert alert-info\\\"> <div class=\\\"form-group mb-0\\\"> <h3 class=\\\"form-label\\\" t=\\\"dialogs.manageAttendanceIntervals.titleAndDate\\\" t-params.to-view=\\\"{title: model.event.title, date: dateService.formatDate(model.event.plannedDateFrom)}\\\"></h3> </div> <p class=\\\"my-0\\\" t=\\\"dialogs.manageAttendanceIntervals.plannedStart\\\" t-params.to-view=\\\"{plannedTimeFrom: dateService.formatTime(model.event.plannedDateFrom)}\\\"></p> <p class=\\\"my-0\\\" t=\\\"dialogs.manageAttendanceIntervals.plannedEnd\\\" t-params.to-view=\\\"{plannedTimeTo: dateService.formatTime(model.event.plannedDateTo)}\\\"></p> <div if.to-view=\\\"model.event.actualDateTo && model.event.actualDateFrom\\\"> <p class=\\\"my-0\\\" t=\\\"dialogs.manageAttendanceIntervals.actualStart\\\" t-params.to-view=\\\"{actualTimeFrom: dateService.formatTime(model.event.actualDateFrom)}\\\"></p> <p class=\\\"my-0\\\" t=\\\"dialogs.manageAttendanceIntervals.actualEnd\\\" t-params.to-view=\\\"{actualTimeTo: dateService.formatTime(model.event.actualDateTo)}\\\"></p> </div> </div> </div> </div> <div if.to-view=\\\"attendanceIntervals.length\\\" class=\\\"row mt-4\\\"> <div class=\\\"col-md-12\\\"> <h3 class=\\\"form-label\\\" t=\\\"dialogs.manageAttendanceIntervals.editAttendance\\\"></h3> </div> </div> <div if.to-view=\\\"attendanceIntervals.length\\\" class=\\\"row\\\"> <div class=\\\"col-md-5\\\"> <h3 class=\\\"form-label\\\" t=\\\"dialogs.manageAttendanceIntervals.from\\\"></h3> </div> <div class=\\\"col-md-5\\\"> <h3 class=\\\"form-label\\\" t=\\\"dialogs.manageAttendanceIntervals.to\\\"></h3> </div> </div> <div class=\\\"row\\\" repeat.for=\\\"interval of attendanceIntervals\\\"> <div class=\\\"col-md-5\\\"> <div class=\\\"form-group\\\"> <date-input mode.to-view=\\\"'time'\\\" minute-step.to-view=\\\"1\\\" click.trigger=\\\"resetErrorTks()\\\" is-invalid.to-view=\\\"!!errorTks[`editAttendanceFrom${interval.id}`]\\\" value.two-way=\\\"interval.from\\\"></date-input> <div if.to-view=\\\"errorTks[`editAttendanceFrom${interval.id}`]\\\" class=\\\"invalid-feedback d-block\\\" t=\\\"${errorTks[`editAttendanceFrom${interval.id}`]}\\\"></div> </div> </div> <div class=\\\"col-md-5\\\"> <div class=\\\"form-group\\\"> <date-input mode.to-view=\\\"'time'\\\" minute-step.to-view=\\\"1\\\" click.trigger=\\\"resetErrorTks()\\\" is-invalid.to-view=\\\"!!errorTks[`editAttendanceTo${interval.id}`]\\\" value.two-way=\\\"interval.to\\\"></date-input> <div if.to-view=\\\"errorTks[`editAttendanceTo${interval.id}`]\\\" class=\\\"invalid-feedback d-block\\\" t=\\\"${errorTks[`editAttendanceTo${interval.id}`]}\\\"></div> </div> </div> <div class=\\\"col-md-2\\\"> <div class=\\\"form-group\\\"> <button disabled.to-view=\\\"!!indicatorService.waitingClients\\\" click.trigger=\\\"deleteAttendanceInterval(interval.id)\\\" class=\\\"btn btn-outline-danger\\\"><i class=\\\"fe fe-trash\\\"></i></button> <button disabled.to-view=\\\"!!indicatorService.waitingClients\\\" click.trigger=\\\"editAttendanceInterval(interval)\\\" class=\\\"btn btn-outline-primary\\\"><i class=\\\"fe fe-save\\\"></i></button> </div> </div> </div> <div class=\\\"row\\\"> <div class=\\\"col-md-12\\\"> <h3 class=\\\"form-label\\\" t=\\\"dialogs.manageAttendanceIntervals.addAttendance\\\"></h3> </div> </div> <div class=\\\"row\\\"> <div class=\\\"col-md-5\\\"> <div class=\\\"form-group\\\"> <date-input mode.to-view=\\\"'time'\\\" minute-step.to-view=\\\"1\\\" click.trigger=\\\"resetErrorTks()\\\" is-invalid.to-view=\\\"!!errorTks.addAttendanceFrom\\\" value.two-way=\\\"newInterval.from\\\"></date-input> <div if.to-view=\\\"errorTks.addAttendanceFrom\\\" class=\\\"invalid-feedback d-block\\\" t=\\\"${errorTks.addAttendanceFrom}\\\"></div> </div> </div> <div class=\\\"col-md-5\\\"> <div class=\\\"form-group\\\"> <date-input mode.to-view=\\\"'time'\\\" minute-step.to-view=\\\"1\\\" click.trigger=\\\"resetErrorTks()\\\" is-invalid.to-view=\\\"!!errorTks.addAttendanceTo\\\" value.two-way=\\\"newInterval.to\\\"></date-input> <div if.to-view=\\\"errorTks.addAttendanceTo\\\" class=\\\"invalid-feedback d-block\\\" t=\\\"${errorTks.addAttendanceTo}\\\"></div> </div> </div> <div class=\\\"col-md-2\\\"> <div class=\\\"form-group\\\"> <button disabled.to-view=\\\"!!indicatorService.waitingClients\\\" click.trigger=\\\"addAttendanceInterval()\\\" class=\\\"btn btn-outline-primary\\\"><i class=\\\"fe fe-plus\\\"></i></button> </div> </div> </div> </div> </div> </form> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <form submit.trigger=\\\"ok()\\\"> <div class=\\\"card\\\"> <div class=\\\"card-header\\\"> <h1 class=\\\"card-title\\\" t=\\\"dialogs.mediaLibraryUpload.title\\\"></h1> <button-standard class=\\\"ml-auto\\\" click.trigger=\\\"cancel()\\\" icon-name=\\\"System/Tabler/X\\\" btn-type=\\\"editor-flat\\\" btn-size=\\\"icon\\\" btn-color=\\\"danger\\\"></button-standard> </div> <div class=\\\"card-body\\\"> <div class=\\\"text-center mt-4\\\"> <label class=\\\"custom-control custom-checkbox custom-control-inline\\\"> <input type=\\\"checkbox\\\" class=\\\"custom-control-input\\\" checked.bind=\\\"providerSettings.overrideFiles\\\"> <span class=\\\"custom-control-label\\\" t=\\\"dialogs.mediaLibraryUpload.overrideFiles\\\"></span> </label> </div> </div> <div class=\\\"card-footer text-right\\\"> <button class=\\\"btn btn-primary\\\" type=\\\"submit\\\" t=\\\"dialogs.mediaLibraryUpload.importFiles\\\"></button> </div> </div> </form> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <div class=\\\"container\\\"> <gallery-widget selected.two-way=\\\"value\\\" ok-callback.call=\\\"ok()\\\" cancel-callback.call=\\\"cancel()\\\" preselected-media-type.to-view=\\\"model.preselectedMediaType\\\" preselected-media-id.to-view=\\\"model.preselectedMediaId\\\" show-media-type-filter.to-view=\\\"model.showMediaTypeFilter\\\" selected-media-type.to-view=\\\"model.selectedMediaType\\\"></gallery-widget> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"media-share-dialog\\\"> <div class=\\\"card media-share-dialog__card ${ isProvider ? 'media-share-dialog__card--smaller' : '' }\\\"> <div class=\\\"card-header justify-content-between\\\"> <h3 class=\\\"card-title\\\" t=\\\"dialogs.mediaShareDialog.title\\\"></h3> </div> <media-share-create-form class=\\\"px-5 pb-5 media-share-dialog__create-form\\\" is-provider.to-view=\\\"isProvider\\\" available-courses.to-view=\\\"availableCourses\\\" create-share.trigger=\\\"handleShareEntryCreated($event)\\\"></media-share-create-form> <div if.to-view=\\\"selectedCourses.length\\\" class=\\\"media-share-dialog__scrollbox\\\"> <ul class=\\\"list-group list-group-flush\\\"> <li repeat.for=\\\"course of selectedCourses\\\" class=\\\"px-5 list-group-item media-share-dialog__list-item\\\"> <media-share-edit-list-entry course.to-view=\\\"course\\\" is-provider.to-view=\\\"isProvider\\\" media-share-details.to-view=\\\"getMediaShareDetails(course)\\\" groups-changed.trigger=\\\"handleGroupsChanged($event)\\\" deleted.trigger=\\\"handleShareEntryDeleted($event)\\\"></media-share-edit-list-entry> </li> </ul> </div> <div class=\\\"card-footer text-right mt-auto\\\"> <button type=\\\"button\\\" disabled.to-view=\\\"!canSave\\\" click.delegate=\\\"ok()\\\" class=\\\"btn btn-primary\\\" t=\\\"dialogs.mediaShareDialog.okButtonLabel\\\"> </button> <button class=\\\"btn btn-secondary\\\" click.trigger=\\\"cancel()\\\" t=\\\"globals.cancel\\\"></button> </div> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <div class=\\\"card media-share-table-dialog__card\\\"> <div class=\\\"card-header\\\"> <h3 class=\\\"card-title\\\" t=\\\"globals.shares\\\"></h3> <button-standard class=\\\"ml-auto\\\" click.trigger=\\\"controller.cancel()\\\" icon-name=\\\"System/Tabler/X\\\" btn-type=\\\"outline\\\" btn-color=\\\"danger\\\"></button-standard> </div> <div class=\\\"card-body media-share-table-dialog__body\\\"> <media-share-table if.to-view=\\\"courseId\\\" for-tenant-courses-only.to-view=\\\"forTenantCoursesOnly\\\" for-overview-only.to-view=\\\"!forTenantCoursesOnly\\\" course-id.to-view=\\\"courseId\\\"></media-share-table> </div> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <div class=\\\"card operation-status-dialog__card\\\"> <div class=\\\"card-header\\\"> <h1 if.to-view=\\\"titleTk || title\\\" class=\\\"card-title\\\" t.to-view=\\\"titleTk || title\\\" t-params.to-view=\\\"titleParams\\\"></h1> <div if.to-view=\\\"subtitleTk || subtitle\\\" class=\\\"card-subtitle text-muted operation-status-dialog__header-subtitle\\\" t.to-view=\\\"subtitleTk || subtitle\\\" t-params.to-view=\\\"subtitleParams\\\"></div> <button-standard class=\\\"ml-auto\\\" click.trigger=\\\"close()\\\" icon-name=\\\"System/Tabler/X\\\" btn-type=\\\"outline\\\" btn-color=\\\"danger\\\"></button-standard> </div> <div class=\\\"card-body operation-status-dialog__card-body\\\"> <operation-status-list operation-context.to-view=\\\"operationContext\\\" return-values.from-view=\\\"value\\\"></operation-status-list> </div> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <form submit.trigger=\\\"handleSubmit()\\\"> <div class=\\\"card pdf-generated-dialog__card\\\"> <div class=\\\"card-header\\\"> <h3 class=\\\"card-title\\\" t=\\\"globals.actions\\\"></h3> </div> <navigation-tabs class=\\\"mt-4\\\" tabs.to-view=\\\"navigationTabs\\\"></navigation-tabs> <div if.to-view=\\\"activeTab === PdfGeneratedDialogTabs.Save\\\" class=\\\"card-body\\\"> <h5 class=\\\"pdf-generated-dialog__tab-title\\\" t=\\\"dialogs.pdfGenerated.saveToGallery\\\"></h5> <template if.to-view=\\\"isProvider\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"dialogs.pdfGenerated.saveForCourses\\\"></label> <multi-select-combo-box selected-items-changed.trigger=\\\"handleSelectedCoursesChanged($event)\\\" total-items.to-view=\\\"courses\\\" label-property-name=\\\"title\\\" selected-items.to-view=\\\"selectedCourses\\\"></multi-select-combo-box> </div> <div class=\\\"form-group\\\"> <button-lightswitch value.to-view=\\\"shareAfterSaveToGallery\\\" click.trigger=\\\"toggleShareAfterSaveToGallery()\\\" theme=\\\"admin\\\" t=\\\"[label]dialogs.pdfGenerated.shareAfterSaveToGallery\\\"> </button-lightswitch> </div> </template> <template else> <div class=\\\"form-group\\\"> <button-lightswitch value.to-view=\\\"saveToGallery\\\" click.trigger=\\\"toggleSaveToGallery()\\\" theme=\\\"admin\\\" t=\\\"[label]dialogs.pdfGenerated.saveToGallery\\\"> </button-lightswitch> </div> <div if.to-view=\\\"saveToGallery\\\" class=\\\"form-group\\\"> <button-lightswitch value.to-view=\\\"shareAfterSaveToGallery\\\" click.trigger=\\\"toggleShareAfterSaveToGallery()\\\" theme=\\\"admin\\\" t=\\\"[label]dialogs.pdfGenerated.shareAfterSaveToGallery\\\"> </button-lightswitch> </div> </template> </div> <div if.to-view=\\\"activeTab === PdfGeneratedDialogTabs.Download\\\" class=\\\"card-body mt-4 mb-4 d-flex align-items-center justify-content-center\\\"> <button-standard click.delegate=\\\"handleDownloadClicked()\\\" class=\\\"mb-2 d-inline-block\\\" t=\\\"[btnText]dialogs.pdfGenerated.downloadPdf\\\" icon-name=\\\"System/Tabler/Download\\\" btn-color=\\\"primary\\\"></button-standard> </div> <div if.to-view=\\\"activeTab === PdfGeneratedDialogTabs.Details\\\" class=\\\"card-body\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"globals.title\\\"></label> <div class=\\\"input-group\\\"> <input type=\\\"text\\\" maxlength=\\\"255\\\" class=\\\"form-control\\\" value.two-way=\\\"title\\\"> </div> </div> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"globals.filename\\\"></label> <input type=\\\"text\\\" maxlength=\\\"255\\\" class=\\\"form-control\\\" value.two-way=\\\"filename\\\"> </div> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"globals.description\\\"></label> <textarea class=\\\"form-control\\\" maxlength=\\\"200\\\" value.two-way=\\\"description\\\" rows=\\\"3\\\"></textarea> </div> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"elements.gallery.addTags\\\"></label> <text-tags-widget tags.two-way=\\\"tags\\\"></text-tags-widget> </div> </div> <div class=\\\"card-footer pdf-generated-dialog__footer\\\"> <span class=\\\"pdf-generated-dialog__footer-error\\\" t.to-view=\\\"offerOverwrite ? 'dialogs.pdfGenerated.offerOverwrite' : ''\\\"></span> <button type=\\\"submit\\\" class=\\\"btn btn-primary\\\" disabled.to-view=\\\"!uploadPossible\\\" t.to-view=\\\"offerOverwrite ? 'dialogs.pdfGenerated.overwrite' : 'globals.save'\\\"></button> <button class=\\\"btn btn-secondary\\\" click.trigger=\\\"cancel()\\\" t=\\\"globals.cancel\\\"></button> </div> </div> </form> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <div class=\\\"card picture-preview-dialog\\\"> <div class=\\\"card-header\\\"> <div class=\\\"card-title\\\">${model.picture.title}</div> <div class=\\\"card-options\\\"> <button class=\\\"btn btn-sm\\\" click.delegate=\\\"ok()\\\"><i class=\\\"fe fe-x text-secondary\\\"></i></button> </div> </div> <div class=\\\"card-img\\\"> <img src.to-view=\\\"model.picture.url\\\" class=\\\"picture-preview-dialog__image\\\"> </div> </div> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <div class=\\\"card\\\"> <div class=\\\"card-header\\\"> <h3 class=\\\"card-title\\\" t=\\\"dialogs.pointsExplanation.title\\\"></h3> <button-standard class=\\\"ml-auto\\\" click.trigger=\\\"controller.cancel()\\\" icon-name=\\\"System/Tabler/X\\\" btn-type=\\\"outline\\\" btn-color=\\\"danger\\\"></button-standard> </div> <div class=\\\"card-body\\\"> <div class=\\\"row\\\"> <div class=\\\"col-md-12\\\"> <points-explanation training-questions-total.to-view=\\\"model.trainingQuestionsTotal\\\" course.to-view=\\\"model.course\\\" show-games.to-view=\\\"model.showGames\\\"></points-explanation> </div> </div> </div> <div class=\\\"card-footer text-right\\\"> <button class=\\\"btn btn-secondary\\\" click.trigger=\\\"controller.cancel()\\\" t=\\\"globals.back\\\"></button> </div> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <div class=\\\"container\\\"> <gallery-widget selected.two-way=\\\"value\\\" ok-callback.call=\\\"ok()\\\" cancel-callback.call=\\\"cancel()\\\" course-id.to-view=\\\"model.courseId\\\" selected-media-type.to-view=\\\"model.selectedMediaType\\\"></gallery-widget> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <div class=\\\"card question-preview-dialog__card question-preview-dialog__card--vertical-display-mode-${model.verticalDisplayMode}\\\"> <div class=\\\"card-header\\\"> <button-standard class=\\\"ml-auto\\\" click.trigger=\\\"controller.cancel()\\\" icon-name=\\\"System/Tabler/X\\\" btn-type=\\\"outline\\\" btn-color=\\\"danger\\\"></button-standard> </div> <div class=\\\"card-body question-preview-dialog__card-body question-preview-dialog__card-body--vertical-display-mode-${model.verticalDisplayMode}\\\"> <question-preview-widget question.to-view=\\\"model.question\\\" vertical-display-mode.to-view=\\\"model.verticalDisplayMode\\\"></question-preview-widget> </div> </div> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <div class=\\\"card\\\"> <div class=\\\"card-header\\\"> <button-standard class=\\\"ml-auto\\\" click.trigger=\\\"controller.cancel()\\\" icon-name=\\\"System/Tabler/X\\\" btn-type=\\\"outline\\\" btn-color=\\\"danger\\\"></button-standard> </div> <div class=\\\"card-body questions-import-dialog__card-body\\\"> <label class=\\\"mb-2 d-inline-block\\\"> <input type=\\\"file\\\" style=\\\"display:none\\\" files.two-way=\\\"selectedModuleQuestionsFiles\\\" value.bind=\\\"moduleQuestionsFilesInputValue\\\"/> <div class=\\\"btn btn-secondary questions-import-dialog__import-btn-content\\\"> <span t=\\\"dialogs.questionsImport.selectFile\\\"></span> </div> </label> <div show.to-view=\\\"moduleQuestionsFilesInputValue != null\\\" class=\\\"text-muted mb-2\\\"> ${moduleQuestionsFilesInputValue} </div> <div if.to-view=\\\"!isFrp\\\" class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"elements.courseImport.courseIdentifier\\\"> </label> <input type=\\\"text\\\" class=\\\"form-control\\\" value.two-way=\\\"selectedModuleForModuleQuestionsFile\\\"> </div> <button-standard click.delegate=\\\"startImport()\\\" t=\\\"[btnText]dialogs.questionsImport.import\\\" icon-name=\\\"System/Tabler/Upload\\\" btn-color=\\\"primary\\\" btn-fill-mode=\\\"fill-width\\\"></button-standard> </div> </div> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <form submit.trigger=\\\"ok()\\\"> <div class=\\\"card\\\"> <div class=\\\"card-header\\\"> <h3 class=\\\"card-title\\\" t=\\\"dialogs.quizTemplateCreate.title\\\"></h3> </div> <div class=\\\"card-body\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"dialogs.quizTemplateCreate.selectCourse\\\"></label> <select class=\\\"custom-select\\\" value.bind=\\\"value.courseId\\\" attach-focus> <option repeat.for=\\\"course of availableCourses\\\" model.bind=\\\"course.id\\\"> ${course.title} </option> </select> </div> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"dialogs.quizTemplateCreate.quizNameLabel\\\"></label> <input class=\\\"form-control\\\" type=\\\"text\\\" required=\\\"true\\\" value.two-way=\\\"value.name\\\"> </div> </div> <div class=\\\"card-footer text-right\\\"> <button type=\\\"submit\\\" class=\\\"btn btn-primary\\\" t=\\\"globals.save\\\"></button> <button class=\\\"btn btn-secondary\\\" click.trigger=\\\"cancel()\\\" t=\\\"globals.cancel\\\"></button> </div> </div> </form> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <form submit.trigger=\\\"ok()\\\"> <div class=\\\"card\\\"> <div class=\\\"card-header\\\"> <h3 class=\\\"card-title\\\" t=\\\"dialogs.quizTemplateEdit.title\\\"></h3> </div> <div class=\\\"card-body\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"dialogs.quizTemplateEdit.quizNameLabel\\\"></label> <input class=\\\"form-control\\\" type=\\\"text\\\" required=\\\"true\\\" attach-focus value.two-way=\\\"value.name\\\"> </div> </div> <div class=\\\"card-footer text-right\\\"> <button type=\\\"submit\\\" class=\\\"btn btn-primary\\\" t=\\\"globals.save\\\"></button> <button class=\\\"btn btn-secondary\\\" click.trigger=\\\"cancel()\\\" t=\\\"globals.cancel\\\"></button> </div> </div> </form> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <div class=\\\"card scorm-preview-dialog\\\"> <div class=\\\"card-header\\\"> <h1 class=\\\"card-title\\\">${model.scorm.title}</h1> <button-standard class=\\\"ml-auto\\\" click.delegate=\\\"ok()\\\" icon-name=\\\"System/Tabler/X\\\" btn-type=\\\"outline\\\" btn-color=\\\"danger\\\"></button-standard> </div> <div class=\\\"card-body\\\"> <scorm-player class=\\\"scorm-preview-dialog__player\\\" title.to-view=\\\"model.scorm.title\\\" scorm-url.to-view=\\\"model.scorm.url\\\"></scorm-player> </div> </div> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <div class=\\\"card send-message-to-students-dialog\\\"> <div class=\\\"card-header\\\"> <h1 class=\\\"card-title\\\" t=\\\"dialogs.sendMessageToStudents.titleSendMessage\\\"></h1> </div> <div class=\\\"card-body send-message-to-students-dialog__body\\\"> <div if.to-view=\\\"!directMessage\\\" class=\\\"row row-cards row-deck\\\"> <div class=\\\"col-12\\\"> <label class=\\\"form-label\\\" t=\\\"dialogs.sendMessageToStudents.selectedStudents\\\"></label> <text-tags-widget table-columns.to-view=\\\"userTableColumns\\\" table-headers.to-view=\\\"userTableHeaders\\\" table-data.to-view=\\\"foundUsers\\\" tags.to-view=\\\"selectedUsersTags\\\" mark-selected.to-view=\\\"true\\\" should-list-stay-open.to-view=\\\"true\\\" is-selected-callback.call=\\\"isSelected($event)\\\" tags-edited.trigger=\\\"handleUserEntryRemoved($event)\\\" entry-selected.trigger=\\\"handleUserEntrySelected($event)\\\" search-string-changed.trigger=\\\"handleUserSearchStringChanged($event)\\\"></text-tags-widget> </div> </div> <hr if.to-view=\\\"!directMessage\\\" class=\\\"my-6\\\"/> <div class=\\\"row\\\"> <div class=\\\"col-12\\\"> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"dialogs.sendMessageToStudents.message\\\"></label> <textarea type=\\\"text\\\" attach-focus t=\\\"[placeholder]dialogs.sendMessageToStudents.yourMessage\\\" class=\\\"form-control send-message-to-students-dialog__textarea\\\" value.two-way=\\\"message\\\"></textarea> </div> </div> </div> </div> <div class=\\\"card-footer text-right\\\"> <button disabled.to-view=\\\"selectedUsers.length === 0 || loading\\\" class=\\\"btn btn-primary\\\" click.trigger=\\\"sendSingle()\\\" t=\\\"dialogs.sendMessageToStudents.sendMessage\\\"></button> <button class=\\\"btn btn-secondary\\\" click.trigger=\\\"cancel()\\\" t=\\\"globals.cancel\\\"></button> </div> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <form submit.trigger=\\\"handleSubmit()\\\"> <div class=\\\"card\\\"> <div class=\\\"card-body show-distinar-qr-code-dialog__body\\\"> <h2 class=\\\"show-distinar-qr-code-dialog__title\\\" t=\\\"dialogs.distinarShowQrCode.title\\\"></h2> <p class=\\\"show-distinar-qr-code-dialog__subtitle\\\" t=\\\"dialogs.distinarShowQrCode.subtitle\\\"></p> <img class=\\\"show-distinar-qr-code-dialog__qr-code\\\" src.to-view=\\\"qrCodeDataUrl\\\"/> <div class=\\\"show-distinar-qr-code-dialog__text-code\\\">${code}</div> </div> <div class=\\\"card-footer text-right\\\"> <button type=\\\"submit\\\" class=\\\"btn btn-primary\\\" t=\\\"globals.close\\\"></button> </div> </div> </form> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <div class=\\\"card show-students-dialog__card\\\"> <div class=\\\"card-header\\\"> <h3 class=\\\"card-title\\\" t=\\\"globals.students\\\"></h3> <button-standard class=\\\"ml-auto\\\" click.trigger=\\\"controller.cancel()\\\" icon-name=\\\"System/Tabler/X\\\" btn-type=\\\"outline\\\" btn-color=\\\"danger\\\"></button-standard> </div> <div class=\\\"card-body show-students-dialog__body\\\"> <div class=\\\"row row-cards row-deck\\\"> <div class=\\\"col-12\\\"> <custom-table columns.to-view=\\\"tableColumns\\\" table-id=\\\"show-students-dialog-table\\\" get-shown-entries-data.call=\\\"fetchTableData(limit, offset)\\\"></custom-table> </div> </div> </div> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <form submit.trigger=\\\"ok()\\\"> <div class=\\\"card single-rating-dialog__card\\\"> <div class=\\\"card-header\\\"> <h3 class=\\\"card-title\\\" t=\\\"elements.ratingTable.rating\\\"></h3> </div> <div class=\\\"card-body single-rating-dialog__body\\\"> <div class=\\\"single-rating-dialog__item\\\"> <div class=\\\"single-rating-dialog__item-label\\\" t=\\\"globals.course\\\"></div> <div class=\\\"single-rating-dialog__item-value\\\">${model.rating.courseTitle}</div> </div> <div class=\\\"single-rating-dialog__item\\\"> <div class=\\\"single-rating-dialog__item-label\\\" t=\\\"globals.user\\\"></div> <div class=\\\"single-rating-dialog__item-value\\\">${model.rating.userName}</div> </div> <div class=\\\"single-rating-dialog__item\\\"> <div class=\\\"single-rating-dialog__item-label\\\" t=\\\"elements.ratingTable.ratedAt\\\"></div> <div class=\\\"single-rating-dialog__item-value\\\">${formatDate(model.rating.updatedAt)}</div> </div> <div class=\\\"single-rating-dialog__item\\\"> <div class=\\\"single-rating-dialog__item-label\\\" t=\\\"elements.ratingTable.rating\\\"></div> <star-rating size=\\\"small\\\" rating.to-view=\\\"model.rating.rating\\\"></star-rating> </div> <div class=\\\"single-rating-dialog__item single-rating-dialog__item--comment\\\"> <div class=\\\"single-rating-dialog__item-label\\\" t=\\\"elements.ratingTable.comment\\\"></div> <div class=\\\"single-rating-dialog__item-value\\\">${model.rating.comment}</div> </div> </div> <div class=\\\"card-footer text-right\\\"> <button if.to-view=\\\"model.showNavigateButton\\\" type=\\\"submit\\\" class=\\\"btn btn-primary\\\" t=\\\"elements.ratingTable.showAllOfCourse\\\"></button> <button class=\\\"btn btn-secondary\\\" click.trigger=\\\"cancel()\\\" t=\\\"globals.close\\\"></button> </div> </div> </form> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <form submit.trigger=\\\"startQuickQuiz()\\\"> <div class=\\\"card start-quick-quiz-dialog__card\\\"> <div class=\\\"card-header\\\"> <h1 class=\\\"card-title\\\" t=\\\"dialogs.startQuickQuiz.title\\\"></h1> </div> <div class=\\\"card-body start-quick-quiz-dialog__card-body\\\"> <div class=\\\"form-group start-quick-quiz-dialog__course-select\\\"> <label class=\\\"form-label\\\" t=\\\"globals.course\\\"></label> <select class=\\\"custom-select\\\" value.to-view=\\\"selectedCourse.id == null ? '' : selectedCourse.id.toString()\\\" change.trigger=\\\"handleCourseSelectChanged($event)\\\"> <option if.to-view=\\\"selectedCourse.id == null\\\" value=\\\"\\\" t=\\\"dialogs.startQuickQuiz.noCourseSelected\\\"> </option> <option repeat.for=\\\"course of availableCourses\\\" value.to-view=\\\"course.id\\\">${course.title}</option> </select> </div> <div class=\\\"form-group start-quick-quiz-dialog__chapter-select\\\"> <label class=\\\"form-label\\\" t=\\\"dialogs.startQuickQuiz.selectChapter\\\"></label> <multi-select-combo-box selected-items-changed.trigger=\\\"handleChapterChanged($event)\\\" total-items.to-view=\\\"availableChapters\\\" label-property-name.to-view=\\\"`title`\\\" selected-items.to-view=\\\"selectedChapters\\\"></multi-select-combo-box> </div> <div class=\\\"form-group start-quick-quiz-dialog__question-count-select\\\"> <label class=\\\"form-label\\\" t=\\\"dialogs.startQuickQuiz.numberOfQuestions\\\" t-params.to-view=\\\"{ totalMax: ABSOLUTE_MAX_QUESTIONS }\\\"></label> <input type=\\\"number\\\" class=\\\"form-control\\\" disabled.to-view=\\\"!maxNumberOfQuestions\\\" value.bind=\\\"numberOfQuestions\\\" min.to-view=\\\"1\\\" max.to-view=\\\"maxNumberOfQuestions\\\" change.trigger=\\\"handleNumberOfQuestionsChanged($event)\\\"> <small class=\\\"form-text text-muted\\\" t-params.to-view=\\\"{ count: maxNumberOfQuestions }\\\" t=\\\"dialogs.startQuickQuiz.numberOfQuestionsHelp\\\"></small> </div> <div class=\\\"form-group start-quick-quiz-dialog__time-select\\\"> <fieldset> <legend class=\\\"form-label\\\" t=\\\"dialogs.startQuickQuiz.timeToAnswer\\\"></legend> <div repeat.for=\\\"timeToAnswer of answerTimes\\\" class=\\\"form-check form-check-inline\\\"> <div class=\\\"custom-control custom-radio\\\"> <input class=\\\"custom-control-input\\\" type=\\\"radio\\\" name=\\\"timeToAnswer\\\" id=\\\"timeToAnswerRadio${$index}\\\" model.bind=\\\"timeToAnswer\\\" checked.bind=\\\"selectedAnswerTime\\\"/> <label class=\\\"custom-control-label\\\" for=\\\"timeToAnswerRadio${$index}\\\" t=\\\"dialogs.startQuickQuiz.${timeToAnswer}\\\"></label> </div> </div> </fieldset> </div> </div> <div class=\\\"card-footer text-right\\\"> <button type=\\\"submit\\\" disabled.to-view=\\\"!maxNumberOfQuestions || !selectedNumberOfQuestions\\\" class=\\\"btn btn-primary\\\" t=\\\"globals.start\\\"></button> <button class=\\\"btn btn-secondary\\\" click.trigger=\\\"cancel()\\\" t=\\\"globals.cancel\\\"></button> </div> </div> </form> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <form> <div class=\\\"card\\\"> <div class=\\\"card-header\\\"> <h1 class=\\\"card-title\\\" t=\\\"dialogs.startTemplateQuiz.title\\\"></h1> </div> <div class=\\\"card-body\\\"> <div class=\\\"form-group\\\"> <fieldset> <legend class=\\\"form-label\\\" t=\\\"dialogs.startTemplateQuiz.timeToAnswer\\\"></legend> <div repeat.for=\\\"timeToAnswer of answerTimes\\\" class=\\\"form-check\\\"> <div class=\\\"custom-control custom-radio\\\"> <input class=\\\"custom-control-input\\\" type=\\\"radio\\\" name=\\\"timeToAnswer\\\" id=\\\"timeToAnswerRadio${$index}\\\" model.bind=\\\"timeToAnswer\\\" checked.bind=\\\"value.answerTime\\\"/> <label class=\\\"custom-control-label\\\" t=\\\"dialogs.startTemplateQuiz.${timeToAnswer}\\\" for=\\\"timeToAnswerRadio${$index}\\\"></label> </div> </div> </fieldset> </div> </div> <div class=\\\"card-footer text-right\\\"> <button type=\\\"submit\\\" class=\\\"btn btn-primary\\\" click.trigger=\\\"ok()\\\" t=\\\"globals.start\\\"></button> <button class=\\\"btn btn-secondary\\\" click.trigger=\\\"cancel()\\\" t=\\\"globals.cancel\\\"></button> </div> </div> </form> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <div class=\\\"card\\\"> <div class=\\\"card-header\\\"> <h3 class=\\\"card-title\\\" t=\\\"dialogs.studentImport.result\\\"></h3> </div> <div class=\\\"card-body\\\"> <alert-message if.to-view=\\\"infoMessage\\\" message.to-view=\\\"infoMessage\\\" message-style=\\\"alert-success\\\"></alert-message> <alert-message if.to-view=\\\"errorMessage\\\" message.to-view=\\\"errorMessage\\\" message-style=\\\"alert-info\\\"></alert-message> <alert-message if.to-view=\\\"warnMessage\\\" message.to-view=\\\"warnMessage\\\" message-style=\\\"alert-warning\\\"></alert-message> <div class=\\\"row row-cards row-deck\\\"> <div class=\\\"col-12\\\"> <custom-table data.to-view=\\\"model.students\\\" hide-footer.to-view=\\\"true\\\" columns.to-view=\\\"tableColumns\\\"></custom-table> </div> </div> </div> <div class=\\\"card-footer text-right\\\"> <button type=\\\"submit\\\" class=\\\"btn btn-primary\\\" click.delegate=\\\"ok()\\\" t=\\\"globals.ok\\\"></button> </div> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <div class=\\\"card transfer-invitation-warning-dialog__card\\\"> <div class=\\\"card-header\\\"> <h1 class=\\\"card-title\\\" t=\\\"dialogs.transferInvitationWarningDialog.title\\\"></h1> </div> <div class=\\\"card-body\\\"> <alert-message message.to-view=\\\"{ tk: `dialogs.transferInvitationWarningDialog.alertMessage`, tkParams: { count: model.transferableCodes.length } }\\\" message-style=\\\"alert-warning\\\"></alert-message> <label class=\\\"form-label mt-3\\\" t=\\\"dialogs.transferInvitationWarningDialog.coursesAtOtherTenants\\\"></label> <div class=\\\"transfer-invitation-warning-dialog__course-and-group-list-scrollbox\\\"> <course-and-group-list-item repeat.for=\\\"transferableCode of model.transferableCodes\\\" class=\\\"mt-2\\\" removable.to-view=\\\"false\\\" course.to-view=\\\"transferableCode.course\\\" course-group.to-view=\\\"transferableCode.courseGroup\\\"></course-and-group-list-item> </div> </div> <div class=\\\"card-footer text-right\\\"> <button-standard class=\\\"d-inline-block\\\" t=\\\"[btnText]dialogs.invitationCreate.sendInvitation\\\" click.delegate=\\\"ok()\\\" btn-color=\\\"primary\\\"></button-standard> <button-standard t=\\\"[btnText]globals.cancel\\\" class=\\\"d-inline-block\\\" click.trigger=\\\"value.previouslyAddedData ? ok() : cancel()\\\" btn-color=\\\"secondary\\\"></button-standard> </div> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <div class=\\\"card video-preview-dialog\\\"> <div class=\\\"card-header\\\"> <h1 class=\\\"card-title\\\">${model.video.title}</h1> <button-standard class=\\\"ml-auto\\\" click.delegate=\\\"ok()\\\" icon-name=\\\"System/Tabler/X\\\" btn-type=\\\"outline\\\" btn-color=\\\"danger\\\"></button-standard> </div> <div class=\\\"card-body\\\"> <aspect-ratio-container class=\\\"video-preview-dialog__player-wrapper\\\" mode=\\\"width-and-height-dependent\\\"> <video-player fit-to-container.to-view=\\\"true\\\" transcript.to-view=\\\"model.video.text\\\" video-sources.to-view=\\\"model.video.videoSources\\\" vimeo-id.to-view=\\\"model.video.vimeoId\\\" bunny-id.to-view=\\\"model.video.bunnyId\\\" bordered.to-view=\\\"true\\\"></video-player> </aspect-ratio-container> </div> </div> </template> \";\n// Exports\nexport default code;","import { CustomDialog } from './../../../services/CustomDialog';\nimport { autoinject } from 'aurelia-framework';\n\n@autoinject\nexport class EmailPrompt extends CustomDialog {\n  public model!: IEmailPromptModel;\n  public value = '';\n\n  protected ok(): void {\n    this.controller.ok(this.value.trim());\n  }\n}\n\nexport interface IEmailPromptModel {\n  titleTk?: string;\n  labelTk: string;\n  placeholderTk: string;\n}\n","import { DialogController } from 'aurelia-dialog';\nimport { autoinject } from 'aurelia-framework';\nimport { ArrayUtils } from 'common/utils/ArrayUtils';\nimport { CustomDialog } from '../../../services/CustomDialog';\nimport { DateService } from '../../../services/DateService';\nimport { ValidationUtils } from '../../../utils/ValidationUtils';\n\n@autoinject()\nexport class FromToDatesDialog extends CustomDialog {\n  public value!: IFromToDatesDialogValue;\n  private errorTks: IErrorTk = {\n    fromDate: null,\n    toDate: null,\n  };\n\n  constructor(\n    dialogController: DialogController,\n    private dateService: DateService,\n  ) {\n    super(dialogController);\n  }\n\n  public initValue(): void {\n    this.value = {\n      fromDate: null,\n      toDate: null,\n    };\n  }\n\n  protected async ok(): Promise<void> {\n    if(this.checkDates(this.value)) {\n      this.value.fromDate = this.value.fromDate ? this.dateService.getStartOfDayISOString(this.value.fromDate) : null;\n      this.value.toDate = this.value.toDate ? this.dateService.getStartOfDayISOString(this.value.toDate) : null;\n      this.controller.ok(this.value);\n    }\n  }\n\n  private checkDates(dates: IFromToDatesDialogValue): boolean {\n    this.errorTks.fromDate = ValidationUtils.isDateValid(dates.fromDate);\n    this.errorTks.toDate = ArrayUtils.getFirstNonNullValue(\n      ValidationUtils.isDateValid(dates.toDate),\n      ValidationUtils.isEndDateBeforeStartDate(dates.fromDate, dates.toDate)\n    );\n    return Object.values(this.errorTks).every(value => !value);\n  }\n\n  private resetErrorTkByKey(key: keyof IErrorTk): void {\n    this.errorTks[key] = null;\n  }\n}\n\nexport interface IFromToDatesDialogValue {\n  fromDate: string | null;\n  toDate: string | null;\n}\n\ninterface IErrorTk {\n  fromDate: string | null;\n  toDate: string | null;\n}","import { DialogController } from 'aurelia-dialog';\nimport { autoinject, computedFrom } from 'aurelia-framework';\nimport { SmsService } from 'common/aurelia-services/SmsService';\nimport { StoreService } from 'common/aurelia-services/StoreService';\nimport { STATES } from 'common/constants/states.constants';\nimport { ICourseCodeCreationCourseInfoDto, ICourseCodeMetadataDto, ICourseCodeResponseDto } from 'common/dto/course/code/course.code.interface';\nimport { NewCourseCodeResponse } from 'common/dto/course/code/course.code.response';\nimport { ICourseGroupResponseDto } from 'common/dto/course/course.group.interface';\nimport { ICourseEditResponseDto } from 'common/dto/course/management/course.management.interface';\nimport { FilterOperationType } from 'common/dto/filter/filter.enum';\nimport { NotificationMethod } from 'common/enum/auth.enum';\nimport { ActivityFilterType } from 'common/enum/course.access.enum';\nimport { ErrorType } from 'common/enum/errortype.enum';\nimport { Config } from 'common/fe-config/config';\nimport { ArrayUtils } from 'common/utils/ArrayUtils';\nimport { FunctionUtils } from 'common/utils/FunctionUtils';\nimport { LogUtils } from 'common/utils/LogUtils';\nimport { ValidationUtils as CommonValidationUtils } from 'common/utils/ValidationUtils';\nimport Moment from 'moment';\nimport { InvitationApiService } from '../../../services/api/InvitationApiService';\nimport { CustomDialog } from '../../../services/CustomDialog';\nimport { CustomDialogService } from '../../../services/CustomDialogService';\nimport { DateService } from '../../../services/DateService';\nimport { PageLoadingIndicatorService } from '../../../services/PageLoadingIndicatorService';\nimport { ToastService } from '../../../services/ToastService';\nimport { IState } from '../../../store/state';\nimport { RemoveCourseAndGroupClickedEvent } from '../../elements/course-and-group-list-item/course-and-group-list-item';\nimport { AddCourseAndGroupClickedEvent } from '../../elements/course-and-group-select/course-and-group-select';\nimport { VirtualFilterField } from '../../elements/custom-table/custom-table-helpers';\nimport { LinkBehavior } from '../../elements/toast-controller/toasts/default-toast/default-toast';\n\n@autoinject()\nexport class InvitationCreateDialog extends CustomDialog {\n  public model!: IInvitationCreateDialogModel;\n  public value: IInvitationCreateDialogValue = {\n    metadata: this.getEmptyMetaData(),\n    selectedCoursesAndGroups: []\n  };\n\n  private inputEmailDomElement: HTMLInputElement | null = null;\n  private inputPhoneNumberDomElement: HTMLInputElement | null = null;\n\n  private checkForExistingUserInProgress = false;\n  private debouncedCheckForExistingUserInProgress = FunctionUtils.debounce(() => { this.checkForExistingUserInProgress = false; }, 200);\n\n  private existingUser: ICourseCodeResponseDto<string> | null = null;\n  private existingUserInvitations: ICourseCodeResponseDto<string>[] = [];\n  private existingUserApplied = false;\n  private matchingUserId: number | null = null;\n\n  private createAdditionalInvitations = false;\n  private loading = false;\n  private freeCodesUntil: string | null = null;\n  private unavailableCourseIds: number[] = [];\n  private examDate: string | null = null;\n  private availableCallingCodes: string[] = [];\n  private inviteBySmsEnabled = Config().sms.enabled;\n\n  private states = STATES;\n  private NotificationMethod = NotificationMethod;\n\n  constructor(\n    protected controller: DialogController,\n    private indicatorService: PageLoadingIndicatorService,\n    private invitationApiService: InvitationApiService,\n    private customDialogService: CustomDialogService,\n    private dateService: DateService,\n    private toastService: ToastService,\n    private storeService: StoreService<IState>,\n    private smsService: SmsService,\n  ) {\n    super(controller);\n  }\n\n  private errorTks: IErrorTk = {\n    birthdate: null,\n    firstname: null,\n    lastname: null,\n    state: null,\n    email: null,\n    phoneNumber: null,\n    courseGroup: null,\n    importantNotificationMethod: null,\n  };\n\n  public activate(model: IInvitationCreateDialogModel): void {\n    this.model = model;\n    if(this.model.studentId) {\n      this.checkAndApplyPreExistingUser();\n    } else {\n      this.updateCallingCodes();\n    }\n\n    this.storeService.subscribeToDetailedChanges(this, [\n      state => state.currentRole?.freeCodesUntil ?? null,\n    ], (_, freeCodesUntil) => {\n      this.freeCodesUntil = freeCodesUntil;\n    });\n  }\n\n  protected deactivate(): void {\n    this.debouncedCheckForExistingUserInProgress?.cancel();\n    this.storeService.disposeAllSubscriptions(this);\n  }\n\n  /**\n   * invitation must have birthdate, firstname, lastname and state\n   * birthdate must be at least 14 years in the past\n   * birthdate must be valid and can't be today or any time in the future\n   * birthdate can't also be more than 100 years in the past\n   */\n  private checkMetadata(metadata: ICourseCodeMetadataDto<string>): boolean {\n    this.errorTks.birthdate = metadata.birthdate\n      ? ArrayUtils.getFirstNonNullValue(\n        CommonValidationUtils.isBirthdateValid(metadata.birthdate),\n        CommonValidationUtils.isBirthdateTodayOrInFuture(metadata.birthdate),\n        CommonValidationUtils.isBirthdateFarEnoughInPast(metadata.birthdate),\n        CommonValidationUtils.isBirthdateTooFarInPast(metadata.birthdate)\n      )\n      : null;\n\n    this.errorTks.firstname = CommonValidationUtils.checkFirstname(metadata.firstname);\n    this.errorTks.lastname = CommonValidationUtils.checkLastname(metadata.lastname);\n\n    this.errorTks.email = metadata.importantNotificationMethod === NotificationMethod.Email || !this.inviteBySmsEnabled\n      ? CommonValidationUtils.checkMandatoryEmail(metadata.email)\n      : CommonValidationUtils.checkOptionalEmail(metadata.email);\n\n    this.errorTks.phoneNumber = metadata.importantNotificationMethod === NotificationMethod.Sms\n      ? CommonValidationUtils.checkMandatoryPhoneNumber(metadata.phoneNumber, this.availableCallingCodes)\n      : CommonValidationUtils.checkOptionalPhoneNumber(metadata.phoneNumber, this.availableCallingCodes);\n\n    this.errorTks.state = metadata.address.state\n      ? CommonValidationUtils.checkState(metadata.address.state)\n      : null;\n\n    this.errorTks.importantNotificationMethod = !metadata.importantNotificationMethod\n      ? 'common.validationUtils.noImportantNotificationMethodError'\n      : null;\n\n    return Object.values(this.errorTks).every(value => !value);\n  }\n\n  private resetErrorTkByKey(key: keyof IErrorTk): void {\n    this.errorTks[key] = null;\n  }\n\n  private handleEmailInput(): void {\n    this.resetErrorTkByKey('email');\n    this.existingUser = null;\n    // timeout since update didn't happen yet\n    setTimeout(() => this.autoUpdateImportantNotificationMethod());\n  }\n\n  private handlePhoneInput(): void {\n    this.resetErrorTkByKey('phoneNumber');\n    this.existingUser = null;\n    // timeout since update didn't happen yet\n    setTimeout(() => this.autoUpdateImportantNotificationMethod());\n  }\n\n  private autoUpdateImportantNotificationMethod(): void {\n    if(!this.inviteBySmsEnabled) return;\n\n    const { importantNotificationMethod, email, phoneNumber } = this.value.metadata;\n    if(importantNotificationMethod !== NotificationMethod.Email && !phoneNumber && email) {\n      this.value.metadata.importantNotificationMethod = NotificationMethod.Email;\n    }\n\n    if(importantNotificationMethod !== NotificationMethod.Sms && !email && phoneNumber) {\n      this.value.metadata.importantNotificationMethod = NotificationMethod.Sms;\n    }\n\n    if(importantNotificationMethod != null && !phoneNumber && !email) {\n      this.value.metadata.importantNotificationMethod = NotificationMethod.Email;\n    }\n  }\n\n  private async checkForExistingUserByMail(): Promise<void> {\n    this.inputEmailDomElement?.blur();\n    if(CommonValidationUtils.checkMandatoryEmail(this.value.metadata.email)) return;\n\n    this.checkForExistingUser('mail');\n  }\n\n  private async checkForExistingUserByPhoneNumber(): Promise<void> {\n    this.inputPhoneNumberDomElement?.blur();\n    if(CommonValidationUtils.checkMandatoryPhoneNumber(this.value.metadata.phoneNumber, this.availableCallingCodes)) return;\n\n    this.checkForExistingUser('phoneNumber');\n  }\n\n  private async checkForExistingUser(mode: 'mail' | 'phoneNumber'): Promise<void> {\n    if(this.checkForExistingUserInProgress) return;\n\n    this.checkForExistingUserInProgress = true;\n\n    try {\n      const existingUser = (await this.invitationApiService.getInvitations({\n        filter: [\n          mode === 'mail'\n            ? {\n              field: 'metadataEmail' as VirtualFilterField,\n              type: FilterOperationType.Eq,\n              value: this.value.metadata.email?.trim()\n            }\n            : {\n              field: 'metadataPhoneNumber' as VirtualFilterField,\n              type: FilterOperationType.Eq,\n              value: this.value.metadata.phoneNumber?.trim(),\n            },\n        ],\n        limit: 1,\n      }))?.rows as ICourseCodeResponseDto<string>[] ?? [];\n      this.existingUser = existingUser[0] ?? null;\n\n      if(this.existingUser != null && this.matchingUserId !== this.existingUser.id) {\n        if(this.existingUser.student?.id) {\n          await this.updateExistingActiveUserInvitations(this.existingUser.student.id);\n        }\n        this.existingUserApplied = false;\n        this.value.selectedCoursesAndGroups = [];\n      }\n\n      this.matchingUserId = this.existingUser?.id ?? null;\n      this.updateUnavailableCourseIds();\n    } catch(e) {\n      LogUtils.exception(e);\n    }\n    this.debouncedCheckForExistingUserInProgress();\n  }\n\n  private applyExistingUser(): void {\n    const metadata: ICourseCodeMetadataDto<string> = this.existingUser?.metadata || this.getEmptyMetaData();\n    if(!metadata.email) metadata.email = this.existingUser?.student?.email || null;\n    if(!metadata.firstname) metadata.firstname = this.existingUser?.student?.firstname ?? '';\n    if(!metadata.lastname) metadata.lastname = this.existingUser?.student?.lastname ?? '';\n    if(!metadata.phoneNumber) metadata.phoneNumber = this.existingUser?.student?.phoneNumber || null;\n    if(!metadata.importantNotificationMethod) metadata.importantNotificationMethod = this.existingUser?.student?.importantNotificationMethod || NotificationMethod.Email;\n    this.value.metadata = metadata;\n    this.existingUser = null;\n    this.existingUserApplied = true;\n    this.updateUnavailableCourseIds();\n    this.autoUpdateImportantNotificationMethod();\n  }\n\n  private async checkAndApplyPreExistingUser(): Promise<void> {\n    try {\n      if(!this.model.studentId) return;\n\n      await this.updateCallingCodes();\n      const existingUser = (await this.invitationApiService.getInvitations({\n        filter: [\n          {\n            field: 'userId' as VirtualFilterField,\n            value: this.model.studentId,\n            type: FilterOperationType.Eq,\n          },\n        ],\n        limit: 1,\n      }))?.rows as ICourseCodeResponseDto<string>[] ?? [];\n\n      this.existingUser = existingUser[0] ?? null;\n      await this.updateExistingActiveUserInvitations(this.model.studentId);\n      this.applyExistingUser();\n    } catch(e) {\n      LogUtils.exception(e);\n    }\n  }\n\n  private async updateExistingActiveUserInvitations(studentId: number): Promise<void> {\n    this.existingUserInvitations = (await this.invitationApiService.getInvitations({\n      filter: [\n        {\n          field: 'userId' as VirtualFilterField,\n          value: studentId,\n          type: FilterOperationType.Eq,\n        },\n        {\n          field: 'activityFilter' as VirtualFilterField,\n          type: FilterOperationType.Eq,\n          value: ActivityFilterType.ActiveInUse,\n        }\n      ]\n    }))?.rows as ICourseCodeResponseDto<string>[] ?? [];\n  }\n\n  private async createInvitation(force: boolean = false): Promise<void> {\n    this.value.metadata.firstname = this.value.metadata.firstname.trim();\n    this.value.metadata.lastname = this.value.metadata.lastname.trim();\n    this.value.metadata.email = this.value.metadata.email?.trim() ?? null;\n    if(!this.checkMetadata(this.value.metadata)) return;\n\n    const courseInfos: ICourseCodeCreationCourseInfoDto<string>[] = this.value.selectedCoursesAndGroups.map(sCAG => ({\n      courseId: sCAG.course.id,\n      courseGroupId: sCAG.courseGroup.id,\n      examDate: Moment(sCAG.examDate).isValid() ? sCAG.examDate : null,\n    }));\n\n    this.setLoading(true);\n    try {\n      const response = await this.invitationApiService.createInvitation({\n        courseInfos,\n        metadata: {\n          ...this.value.metadata,\n          birthdate: this.value.metadata.birthdate?.trim() || null,\n        },\n        note: null,\n        force,\n      });\n      const cancel = await this.handleInvitationsCreatedResponse(response);\n      if(cancel) {\n        this.setLoading(false);\n        return;\n      }\n\n    } catch(e) {\n      if(e.message === ErrorType.USER_EXISTS_AS_ADMIN) {\n        this.toastService.error('dialogs.invitationCreate.createInvitationUserIsAdminError');\n      } else if(e.message === ErrorType.INVALID_EMAIL) {\n        this.toastService.error('common.validationUtils.emailInvalidError');\n      } else if(e.message === ErrorType.COURSE_INVITATION_NO_PHONE_NUMBER) {\n        this.toastService.error('dialogs.invitationCreate.createInvitationNoPhoneNumberError');\n      } else {\n        this.toastService.error('dialogs.invitationCreate.createInvitationError');\n      }\n    } finally {\n      this.setLoading(false);\n    }\n\n    if(!this.createAdditionalInvitations) {\n      this.ok();\n    } else {\n      const { firstname, lastname, birthdate, email } = this.value.metadata;\n      const courseAndCourseGroups = this.value.selectedCoursesAndGroups.map(sCAG => ({\n        courseTitle: sCAG.course.title,\n        courseGroupName: sCAG.courseGroup.name\n      }));\n      this.value.previouslyAddedData = { firstname, lastname, birthdate, email, courseAndCourseGroups };\n      this.value.metadata = this.getEmptyMetaData();\n    }\n  }\n\n  /**\n   * shows an error toast if there are existing or transfered codes at the current tenant\n   * shows a success toast if there are codes or transfers created\n   * shows a warning toast if there are transferable codes at other tenants\n   * returns false if the user decides to cancel the transfer\n   * if the transfer is confirmed, sends another request to create the codes\n   */\n  private async handleInvitationsCreatedResponse(response: NewCourseCodeResponse<string>): Promise<boolean> {\n    if('existingCodes' in response && response.existingCodes.length) {\n      const existingCourseNames = response.existingCodes.map(c => c.course.title).join(', ');\n      this.toastService.error('dialogs.invitationCreate.existingInvitationText', { courses: existingCourseNames }, null, {\n        textTk: 'dialogs.invitationCreate.existingInvitationLink',\n        linkHref: `/student-invitations/${response.existingCodes[0].student?.id}/invitations`,\n        behavior: LinkBehavior.Navigate,\n      });\n    }\n\n    if('newCodes' in response && response.newCodes.length || 'transferingCodes' in response && response.transferingCodes.length) {\n      this.toastService.success('dialogs.invitationCreate.createInvitationSuccess');\n    }\n\n    if('transferedCodes' in response && response.transferedCodes.length) {\n      const transferedCourseNames = response.transferedCodes.map(c => c.course.title).join(', ');\n      this.toastService.error('dialogs.invitationCreate.transferedInvitationText', { courses: transferedCourseNames });\n    }\n\n    if('transferableCodes' in response && response.transferableCodes.length) {\n      const continueWithTransfer = await this.customDialogService.showTransferInvitationWarningDialog({\n        transferableCodes: response.transferableCodes,\n      });\n      if(!continueWithTransfer) return true;\n      await this.createInvitation(true);\n    }\n    return false;\n  }\n\n  private updateUnavailableCourseIds(): void {\n    this.unavailableCourseIds = [\n      ...this.value.selectedCoursesAndGroups.map(sCAG => sCAG.course.id),\n      ...(this.existingUserApplied\n        ? this.existingUserInvitations.map(invitation => invitation.course.id)\n        : [])\n    ];\n  }\n\n  private addCourseAndGroup(event: AddCourseAndGroupClickedEvent): void {\n    const { selectedCourse, selectedCourseGroup, examDate } = event.detail;\n    if(selectedCourse && selectedCourseGroup) {\n      const alreadyAdded = this.value.selectedCoursesAndGroups.some(sCAG =>\n        sCAG.course.id === selectedCourse.id\n        || sCAG.courseGroup.id === selectedCourseGroup.id\n      );\n      if(alreadyAdded) return;\n      this.value.selectedCoursesAndGroups.push({\n        course: selectedCourse,\n        courseGroup: selectedCourseGroup,\n        examDate\n      });\n      this.updateUnavailableCourseIds();\n    }\n  }\n\n  private removeCourseAndGroup(event: RemoveCourseAndGroupClickedEvent): void {\n    const { course, courseGroup } = event.detail;\n    if(course && courseGroup) {\n      this.value.selectedCoursesAndGroups = this.value.selectedCoursesAndGroups.filter(sCAG =>\n        sCAG.course.id !== course.id\n        || sCAG.courseGroup.id !== courseGroup.id\n      );\n      this.updateUnavailableCourseIds();\n    }\n  }\n\n  private getEmptyMetaData(): ICourseCodeMetadataDto<string> {\n    return {\n      firstname: '',\n      lastname: '',\n      address: {\n        city: '',\n        state: '',\n        country: '',\n        street: '',\n        postalCode: '',\n      },\n      email: '',\n      phoneNumber: '',\n      birthdate: '',\n      importantNotificationMethod: NotificationMethod.Email\n    };\n  }\n\n  @computedFrom('freeCodesUntil')\n  private get freeCodesUntilFormatted(): string | null {\n    if(!this.freeCodesUntil) return null;\n    if(this.dateService.isInPast(this.freeCodesUntil)) return null;\n    return this.dateService.formatDate(this.freeCodesUntil);\n  }\n\n  private async updateCallingCodes(): Promise<void> {\n    this.availableCallingCodes = await this.smsService.getCallingCodeArray();\n  }\n\n\n  private setLoading(loading: boolean): void {\n    this.loading = loading;\n    if(loading) {\n      this.indicatorService.start();\n    } else {\n      this.indicatorService.stop();\n    }\n  }\n}\n\nexport interface ICourseAndGroupSelect {\n  course: ICourseEditResponseDto;\n  courseGroup: ICourseGroupResponseDto<string>;\n  examDate: string | null;\n}\n\nexport interface IInvitationCreateDialogValue {\n  selectedCoursesAndGroups: ICourseAndGroupSelect[];\n  metadata: ICourseCodeMetadataDto<string>;\n  previouslyAddedData?: IPreviouslyAddedData;\n}\n\nexport interface IInvitationCreateDialogModel {\n  studentId?: number;\n}\n\ninterface IErrorTk {\n  firstname: string | null;\n  lastname: string | null;\n  birthdate: string | null;\n  email: string | null;\n  phoneNumber: string | null;\n  state: string | null;\n  courseGroup: string | null;\n  importantNotificationMethod: string | null;\n}\n\ninterface IPreviouslyAddedData {\n  firstname: string;\n  lastname: string;\n  birthdate: string | null;\n  email: string | null;\n  courseAndCourseGroups: { courseTitle: string; courseGroupName: string }[];\n}\n","import { DialogController } from 'aurelia-dialog';\nimport { autoinject, computedFrom } from 'aurelia-framework';\nimport { StoreService } from 'common/aurelia-services/StoreService';\nimport { UniversalBlock, UniversalLayoutContainer } from 'common/dto/content-editor/content.editor.interface';\nimport { BlockType } from 'common/dto/course/content/course.types';\nimport { LayoutContainerDirection, LayoutContainerType } from 'common/dto/course/layout.container.interface';\nimport { CustomDialog } from '../../../services/CustomDialog';\nimport { IState } from '../../../store/state';\n\n@autoinject()\nexport class LayoutContainerPreviewDialog extends CustomDialog {\n  public model!: ILayoutContainerPreviewDialogModel;\n  private layoutContainerId: number | null = null;\n  private layoutContainer: UniversalLayoutContainer | null = null;\n  private block: UniversalBlock | null = null;\n\n  constructor(\n    dialogController: DialogController,\n    private storeService: StoreService<IState>,\n  ) {\n    super(dialogController);\n  }\n\n  public initValue(model: ILayoutContainerPreviewDialogModel): void {\n    this.layoutContainerId = model.layoutContainerId;\n    if(this.layoutContainerId != null) this.subscribeToState();\n  }\n\n  protected detached(): void {\n    this.storeService.disposeAllSubscriptions(this);\n  }\n\n  private subscribeToState(): void {\n    this.storeService.disposeAllSubscriptions(this);\n    this.storeService.subscribeToDetailedChanges(this, [\n      state => state.contentEditor.clipboard,\n    ], state => {\n      this.layoutContainer = state.contentEditor.clipboard.layoutContainers\n        .find(container => container.id === this.layoutContainerId) ?? null;\n      if(this.layoutContainer != null) {\n        this.block = state.contentEditor.clipboard.blocks\n          .find(block => block.id === this.layoutContainer?.blockId) ?? null;\n      }\n    });\n  }\n\n  private close(): void {\n    this.storeService.disposeAllSubscriptions(this);\n    this.cancel();\n  }\n\n  @computedFrom('block.type')\n  private get hasIntrinsicSize(): boolean {\n    return !!this.block?.type && [BlockType.PICTURE, BlockType.TEXT].includes(this.block.type);\n  }\n\n  @computedFrom('layoutContainer.type')\n  private get isCard(): boolean {\n    return !!this.layoutContainer?.type && this.layoutContainer.type === LayoutContainerType.Card;\n  }\n\n  @computedFrom('layoutContainer.layout.direction')\n  private get hasVerticalLayout(): boolean {\n    return !!this.layoutContainer?.layout.direction\n      && this.layoutContainer.layout.direction === LayoutContainerDirection.Vertical;\n  }\n}\n\nexport interface ILayoutContainerPreviewDialogModel {\n  layoutContainerId: number;\n}\n","import { DefaultBrowserBehavior } from 'amazon-chime-sdk-js';\nimport { DialogController } from 'aurelia-dialog';\nimport { autoinject } from 'aurelia-framework';\nimport { ChimeService } from 'common/aurelia-services/ChimeService';\nimport { StoreService } from 'common/aurelia-services/StoreService';\nimport { SubscriptionManagerService } from 'common/aurelia-services/SubscriptionManagerService';\nimport { IUpdateLectureDto } from 'common/dto/tenant/event/tenant.event.interface';\nimport { setSelectedAudioInputDevice, setSelectedAudioOutputDevice, setSelectedVideoInputDevice } from 'common/store/mutations/distinar.mutations';\nimport { LogUtils } from 'common/utils/LogUtils';\nimport dayjs from 'dayjs';\nimport { cloneDeep } from 'lodash';\nimport { FocusTrapCustomDialog } from '../../../services/CustomDialog';\nimport { DateService } from '../../../services/DateService';\nimport { IState } from '../../../store/state';\n\n@autoinject()\nexport class LectureSettingsDialog extends FocusTrapCustomDialog {\n  public value!: IUpdateLectureDto<string>;\n\n  public showPreview = true;\n  public missingDate = false;\n  public endTimeBeforeStartTime = false;\n\n  private eventStartTimeString: string = '';\n  private eventEndTimeString: string = '';\n\n  private selectedAudioOutput: MediaDeviceInfo | null = null;\n  private selectedMicrophone: MediaDeviceInfo | null = null;\n  private selectedCamera: MediaDeviceInfo | null = null;\n  private hasActiveMeeting = false;\n\n  private SettingsArea = SettingsArea;\n  private selectedSettingsArea: SettingsArea = SettingsArea.General;\n  private settingsAreaItems: Array<ISettingsAreaItem> = [\n    {\n      area: SettingsArea.General,\n      icon: 'fe-settings',\n      textTk: 'dialogs.lectureSettings.general'\n    },\n    {\n      area: SettingsArea.Devices,\n      icon: 'fe-mic',\n      textTk: 'dialogs.lectureSettings.devices'\n    },\n  ];\n\n  private loading = false;\n  private supportsOutputDevice = new DefaultBrowserBehavior().supportsSetSinkId();\n\n  constructor(\n    element: Element,\n    controller: DialogController,\n    private storeService: StoreService<IState>,\n    private dateService: DateService,\n    private chimeService: ChimeService,\n    subscriptionManagerService: SubscriptionManagerService\n  ) {\n    super(controller, element, subscriptionManagerService);\n  }\n\n  public async initValue(model: ILectureSettingsDialogModel): Promise<void> {\n    this.value = cloneDeep(model.value);\n    if(model.value.plannedDateFrom && model.value.plannedDateTo) {\n      this.eventStartTimeString = model.value.plannedDateFrom ?? dayjs().startOf('day').toISOString();\n      this.eventEndTimeString = model.value.plannedDateTo ?? dayjs().startOf('day').toISOString();\n    }\n  }\n\n  protected async attached(): Promise<void> {\n    // get devices for initial selection representation\n    const {\n      distinar: {\n        conferenceConfiguration: { selectedDevices },\n        conference: { hasActiveMeeting },\n      },\n    } = await this.storeService.getState();\n\n    this.selectedAudioOutput = selectedDevices.audioOutput;\n    this.selectedMicrophone = selectedDevices.audioInput;\n    this.selectedCamera = selectedDevices.videoInput;\n    this.hasActiveMeeting = hasActiveMeeting;\n  }\n\n  protected async ok(): Promise<void> {\n    if(!this.value.plannedDateFrom) {\n      this.missingDate = true;\n      return;\n    }\n\n    this.value.plannedDateFrom = this.dateService.combineDateAndTime(this.value.plannedDateFrom, this.eventStartTimeString);\n    this.value.plannedDateTo = this.dateService.combineDateAndTime(this.value.plannedDateFrom, this.eventEndTimeString);\n\n    if(dayjs(this.value.plannedDateFrom).isAfter(this.value.plannedDateTo)) {\n      this.endTimeBeforeStartTime = true;\n      return;\n    }\n    this.loading = true;\n    try {\n      await this.storeService\n        .pipe(setSelectedAudioInputDevice, this.selectedMicrophone)\n        .pipe(setSelectedAudioOutputDevice, this.selectedAudioOutput)\n        .pipe(setSelectedVideoInputDevice, this.selectedCamera)\n        .dispatch();\n\n      if(this.hasActiveMeeting) {\n        await this.chimeService.chooseAudioInputDevice(this.selectedMicrophone?.deviceId ?? null);\n        await this.chimeService.chooseAudioOutputDevice(this.selectedAudioOutput?.deviceId ?? null);\n        await this.chimeService.chooseVideoInputDevice(this.selectedCamera?.deviceId ?? null);\n      }\n\n      this.missingDate = false;\n      this.endTimeBeforeStartTime = false;\n\n      this.controller.ok(this.value);\n    } catch(e) {\n      LogUtils.exception(e);\n    } finally {\n      this.loading = false;\n    }\n  }\n\n  private selectSettingsArea(item: ISettingsAreaItem): void {\n    this.selectedSettingsArea = item.area;\n  }\n}\n\ninterface ISettingsAreaItem {\n  area: SettingsArea;\n  icon: string;\n  textTk: string;\n}\n\nenum SettingsArea {\n  Devices = 'devices',\n  General = 'general',\n}\n\nexport interface ILectureSettingsDialogModel {\n  value: IUpdateLectureDto<string>;\n}\n","import { DialogController } from 'aurelia-dialog';\nimport { autoinject } from 'aurelia-framework';\nimport { CustomDialog } from '../../../services/CustomDialog';\nimport { IEditEventAttendeeDto, IEventOverviewUserDto } from 'common/dto/tenant/event/tenant.event.interface';\n\n@autoinject\nexport class ManageAttendanceDialog extends CustomDialog {\n  public model!: IManageAttendanceDialogModel;\n  public value: IEditEventAttendeeDto = {\n    attended: false,\n    note: ''\n  };\n\n  constructor(dialogController: DialogController) {\n    super(dialogController);\n  }\n\n  public initValue(model: IManageAttendanceDialogModel): void {\n    this.value.attended = model.user.attended;\n    this.value.note = model.user.attendanceNote ?? '';\n  }\n}\n\nexport interface IManageAttendanceDialogModel {\n  user: IEventOverviewUserDto;\n}","import { DialogController } from 'aurelia-dialog';\nimport { autoinject } from 'aurelia-framework';\nimport { IAttendanceIntervalDto, IEditAttendanceIntervalDto, IEventOverviewEventDto } from 'common/dto/tenant/event/tenant.event.interface';\nimport { ErrorType } from 'common/enum/errortype.enum';\nimport { LogUtils } from 'common/utils/LogUtils';\nimport Moment from 'moment';\nimport { EventsApiService } from '../../../services/api/EventsApiService';\nimport { CustomDialog } from '../../../services/CustomDialog';\nimport { DateService } from '../../../services/DateService';\nimport { PageLoadingIndicatorService } from '../../../services/PageLoadingIndicatorService';\nimport { ToastService } from '../../../services/ToastService';\n\n@autoinject()\nexport class ManageAttendanceIntervalsDialog extends CustomDialog {\n  public model!: IManageAttendanceIntervalsDialogModel;\n  public value: boolean | null = null;\n  private attendanceIntervals: IAttendanceIntervalDto<string>[] = [];\n  private newInterval: INewInterval = {\n    from: '',\n    to: ''\n  };\n  private errorTks: IErrorTk = {\n    addAttendanceFrom: null,\n    addAttendanceTo: null,\n  };\n\n  constructor(\n    dialogController: DialogController,\n    private dateService: DateService,\n    private eventApiService: EventsApiService,\n    private toastService: ToastService,\n    private indicatorService: PageLoadingIndicatorService\n  ) {\n    super(dialogController);\n  }\n\n  public activate(model: IManageAttendanceIntervalsDialogModel): void {\n    super.activate(model);\n    this.updateAttendanceIntervals();\n  }\n\n  private async updateAttendanceIntervals(): Promise<void> {\n    this.attendanceIntervals = await this.eventApiService.getEventAttendanceIntervals(this.model.event.id, this.model.user.id);\n  }\n\n  private async editAttendanceInterval(interval: IAttendanceIntervalDto<string>): Promise<void> {\n    interval.from = this.dateService.combineDateAndTime(this.model.event.plannedDateFrom, interval.from);\n    interval.to = this.dateService.combineDateAndTime(this.model.event.plannedDateFrom, interval.to);\n\n    if(!this.checkFromTo(interval, `editAttendanceFrom${interval.id}`, `editAttendanceTo${interval.id}`)) return;\n\n    this.indicatorService.start();\n    try {\n      const editedInterval: IEditAttendanceIntervalDto<string> = {\n        from: interval.from,\n        to: interval.to,\n      };\n      await this.eventApiService.editEventAttendanceInterval(this.model.event.id, this.model.user.id, interval.id, editedInterval);\n      this.toastService.success('dialogs.manageAttendanceIntervals.editAttendanceSuccess');\n      this.updateAttendanceIntervals();\n      this.value = true;\n    } catch(e) {\n      if(e.message === ErrorType.EVENT_ATTENDANCE_INTERVAL_OUT_OF_BOUNDS) {\n        this.toastService.error('dialogs.manageAttendanceIntervals.errors.outOfBoundsError');\n      } else {\n        LogUtils.exception(e);\n        this.toastService.error('dialogs.manageAttendanceIntervals.errors.editAttendanceError');\n      }\n    }\n    this.indicatorService.stop();\n  }\n\n  private async addAttendanceInterval(): Promise<void> {\n    if(!this.newInterval.from.length || !this.newInterval.to.length) return;\n\n    this.newInterval.from = this.dateService.combineDateAndTime(this.model.event.plannedDateFrom, this.newInterval.from);\n    this.newInterval.to = this.dateService.combineDateAndTime(this.model.event.plannedDateFrom, this.newInterval.to);\n\n    if(!this.checkFromTo(this.newInterval, 'addAttendanceFrom', 'addAttendanceTo')) return;\n\n    this.indicatorService.start();\n    try {\n      await this.eventApiService.addEventAttendanceInterval(this.model.event.id, this.model.user.id, this.newInterval);\n      this.toastService.success('dialogs.manageAttendanceIntervals.addAttendanceSuccess');\n      this.updateAttendanceIntervals();\n      this.value = true;\n      this.newInterval = {\n        from: '',\n        to: ''\n      };\n    } catch(e) {\n      if(e.message === ErrorType.EVENT_ATTENDANCE_INTERVAL_OUT_OF_BOUNDS) {\n        this.toastService.error('dialogs.manageAttendanceIntervals.errors.outOfBoundsError');\n      } else {\n        LogUtils.exception(e);\n        this.toastService.error('dialogs.manageAttendanceIntervals.errors.addAttendanceError');\n      }\n    }\n    this.indicatorService.stop();\n  }\n\n  private async deleteAttendanceInterval(intervalId: number): Promise<void> {\n    this.indicatorService.start();\n    try {\n      await this.eventApiService.deleteEventAttendanceInterval(this.model.event.id, this.model.user.id, intervalId);\n      this.toastService.success('dialogs.manageAttendanceIntervals.deleteAttendanceSuccess');\n      this.updateAttendanceIntervals();\n      this.value = true;\n    } catch(e) {\n      LogUtils.exception(e);\n      this.toastService.error('dialogs.manageAttendanceIntervals.errors.deleteAttendanceError');\n    }\n    this.indicatorService.stop();\n  }\n\n  private resetErrorTks(): void {\n    this.errorTks = {};\n  }\n\n  private checkFromTo(attendanceInterval: INewInterval | IAttendanceIntervalDto<string>, keyFrom: string, keyTo: string): boolean {\n    const start = Moment(attendanceInterval.from);\n    const end = Moment(attendanceInterval.to);\n\n    const eventStart = Moment(this.model.event.actualDateFrom ?? this.model.event.plannedDateFrom).startOf('minute');\n    const eventEnd = Moment(this.model.event.actualDateTo ?? this.model.event.plannedDateTo);\n\n    if(!start.isValid()) {\n      this.errorTks[keyFrom] = 'dialogs.manageAttendanceIntervals.errors.invalidTimeError';\n    }\n    if(!end.isValid()) {\n      this.errorTks[keyTo] = 'dialogs.manageAttendanceIntervals.errors.invalidTimeError';\n    } else if(end.isBefore(start)) {\n      this.errorTks[keyTo] = 'dialogs.manageAttendanceIntervals.errors.endBeforeStartError';\n    } else if(start.isBefore(eventStart)) {\n      this.errorTks[keyFrom] = 'dialogs.manageAttendanceIntervals.errors.startBeforeEventStartError';\n    } else if(start.isAfter(eventEnd)) {\n      this.errorTks[keyFrom] = 'dialogs.manageAttendanceIntervals.errors.startBeforeEventEndError';\n    } else if(start.isSame(end)) {\n      this.errorTks[keyFrom] = 'dialogs.manageAttendanceIntervals.errors.startIsSameAsEndError';\n      this.errorTks[keyTo] = 'dialogs.manageAttendanceIntervals.errors.startIsSameAsEndError';\n    } else if(end.isAfter(eventEnd)) {\n      this.errorTks[keyTo] = 'dialogs.manageAttendanceIntervals.errors.endBeforeEventEndError';\n    } else if(this.attendanceIntervals.some(interval => attendanceInterval.id !== interval.id && start.isBetween(interval.from, interval.to, 'minute', '()'))) {\n      this.errorTks[keyFrom] = 'dialogs.manageAttendanceIntervals.errors.overlapWithExistingIntervalsError';\n    } else if(this.attendanceIntervals.some(interval => attendanceInterval.id !== interval.id && end.isBetween(interval.from, interval.to, 'minute', '()'))) {\n      this.errorTks[keyTo] = 'dialogs.manageAttendanceIntervals.errors.overlapWithExistingIntervalsError';\n    }\n\n    return Object.values(this.errorTks).every(value => !value);\n  }\n}\n\nexport interface IManageAttendanceIntervalsDialogModel {\n  event: IEventOverviewEventDto<string>;\n  user: {\n    id: number;\n    nickname: string | null;\n  };\n}\n\nexport interface INewInterval {\n  from: string;\n  to: string;\n  id?: undefined;\n}\n\nexport interface IErrorTk {\n  [key: string]: string | null;\n}\n","import { DialogController } from 'aurelia-dialog';\nimport { SubscriptionManagerService } from 'common/aurelia-services/SubscriptionManagerService';\nimport { IMediaImportSettings } from 'common/dto/content/media/media.import';\nimport { FocusTrapCustomDialog } from '../../../services/CustomDialog';\n\nexport class MediaLibraryUploadDialog extends FocusTrapCustomDialog {\n  public value: IMediaImportSettings | null = null;\n\n  private providerSettings: IMediaImportSettings = {\n    overrideFiles: false,\n  };\n\n  constructor(\n    controller: DialogController,\n    element: Element,\n    subscriptionManagerService: SubscriptionManagerService\n  ) {\n    super(controller, element, subscriptionManagerService);\n  }\n\n  protected ok(): void {\n    this.value = this.providerSettings;\n    super.ok();\n  }\n\n  protected cancel(): void {\n    super.cancel();\n  }\n}\n","import { autoinject } from 'aurelia-framework';\nimport { GalleryMediaType } from 'common/enum/gallery.enum';\nimport { FullWidthCustomDialog } from '../../../services/CustomDialog';\nimport { Item } from '../../elements/gallery-widget/gallery-item/gallery-item';\n\n@autoinject()\nexport class MediaSelectDialog extends FullWidthCustomDialog {\n  public value: Item | null = null;\n  public model!: IMediaSelectDialogModel;\n}\n\nexport interface IMediaSelectDialogModel {\n  /**\n   * allows the switching of selected media type\n   */\n  showMediaTypeFilter?: boolean;\n  /**\n   * the default selected media type\n   */\n  selectedMediaType?: GalleryMediaType;\n\n  /**\n   * select media and displays it in the sidebar\n   */\n  preselectedMediaId?: number | null;\n  preselectedMediaType?: GalleryMediaType | null;\n}","import { DialogController } from 'aurelia-dialog';\nimport { autoinject, computedFrom, observable } from 'aurelia-framework';\nimport { StoreService } from 'common/aurelia-services/StoreService';\nimport { IMediaShareDetails } from 'common/dto/content/share/media.share.interface';\nimport { ICourseEditResponseDto } from 'common/dto/course/management/course.management.interface';\nimport { GalleryMediaType } from 'common/enum/gallery.enum';\nimport { RoleName } from 'common/enum/role.enums';\nimport { CustomDialog } from '../../../services/CustomDialog';\nimport { CourseManagementApiService } from '../../../services/api/CourseManagementApiService';\nimport { MediaShareApiService } from '../../../services/api/MediaShareApiService';\nimport { TenantApiService } from '../../../services/api/TenantApiService';\nimport { IState } from '../../../store/state';\nimport { CreateShareEvent } from '../../elements/media-share-create-form/media-share-create-form';\nimport { MediaShareEditListEntryDeleteEvent, MediaShareEditListEntryGroupsChangedEvent } from '../../elements/media-share/media-share-edit-list-entry';\n\n@autoinject()\nexport class MediaShareDialog extends CustomDialog {\n  public value!: IMediaShareDialogValue;\n  public model!: IMediaShareDialogModel;\n\n  private courses: ICourseEditResponseDto[] = [];\n  private selectedCourses: ICourseEditResponseDto[] = [];\n\n  @observable() private shares: IMediaShareDetails[] = [];\n\n  private isProvider: boolean = false;\n\n  constructor(\n    dialogController: DialogController,\n    private courseManagementApiService: CourseManagementApiService,\n    private mediaShareApiService: MediaShareApiService,\n    private tenantApi: TenantApiService,\n    private storeService: StoreService<IState>,\n  ) {\n    super(dialogController);\n  }\n\n  public initValue(model: IMediaShareDialogModel): void {\n    this.value = {\n      mediaId: model.mediaId,\n      mediaType: model.mediaType,\n      shares: [],\n    };\n  }\n\n  public activate(model: IMediaShareDialogModel): void {\n    super.activate(model);\n    this.storeService.subscribeToDetailedChanges(this, [\n      state => state.currentRole?.role === RoleName.Provider\n    ], (_, isProvider) => {\n      this.isProvider = isProvider;\n      this.loadData();\n    });\n  }\n\n  public deactivate(): void {\n    this.storeService.disposeAllSubscriptions(this);\n  }\n\n  private async loadData(): Promise<void> {\n    await this.loadCourses();\n    await this.loadShares();\n  }\n\n  private async loadCourses(): Promise<void> {\n    const courses = this.isProvider\n      ? await this.courseManagementApiService.getAvailableRegularCourses()\n      : await this.tenantApi.getAvailableRegularCourses();\n    this.courses = courses.sort((a, b) => a.title.localeCompare(b.title));\n  }\n\n  private async loadShares(): Promise<void> {\n    if(!this.value.mediaType || !this.value.mediaId) return;\n    this.shares = await this.mediaShareApiService.geExistingSharesForMedia(this.value.mediaType, this.value.mediaId);\n    this.selectedCourses = this.courses.filter(c => this.shares.some(s => s.courseId === c.id));\n  }\n\n  private getMediaShareDetails(course: ICourseEditResponseDto): IMediaShareDetails | undefined {\n    return this.shares.find(s => s.courseId === course.id);\n  }\n\n  @computedFrom('selectedCourses.length', 'courses')\n  private get availableCourses(): ICourseEditResponseDto[] {\n    const selectedCourseIds = this.selectedCourses.map(c => c.id);\n    return this.courses.filter(c => !selectedCourseIds.includes(c.id));\n  }\n\n  @computedFrom('isProvider', 'shares')\n  private get canSave(): boolean {\n    return this.isProvider || this.shares.every(s => !!s.limitToCourseGroupIds?.length);\n  }\n\n  private handleShareEntryCreated(event: CreateShareEvent): void {\n    const { share } = event.detail;\n    const course = this.courses.find(c => c.id === share.courseId);\n    if(course == null || this.selectedCourses.find(c => c.id === course.id)) return;\n    this.selectedCourses = [...this.selectedCourses, course];\n    this.shares = [...this.shares, event.detail.share];\n  }\n\n  private handleShareEntryDeleted(event: MediaShareEditListEntryDeleteEvent): void {\n    const deletedCourseId = event.detail.course.id;\n    this.selectedCourses = this.selectedCourses.filter(sc => sc.id !== deletedCourseId);\n    this.shares = this.shares.filter(s => s.courseId !== deletedCourseId);\n  }\n\n  private handleGroupsChanged(event: MediaShareEditListEntryGroupsChangedEvent): void {\n    const shareIndex = this.shares.findIndex(s => s.courseId === event.detail.course.id);\n    if(shareIndex === -1) return;\n    const share = {\n      ...this.shares[shareIndex],\n      limitToCourseGroupIds: event.detail.limitToGroups?.map(g => g.id)\n    };\n    this.shares = [...this.shares.filter(s => s.courseId !== share.courseId), share];\n  }\n\n  protected ok(): void {\n    this.value.shares = this.shares;\n    super.ok();\n  }\n\n  protected cancel(): void {\n    super.cancel();\n  }\n}\n\nexport interface IMediaShareDialogModel {\n  mediaId: number;\n  mediaType: GalleryMediaType;\n}\n\nexport interface IMediaShareDialogValue {\n  /** Will be set to null if the user decides this file is not worth sharing */\n  mediaId: number | null;\n  mediaType: GalleryMediaType | null;\n  shares: IMediaShareDetails[];\n}\n","import { autoinject } from 'aurelia-framework';\nimport { FullWidthCustomDialog } from '../../../services/CustomDialog';\n\n@autoinject()\nexport class MediaShareTableDialog extends FullWidthCustomDialog {\n  public value: null = null;\n  public model!: IMediaShareTableDialogModel;\n  private courseId: number | null = null;\n  private forTenantCoursesOnly: boolean = false;\n\n  public initValue(model: IMediaShareTableDialogModel): void {\n    this.courseId = model.courseId;\n    this.forTenantCoursesOnly = model.forTenantCoursesOnly;\n  }\n}\n\nexport interface IMediaShareTableDialogModel {\n  courseId: number;\n  forTenantCoursesOnly: boolean;\n}\n\n","import { DialogController } from 'aurelia-dialog';\nimport { autoinject } from 'aurelia-framework';\nimport { OperationStatusListReturnValue } from 'resources/elements/operation-status-list/operation-status-list';\nimport { CustomDialog } from '../../../services/CustomDialog';\nimport { OperationContext } from 'services/ExportImportService';\n\n@autoinject()\nexport class OperationStatusDialog<T> extends CustomDialog {\n  public value: Array<OperationStatusListReturnValue<T>> | null = null;\n  public model!: IOperationStatusDialogModel;\n\n  private title?: string;\n  private titleTk?: string;\n  private titleParams?: Record<string, unknown>;\n\n  private subtitle?: string;\n  private subtitleTk?: string;\n  private subtitleParams?: Record<string, unknown>;\n\n  private operationContext?: OperationContext;\n\n  constructor(\n    dialogController: DialogController,\n  ) {\n    super(dialogController);\n  }\n\n  public initValue(): void {\n    this.title = typeof this.model.title === 'string' ? this.model.title : undefined;\n    this.titleTk = typeof this.model.title === 'object' ? this.model.title.textTk : undefined;\n    this.titleParams = typeof this.model.title === 'object' ? this.model.title.params : undefined;\n\n    this.subtitle = typeof this.model.subtitle === 'string' ? this.model.subtitle : undefined;\n    this.subtitleTk = typeof this.model.subtitle === 'object' ? this.model.subtitle.textTk : undefined;\n    this.subtitleParams = typeof this.model.subtitle === 'object' ? this.model.subtitle.params : undefined;\n\n    this.operationContext = this.model.operationContext;\n  }\n  \n  private close(): void {\n    this.ok();\n  }\n}\n\nexport interface IOperationStatusDialogModel {\n  title: string | { textTk: string; params?: Record<string, unknown> };\n  subtitle?: string | { textTk: string; params?: Record<string, unknown> };\n  operationContext: OperationContext;\n}\n","import { DialogController } from 'aurelia-dialog';\nimport { autoinject, computedFrom, observable } from 'aurelia-framework';\nimport { StoreService } from 'common/aurelia-services/StoreService';\nimport { SubscriptionManagerService } from 'common/aurelia-services/SubscriptionManagerService';\nimport { ICourseEditResponseDto } from 'common/dto/course/management/course.management.interface';\nimport { IPresentationPdfOperationDto } from 'common/dto/course/management/presentation.management.interface';\nimport { ErrorType } from 'common/enum/errortype.enum';\nimport { RoleName } from 'common/enum/role.enums';\nimport { DownloadUtils } from 'common/utils/DownloadUtils';\nimport { MultiSelectComboBoxSelectedItemChangedEvent } from '../../elements/multi-select-combo-box/multi-select-combo-box';\nimport { CourseManagementApiService } from '../../../services/api/CourseManagementApiService';\nimport { PresentationManagementApiService } from '../../../services/api/PresentationManagementApiService';\nimport { TenantApiService } from '../../../services/api/TenantApiService';\nimport { FocusTrapCustomDialog } from '../../../services/CustomDialog';\nimport { ToastService } from '../../../services/ToastService';\nimport { IState } from '../../../store/state';\nimport { INavigationTab } from '../../elements/navigation-tabs/navigation-tabs';\nimport { LinkBehavior } from '../../elements/toast-controller/toasts/default-toast/default-toast';\n\n@autoinject()\nexport class PdfGeneratedDialog extends FocusTrapCustomDialog {\n  public model!: IPdfGeneratedDialogModel;\n  public value: IPdfGeneratedDialogValue = { fileIds: [], share: false };\n\n  private isProvider = false;\n  private PdfGeneratedDialogTabs = PdfGeneratedDialogTabs;\n  private activeTab = PdfGeneratedDialogTabs.Save;\n  private navigationTabs: IPdfGeneratedDialogNavigationTab[] = [];\n\n  // Save & Share\n  private courses: ICourseEditResponseDto[] = [];\n  private selectedCourses: ICourseEditResponseDto[] = [];\n  private saveToGallery = false;\n  private shareAfterSaveToGallery = false;\n\n  // Details\n  private title: string = '';\n  private description: string = '';\n  @observable() private filename: string = '';\n  private tags: string[] = [];\n\n  // Overwrite\n  private offerOverwrite = false;\n\n  constructor(\n    protected controller: DialogController,\n    private tenantApi: TenantApiService,\n    private courseManagementApiService: CourseManagementApiService,\n    private presentationManagementApiService: PresentationManagementApiService,\n    private storeService: StoreService<IState>,\n    private toastService: ToastService,\n    element: Element,\n    subscriptionManagerService: SubscriptionManagerService,\n  ) {\n    super(controller, element, subscriptionManagerService);\n  }\n\n  public activate(model: IPdfGeneratedDialogModel): void {\n    super.activate(model);\n    this.title = model.title;\n    this.filename = model.filename;\n    this.updateNavigationTabs();\n  }\n\n  public initValue(): void {\n    this.value = { fileIds: [], share: false };\n  }\n\n  protected attached(): void {\n    this.storeService.subscribeToDetailedChanges(this, [\n      state => state.currentRole,\n    ], (_, currentRole) => {\n      this.isProvider = currentRole?.role === RoleName.Provider;\n      if(this.isProvider) {\n        this.loadCourses();\n      }\n    });\n  }\n\n  protected detached(): void {\n    this.storeService.disposeAllSubscriptions(this);\n  }\n\n  @computedFrom('saveToGallery', 'selectedCourses.length')\n  private get uploadPossible(): boolean {\n    return this.saveToGallery || this.selectedCourses.length > 0;\n  }\n\n  private updateNavigationTabs(): void {\n    this.activeTab = this.model.availableTabs?.length\n      ? this.model.availableTabs[0]\n      : PdfGeneratedDialogTabs.Save;\n    this.navigationTabs = [\n      {\n        active: this.activeTab === PdfGeneratedDialogTabs.Save,\n        type: PdfGeneratedDialogTabs.Save,\n        callback: () => { this.activeTab = PdfGeneratedDialogTabs.Save; },\n        title: {\n          titleTk: 'dialogs.pdfGenerated.tabs.saveAndShare'\n        }\n      },\n      {\n        active: this.activeTab === PdfGeneratedDialogTabs.Download,\n        type: PdfGeneratedDialogTabs.Download,\n        callback: () => { this.activeTab = PdfGeneratedDialogTabs.Download; },\n        title: {\n          titleTk: 'dialogs.pdfGenerated.tabs.download'\n        }\n      },\n      {\n        active: this.activeTab === PdfGeneratedDialogTabs.Details,\n        type: PdfGeneratedDialogTabs.Details,\n        callback: () => { this.activeTab = PdfGeneratedDialogTabs.Details; },\n        title: {\n          titleTk: 'dialogs.pdfGenerated.tabs.details'\n        }\n      }\n    ];\n\n    if(this.model.availableTabs?.length) {\n      this.navigationTabs = this.navigationTabs.filter(tab => this.model.availableTabs?.includes(tab.type));\n    }\n  }\n\n  private filenameChanged(): void {\n    this.offerOverwrite = false;\n  }\n\n  private async loadCourses(): Promise<void> {\n    const courses = this.isProvider\n      ? await this.courseManagementApiService.getAvailableRegularCourses()\n      : await this.tenantApi.getAvailableRegularCourses();\n    this.courses = courses.sort((a, b) => a.title.localeCompare(b.title));\n  }\n\n  private toggleSaveToGallery(): void {\n    this.saveToGallery = !this.saveToGallery;\n  }\n\n  private toggleShareAfterSaveToGallery(): void {\n    this.shareAfterSaveToGallery = !this.shareAfterSaveToGallery;\n  }\n\n  private async handleSelectedCoursesChanged(event: MultiSelectComboBoxSelectedItemChangedEvent<ICourseEditResponseDto>): Promise<void> {\n    this.selectedCourses = event.detail.selectedItems;\n    this.offerOverwrite = false;\n  }\n\n  private handleDownloadClicked(): void {\n    DownloadUtils.download({\n      url: this.model.download.url,\n      filename: this.filename,\n    });\n  }\n\n  private async handleSubmit(): Promise<void> {\n    if(this.uploadPossible) {\n      try {\n        const overwrite = this.offerOverwrite;\n        this.offerOverwrite = false;\n        const savedFiles = await this.presentationManagementApiService.addPdfToGallery(this.model.operationId, {\n          courseIds: this.selectedCourses.map(c => c.id),\n          filename: this.filename,\n          details: {\n            tags: this.tags,\n            title: this.title,\n            description: this.description\n          },\n          overwrite,\n        });\n\n        this.toastService.success('dialogs.pdfGenerated.savedSuccessfully', {}, {\n          linkHref: this.model.download.url,\n          textTk: 'dialogs.pdfGenerated.downloadPdf',\n          behavior: LinkBehavior.Download,\n          filename: this.filename,\n        });\n        this.value = {\n          fileIds: savedFiles.fileIds,\n          share: this.shareAfterSaveToGallery,\n        };\n        this.ok();\n      } catch(e) {\n        if(e.message === ErrorType.FILE_WITH_SAME_NAME_ALREADY_EXISTS) {\n          this.offerOverwrite = true;\n        } else {\n          this.toastService.genericCreateError('globals.file');\n          throw e;\n        }\n      }\n    }\n  }\n}\n\nexport interface IPdfGeneratedDialogModel extends IPresentationPdfOperationDto {\n  operationId: number;\n  availableTabs?: PdfGeneratedDialogTabs[];\n}\n\nexport interface IPdfGeneratedDialogValue {\n  fileIds: Array<number>;\n  share: boolean;\n}\n\nexport interface IPdfGeneratedDialogNavigationTab extends INavigationTab {\n  type: PdfGeneratedDialogTabs;\n}\n\nexport enum PdfGeneratedDialogTabs {\n  Save = 'save',\n  Download = 'download',\n  Details = 'details',\n}\n","import { autoinject } from 'aurelia-framework';\nimport { IGalleryPictureDto } from 'common/dto/content/pictures/picture.gallery.interface';\nimport { CustomDialog } from 'services/CustomDialog';\n\n@autoinject\nexport class PicturePreviewDialog extends CustomDialog {\n  public model!: IPicturePreviewDialogModel;\n  public value = '';\n}\n\nexport interface IPicturePreviewDialogModel {\n  picture: IGalleryPictureDto<string>;\n}\n","import { ICourseDto } from 'common/dto/course/content/course.interface';\nimport { CustomDialog } from '../../../services/CustomDialog';\n\nexport class PointsExplanationDialog extends CustomDialog {\n  public model!: IPointsExplanationDialogModel;\n}\n\nexport interface IPointsExplanationDialogModel {\n  trainingQuestionsTotal: number;\n  course: ICourseDto | null;\n  showGames: boolean;\n}","import { autoinject } from 'aurelia-framework';\nimport { Item } from '../../elements/gallery-widget/gallery-item/gallery-item';\nimport { FullWidthCustomDialog } from '../../../services/CustomDialog';\nimport { GalleryMediaType } from 'common/enum/gallery.enum';\n\n@autoinject()\nexport class ProviderMediaSelectDialog extends FullWidthCustomDialog {\n  public model!: IProviderMediaSelectDialogModel;\n  public value: Item | null = null;\n}\n\nexport interface IProviderMediaSelectDialogModel {\n  courseId: number | null;\n  selectedMediaType: GalleryMediaType;\n}\n","import { IQuestionDto } from 'common/dto/course/content/question.interface';\nimport { VerticalDisplayMode } from 'common/enum/responsiveness-mode.enum';\nimport { FullWidthCustomDialog } from '../../../services/CustomDialog';\n\n\n\nexport class QuestionPreviewDialog extends FullWidthCustomDialog {\n  public model!: IQuestionPreviewDialogModel;\n}\n\nexport interface IQuestionPreviewDialogModel {\n  question: IQuestionDto;\n  verticalDisplayMode: VerticalDisplayMode;\n}\n","import { DialogController } from 'aurelia-dialog';\nimport { autoinject } from 'aurelia-framework';\nimport { AppUtils } from 'common/utils/AppUtils';\nimport { CourseImportApiService } from 'services/api/CourseImportApiService';\nimport { CustomDialog } from '../../../services/CustomDialog';\n\n@autoinject()\nexport class QuestionsImportDialog extends CustomDialog {\n  public model!: IQuestionsImportDialogModel;\n  public value: IQuestionsImportDialogResult | null = null;\n\n  private moduleQuestionsFilesInputValue: string | null = null;\n  private selectedModuleQuestionsFiles: FileList | null = null;\n  private selectedModuleForModuleQuestionsFile = 'A';\n  private isFrp = AppUtils.isFrp;\n\n  constructor(\n    controller: DialogController,\n    private courseImportApiService: CourseImportApiService,\n  ) {\n    super(controller);\n  }\n\n  private async startImport(): Promise<void> {\n    const file = this.selectedModuleQuestionsFiles?.[0];\n    if(file == null) return;\n\n    const operationId = await this.courseImportApiService.uploadCourseQuestions(this.model.courseId, file, this.selectedModuleForModuleQuestionsFile);\n    this.value = { operationId, fileName: file.name };\n    this.ok();\n  }\n}\n\nexport interface IQuestionsImportDialogModel {\n  courseId: number;\n}\n\nexport interface IQuestionsImportDialogResult {\n  operationId: number;\n  fileName: string;\n}\n","import { autoinject, computedFrom } from 'aurelia-framework';\nimport { CustomDialog } from '../../../services/CustomDialog';\nimport { ICourseEditResponseDto } from 'common/dto/course/management/course.management.interface';\nimport { ICreateQuizTemplateDto } from 'common/dto/course/quiz/template/quiz.template.interface';\nimport { ArrayUtils } from 'common/utils/ArrayUtils';\n\n@autoinject()\nexport class QuizTemplateCreateDialog extends CustomDialog {\n  public model!: IQuizTemplateCreateDialogModel;\n  public value!: ICreateQuizTemplateDto;\n\n  public activate(model: IQuizTemplateCreateDialogModel): void {\n    super.activate(model);\n    this.value = {\n      courseId: -1,\n      name: ''\n    };\n  }\n\n  public ok(): void {\n    if(this.value.name.length && this.value.courseId > 0) {\n      this.controller.ok(this.value);\n    }\n  }\n\n  @computedFrom('model.availableCourses')\n  private get availableCourses(): ICourseEditResponseDto[] {\n    return ArrayUtils.immutableSort(this.model.availableCourses, (a, b) => a.title.localeCompare(b.title));\n  }\n}\n\nexport interface IQuizTemplateCreateDialogModel {\n  availableCourses: ICourseEditResponseDto[];\n}\n","import { autoinject } from 'aurelia-framework';\nimport { CustomDialog } from '../../../services/CustomDialog';\nimport { IEditQuizTemplateDto, IQuizTemplateWithQuestionIdsDto } from 'common/dto/course/quiz/template/quiz.template.interface';\n\n@autoinject\nexport class QuizTemplateEditDialog extends CustomDialog {\n  public model!: IQuizTemplateEditDialogModel;\n  public value!: IEditQuizTemplateDto;\n\n  public activate(model: IQuizTemplateEditDialogModel): void {\n    super.activate(model);\n    this.value = {\n      name: model.quizTemplate.name\n    };\n  }\n}\n\nexport interface IQuizTemplateEditDialogModel {\n  quizTemplate: IQuizTemplateWithQuestionIdsDto;\n}\n","import { autoinject } from 'aurelia-framework';\nimport { IGalleryScormDto } from 'common/dto/content/scorms/scorm.gallery.interface';\nimport { CustomDialog } from 'services/CustomDialog';\n\n@autoinject()\nexport class ScormPreviewDialog extends CustomDialog {\n  public model!: IScormPreviewDialogModel;\n  public value = '';\n}\n\nexport interface IScormPreviewDialogModel {\n  scorm: IGalleryScormDto<string>;\n}\n","import { DialogController } from 'aurelia-dialog';\nimport { autoinject, computedFrom, observable } from 'aurelia-framework';\nimport { I18N } from 'aurelia-i18n';\nimport { ChatApiService } from 'common/aurelia-services/ChatApiService';\nimport { IMinimalUserDataWithId } from 'common/dto/auth/auth.interface';\nimport { CodeStatus } from 'common/dto/course/code/course.code.interface';\nimport { ColumnSortDirection, FilterOperationType } from 'common/dto/filter/filter.enum';\nimport { IFilterDto } from 'common/dto/filter/filter.interface';\nimport { SendChatMessageType } from 'common/enum/chat.message.enum';\nimport { ErrorType } from 'common/enum/errortype.enum';\nimport { LogUtils } from 'common/utils/LogUtils';\nimport { InvitationApiService } from '../../../services/api/InvitationApiService';\nimport { CustomDialog } from '../../../services/CustomDialog';\nimport { LocalCourseUser } from '../../../services/InvitationService';\nimport { ToastService } from '../../../services/ToastService';\nimport { VirtualFilterField } from '../../elements/custom-table/custom-table-helpers';\nimport {\n  EntrySelectedEvent,\n  ITextTagsWidgetTableColumn,\n  SearchStringChangedEvent,\n  TagsEditedEvent\n} from '../../elements/text-tags-widget/text-tags-widget';\n\n@autoinject()\nexport class SendMessageToStudentsDialog extends CustomDialog {\n  @observable() private triggerReLoadPossibleRecipients = false;\n\n  public model!: ISendMessageToStudentsDialogModel;\n  public value: ISendMessageToStudentsDialogValue | null = null;\n  private directMessage = true;\n  private loading = false;\n  private selectedUsers: IMinimalUserDataWithId[] = [];\n\n  private allUsers: IMinimalUserDataWithId[] = [];\n  private foundUsers: IMinimalUserDataWithId[] = [];\n  private message: string = '';\n  private userTableHeaders: string[] = [this.i18N.tr('globals.firstname'), this.i18N.tr('globals.lastname'), this.i18N.tr('globals.nickname')];\n  private userTableColumns: ITextTagsWidgetTableColumn<IMinimalUserDataWithId>[] = [\n    {\n      transformer: e => e.firstname ?? '-'\n    },\n    {\n      transformer: e => e.lastname ?? '-'\n    },\n    {\n      transformer: e => e.nickname ?? '-'\n    },\n  ];\n\n  constructor(\n    protected controller: DialogController,\n    private chatApi: ChatApiService,\n    private invitationApi: InvitationApiService,\n    private toastService: ToastService,\n    private i18N: I18N,\n  ) {\n    super(controller);\n  }\n\n  public initValue(model: ISendMessageToStudentsDialogModel): void {\n    this.directMessage = model.directMessage ?? false;\n    this.selectedUsers = model.selectedUsers ?? [];\n    this.triggerReLoadPossibleRecipients = !this.directMessage;\n  }\n\n  private async triggerReLoadPossibleRecipientsChanged(): Promise<void> {\n    if(!this.triggerReLoadPossibleRecipients) return;\n\n    const filter: IFilterDto<LocalCourseUser> = {\n      offset: 0,\n      limit: 500,\n      order: [{\n        field: 'lastname',\n        dir: ColumnSortDirection.ASC,\n      }],\n      filter: [{\n        field: 'status' as VirtualFilterField,\n        value: CodeStatus.Active,\n        type: FilterOperationType.Eq\n      }]\n    };\n    try {\n      const result = await this.invitationApi.getUsers(filter);\n      this.allUsers = result.rows;\n      this.updateUserData();\n    } catch(e) {\n      LogUtils.exception(e);\n    }\n    this.triggerReLoadPossibleRecipients = false;\n  }\n\n  private removeUsersFromList(\n    list: IMinimalUserDataWithId[],\n    toRemove: IMinimalUserDataWithId[]\n  ): IMinimalUserDataWithId[] {\n    const result: IMinimalUserDataWithId[] = [];\n    list.forEach(userToCheck => {\n      if(toRemove.findIndex(userToRemove => userToRemove.id === userToCheck.id) === -1) {\n        result.push(userToCheck);\n      }\n    });\n    return result;\n  }\n\n  private updateUserData(searchString?: string): void {\n    this.foundUsers = this.allUsers.filter(\n      user => searchString == null || searchString.length === 0\n        || user.firstname?.toLocaleLowerCase().includes(searchString.toLocaleLowerCase())\n        || user.lastname?.toLocaleLowerCase().includes(searchString.toLocaleLowerCase())\n        || user.nickname?.toLocaleLowerCase().includes(searchString.toLocaleLowerCase())\n        || this.getFullUserName(user).toLocaleLowerCase().includes(searchString.toLocaleLowerCase())\n    );\n  }\n\n  private getFullUserName(user: IMinimalUserDataWithId): string {\n    return (user.lastname ?? '') + (user.lastname ? ' ' : '') + (user.firstname ?? '');\n  }\n\n  @computedFrom('selectedUsers.length')\n  private get selectedUsersTags(): string[] {\n    return this.selectedUsers.map(user => this.getFullUserName(user));\n  }\n\n  private handleUserSearchStringChanged(event: SearchStringChangedEvent): void {\n    this.updateUserData(event.detail.searchString.trim());\n  }\n\n  private handleUserEntrySelected(event: EntrySelectedEvent<IMinimalUserDataWithId>): void {\n    const selected = event.detail.entry;\n    if(!this.isSelected(selected)) {\n      this.selectedUsers.push(selected);\n      this.updateUserData();\n    }\n  }\n\n  protected isSelected(student: IMinimalUserDataWithId): boolean {\n    return !!this.selectedUsers.find(user => user.id === student.id);\n  }\n\n  private handleUserEntryRemoved(event: TagsEditedEvent): void {\n    this.selectedUsers = this.selectedUsers.filter(user => event.detail.tags.includes(this.getFullUserName(user)));\n    this.updateUserData();\n  }\n\n  private async sendSingle(): Promise<void> {\n    const msgBaseTk = `dialogs.sendMessageToStudents.send${this.selectedUsers.length < 2 ? 'Single' : 'Multiple'}`;\n    this.value = { chatRoomIds: [] };\n    this.loading = true;\n    try {\n      for(let i = 0; i < this.selectedUsers.length; i++) {\n        const chatRoomId = await this.chatApi.getChatRoomId(this.selectedUsers[i].id);\n        await this.chatApi.sendMessage(chatRoomId, {\n          anonymous: false,\n          text: this.message,\n          type: SendChatMessageType.Regular,\n        });\n        this.value.chatRoomIds.push(chatRoomId);\n      }\n      this.toastService.success(`${msgBaseTk}Success`);\n      this.ok();\n    } catch(e) {\n      this.handleSendError(e, msgBaseTk);\n    } finally {\n      this.loading = false;\n    }\n  }\n\n  private handleSendError(error: Error, msgBaseTk: string): void {\n    if(error.message === ErrorType.CANNOT_MESSAGE_YOURSELF) {\n      this.toastService.error('dialogs.sendMessageToStudents.cannotMessageYourselfError');\n    } else if(error.message === ErrorType.VALIDATION_FAILED) {\n      this.toastService.error('dialogs.sendMessageToStudents.cannotSendEmptyMessage');\n    } else {\n      this.toastService.error(`${msgBaseTk}Error`);\n    }\n  }\n}\n\n/**\n * dialog configuration:\n * * directMessage implies 1:1 mode without recipient tag search select,\n * * selectedUsers: CAN be provided for 1:n message; MUST be provided for 1:1 message\n */\nexport interface ISendMessageToStudentsDialogModel {\n  directMessage?: boolean;\n  selectedUsers?: IMinimalUserDataWithId[];\n}\n\nexport interface ISendMessageToStudentsDialogValue {\n  chatRoomIds: number[];\n}\n","import { DialogController } from 'aurelia-dialog';\nimport { autoinject, observable } from 'aurelia-framework';\nimport { StoreService } from 'common/aurelia-services/StoreService';\nimport { Config } from 'common/fe-config/config';\nimport { toDataURL } from 'qrcode';\nimport { CustomDialog } from '../../../services/CustomDialog';\nimport { IState } from '../../../store/state';\n\n@autoinject\nexport class ShowDistinarQrCodeDialog extends CustomDialog {\n  public model!: IShowDistinarQrCodeDialogModel;\n\n  constructor(\n    protected controller: DialogController,\n    private storeService: StoreService<IState>,\n  ) {\n    super(controller);\n  }\n\n  @observable() private code: string | null = null;\n  private qrCodeDataUrl: string | null = null;\n\n  public activate(model: IShowDistinarQrCodeDialogModel): void {\n    super.activate(model);\n  }\n\n\n  protected attached(): void {\n    this.storeService.subscribeToDetailedChanges(this, [\n      state => state.distinar.lectureStatus?.qrCode?.shown\n    ], (_, isQrCodeShown) => {\n      if(!isQrCodeShown) this.ok();\n    });\n\n    this.storeService.subscribeToDetailedChanges(this, [\n      state => state.distinar.activeLecture?.code\n    ], (_, code) => {\n      this.code = code ?? null;\n    });\n  }\n\n  protected detached(): void {\n    this.storeService.disposeAllSubscriptions(this);\n  }\n\n  private codeChanged(): void {\n    this.updateQrCode();\n  }\n\n  private handleSubmit(): void {\n    this.controller.cancel();\n  }\n\n  private async updateQrCode(): Promise<void> {\n    const codePayload = `${Config().ufe.baseUrl}/#/distinar/code/${this.code}`;\n    this.qrCodeDataUrl = this.code && await toDataURL(codePayload, {\n      margin: 0,\n      width: 280,\n    });\n  }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface IShowDistinarQrCodeDialogModel {\n}\n","import { DialogController } from 'aurelia-dialog';\nimport { autoinject } from 'aurelia-framework';\nimport { I18N } from 'aurelia-i18n';\nimport { ColumnSortDirection } from 'common/dto/filter/filter.enum';\nimport { IFilterDto } from 'common/dto/filter/filter.interface';\nimport { IEventUserWithCourseGroupsOverviewDto } from 'common/dto/tenant/event/tenant.event.interface';\nimport { EventsApiService } from '../../../services/api/EventsApiService';\nimport { CustomDialog } from '../../../services/CustomDialog';\nimport { AvatarCell } from '../../elements/custom-table/avatar-cell/avatar-cell';\nimport { CustomTableCell } from '../../elements/custom-table/custom-table-cell/custom-table-cell';\nimport { createPrepareServersideSortingFunction, prepareServersideFiltering } from '../../elements/custom-table/custom-table-helpers';\nimport { IColumnDefinition } from '../../elements/custom-table/custom-table-interfaces';\n\n@autoinject()\nexport class ShowStudentsDialog extends CustomDialog {\n  public value: number | null = null;\n  public model!: IShowStudentsDialogModel;\n  private filter: IFilterDto<IEventUserWithCourseGroupsOverviewDto> = {\n    offset: 0,\n    limit: 0,\n    order: [{\n      field: 'lastname',\n      dir: ColumnSortDirection.ASC,\n    }],\n    filter: []\n  };\n\n  constructor(\n    protected controller: DialogController,\n    private i18n: I18N,\n    private eventApi: EventsApiService,\n  ) {\n    super(controller);\n  }\n\n  public activate(model: IShowStudentsDialogModel): void {\n    super.activate(model);\n  }\n\n  private tableColumns: Array<IColumnDefinition<AvatarCell<IEventUserWithCourseGroupsOverviewDto> | CustomTableCell<IEventUserWithCourseGroupsOverviewDto>>> = [\n    {\n      id: 'avatar',\n      nameTk: 'pages.students.columns.avatar',\n      cellViewModel: AvatarCell,\n      cellOptions: {\n        avatarSvgDownloadLink: u => u.avatarSvgDownloadLink ?? null,\n        points: () => 0,\n        online: () => false\n      },\n    },\n    {\n      id: 'firstname',\n      nameTk: 'globals.firstname',\n      cellViewModel: CustomTableCell,\n      cellOptions: {\n        transformer: u => u.firstname ?? this.i18n.tr('globals.empty'),\n        callback: u => this.navigateToStudentInvitationsPage(u.id),\n        clickable: () => true,\n      },\n      prepareSorting: createPrepareServersideSortingFunction(() => this.filter, 'firstname'),\n      filter: {\n        placeholderTk: 'globals.filter',\n        prepare: i => prepareServersideFiltering(this.filter, 'firstname', i),\n      },\n    },\n    {\n      id: 'lastname',\n      nameTk: 'globals.lastname',\n      cellViewModel: CustomTableCell,\n      cellOptions: {\n        transformer: u => u.lastname ?? this.i18n.tr('globals.empty'),\n        callback: u => this.navigateToStudentInvitationsPage(u.id),\n        clickable: () => true,\n      },\n      prepareSorting: createPrepareServersideSortingFunction(() => this.filter, 'lastname'),\n      filter: {\n        placeholderTk: 'globals.filter',\n        prepare: u => prepareServersideFiltering(this.filter, 'lastname', u),\n      },\n    },\n    {\n      id: 'nickname',\n      nameTk: 'globals.nickname',\n      cellViewModel: CustomTableCell,\n      cellOptions: {\n        transformer: u => u.nickname ?? this.i18n.tr('globals.empty'),\n        callback: u => this.navigateToStudentInvitationsPage(u.id),\n        clickable: () => true,\n      },\n      prepareSorting: createPrepareServersideSortingFunction(() => this.filter, 'nickname'),\n      filter: {\n        placeholderTk: 'globals.filter',\n        prepare: u => prepareServersideFiltering(this.filter, 'nickname', u),\n      },\n    },\n    {\n      id: 'invitationType',\n      nameTk: 'dialogs.showStudents.invitationType',\n      cellViewModel: CustomTableCell,\n      cellOptions: {\n        transformer: u => u.courseGroups.length\n          ? u.courseGroups.map(course => course.name).join(', ')\n          : this.i18n.tr('globals.personalInvitation')\n      },\n      wrap: true\n    },\n  ];\n\n  private async fetchTableData(limit: number, offset: number): Promise<{ total: number; data: IEventUserWithCourseGroupsOverviewDto[] }> {\n    this.filter.limit = limit;\n    this.filter.offset = offset;\n    const results = await this.eventApi.getEventUsers(this.model.eventId, this.filter);\n    return { data: results.rows, total: results.count };\n  }\n\n  private navigateToStudentInvitationsPage(userId: number): void {\n    this.value = userId;\n    this.controller.ok(this.value);\n  }\n}\n\nexport interface IShowStudentsDialogModel {\n  eventId: number;\n}\n","import { DialogController } from 'aurelia-dialog';\nimport { autoinject } from 'aurelia-framework';\nimport { ICourseRatingDto } from 'common/dto/course/content/course.interface';\nimport { CustomDialog } from '../../../services/CustomDialog';\nimport { DateService } from '../../../services/DateService';\n\n@autoinject\nexport class SingleRatingDialog extends CustomDialog {\n  public value = true;\n\n  constructor(\n    controller: DialogController,\n    private dateService: DateService,\n  ) {\n    super(controller);\n  }\n\n  private formatDate(date: string): string {\n    return this.dateService.formatDate(date);\n  }\n}\n\nexport interface ISingleRatingDialogModel {\n  rating: ICourseRatingDto<string>;\n  showNavigateButton?: boolean;\n}\n","import { DialogController } from 'aurelia-dialog';\nimport { autoinject } from 'aurelia-framework';\nimport { SubscriptionManagerService } from 'common/aurelia-services/SubscriptionManagerService';\nimport { ABSOLUTE_MAX_QUESTIONS } from 'common/constants/quiz.constants';\nimport { ICourseEditResponseDto } from 'common/dto/course/management/course.management.interface';\nimport { IAttendeeDto, IPrepareQuickQuizDto } from 'common/dto/distinar/distinar.interface';\nimport { QuizAnswerTime } from 'common/enum/quiz.attempt.status.enum';\nimport { ArrayUtils } from 'common/utils/ArrayUtils';\nimport { DomUtils } from 'common/utils/DomUtils';\nimport { MathUtils } from 'common/utils/MathUtils';\nimport { DistinarApiService } from '../../../services/api/DistinarApiService';\nimport { FocusTrapCustomDialog } from '../../../services/CustomDialog';\nimport { MultiSelectComboBoxSelectedItemChangedEvent } from '../../elements/multi-select-combo-box/multi-select-combo-box';\n\n@autoinject()\nexport class StartQuickQuizDialog extends FocusTrapCustomDialog {\n  public model!: IStartQuickQuizDialogModel;\n  public value: IPrepareQuickQuizDto | null = null;\n\n  private availableCourses: ICourseEditResponseDto[] = [];\n  private selectedCourse: ICourseEditResponseDto | null = null;\n\n  private availableChapters: IChapterSelectModel[] = [];\n  private selectedChapters: IChapterSelectModel[] = [];\n\n  private numberOfQuestions = ABSOLUTE_MAX_QUESTIONS;\n  private maxNumberOfQuestions = 0;\n  private selectedNumberOfQuestions = ABSOLUTE_MAX_QUESTIONS;\n  private ABSOLUTE_MAX_QUESTIONS = ABSOLUTE_MAX_QUESTIONS;\n\n  private answerTimes: Array<QuizAnswerTime> = [\n    QuizAnswerTime.Short,\n    QuizAnswerTime.Medium,\n    QuizAnswerTime.Long,\n    QuizAnswerTime.Manual,\n  ];\n  private selectedAnswerTime = QuizAnswerTime.Manual;\n\n  constructor(\n    controller: DialogController,\n    element: Element,\n    subscriptionManagerService: SubscriptionManagerService,\n    private distinarApiService: DistinarApiService\n  ) {\n    super(controller, element, subscriptionManagerService);\n  }\n\n  public activate(model: IStartQuickQuizDialogModel): void {\n    super.activate(model);\n    this.sortCoursesByAttendeeCount();\n    this.setSelectedCourse(this.availableCourses[0]?.id ?? null);\n    this.updateConfiguration();\n  }\n\n  private handleCourseSelectChanged(event: Event): void {\n    const courseId = DomUtils.extractChangeEventValueAsNumber(event);\n    if(Number.isNaN(courseId)) {\n      this.setSelectedCourse(null);\n    } else {\n      this.setSelectedCourse(courseId);\n    }\n  }\n\n  private async setSelectedCourse(courseId: number | null): Promise<void> {\n    this.selectedCourse = courseId === null\n      ? null\n      : this.availableCourses.find(c => c.id === courseId) ?? null;\n    this.updateConfiguration();\n    this.updateQuestionCount();\n  }\n\n  private handleChapterChanged(event: MultiSelectComboBoxSelectedItemChangedEvent<IChapterSelectModel>): void {\n    this.selectedChapters = event.detail.selectedItems;\n    this.updateQuestionCount();\n  }\n\n  private updateQuestionCount(): void {\n    this.maxNumberOfQuestions = this.selectedChapters.reduce((acc, chapter) => acc + chapter.numberOfQuestions, 0);\n    this.numberOfQuestions = Math.min(this.maxNumberOfQuestions, ABSOLUTE_MAX_QUESTIONS);\n  }\n\n  private async updateConfiguration(): Promise<void> {\n    this.selectedChapters = [];\n    if(this.selectedCourse) {\n      const chapters = await this.distinarApiService.getQuickQuizChapters(this.selectedCourse.id);\n      this.availableChapters = chapters\n        .sort((a, b) => a.title.localeCompare(b.title));\n    }\n  }\n\n  private handleNumberOfQuestionsChanged(event: Event): void {\n    const numberOfQuestions = DomUtils.extractChangeEventValueAsNumber(event);\n    if(!Number.isNaN(numberOfQuestions)) {\n      const currentMax = Math.min(this.maxNumberOfQuestions, ABSOLUTE_MAX_QUESTIONS);\n      this.selectedNumberOfQuestions = MathUtils.clamp(numberOfQuestions, 1, currentMax);\n      this.numberOfQuestions = Math.min(this.selectedNumberOfQuestions, currentMax);\n    }\n  }\n\n  private startQuickQuiz(): void {\n    if(!this.selectedCourse || !this.selectedChapters.length) return;\n    const value = {\n      courseId: this.selectedCourse.id,\n      chapterIds: this.selectedChapters.map(c => c.pageId),\n      questionCount: this.selectedNumberOfQuestions,\n      answerTime: this.selectedAnswerTime\n    };\n    this.controller.ok(value);\n  }\n\n  private sortCoursesByAttendeeCount(): void {\n    const { availableCourses, attendees } = this.model;\n    const attendeeCountsByCourseId: Partial<Record<number, number>> = ArrayUtils.toRecord(attendees, a => a.courseId, (_, existing) => (existing ?? 0) + 1);\n    this.availableCourses = ArrayUtils.immutableSort(availableCourses, (a, b) => (attendeeCountsByCourseId[b.id] ?? 0) - (attendeeCountsByCourseId[a.id] ?? 0));\n  }\n}\n\nexport interface IStartQuickQuizDialogModel {\n  availableCourses: Array<ICourseEditResponseDto>;\n  attendees: IAttendeeDto[];\n}\n\nexport interface IChapterSelectModel {\n  pageId: number;\n  title: string;\n  numberOfQuestions: number;\n}\n","import { DialogController } from 'aurelia-dialog';\nimport { autoinject } from 'aurelia-framework';\nimport { SubscriptionManagerService } from 'common/aurelia-services/SubscriptionManagerService';\nimport { QuizAnswerTime } from 'common/enum/quiz.attempt.status.enum';\nimport { FocusTrapCustomDialog } from '../../../services/CustomDialog';\n\n@autoinject()\nexport class StartTemplateQuizDialog extends FocusTrapCustomDialog {\n  public value!: IStartTemplateQuizDialogValue;\n\n  private answerTimes: Array<QuizAnswerTime> = [\n    QuizAnswerTime.Short,\n    QuizAnswerTime.Medium,\n    QuizAnswerTime.Long,\n    QuizAnswerTime.Manual,\n  ];\n\n  constructor(\n    controller: DialogController,\n    element: Element,\n    subscriptionManagerService: SubscriptionManagerService\n  ) {\n    super(controller, element, subscriptionManagerService);\n  }\n\n  public activate(model: IStartTemplateQuizDialogValue): void {\n    super.activate(model);\n    this.value = {\n      answerTime: QuizAnswerTime.Manual\n    };\n  }\n}\n\nexport interface IStartTemplateQuizDialogValue {\n  answerTime: QuizAnswerTime;\n}\n","import { DialogController } from 'aurelia-dialog';\nimport { IImportStudentDto } from 'common/dto/import/import.interface';\nimport { autoinject, computedFrom } from 'aurelia-framework';\nimport { I18N } from 'aurelia-i18n';\nimport { CustomTableCell } from '../../elements/custom-table/custom-table-cell/custom-table-cell';\nimport { IColumnDefinition } from '../../elements/custom-table/custom-table-interfaces';\nimport { CustomDialog } from '../../../services/CustomDialog';\nimport { IText } from 'common/interfaces/translations.interface';\n\n@autoinject()\nexport class StudentImportDialog extends CustomDialog {\n  public model!: IStudentImportDialogModel;\n\n  private tableColumns: Array<IColumnDefinition<CustomTableCell<IImportStudentDto>>> = [\n    {\n      id: 'firstname',\n      nameTk: 'globals.firstname',\n      cellViewModel: CustomTableCell,\n      cellOptions: {\n        property: 'firstname'\n      },\n    },\n    {\n      id: 'lastname',\n      nameTk: 'globals.lastname',\n      cellViewModel: CustomTableCell,\n      cellOptions: {\n        property: 'lastname'\n      },\n    },\n    {\n      id: 'email',\n      nameTk: 'globals.email',\n      cellViewModel: CustomTableCell,\n      cellOptions: {\n        property: 'email'\n      },\n    },\n    {\n      id: 'importSuccess',\n      nameTk: 'dialogs.studentImport.importStatus',\n      cellViewModel: CustomTableCell,\n      cellOptions: {\n        spanClasses: r => r.importSuccessful ? 'text-success' : 'text-info',\n        transformer: r => this.i18N.tr(`dialogs.studentImport.${r.importSuccessful ? 'successful' : 'skipped'}`)\n      },\n    },\n  ];\n\n  constructor(\n    private i18N: I18N,\n    controller: DialogController,\n  ) {\n    super(controller);\n  }\n\n  @computedFrom('model.students')\n  private get errorMessage(): IText | null {\n    const unSuccessFullyImportedCount = this.model.students.filter(s => !s.importSuccessful).length;\n    return unSuccessFullyImportedCount\n      ? { tk: 'dialogs.studentImport.errorMsg', tkParams: { count: unSuccessFullyImportedCount } }\n      : null;\n  }\n\n  @computedFrom('model.students')\n  private get infoMessage(): IText | null {\n    const successFullyImportedCount = this.model.students.filter(s => s.importSuccessful).length;\n    return successFullyImportedCount\n      ? { tk: 'dialogs.studentImport.successMsg', tkParams: { count: successFullyImportedCount } }\n      : null;\n  }\n\n  @computedFrom('model.students')\n  private get warnMessage(): IText | null {\n    const inValidExamDateImportedCount = this.model.students.filter(s => s.importSuccessful && !s.examDateValid).length;\n    return inValidExamDateImportedCount\n      ? { tk: 'dialogs.studentImport.successInvalidExamDateMsg', tkParams: { count: inValidExamDateImportedCount } }\n      : null;\n  }\n}\n\nexport interface IStudentImportDialogModel {\n  students: IImportStudentDto[];\n}\n","import { DialogController } from 'aurelia-dialog';\nimport { autoinject } from 'aurelia-framework';\nimport { ICourseCodeResponseDto } from 'common/dto/course/code/course.code.interface';\nimport { CustomDialog } from '../../../services/CustomDialog';\n\n@autoinject()\nexport class TransferInvitationWarningDialog extends CustomDialog {\n  public value: boolean | null = null;\n  public model!: ITransferInvitationWarningDialogModel;\n\n  constructor(\n    protected controller: DialogController,\n  ) {\n    super(controller);\n  }\n\n  public activate(model: ITransferInvitationWarningDialogModel): void {\n    super.activate(model);\n  }\n\n  public ok(): void {\n    this.value = true;\n    this.controller.ok(this.value);\n  }\n}\n\nexport interface ITransferInvitationWarningDialogModel {\n  transferableCodes: ICourseCodeResponseDto<string>[];\n}\n","import { autoinject } from 'aurelia-framework';\nimport { IGalleryVideoDto } from 'common/dto/content/videos/video.gallery.interface';\nimport { CustomDialog } from 'services/CustomDialog';\n\n@autoinject\nexport class VideoPreviewDialog extends CustomDialog {\n  public model!: IVideoPreviewDialogModel;\n  public value = '';\n}\n\nexport interface IVideoPreviewDialogModel {\n  picture: IGalleryVideoDto<string>;\n}\n"],"names":[],"sourceRoot":""}