diff --git a/assets/components/misSession.js b/assets/components/misSession.js new file mode 100644 index 0000000..45088ef --- /dev/null +++ b/assets/components/misSession.js @@ -0,0 +1,118 @@ +/** + * MIS (webSDK / widget.sovamed.ru) session helpers. + * Symfony login (ROLE_USER) and MIS session are independent. + */ + +function MisSessionError() { + this.name = 'MisSessionError'; + this.message = 'MIS session is not authenticated'; +} + +function isAuthenticated(webSDK) { + return Boolean(webSDK?.data?.user?.authenticated); +} + +function ensureAuthenticated(webSDK) { + return new Promise(function(resolve, reject) { + if (isAuthenticated(webSDK)) { + resolve(webSDK); + return; + } + + if (typeof webSDK?.isLoggedIn === 'function') { + webSDK.isLoggedIn(webSDK.sdkOrigin).then(function(result) { + if (result?.authenticated) { + resolve(webSDK); + return; + } + reject(new MisSessionError()); + }).catch(function() { + reject(new MisSessionError()); + }); + return; + } + + reject(new MisSessionError()); + }); +} + +function removeSdkOverlayModals() { + document.querySelectorAll('.wr-sdk-widget-modal').forEach(function(modal) { + modal.remove(); + }); +} + +/** + * Move #iframeProtocol from SDK overlay into cabinet bootstrap popup. + * openConference() must be called without container (SDK applies Guest URL fix). + */ +function mountConferenceInPopup(popup) { + var iframe = document.getElementById('iframeProtocol'); + var popupBody = popup?.querySelector('#popup-body'); + + if (!iframe || !popupBody) { + return false; + } + + removeSdkOverlayModals(); + popupBody.innerHTML = ''; + popupBody.appendChild(iframe); + iframe.style.width = '100%'; + iframe.style.border = 'none'; + iframe.style.height = (window.innerHeight - 100) + 'px'; + + var fullScreenBtn = popup.querySelector('.full-scren-modal'); + if (fullScreenBtn) { + fullScreenBtn.classList.remove('d-none'); + } + + popup.querySelector('.modal-dialog').classList = 'modal-dialog'; + popup.querySelector('.modal-content').classList = 'modal-content'; + popup.querySelector('.modal-title').innerHTML = 'Онлайн консультация'; + + if (typeof $ !== 'undefined' && typeof $(popup).modal === 'function') { + $(popup).modal('show'); + } + + return true; +} + +function showMisSessionExpired(popup) { + if (!popup) { + window.location.pathname = '/logout'; + return; + } + + popup.querySelector('.modal-dialog').classList = 'modal-dialog'; + popup.querySelector('.modal-title').innerHTML = 'Сессия виджета истекла'; + popup.querySelector('#popup-body').innerHTML = + '

Личный кабинет открыт, но сессия виджета записи (MIS) истекла. ' + + 'Для оплаты и онлайн-приёма нужно войти снова — повторная авторизация в iframe не требуется.

' + + ''; + + popup.querySelector('#mis-session-relogin').addEventListener('click', function() { + window.location.pathname = '/logout'; + }); + + if (typeof $ !== 'undefined' && typeof $(popup).modal === 'function') { + $(popup).modal('show'); + } +} + +function handleMisSessionFailure(popup, error, logContext) { + if (error instanceof MisSessionError || error?.name === 'MisSessionError') { + showMisSessionExpired(popup); + return true; + } + + return false; +} + +module.exports = { + MisSessionError: MisSessionError, + isAuthenticated: isAuthenticated, + ensureAuthenticated: ensureAuthenticated, + mountConferenceInPopup: mountConferenceInPopup, + showMisSessionExpired: showMisSessionExpired, + handleMisSessionFailure: handleMisSessionFailure, +}; diff --git a/assets/controllers/caseHistory_controller.js b/assets/controllers/caseHistory_controller.js index 735c13c..aabafb1 100644 --- a/assets/controllers/caseHistory_controller.js +++ b/assets/controllers/caseHistory_controller.js @@ -2,6 +2,7 @@ import { Controller } from 'stimulus'; import Cookies from 'js-cookie'; const loader = require("./../components/loader.js"); const helper = require("./../components/helper.js"); +const misSession = require("./../components/misSession.js"); /* * This is an example Stimulus controller! @@ -248,20 +249,23 @@ export default class extends Controller { btnConfirence.setAttribute('data-filial' , data.filial) btnConfirence.addEventListener('click', function () { popup.querySelector('#popup-body').innerHTML = ''; - - webSDK.openConference({ - schedid: btnConfirence.dataset.id, - container: popup.querySelector('#popup-body') - }).then(function () { - popup.querySelector('.full-scren-modal').classList.remove('d-none'); - document.getElementById('iframeProtocol').style.height = (window.innerHeight - 100) + 'px'; - popup.querySelector('.modal-dialog').classList = 'modal-dialog'; - popup.querySelector('.modal-content').classList = 'modal-content'; - popup.querySelector('.modal-content').classList = 'modal-content'; - popup.querySelector('.modal-title').innerHTML = 'Онлайн консультация'; - $(popup).modal('show'); + misSession.ensureAuthenticated(webSDK).then(function() { + return webSDK.openConference({ + schedid: btnConfirence.dataset.id + }); + }).then(function () { + if (!misSession.mountConferenceInPopup(popup)) { + throw { data: { message: 'Не удалось открыть окно онлайн-консультации.' } }; + } }).catch(function (e) { + if (misSession.handleMisSessionFailure(popup, e)) { + helper.sendRequest({ + data: {'error': e, method: 'openConference', reason: 'mis_session_expired'} + }, helper.getHostname() + '/api/log', "POST", "json", true, "application/json"); + return; + } + if (typeof e.data?.message !== 'undefined') { var msg = e.data.message.replace('UTC+3', 'UTC+3 (московское время)'); popup.querySelector('#popup-body').innerHTML = msg; @@ -272,9 +276,9 @@ export default class extends Controller { } helper.sendRequest({ - data: {'error': e, method: 'openConference'} - }, helper.getHostname() + '/api/log', "POST", "json", true, "application/json"); - }); + data: {'error': e, method: 'openConference'} + }, helper.getHostname() + '/api/log', "POST", "json", true, "application/json"); + }); }); } else { @@ -376,7 +380,6 @@ export default class extends Controller { btnPayment.setAttribute('data-amt' , data.payment.amt); btnPayment.setAttribute('data-payprofileid' , data.payment.magazineId); btnPayment.addEventListener('click', function () { - var params = { 'orderid': Number(btnPayment.dataset.id) , 'payprofileid': btnPayment.dataset.payprofileid, @@ -386,14 +389,26 @@ export default class extends Controller { 'pcode': webSDK.data.user.id, 'successurl': document.location.origin + '/case-history#pay-success', 'errorurl': document.location.origin + '/case-history#error', - 'containerId': 'popup-body', + 'containerId': 'popup-body', }; - webSDK.loadPaymentView(params); + misSession.ensureAuthenticated(webSDK).then(function() { + webSDK.loadPaymentView(params); + popup.querySelector('#popup-body').innerHTML = ''; + popup.querySelector('.modal-title').innerHTML = 'Оплата'; + $(popup).modal('show'); + }).catch(function(e) { + if (misSession.handleMisSessionFailure(popup, e)) { + helper.sendRequest({ + data: {'error': e, method: 'loadPaymentView', reason: 'mis_session_expired'} + }, helper.getHostname() + '/api/log', "POST", "json", true, "application/json"); + return; + } - popup.querySelector('#popup-body').innerHTML = ''; - popup.querySelector('.modal-title').innerHTML = 'Оплата'; - $(popup).modal('show'); + helper.sendRequest({ + data: {'error': e, method: 'loadPaymentView'} + }, helper.getHostname() + '/api/log', "POST", "json", true, "application/json"); + }); }); } else { btnPayment.classList.add('d-none');