diff --git a/packages/check-in-place-select/src/check-in-place-select.js b/packages/check-in-place-select/src/check-in-place-select.js index 24a8d285b31414bc0dc8cdea1624358e06f3c597..e5416afc0bf27c8072bbc1f276a74e24763766de 100644 --- a/packages/check-in-place-select/src/check-in-place-select.js +++ b/packages/check-in-place-select/src/check-in-place-select.js @@ -24,6 +24,7 @@ export class CheckInPlaceSelect extends ScopedElementsMixin(AdapterLitElement) { constructor() { super(); + Object.assign(CheckInPlaceSelect.prototype, errorUtils.backupMixin); this.lang = 'de'; this.entryPointUrl = ''; this.jsonld = null; @@ -187,7 +188,7 @@ export class CheckInPlaceSelect extends ScopedElementsMixin(AdapterLitElement) { results: results }; }, - error: errorUtils.handleXhrError, + error: (jqXHR, textStatus, errorThrown) => { this.handleXhrError(jqXHR, textStatus, errorThrown); }, complete: (jqXHR, textStatus) => { that.isSearching = false; } diff --git a/packages/common/error.js b/packages/common/error.js index 868fde60c16863417fa1379e1977f837cd16ad95..9ed2522f786c7b3e2cd73fd043f7ea358ed39de5 100644 --- a/packages/common/error.js +++ b/packages/common/error.js @@ -39,10 +39,6 @@ export const handleXhrError = (jqXHR, textStatus, errorThrown, icon = "sad") => "icon": icon, "type": "danger", }); - - if (window._paq !== undefined) { - window._paq.push(['trackEvent', 'XhrError', body]); - } }; /** @@ -88,10 +84,6 @@ export const handleFetchError = async (error, summary = "", icon = "sad") => { "icon": icon, "type": "danger", }); - - if (window._paq !== undefined) { - window._paq.push(['trackEvent', 'FetchError', summary === "" ? body : summary + ": " + body]); - } }; /** @@ -120,3 +112,108 @@ export const stripHTML = (string) => { return div.textContent || div.innerText || ""; }; + +/** + * We need this mixin so we can use this.sendSetPropertyEvent to post analytics events + */ +export const backupMixin = { + /** + * Error handling for XHR errors + * + * @param jqXHR + * @param textStatus + * @param errorThrown + * @param icon + */ + handleXhrError(jqXHR, textStatus, errorThrown, icon = "sad") { + // return if user aborted the request + if (textStatus === "abort") { + return; + } + + let body; + + if (jqXHR.responseJSON !== undefined && jqXHR.responseJSON["hydra:description"] !== undefined) { + // response is a JSON-LD + body = jqXHR.responseJSON["hydra:description"]; + } else if (jqXHR.responseJSON !== undefined && jqXHR.responseJSON['detail'] !== undefined) { + // response is a plain JSON + body = jqXHR.responseJSON['detail']; + } else { + // no description available + body = textStatus; + + if (errorThrown) { + body += ' - ' + errorThrown; + } + } + + // if the server is not reachable at all + if (jqXHR.status === 0) { + body = i18n.t('error.connection-to-server-refused'); + } + + notify({ + "summary": i18n.t('error.summary'), + "body": escapeHTML(stripHTML(body)), + "icon": icon, + "type": "danger", + }); + + if (this.sendSetPropertyEvent !== undefined) { + this.sendSetPropertyEvent('analytics-event', {'category': 'XhrError', 'action': body}); + } + }, + + /** + * Error handling for fetch errors + * + * @param error + * @param summary + * @param icon + */ + handleFetchError: async function (error, summary = "", icon = "sad") { + // return if user aborted the request + if (error.name === "AbortError") { + return; + } + + let body; + + try { + await error.json().then((json) => { + if (json["hydra:description"] !== undefined) { + // response is a JSON-LD and possibly also contains HTML! + body = json["hydra:description"]; + } else if (json['detail'] !== undefined) { + // response is a plain JSON + body = json['detail']; + } else { + // no description available + body = error.statusText; + } + }).catch(() => { + body = error.statusText !== undefined ? error.statusText : error; + }); + } catch (e) { + // a TypeError means the connection to the server was refused most of the times + if (error.name === "TypeError") { + body = error.message !== "" ? error.message : i18n.t('error.connection-to-server-refused'); + } + } + + notify({ + "summary": summary === "" ? i18n.t('error.summary') : summary, + "body": escapeHTML(stripHTML(body)), + "icon": icon, + "type": "danger", + }); + + if (this.sendSetPropertyEvent !== undefined) { + this.sendSetPropertyEvent('send-analytics-event', { + 'category': 'FetchError', + 'action': summary === "" ? body : summary + ": " + body + }); + } + } +}; diff --git a/packages/person-select/src/person-select.js b/packages/person-select/src/person-select.js index d425691637f3974cb32400b4c82e2a84c43b72d8..641942c54550c553d9f38a1ac73b59c383cea5ad 100644 --- a/packages/person-select/src/person-select.js +++ b/packages/person-select/src/person-select.js @@ -27,6 +27,7 @@ export class PersonSelect extends ScopedElementsMixin(AdapterLitElement) { constructor() { super(); + Object.assign(PersonSelect.prototype, errorUtils.backupMixin); this.auth = {}; this.lang = 'de'; this.entryPointUrl = ''; @@ -178,7 +179,7 @@ export class PersonSelect extends ScopedElementsMixin(AdapterLitElement) { results: results }; }, - error: errorUtils.handleXhrError, + error: (jqXHR, textStatus, errorThrown) => { this.handleXhrError(jqXHR, textStatus, errorThrown); }, complete: (jqXHR, textStatus) => { that.isSearching = false; }