UNPKG

@digital-blueprint/formalize-app

Version:

[GitHub Repository](https://github.com/digital-blueprint/formalize-app) | [npmjs package](https://www.npmjs.com/package/@digital-blueprint/formalize-app) | [Unpkg CDN](https://unpkg.com/browse/@digital-blueprint/formalize-app/) | [Formalize Bundle](https:

1,021 lines (906 loc) • 42.6 kB
import {BaseFormElement, BaseObject} from '../form/base-object.js'; import {html, css} from 'lit'; import {classMap} from 'lit/directives/class-map.js'; import * as commonStyles from '@dbp-toolkit/common/styles.js'; import {sendNotification, Translated} from '@dbp-toolkit/common'; import {DbpStringElement, DbpStringView} from '@dbp-toolkit/form-elements'; import {DbpCourseSelectElement} from '../form/elements/courseselect.js'; import {DeletionConfirmationModal} from '../deletion-confirmation-modal.js'; import {getFormRenderUrl, SUBMISSION_STATES, getFormManageFormsUrl} from '../utils.js'; import {validateRequiredFields} from '@dbp-toolkit/form-elements/src/utils.js'; export default class extends BaseObject { getUrlSlug() { // URL-Slug return 'accessible-courses'; } getFormComponent() { return FormalizeFormElement; } hasReadOnlyMode() { return true; } // Formalize-Formular-ID for course registration getFormIdentifier() { return '019ada3e-b7ff-7b35-b1dd-7b578d810955'; } } class FormalizeFormElement extends BaseFormElement { constructor() { super(); this.saveButtonEnabled = false; this.isUserAllowedToDownloadPdf = false; this._fetchingUserData = false; this._userDataFetched = false; this.wasSubmissionSuccessful = false; // ensuring we have an object to extend this.formData = this.formData || {}; this.handleFormDeleteSubmission = this.handleFormDeleteSubmission.bind(this); this.handleFormSaveSubmission = this.handleFormSaveSubmission.bind(this); this.handleValidationOnFocusOut = this.handleValidationOnFocusOut.bind(this); } static get properties() { return { ...super.properties, }; } connectedCallback() { super.connectedCallback(); void this.updateComplete.then(() => { // Event listener for delete submission this.addEventListener( 'DbpFormalizeFormDeleteSubmission', this.handleFormDeleteSubmission, ); // Handle field validation on focus out this.renderRoot.addEventListener('focusout', this.handleValidationOnFocusOut, { capture: true, }); this.addEventListener('DbpFormalizeFormSaveSubmission', this.handleFormSaveSubmission); this.addEventListener( 'DbpFormalizeFormSubmission', async (/** @type {CustomEvent} */ event) => { const formData = event.detail.formData; const i18n = this._i18n; // use Lecturer-Array from formData formData.lecturers = this.formData.lecturers || []; try { this.isPostingSubmission = true; if (this.wasSubmissionSuccessful) return; // submit relevant data const payload = { courseName: formData.courseName, courseIdentifier: this.formData.courseIdentifier ?? '', lecturers: formData.lecturers, groupAssignment: formData.groupAssignment ?? '', adaptations: formData.adaptations, matriculationNumber: formData.matriculationNumber ?? '', studentGivenName: formData.studentGivenName ?? '', studentFamilyName: formData.studentFamilyName ?? '', studentEmail: formData.studentEmail ?? '', comment: formData.comment ?? '', }; const body = { form: '/formalize/forms/' + '019ada3e-b7ff-7b35-b1dd-7b578d810955', dataFeedElement: JSON.stringify(payload), }; const response = await fetch( this.entryPointUrl + '/formalize/submissions', { method: 'POST', headers: { 'Content-Type': 'application/ld+json', Authorization: 'Bearer ' + this.getToken(), }, body: JSON.stringify(body), }, ); if (!response.ok) { this.saveButtonEnabled = true; await this.displayErrors(response); } else { this.wasSubmissionSuccessful = true; this._('.form-title').style.display = 'none'; this._('.description').style.display = 'none'; this._('#accessible-courses-form').style.display = 'none'; this.disableLeavePageWarning(); sendNotification({ summary: i18n.t('success.success-title'), body: i18n.t('success.form-saved-successfully'), type: 'success', timeout: 5, }); // Notify parent component to refresh submission data window.dispatchEvent( new CustomEvent('dbpFormDataUpdated', { detail: {needUpdate: true}, bubbles: true, composed: true, }), ); } this.submitted = this.wasSubmissionSuccessful; return response; } catch (error) { console.error(error.message); } finally { this.isPostingSubmission = false; } }, ); }); } disconnectedCallback() { super.disconnectedCallback(); this.removeEventListener('DbpFormalizeFormSaveSubmission', this.handleFormSaveSubmission); this.removeEventListener( 'DbpFormalizeFormDeleteSubmission', this.handleFormDeleteSubmission, ); this.renderRoot.removeEventListener('focusout', this.handleValidationOnFocusOut, { capture: true, }); } /** * Run validation on focus out of form elements and set isFormValid property * @param {Event} event */ async handleValidationOnFocusOut(event) { const currentUrl = window.location.href; const url = new URL(currentUrl); const needsValidation = url.searchParams.get('validate'); if (needsValidation !== 'true') return; // Only if validation is needed const formElement = this.formElement; this.isFormValid = await validateRequiredFields(formElement); } static get scopedElements() { return { ...super.scopedElements, 'dbp-form-string-element': DbpStringElement, 'dbp-form-string-view': DbpStringView, 'dbp-course-select-element': DbpCourseSelectElement, 'dbp-deletion-confirmation-modal': DeletionConfirmationModal, 'dbp-translated': Translated, }; } async fetchUserData() { try { const response = await fetch( this.entryPointUrl + '/base/people/' + this.getUserId() + '?includeLocal=email,matriculationNumber', { headers: { 'Content-Type': 'application/ld+json', Authorization: 'Bearer ' + this.getToken(), }, }, ); if (!response.ok) { throw new Error( `Request failed with status ${response.status}: ${response.statusText}`, {cause: response}, ); } const person = await response.json(); // A submission may have been loaded while the request was in flight. // Its saved personal data must not be replaced by the current user's data. if (this.data?.identifier) return; // completing/updating fields this.formData = this.formData || {}; this.formData.identifier = String(person.identifier ?? ''); this.formData.studentGivenName = String(person.givenName ?? ''); this.formData.studentFamilyName = String(person.familyName ?? ''); this.formData.matriculationNumber = String(person.localData?.matriculationNumber ?? ''); this.formData.studentEmail = String(person.localData?.email ?? ''); this.requestUpdate(); } catch (error) { console.error(error.message); } } getLecturerFallbackLabel() { return String(this.lang || '').startsWith('de') ? 'Lehrende*r unbekannt' : 'Unknown lecturer'; } getLecturerList(lecturers) { if (Array.isArray(lecturers)) { return lecturers.map((lecturer) => String(lecturer).trim()).filter(Boolean); } if (typeof lecturers === 'string') { return lecturers .split('\n') .map((lecturer) => lecturer.trim()) .filter(Boolean); } return []; } // Reaction to dbp-course-changed async handleCourseChange(e) { this.saveButtonEnabled = false; if (!this.formData) { this.formData = {}; } this.formData.groupAssignment = ''; const course = e.detail?.course; this.formData.courseIdentifier = course?.identifier ?? ''; if (!course) { this.formData.lecturers = [this.getLecturerFallbackLabel()]; this.requestUpdate(); return; } const lecturerIds = Array.isArray(course.localData?.lecturers) ? course.localData.lecturers .map((lecturer) => { if (typeof lecturer === 'string') { return lecturer.trim(); } if (lecturer && typeof lecturer === 'object') { return String(lecturer.personIdentifier || '').trim(); } return ''; }) .filter((lecturerId) => lecturerId !== '') : []; const lecturerStrings = []; // If no lecturer IDs are available at all, use the fallback label. if (lecturerIds.length === 0) { lecturerStrings.push(this.getLecturerFallbackLabel()); } else { for (const lecturerId of lecturerIds) { if (!lecturerId) { lecturerStrings.push(this.getLecturerFallbackLabel()); continue; } try { const resp = await fetch( `${this.entryPointUrl}/base/people/${lecturerId}?includeLocal=email`, { headers: { 'Content-Type': 'application/ld+json', Authorization: 'Bearer ' + this.getToken(), }, }, ); if (!resp.ok) { console.warn('Lecturer fetch failed for', lecturerId, resp.status); lecturerStrings.push(this.getLecturerFallbackLabel()); continue; } const person = await resp.json(); const name = `${person.givenName ?? ''} ${person.familyName ?? ''}`.trim(); const email = person.localData?.email ?? null; const isOpaqueIdentifier = typeof lecturerId === 'string' && /^[A-Z0-9]{8,}$/.test(lecturerId) && !/[\s@]/.test(lecturerId); if (!name && isOpaqueIdentifier) { lecturerStrings.push(this.getLecturerFallbackLabel()); continue; } const label = email ? `${name} (${email})` : name; lecturerStrings.push(label || this.getLecturerFallbackLabel()); } catch (err) { console.error('Error fetching lecturer', lecturerId, err); lecturerStrings.push(this.getLecturerFallbackLabel()); } } } this.saveButtonEnabled = true; this.formData.lecturers = lecturerStrings; this.requestUpdate(); } /** * Handle deleting submission. * @param {CustomEvent} event - The event object containing the submission id to delete. */ async handleFormDeleteSubmission(event) { const i18n = this._i18n; const data = event.detail; const submissionId = data.submissionId; if (!submissionId) { sendNotification({ summary: i18n.t('errors.error-title'), body: i18n.t('errors.no-submission-id-provided'), type: 'danger', timeout: 0, }); return; } const confirmed = await this._('#deletion-modal').confirm(); if (!confirmed) return; try { const response = await fetch( this.entryPointUrl + `/formalize/submissions/${submissionId}`, { method: 'DELETE', headers: { Authorization: 'Bearer ' + this.getToken(), }, }, ); if (!response.ok) { this.deleteSubmissionError = true; sendNotification({ summary: i18n.t('errors.error-title'), body: i18n.t('errors.failed-to-delete-submission-status', { status: response.status, }), type: 'danger', timeout: 0, }); } else { this.wasDeleteSubmissionSuccessful = true; this.deleteSubmissionError = false; } } catch (error) { console.error(error); sendNotification({ summary: i18n.t('errors.error-title'), body: i18n.t('errors.unknown-error-on-delete-submission'), type: 'danger', timeout: 0, }); } finally { if (this.wasDeleteSubmissionSuccessful) { sendNotification({ summary: i18n.t('success.success-title'), body: i18n.t('success.form-submission-deleted-successfully'), type: 'success', timeout: 5, }); const emptyFormUrl = getFormRenderUrl(this.formUrlSlug, this.lang); window.history.pushState({}, '', emptyFormUrl.toString()); this.resetForm(event); this.readOnly = false; this.sendSetPropertyEvent('routing-url', `/${this.formUrlSlug}`); } } } /** * Handle save (PATCH) submission. * @param {CustomEvent} event - The event object containing the form data. */ async handleFormSaveSubmission(event) { const i18n = this._i18n; if (!event.detail.submissionId) return; const data = event.detail.formData; const formData = new FormData(); data.lecturers = this.getLecturerList(data.lecturers); const payload = { courseName: data.courseName, courseIdentifier: this.formData.courseIdentifier ?? '', lecturers: data.lecturers, groupAssignment: data.groupAssignment ?? '', adaptations: data.adaptations, matriculationNumber: data.matriculationNumber ?? '', studentGivenName: data.studentGivenName ?? '', studentFamilyName: data.studentFamilyName ?? '', studentEmail: data.studentEmail ?? '', comment: data.comment ?? '', }; formData.append('dataFeedElement', JSON.stringify(payload)); const options = this._buildRequestOptions(formData, 'PATCH'); const url = this._buildSubmissionUrl(event.detail.submissionId); try { const response = await fetch(url, options); if (!response.ok) { await this.displayErrors(response); } else { // formDataUpdated event to notify parent component this.dispatchEvent( new CustomEvent('dbpFormDataUpdated', { detail: { needUpdate: true, }, bubbles: true, composed: true, }), ); this.disableLeavePageWarning(); sendNotification({ summary: i18n.t('success.success-title'), body: i18n.t('success.form-saved-successfully'), type: 'success', timeout: 5, }); } } catch (error) { console.error(error); sendNotification({ summary: i18n.t('errors.error-title'), body: i18n.t('errors.unknown-error-on-save-submission'), type: 'danger', timeout: 0, }); } } static get styles() { return [ super.styles, commonStyles.getButtonCSS(), css` .field-note { margin-top: 0; font-style: italic; } fieldset { margin-bottom: 20px; } .description a { text-decoration: underline; text-underline-offset: 2px; transition: text-underline-offset 0.1s ease-in; } .description a:hover { text-underline-offset: 1px; } `, ]; } render() { return html` ${ this.readOnly ? html` ${this.renderFormViews()} ` : html` ${this.renderFormElements()} ` } `; } renderFormElements() { const i18n = this._i18n; const hasPersonalData = this.formData.studentGivenName && this.formData.studentFamilyName && this.formData.studentEmail; const isExistingSubmission = Boolean(this.data?.identifier); if ( !isExistingSubmission && !hasPersonalData && !this._userDataFetched && !this._fetchingUserData && this.getToken() && this.getUserId() ) { this._fetchingUserData = true; void this.fetchUserData().finally(() => { this._fetchingUserData = false; this._userDataFetched = true; }); } const data = this.formData || {}; const hasMultipleLecturers = this.getLecturerList(data.lecturers).length > 1; return html` <form id="accessible-courses-form" class=${classMap({ hidden: this.hideForm, 'readonly-mode': this.readOnly, 'edit-mode': !this.readOnly, 'formalize-form': true, })}> <div class="form-header">${this.getButtonRowHtml()}</div> <h2 class="form-title"> ${i18n.t('render-form.forms.accessible-courses-form.title')} </h2> <div class="description"> <dbp-translated subscribe="lang"> <div slot="de"> <p class="field-note"> Bitte beachten Sie, dass die Bearbeitung von Anfragen zur barrierefreien Lehrveranstaltungsteilnahme mehrere Werktage in Anspruch nehmen kann. Kurzfristige Anfragen und Anfragen, die sich auf rückwirkende Anpassungen beziehen, können nicht berücksichtigt werden. In diesen Fällen wenden Sie sich bitte direkt an <a href="mailto:barrierefrei-studieren@tugraz.at"> barrierefrei-studieren@tugraz.at </a> . Anpassungen, die ausschließlich Prüfungen betreffen, bitte rechtzeitig über das entsprechende Formular angeben: <a href="https://formulare.tugraz.at/de/render-form/accessible-exams" target="_blank"> Barrierefreie Lehrveranstaltungen </a> . Handelt es sich um eine Lehrveranstaltung, für die Anpassungen über die Prüfung hinaus erforderlich sind, bitte hier im Formular alle notwendigen Anpassungen angeben. </p> </div> <div slot="en"> <p class="field-note"> Please note that processing requests for accessible participation in courses may take several business days. Last-minute requests and requests for retroactive adjustments cannot be considered. In such cases, please contact <a href="mailto:barrierefrei-studieren@tugraz.at"> barrierefrei-studieren@tugraz.at </a> directly. Please submit requests for adjustments that pertain exclusively to exams in a timely manner using the appropriate form: <a href="https://formulare.tugraz.at/de/render-form/accessible-exams" target="_blank"> accessible exams </a> . If the course requires adjustments beyond the exam, please list all necessary adjustments here in the form. </p> </div> </dbp-translated> <p>${i18n.t('render-form.forms.accessible-courses-form.mandatory-fields')}</p> </div> <fieldset> <legend> ${i18n.t('render-form.forms.accessible-courses-form.course-data')} </legend> <dbp-course-select-element subscribe="lang,auth,entry-point-url" name="courseName" label="${i18n.t('render-form.forms.accessible-courses-form.course-name')}" value=${data.courseName || ''} course-identifier=${data.courseIdentifier || ''} required @dbp-course-changed=${(e) => this.handleCourseChange(e)}></dbp-course-select-element> <dbp-form-string-element subscribe="lang" name="lecturers" rows=${ Array.isArray(data.lecturers) && data.lecturers.length > 1 ? String(data.lecturers.length) : '1' } label=${i18n.t('render-form.forms.accessible-courses-form.lecturers')} value=${ Array.isArray(data.lecturers) ? data.lecturers.filter(Boolean).join('\n') : data.lecturers || '' } disabled></dbp-form-string-element> ${ hasMultipleLecturers ? html` <dbp-form-string-element subscribe="lang" name="groupAssignment" label=${i18n.t( 'render-form.forms.accessible-courses-form.group-assignment', )} .value=${data.groupAssignment || ''}></dbp-form-string-element> ` : '' } <dbp-form-string-element subscribe="lang" name="adaptations" aria-describedby="adapt-descr" label=${i18n.t('render-form.forms.accessible-courses-form.adaptations')} .value=${data.adaptations || ''} required rows="5"> <div slot="description"> <dbp-translated subscribe="lang"> <div slot="de"> <p> Gutes Beispiel: Anstelle von Tafelübungen vor den Kommiliton*innen bitte ich um eine Übung im Einzelsetting. <br /> Schlechtes Beispiel 1: Bitte keine Tafelübungen. <br /> Schlechtes Beispiel 2: Bitte alle ausgemachten Adaptierungen für diese LV anfragen. </p> </div> <div slot="en"> <p> Good example: Instead of board exercises in front of my classmates, I’d prefer to do an exercise in a one-on-one setting. <br /> Bad example 1: Please, no board exercises. <br /> Bad example 2: Please ask about all the adjustments for this course. </p> </div> </dbp-translated> </div> </dbp-form-string-element> </fieldset> <fieldset> <legend> ${i18n.t('render-form.forms.accessible-courses-form.personal-data')} </legend> <dbp-form-string-element subscribe="lang" name="matriculationNumber" label=${i18n.t( 'render-form.forms.accessible-courses-form.matriculation-number', )} value=${data.matriculationNumber || ''} disabled></dbp-form-string-element> <dbp-form-string-element subscribe="lang" name="studentGivenName" label=${i18n.t('render-form.forms.accessible-courses-form.given-name')} value=${data.studentGivenName || ''} disabled></dbp-form-string-element> <dbp-form-string-element subscribe="lang" name="studentFamilyName" label=${i18n.t('render-form.forms.accessible-courses-form.family-name')} value=${data.studentFamilyName || ''} disabled></dbp-form-string-element> <dbp-form-string-element subscribe="lang" name="studentEmail" label=${i18n.t('render-form.forms.accessible-courses-form.email')} value=${data.studentEmail || ''} disabled></dbp-form-string-element> ${ this.isAdmin ? html` <dbp-form-string-element subscribe="lang" name="comment" label=${i18n.t( 'render-form.forms.accessible-courses-form.comment', )} .value=${data.comment || ''} description=${i18n.t( 'render-form.forms.accessible-courses-form.comment-placeholder', )} rows="5"></dbp-form-string-element> ` : '' } </fieldset> </form> <dbp-deletion-confirmation-modal id="deletion-modal"></dbp-deletion-confirmation-modal> ${this.renderResult(this.submitted)} `; } renderFormViews() { const i18n = this._i18n; const data = this.formData || {}; const hasMultipleLecturers = this.getLecturerList(data.lecturers).length > 1; return html` <form id="accessible-courses-form" class=${classMap({ hidden: this.hideForm, 'readonly-mode': this.readOnly, 'edit-mode': !this.readOnly, 'formalize-form': true, })}> <div class="form-header">${this.getButtonRowHtml()}</div> <h2 class="form-title"> ${i18n.t('render-form.forms.accessible-courses-form.title')} </h2> <fieldset> <legend> ${i18n.t('render-form.forms.accessible-courses-form.course-data')} </legend> <dbp-form-string-view subscribe="lang,auth,entry-point-url" name="courseName" label="${i18n.t('render-form.forms.accessible-courses-form.course-name')}" value=${data.courseName || ''}></dbp-form-string-view> <dbp-form-string-view subscribe="lang" name="lecturers" label=${i18n.t('render-form.forms.accessible-courses-form.lecturers')} value=${ Array.isArray(data.lecturers) ? data.lecturers.filter(Boolean).join(', ') : data.lecturers || '' }></dbp-form-string-view> ${ hasMultipleLecturers ? html` <dbp-form-string-view subscribe="lang" name="groupAssignment" label=${i18n.t( 'render-form.forms.accessible-courses-form.group-assignment', )} .value=${data.groupAssignment || ''}></dbp-form-string-view> ` : '' } <dbp-form-string-view subscribe="lang" name="adaptations" description=${i18n.t( 'render-form.forms.accessible-courses-form.description', )} aria-describedby="adapt-descr" label=${i18n.t('render-form.forms.accessible-courses-form.adaptations')} .value=${data.adaptations || ''}></dbp-form-string-view> </fieldset> <fieldset> <legend> ${i18n.t('render-form.forms.accessible-courses-form.personal-data')} </legend> <dbp-form-string-view subscribe="lang" name="matriculationNumber" label=${i18n.t( 'render-form.forms.accessible-courses-form.matriculation-number', )} value=${data.matriculationNumber || ''} disabled></dbp-form-string-view> <dbp-form-string-view subscribe="lang" name="studentGivenName" label=${i18n.t('render-form.forms.accessible-courses-form.given-name')} value=${data.studentGivenName || ''} disabled></dbp-form-string-view> <dbp-form-string-view subscribe="lang" name="studentFamilyName" label=${i18n.t('render-form.forms.accessible-courses-form.family-name')} value=${data.studentFamilyName || ''} disabled></dbp-form-string-view> <dbp-form-string-view subscribe="lang" name="studentEmail" label=${i18n.t('render-form.forms.accessible-courses-form.email')} value=${data.studentEmail || ''} disabled></dbp-form-string-view> ${ this.isAdmin ? html` <dbp-form-string-view subscribe="lang" name="comment" label=${i18n.t( 'render-form.forms.accessible-courses-form.comment', )} .value=${data.comment || ''} description=${i18n.t( 'render-form.forms.accessible-courses-form.comment-placeholder', )} rows="5"></dbp-form-string-view> ` : '' } </fieldset> </form> <dbp-deletion-confirmation-modal id="deletion-modal"></dbp-deletion-confirmation-modal> `; } renderResult(submitted) { const i18n = this._i18n; if (submitted) { return html` <div class="container"> <h2> ${i18n.t( 'render-form.forms.accessible-courses-form.submission-result-thanks', )} </h2> <p> ${i18n.t( 'render-form.forms.accessible-courses-form.submission-result-notification', )} </p> <div class="after-submission-button-container"> ${ this.canUserSubmitSubmission() ? html` <a href="${getFormRenderUrl(this.formUrlSlug, this.lang)}" class="button button--new-submission"> <dbp-icon name="plus" aria-hidden="true"></dbp-icon> ${i18n.t('success.create-new-submission-button-label')} </a> ` : '' } ${ this.areSubmissionReadableAfterSubmission() ? html` <a href="${getFormManageFormsUrl( this.formIdentifier, this.lang, )}" class="button button--back-to-submissions-list"> <dbp-icon name="list" aria-hidden="true"></dbp-icon> ${i18n.t('success.back-to-submissions-list-button-label')} </a> ` : '' } </div> </div> `; } return html``; } async updated(changedProperties) { super.updated(changedProperties); const i18n = this._i18n; if (changedProperties.has('data') || changedProperties.has('readOnly')) { // Reset observer so it can re-attach if needed this._formHeaderObserved = false; this.stickyHeaderObserver(); } if (changedProperties.has('data') && Object.keys(this.data).length > 0) { this.formData = JSON.parse(this.data.dataFeedElement); this.submissionId = this.data.identifier; this.currentSubmission = this.data; this.lastModifiedCreatorId = this.data.lastModifiedById; this.submissionBinaryState = this.data.submissionState; this.submissionGrantedActions = this.data.grantedActions; switch (Number(this.submissionBinaryState)) { case 1: this.currentState = SUBMISSION_STATES.DRAFT; break; case 4: this.currentState = SUBMISSION_STATES.SUBMITTED; break; default: this.currentState = null; break; } if (this.formData) { try { const lastModifierDetailsResponse = await this.apiGetUserDetails( this.lastModifiedCreatorId, ); if (!lastModifierDetailsResponse.ok) { sendNotification({ summary: i18n.t('errors.error-title'), body: i18n.t('errors.failed-to-get-last-modifier-details', { status: lastModifierDetailsResponse.status, }), type: 'danger', timeout: 0, }); } else { const lastModifierDetails = await lastModifierDetailsResponse.json(); this.lastModifiedCreatorName = `${lastModifierDetails?.givenName} ${lastModifierDetails?.familyName}`; } } catch (e) { console.log(e); sendNotification({ summary: i18n.t('errors.error-title'), body: i18n.t('errors.failed-to-get-last-modifier-details'), type: 'danger', timeout: 0, }); } } this.setButtonStates(); this.isUserAllowedToDownloadPdf = false; // @ts-ignore void this.updateComplete.then(async () => { await this.processConditionalFields(); // If query parameter 'validate' is set to true, validate required fields const urlParams = new URLSearchParams(window.location.search); if (this.readOnly === false && urlParams.get('validate') === 'true') { const formElement = this.formElement; this.isFormValid = await validateRequiredFields(formElement); if (!this.isFormValid) { this.scrollToFirstInvalidField(formElement, true); // Show notification sendNotification({ summary: i18n.t('errors.warning-title'), body: i18n.t('errors.form-validation-warning-notification-body'), type: 'warning', timeout: 0, }); } } }); } } }