xv-webcomponents 1.24.10 → 1.24.13-qa.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/_vars-Cyrk3TAl.js +3423 -0
- package/dist/cjs/xv-accordion-v2_50.cjs.entry.js +94 -8
- package/dist/cjs/xv-header-next.cjs.entry.js +87 -8
- package/dist/collection/components/xv-header/_vars.js +51 -0
- package/dist/collection/components/xv-header/xv-header.js +88 -7
- package/dist/collection/components/xv-header-next/xv-header-next.js +88 -7
- package/dist/collection/components/xv-overflow-menu/xv-overflow-menu.js +7 -0
- package/dist/esm/_vars-BkYBzv3h.js +3413 -0
- package/dist/esm/xv-accordion-v2_50.entry.js +94 -8
- package/dist/esm/xv-header-next.entry.js +87 -8
- package/dist/types/components/xv-header/_vars.d.ts +47 -0
- package/dist/types/components/xv-header/xv-header.d.ts +29 -13
- package/dist/types/components/xv-header-next/xv-header-next.d.ts +29 -13
- package/dist/types/components/xv-overflow-menu/xv-overflow-menu.d.ts +1 -0
- package/dist/xv-webcomponents/p-7832549c.entry.js +8 -0
- package/dist/xv-webcomponents/p-BkYBzv3h.js +1 -0
- package/dist/xv-webcomponents/p-f46bb687.entry.js +1 -0
- package/dist/xv-webcomponents/xv-webcomponents.esm.js +1 -1
- package/package.json +2 -1
- package/dist/cjs/_vars-DMytunQw.js +0 -26
- package/dist/esm/_vars-CDEU4jkD.js +0 -23
- package/dist/xv-webcomponents/p-51664dbf.entry.js +0 -1
- package/dist/xv-webcomponents/p-CDEU4jkD.js +0 -1
- package/dist/xv-webcomponents/p-b6eb6373.entry.js +0 -8
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var index$1 = require('./index-DpLAFt0R.js');
|
|
4
4
|
var index$2 = require('./index-Cb30DBqk.js');
|
|
5
|
-
var _vars = require('./_vars-
|
|
5
|
+
var _vars = require('./_vars-Cyrk3TAl.js');
|
|
6
6
|
|
|
7
7
|
const xvAccordionCss = () => `:host{display:block}`;
|
|
8
8
|
|
|
@@ -82619,9 +82619,15 @@ const XvHeader = class {
|
|
|
82619
82619
|
this.metaNav = metaNav;
|
|
82620
82620
|
this.orgUnit = ((_b = (_a = this.metaNav) === null || _a === void 0 ? void 0 : _a.User) === null || _b === void 0 ? void 0 : _b.SelectedOrgUnitName) || '';
|
|
82621
82621
|
void this.getNotifications();
|
|
82622
|
+
void this.connectNotificationsHub();
|
|
82622
82623
|
}
|
|
82623
82624
|
console.info('MetaNav was updated', this.metaNav);
|
|
82624
82625
|
}
|
|
82626
|
+
disconnectedCallback() {
|
|
82627
|
+
var _a;
|
|
82628
|
+
void ((_a = this.notificationsHub) === null || _a === void 0 ? void 0 : _a.stop());
|
|
82629
|
+
this.notificationsHub = undefined;
|
|
82630
|
+
}
|
|
82625
82631
|
componentWillLoad() {
|
|
82626
82632
|
this.baseUrl = index$2.getBaseUrl();
|
|
82627
82633
|
void this.initHeader();
|
|
@@ -82666,16 +82672,89 @@ const XvHeader = class {
|
|
|
82666
82672
|
this.notifications = [];
|
|
82667
82673
|
}
|
|
82668
82674
|
}
|
|
82675
|
+
/**
|
|
82676
|
+
* Subscribes to the notifications hub so the bell reflects a status change without a reload.
|
|
82677
|
+
*
|
|
82678
|
+
* The platform calls `NotifyUserAsync` after it completes or fails a notification, which
|
|
82679
|
+
* invokes `NotificationsUpdated` on the person's group — but nothing here was listening, so
|
|
82680
|
+
* the bell only ever caught up on a full page load (MAR-15569). The list is re-fetched on
|
|
82681
|
+
* each push rather than patched from the message, because the hub carries no payload.
|
|
82682
|
+
*
|
|
82683
|
+
* Failure to connect is logged and otherwise ignored: the bell still works, it just needs a
|
|
82684
|
+
* reload to refresh, which is the behaviour this replaces.
|
|
82685
|
+
*/
|
|
82686
|
+
async connectNotificationsHub() {
|
|
82687
|
+
var _a, _b, _c;
|
|
82688
|
+
if (!((_a = this.metaNav) === null || _a === void 0 ? void 0 : _a.IsManager) || this.notificationsHub)
|
|
82689
|
+
return;
|
|
82690
|
+
const personId = (_c = (_b = this.metaNav) === null || _b === void 0 ? void 0 : _b.User) === null || _c === void 0 ? void 0 : _c.Id;
|
|
82691
|
+
if (!personId)
|
|
82692
|
+
return;
|
|
82693
|
+
try {
|
|
82694
|
+
const hubUrl = await this.getNotificationsHubUrl();
|
|
82695
|
+
if (!hubUrl)
|
|
82696
|
+
return;
|
|
82697
|
+
const hub = new _vars.HubConnectionBuilder()
|
|
82698
|
+
.withUrl(hubUrl)
|
|
82699
|
+
.withAutomaticReconnect()
|
|
82700
|
+
.build();
|
|
82701
|
+
hub.on(_vars.SIGNALR_NOTIFICATIONS_UPDATED, () => void this.getNotifications());
|
|
82702
|
+
// Re-join after a reconnect: group membership lives on the connection, so it is lost
|
|
82703
|
+
// when the transport drops and the bell would silently stop updating.
|
|
82704
|
+
hub.onreconnected(() => void hub.invoke(_vars.SIGNALR_JOIN_GROUP, String(personId)));
|
|
82705
|
+
await hub.start();
|
|
82706
|
+
await hub.invoke(_vars.SIGNALR_JOIN_GROUP, String(personId));
|
|
82707
|
+
this.notificationsHub = hub;
|
|
82708
|
+
}
|
|
82709
|
+
catch (error) {
|
|
82710
|
+
console.error('Failed to connect to the notifications hub:', error === null || error === void 0 ? void 0 : error.message, error);
|
|
82711
|
+
}
|
|
82712
|
+
}
|
|
82713
|
+
/**
|
|
82714
|
+
* Reads the hub URL from the platform's client settings. That endpoint serves JavaScript
|
|
82715
|
+
* rather than JSON, and the `xv` global it defines is absent on Angular-rendered pages, so
|
|
82716
|
+
* the value is parsed out of the response text.
|
|
82717
|
+
*/
|
|
82718
|
+
async getNotificationsHubUrl() {
|
|
82719
|
+
var _a, _b;
|
|
82720
|
+
const fromGlobal = (_b = (_a = window.xv) === null || _a === void 0 ? void 0 : _a.clientApplicationSettings) === null || _b === void 0 ? void 0 : _b[_vars.SIGNALR_HUB_URL_SETTING];
|
|
82721
|
+
if (fromGlobal)
|
|
82722
|
+
return fromGlobal;
|
|
82723
|
+
const settings = await fetch(`${this.baseUrl}/de-de/assets/clientapplicationsettings`, {
|
|
82724
|
+
credentials: 'include',
|
|
82725
|
+
}).then(res => res.text());
|
|
82726
|
+
const match = settings.match(new RegExp(`"${_vars.SIGNALR_HUB_URL_SETTING.replace(/\./g, '\\.')}"\\s*:\\s*"([^"]+)"`));
|
|
82727
|
+
return match === null || match === void 0 ? void 0 : match[1];
|
|
82728
|
+
}
|
|
82729
|
+
/**
|
|
82730
|
+
* Dismisses a notification. The platform soft-deletes it (`DateDeletedUtc`), which drops it
|
|
82731
|
+
* from the list endpoint. Without this the bell could not be cleared at all and every entry
|
|
82732
|
+
* sat there until its 24-hour expiry — the old MVC bell's "Geprüft" button did this and was
|
|
82733
|
+
* not carried over when the header moved to this component.
|
|
82734
|
+
*/
|
|
82735
|
+
async dismissNotification(event, orderId) {
|
|
82736
|
+
// The row is inside an overflow-menu item; without this the menu closes on click and the
|
|
82737
|
+
// list is torn down before the request resolves.
|
|
82738
|
+
event.preventDefault();
|
|
82739
|
+
event.stopPropagation();
|
|
82740
|
+
try {
|
|
82741
|
+
await index$2.api.delete(`${this.baseUrl}/de-de/api/notifications/${orderId}`, {
|
|
82742
|
+
credentials: 'include',
|
|
82743
|
+
});
|
|
82744
|
+
}
|
|
82745
|
+
catch (error) {
|
|
82746
|
+
console.error('Failed to dismiss the notification:', error === null || error === void 0 ? void 0 : error.message, error);
|
|
82747
|
+
}
|
|
82748
|
+
await this.getNotifications();
|
|
82749
|
+
}
|
|
82669
82750
|
_renderNotifications() {
|
|
82670
82751
|
var _a;
|
|
82671
82752
|
if (!((_a = this.metaNav) === null || _a === void 0 ? void 0 : _a.IsManager))
|
|
82672
82753
|
return null;
|
|
82673
|
-
return (index$1.h("li", { class: "notifications" }, index$1.h("xv-overflow-menu-v2", { position: "right", size: _vars.SIZE_VAR.MD }, index$1.h("span", { slot: "trigger", class: "fa-stack" }, index$1.h("i", { class: "notifications-icon far fa-bell fa-stack-1x" }), this.notifications.length > 0 && (index$1.h("xv-tag-v2", { class: "counter-badge counter-badge--absolute", bg: "var(--icon-interactive, #97BF0D)", color: "var(--text-inverse, #FFF)" }, this.notifications.length))), this.notifications.map((notification) =>
|
|
82674
|
-
|
|
82675
|
-
|
|
82676
|
-
|
|
82677
|
-
'fa-circle': notification.status && notification.status !== 1,
|
|
82678
|
-
} }), index$1.h("div", { class: "notifications-item-body" }, index$1.h("span", null, "Rechnungsentwurf f\u00FCr Auftrag ", notification.orderId, " ist ausstehend"), index$1.h("xv-link-v2", { variant: notification.isRead ? 'ghost' : 'standalone', href: `/de-de/manager/ordersales/details/${notification.orderId}` }, "Auftrag anschauen")))))))));
|
|
82754
|
+
return (index$1.h("li", { class: "notifications" }, index$1.h("xv-overflow-menu-v2", { position: "right", size: _vars.SIZE_VAR.MD }, index$1.h("span", { slot: "trigger", class: "fa-stack" }, index$1.h("i", { class: "notifications-icon far fa-bell fa-stack-1x" }), this.notifications.length > 0 && (index$1.h("xv-tag-v2", { class: "counter-badge counter-badge--absolute", bg: "var(--icon-interactive, #97BF0D)", color: "var(--text-inverse, #FFF)" }, this.notifications.length))), this.notifications.map((notification) => {
|
|
82755
|
+
const status = _vars.invoiceNotificationStatusOf(notification.status);
|
|
82756
|
+
return (index$1.h("xv-overflow-menu-v2-item", { value: notification.id, variant: _vars.OverflowMenuVariant.GHOST, disabled: notification.isRead, clickable: false }, index$1.h("div", { class: "notifications-item" }, index$1.h("i", { class: { far: true, [_vars.INVOICE_NOTIFICATION_STATUS_ICON[status]]: true } }), index$1.h("div", { class: "notifications-item-body" }, index$1.h("span", null, "Rechnungsentwurf f\u00FCr Auftrag ", notification.orderId, " ist ", _vars.INVOICE_NOTIFICATION_STATUS_TEXT[status]), status === _vars.InvoiceNotificationStatus.COMPLETED && notification.pdfSrc ? (index$1.h("xv-link-v2", { variant: notification.isRead ? 'ghost' : 'standalone', href: notification.pdfSrc, target: "_blank" }, "Rechnung ansehen")) : (index$1.h("xv-link-v2", { variant: notification.isRead ? 'ghost' : 'standalone', href: `/de-de/manager/ordersales/details/${notification.orderId}` }, "Auftrag anschauen"))), index$1.h("xv-button-v2", { variant: "ghost", size: _vars.SIZE_VAR.SM, title: "Gepr\u00FCft", "aria-label": `Benachrichtigung für Auftrag ${notification.orderId} als geprüft markieren`, onClick: (event) => void this.dismissNotification(event, notification.orderId) }, index$1.h("i", { class: "far fa-times" })))));
|
|
82757
|
+
}))));
|
|
82679
82758
|
}
|
|
82680
82759
|
_renderAccount() {
|
|
82681
82760
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
@@ -82700,7 +82779,7 @@ const XvHeader = class {
|
|
|
82700
82779
|
render() {
|
|
82701
82780
|
var _a, _b, _c, _d, _e;
|
|
82702
82781
|
const isXvBrand = (((_a = this.metaNav) === null || _a === void 0 ? void 0 : _a['WhitelabelName']) || 'Xv') === 'Xv';
|
|
82703
|
-
return (index$1.h("header", { key: '
|
|
82782
|
+
return (index$1.h("header", { key: 'e9157c2348f2e286e05e7b694d692ed88c80a543', class: "header" }, index$1.h("div", { key: 'ce7a4aa5e9820598eff8331b8f9ae6f57cc2c034', class: "header-wrapper" }, index$1.h("div", { key: '7bbec18df899b1234e8409b0c3723719180057ba', class: "xv-container" }, index$1.h("div", { key: 'f733864d082f8d23f69cb57961bdffeea60c7657', class: "header-top" }, index$1.h("div", { key: '63df8d29d16e79ef15cf5c5733a2f9b7662a990e', class: "header-top--left" }, index$1.h("xv-button-v2", { key: '5a782cdff61ce2fb4b9a5685d93d5c36a6a0fc9e', class: "menu-btn", variant: "ghost", onClick: this.toggleMobMenu }, index$1.h("i", { key: '2388b08c95773c3b08eeadf5acbe101119cc996d', slot: "icon-left", class: { 'fa': true, 'fa-times': this.mobMenuOpen, 'fa-bars': !this.mobMenuOpen } })), this.metaNav && (index$1.h("a", { key: '277a9e5179a10208e09b0896e234fd6abac4e6d4', href: `${window.location.origin}/` }, index$1.h("picture", { key: 'f07378b064d3af36a6f3059fd1665544eecd17be' }, index$1.h("source", { key: '719e3c4b4147df467f36c45ba91457c3b7724a35', srcSet: ((_b = this.metaNav) === null || _b === void 0 ? void 0 : _b.LogoUrl) || 'https://www.crossvertise.com/ResourcePackages/Bootstrap/assets/dist/images/logo.svg', media: "(min-width: 990px)" }), index$1.h("img", { key: 'cd5a8c6bcd09d0254b3518410efe1b45b9922b97', src: ((_c = this.metaNav) === null || _c === void 0 ? void 0 : _c.LogoSmallUrl) || 'https://www.crossvertise.com/ResourcePackages/Bootstrap/assets/dist/images/logo-small.svg', onError: this.logoFallback, loading: "lazy", alt: "Crossvertise" })))), this.orgUnit && (index$1.h("xv-link-v2", { key: '4775620b83865d75a8fdb1201ceca5bbe543ad67', class: "header-top--orgUnit", variant: "standalone", href: "/de-de/mycrossvertise" }, this.orgUnit))), index$1.h("ul", { key: 'c3b86b2b97c3fd04fe471c5d2ae49d2b7fc03d27', class: "header-top--right" }, this._renderSearch(), this._renderImpersonationInfo(), !((_d = this.metaNav) === null || _d === void 0 ? void 0 : _d.IsManager) && isXvBrand && (index$1.h("li", { key: '9bfbc4f0ba394fc1b36dbb62f86e334cb06257b3' }, index$1.h("xv-link-v2", { key: 'bca968a2fe64bf6872d43d8ac7f10d78b089a23a', variant: "ghost", href: "https://www.crossvertise.com/ueber-uns/kontakt" }, index$1.h("xv-button-v2", { key: '0db4cf67178bb86beefe8dddf7b378171e15198d', variant: "ghost", size: _vars.SIZE_VAR.MD }, index$1.h("i", { key: 'ed1b26d33fc9b843a0c89b05a4bb609273fa8ce8', class: "header-icon far fa-envelope" }), index$1.h("span", { key: '4e8f6fea781c552338e248b111a24ad289526d46', class: "header-label xv-body-02" }, "Kontakt"))))), this._renderNotifications(), this._renderAccount(), !((_e = this.metaNav) === null || _e === void 0 ? void 0 : _e.IsManager) && isXvBrand && (index$1.h("li", { key: '23f641be3c9218dac34b8abe6b2cbb263c856843' }, index$1.h("xv-link-v2", { key: 'b4315fa914b8173f92092aeb3735fabbd5986d25', variant: "ghost", href: "https://help.crossvertise.com" }, index$1.h("xv-button-v2", { key: '0bec228884977d7c88549a24fe4e62f76a11753b', variant: "ghost", size: _vars.SIZE_VAR.MD }, index$1.h("i", { key: 'd23ccaed77af7631742f23c053ff718278012d4e', class: "header-icon far fa-question-circle" }), index$1.h("span", { key: '0771508d8bdffa99d1e4748141e085191c421bf7', class: "header-label xv-body-02" }, "Hilfe"))))), this._renderShoppingCart()))), index$1.h("div", { key: '97bf836216e1ac3f1d8b0b4ed96b7e0875f6cdcc', class: "header-wrapper--bg" }, index$1.h("div", { key: '9d542f3553673d6c5c27a74b81d899b56562e724', class: "xv-container" }, index$1.h("xv-mega-menu", { key: 'b8b0af38f25546dd3d48a76a4fd7e381982e482e', open: this.mobMenuOpen, onOpenChange: this.closeMobMenu })))), index$1.h("xv-login-modal", { key: 'cad3944d560a74e29399f54c5e47b993a7e7dbe4', visible: this.showLoginModal, onClose: () => this.showLoginModal = false })));
|
|
82704
82783
|
}
|
|
82705
82784
|
get el() { return index$1.getElement(this); }
|
|
82706
82785
|
};
|
|
@@ -83420,6 +83499,13 @@ const XvOverflowMenu = class {
|
|
|
83420
83499
|
const button = (index$1.h("button", { class: { btn: true, open: this.open }, onClick: this.onOpenToggle, disabled: this.disabled, "aria-haspopup": "menu", "aria-expanded": this.open ? 'true' : 'false', ref: (el) => (this.triggerButtonEl = el) }, index$1.h("slot", { name: "trigger" }, index$1.h("svg", { xmlns: "http://www.w3.org/2000/svg", width: "1em", height: "1em", viewBox: "0 0 128 512" }, index$1.h("path", { d: "M64 368a48 48 0 1 0 0 96 48 48 0 1 0 0-96zm0-160a48 48 0 1 0 0 96 48 48 0 1 0 0-96zM112 96A48 48 0 1 0 16 96a48 48 0 1 0 96 0z" })))));
|
|
83421
83500
|
return (index$1.h(index$1.Host, { class: "xv-overflow-menu", size: this.size }, this.tooltip ? index$1.h("xv-tooltip-v2", { message: this.tooltip }, button) : button, list));
|
|
83422
83501
|
}
|
|
83502
|
+
// Moving the host in the DOM — a framework reordering a list, say — disconnects and reconnects
|
|
83503
|
+
// it, and the disconnect tears the anchor listener down. componentDidLoad does not run a second
|
|
83504
|
+
// time, so without this the menu stays dead. Safe on the first mount: addEventListener discards
|
|
83505
|
+
// a duplicate of the same handler, and setupAnchor is a no-op until anchor is set.
|
|
83506
|
+
connectedCallback() {
|
|
83507
|
+
this.setupAnchor();
|
|
83508
|
+
}
|
|
83423
83509
|
componentDidLoad() {
|
|
83424
83510
|
this.setupAnchor();
|
|
83425
83511
|
this.syncOpenState();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var index = require('./index-DpLAFt0R.js');
|
|
4
|
-
var _vars = require('./_vars-
|
|
4
|
+
var _vars = require('./_vars-Cyrk3TAl.js');
|
|
5
5
|
var index$1 = require('./index-Cb30DBqk.js');
|
|
6
6
|
|
|
7
7
|
const userMagnifyingGlassRegularFullSvg = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2NDAgNjQwIj48IS0tIUZvbnQgQXdlc29tZSBQcm8gNy4xLjAgYnkgQGZvbnRhd2Vzb21lIC0gaHR0cHM6Ly9mb250YXdlc29tZS5jb20gTGljZW5zZSAtIGh0dHBzOi8vZm9udGF3ZXNvbWUuY29tL2xpY2Vuc2UgKENvbW1lcmNpYWwgTGljZW5zZSkgQ29weXJpZ2h0IDIwMjUgRm9udGljb25zLCBJbmMuLS0+PHBhdGggZD0iTTE3Ni41IDE5MkMxNzYuNSAxNDcuOCAyMTIuMyAxMTIgMjU2LjUgMTEyQzMwMC43IDExMiAzMzYuNSAxNDcuOCAzMzYuNSAxOTJDMzM2LjUgMjM2LjIgMzAwLjcgMjcyIDI1Ni41IDI3MkMyMTIuMyAyNzIgMTc2LjUgMjM2LjIgMTc2LjUgMTkyek0zODQuNSAxOTJDMzg0LjUgMTIxLjMgMzI3LjIgNjQgMjU2LjUgNjRDMTg1LjggNjQgMTI4LjUgMTIxLjMgMTI4LjUgMTkyQzEyOC41IDI2Mi43IDE4NS44IDMyMCAyNTYuNSAzMjBDMzI3LjIgMzIwIDM4NC41IDI2Mi43IDM4NC41IDE5MnpNODAuNSA1NDRDODAuNSA0NzMuMyAxMzcuOCA0MTYgMjA4LjUgNDE2TDI4OC43IDQxNkMyODkuNSAzOTkuMiAyOTIuNyAzODMuMSAyOTguMSAzNjhMMjA4LjUgMzY4QzExMS4zIDM2OCAzMi41IDQ0Ni44IDMyLjUgNTQ0TDMyLjUgNTUyQzMyLjUgNTY1LjMgNDMuMiA1NzYgNTYuNSA1NzZDNjkuOCA1NzYgODAuNSA1NjUuMyA4MC41IDU1Mkw4MC41IDU0NHpNNDU2LjUgMzUyQzQ5Ni4zIDM1MiA1MjguNSAzODQuMiA1MjguNSA0MjRDNTI4LjUgNDYzLjggNDk2LjMgNDk2IDQ1Ni41IDQ5NkM0MTYuNyA0OTYgMzg0LjUgNDYzLjggMzg0LjUgNDI0QzM4NC41IDM4NC4yIDQxNi43IDM1MiA0NTYuNSAzNTJ6TTQ1Ni41IDU0NEM0ODAuOSA1NDQgNTAzLjYgNTM2LjcgNTIyLjYgNTI0LjJMNTgzLjUgNTg1LjFDNTkyLjkgNTk0LjUgNjA4LjEgNTk0LjUgNjE3LjQgNTg1LjFDNjI2LjcgNTc1LjcgNjI2LjggNTYwLjUgNjE3LjQgNTUxLjJMNTU2LjUgNDkwLjNDNTY5LjEgNDcxLjMgNTc2LjQgNDQ4LjUgNTc2LjQgNDI0QzU3Ni40IDM1Ny43IDUyMi43IDMwNCA0NTYuNCAzMDRDMzkwLjEgMzA0IDMzNi40IDM1Ny43IDMzNi40IDQyNEMzMzYuNCA0OTAuMyAzOTAuMSA1NDQgNDU2LjQgNTQ0eiIvPjwvc3ZnPg==';
|
|
@@ -99,9 +99,15 @@ const XvHeaderNext = class {
|
|
|
99
99
|
this.metaNav = metaNav;
|
|
100
100
|
this.orgUnit = ((_b = (_a = this.metaNav) === null || _a === void 0 ? void 0 : _a.User) === null || _b === void 0 ? void 0 : _b.SelectedOrgUnitName) || '';
|
|
101
101
|
void this.getNotifications();
|
|
102
|
+
void this.connectNotificationsHub();
|
|
102
103
|
}
|
|
103
104
|
console.info('MetaNav was updated', this.metaNav);
|
|
104
105
|
}
|
|
106
|
+
disconnectedCallback() {
|
|
107
|
+
var _a;
|
|
108
|
+
void ((_a = this.notificationsHub) === null || _a === void 0 ? void 0 : _a.stop());
|
|
109
|
+
this.notificationsHub = undefined;
|
|
110
|
+
}
|
|
105
111
|
componentWillLoad() {
|
|
106
112
|
this.baseUrl = index$1.getBaseUrl();
|
|
107
113
|
void this.initHeader();
|
|
@@ -171,16 +177,89 @@ const XvHeaderNext = class {
|
|
|
171
177
|
this.notifications = [];
|
|
172
178
|
}
|
|
173
179
|
}
|
|
180
|
+
/**
|
|
181
|
+
* Subscribes to the notifications hub so the bell reflects a status change without a reload.
|
|
182
|
+
*
|
|
183
|
+
* The platform calls `NotifyUserAsync` after it completes or fails a notification, which
|
|
184
|
+
* invokes `NotificationsUpdated` on the person's group — but nothing here was listening, so
|
|
185
|
+
* the bell only ever caught up on a full page load (MAR-15569). The list is re-fetched on
|
|
186
|
+
* each push rather than patched from the message, because the hub carries no payload.
|
|
187
|
+
*
|
|
188
|
+
* Failure to connect is logged and otherwise ignored: the bell still works, it just needs a
|
|
189
|
+
* reload to refresh, which is the behaviour this replaces.
|
|
190
|
+
*/
|
|
191
|
+
async connectNotificationsHub() {
|
|
192
|
+
var _a, _b, _c;
|
|
193
|
+
if (!((_a = this.metaNav) === null || _a === void 0 ? void 0 : _a.IsManager) || this.notificationsHub)
|
|
194
|
+
return;
|
|
195
|
+
const personId = (_c = (_b = this.metaNav) === null || _b === void 0 ? void 0 : _b.User) === null || _c === void 0 ? void 0 : _c.Id;
|
|
196
|
+
if (!personId)
|
|
197
|
+
return;
|
|
198
|
+
try {
|
|
199
|
+
const hubUrl = await this.getNotificationsHubUrl();
|
|
200
|
+
if (!hubUrl)
|
|
201
|
+
return;
|
|
202
|
+
const hub = new _vars.HubConnectionBuilder()
|
|
203
|
+
.withUrl(hubUrl)
|
|
204
|
+
.withAutomaticReconnect()
|
|
205
|
+
.build();
|
|
206
|
+
hub.on(_vars.SIGNALR_NOTIFICATIONS_UPDATED, () => void this.getNotifications());
|
|
207
|
+
// Re-join after a reconnect: group membership lives on the connection, so it is lost
|
|
208
|
+
// when the transport drops and the bell would silently stop updating.
|
|
209
|
+
hub.onreconnected(() => void hub.invoke(_vars.SIGNALR_JOIN_GROUP, String(personId)));
|
|
210
|
+
await hub.start();
|
|
211
|
+
await hub.invoke(_vars.SIGNALR_JOIN_GROUP, String(personId));
|
|
212
|
+
this.notificationsHub = hub;
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
console.error('Failed to connect to the notifications hub:', error === null || error === void 0 ? void 0 : error.message, error);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Reads the hub URL from the platform's client settings. That endpoint serves JavaScript
|
|
220
|
+
* rather than JSON, and the `xv` global it defines is absent on Angular-rendered pages, so
|
|
221
|
+
* the value is parsed out of the response text.
|
|
222
|
+
*/
|
|
223
|
+
async getNotificationsHubUrl() {
|
|
224
|
+
var _a, _b;
|
|
225
|
+
const fromGlobal = (_b = (_a = window.xv) === null || _a === void 0 ? void 0 : _a.clientApplicationSettings) === null || _b === void 0 ? void 0 : _b[_vars.SIGNALR_HUB_URL_SETTING];
|
|
226
|
+
if (fromGlobal)
|
|
227
|
+
return fromGlobal;
|
|
228
|
+
const settings = await fetch(`${this.baseUrl}/de-de/assets/clientapplicationsettings`, {
|
|
229
|
+
credentials: 'include',
|
|
230
|
+
}).then(res => res.text());
|
|
231
|
+
const match = settings.match(new RegExp(`"${_vars.SIGNALR_HUB_URL_SETTING.replace(/\./g, '\\.')}"\\s*:\\s*"([^"]+)"`));
|
|
232
|
+
return match === null || match === void 0 ? void 0 : match[1];
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Dismisses a notification. The platform soft-deletes it (`DateDeletedUtc`), which drops it
|
|
236
|
+
* from the list endpoint. Without this the bell could not be cleared at all and every entry
|
|
237
|
+
* sat there until its 24-hour expiry — the old MVC bell's "Geprüft" button did this and was
|
|
238
|
+
* not carried over when the header moved to this component.
|
|
239
|
+
*/
|
|
240
|
+
async dismissNotification(event, orderId) {
|
|
241
|
+
// The row is inside an overflow-menu item; without this the menu closes on click and the
|
|
242
|
+
// list is torn down before the request resolves.
|
|
243
|
+
event.preventDefault();
|
|
244
|
+
event.stopPropagation();
|
|
245
|
+
try {
|
|
246
|
+
await index$1.api.delete(`${this.baseUrl}/de-de/api/notifications/${orderId}`, {
|
|
247
|
+
credentials: 'include',
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
251
|
+
console.error('Failed to dismiss the notification:', error === null || error === void 0 ? void 0 : error.message, error);
|
|
252
|
+
}
|
|
253
|
+
await this.getNotifications();
|
|
254
|
+
}
|
|
174
255
|
_renderNotifications() {
|
|
175
256
|
var _a;
|
|
176
257
|
if (!((_a = this.metaNav) === null || _a === void 0 ? void 0 : _a.IsManager))
|
|
177
258
|
return null;
|
|
178
|
-
return (index.h("li", { class: "notifications" }, index.h("xv-overflow-menu-v2", { position: "right", size: _vars.SIZE_VAR.MD }, index.h("span", { slot: "trigger", class: "fa-stack" }, index.h("i", { class: "notifications-icon far fa-bell fa-stack-1x" }), this.notifications.length > 0 && (index.h("xv-tag-v2", { class: "counter-badge counter-badge--absolute", bg: "var(--icon-interactive, #97BF0D)", color: "var(--text-inverse, #FFF)" }, this.notifications.length))), this.notifications.map((notification) =>
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
'fa-circle': notification.status && notification.status !== 1,
|
|
183
|
-
} }), index.h("div", { class: "notifications-item-body" }, index.h("span", null, "Rechnungsentwurf f\u00FCr Auftrag ", notification.orderId, " ist ausstehend"), index.h("xv-link-v2", { variant: notification.isRead ? 'ghost' : 'standalone', href: `/de-de/manager/ordersales/details/${notification.orderId}` }, "Auftrag anschauen")))))))));
|
|
259
|
+
return (index.h("li", { class: "notifications" }, index.h("xv-overflow-menu-v2", { position: "right", size: _vars.SIZE_VAR.MD }, index.h("span", { slot: "trigger", class: "fa-stack" }, index.h("i", { class: "notifications-icon far fa-bell fa-stack-1x" }), this.notifications.length > 0 && (index.h("xv-tag-v2", { class: "counter-badge counter-badge--absolute", bg: "var(--icon-interactive, #97BF0D)", color: "var(--text-inverse, #FFF)" }, this.notifications.length))), this.notifications.map((notification) => {
|
|
260
|
+
const status = _vars.invoiceNotificationStatusOf(notification.status);
|
|
261
|
+
return (index.h("xv-overflow-menu-v2-item", { value: notification.id, variant: _vars.OverflowMenuVariant.GHOST, disabled: notification.isRead, clickable: false }, index.h("div", { class: "notifications-item" }, index.h("i", { class: { far: true, [_vars.INVOICE_NOTIFICATION_STATUS_ICON[status]]: true } }), index.h("div", { class: "notifications-item-body" }, index.h("span", null, "Rechnungsentwurf f\u00FCr Auftrag ", notification.orderId, " ist ", _vars.INVOICE_NOTIFICATION_STATUS_TEXT[status]), status === _vars.InvoiceNotificationStatus.COMPLETED && notification.pdfSrc ? (index.h("xv-link-v2", { variant: notification.isRead ? 'ghost' : 'standalone', href: notification.pdfSrc, target: "_blank" }, "Rechnung ansehen")) : (index.h("xv-link-v2", { variant: notification.isRead ? 'ghost' : 'standalone', href: `/de-de/manager/ordersales/details/${notification.orderId}` }, "Auftrag anschauen"))), index.h("xv-button-v2", { variant: "ghost", size: _vars.SIZE_VAR.SM, title: "Gepr\u00FCft", "aria-label": `Benachrichtigung für Auftrag ${notification.orderId} als geprüft markieren`, onClick: (event) => void this.dismissNotification(event, notification.orderId) }, index.h("i", { class: "far fa-times" })))));
|
|
262
|
+
}))));
|
|
184
263
|
}
|
|
185
264
|
_renderAccount() {
|
|
186
265
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
@@ -199,7 +278,7 @@ const XvHeaderNext = class {
|
|
|
199
278
|
render() {
|
|
200
279
|
var _a, _b, _c, _d, _e;
|
|
201
280
|
const isXvBrand = (((_a = this.metaNav) === null || _a === void 0 ? void 0 : _a['WhitelabelName']) || 'Xv') === 'Xv';
|
|
202
|
-
return (index.h("header", { key: '
|
|
281
|
+
return (index.h("header", { key: '9c04fce6bf5c86c2f7ce9eec4f2c0ebbb5941e1a', class: "header" }, index.h("div", { key: 'fee93197d318b26dbca661595916d9e8cbe94375', class: "header-wrapper" }, index.h("div", { key: 'e5ba7c77f93cfd10ac648125e3785572b1b2b352', class: "xv-container" }, index.h("div", { key: '784da35e8aa09bab4268377d22d7ae40aa7fcc5a', class: "header-top" }, index.h("div", { key: '93bffa009121bd0ef93d1c690bed6b90dbb9de4b', class: "header-top--left" }, index.h("xv-button-v2", { key: 'f60f995957e9b929516d30e8c79e6e69354fa4a3', class: "menu-btn", variant: "ghost", onClick: this.toggleMobMenu }, index.h("i", { key: 'd0f2b955f98752b4825b921f57858bba1bdac2cd', slot: "icon-left", class: { 'fa': true, 'fa-times': this.mobMenuOpen, 'fa-bars': !this.mobMenuOpen } })), this.metaNav && (index.h("a", { key: 'd393b761eb12268735da317e85cbb7845c9ee15f', href: `${window.location.origin}/` }, index.h("picture", { key: 'ebc31771f501886f73c033cd8df3ed3f6097dbea' }, index.h("source", { key: '1852235f967ab2fa08d14837d8e2f19607b2da05', srcSet: ((_b = this.metaNav) === null || _b === void 0 ? void 0 : _b.LogoUrl) || 'https://www.crossvertise.com/ResourcePackages/Bootstrap/assets/dist/images/logo.svg', media: "(min-width: 990px)" }), index.h("img", { key: '5d36ae93c924554a4af9e266e090d9ab5cace2d6', src: ((_c = this.metaNav) === null || _c === void 0 ? void 0 : _c.LogoSmallUrl) || 'https://www.crossvertise.com/ResourcePackages/Bootstrap/assets/dist/images/logo-small.svg', onError: this.logoFallback, loading: "lazy", alt: "Crossvertise" })))), this.orgUnit && (index.h("xv-link-v2", { key: '2a674365dbb3d87541fa8ee21e681d30803845f5', class: "header-top--orgUnit", variant: "standalone", href: "/de-de/mycrossvertise" }, this.orgUnit))), index.h("ul", { key: 'c04cc5a6124c47f63aa4a31c6105707fde987f80', class: "header-top--right" }, this._renderLocaleSwitcher(), this._renderSearch(), this._renderImpersonationInfo(), !((_d = this.metaNav) === null || _d === void 0 ? void 0 : _d.IsManager) && isXvBrand && (index.h("li", { key: 'f98924908679cb70e040342e3d2037ca0c328cfb' }, index.h("xv-link-v2", { key: 'df6c95995411827fb9e7d2d772672d71ca94e8b4', variant: "ghost", href: "https://www.crossvertise.com/ueber-uns/kontakt" }, index.h("xv-button-v2", { key: '26fb5b25c5c9d8763ae8162bd027814a511aaeea', variant: "ghost", size: _vars.SIZE_VAR.MD }, index.h("i", { key: '125dcdb6c7732ef43b32cd5600e26b046aa14c62', class: "header-icon far fa-envelope" }), index.h("span", { key: '2a0b974fb77e7aa9eeafec92789bb73f2201c865', class: "header-label xv-body-02" }, "Kontakt"))))), this._renderNotifications(), this._renderAccount(), !((_e = this.metaNav) === null || _e === void 0 ? void 0 : _e.IsManager) && isXvBrand && (index.h("li", { key: 'f0ed40566ca8c76960940a602d8829adc0ede357' }, index.h("xv-link-v2", { key: '5ee23ea00cfba00c759bde207af7385d84e9db6a', variant: "ghost", href: "https://help.crossvertise.com" }, index.h("xv-button-v2", { key: '97129651b7d2726eaf76db5ed4cbc838eaa7e047', variant: "ghost", size: _vars.SIZE_VAR.MD }, index.h("i", { key: 'be2de402a7e605cf600aec63051291d62e497865', class: "header-icon far fa-question-circle" }), index.h("span", { key: '5fe9768447d0d8a8a57fa5a95b98326121eca94b', class: "header-label xv-body-02" }, "Hilfe"))))), this._renderShoppingCart()))), index.h("div", { key: '1e57385c58e31de469d67829e829781065799ca2', class: "header-wrapper--bg" }, index.h("div", { key: '40eaa28197cf1b27b7bd7a6b559440b805764fc6', class: "xv-container" }, index.h("xv-mega-menu-next", { key: '387772fe79f32eef0286fab9f8dd38a2fbb9d6ee', open: this.mobMenuOpen, onOpenChange: this.closeMobMenu, menuData: this.menuData })))), index.h("xv-login-modal", { key: '182eab0fb5f02c082be39f681fc2632881da9e39', visible: this.showLoginModal, onClose: () => this.showLoginModal = false })));
|
|
203
282
|
}
|
|
204
283
|
get el() { return index.getElement(this); }
|
|
205
284
|
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Status of a draft-invoice notification, mirroring the platform's
|
|
3
|
+
* `InvoiceNotificationPayloadStatus` (Xv.Domain/Notifications/Payloads).
|
|
4
|
+
*
|
|
5
|
+
* The numeric values are the wire format: `/de-de/api/notifications/list` serializes the
|
|
6
|
+
* enum by ordinal, so these MUST stay in sync with the backend. The header used to compare
|
|
7
|
+
* `status === 1` while treating it as a failure, so a draft invoice that had been generated
|
|
8
|
+
* was shown with the error icon and the text "ist ausstehend" (MAR-15569).
|
|
9
|
+
*/
|
|
10
|
+
export var InvoiceNotificationStatus;
|
|
11
|
+
(function (InvoiceNotificationStatus) {
|
|
12
|
+
InvoiceNotificationStatus[InvoiceNotificationStatus["PENDING"] = 0] = "PENDING";
|
|
13
|
+
InvoiceNotificationStatus[InvoiceNotificationStatus["COMPLETED"] = 1] = "COMPLETED";
|
|
14
|
+
InvoiceNotificationStatus[InvoiceNotificationStatus["FAILED"] = 2] = "FAILED";
|
|
15
|
+
})(InvoiceNotificationStatus || (InvoiceNotificationStatus = {}));
|
|
16
|
+
/** Bell label per status. German only — this component carries no i18n layer. */
|
|
17
|
+
export const INVOICE_NOTIFICATION_STATUS_TEXT = {
|
|
18
|
+
[InvoiceNotificationStatus.PENDING]: 'ausstehend',
|
|
19
|
+
[InvoiceNotificationStatus.COMPLETED]: 'generiert',
|
|
20
|
+
[InvoiceNotificationStatus.FAILED]: 'fehlgeschlagen',
|
|
21
|
+
};
|
|
22
|
+
/** Font Awesome icon per status. */
|
|
23
|
+
export const INVOICE_NOTIFICATION_STATUS_ICON = {
|
|
24
|
+
[InvoiceNotificationStatus.PENDING]: 'fa-clock',
|
|
25
|
+
[InvoiceNotificationStatus.COMPLETED]: 'fa-check-circle',
|
|
26
|
+
[InvoiceNotificationStatus.FAILED]: 'fa-times-circle',
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Falls back to PENDING for an unknown value so a new backend status renders as
|
|
30
|
+
* "waiting" rather than silently claiming success or failure.
|
|
31
|
+
*/
|
|
32
|
+
export function invoiceNotificationStatusOf(status) {
|
|
33
|
+
switch (status) {
|
|
34
|
+
case InvoiceNotificationStatus.COMPLETED:
|
|
35
|
+
return InvoiceNotificationStatus.COMPLETED;
|
|
36
|
+
case InvoiceNotificationStatus.FAILED:
|
|
37
|
+
return InvoiceNotificationStatus.FAILED;
|
|
38
|
+
default:
|
|
39
|
+
return InvoiceNotificationStatus.PENDING;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Key of the platform setting holding the notifications hub URL. Served as JavaScript (not
|
|
44
|
+
* JSON) by `/de-de/assets/clientapplicationsettings`, and the `xv` global it defines is not
|
|
45
|
+
* present on Angular-rendered pages, so the value is parsed out of the response text.
|
|
46
|
+
*/
|
|
47
|
+
export const SIGNALR_HUB_URL_SETTING = 'SignalR.Hub.Notifications.Url';
|
|
48
|
+
/** Hub method the platform invokes after it changes a notification (see NotificationService). */
|
|
49
|
+
export const SIGNALR_NOTIFICATIONS_UPDATED = 'NotificationsUpdated';
|
|
50
|
+
/** Hub method that subscribes this connection to one person's notifications. */
|
|
51
|
+
export const SIGNALR_JOIN_GROUP = 'joinGroup';
|
|
@@ -2,6 +2,8 @@ import { h } from "@stencil/core";
|
|
|
2
2
|
import { SIZE_VAR } from "../../types/enum";
|
|
3
3
|
import { api, debounce, getBaseUrl, getMetaNav } from "../../utils/utils";
|
|
4
4
|
import { OverflowMenuVariant } from "../xv-overflow-menu/_vars";
|
|
5
|
+
import { HubConnectionBuilder } from "@microsoft/signalr";
|
|
6
|
+
import { INVOICE_NOTIFICATION_STATUS_ICON, INVOICE_NOTIFICATION_STATUS_TEXT, InvoiceNotificationStatus, invoiceNotificationStatusOf, SIGNALR_HUB_URL_SETTING, SIGNALR_JOIN_GROUP, SIGNALR_NOTIFICATIONS_UPDATED, } from "./_vars";
|
|
5
7
|
import UserSearchIcon from "./user-magnifying-glass-regular-full.svg";
|
|
6
8
|
export class XvHeader {
|
|
7
9
|
constructor() {
|
|
@@ -92,9 +94,15 @@ export class XvHeader {
|
|
|
92
94
|
this.metaNav = metaNav;
|
|
93
95
|
this.orgUnit = ((_b = (_a = this.metaNav) === null || _a === void 0 ? void 0 : _a.User) === null || _b === void 0 ? void 0 : _b.SelectedOrgUnitName) || '';
|
|
94
96
|
void this.getNotifications();
|
|
97
|
+
void this.connectNotificationsHub();
|
|
95
98
|
}
|
|
96
99
|
console.info('MetaNav was updated', this.metaNav);
|
|
97
100
|
}
|
|
101
|
+
disconnectedCallback() {
|
|
102
|
+
var _a;
|
|
103
|
+
void ((_a = this.notificationsHub) === null || _a === void 0 ? void 0 : _a.stop());
|
|
104
|
+
this.notificationsHub = undefined;
|
|
105
|
+
}
|
|
98
106
|
componentWillLoad() {
|
|
99
107
|
this.baseUrl = getBaseUrl();
|
|
100
108
|
void this.initHeader();
|
|
@@ -139,16 +147,89 @@ export class XvHeader {
|
|
|
139
147
|
this.notifications = [];
|
|
140
148
|
}
|
|
141
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Subscribes to the notifications hub so the bell reflects a status change without a reload.
|
|
152
|
+
*
|
|
153
|
+
* The platform calls `NotifyUserAsync` after it completes or fails a notification, which
|
|
154
|
+
* invokes `NotificationsUpdated` on the person's group — but nothing here was listening, so
|
|
155
|
+
* the bell only ever caught up on a full page load (MAR-15569). The list is re-fetched on
|
|
156
|
+
* each push rather than patched from the message, because the hub carries no payload.
|
|
157
|
+
*
|
|
158
|
+
* Failure to connect is logged and otherwise ignored: the bell still works, it just needs a
|
|
159
|
+
* reload to refresh, which is the behaviour this replaces.
|
|
160
|
+
*/
|
|
161
|
+
async connectNotificationsHub() {
|
|
162
|
+
var _a, _b, _c;
|
|
163
|
+
if (!((_a = this.metaNav) === null || _a === void 0 ? void 0 : _a.IsManager) || this.notificationsHub)
|
|
164
|
+
return;
|
|
165
|
+
const personId = (_c = (_b = this.metaNav) === null || _b === void 0 ? void 0 : _b.User) === null || _c === void 0 ? void 0 : _c.Id;
|
|
166
|
+
if (!personId)
|
|
167
|
+
return;
|
|
168
|
+
try {
|
|
169
|
+
const hubUrl = await this.getNotificationsHubUrl();
|
|
170
|
+
if (!hubUrl)
|
|
171
|
+
return;
|
|
172
|
+
const hub = new HubConnectionBuilder()
|
|
173
|
+
.withUrl(hubUrl)
|
|
174
|
+
.withAutomaticReconnect()
|
|
175
|
+
.build();
|
|
176
|
+
hub.on(SIGNALR_NOTIFICATIONS_UPDATED, () => void this.getNotifications());
|
|
177
|
+
// Re-join after a reconnect: group membership lives on the connection, so it is lost
|
|
178
|
+
// when the transport drops and the bell would silently stop updating.
|
|
179
|
+
hub.onreconnected(() => void hub.invoke(SIGNALR_JOIN_GROUP, String(personId)));
|
|
180
|
+
await hub.start();
|
|
181
|
+
await hub.invoke(SIGNALR_JOIN_GROUP, String(personId));
|
|
182
|
+
this.notificationsHub = hub;
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
console.error('Failed to connect to the notifications hub:', error === null || error === void 0 ? void 0 : error.message, error);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Reads the hub URL from the platform's client settings. That endpoint serves JavaScript
|
|
190
|
+
* rather than JSON, and the `xv` global it defines is absent on Angular-rendered pages, so
|
|
191
|
+
* the value is parsed out of the response text.
|
|
192
|
+
*/
|
|
193
|
+
async getNotificationsHubUrl() {
|
|
194
|
+
var _a, _b;
|
|
195
|
+
const fromGlobal = (_b = (_a = window.xv) === null || _a === void 0 ? void 0 : _a.clientApplicationSettings) === null || _b === void 0 ? void 0 : _b[SIGNALR_HUB_URL_SETTING];
|
|
196
|
+
if (fromGlobal)
|
|
197
|
+
return fromGlobal;
|
|
198
|
+
const settings = await fetch(`${this.baseUrl}/de-de/assets/clientapplicationsettings`, {
|
|
199
|
+
credentials: 'include',
|
|
200
|
+
}).then(res => res.text());
|
|
201
|
+
const match = settings.match(new RegExp(`"${SIGNALR_HUB_URL_SETTING.replace(/\./g, '\\.')}"\\s*:\\s*"([^"]+)"`));
|
|
202
|
+
return match === null || match === void 0 ? void 0 : match[1];
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Dismisses a notification. The platform soft-deletes it (`DateDeletedUtc`), which drops it
|
|
206
|
+
* from the list endpoint. Without this the bell could not be cleared at all and every entry
|
|
207
|
+
* sat there until its 24-hour expiry — the old MVC bell's "Geprüft" button did this and was
|
|
208
|
+
* not carried over when the header moved to this component.
|
|
209
|
+
*/
|
|
210
|
+
async dismissNotification(event, orderId) {
|
|
211
|
+
// The row is inside an overflow-menu item; without this the menu closes on click and the
|
|
212
|
+
// list is torn down before the request resolves.
|
|
213
|
+
event.preventDefault();
|
|
214
|
+
event.stopPropagation();
|
|
215
|
+
try {
|
|
216
|
+
await api.delete(`${this.baseUrl}/de-de/api/notifications/${orderId}`, {
|
|
217
|
+
credentials: 'include',
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
console.error('Failed to dismiss the notification:', error === null || error === void 0 ? void 0 : error.message, error);
|
|
222
|
+
}
|
|
223
|
+
await this.getNotifications();
|
|
224
|
+
}
|
|
142
225
|
_renderNotifications() {
|
|
143
226
|
var _a;
|
|
144
227
|
if (!((_a = this.metaNav) === null || _a === void 0 ? void 0 : _a.IsManager))
|
|
145
228
|
return null;
|
|
146
|
-
return (h("li", { class: "notifications" }, h("xv-overflow-menu-v2", { position: "right", size: SIZE_VAR.MD }, h("span", { slot: "trigger", class: "fa-stack" }, h("i", { class: "notifications-icon far fa-bell fa-stack-1x" }), this.notifications.length > 0 && (h("xv-tag-v2", { class: "counter-badge counter-badge--absolute", bg: "var(--icon-interactive, #97BF0D)", color: "var(--text-inverse, #FFF)" }, this.notifications.length))), this.notifications.map((notification) =>
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
'fa-circle': notification.status && notification.status !== 1,
|
|
151
|
-
} }), h("div", { class: "notifications-item-body" }, h("span", null, "Rechnungsentwurf f\u00FCr Auftrag ", notification.orderId, " ist ausstehend"), h("xv-link-v2", { variant: notification.isRead ? 'ghost' : 'standalone', href: `/de-de/manager/ordersales/details/${notification.orderId}` }, "Auftrag anschauen")))))))));
|
|
229
|
+
return (h("li", { class: "notifications" }, h("xv-overflow-menu-v2", { position: "right", size: SIZE_VAR.MD }, h("span", { slot: "trigger", class: "fa-stack" }, h("i", { class: "notifications-icon far fa-bell fa-stack-1x" }), this.notifications.length > 0 && (h("xv-tag-v2", { class: "counter-badge counter-badge--absolute", bg: "var(--icon-interactive, #97BF0D)", color: "var(--text-inverse, #FFF)" }, this.notifications.length))), this.notifications.map((notification) => {
|
|
230
|
+
const status = invoiceNotificationStatusOf(notification.status);
|
|
231
|
+
return (h("xv-overflow-menu-v2-item", { value: notification.id, variant: OverflowMenuVariant.GHOST, disabled: notification.isRead, clickable: false }, h("div", { class: "notifications-item" }, h("i", { class: { far: true, [INVOICE_NOTIFICATION_STATUS_ICON[status]]: true } }), h("div", { class: "notifications-item-body" }, h("span", null, "Rechnungsentwurf f\u00FCr Auftrag ", notification.orderId, " ist ", INVOICE_NOTIFICATION_STATUS_TEXT[status]), status === InvoiceNotificationStatus.COMPLETED && notification.pdfSrc ? (h("xv-link-v2", { variant: notification.isRead ? 'ghost' : 'standalone', href: notification.pdfSrc, target: "_blank" }, "Rechnung ansehen")) : (h("xv-link-v2", { variant: notification.isRead ? 'ghost' : 'standalone', href: `/de-de/manager/ordersales/details/${notification.orderId}` }, "Auftrag anschauen"))), h("xv-button-v2", { variant: "ghost", size: SIZE_VAR.SM, title: "Gepr\u00FCft", "aria-label": `Benachrichtigung für Auftrag ${notification.orderId} als geprüft markieren`, onClick: (event) => void this.dismissNotification(event, notification.orderId) }, h("i", { class: "far fa-times" })))));
|
|
232
|
+
}))));
|
|
152
233
|
}
|
|
153
234
|
_renderAccount() {
|
|
154
235
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
@@ -173,7 +254,7 @@ export class XvHeader {
|
|
|
173
254
|
render() {
|
|
174
255
|
var _a, _b, _c, _d, _e;
|
|
175
256
|
const isXvBrand = (((_a = this.metaNav) === null || _a === void 0 ? void 0 : _a['WhitelabelName']) || 'Xv') === 'Xv';
|
|
176
|
-
return (h("header", { key: '
|
|
257
|
+
return (h("header", { key: 'e9157c2348f2e286e05e7b694d692ed88c80a543', class: "header" }, h("div", { key: 'ce7a4aa5e9820598eff8331b8f9ae6f57cc2c034', class: "header-wrapper" }, h("div", { key: '7bbec18df899b1234e8409b0c3723719180057ba', class: "xv-container" }, h("div", { key: 'f733864d082f8d23f69cb57961bdffeea60c7657', class: "header-top" }, h("div", { key: '63df8d29d16e79ef15cf5c5733a2f9b7662a990e', class: "header-top--left" }, h("xv-button-v2", { key: '5a782cdff61ce2fb4b9a5685d93d5c36a6a0fc9e', class: "menu-btn", variant: "ghost", onClick: this.toggleMobMenu }, h("i", { key: '2388b08c95773c3b08eeadf5acbe101119cc996d', slot: "icon-left", class: { 'fa': true, 'fa-times': this.mobMenuOpen, 'fa-bars': !this.mobMenuOpen } })), this.metaNav && (h("a", { key: '277a9e5179a10208e09b0896e234fd6abac4e6d4', href: `${window.location.origin}/` }, h("picture", { key: 'f07378b064d3af36a6f3059fd1665544eecd17be' }, h("source", { key: '719e3c4b4147df467f36c45ba91457c3b7724a35', srcSet: ((_b = this.metaNav) === null || _b === void 0 ? void 0 : _b.LogoUrl) || 'https://www.crossvertise.com/ResourcePackages/Bootstrap/assets/dist/images/logo.svg', media: "(min-width: 990px)" }), h("img", { key: 'cd5a8c6bcd09d0254b3518410efe1b45b9922b97', src: ((_c = this.metaNav) === null || _c === void 0 ? void 0 : _c.LogoSmallUrl) || 'https://www.crossvertise.com/ResourcePackages/Bootstrap/assets/dist/images/logo-small.svg', onError: this.logoFallback, loading: "lazy", alt: "Crossvertise" })))), this.orgUnit && (h("xv-link-v2", { key: '4775620b83865d75a8fdb1201ceca5bbe543ad67', class: "header-top--orgUnit", variant: "standalone", href: "/de-de/mycrossvertise" }, this.orgUnit))), h("ul", { key: 'c3b86b2b97c3fd04fe471c5d2ae49d2b7fc03d27', class: "header-top--right" }, this._renderSearch(), this._renderImpersonationInfo(), !((_d = this.metaNav) === null || _d === void 0 ? void 0 : _d.IsManager) && isXvBrand && (h("li", { key: '9bfbc4f0ba394fc1b36dbb62f86e334cb06257b3' }, h("xv-link-v2", { key: 'bca968a2fe64bf6872d43d8ac7f10d78b089a23a', variant: "ghost", href: "https://www.crossvertise.com/ueber-uns/kontakt" }, h("xv-button-v2", { key: '0db4cf67178bb86beefe8dddf7b378171e15198d', variant: "ghost", size: SIZE_VAR.MD }, h("i", { key: 'ed1b26d33fc9b843a0c89b05a4bb609273fa8ce8', class: "header-icon far fa-envelope" }), h("span", { key: '4e8f6fea781c552338e248b111a24ad289526d46', class: "header-label xv-body-02" }, "Kontakt"))))), this._renderNotifications(), this._renderAccount(), !((_e = this.metaNav) === null || _e === void 0 ? void 0 : _e.IsManager) && isXvBrand && (h("li", { key: '23f641be3c9218dac34b8abe6b2cbb263c856843' }, h("xv-link-v2", { key: 'b4315fa914b8173f92092aeb3735fabbd5986d25', variant: "ghost", href: "https://help.crossvertise.com" }, h("xv-button-v2", { key: '0bec228884977d7c88549a24fe4e62f76a11753b', variant: "ghost", size: SIZE_VAR.MD }, h("i", { key: 'd23ccaed77af7631742f23c053ff718278012d4e', class: "header-icon far fa-question-circle" }), h("span", { key: '0771508d8bdffa99d1e4748141e085191c421bf7', class: "header-label xv-body-02" }, "Hilfe"))))), this._renderShoppingCart()))), h("div", { key: '97bf836216e1ac3f1d8b0b4ed96b7e0875f6cdcc', class: "header-wrapper--bg" }, h("div", { key: '9d542f3553673d6c5c27a74b81d899b56562e724', class: "xv-container" }, h("xv-mega-menu", { key: 'b8b0af38f25546dd3d48a76a4fd7e381982e482e', open: this.mobMenuOpen, onOpenChange: this.closeMobMenu })))), h("xv-login-modal", { key: 'cad3944d560a74e29399f54c5e47b993a7e7dbe4', visible: this.showLoginModal, onClose: () => this.showLoginModal = false })));
|
|
177
258
|
}
|
|
178
259
|
static get is() { return "xv-header"; }
|
|
179
260
|
static get originalStyleUrls() {
|