{"version":3,"file":"chunk-m8iog6ye.js","sources":["packages/vanilla/lib/features/message-panel/src/message-panel-registry.service.ts","packages/vanilla/lib/features/message-panel/src/message-panel.html","packages/vanilla/lib/features/message-panel/src/message-panel.component.ts","packages/vanilla/lib/shared/offers/src/offers-resource.service.ts","packages/vanilla/lib/shared/offers/src/offers.service.ts","packages/vanilla/lib/shared/offers/src/offers.models.ts","packages/vanilla/lib/shared/kyc/src/kyc-status.service.ts","packages/design-system/ui/checkbox/src/checkbox.component.html","packages/design-system/ui/checkbox/src/checkbox.component.ts","packages/vanilla/lib/features/inbox/src/inbox.models.ts","packages/vanilla/lib/features/inbox/src/services/inbox-resource.service.ts","packages/vanilla/lib/features/inbox/src/services/inbox-tracking.service.ts","packages/vanilla/lib/features/inbox/src/services/crappy-inbox.service.ts","packages/vanilla/lib/features/inbox/src/services/inbox.client-config.ts","packages/vanilla/lib/features/inbox/src/services/inbox-count.service.ts","packages/vanilla/lib/features/inbox/src/services/inbox-data.service.ts","packages/vanilla/lib/features/inbox/src/services/inbox.models.ts","packages/vanilla/lib/features/inbox/src/component-helpers/inbox-content.component.ts","packages/vanilla/lib/features/inbox/src/component-helpers/inbox-cta-action.component.ts","packages/vanilla/lib/features/inbox/src/components/inbox-message-channels.component.html","packages/vanilla/lib/features/inbox/src/components/inbox-message-channels.component.ts","packages/vanilla/lib/features/inbox/src/components/inbox-desktop-game-list.component.html","packages/vanilla/lib/features/inbox/src/components/inbox-desktop-game-list.component.ts","packages/vanilla/lib/features/inbox/src/components/inbox-mobile-game-list.component.html","packages/vanilla/lib/features/inbox/src/components/inbox-mobile-game-list.component.ts","packages/vanilla/lib/features/inbox/src/components/inbox-details.component.html","packages/vanilla/lib/features/inbox/src/components/inbox-details.component.ts","packages/vanilla/lib/features/inbox/src/components/inbox-list.component.html","packages/vanilla/lib/features/inbox/src/components/inbox-list.component.ts","packages/vanilla/lib/features/inbox/src/components/inbox-notification-banner.component.ts","packages/vanilla/lib/features/inbox/src/components/inbox-notification-banner.html","packages/vanilla/lib/features/inbox/src/components/on-bottom-scroll.directive.ts","packages/vanilla/lib/features/inbox/src/components/inbox.component.html","packages/vanilla/lib/features/inbox/src/components/inbox.component.ts","packages/vanilla/lib/features/inbox/src/components/inbox-overlay.component.ts","packages/vanilla/lib/features/inbox/src/components/inbox-overlay.html","packages/vanilla/lib/features/inbox/src/services/inbox.service.ts","packages/vanilla/lib/features/inbox/src/inbox-bootstrap.service.ts","packages/vanilla/lib/features/inbox/src/inbox-menu-counters-provider.ts","packages/vanilla/lib/features/inbox/src/inbox.feature.ts","packages/vanilla/lib/features/inbox/src/components/inbox-view.component.ts","packages/vanilla/lib/features/inbox/src/components/inbox-view.html","packages/vanilla/lib/features/inbox/src/inbox.routes.ts","packages/vanilla/lib/shared/dark-mode/src/dark-mode.service.ts","packages/vanilla/lib/shared/copy-right/src/copyright.component.ts","packages/vanilla/lib/features/content-messages/src/content-messages-tracking.service.ts","packages/vanilla/lib/features/content-messages/src/content-message.html","packages/vanilla/lib/features/content-messages/src/content-message.component.ts","packages/vanilla/lib/features/content-messages/src/close-message.component.ts","packages/vanilla/lib/features/content-messages/src/content-messages-bootstrap.service.ts","packages/vanilla/lib/features/content-messages/src/content-messages.feature.ts","packages/vanilla/lib/features/content-messages/src/content-messages.service.ts","packages/vanilla/lib/features/content-messages/src/content-messages.html","packages/vanilla/lib/features/content-messages/src/content-messages.component.ts","packages/vanilla/lib/features/label-switcher/src/label-switcher.client-config.ts","packages/vanilla/lib/features/label-switcher/src/label-switcher-tracking.service.ts","packages/vanilla/lib/features/label-switcher/src/label-switcher.service.ts","packages/vanilla/lib/features/label-switcher/src/label-switcher-bootstrap.service.ts","packages/vanilla/lib/features/label-switcher/src/label-switcher.feature.ts","packages/vanilla/lib/features/label-switcher/src/label-switcher.html","packages/vanilla/lib/features/label-switcher/src/label-switcher.component.ts","packages/design-system/ui/radio-button/src/radio-button.component.ts","packages/design-system/ui/radio-button/src/index.ts","packages/vanilla/lib/features/language-switcher/src/language-switcher.client-config.ts","packages/vanilla/lib/features/language-switcher/src/language-item.html","packages/vanilla/lib/features/language-switcher/src/language-item.component.ts","packages/vanilla/lib/features/language-switcher/src/language-switcher-tracking.service.ts","packages/vanilla/lib/features/flags/src/flags.service.ts","packages/vanilla/lib/features/language-switcher/src/default-language-switcher-urls-provider.ts","packages/vanilla/lib/features/language-switcher/src/language-switcher-urls-provider.ts","packages/vanilla/lib/features/language-switcher/src/language-switcher.service.ts","packages/vanilla/lib/features/language-switcher/src/language-switcher.tokens.ts","packages/vanilla/lib/features/language-switcher/src/language-switcher-menu.html","packages/vanilla/lib/features/language-switcher/src/language-switcher-menu.component.ts","packages/vanilla/lib/features/language-switcher/src/language-switcher-overlay.service.ts","packages/vanilla/lib/features/language-switcher/src/language-switcher-bootstrap.service.ts","packages/vanilla/lib/features/language-switcher/src/language-switcher.feature.ts","packages/vanilla/lib/features/language-switcher/src/language-switcher-radio-menu.html","packages/vanilla/lib/features/language-switcher/src/language-switcher-radio-menu.component.ts","packages/vanilla/lib/features/language-switcher/src/seo-language-links.html","packages/vanilla/lib/features/language-switcher/src/seo-language-links.component.ts","packages/vanilla/lib/features/language-switcher/src/responsive-language-switcher.html","packages/vanilla/lib/features/language-switcher/src/responsive-language-switcher.component.ts","packages/vanilla/lib/features/footer/src/footer.client-config.ts","packages/vanilla/lib/features/footer/src/footer-menu-item.component.ts","packages/vanilla/lib/features/footer/src/footer-menu-item.html","packages/vanilla/lib/features/footer/src/footer-menu-section.html","packages/vanilla/lib/features/footer/src/footer-menu-section.component.ts","packages/vanilla/lib/features/footer/src/sub-components/help-button.html","packages/vanilla/lib/features/footer/src/sub-components/help-button.component.ts","packages/vanilla/lib/features/footer/src/footer.html","packages/vanilla/lib/features/footer/src/footer.component.ts","packages/vanilla/lib/features/footer/src/footer-bootstrap.service.ts","packages/vanilla/lib/features/footer/src/footer.feature.ts","packages/vanilla/lib/features/navigation-layout/src/navigation-layout-scroll.service.ts","packages/vanilla/lib/features/navigation-layout/src/navigation-layout.client-config.ts","packages/vanilla/lib/features/navigation-layout/src/navigation-layout.service.ts","packages/vanilla/lib/features/navigation-layout/src/navigation-layout-left-menu.component.html","packages/vanilla/lib/features/navigation-layout/src/navigation-layout-left-menu.component.ts","packages/vanilla/lib/features/navigation-layout/src/navigation-layout-top-menu-base.component.ts","packages/vanilla/lib/features/navigation-layout/src/navigation-layout-top-menu-v2.html","packages/vanilla/lib/features/navigation-layout/src/navigation-layout-top-menu-v2.component.ts","packages/vanilla/lib/features/navigation-layout/src/navigation-layout.component.html","packages/vanilla/lib/features/navigation-layout/src/navigation-layout.component.ts","packages/vanilla/lib/features/navigation-layout/src/navigation-layout-page.component.html","packages/vanilla/lib/features/navigation-layout/src/navigation-layout-page.component.ts","packages/vanilla/lib/features/navigation-layout/src/navigation-layout-top-menu.component.html","packages/vanilla/lib/features/navigation-layout/src/navigation-layout-top-menu.component.ts","packages/vanilla/lib/features/navigation-layout/src/dark-mode/dark-mode.guard.ts","packages/vanilla/lib/features/navigation-layout/src/dark-mode/dark-mode.component.ts","packages/vanilla/lib/features/navigation-layout/src/dark-mode/dark-mode.html","packages/vanilla/lib/features/navigation-layout/src/dark-mode/navigation-layout-dark-mode.component.ts","packages/vanilla/lib/features/navigation-layout/src/dark-mode/navigation-layout-dark-mode.component.html","packages/vanilla/lib/features/navigation-layout/src/dark-mode/dark-mode-routes.ts","packages/vanilla/lib/features/navigation-layout/src/navigation-layout-cashier.component.ts","packages/vanilla/lib/features/navigation-layout/src/navigation-layout-cashier.html","packages/vanilla/lib/features/navigation-layout/src/navigation-layout-menu-page.component.html","packages/vanilla/lib/features/navigation-layout/src/navigation-layout-menu-page.component.ts","packages/vanilla/lib/features/navigation-layout/src/navigation-layout-routes.ts","packages/vanilla/lib/features/navigation-layout/src/navigation-layout-bootstrap.service.ts","packages/vanilla/lib/features/navigation-layout/src/navigation-layout.feature.ts","packages/vanilla/lib/features/navigation-layout/src/profile-page/common-actions-card.html","packages/vanilla/lib/features/navigation-layout/src/profile-page/common-actions-card.compontent.ts","packages/vanilla/lib/features/navigation-layout/src/profile-page/help-card.html","packages/vanilla/lib/features/navigation-layout/src/profile-page/help-card.component.ts","packages/vanilla/lib/features/navigation-layout/src/profile-page/inbox-card.html","packages/vanilla/lib/features/navigation-layout/src/profile-page/inbox-card.component.ts","packages/vanilla/lib/features/navigation-layout/src/profile-page/profile-page-nudges.service.ts","packages/vanilla/lib/features/navigation-layout/src/profile-page/profile-page-nudges.html","packages/vanilla/lib/features/navigation-layout/src/profile-page/profile-page-nudges.component.ts","packages/vanilla/lib/features/navigation-layout/src/profile-page/profile-page.html","packages/vanilla/lib/features/navigation-layout/src/profile-page/profile-page.component.ts","packages/vanilla/lib/features/navigation-layout/src/profile-page/profile-page.guard.ts","packages/vanilla/lib/features/navigation-layout/src/profile-page/profile-page-routes.ts","packages/poker/core-lib/hand-history/hand-history.models.ts","packages/poker/core-lib/hand-history/hand-history.service.ts","packages/poker/core-lib/hand-history/hands-mainbody/hand-filters/hand-filters.component.html","packages/poker/core-lib/hand-history/hands-mainbody/hand-filters/hand-filters.component.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/point.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/utils/properties.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/chip.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/player.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/pot.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/seat.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/table-events.enum.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/game-table.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/card.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/dealer.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/player-status.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/table-event-info.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/all-in-other-blind.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/Rit-Win-High.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/all-in-ante.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/all-in-big-blind.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/all-in-bring-in.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/all-in-button-ante.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/all-in-call.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/all-in-complete-bring-in.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/all-in-double-bet.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/all-in-double-raise.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/all-in-raise.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/all-in-small-blind.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/bet.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/call.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/card-hidden.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/card-shown.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/cashout.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/check.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/community-card.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/community-card-task.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/complete-bring-in.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/deal-hole-cards.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/dealing-fifth-street.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/dealing-flop.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/dealing-fourth-street.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/dealing-river.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/dealing-seventh-street.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/dealing-sixth-street.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/dealing-third-street.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/dealing-turn.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/deselected-advanced.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/double-bet.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/double-raise.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/fold.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/missed-small-blind.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/option-set.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/player-cash-reduce-action.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/player-chat.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/player-holecards-events.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/player-hurry-up.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/player-muck-cards.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/player-show-cards.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/player-timed-out.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/players-ante-event.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/post-ante.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/post-big-blind.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/post-bring-in.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/post-button-ante.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/post-dummy-ante.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/post-new-player-blind.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/post-other-blind.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/post-small-blind.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/posting-antes.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/posting-blind.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/pot-created.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/raise.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/rit-community-card-task.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/selected-advanced.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/sevencard-player-holecards-events.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/sevencard-playerfifthStreet-holecards-events.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/sevencard-playerfourthStreet-holecards-events.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/sevencard-playerseventhStreet-holecards-events.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/sevencard-playersixthStreet-holecards-events.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/show-down.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/unknowncards.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/win-high.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/win-low.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/events/event-factory.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/utils/hhparser.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/services/game.service.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/game/game-table/game-table.service.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/MobileTab.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/models/Tab.ts","packages/poker/core-lib/hand-history/hands-mainbody/text-view/text-view.component.html","packages/poker/core-lib/hand-history/hands-mainbody/text-view/text-view.component.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/game/card/card.component.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/game/card/card.component.html","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/game/player/player.component.html","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/game/player/player.component.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/game/dealer/dealer.component.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/game/dealer/dealer.component.html","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/game/pot/pot.component.html","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/game/pot/pot.component.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/game/community-cards/community-cards.component.html","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/game/community-cards/community-cards.component.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/game/player-pot/player-pot.component.html","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/game/player-pot/player-pot.component.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/game/player-pots/player-pots.component.html","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/game/player-pots/player-pots.component.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/game/table-text-view/table-text-view.component.html","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/game/table-text-view/table-text-view.component.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/game/game-table/game-table.component.html","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/game/game-table/game-table.component.ts","packages/poker/core-lib/hand-history/hands-mainbody/hands-mainbody.component.html","packages/poker/core-lib/hand-history/hands-mainbody/hands-mainbody.component.ts","packages/poker/core-lib/hand-history/scroll-bar-width.service.ts","packages/poker/core-lib/hand-history/hand-history.component.html","packages/poker/core-lib/hand-history/hand-history.component.ts","packages/poker/core-lib/hand-history/hand-history.resolver.ts","packages/poker/core-lib/hand-history/hands-mainbody/hh-replayer/replayer/game/game.module.ts","packages/poker/core-lib/hand-history/hand-history.module.ts","packages/poker/core-lib/hand-history/hand-history-routing.module.ts","node_modules/@swimlane/ngx-datatable/fesm2020/swimlane-ngx-datatable.mjs","node_modules/@angular/material/fesm2022/button.mjs","node_modules/@angular/material/fesm2022/paginator.mjs","node_modules/@angular/cdk/fesm2022/table.mjs","node_modules/@angular/material/fesm2022/table.mjs","packages/poker/core-lib/leaderboard/leaderboard.service.ts","packages/poker/core-lib/leaderboard/leaderboard.resolvers.ts","packages/poker/core-lib/leaderboard/leaderboard.component.html","packages/poker/core-lib/leaderboard/leaderboard.component.ts","packages/poker/core-lib/leaderboard/leaderboard-routing.module.ts","node_modules/detect-it/dist/detect-it.esm.js","node_modules/ngx-slider-v2/fesm2022/ngx-slider-v2.mjs","packages/poker/core-lib/tournament-calendar/LimitName.pipe.ts","packages/poker/core-lib/tournament-calendar/RemoveColorCodes.pipe.ts","packages/poker/core-lib/tournament-calendar/currency-map.ts","packages/poker/core-lib/tournament-calendar/formatCurrency.pipe.ts","packages/poker/core-lib/tournament-calendar/tournamentcalendar.service.ts","packages/poker/core-lib/tournament-calendar/gameName.pipe.ts","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/util/isFunction.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/config.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/util/hostReportError.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/Observer.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/util/isArray.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/util/isObject.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/util/UnsubscriptionError.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/Subscription.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/symbol/rxSubscriber.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/Subscriber.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/util/canReportError.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/util/toSubscriber.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/symbol/observable.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/util/identity.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/util/pipe.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/Observable.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/util/ObjectUnsubscribedError.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/SubjectSubscription.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/Subject.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/scheduler/Action.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/scheduler/AsyncAction.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/src/internal/Scheduler.ts","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/scheduler/AsyncScheduler.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/scheduler/async.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/util/noop.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/operators/filter.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/operators/distinctUntilChanged.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/operators/tap.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/operators/throttle.js","node_modules/@angular-slider/ngx-slider/node_modules/rxjs/_esm2015/internal/operators/throttleTime.js","node_modules/@angular-slider/ngx-slider/fesm2015/angular-slider-ngx-slider.js","packages/poker/core-lib/tournament-calendar/tournament-calendar-timer/tournament-calendar-timer.component.ts","packages/poker/core-lib/tournament-calendar/tournament-calendar-timer/tournament-calendar-timer.component.html","packages/poker/core-lib/tournament-calendar/tournamentcalendar.resolver.ts","packages/poker/core-lib/tournament-calendar/window-scrolling.service.ts","packages/poker/core-lib/tournament-calendar/tournament-details.component.html","packages/poker/core-lib/tournament-calendar/tournament-details.component.ts","packages/poker/core-lib/tournament-calendar/tournament-calendar-filters.component.html","packages/poker/core-lib/tournament-calendar/tournament-calendar-filters.component.ts","packages/poker/core-lib/tournament-calendar/tournamentcalendar.component.html","packages/poker/core-lib/tournament-calendar/tournamentcalendar.component.ts","packages/poker/core-lib/tournament-calendar/Tournament-calendar-pager.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\n\nimport { Observable, Subject } from 'rxjs';\n\nimport { IMessagePanelComponent, MessagePanelRegistryEvent } from './message-panel.models';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class MessagePanelRegistry {\n get onChange(): Observable {\n return this.onChangeSubject.asObservable();\n }\n\n private onChangeSubject = new Subject();\n private components = [] as IMessagePanelComponent[];\n\n add(component: IMessagePanelComponent) {\n this.components.push(component);\n this.onChangeSubject.next({ component });\n }\n\n remove(component: IMessagePanelComponent) {\n const index = this.components.indexOf(component);\n this.components.splice(index, 1);\n\n const componentsInScope = this.components.filter((c: IMessagePanelComponent) => c.currentScope === component.currentScope);\n const lastMessagePanelComponent = componentsInScope[componentsInScope.length - 1] || null;\n\n this.onChangeSubject.next({\n component: lastMessagePanelComponent,\n });\n }\n}\n","@if (messages.length && isLatest) {\n
\n @for (message of messages; track trackByHtml($index, message)) {\n \n
\n
\n }\n \n}\n","import { CommonModule } from '@angular/common';\nimport { Component, EffectRef, ElementRef, Input, OnDestroy, OnInit, ViewEncapsulation, effect } from '@angular/core';\n\nimport {\n DynamicHtmlDirective,\n Message,\n MessageQueueService,\n WebWorkerService,\n WindowOffsetModifierService,\n WorkerType,\n trackByProp,\n} from '@frontend/vanilla/core';\nimport { Subject } from 'rxjs';\nimport { filter, takeUntil } from 'rxjs/operators';\n\nimport { MessagePanelRegistry } from './message-panel-registry.service';\nimport { IMessagePanelComponent, MessagePanelRegistryEvent } from './message-panel.models';\n\n/**\n * @whatItDoes Displays messages that have been added by {@link MessageQueueService}.\n *\n * @howToUse\n *\n * Place this component on a page where you want to display messages.\n *\n * ```\n * \n * ```\n *\n * @stable\n */\n@Component({\n standalone: true,\n imports: [CommonModule, DynamicHtmlDirective],\n selector: 'vn-message-panel',\n templateUrl: 'message-panel.html',\n styleUrls: ['../../../../../themepark/themes/whitelabel/components/message-panel/styles.scss'],\n encapsulation: ViewEncapsulation.None,\n})\nexport class MessagePanelComponent implements IMessagePanelComponent, OnInit, OnDestroy {\n @Input() scope: string;\n\n messages: Message[] = [];\n isLatest: boolean;\n readonly trackByHtml = trackByProp('html');\n\n private unsubscribe = new Subject();\n private messagesEffectRef: EffectRef;\n\n constructor(\n private service: MessageQueueService,\n private elementRef: ElementRef,\n private windowOffsetModifierService: WindowOffsetModifierService,\n private registry: MessagePanelRegistry,\n private webWorkerService: WebWorkerService,\n ) {\n this.messagesEffectRef = effect(() => {\n this.messages = this.service.messages().filter((message: Message) => (message.scope || '') === this.currentScope);\n\n if (this.messages.length) {\n const offset = this.elementRef.nativeElement.getBoundingClientRect().top;\n this.windowOffsetModifierService.scrollBy(offset);\n }\n });\n }\n\n get currentScope(): string {\n return this.scope || '';\n }\n\n ngOnInit() {\n this.registry.onChange\n .pipe(\n takeUntil(this.unsubscribe),\n filter((c: MessagePanelRegistryEvent) => c.component?.currentScope === this.currentScope),\n )\n .subscribe((c: MessagePanelRegistryEvent) => {\n const workerType = WorkerType.MessagePanelTimeout + this.currentScope;\n\n this.webWorkerService.createWorker(workerType, { timeout: 0 }, () => {\n this.isLatest = c.component === this;\n this.webWorkerService.removeWorker(workerType);\n });\n });\n\n this.registry.add(this);\n }\n\n ngOnDestroy() {\n this.unsubscribe.next();\n this.unsubscribe.complete();\n this.messagesEffectRef.destroy();\n this.registry.remove(this);\n this.webWorkerService.removeWorker(WorkerType.MessagePanelTimeout + this.currentScope);\n }\n}\n","import { Injectable } from '@angular/core';\n\nimport { SharedFeaturesApiService } from '@frontend/vanilla/core';\nimport { Observable } from 'rxjs';\n\nimport { KeyValue, OfferResponse } from './offers.models';\n\n/**\n * @stable\n */\n@Injectable({\n providedIn: 'root',\n})\nexport class OffersResourceService {\n constructor(private api: SharedFeaturesApiService) {}\n\n getCount(): Observable {\n return this.api.get('offers/count');\n }\n\n getStatus(offerType: string, offerId: string): Observable {\n return this.api.get(`offers/${offerType}/${offerId}`);\n }\n\n updateStatus(offerType: string, offerId: string, optIn = true): Observable {\n return this.api.post(`offers/${offerType}/${offerId}/${optIn}`);\n }\n}\n","import { Injectable } from '@angular/core';\n\nimport {\n MenuCountersService,\n UserEvent,\n UserLogoutEvent,\n UserService,\n UserSessionExpiredEvent,\n WebWorkerService,\n WorkerType,\n} from '@frontend/vanilla/core';\nimport { BehaviorSubject, Observable } from 'rxjs';\nimport { filter } from 'rxjs/operators';\n\nimport { OffersResourceService } from './offers-resource.service';\nimport { KeyValue } from './offers.models';\n\n/**\n * @whatItDoes Provides info about user's offers.\n *\n * @howToUse\n *\n * ```this.offersService.offersCount.subscribe(...);```\n *\n * @description\n *\n * Provides info about user's offers.\n *\n * @stable\n */\n@Injectable({\n providedIn: 'root',\n})\nexport class OffersService {\n private countEvents = new BehaviorSubject([]);\n\n constructor(\n private offersResourceService: OffersResourceService,\n private menuCountersService: MenuCountersService,\n private user: UserService,\n private webWorkerService: WebWorkerService,\n ) {}\n\n get counts(): Observable {\n return this.countEvents;\n }\n\n getCount(key: string): number {\n const newOffers = Array.isArray(this.countEvents.value) ? this.countEvents.value.find((o: KeyValue) => o.key === key) : null;\n\n return newOffers?.value || 0;\n }\n\n initPolling(interval: number) {\n this.user.events\n .pipe(filter((e: UserEvent) => e instanceof UserSessionExpiredEvent || e instanceof UserLogoutEvent))\n .subscribe(() => this.stopPolling());\n\n this.refresh();\n this.stopPolling();\n\n this.webWorkerService.createWorker(WorkerType.OffersTimeout, { timeout: 15000 }, () => {\n this.webWorkerService.createWorker(WorkerType.OffersInterval, { interval }, () => {\n this.refresh();\n });\n });\n }\n\n stopPolling() {\n this.webWorkerService.removeWorker(WorkerType.OffersTimeout);\n this.webWorkerService.removeWorker(WorkerType.OffersInterval);\n }\n\n private refresh() {\n this.offersResourceService.getCount().subscribe((data: any) => {\n this.countEvents.next(data.offers);\n this.menuCountersService.update();\n });\n }\n}\n","/**\n * @stable\n */\nexport interface OfferResponse {\n status: OfferStatus;\n}\n\n/**\n * @stable\n */\nexport enum OfferStatus {\n OFFER_NEW = 'OFFER_NEW',\n OFFER_TNC_ACCEPTED = 'OFFER_TNC_ACCEPTED',\n OFFER_CLAIMED = 'OFFER_CLAIMED',\n OFFER_DROPPED = 'OFFER_DROPPED',\n OFFER_EXPIRED = 'OFFER_EXPIRED',\n OFFERED = 'OFFERED',\n NOTOFFERED = 'NOTOFFERED',\n NOT_OFFERED = 'NOT_OFFERED',\n EXPIRED = 'EXPIRED',\n OPTEDIN = 'OPTEDIN',\n OPTED_IN = 'OPTED_IN',\n OPTEDOUT = 'OPTEDOUT',\n OPTED_OUT = 'OPTED_OUT',\n INVALID = 'INVALID',\n NO_OFFER = 'NO_OFFER',\n}\n\n/**\n * @stable\n */\nexport interface KeyValue {\n key: string;\n value: number;\n}\n\n/**\n * @stable\n */\nexport enum OfferType {\n EDS = 'eds',\n BONUSES = 'bonuses',\n PROMOS = 'promos',\n EDS_GROUP = 'edsgroup',\n}\n","import { Injectable, signal } from '@angular/core';\n\nimport { SharedFeaturesApiService, UserService } from '@frontend/vanilla/core';\nimport { BehaviorSubject, Observable, Subject, groupBy, mergeMap, throttleTime } from 'rxjs';\n\n/**\n * @stable\n */\nexport interface KycStatus extends Record {\n accountStatus: string;\n accountVerificationIsRequired: boolean;\n additionalKycInfo: { Key: ''; Value: '' }[];\n additionalRibbonInfo: { Key: ''; Value: '' }[];\n addressVerificationStatus: string;\n ageVerificationGraceDays: number;\n ageVerificationGracePeriod: string;\n ageVerificationStatus: string;\n amlVerificationStatus: string;\n bankAccountIsRegistered: boolean;\n bankIdVerificationStatus: string;\n blackListVerificationStatus: string;\n createDate: string;\n custom3: string;\n custom4: string;\n depositGraceDays: number;\n depositSuppressed: boolean;\n docsPendingWith: string;\n documentUploadStatusIsPending: boolean;\n emailVerificationStatus: string;\n f2FVerificationRequired: boolean;\n graceDaysBeforeNextAction: number;\n graceDaysUnit: string;\n idVerificationGraceDays: number;\n idVerificationStatus: string;\n idVerificationGracePeriod: string;\n isBlackListAttempted: boolean;\n isCommVerified: boolean;\n isEmailVerified: boolean;\n isKycStarted: boolean;\n isMobileNumberVerified: boolean;\n isTransitionPlayer: boolean;\n kycAttempts: number;\n kycAuthenticationStatus: string;\n kycMaxAttempts: number;\n kycMaxAttemptsReached: boolean;\n kycVerified: boolean;\n partiallyVerified: boolean;\n personalIdVerificationStatus: string;\n ribbonStatusCode: string;\n ribbonStatusMessage: string;\n secretPinVerificationStatus: string;\n ssnVerificationAttempts: number;\n ssnVerificationMaxAttempts: number;\n ssnVerificationMaxAttemptsReached: boolean;\n ssnVerificationStatus: string;\n thirdPartyVerificationStatus: string;\n userHasBonuses: boolean;\n verificationDaysLeft: number;\n verificationStatus: string;\n verificationType: string;\n}\n\n/**\n * Options to be passed to {@link KycStatusService#refresh}\n *\n * @experimental\n */\nexport interface KycStatusOptions extends Record {\n /**\n * If provided, it will be passed to the document upload API.\n */\n useCase?: string;\n /**\n * if true it will try to fetch values from cache.\n */\n cached?: boolean;\n}\n\n/**\n * @stable\n */\n@Injectable({\n providedIn: 'root',\n})\nexport class KycStatusService {\n readonly status = signal(null);\n public static UnauthKycStatus: KycStatus = {\n accountStatus: 'Unknown',\n accountVerificationIsRequired: false,\n additionalKycInfo: [],\n additionalRibbonInfo: [],\n addressVerificationStatus: 'Unknown',\n ageVerificationGraceDays: -1,\n ageVerificationGracePeriod: 'Unknown',\n ageVerificationStatus: 'Unknown',\n amlVerificationStatus: 'Unknown',\n bankAccountIsRegistered: false,\n bankIdVerificationStatus: 'Unknown',\n blackListVerificationStatus: 'Unknown',\n createDate: 'Unknown',\n custom3: 'Unknown',\n custom4: 'Unknown',\n depositGraceDays: -1,\n depositSuppressed: false,\n docsPendingWith: '',\n documentUploadStatusIsPending: false,\n emailVerificationStatus: 'Unknown',\n f2FVerificationRequired: false,\n graceDaysBeforeNextAction: -1,\n graceDaysUnit: 'Unknown',\n idVerificationGraceDays: -1,\n idVerificationStatus: 'Unknown',\n idVerificationGracePeriod: 'Unknown',\n isBlackListAttempted: false,\n isCommVerified: false,\n isEmailVerified: false,\n isKycStarted: false,\n isMobileNumberVerified: false,\n isTransitionPlayer: false,\n kycAttempts: -1,\n kycAuthenticationStatus: 'Unknown',\n kycMaxAttempts: -1,\n kycMaxAttemptsReached: false,\n kycVerified: false,\n partiallyVerified: false,\n personalIdVerificationStatus: 'Unknown',\n ribbonStatusCode: 'Unknown',\n ribbonStatusMessage: 'Unknown',\n secretPinVerificationStatus: 'Unknown',\n ssnVerificationAttempts: -1,\n ssnVerificationMaxAttempts: -1,\n ssnVerificationMaxAttemptsReached: false,\n ssnVerificationStatus: 'Unknown',\n thirdPartyVerificationStatus: 'Unknown',\n userHasBonuses: false,\n verificationDaysLeft: -1,\n verificationStatus: 'Unknown',\n verificationType: 'Unspecified',\n };\n\n private kycStatusEvents = new BehaviorSubject(null);\n private refreshSubject = new Subject();\n\n get kycStatus(): Observable {\n return this.kycStatusEvents;\n }\n\n constructor(\n private apiService: SharedFeaturesApiService,\n private user: UserService,\n ) {\n this.refreshSubject\n .pipe(\n groupBy((kycStatusOptions) => JSON.stringify(kycStatusOptions)), // Group by kycStatusOptions value\n mergeMap((group) =>\n group.pipe(\n throttleTime(1000), // Apply throttle to each group\n ),\n ),\n )\n .subscribe((kycStatusOptions) => {\n this.load(kycStatusOptions);\n });\n }\n\n /**\n * @description Will not call the API if user is not authenticated.\n *\n * @param kycStatusOptions Kyc options to be passed to kyc status api.\n */\n refresh(kycStatusOptions?: KycStatusOptions) {\n if (!this.user.isAuthenticated) {\n return;\n }\n\n this.refreshSubject.next(kycStatusOptions);\n }\n\n private load(kycStatusOptions?: KycStatusOptions) {\n if (this.user.isAuthenticated) {\n this.apiService\n .get('kycstatus', { useCase: kycStatusOptions?.useCase, cached: !!kycStatusOptions?.cached })\n .subscribe((status: KycStatus) => {\n this.kycStatusEvents.next(status);\n this.status.set(status);\n });\n }\n }\n}\n","\n","import { FocusMonitor } from '@angular/cdk/a11y';\nimport { CommonModule, NgStyle } from '@angular/common';\nimport {\n AfterViewInit,\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n EventEmitter,\n Input,\n OnDestroy,\n Output,\n ViewChild,\n ViewEncapsulation,\n booleanAttribute,\n computed,\n forwardRef,\n signal,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\n\nimport { rxHostPressedListener } from '@frontend/ui/rx-host-listener';\n\nexport const DS_CHECKBOX_SIZE_ARRAY = ['medium', 'large'] as const;\nexport type DsCheckboxSize = (typeof DS_CHECKBOX_SIZE_ARRAY)[number];\nexport const DS_CHECKBOX_POSITION_ARRAY = ['left', 'right'] as const;\nexport type DsCheckboxLabelPosition = (typeof DS_CHECKBOX_POSITION_ARRAY)[number];\n\n@Component({\n selector: 'ds-checkbox',\n standalone: true,\n imports: [CommonModule, NgStyle],\n templateUrl: 'checkbox.component.html',\n styleUrls: ['./checkbox.component.scss'],\n host: {\n 'class': 'ds-checkbox',\n '[tabindex]': 'isDisabled() ? -1 : 0',\n '[class]': '\"ds-checkbox-\" + size + \" ds-checkbox-label-\" + labelPosition',\n '[class.ds-checkbox-checked]': 'isChecked()',\n '[class.ds-checkbox-indeterminate]': 'isIndeterminate()',\n '[class.ds-checkbox-disabled]': 'isDisabled()',\n '[attr.aria-labelledby]': 'null',\n '[attr.aria-label]': 'null',\n '[attr.aria-describedby]': 'null',\n '[class.ds-checkbox-inverse]': 'inverse',\n },\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => DsCheckbox),\n multi: true,\n },\n ],\n})\nexport class DsCheckbox implements AfterViewInit, OnDestroy, ControlValueAccessor {\n @ViewChild('checkbox') checkbox!: ElementRef;\n\n @Input() size: DsCheckboxSize = 'large';\n @Input() labelPosition: DsCheckboxLabelPosition = 'right';\n @Input() ariaLabel = 'checkbox';\n @Input() ariaLabelledby: string | null = null;\n @Input() ariaDescribedby: string | null = null;\n @Input() name?: string;\n @Input() id?: string;\n @Input({ transform: booleanAttribute }) inverse = false;\n\n @Input() set checked(value: boolean) {\n if (this.checkedSignal() !== value) {\n this.checkedSignal.set(value);\n this.indeterminateSignal.set(false);\n this.updateCheckboxState();\n this.checkedChange.emit(value);\n this.onChange(value);\n }\n }\n\n @Input() set indeterminate(value: boolean) {\n if (this.indeterminateSignal() !== value) {\n this.indeterminateSignal.set(value);\n if (value) {\n this.checkedSignal.set(false);\n }\n this.updateCheckboxState();\n }\n }\n\n @Input() set disabled(value: boolean) {\n if (this.disabledSignal() !== value) {\n this.disabledSignal.set(value);\n this.updateCheckboxState();\n }\n }\n\n @Output() checkedChange = new EventEmitter();\n\n private checkedSignal = signal(false);\n private indeterminateSignal = signal(false);\n private disabledSignal = signal(false);\n\n isChecked = computed(() => this.checkedSignal());\n isIndeterminate = computed(() => this.indeterminateSignal());\n isDisabled = computed(() => this.disabledSignal());\n\n private onChange: (value: any) => void = () => {};\n private onTouched: () => void = () => {};\n\n constructor(\n private elementRef: ElementRef,\n private focusMonitor: FocusMonitor,\n ) {\n rxHostPressedListener()\n .pipe(takeUntilDestroyed())\n .subscribe(() => this.toggle());\n }\n\n ngAfterViewInit() {\n this.focusMonitor.monitor(this.elementRef, true).subscribe((focusOrigin) => {\n if (!focusOrigin) {\n this.onTouched();\n }\n });\n\n this.updateCheckboxState();\n }\n\n ngOnDestroy() {\n this.focusMonitor.stopMonitoring(this.elementRef);\n }\n\n toggle() {\n if (this.isDisabled()) {\n return;\n }\n if (this.isIndeterminate()) {\n this.indeterminate = false;\n this.checked = true;\n } else {\n this.checked = !this.isChecked();\n }\n }\n\n private updateCheckboxState() {\n if (this.checkbox) {\n Object.assign(this.checkbox.nativeElement, {\n indeterminate: this.isIndeterminate(),\n checked: this.isChecked(),\n disabled: this.isDisabled(),\n });\n }\n }\n\n writeValue(value: any): void {\n this.checkedSignal.set(!!value);\n this.indeterminateSignal.set(false);\n this.updateCheckboxState();\n }\n\n registerOnChange(fn: any): void {\n this.onChange = fn;\n }\n\n registerOnTouched(fn: any): void {\n this.onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this.disabled = isDisabled;\n }\n}\n","import { OfferResponse } from '@frontend/vanilla/shared/offers';\n\nimport { InboxMessage } from './services/inbox.models';\n\nexport enum InboxMessageActionType {\n MessageSelected = 'MessageSelected',\n MessagesRemoveClicked = 'MessagesRemoveClicked',\n MessagesRemoved = 'MessagesRemoved',\n MessageClicked = 'MessageClicked',\n LoadMoreMessages = 'LoadMoreMessages',\n}\n\nexport enum CtaActionType {\n HideInbox = 'HideInbox',\n ClaimOfferSuccess = 'ClaimOfferSuccess',\n}\n\nexport interface InboxAction {\n type: InboxMessageActionType;\n value?: InboxMessage;\n}\n\nexport interface InboxMessageUpdateStatusResponse {\n isUpdated: boolean;\n result: string;\n}\n\nexport interface CtaAction {\n type: CtaActionType;\n value?: OfferResponse;\n}\n","import { Injectable } from '@angular/core';\n\nimport { SharedFeaturesApiService } from '@frontend/vanilla/core';\nimport { Observable } from 'rxjs';\n\nimport { InboxGetCountResponse, InboxGetListResponse, MessageStatus, StatusType } from './inbox.models';\n\n@Injectable({ providedIn: 'root' })\nexport class InboxResourceService {\n constructor(private api: SharedFeaturesApiService) {}\n\n getMessages(pageIndex: number, pageSize: number, messageStatus: StatusType): Observable {\n return this.api.get('inbox/list', {\n pageIndex: pageIndex,\n pageSize: pageSize,\n messageStatus: messageStatus,\n });\n }\n\n getMessagesCount(): Observable {\n return this.api.get('inbox/count');\n }\n\n getMessage(id: string) {\n return this.api.get('inbox/single', { id: id });\n }\n\n removeMessages(ids: string[]) {\n return this.api.post('inbox/remove', { ids: ids });\n }\n\n updateStatus(ids: string[], messageStatus: MessageStatus) {\n return this.api.post('inbox/setstatus', { ids: ids, status: messageStatus.toString() }, { showSpinner: false });\n }\n\n getInboxMessagesInitData() {\n return this.api.get('inbox/initdata');\n }\n}\n","import { Injectable } from '@angular/core';\n\nimport { TrackingService } from '@frontend/vanilla/core';\n\nimport { InboxMessage } from './inbox.models';\n\nconst defaultPromiseResult = Promise.resolve(0);\n\nexport interface InboxOpenedTrackingData {\n eventName: string | undefined;\n newMessagesCount?: number;\n}\n\n@Injectable({ providedIn: 'root' })\nexport class InboxTrackingService {\n constructor(private trackingService: TrackingService) {}\n\n trackInboxOpened(data?: InboxOpenedTrackingData) {\n let eventName, eventData;\n if (data) {\n eventName = data.eventName || 'Event.inbox.unknown_source';\n eventData = { 'page.inbox.newMessageCount': data.newMessagesCount ?? 0 };\n }\n return this.trackingService.triggerEvent(eventName || 'Event.inbox.clicked', eventData || null);\n }\n\n trackInboxClosed(message: InboxMessage) {\n return this.trackMessageAction('Event.inbox.messageClosed', {}, message);\n }\n\n trackInboxClosedEarly() {\n return this.trackingService.triggerEvent('Event.inbox.previewOpenedLessthan1Sec');\n }\n\n trackMessageOpened(message: InboxMessage) {\n if (!message) {\n return defaultPromiseResult;\n }\n return this.trackingService.triggerEvent('Event.inbox.messageOpened', this.getCommonValues(message));\n }\n\n trackMessageDeleted(count: number) {\n return this.trackingService.triggerEvent('Event.inbox.messageDeleted', {\n 'page.inbox.deleteMessageCount': count,\n });\n }\n\n trackCtaBonusClicked(message: InboxMessage) {\n return this.trackMessageAction(\n 'Event.inbox.claimBonusClicked',\n {\n 'page.inbox.bonusId': message.offerId,\n },\n message,\n );\n }\n\n trackCtaBonusSuccess(message: InboxMessage) {\n return this.trackMessageAction(\n 'Event.inbox.bonusOfferClaimSuccess',\n {\n 'page.inbox.bonusId': message.offerId,\n },\n message,\n );\n }\n\n trackCtaPromoClicked(message: InboxMessage) {\n return this.trackMessageAction(\n 'Event.inbox.optedInPromoClicked',\n {\n 'page.inbox.promotionId': message.offerId,\n },\n message,\n );\n }\n\n trackCtaPromoSuccess(message: InboxMessage) {\n return this.trackMessageAction(\n 'Event.inbox.optedInPromoSuccess',\n {\n 'page.inbox.promotionId': message.offerId,\n },\n message,\n );\n }\n\n trackCtaEdsClicked(message: InboxMessage) {\n return this.trackMessageAction(\n 'Event.inbox.optedInEdsEventClicked',\n {\n 'page.inbox.eventId': message.offerId,\n },\n message,\n );\n }\n\n trackCtaEdsSuccess(message: InboxMessage) {\n return this.trackMessageAction(\n 'Event.inbox.edsEventClaimSuccess',\n {\n 'page.inbox.eventId': message.offerId,\n },\n message,\n );\n }\n\n trackKycVerifyClicked() {\n return this.trackingService.triggerEvent('Event.Functionality.JumioKyc', {\n 'page.referringAction': 'KYC_PlayerInbox_TriggerKYC_LoadStatus_InboxMsg_Action_VerifyNow_Clicked',\n });\n }\n\n reportError(id: string, details?: any) {\n id = id || 'unknown';\n const errorDetails = Object.assign({ id: `inbox.${id}` }, details || {});\n this.trackingService.reportError(errorDetails);\n }\n\n private trackMessageAction(eventName: string, eventData: any, message: InboxMessage) {\n if (!message) {\n return defaultPromiseResult;\n }\n\n const data = Object.assign(this.getCommonValues(message), eventData);\n return this.trackingService.triggerEvent(eventName, data);\n }\n\n private getCommonValues(message: InboxMessage) {\n if (!message) {\n return {};\n }\n return {\n 'page.inbox.messageSentDate': message.createdDate,\n 'page.inbox.messageType': message.messageType,\n 'page.inbox.messageSource': message.messageSource,\n 'page.inbox.promotionId': message.bonusCode,\n 'page.inbox.templateId': message.sitecoreId,\n 'page.inbox.offerId': message.offerId,\n 'page.inbox.isPreviewTncClicked': message.isTnCTemplate && message.isTnCViewed,\n 'page.inbox.previewMode': false,\n };\n }\n}\n","import { Injectable } from '@angular/core';\n\nimport { OfferResponse, OffersResourceService } from '@frontend/vanilla/shared/offers';\nimport { BehaviorSubject, Observable, throwError as _throw } from 'rxjs';\nimport { catchError, map } from 'rxjs/operators';\n\nimport { InboxResourceService } from './inbox-resource.service';\nimport { InboxTrackingService } from './inbox-tracking.service';\nimport { InboxGetListResponse, InboxMessage, MessageStatus, StatusType } from './inbox.models';\n\n@Injectable({ providedIn: 'root' })\nexport class CrappyInboxService {\n messages: BehaviorSubject;\n wait: boolean = false;\n isAllMessagesLoaded: boolean = false;\n\n private _messageList: InboxMessage[];\n\n constructor(\n private resource: InboxResourceService,\n private tracking: InboxTrackingService,\n private offersResourceService: OffersResourceService,\n ) {\n this._messageList = [];\n this.messages = new BehaviorSubject(this._messageList);\n }\n\n getMessages(pageIndex: number, pageSize: number, messageStatus: StatusType): Observable {\n return this.resource.getMessages(pageIndex, pageSize, messageStatus).pipe(\n catchError((err) => this.trackAndThrow(err, 'getMessages')),\n map((response: InboxGetListResponse) => {\n if (response.actualReceivedNumberOfMessages < pageSize) {\n this.isAllMessagesLoaded = true;\n }\n\n this._messageList = this._messageList.concat(response.messages);\n this.emitMessages();\n }),\n );\n }\n\n resetMessages() {\n this.isAllMessagesLoaded = false;\n this._messageList = [];\n this.emitMessages();\n }\n\n updateStatus(ids: string[], messageStatus: MessageStatus): Observable {\n return this.resource.updateStatus(ids, messageStatus);\n }\n\n claimOffer(offerType: string, offerId: string): Observable {\n return this.offersResourceService\n .updateStatus(offerType, offerId)\n .pipe(catchError((err: any) => this.trackAndThrow(err, 'claimOffer', { offerId: offerId, action: offerType })));\n }\n\n remove(ids: string[]): Observable {\n return this.resource.removeMessages(ids).pipe(\n catchError((err: any) => {\n if (this._messageList !== null) {\n this.emitMessages();\n }\n return _throw(err);\n }),\n map((response: any) => {\n if (this._messageList !== null && response && response.isUpdated) {\n this._messageList = this._messageList.filter((el: InboxMessage) => {\n return ids.indexOf(el.id) < 0;\n });\n this.emitMessages();\n }\n\n return response;\n }),\n );\n }\n\n isDepositBonusLink(rawLink: string, additionalAttrs: { [key: string]: string }): boolean {\n return !!(rawLink?.match(/mobileportal\\/cashier.*/i) && additionalAttrs && additionalAttrs['data-bonuscode']?.trim());\n }\n\n getDepositBonusLink(rawLink: string, additionalAttrs: { [key: string]: string }): string {\n if (!rawLink) return rawLink;\n if (this.isDepositBonusLink(rawLink, additionalAttrs)) {\n const depositBonusPartUrl = `mobileportal/cashier/deposit?bonusCodeForPrefill=${additionalAttrs['data-bonuscode']?.trim()}`;\n return rawLink.replace(/mobileportal\\/cashier.*/i, depositBonusPartUrl);\n }\n return rawLink;\n }\n\n private emitMessages() {\n this.messages.next(this._messageList);\n }\n\n private trackAndThrow(error: any, id: string, details?: any): Observable {\n this.tracking.reportError(id, details || null);\n\n return _throw(error);\n }\n}\n","import { Injectable } from '@angular/core';\n\nimport { ClientConfigProductName, LazyClientConfig, LazyClientConfigBase, LazyClientConfigService } from '@frontend/vanilla/core';\n\n/**\n * @stable\n */\n@LazyClientConfig({ key: 'vnInbox', product: ClientConfigProductName.SF })\n@Injectable({\n providedIn: 'root',\n deps: [LazyClientConfigService],\n useFactory: inboxConfigFactory,\n})\nexport class InboxConfig extends LazyClientConfigBase {\n counterPullInterval: number;\n enabled: boolean;\n jumioKycUrl: string;\n lazyLoading: LazyLoading;\n readTime: number;\n showOfferMessage: boolean;\n triggerJumioFromPlayerInbox: boolean;\n useRtms: boolean;\n}\n\nexport function inboxConfigFactory(service: LazyClientConfigService) {\n return service.get(InboxConfig);\n}\n\nexport class LazyLoading {\n pageSize: number;\n loadBeforeItems: number;\n}\n","import { Injectable } from '@angular/core';\n\nimport {\n RtmsMessage,\n RtmsService,\n RtmsType,\n UserEvent,\n UserLoginEvent,\n UserLogoutEvent,\n UserService,\n UserSessionExpiredEvent,\n WebWorkerService,\n WorkerType,\n} from '@frontend/vanilla/core';\nimport { Observable, ReplaySubject } from 'rxjs';\nimport { filter } from 'rxjs/operators';\n\nimport { InboxResourceService } from './inbox-resource.service';\nimport { InboxConfig } from './inbox.client-config';\nimport { InboxGetCountResponse } from './inbox.models';\n\n@Injectable({ providedIn: 'root' })\nexport class InboxCountService {\n private countStream = new ReplaySubject(1);\n\n constructor(\n private inboxConfig: InboxConfig,\n private inboxResourceService: InboxResourceService,\n private rtmsService: RtmsService,\n private webWorkerService: WebWorkerService,\n private user: UserService,\n ) {\n this.inboxConfig.whenReady.subscribe(() => {\n if (user.isAuthenticated) {\n this.subscribe();\n }\n\n user.events.pipe(filter((e: UserEvent) => e instanceof UserLoginEvent)).subscribe(() => this.subscribe());\n });\n }\n\n get count(): Observable {\n return this.countStream;\n }\n\n refresh() {\n if (this.inboxConfig.useRtms) {\n this.poll();\n } else {\n this.stopPolling();\n this.poll();\n this.startPolling();\n }\n }\n\n private subscribe() {\n this.poll(); // Get initial count from service since rtms message might come late.\n\n if (this.inboxConfig.useRtms) {\n this.rtmsService.messages\n .pipe(filter((m: RtmsMessage) => m.type == RtmsType.PLAYERINBOX_UPDATE))\n .subscribe((m: RtmsMessage) => this.next(m.payload.newMsgCount));\n } else {\n this.startPolling();\n\n this.user.events\n .pipe(filter((e: UserEvent) => e instanceof UserSessionExpiredEvent || e instanceof UserLogoutEvent))\n .subscribe(() => this.stopPolling());\n }\n }\n\n private next(count: number) {\n // truncate to 99\n this.countStream.next(Math.min(count, 99));\n }\n\n private stopPolling() {\n this.webWorkerService.removeWorker(WorkerType.InboxCountPollInterval);\n }\n\n private startPolling() {\n this.webWorkerService.createWorker(WorkerType.InboxCountPollInterval, { interval: this.inboxConfig.counterPullInterval }, () => this.poll());\n }\n\n private poll() {\n this.inboxResourceService.getMessagesCount().subscribe((r: InboxGetCountResponse) => this.next(r.count));\n }\n}\n","import { Injectable } from '@angular/core';\n\nimport { ViewTemplateForClient } from '@frontend/vanilla/core';\nimport { Observable, ReplaySubject } from 'rxjs';\nimport { map } from 'rxjs/operators';\n\nimport { InboxResourceService } from './inbox-resource.service';\n\n/**\n * @stable\n */\n@Injectable({ providedIn: 'root' })\nexport class InboxDataService {\n private contentStream: ReplaySubject | null = null;\n\n constructor(private inboxResourceService: InboxResourceService) {}\n\n getContent(): Observable {\n if (!this.contentStream) {\n this.contentStream = new ReplaySubject(1);\n this.inboxResourceService\n .getInboxMessagesInitData()\n .pipe(map((c) => c.content))\n .subscribe(this.contentStream);\n }\n return this.contentStream;\n }\n}\n","import { OfferStatus } from '@frontend/vanilla/shared/offers';\n\n/**\n * @stable\n */\nexport class MessageContent {\n detailTitle: string;\n detailImage: InboxDetailImage;\n detailDescription: string;\n detailCallToAction: string;\n shortImage: string;\n snippetTitle: string;\n snippetDescription: string;\n snippetCallToAction: string;\n showManualTermsAndConditions: boolean;\n isManualTermsAndConditionsEmpty: boolean;\n manualTermsAndConditions?: string;\n expandTermsAndConditionsByDefault: boolean;\n headerTermsAndConditionsInbox: string;\n inboxImageTitleText: string;\n inboxImageIntroductoryText: string;\n inboxImageSubtitleText: string;\n inboxImageTitleFontSize: string;\n inboxImageTextAlignment: string;\n}\n\n/**\n * @stable\n */\nexport class InboxDetailImage {\n detailImage: string;\n detailImageLink: string;\n detailImageAttrs: { [key: string]: string };\n}\n\n/**\n * @stable\n */\nexport class MessageData {\n id: string;\n createdDate: Date;\n eligibleProducts: string[];\n messageSource: string;\n messageStatus: MessageStatus;\n messageType: MessageType;\n priority: number;\n sourceStatus: OfferStatus;\n content: MessageContent;\n isExpired: boolean;\n isNew: boolean;\n isNoDepositBonus: boolean;\n isTnCTemplate: boolean;\n tnCData: string;\n sitecoreId: string;\n isAllMobileGames: boolean;\n isAllDesktopGames: boolean;\n casinoHomeLink: string;\n channelId: string;\n}\n\n/**\n * @stable\n */\nexport class InboxMessage extends MessageData {\n selected: boolean;\n mobileGameList: any;\n desktopGameList: any;\n mobileAllList: { sectionTitle: string; link: string }[];\n desktopAllList: { sectionTitle: string; link: string }[];\n mobileChannelList: string[];\n desktopChannelList: string[];\n desktopSectionGamesPairs: any;\n mobileSectionGamesPairs: any;\n desktopSectionGamesViewModel: { title: string; value: string }[];\n mobileSectionGamesViewModel: { title: string; value: string }[];\n desktopGames: any;\n desktopGameTitles: any;\n mobileGames: any;\n mobileGameTitles: any;\n bonusCode: string;\n offerId: string;\n isTnCViewed?: boolean;\n bonusSourceStatus: OfferStatus;\n}\n\n/**\n * @stable\n */\nexport class InboxGetListResponse {\n messages: InboxMessage[];\n actualReceivedNumberOfMessages: number;\n}\n\n/**\n * @stable\n */\nexport class InboxGetCountResponse {\n count: number;\n}\n\n/**\n * @stable\n */\nexport enum MessageStatus {\n unread = 'unread',\n read = 'read',\n new = 'new',\n}\n\n/**\n * @stable\n */\nexport enum StatusType {\n all = 'ALL',\n new = 'NEW',\n}\n\n/**\n * @stable\n */\nexport enum MessageType {\n EDS_OFFER = 'EDS_OFFER',\n EDS_REWARD = 'EDS_REWARD',\n PROMO_TARGET = 'PROMO_TARGET',\n PROMO_REWARD = 'PROMO_REWARD',\n CMS_OFFER = 'CMS_OFFER',\n BONUS_OFFER = 'BONUS_OFFER',\n}\n","import { Component, ElementRef, Input } from '@angular/core';\n\nimport { DynamicHtmlDirective } from '@frontend/vanilla/core';\n\n@Component({\n standalone: true,\n imports: [DynamicHtmlDirective],\n selector: 'vn-inbox-cta-content',\n template: `
`,\n})\nexport class InboxCtaContentComponent {\n @Input() content: any;\n constructor(public elementRef: ElementRef) {}\n}\n","import { DOCUMENT } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n EventEmitter,\n Input,\n OnChanges,\n OnDestroy,\n Output,\n Renderer2,\n SimpleChanges,\n ViewChild,\n inject,\n} from '@angular/core';\n\nimport { CashierService, NativeAppService, NavigationService, TimerService, WINDOW } from '@frontend/vanilla/core';\nimport { OfferResponse, OfferStatus, OfferType, OffersResourceService } from '@frontend/vanilla/shared/offers';\nimport { first } from 'rxjs/operators';\n\nimport { CtaAction, CtaActionType } from '../inbox.models';\nimport { CrappyInboxService } from '../services/crappy-inbox.service';\nimport { InboxTrackingService } from '../services/inbox-tracking.service';\nimport { InboxConfig } from '../services/inbox.client-config';\nimport { InboxMessage, MessageType } from '../services/inbox.models';\nimport { InboxCtaContentComponent } from './inbox-content.component';\n\nconst OFFER_MESSAGE_CLASS = 'offer-message';\n\n@Component({\n standalone: true,\n imports: [InboxCtaContentComponent],\n selector: 'lh-inbox-cta-action',\n template: `\n \n \n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class InboxCtaActionComponent implements OnChanges, OnDestroy {\n @Output() action: EventEmitter = new EventEmitter();\n @Input() inboxMessage: InboxMessage;\n @Input() inboxCtaActionMessages: any;\n @Input() detailContent: string;\n @ViewChild(InboxCtaContentComponent, { read: ElementRef, static: true }) contentItem: ElementRef;\n\n private ctaElements: HTMLAnchorElement[];\n private linksClickListeners: (() => void)[] = [];\n private ctaHrefIndicator: string = 'inbox://cta/';\n private ctaEdsHrefIndicator: string = '/INBOXEDS';\n private ctaPatHrefIndicator: string = '/INBOXPAT';\n private readonly _doc = inject(DOCUMENT);\n readonly #window = inject(WINDOW);\n\n constructor(\n private elementRef: ElementRef,\n private navigation: NavigationService,\n private cashierService: CashierService,\n private renderer: Renderer2,\n private inboxService: CrappyInboxService,\n private nativeApplication: NativeAppService,\n private tracking: InboxTrackingService,\n private offersResourceService: OffersResourceService,\n private inboxConfig: InboxConfig,\n private timerService: TimerService,\n ) {}\n\n ngOnChanges(changes: SimpleChanges) {\n if (changes.detailContent || changes.inboxMessage) {\n this.bindImageLinkClick();\n\n if (this.detailContent) {\n this.timerService.setTimeout(() => this.handleInjectedContent(this.contentItem));\n }\n }\n }\n\n ngOnDestroy() {\n if (this.linksClickListeners) {\n this.linksClickListeners.forEach((listener: () => void) => {\n if (listener) {\n listener();\n }\n });\n }\n }\n\n private bindImageLinkClick() {\n // close inbox on clickable img\n const imageLinks = this.elementRef.nativeElement.querySelectorAll('a[class=\"ctaImageLink\"]');\n\n for (let n = 0; n < imageLinks.length; n++) {\n const link = imageLinks[n];\n\n if (link.tagName === 'A') {\n this.bindHideInbox(link);\n }\n }\n }\n\n private handleInjectedContent(parentElement: ElementRef) {\n if (Object.keys(this.inboxMessage).length > 0) {\n if (!this.inboxCtaActionMessages) {\n return;\n }\n\n const depositDeepLinks = this.getDepositDeepLinks(parentElement);\n depositDeepLinks.forEach(this.handleDepositDeepLink.bind(this));\n\n this.ctaElements = this.getCtaElements(parentElement);\n this.bindElementsToHideInboxEvent(parentElement);\n\n // CTA element logic\n this.ctaElements.forEach((ctaElement: HTMLAnchorElement) => {\n this.handleCtaElement(ctaElement);\n });\n this.setTargetTopAttributeToLinksWithSameHost(parentElement);\n this.bindCashierLinks(parentElement);\n }\n }\n\n private handleCtaElement(ctaElement: HTMLAnchorElement) {\n const msg = this.inboxMessage;\n ctaElement.classList.add('btn', 'send', 'ctabutton');\n this.renderer.setAttribute(ctaElement, 'sitecoreid', msg.sitecoreId);\n const isCta: boolean = !!ctaElement.href.match(new RegExp(this.ctaHrefIndicator, 'igm'));\n const isInboxEds: boolean = !!ctaElement.href.match(new RegExp(this.ctaEdsHrefIndicator, 'igm'));\n const isInboxPat: boolean = !!ctaElement.href.match(new RegExp(this.ctaPatHrefIndicator, 'igm'));\n\n if (!msg.offerId && (!ctaElement.getAttribute('data-eds-event-id') || ctaElement.getAttribute('data-eds-event-id') === '[empty]')) {\n this.setElementIsHidden(ctaElement, true);\n } else {\n const edsEventId = ctaElement.attributes.getNamedItem('data-eds-event-id');\n msg.offerId = edsEventId && edsEventId.textContent !== '[empty]' ? edsEventId.textContent! : msg.offerId;\n\n if (isCta) {\n this.handleBonusMessage(ctaElement);\n } else if (isInboxEds || isInboxPat) {\n const offerType = isInboxPat ? OfferType.PROMOS : OfferType.EDS;\n this.setElementIsDisable(ctaElement, true);\n\n //get current message status\n this.offersResourceService\n .getStatus(offerType, msg.offerId)\n .pipe(first())\n .subscribe({\n next: (response: OfferResponse) => {\n response.status\n ? this.handleEdsMessage(ctaElement, response.status, offerType)\n : this.handleMessage(ctaElement, offerType);\n },\n error: () => {\n this.handleMessage(ctaElement, offerType);\n },\n });\n }\n }\n if (isCta || isInboxEds || isInboxPat) {\n ctaElement.href = 'javascript:void(0)';\n } //else deep link\n }\n\n private getCtaElements(parentElement: ElementRef): HTMLAnchorElement[] {\n return [\n ...Array.from(parentElement.nativeElement.querySelectorAll(`a[href^=\"${this.ctaHrefIndicator}\"]`)),\n ...Array.from(parentElement.nativeElement.querySelectorAll(`a[href^=\"${this.ctaEdsHrefIndicator}\"]`)),\n ...Array.from(parentElement.nativeElement.querySelectorAll(`a[href^=\"${this.ctaPatHrefIndicator}\"]`)),\n ];\n }\n\n private getDepositDeepLinks(parentElement: ElementRef): HTMLAnchorElement[] {\n return Array.from(parentElement.nativeElement.querySelectorAll('a[data-bonuscode]'));\n }\n\n private handleDepositDeepLink(el: HTMLAnchorElement): void {\n const attrs: { [key: string]: string } = {};\n Array.from(el.attributes).forEach((a) => (attrs[a.name] = a.value));\n\n if (this.inboxService.isDepositBonusLink(el.href, attrs)) {\n el.href = this.inboxService.getDepositBonusLink(el.href, attrs);\n }\n }\n\n private bindElementsToHideInboxEvent(parentElement: ElementRef): void {\n // close inbox on click any link\n const linkWithoutButtons = parentElement.nativeElement.querySelectorAll('a[class*=\"LinkWithoutButton\"]');\n\n for (let i = 0; i < linkWithoutButtons.length; i++) {\n this.bindHideInbox(linkWithoutButtons[i]);\n }\n }\n\n private setTargetTopAttributeToLinksWithSameHost(parentElement: ElementRef) {\n // Solves that the link doesn't close the inbox message when the href is the same as the current window location.\n const allButtons = parentElement.nativeElement.querySelectorAll('a[class*=\"btn\"]');\n\n allButtons.forEach((linkButton: HTMLAnchorElement) => {\n if (linkButton.host === this.#window.location.host) {\n this.renderer.setProperty(linkButton, 'target', '_top');\n }\n });\n }\n\n private bindCashierLinks(parentElement: ElementRef) {\n const allButtons = parentElement.nativeElement.querySelectorAll('a[class*=\"btn-cashier\"]');\n\n allButtons.forEach((linkButton: HTMLAnchorElement) => {\n this.linksClickListeners.push(\n this.renderer.listen(linkButton, 'click', (event: Event) => {\n event.stopPropagation();\n event.preventDefault();\n if (linkButton.href) {\n this.action.emit({\n type: CtaActionType.HideInbox,\n });\n this.navigation.goTo(linkButton.href);\n }\n }),\n );\n });\n }\n\n private bindHideInbox(ctaElement: HTMLAnchorElement) {\n this.linksClickListeners.push(\n this.renderer.listen(ctaElement, 'click', (event: Event) => {\n this.action.emit({\n type: CtaActionType.HideInbox,\n });\n event.stopPropagation();\n }),\n );\n }\n\n private handleEdsMessage(ctaElement: HTMLAnchorElement, sourceStatus: OfferStatus, offerType: string): void {\n this.setElementIsHidden(ctaElement, false);\n this.setElementIsDisable(ctaElement, false);\n\n switch (sourceStatus) {\n case OfferStatus.OFFERED:\n const unbind: () => void = this.renderer.listen(ctaElement, 'click', (event: Event) => {\n event.stopPropagation();\n offerType === OfferType.EDS\n ? this.tracking.trackCtaEdsClicked(this.inboxMessage)\n : this.tracking.trackCtaPromoClicked(this.inboxMessage);\n\n this.claimCta(ctaElement, offerType);\n unbind();\n });\n this.linksClickListeners.push(unbind);\n break;\n case OfferStatus.NOTOFFERED:\n case OfferStatus.NOT_OFFERED:\n this.setElementIsDisable(ctaElement, true);\n this.setTextFormAttr(ctaElement, 'data-eds-message-not-offered', this.inboxCtaActionMessages['NotEligible']);\n break;\n case OfferStatus.EXPIRED:\n this.setElementIsDisable(ctaElement, true);\n this.setTextFormAttr(ctaElement, 'data-eds-message-expired', this.inboxCtaActionMessages['Expired']);\n break;\n case OfferStatus.OPTEDIN:\n case OfferStatus.OPTED_IN:\n this.setElementIsDisable(ctaElement, true);\n this.setTextFormAttr(ctaElement, 'data-eds-message-opted-in', this.inboxCtaActionMessages['YouHaveOptedIn']);\n break;\n case OfferStatus.OPTEDOUT:\n this.setElementIsDisable(ctaElement, true);\n this.setTextFormAttr(ctaElement, 'data-eds-message-opted-out', this.inboxCtaActionMessages['YouHaveOptedOut']);\n break;\n case OfferStatus.INVALID:\n this.setElementIsDisable(ctaElement, true);\n break;\n case OfferStatus.NO_OFFER:\n this.setElementIsHidden(ctaElement, true);\n break;\n default:\n this.setElementIsDisable(ctaElement, true);\n if (this.inboxCtaActionMessages[`${sourceStatus}_BUTTON`]) {\n this.renderer.setProperty(ctaElement, 'innerText', this.inboxCtaActionMessages[`${sourceStatus}_BUTTON`]);\n }\n }\n this.setOfferMessageContainer(ctaElement, false, sourceStatus);\n }\n\n private setTextFormAttr(ctaElement: HTMLAnchorElement, textProperty: string, backupText: string): void {\n const attr = ctaElement.attributes.getNamedItem(textProperty);\n\n if (attr && attr.textContent !== '[empty]') {\n this.renderer.setProperty(ctaElement, 'innerText', attr.textContent);\n } else if (backupText) {\n this.renderer.setProperty(ctaElement, 'innerText', backupText);\n }\n }\n\n private setElementIsHidden(element: HTMLAnchorElement, isHidden: boolean) {\n this.renderer.setStyle(element, 'display', isHidden ? 'none' : '');\n }\n\n private claimCta(ctaElement: HTMLAnchorElement, offerType: string) {\n this.setElementIsDisable(ctaElement, true);\n const edsEventId = ctaElement.attributes.getNamedItem('data-eds-event-id');\n const offerId = edsEventId && edsEventId.textContent !== '[empty]' ? edsEventId.textContent! : this.inboxMessage.offerId;\n\n this.inboxService.claimOffer(offerType, offerId).subscribe({\n next: (response: OfferResponse) => {\n this.action.emit({\n type: CtaActionType.ClaimOfferSuccess,\n value: response,\n });\n\n if (response.status === OfferStatus.OPTED_IN || response.status === OfferStatus.OFFER_CLAIMED) {\n // pass list and current CTA buttons for update\n const ctaList = [ctaElement];\n this.renderer.removeAttribute(ctaElement, 'disabled');\n this.onClaimCtaSuccess(ctaList);\n }\n this.setOfferMessageContainer(ctaElement, false, response.status);\n },\n error: () => {\n this.renderer.removeAttribute(ctaElement, 'disabled');\n },\n });\n }\n\n private onClaimCtaSuccess(ctaElements: HTMLAnchorElement[]) {\n //Set Claim Button\n this.updateElementOnClaimCtaSuccess(ctaElements);\n this.launchGame();\n }\n\n private updateElementOnClaimCtaSuccess(ctaElements: HTMLAnchorElement[]) {\n for (let i = 0; i < ctaElements.length; i++) {\n const ctaElement = ctaElements[i]!;\n\n if (this.inboxMessage.messageType === MessageType.BONUS_OFFER) {\n this.tracking.trackCtaBonusSuccess(this.inboxMessage);\n this.renderer.setProperty(ctaElement, 'innerText', this.inboxCtaActionMessages.Claimed);\n } else if (this.inboxMessage.messageType === MessageType.EDS_OFFER) {\n this.tracking.trackCtaEdsSuccess(this.inboxMessage);\n this.setTextFormAttr(ctaElement, 'data-eds-message-opted-in', this.inboxCtaActionMessages.YouHaveOptedIn);\n } else {\n this.tracking.trackCtaPromoSuccess(this.inboxMessage);\n this.renderer.setProperty(ctaElement, 'innerText', this.inboxCtaActionMessages.YouHaveOptedIn);\n }\n\n if (!this.inboxMessage.isNoDepositBonus && this.inboxMessage.messageType === MessageType.BONUS_OFFER) {\n const unbind: () => void = this.renderer.listen(ctaElement, 'click', (event: Event) => {\n event.stopPropagation();\n unbind();\n this.goToOrReturnCashierUrlStrategy(this.inboxMessage.bonusCode);\n });\n this.linksClickListeners.push(unbind);\n this.renderer.setProperty(ctaElement, 'innerText', this.inboxCtaActionMessages.DepositNow);\n } else {\n this.setElementIsDisable(ctaElement, true);\n // Add possible display gamelist logic here\n }\n }\n }\n\n private launchGame() {\n //Redirect or Launch Game or stay on the page\n if (!this.inboxMessage.isNoDepositBonus && this.inboxMessage.messageType === MessageType.BONUS_OFFER) {\n // DepositBonus\n this.goToOrReturnCashierUrlStrategy(this.inboxMessage.bonusCode);\n } else if (this.inboxMessage.isNoDepositBonus && this.inboxMessage.mobileGames && this.inboxMessage.mobileGames.length === 1) {\n // Launch single game\n const mobileGameInfo = this.inboxMessage.mobileGames[0];\n if (this.nativeApplication.isNativeApp) {\n this.#window.location.href = mobileGameInfo.launchUrl; //event to native\n } else {\n this.navigation.goTo(mobileGameInfo.launchUrl, { forceReload: true });\n }\n }\n }\n\n private handleBonusMessage(ctaElement: HTMLAnchorElement) {\n let unbind: (() => void) | undefined;\n\n switch (this.inboxMessage.sourceStatus) {\n case OfferStatus.OFFER_NEW:\n unbind = this.renderer.listen(ctaElement, 'click', (event: Event) => {\n event.stopPropagation();\n\n if (unbind) {\n unbind();\n }\n\n this.tracking.trackCtaBonusClicked(this.inboxMessage);\n this.claimCta(ctaElement, OfferType.BONUSES);\n });\n break;\n case OfferStatus.OFFER_TNC_ACCEPTED:\n // DepositBonus\n unbind = this.renderer.listen(ctaElement, 'click', (event: Event) => {\n event.stopPropagation();\n\n if (unbind) {\n unbind();\n }\n\n this.goToOrReturnCashierUrlStrategy(this.inboxMessage.bonusCode);\n });\n this.renderer.setProperty(ctaElement, 'innerText', this.inboxCtaActionMessages.DepositNow);\n break;\n case OfferStatus.OFFER_CLAIMED:\n this.setElementIsDisable(ctaElement, true);\n this.renderer.setProperty(ctaElement, 'innerText', this.inboxCtaActionMessages.Claimed);\n break;\n case OfferStatus.OFFER_DROPPED:\n case OfferStatus.OFFER_EXPIRED:\n this.setElementIsDisable(ctaElement, true);\n this.renderer.setProperty(ctaElement, 'innerHTML', this.inboxCtaActionMessages.Expired);\n break;\n case OfferStatus.NO_OFFER:\n this.setElementIsHidden(ctaElement, true);\n break;\n }\n\n if (unbind) {\n this.linksClickListeners.push(unbind);\n }\n\n this.setOfferMessageContainer(ctaElement, true);\n }\n\n private handleMessage(ctaElement: HTMLAnchorElement, offerType: OfferType) {\n this.setElementIsHidden(ctaElement, false);\n this.setElementIsDisable(ctaElement, false);\n\n (ctaElement as any).unlistenClaimCta = this.renderer.listen(ctaElement, 'click', (event: any) => {\n event.stopPropagation();\n this.claimCta(ctaElement, offerType);\n });\n\n //TODO: refactor all component, this is a patch fix for memory leak\n this.linksClickListeners.push((ctaElement as any).unlistenClaimCta);\n }\n\n private goToOrReturnCashierUrlStrategy(bonusCode: string) {\n this.cashierService.goToCashierDeposit({ queryParameters: { ['bonusCodeForPrefill']: bonusCode } });\n }\n\n private setElementIsDisable(element: HTMLAnchorElement, isDisabled: boolean) {\n isDisabled ? this.renderer.setAttribute(element, 'disabled', 'disabled') : this.renderer.removeAttribute(element, 'disabled');\n }\n\n private setOfferMessageContainer(ctaElement: HTMLAnchorElement, checkOfferStatus: boolean, sourceStatus?: OfferStatus) {\n if (this.inboxConfig.showOfferMessage) {\n if (checkOfferStatus) {\n this.offersResourceService\n .getStatus(OfferType.BONUSES, this.inboxMessage.offerId)\n .pipe(first())\n .subscribe({\n next: (response: OfferResponse) => {\n if (response.status) {\n this.setMessage(ctaElement, response.status);\n }\n },\n error: () => {},\n });\n } else {\n this.setMessage(ctaElement, sourceStatus);\n }\n }\n }\n\n private setMessage(ctaElement: HTMLAnchorElement, sourceStatus?: OfferStatus) {\n const message = this.inboxCtaActionMessages[`${sourceStatus}_MESSAGE`];\n if (message) {\n let container = ctaElement.previousElementSibling;\n /* check if container already exist */\n if (container && container.classList.contains(OFFER_MESSAGE_CLASS)) {\n container.innerHTML = message;\n } else {\n container = this.createMessageContainer(message, ctaElement.getAttribute('data-eds-message-class'));\n ctaElement.parentNode?.insertBefore(container, ctaElement);\n }\n }\n }\n\n private createMessageContainer(text: string, cssClass: string | null): HTMLDivElement {\n const div = this._doc.createElement('div');\n div.innerHTML = text;\n div.classList.add(OFFER_MESSAGE_CLASS);\n div.classList.add('badge-date');\n\n if (cssClass) {\n div.classList.add(cssClass);\n }\n\n return div;\n }\n}\n","\n@if (channelList && channelList.length) {\n \n (\n @for (channel of channelList; track trackByItem(i, channel); let i = $index; let isLast = $last) {\n \n \n @if (!isLast) {\n \n }\n \n }\n )\n \n}\n","import { CommonModule } from '@angular/common';\nimport { Component, Input } from '@angular/core';\n\nimport { trackByItem } from '@frontend/vanilla/core';\nimport { TrustAsHtmlPipe } from '@frontend/vanilla/shared/browser';\n\n@Component({\n standalone: true,\n imports: [CommonModule, TrustAsHtmlPipe],\n selector: 'lh-inbox-message-channels',\n templateUrl: 'inbox-message-channels.component.html',\n})\nexport class InboxMessageChannelsComponent {\n @Input() channelList: string[];\n @Input() contentMessages: { [key: string]: string };\n @Input() sectionTitle: string;\n readonly trackByItem = trackByItem;\n}\n","
\n
\n \n
\n
\n @if (message && message.desktopChannelList && message.desktopChannelList.length) {\n \n }\n
\n {{ message.desktopGameTitles }}\n
\n @for (sectionNameGames of message.desktopSectionGamesViewModel; track trackByTitle($index, sectionNameGames)) {\n
\n \n
{{ sectionNameGames.value }}
\n
\n }\n
\n {{ contentMessages.AllCasinoGames }}\n
\n
\n
\n @for (current of message.desktopAllList; track trackBySectionTitle($index, current)) {\n
{{ contentMessages.All }}
\n }\n
\n
\n","import { CommonModule } from '@angular/common';\nimport { Component, Input, OnInit } from '@angular/core';\n\nimport { trackByProp } from '@frontend/vanilla/core';\nimport { TrustAsHtmlPipe } from '@frontend/vanilla/shared/browser';\n\nimport { InboxMessage } from '../services/inbox.models';\nimport { InboxMessageChannelsComponent } from './inbox-message-channels.component';\n\n@Component({\n standalone: true,\n imports: [CommonModule, TrustAsHtmlPipe, InboxMessageChannelsComponent],\n selector: 'lh-inbox-desktop-game-list',\n templateUrl: 'inbox-desktop-game-list.component.html',\n})\nexport class InboxDesktopGameListComponent implements OnInit {\n @Input() message: InboxMessage;\n @Input() contentMessages: { [key: string]: string };\n isGameListHidden: boolean;\n readonly trackByTitle = trackByProp('title');\n readonly trackBySectionTitle = trackByProp('sectionTitle');\n\n ngOnInit() {\n this.isGameListHidden =\n (!this.message.desktopGameList || this.message.desktopGameList.length === 0) &&\n (!this.message.desktopAllList || this.message.desktopAllList.length === 0) &&\n !this.message.isAllDesktopGames;\n }\n\n getSectionTitle(sectionTitle: string): string {\n return this.contentMessages['GameSection.' + sectionTitle.replace(' ', '')] || sectionTitle;\n }\n}\n","
\n
\n \n
\n
\n @if (message.mobileChannelList && message.mobileChannelList.length) {\n \n }\n
\n {{ message.mobileGameTitles }}\n
\n
\n :\n @for (sectionNameGames of message.mobileSectionGamesViewModel; track trackByTitle($index, sectionNameGames)) {\n
{{ sectionNameGames.value }}
\n }\n
\n
\n \n @if (isBonusApplied()) {\n \n }\n @if (!isBonusApplied()) {\n \n }\n
\n
\n @for (current of message.mobileAllList; track trackBySectionTitle($index, current)) {\n
\n \n @if (isBonusApplied()) {\n \n }\n @if (!isBonusApplied()) {\n \n }\n
\n }\n
\n
\n
\n","import { CommonModule } from '@angular/common';\nimport { Component, Input, OnInit, inject } from '@angular/core';\n\nimport { NativeAppService, NavigationService, WINDOW, trackByProp } from '@frontend/vanilla/core';\nimport { TrustAsHtmlPipe } from '@frontend/vanilla/shared/browser';\nimport { OfferStatus } from '@frontend/vanilla/shared/offers';\n\nimport { InboxMessage } from '../services/inbox.models';\nimport { InboxMessageChannelsComponent } from './inbox-message-channels.component';\n\n@Component({\n standalone: true,\n imports: [CommonModule, TrustAsHtmlPipe, InboxMessageChannelsComponent],\n selector: 'lh-inbox-mobile-game-list',\n templateUrl: 'inbox-mobile-game-list.component.html',\n})\nexport class InboxMobileGameListComponent implements OnInit {\n @Input() message: InboxMessage;\n @Input() contentMessages: { [key: string]: string };\n isGameListHidden: boolean;\n readonly trackByTitle = trackByProp('title');\n readonly trackBySectionTitle = trackByProp('sectionTitle');\n\n readonly #window = inject(WINDOW);\n\n constructor(\n private nativeApplication: NativeAppService,\n private vanillaNavigation: NavigationService,\n ) {}\n\n ngOnInit(): void {\n this.isGameListHidden =\n (!this.message.mobileGameList || this.message.mobileGameList.length === 0) &&\n (!this.message.mobileAllList || this.message.mobileAllList.length === 0) &&\n !this.message.isAllMobileGames;\n }\n\n isBonusApplied(): boolean {\n return this.message.sourceStatus === OfferStatus.OFFER_CLAIMED && !this.message.isExpired;\n }\n\n goTo(linkUrl: string): void {\n if (linkUrl) {\n if (this.nativeApplication.isNativeApp) {\n this.#window.location.href = linkUrl;\n } else {\n this.vanillaNavigation.goTo(linkUrl, { forceReload: true });\n }\n }\n }\n\n getSectionTitle(sectionTitle: string): string {\n return this.contentMessages['GameSection.' + sectionTitle.replace(' ', '')] || sectionTitle;\n }\n}\n","\n\n@if (message) {\n
\n
\n @if (message.content.detailImage) {\n \n @if (renderImageLink()) {\n \n \n \n }\n @if (!renderImageLink()) {\n \n }\n \n }\n @if (message.content.headerTermsAndConditionsInbox) {\n
\n }\n
\n
\n \n @if (message.isExpired) {\n \n }\n
\n

\n \n @if (!showJumioTriggerButton && showCallToActionButton) {\n \n }\n @if (showJumioTriggerButton) {\n
\n \n
\n }\n @if (showTermsAndConditions) {\n
\n
\n

\n @if (isTacExpanded) {\n \n } @else {\n \n }\n
\n
\n
\n }\n \n \n
\n}\n\n @if (message?.content; as content) {\n \n }\n\n","import { CommonModule } from '@angular/common';\nimport { Component, EventEmitter, Input, OnChanges, OnDestroy, Output, SimpleChanges } from '@angular/core';\n\nimport { InboxService, NavigationService, ProductHomepagesConfig, ViewTemplateForClient } from '@frontend/vanilla/core';\nimport { TrustAsHtmlPipe } from '@frontend/vanilla/shared/browser';\nimport { IconCustomComponent } from '@frontend/vanilla/shared/icons';\nimport { ImageComponent } from '@frontend/vanilla/shared/image';\nimport { KycStatus, KycStatusService } from '@frontend/vanilla/shared/kyc';\nimport { Subject, takeUntil } from 'rxjs';\n\nimport { InboxCtaActionComponent } from '../component-helpers/inbox-cta-action.component';\nimport { CtaAction, CtaActionType } from '../inbox.models';\nimport { CrappyInboxService } from '../services/crappy-inbox.service';\nimport { InboxTrackingService } from '../services/inbox-tracking.service';\nimport { InboxConfig } from '../services/inbox.client-config';\nimport { InboxMessage } from '../services/inbox.models';\nimport { InboxDesktopGameListComponent } from './inbox-desktop-game-list.component';\nimport { InboxMobileGameListComponent } from './inbox-mobile-game-list.component';\n\n@Component({\n standalone: true,\n imports: [\n CommonModule,\n TrustAsHtmlPipe,\n ImageComponent,\n InboxDesktopGameListComponent,\n InboxMobileGameListComponent,\n InboxCtaActionComponent,\n IconCustomComponent,\n ],\n selector: 'lh-inbox-details',\n templateUrl: 'inbox-details.component.html',\n})\nexport class InboxDetailsComponent implements OnChanges, OnDestroy {\n @Output() action: EventEmitter = new EventEmitter();\n @Input() message?: InboxMessage;\n @Input() content: ViewTemplateForClient;\n\n isTacExpanded: boolean;\n showJumioTriggerButton: boolean = false;\n showCallToActionButton: boolean = true;\n showTermsAndConditions: boolean = false;\n termsAndConditionsTitle: string;\n termsAndConditionsData: string | undefined;\n\n contentMessages: Record;\n\n private unsubscribe = new Subject();\n\n constructor(\n private crappyInboxService: CrappyInboxService,\n private vanillaNavigation: NavigationService,\n private inboxConfig: InboxConfig,\n private productHomepages: ProductHomepagesConfig,\n private kycStatusService: KycStatusService,\n private tracking: InboxTrackingService,\n private inboxService: InboxService,\n ) {}\n\n ngOnChanges(changes: SimpleChanges) {\n if (changes.message?.currentValue && this.message) {\n const showManualTnc = this.message.content.showManualTermsAndConditions && !this.message.content.isManualTermsAndConditionsEmpty;\n const showBonusTnc = this.message.isTnCTemplate && !!this.message.tnCData;\n this.showTermsAndConditions = showManualTnc || showBonusTnc;\n this.isTacExpanded = showManualTnc && this.message.content.expandTermsAndConditionsByDefault;\n this.termsAndConditionsTitle = this.content.messages\n ? showManualTnc\n ? this.content.messages['ManualTermsAndConditions']!\n : this.content.messages['TermsAndConditions']!\n : '';\n this.termsAndConditionsData = showManualTnc ? this.message.content.manualTermsAndConditions : this.message.tnCData;\n this.message.mobileGameList = this.message.mobileGameList ? this.message.mobileGameList : [];\n this.message.desktopGameList = this.message.desktopGameList ? this.message.desktopGameList : [];\n this.message.mobileAllList = this.message.mobileAllList ? this.message.mobileAllList : [];\n this.message.desktopAllList = this.message.desktopAllList ? this.message.desktopAllList : [];\n this.message.mobileChannelList = this.message.mobileChannelList ? this.message.mobileChannelList : [];\n this.message.desktopChannelList = this.message.desktopChannelList ? this.message.desktopChannelList : [];\n this.message.desktopSectionGamesPairs = this.message.desktopSectionGamesPairs ? this.message.desktopSectionGamesPairs : [];\n this.message.mobileSectionGamesPairs = this.message.mobileSectionGamesPairs ? this.message.mobileSectionGamesPairs : [];\n this.message.mobileGames = [];\n this.message.desktopGames = [];\n\n if (this.message.mobileGameList.length) {\n // get mobile games metadata\n this.message.mobileGameTitles = this.getGameTitlesUniqueByGameSections(\n this.message.mobileGameList,\n this.message.mobileSectionGamesPairs,\n );\n }\n\n if (this.message.desktopGameList.length) {\n this.message.desktopGameTitles = this.getGameTitlesUniqueByGameSections(\n this.message.desktopGameList,\n this.message.desktopSectionGamesPairs,\n );\n }\n\n this.message.desktopSectionGamesViewModel = this.convertGameSectionPairsToView(this.message.desktopSectionGamesPairs);\n this.message.mobileSectionGamesViewModel = this.convertGameSectionPairsToView(this.message.mobileSectionGamesPairs);\n\n if (this.inboxConfig.triggerJumioFromPlayerInbox && this.message.messageSource === 'COMPLIANCE') {\n this.showCallToActionButton = false;\n this.kycStatusService.kycStatus\n .pipe(takeUntil(this.unsubscribe))\n .subscribe((status: KycStatus | null) => (this.showJumioTriggerButton = !!status && !status.kycVerified));\n }\n\n this.tracking.trackMessageOpened(this.message);\n }\n\n if (changes.content) {\n this.contentMessages = this.content.messages ?? {};\n }\n }\n\n ngOnDestroy() {\n this.unsubscribe.next();\n this.unsubscribe.complete();\n }\n\n triggerJumio() {\n this.tracking.trackKycVerifyClicked().then(() => {\n this.inboxService.close();\n this.vanillaNavigation.goTo(this.productHomepages.portal + this.inboxConfig.jumioKycUrl);\n });\n }\n\n inboxCtaActions(action: CtaAction) {\n switch (action.type) {\n case CtaActionType.HideInbox:\n this.action.emit(action);\n break;\n case CtaActionType.ClaimOfferSuccess:\n this.claimOfferSuccess(action.value);\n }\n }\n\n renderImageLink(): boolean {\n if (!this.message?.content.detailImage.detailImageLink) {\n return false;\n }\n\n return !this.message.content.detailImage.detailImageLink.includes('inbox://cta');\n }\n\n getDetailImageLink(message: InboxMessage): string {\n const detailImage = message.content.detailImage;\n\n if (this.crappyInboxService.isDepositBonusLink(detailImage.detailImageLink, detailImage.detailImageAttrs)) {\n return this.crappyInboxService.getDepositBonusLink(detailImage.detailImageLink, detailImage.detailImageAttrs);\n }\n\n return detailImage.detailImageLink;\n }\n\n toggleTacExpanded() {\n if (this.message) {\n this.isTacExpanded = !this.isTacExpanded;\n this.message.isTnCViewed = true; // added for tracking only\n }\n }\n\n private getSectionTitle(sectionTitle: string): string {\n return this.content.messages!['GameSection.' + sectionTitle.replace(' ', '')] || sectionTitle;\n }\n\n private claimOfferSuccess(response: any) {\n if (response.status && this.message) {\n // update message status\n this.message.sourceStatus = response.status;\n }\n }\n\n private getGameTitlesUniqueByGameSections(gameList: any, sectionGamesPairs: any): string {\n const gamesTitlesFromSectionsStr = this.selectMany(sectionGamesPairs)\n .map((m: any) => {\n return this.getUniqueStr(m.title);\n })\n .join(',');\n\n return gameList\n .filter((m: any) => {\n return gamesTitlesFromSectionsStr.indexOf(this.getUniqueStr(m.title)) === -1;\n })\n .map((m: any) => {\n return m.title;\n })\n .join(', ');\n }\n\n private selectMany(source: any[]): any[] {\n let res: any[] = [];\n\n for (let i = 0; i < source.length; i++) {\n const current = source[i];\n const currentList = current.value;\n\n if (currentList && currentList.length) {\n res = res.concat(currentList);\n }\n }\n\n return res;\n }\n\n private getUniqueStr(str: string): string {\n return '__|' + str + '|__';\n }\n\n private convertGameSectionPairsToView(gameSectionPairs: any): any {\n return gameSectionPairs.map((current: any) => {\n return {\n title: this.getSectionTitle(current.key),\n value: current.value\n .map((currentVal: any) => {\n return currentVal.title;\n })\n .join(', '),\n };\n });\n }\n}\n","
\n \n @if (!wait && messages.length === 0) {\n
\n
\n
    \n
  • \n \n +.\n
  • \n
\n
\n
\n }\n\n \n\n @for (msg of messagesDisplayed; track trackByOfferId($index, msg)) {\n
\n \n
\n
\n \n
\n
\n @if (msg.content.shortImage; as src) {\n \n }\n
\n
\n
\n @if (msg.isExpired) {\n \n }\n
\n @if (msg.content.snippetDescription) {\n
\n }\n
\n
\n
\n
\n }\n\n","import { CommonModule } from '@angular/common';\nimport { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { DsCheckbox } from '@frontend/ui/checkbox';\nimport { MessageScope, ViewTemplateForClient, trackByProp } from '@frontend/vanilla/core';\nimport { MessagePanelComponent } from '@frontend/vanilla/features/message-panel';\nimport { TrustAsHtmlPipe } from '@frontend/vanilla/shared/browser';\nimport { ImageComponent } from '@frontend/vanilla/shared/image';\n\nimport { InboxAction, InboxMessageActionType } from '../inbox.models';\nimport { InboxMessage, MessageStatus } from '../services/inbox.models';\n\n@Component({\n standalone: true,\n imports: [CommonModule, FormsModule, TrustAsHtmlPipe, MessagePanelComponent, ImageComponent, DsCheckbox],\n selector: 'lh-inbox-list',\n templateUrl: 'inbox-list.component.html',\n})\nexport class InboxListComponent implements OnChanges {\n @Output() action = new EventEmitter();\n @Input() messages: InboxMessage[];\n @Input() content: ViewTemplateForClient;\n @Input() selectedMessage?: InboxMessage;\n\n readonly MessageStatus = MessageStatus;\n readonly MessageScope = MessageScope;\n readonly trackByOfferId = trackByProp('offerId');\n\n wait: boolean;\n isDetailsVisible: boolean;\n messagesDisplayed: InboxMessage[];\n\n ngOnChanges(changes: SimpleChanges) {\n if (changes.messages?.currentValue) {\n this.messagesDisplayed = this.messages;\n }\n }\n\n selectMessage() {\n this.action.emit({\n type: InboxMessageActionType.MessageSelected,\n });\n }\n\n open(message: InboxMessage) {\n this.action.emit({\n type: InboxMessageActionType.MessageClicked,\n value: message,\n });\n }\n}\n","import { CommonModule } from '@angular/common';\nimport { Component, EventEmitter, Input, Output } from '@angular/core';\n\nimport { NativeAppService, NativeEventType, ViewTemplateForClient } from '@frontend/vanilla/core';\nimport { TrustAsHtmlPipe } from '@frontend/vanilla/shared/browser';\nimport { IconCustomComponent } from '@frontend/vanilla/shared/icons';\n\n@Component({\n standalone: true,\n imports: [CommonModule, TrustAsHtmlPipe, IconCustomComponent],\n selector: 'lh-inbox-notification-banner',\n templateUrl: 'inbox-notification-banner.html',\n})\nexport class InboxNotificationBannerComponent {\n @Output() onNotificationsTurnedOn: EventEmitter = new EventEmitter();\n @Input() content: ViewTemplateForClient;\n\n constructor(private nativeAppService: NativeAppService) {}\n\n turnOnNotifications() {\n this.onNotificationsTurnedOn.next();\n this.nativeAppService.sendToNative({\n eventName: NativeEventType.OSPrimerSelected,\n parameters: {\n displaySettingsPage: 'Yes',\n },\n });\n }\n\n close() {\n this.onNotificationsTurnedOn.next();\n }\n}\n","
\n
\n \n \n
\n \n
\n","import { Directive, EventEmitter, HostListener, Input, Output } from '@angular/core';\n\n@Directive({\n selector: '[lhOnBottomScroll]',\n standalone: true,\n})\nexport class OnBottomScrollDirective {\n @Output() lhOnBottomScroll: EventEmitter = new EventEmitter();\n @Input() elementsNumberBottomPadding: number;\n private scrollToHeight: number = 0;\n\n @HostListener('scroll', ['$event'])\n hostScrolled(event: Event) {\n const element = event.target as HTMLElement;\n this.scrollToHeight = this.getScrollToHeight(this.scrollToHeight, element.offsetHeight);\n if (element.scrollTop === element.scrollHeight - element.offsetHeight) {\n this.lhOnBottomScroll.emit();\n }\n }\n\n private getScrollToHeight(scrollToHeight: number, offsetHeight: number) {\n if (!scrollToHeight) {\n return this.elementsNumberBottomPadding ? offsetHeight * this.elementsNumberBottomPadding : offsetHeight;\n }\n return scrollToHeight;\n }\n}\n","@if (content) {\n
\n \n \n @if (nativeApplication.isNative && showNotificationBanner) {\n \n }\n @if (isLoading || messages.length > 0) {\n
\n @if (listVisible) {\n
\n
\n \n
\n @if (footerVisible) {\n
\n
\n
\n \n ALL\n \n
\n
\n \n
\n }\n
\n }\n @if (detailsVisible) {\n
\n \n
\n }\n
\n }\n @if (messages.length === 0 && !isLoading) {\n
\n
\n
\n

\n \n \n \n \n \n \n \n \n
\n
\n
\n }\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n}\n","import { CommonModule } from '@angular/common';\nimport { Component, Input, OnDestroy, OnInit, ViewEncapsulation, inject } from '@angular/core';\nimport { FormsModule } from '@angular/forms';\n\nimport { DsCheckbox } from '@frontend/ui/checkbox';\nimport {\n InboxService,\n MediaQueryService,\n MessageLifetime,\n MessageQueueService,\n MessageScope,\n MessageType,\n NativeAppService,\n NativeEvent,\n NativeEventType,\n Page,\n TimerService,\n UtilsService,\n ViewTemplateForClient,\n WINDOW,\n} from '@frontend/vanilla/core';\nimport { LhHeaderBarComponent } from '@frontend/vanilla/features/header-bar';\nimport { TrustAsHtmlPipe } from '@frontend/vanilla/shared/browser';\nimport { Subject } from 'rxjs';\nimport { filter, first, takeUntil } from 'rxjs/operators';\n\nimport { CtaAction, CtaActionType, InboxAction, InboxMessageActionType, InboxMessageUpdateStatusResponse } from '../inbox.models';\nimport { CrappyInboxService } from '../services/crappy-inbox.service';\nimport { InboxCountService } from '../services/inbox-count.service';\nimport { InboxDataService } from '../services/inbox-data.service';\nimport { InboxTrackingService } from '../services/inbox-tracking.service';\nimport { InboxConfig } from '../services/inbox.client-config';\nimport { InboxMessage, MessageStatus, StatusType } from '../services/inbox.models';\nimport { InboxDetailsComponent } from './inbox-details.component';\nimport { InboxListComponent } from './inbox-list.component';\nimport { InboxNotificationBannerComponent } from './inbox-notification-banner.component';\nimport { OnBottomScrollDirective } from './on-bottom-scroll.directive';\n\n@Component({\n standalone: true,\n imports: [\n CommonModule,\n FormsModule,\n TrustAsHtmlPipe,\n LhHeaderBarComponent,\n InboxListComponent,\n InboxDetailsComponent,\n OnBottomScrollDirective,\n InboxNotificationBannerComponent,\n DsCheckbox,\n ],\n selector: 'lh-inbox',\n templateUrl: 'inbox.component.html',\n styleUrls: ['../../../../../../themepark/themes/whitelabel/components/inbox/styles.scss'],\n encapsulation: ViewEncapsulation.None,\n})\nexport class InboxComponent implements OnInit, OnDestroy {\n @Input() backButton: boolean;\n\n messages: InboxMessage[];\n selectedMessage: InboxMessage | undefined;\n content: ViewTemplateForClient;\n wait: boolean;\n isAllCheckBoxesSelected: boolean;\n deletedMessagesButton: string;\n isDetailsVisible: boolean = false;\n loadBeforeItems: number;\n isLoading: boolean = false;\n showNotificationBanner: boolean = false;\n\n private pageIndex: number;\n private pageSize: number;\n // Needed to do this work around because the paging in server side is not done correctly\n private allNewMessagesLoaded = false;\n private isBackButtonVisible: boolean;\n private unsubscribe = new Subject();\n private timeoutId: NodeJS.Timeout;\n readonly #window = inject(WINDOW);\n\n constructor(\n public nativeApplication: NativeAppService,\n private crappyInboxService: CrappyInboxService,\n private messageQueue: MessageQueueService,\n private inboxConfig: InboxConfig,\n private timerService: TimerService,\n private utils: UtilsService,\n private media: MediaQueryService,\n private tracking: InboxTrackingService,\n private inboxCountService: InboxCountService,\n private inboxDataService: InboxDataService,\n private inboxService: InboxService,\n private page: Page,\n ) {}\n\n get footerVisible(): boolean {\n if (!this.messages) {\n return false;\n }\n\n if (this.media.isActive('xs') && this.isDetailsVisible) {\n return false;\n }\n\n return !this.wait && this.getSelectedMessages().length > 0;\n }\n\n get showBackButton(): boolean {\n return this.isBackButtonVisible || (this.media.isActive('xs') && this.isDetailsVisible);\n }\n\n get detailsVisible(): boolean {\n return (this.media.isActive('xs') && this.isDetailsVisible) || !this.media.isActive('xs');\n }\n\n get listVisible(): boolean {\n return (this.media.isActive('xs') && !this.isDetailsVisible) || !this.media.isActive('xs');\n }\n\n ngOnInit() {\n this.inboxConfig.whenReady.pipe(first()).subscribe(() => {\n this.loadBeforeItems = this.inboxConfig.lazyLoading.loadBeforeItems;\n this.pageSize = this.getPageSize();\n\n this.crappyInboxService.messages.pipe(takeUntil(this.unsubscribe)).subscribe((message: InboxMessage[]) => {\n this.messagesLoaded(message);\n this.wait = false;\n this.isLoading = false;\n });\n\n this.initMessagesList();\n this.isBackButtonVisible = this.backButton;\n this.inboxDataService\n .getContent()\n .pipe(first())\n .subscribe((template: ViewTemplateForClient) => (this.content = template));\n this.wait = true;\n\n if (this.nativeApplication.isNativeApp) {\n this.messageQueue.clear();\n }\n\n if (this.nativeApplication.isNative) {\n this.nativeApplication.eventsFromNative\n .pipe(filter((e: NativeEvent) => e.eventName === NativeEventType.enableOSPrimer))\n .subscribe((e: NativeEvent) => {\n this.showNotificationBanner = e.parameters?.displayOSPrimer?.toLowerCase() === 'yes' || false;\n });\n }\n\n this.media\n .observe()\n .pipe(takeUntil(this.unsubscribe))\n .subscribe(() => {\n if (!this.media.isActive('xs')) {\n this.selectFirstInboxMessage();\n }\n });\n\n this.inboxService.setState({ isOpen: true });\n });\n }\n\n ngOnDestroy() {\n this.unsubscribe.next();\n this.unsubscribe.complete();\n this.crappyInboxService.resetMessages();\n this.timerService.clearTimeout(this.timeoutId);\n }\n\n hide() {\n this.tracking.trackInboxClosed(this.selectedMessage ?? new InboxMessage());\n this.nativeApplication.sendToNative({\n eventName: NativeEventType.INBOXCLOSED,\n parameters: { product: this.page.product },\n });\n this.hideInbox(false);\n }\n\n back() {\n if (this.isDetailsVisible && this.media.isActive('xs')) {\n this.closeMessageDetails();\n } else if (this.isBackButtonVisible) {\n this.hideInbox(true);\n }\n }\n\n inboxListCallback(action: InboxAction) {\n switch (action.type) {\n case InboxMessageActionType.MessageSelected:\n this.clearMessageQueue();\n this.setDeleteButtonText();\n this.updateIsAllCheckBoxesSelected();\n break;\n case InboxMessageActionType.MessagesRemoved:\n this.closeMessageDetails();\n if (!this.crappyInboxService.isAllMessagesLoaded) {\n this.pageIndex++;\n this.loadMessages();\n }\n this.wait = false;\n break;\n case InboxMessageActionType.MessageClicked:\n this.isDetailsVisible = true;\n this.clearMessageQueue();\n this.setSelectedMessage(action.value);\n break;\n case InboxMessageActionType.LoadMoreMessages:\n this.loadMoreMessages();\n break;\n }\n }\n\n inboxDetailsActions(action: CtaAction) {\n switch (action.type) {\n case CtaActionType.HideInbox:\n this.hide();\n break;\n }\n }\n\n removeList() {\n this.wait = true;\n const ids = this.getSelectedMessages().map((item: InboxMessage) => item.id);\n this.removeMessages(ids);\n }\n\n toggleAll() {\n this.messages.forEach((message: InboxMessage) => {\n message.selected = this.isAllCheckBoxesSelected;\n });\n this.setDeleteButtonText();\n }\n\n notificationsTurnedOn() {\n this.showNotificationBanner = false;\n }\n\n loadMoreMessages() {\n if (!this.isLoading && !this.crappyInboxService.isAllMessagesLoaded) {\n this.pageIndex++;\n this.loadMessages();\n }\n }\n\n private getPageSize(): number {\n return Math.ceil(this.getMinMessagesForScreen() / this.inboxConfig.lazyLoading.pageSize) * this.inboxConfig.lazyLoading.pageSize;\n }\n\n private getMinMessagesForScreen(): number {\n const minHeightOfOneMessage = 40;\n\n return this.#window.screen.height / minHeightOfOneMessage;\n }\n\n private messagesLoaded(msgs: InboxMessage[]) {\n this.messages = msgs;\n\n if (!this.media.isActive('xs') && this.messages?.length) {\n this.selectedMessage = this.messages[0];\n }\n\n if (!this.allNewMessagesLoaded) {\n this.setIfAllNewMessagesLoaded();\n }\n\n this.handleNewMessages();\n }\n\n private selectFirstInboxMessage() {\n if (!this.selectedMessage && this.messages?.length) {\n this.setSelectedMessage(this.messages[0]);\n }\n }\n\n private setSelectedMessage(message?: InboxMessage) {\n this.selectedMessage = message;\n\n if (this.selectedMessage && (this.selectedMessage.isNew || this.selectedMessage.messageStatus === MessageStatus.unread)) {\n this.crappyInboxService\n .updateStatus([this.selectedMessage.id], MessageStatus.read)\n .subscribe((response: InboxMessageUpdateStatusResponse) => {\n if (response.isUpdated && this.selectedMessage) {\n this.selectedMessage.messageStatus = MessageStatus.read;\n }\n });\n }\n }\n\n private initMessagesList() {\n this.pageIndex = 0;\n this.allNewMessagesLoaded = false;\n this.messages = [];\n this.wait = true;\n this.loadMessages();\n }\n\n private loadMessages() {\n this.isLoading = true;\n this.clearMessageQueue();\n this.crappyInboxService.getMessages(this.pageIndex, this.pageSize, this.allNewMessagesLoaded ? StatusType.all : StatusType.new).subscribe();\n }\n\n private handleNewMessages() {\n const newMessages = this.messages.filter((el: InboxMessage) => el.isNew);\n\n if (newMessages.length > 0) {\n this.updateNewMessagesStatusToUnread(newMessages);\n }\n }\n\n private setIfAllNewMessagesLoaded() {\n const newMessages = this.messages.filter((el: InboxMessage) => !el.isNew);\n\n if (newMessages.length > 0) {\n this.allNewMessagesLoaded = true;\n //reset pageindex because now it's a new index for not new messages (workaround for backend responses) :(\n this.pageIndex = 0;\n }\n }\n\n private updateNewMessagesStatusToUnread(newMessages: InboxMessage[]) {\n const newMessagesIds = newMessages.map((m: InboxMessage) => m.id);\n\n this.timeoutId = this.timerService.setTimeoutOutsideAngularZone(() => {\n this.crappyInboxService.updateStatus(newMessagesIds, MessageStatus.unread).subscribe((response: InboxMessageUpdateStatusResponse) => {\n if (response.isUpdated) {\n newMessages.forEach((e: InboxMessage) => {\n if (e.messageStatus === MessageStatus.new) {\n e.messageStatus = MessageStatus.unread;\n }\n e.isNew = false;\n });\n\n this.inboxCountService.refresh();\n\n if (this.selectedMessage) {\n this.setSelectedMessage(this.selectedMessage);\n }\n }\n });\n }, this.inboxConfig.readTime);\n }\n\n private closeMessageDetails() {\n this.isDetailsVisible = false;\n this.selectedMessage = undefined;\n }\n\n private setDeleteButtonText() {\n if (this.content.messages?.DeleteButton) {\n this.deletedMessagesButton = this.utils.format(this.content.messages.DeleteButton || '', this.getSelectedMessages().length);\n }\n }\n\n private updateIsAllCheckBoxesSelected() {\n this.isAllCheckBoxesSelected = this.getSelectedMessages().length === this.messages.length;\n }\n\n private getSelectedMessages(): InboxMessage[] {\n return this.messages.filter((m: InboxMessage) => m.selected);\n }\n\n private removeMessages(ids: string[]) {\n this.clearMessageQueue();\n\n this.crappyInboxService.remove(ids).subscribe((response) => {\n if (response?.isUpdated) {\n this.messagesRemovedSuccess(ids);\n }\n });\n }\n\n private messagesRemovedSuccess(ids: string[]) {\n this.tracking.trackMessageDeleted(ids.length);\n\n const showMessage = ids.length !== this.messages.length;\n\n if (showMessage) {\n this.showSuccessMessageRemoved(ids);\n }\n\n this.closeMessageDetails();\n this.wait = false;\n this.updateIsAllCheckBoxesSelected();\n\n if (!this.crappyInboxService.isAllMessagesLoaded) {\n this.pageIndex++;\n this.loadMessages();\n }\n }\n\n private showSuccessMessageRemoved(ids: string[]) {\n if (this.content.messages?.DeleteSuccessOneMessage) {\n const deletedMessagesText =\n ids.length === 1\n ? this.content.messages.DeleteSuccessOneMessage\n : this.utils.format(this.content.messages.DeleteSuccessMessage || '', ids.length);\n\n this.messageQueue.add(deletedMessagesText, MessageType.Success, MessageLifetime.Single, MessageScope.Inbox);\n }\n\n this.timeoutId = this.timerService.setTimeout(() => this.clearMessageQueue(), 3000);\n }\n\n private clearMessageQueue() {\n this.messageQueue.clear({ scope: MessageScope.Inbox, clearPersistent: false });\n }\n\n private hideInbox(back: boolean) {\n this.clearMessageQueue();\n this.inboxService.close(back ? 'back' : 'close');\n }\n}\n","import { OverlayRef } from '@angular/cdk/overlay';\nimport { Component, Inject, InjectionToken, OnDestroy, OnInit } from '@angular/core';\n\nimport { NavigationService } from '@frontend/vanilla/core';\nimport { Subscription } from 'rxjs';\n\nimport { InboxComponent } from './inbox.component';\n\nexport interface InboxData {\n showBackButton: boolean;\n}\n\nexport const INBOX_DATA = new InjectionToken('vn-inbox-data');\n@Component({\n standalone: true,\n imports: [InboxComponent],\n selector: 'vn-inbox-overlay',\n templateUrl: 'inbox-overlay.html',\n})\nexport class InboxOverlayComponent implements OnInit, OnDestroy {\n showBackButton: boolean;\n private locationChangeSubscription: Subscription;\n constructor(\n @Inject(INBOX_DATA) private inboxData: InboxData,\n private overlayRef: OverlayRef,\n private navigationService: NavigationService,\n ) {}\n\n ngOnInit() {\n this.showBackButton = this.inboxData.showBackButton;\n this.locationChangeSubscription = this.navigationService.locationChange.subscribe(() => {\n this.overlayRef.detach();\n });\n }\n ngOnDestroy(): void {\n if (this.locationChangeSubscription) {\n this.locationChangeSubscription.unsubscribe();\n }\n }\n}\n","\n","import { OverlayRef } from '@angular/cdk/overlay';\nimport { ComponentPortal } from '@angular/cdk/portal';\nimport { Injectable, Injector } from '@angular/core';\n\nimport { DateTimeService, EventsService, InboxOpenOptions, InboxState, InboxStateChangeSource, VanillaEventNames } from '@frontend/vanilla/core';\nimport { HeaderBarService } from '@frontend/vanilla/features/header-bar';\nimport { OverlayFactory } from '@frontend/vanilla/shared/overlay-factory';\nimport { BehaviorSubject, Observable, ReplaySubject, combineLatest } from 'rxjs';\nimport { first, tap } from 'rxjs/operators';\n\nimport { INBOX_DATA, InboxData, InboxOverlayComponent } from '../components/inbox-overlay.component';\nimport { InboxCountService } from './inbox-count.service';\nimport { InboxDataService } from './inbox-data.service';\nimport { InboxTrackingService } from './inbox-tracking.service';\nimport { InboxConfig } from './inbox.client-config';\n\n@Injectable({ providedIn: 'root' })\nexport class InboxService {\n private currentCount: number = 0;\n private currentRef: OverlayRef | null;\n private currentOpenTime: number;\n private closeChangeSource: InboxStateChangeSource | undefined;\n private stateStream = new BehaviorSubject({ isOpen: false });\n private countStream = new ReplaySubject(1);\n\n constructor(\n private inboxTrackingService: InboxTrackingService,\n private inboxDataService: InboxDataService,\n private overlay: OverlayFactory,\n private injector: Injector,\n private inboxConfig: InboxConfig,\n private dateTimeService: DateTimeService,\n private inboxCounterService: InboxCountService,\n private headerBarService: HeaderBarService,\n private eventsService: EventsService,\n ) {\n this.inboxCounterService.count.pipe(tap((c) => (this.currentCount = c))).subscribe(this.countStream);\n }\n\n get state(): Observable {\n return this.stateStream;\n }\n\n get count(): Observable {\n return this.countStream;\n }\n\n get isEnabled(): boolean {\n return true;\n }\n\n get panelClass(): string {\n return 'vn-inbox';\n }\n\n getCount(): number {\n return this.currentCount;\n }\n\n setState(state: InboxState) {\n this.stateStream.next(state);\n }\n\n open({ trackingEventName, showBackButton }: InboxOpenOptions) {\n if (this.currentRef) {\n return;\n }\n\n this.eventsService.raise({ eventName: VanillaEventNames.InboxOpen });\n\n this.count.pipe(first()).subscribe((c: number) => {\n this.inboxTrackingService.trackInboxOpened({\n eventName: trackingEventName,\n newMessagesCount: c,\n });\n });\n\n const overlayRef = this.overlay.create({\n panelClass: this.panelClass,\n });\n\n overlayRef.backdropClick().subscribe(() => this.currentRef?.detach());\n\n overlayRef.attachments().subscribe(() => {\n this.currentOpenTime = this.dateTimeService.now().getTime();\n });\n\n overlayRef.detachments().subscribe(() => {\n this.overlay.dispose(this.currentRef);\n this.currentRef = null;\n // trigger isOpen: false when inbox opened as overlay\n this.changeState();\n\n if (this.dateTimeService.now().getTime() - this.currentOpenTime <= 1000) {\n this.inboxTrackingService.trackInboxClosedEarly();\n }\n });\n\n combineLatest([this.inboxConfig.whenReady, this.inboxDataService.getContent()])\n .pipe(first())\n .subscribe(() => {\n const data: InboxData = { showBackButton };\n const portal = new ComponentPortal(\n InboxOverlayComponent,\n null,\n Injector.create({\n providers: [\n { provide: INBOX_DATA, useValue: data },\n { provide: OverlayRef, useValue: overlayRef },\n ],\n parent: this.injector,\n }),\n );\n overlayRef.attach(portal);\n });\n\n this.currentRef = overlayRef;\n }\n\n close(source?: InboxStateChangeSource) {\n this.eventsService.raise({ eventName: VanillaEventNames.InboxClose });\n if (!this.currentRef && this.overlay.overlayRefs.has(this.panelClass)) {\n const overlayRef = this.overlay.overlayRefs?.get(this.panelClass);\n this.currentRef = overlayRef ? overlayRef : null;\n }\n\n if (this.currentRef) {\n this.closeChangeSource = source;\n this.currentRef.detach();\n } else {\n // trigger isOpen: false when inbox opened as route\n this.changeState();\n this.headerBarService.back();\n }\n }\n\n private changeState() {\n const state: InboxState = { isOpen: false };\n\n if (this.closeChangeSource) {\n state.changeSource = this.closeChangeSource;\n }\n\n this.stateStream.next(state);\n }\n}\n","import { Inject, Injectable } from '@angular/core';\n\nimport {\n InboxService as CoreInboxService,\n InboxState,\n MENU_COUNTERS_PROVIDER,\n MenuAction,\n MenuActionsService,\n MenuCountersProvider,\n MenuCountersService,\n NativeAppService,\n NativeEventType,\n NavigationService,\n OnFeatureInit,\n} from '@frontend/vanilla/core';\nimport { AccountMenuDataService } from '@frontend/vanilla/shared/account-menu';\nimport { pairwise } from 'rxjs/operators';\n\nimport { InboxService } from './services/inbox.service';\n\n@Injectable()\nexport class InboxBootstrapService implements OnFeatureInit {\n constructor(\n private menuActionsService: MenuActionsService,\n private accountMenuDataService: AccountMenuDataService,\n private menuCountersService: MenuCountersService,\n private inboxService: InboxService,\n private nativeAppService: NativeAppService,\n private accountMenuService: AccountMenuDataService,\n private navigationService: NavigationService,\n private coreInboxService: CoreInboxService,\n @Inject(MENU_COUNTERS_PROVIDER) private menuCountersProviders: MenuCountersProvider[],\n ) {}\n\n onFeatureInit() {\n this.coreInboxService.set(this.inboxService);\n this.menuCountersService.registerProviders(this.menuCountersProviders);\n this.menuActionsService.register(MenuAction.GOTO_INBOX, () => {\n this.inboxService.open({\n showBackButton: this.accountMenuDataService.routerMode,\n trackingEventName: 'Event.inbox.menu_action',\n });\n });\n\n this.inboxService.count.subscribe((count: number) => {\n this.menuCountersService.update();\n this.nativeAppService.sendToNative({\n eventName: NativeEventType.NotificationCount,\n parameters: {\n inbox: count,\n },\n });\n });\n\n this.inboxService.state.pipe(pairwise()).subscribe((params: [InboxState, InboxState]) => {\n this.sendNativeAppEvent(params[1].isOpen);\n\n if (!params[1].isOpen && params[1].changeSource !== 'back') {\n // if closed after it was open in router mode account menu, close account menu as well\n if (this.accountMenuService.routerModeReturnUrl) {\n this.navigationService.goTo(this.accountMenuService.routerModeReturnUrl, { isBackNavigation: true });\n }\n }\n });\n }\n\n private sendNativeAppEvent(visible: boolean) {\n this.nativeAppService.sendToNative({\n eventName: NativeEventType.SENSITIVEPAGE,\n parameters: {\n id: 'inbox',\n type: 'overlay',\n action: visible ? 'open' : 'close',\n isSensitiveForSliderGames: visible,\n isSensitiveForPushNotifications: visible,\n },\n });\n }\n}\n","import { Injectable } from '@angular/core';\n\nimport { MenuCounters, MenuCountersProvider, MenuSection } from '@frontend/vanilla/core';\n\nimport { InboxService } from './services/inbox.service';\n\n@Injectable({ providedIn: 'root' })\nexport class InboxMenuCountersProvider implements MenuCountersProvider {\n get order() {\n return 10;\n }\n\n constructor(private inboxService: InboxService) {}\n\n setCounters(counters: MenuCounters): void {\n const value = this.inboxService.getCount() || null;\n\n counters.set(MenuSection.Menu, 'myinbox', value);\n counters.set(MenuSection.Header, 'inbox', value);\n }\n}\n","import { MENU_COUNTERS_PROVIDER, runOnFeatureInit } from '@frontend/vanilla/core';\n\nimport { InboxBootstrapService } from './inbox-bootstrap.service';\nimport { InboxMenuCountersProvider } from './inbox-menu-counters-provider';\n\nexport function provide() {\n return [{ provide: MENU_COUNTERS_PROVIDER, useClass: InboxMenuCountersProvider, multi: true }, runOnFeatureInit(InboxBootstrapService)];\n}\n","import { Component, OnInit } from '@angular/core';\n\nimport { InboxService as CoreInboxService } from '@frontend/vanilla/core';\n\nimport { InboxService } from '../services/inbox.service';\nimport { InboxComponent } from './inbox.component';\n\n@Component({\n standalone: true,\n imports: [InboxComponent],\n selector: 'vn-inbox-view',\n templateUrl: 'inbox-view.html',\n})\nexport class InboxViewComponent implements OnInit {\n constructor(\n private coreInboxService: CoreInboxService,\n private inboxService: InboxService,\n ) {}\n ngOnInit() {\n this.coreInboxService.set(this.inboxService);\n }\n}\n","\n","import { Routes } from '@angular/router';\n\nimport { InboxViewComponent } from './components/inbox-view.component';\n\nexport const ROUTES: Routes = [\n {\n path: '',\n component: InboxViewComponent,\n },\n];\n","import { Injectable, inject } from '@angular/core';\n\nimport { CookieName, CookieService, PERMANENT_COOKIE_EXPIRATION, WINDOW } from '@frontend/vanilla/core';\n\nconst DisabledCookieValue = '0';\nconst EnabledCookieValueOldDesktop = '1';\nconst EnabledCookieValue = '2';\n\n/**\n * @whatItDoes Allows toggling of dark mode and check if feature is enabled.\n *\n * @stable\n */\n@Injectable({\n providedIn: 'root',\n})\nexport class DarkModeService {\n private _isEnabled = this.getIsEnabled();\n\n get isEnabled(): boolean {\n return this._isEnabled;\n }\n readonly #window = inject(WINDOW);\n\n constructor(private cookieService: CookieService) {}\n\n toggle() {\n this.writeCookie(this._isEnabled ? DisabledCookieValue : EnabledCookieValue);\n this._isEnabled = this.getIsEnabled();\n this.#window.location.reload();\n }\n\n private writeCookie(value: string) {\n this.cookieService.putRaw(CookieName.DarkMode, value, { expires: PERMANENT_COOKIE_EXPIRATION });\n }\n\n private getIsEnabled(): boolean {\n const value = this.cookieService.get(CookieName.DarkMode);\n\n return value === EnabledCookieValue || value === EnabledCookieValueOldDesktop;\n }\n}\n","import { Component, Input } from '@angular/core';\n\nimport { TrustAsHtmlPipe } from '@frontend/vanilla/shared/browser';\n\n@Component({\n standalone: true,\n imports: [TrustAsHtmlPipe],\n selector: 'vn-copyright',\n template: '@if (copyright) {
}',\n})\nexport class CopyrightComponent {\n @Input() copyright?: string;\n}\n","import { Injectable } from '@angular/core';\n\nimport { ContentItem, TrackingService } from '@frontend/vanilla/core';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class ContentMessagesTrackingService {\n private trackedLoadEvents = new Set();\n\n constructor(private trackingService: TrackingService) {}\n\n trackMessageLoaded(message: ContentItem, scope: string) {\n const key = scope + message.name;\n\n if (this.trackedLoadEvents.has(key)) {\n return;\n }\n\n this.trackedLoadEvents.add(key);\n this.trackingService.trackContentItemEvent(message.parameters, 'tracking.LoadedEvent');\n }\n\n trackMessageClosed(message: ContentItem) {\n this.trackingService.trackContentItemEvent(message.parameters, 'tracking.ClosedEvent');\n }\n}\n","
\n @if (message.parameters?.messageIcon; as messageIcon) {\n \n }\n @if (message.parameters?.showCloseButton === 'true') {\n \n }\n \n
\n","import { CommonModule } from '@angular/common';\nimport { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';\n\nimport { ContentItem, HtmlNode, MenuActionOrigin, MenuActionsService, toBoolean } from '@frontend/vanilla/core';\nimport { PageMatrixComponent } from '@frontend/vanilla/features/content';\nimport { IconCustomComponent } from '@frontend/vanilla/shared/icons';\n\nimport { ContentMessagesTrackingService } from './content-messages-tracking.service';\n\nexport interface ContentMessageCloseEvent {\n message: ContentItem;\n showOnNextSession?: boolean;\n showOnNextLogin?: boolean;\n}\n\n@Component({\n standalone: true,\n imports: [CommonModule, PageMatrixComponent, IconCustomComponent],\n selector: 'vn-content-message',\n templateUrl: 'content-message.html',\n})\nexport class ContentMessageComponent implements OnInit, OnDestroy {\n @Input() message: ContentItem;\n @Input() scope: string;\n @Output() close: EventEmitter = new EventEmitter();\n iconClass: string;\n\n constructor(\n private htmlNode: HtmlNode,\n private contentMessagesTrackingService: ContentMessagesTrackingService,\n private menuActionService: MenuActionsService,\n ) {}\n\n ngOnInit() {\n this.setHtmlCssClass(true);\n this.contentMessagesTrackingService.trackMessageLoaded(this.message, this.scope);\n this.iconClass = this.message.parameters?.closeIcon || 'theme-close-i';\n }\n\n ngOnDestroy() {\n this.setHtmlCssClass(false);\n }\n\n onClick() {\n if (toBoolean(this.message.parameters?.closeOnMessageClick)) {\n this.close.next({ message: this.message });\n }\n }\n\n closeMessage(showOnNextSession: boolean = false, showOnNextLogin: boolean = false) {\n this.close.next({ message: this.message, showOnNextSession, showOnNextLogin });\n\n if (this.message.parameters?.closeAction) {\n this.menuActionService.invoke(this.message.parameters.closeAction, MenuActionOrigin.PageMatrix, [this.message.parameters.queryStringKey]);\n }\n }\n\n private setHtmlCssClass(add: boolean) {\n if (this.message.parameters?.htmlTagClass) {\n this.htmlNode.setCssClass(this.message.parameters.htmlTagClass, add);\n }\n }\n}\n","import { Component, ElementRef, HostListener, OnInit } from '@angular/core';\n\nimport { CustomElement, toBoolean } from '@frontend/vanilla/core';\n\nimport { ContentMessageComponent } from './content-message.component';\n\n/**\n * This is automatically tested in tests of ContentMessageComponent.\n */\n@Component({\n standalone: true,\n // eslint-disable-next-line @angular-eslint/component-selector\n selector: '.message-close',\n template: '',\n})\nexport class CloseMessageComponent implements OnInit {\n private showOnNextSession: boolean | undefined;\n private showOnNextLogin: boolean | undefined;\n\n constructor(\n private parent: ContentMessageComponent,\n private elementRef: ElementRef,\n ) {\n this.showOnNextSession = toBoolean(elementRef.nativeElement.getAttribute('data-show-on-next-session'));\n this.showOnNextLogin = toBoolean(elementRef.nativeElement.getAttribute('data-show-on-next-login'));\n }\n\n ngOnInit() {\n this.elementRef.nativeElement.innerHTML = (this.elementRef.nativeElement).originalHtmlString;\n }\n\n @HostListener('click')\n onClick() {\n this.parent.closeMessage(this.showOnNextSession, this.showOnNextLogin);\n }\n}\n","import { Injectable } from '@angular/core';\n\nimport { EmbeddableComponentsService, OnFeatureInit } from '@frontend/vanilla/core';\n\nimport { CloseMessageComponent } from './close-message.component';\n\n@Injectable()\nexport class ContentMessagesBootstrapService implements OnFeatureInit {\n constructor(private embeddableComponentsService: EmbeddableComponentsService) {}\n\n onFeatureInit() {\n this.embeddableComponentsService.registerEmbeddableComponent(CloseMessageComponent, 100);\n }\n}\n","import { runOnFeatureInit } from '@frontend/vanilla/core';\n\nimport { ContentMessagesBootstrapService } from './content-messages-bootstrap.service';\n\nexport function provide() {\n return [runOnFeatureInit(ContentMessagesBootstrapService)];\n}\n","import { Injectable } from '@angular/core';\n\nimport { ContentItem, CookieName, CookieService, SharedFeaturesApiService, toBoolean } from '@frontend/vanilla/core';\nimport { flatten, isNumber } from 'lodash-es';\nimport { Observable, of } from 'rxjs';\nimport { map } from 'rxjs/operators';\n\nimport { ContentMessagesTrackingService } from './content-messages-tracking.service';\n\n/**\n * @whatItDoes Wraps logic related to content messages esp. manipulation of respective cookies.\n *\n * @description This is meant for Vanilla internal use only!\n *\n * @stable\n */\n@Injectable({\n providedIn: 'root',\n})\nexport class ContentMessagesService {\n private messages: { [key: string]: Observable } = {};\n\n constructor(\n private cookieService: CookieService,\n private api: SharedFeaturesApiService,\n private contentMessagesTrackingService: ContentMessagesTrackingService,\n ) {}\n\n private static generateExpiryDate(days: string | number | null): Date | undefined {\n if (!days) {\n return;\n }\n\n const expireDate = new Date();\n expireDate.setDate(expireDate.getDate() + (isNumber(days) ? days : parseInt(days, 10)));\n\n return expireDate;\n }\n\n getMessages(\n path: string,\n closedCookieKey?: string,\n evaluateFullOnServer?: boolean,\n ): Observable {\n if (this.messages[path] || !path) {\n return this.messages[path] || of([]);\n }\n\n this.messages[path] = this.api\n .get('contentMessages', {\n path,\n closedCookieKey,\n evaluateFullOnServer,\n })\n .pipe(map((r) => r.messages));\n\n return this.messages[path] || of([]);\n }\n\n getClosedMessageNames(cookieKey: string): string[] {\n const cookieNames = [CookieName.ClsdP, CookieName.ClsdS, CookieName.ClsdL];\n\n return flatten(cookieNames.map((c: CookieName) => this.cookieService.getQueryCollection(c, cookieKey)));\n }\n\n markMessageAsClosed(message: ContentItem, cookieKey: string, options?: { showOnNextSession?: boolean; showOnNextLogin?: boolean }) {\n const parameters = message.parameters || {};\n const showOnNextSession = options?.showOnNextSession === undefined ? toBoolean(parameters.showOnNextSession) : options.showOnNextSession;\n const showOnNextLogin = options?.showOnNextLogin === undefined ? toBoolean(parameters.showOnNextLogin) : options.showOnNextLogin;\n let expires = ContentMessagesService.generateExpiryDate(showOnNextSession ? null : 365); // clsd-l is also persistent b/c delete on login\n\n if (toBoolean(parameters.writeOriginalCookie) !== false || !parameters.additionalCookieName) {\n const cookieName = showOnNextLogin ? CookieName.ClsdL : showOnNextSession ? CookieName.ClsdS : CookieName.ClsdP;\n this.cookieService.addToQueryCollection(cookieName, cookieKey, message.name, expires ? { expires } : {});\n }\n\n if (parameters.additionalCookieName) {\n const additionalCookieValue = parameters.additionalCookieValue !== undefined ? parameters.additionalCookieValue : 'true';\n expires =\n parameters.additionalCookieExpireDays !== undefined\n ? ContentMessagesService.generateExpiryDate(parameters.additionalCookieExpireDays)\n : expires;\n\n this.cookieService.putRaw(parameters.additionalCookieName, additionalCookieValue, expires ? { expires } : {});\n }\n\n this.contentMessagesTrackingService.trackMessageClosed(message);\n }\n}\n","@if (messagesToShow.length) {\n
\n @for (message of messagesToShow; track trackByName($index, message)) {\n \n }\n
\n}\n","import { OverlayRef } from '@angular/cdk/overlay';\nimport { CommonModule } from '@angular/common';\nimport { Component, Input, OnChanges, OnDestroy, OnInit, Optional, SimpleChanges } from '@angular/core';\n\nimport {\n ContentItem,\n HtmlNode,\n MenuActionOrigin,\n MenuActionsService,\n UserEvent,\n UserLoginEvent,\n UserService,\n toBoolean,\n trackByProp,\n} from '@frontend/vanilla/core';\nimport { filter, first } from 'rxjs/operators';\n\nimport { ContentMessageComponent } from './content-message.component';\nimport { ContentMessagesService } from './content-messages.service';\n\n/**\n * @whatItDoes Renders a collection of content messages\n *\n * @howToUse\n *\n * ```\n * \n * ```\n *\n * @description\n *\n * Renders a collection of content messages. Content for content messages can be loaded with `IContentMessageLoader` on the\n * server, then rendered on the client with client side page matrix.\n *\n * See http://moss.bwin.com/development/contentservices/The%20Brain/Content%20Messages.aspx for more information\n * about content messages.\n *\n * @stable\n */\n@Component({\n standalone: true,\n imports: [CommonModule, ContentMessageComponent],\n selector: 'vn-content-messages',\n templateUrl: 'content-messages.html',\n})\nexport class ContentMessagesComponent implements OnInit, OnChanges, OnDestroy {\n @Input() closedCookieKey: string;\n @Input() cssClassForHtmlNode: string;\n @Input() messages: ContentItem[];\n @Input() dynamicValues?: { Key: ''; Value: '' }[];\n\n messagesToShow: ContentItem[] = [];\n readonly trackByName = trackByProp('name');\n\n constructor(\n private messagesService: ContentMessagesService,\n private menuActionService: MenuActionsService,\n private htmlNode: HtmlNode,\n user: UserService,\n @Optional() private overlayRef: OverlayRef,\n ) {\n user.events\n .pipe(\n filter((e: UserEvent) => e instanceof UserLoginEvent),\n first(),\n )\n .subscribe(() => this.refreshMessagesToShow());\n }\n\n ngOnInit() {\n if (this.overlayRef) {\n this.overlayRef.backdropClick().subscribe(() => {\n for (const message of this.messagesToShow) {\n if (toBoolean(message.parameters?.writeCookieOnOverlayClick)) {\n this.messagesService.markMessageAsClosed(message, this.closedCookieKey);\n }\n if (message.parameters?.closeAction) {\n this.menuActionService.invoke(message.parameters.closeAction, MenuActionOrigin.PageMatrix, [\n message.parameters.queryStringKey,\n ]);\n }\n }\n\n this.messages = [];\n this.refreshMessagesToShow();\n this.overlayRef.dispose();\n });\n }\n }\n\n ngOnChanges(changes: SimpleChanges) {\n if (changes.messages || changes.closedCookieKey || changes.dynamicValues) {\n this.setDynamicContentValues();\n this.refreshMessagesToShow();\n }\n }\n\n ngOnDestroy() {\n this.toggleClassForHtmlNode(false);\n }\n\n closeMessage(message: ContentItem, showOnNextSession: boolean = false, showOnNextLogin: boolean = false) {\n const options = {\n showOnNextSession,\n showOnNextLogin,\n };\n\n if (Object.keys(options).length > 0) {\n this.messagesService.markMessageAsClosed(message, this.closedCookieKey, options);\n } else {\n this.messagesService.markMessageAsClosed(message, this.closedCookieKey);\n }\n\n this.messages = this.messages.filter((m: ContentItem) => m !== message);\n this.refreshMessagesToShow();\n\n if (this.overlayRef && !this.messagesToShow.length) {\n // Last message closed -> remove overlay if any\n this.overlayRef.dispose();\n }\n }\n\n private refreshMessagesToShow() {\n if (this.messages?.length && this.closedCookieKey) {\n const closedMsgNames = new Set(this.messagesService.getClosedMessageNames(this.closedCookieKey).map((v: string) => v.toLowerCase()));\n this.messagesToShow = this.messages.filter((m: ContentItem) => m && !closedMsgNames.has(m.name.toLowerCase()));\n } else {\n this.messagesToShow = [];\n }\n\n this.toggleClassForHtmlNode(this.messagesToShow.length > 0);\n }\n\n private toggleClassForHtmlNode(enabled: boolean) {\n this.htmlNode.setCssClass(this.cssClassForHtmlNode, enabled);\n }\n\n /**\n * @whatItDoes Goes through all visible message parameters and replace placeholders `{EXAMPLE_KEY}`\n * with a value with the same key from `dynamicValues` input.\n * The message will remain unchanged if placeholder does not mach the format\n * or value is not found in the `dynamicValues`.\n */\n private setDynamicContentValues() {\n if (!this.dynamicValues || !this.messages) {\n return;\n }\n\n this.messages.forEach((message: ContentItem) => {\n for (const param in message.parameters) {\n message.parameters[param] = message.parameters[param]!.replace(/{\\w+}/g, (placeholder: string) => {\n const key = placeholder.replace(/[{}]+/g, '');\n const value = this.dynamicValues?.find((value) => value.Key === key)?.Value;\n\n return value || placeholder;\n });\n }\n });\n }\n}\n","import { Injectable } from '@angular/core';\n\nimport {\n ClientConfigProductName,\n GenericListItem,\n LazyClientConfig,\n LazyClientConfigBase,\n LazyClientConfigService,\n MenuContentItem,\n} from '@frontend/vanilla/core';\n\n/**\n * @stable\n */\n@LazyClientConfig({ key: 'vnLabelSwitcher', product: ClientConfigProductName.SF })\n@Injectable({\n providedIn: 'root',\n deps: [LazyClientConfigService],\n useFactory: labelSwitcherConfigFactory,\n})\nexport class LabelSwitcherConfig extends LazyClientConfigBase {\n main: MenuContentItem;\n resources: GenericListItem;\n showChangeLabelToaster: string;\n isRestrictedAccessCondition: string;\n persistStayInState: boolean;\n}\n\nexport function labelSwitcherConfigFactory(service: LazyClientConfigService) {\n return service.get(LabelSwitcherConfig);\n}\n","import { Injectable } from '@angular/core';\n\nimport { TrackingService } from '@frontend/vanilla/core';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class LabelSwitcherTrackingService {\n constructor(private trackingService: TrackingService) {}\n\n trackConfirmationOverlay(actionEvent: string, positionEvent: string, eventDetails: string) {\n this.track('switching states confirmation popup', actionEvent, positionEvent, eventDetails, 'not applicable');\n }\n\n trackDropDown(actionEvent: string, positionEvent: string, eventDetails: string, urlClicked?: string) {\n this.track('Footer State Switcher', actionEvent, positionEvent, eventDetails, urlClicked);\n }\n\n private track(labelEvent: string, actionEvent: string, positionEvent: string, eventDetails: string, urlClicked?: string) {\n this.trackingService.triggerEvent('Event.Tracking', {\n 'component.CategoryEvent': 'multi state-switch',\n 'component.LabelEvent': labelEvent,\n 'component.ActionEvent': actionEvent,\n 'component.PositionEvent': positionEvent,\n 'component.LocationEvent': 'not applicable',\n 'component.EventDetails': eventDetails,\n 'component.URLClicked': urlClicked || 'not applicable',\n });\n }\n}\n","import { Injectable } from '@angular/core';\n\nimport {\n AuthService,\n CookieName,\n CookieService,\n DateTimeService,\n DslService,\n EventsService,\n GeolocationPosition,\n GeolocationService,\n Logger,\n MenuContentItem,\n NativeAppService,\n NativeEventType,\n NavigationService,\n PERMANENT_COOKIE_EXPIRATION,\n Page,\n SimpleEvent,\n ToastrQueueService,\n ToastrSchedule,\n ToastrType,\n UrlService,\n UserService,\n VanillaEventNames,\n} from '@frontend/vanilla/core';\nimport { BehaviorSubject, Observable, Subject, catchError, distinctUntilChanged, filter, take, takeUntil, tap } from 'rxjs';\n\nimport { LabelSwitcherTrackingService } from './label-switcher-tracking.service';\nimport { LabelSwitcherConfig } from './label-switcher.client-config';\nimport { LabelSwitcherItem } from './label-switcher.models';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class LabelSwitcherService {\n private currentPosition: GeolocationPosition | null;\n private currentLabelItemEvent = new BehaviorSubject(undefined);\n private unsubscribe = new Subject();\n\n constructor(\n private config: LabelSwitcherConfig,\n private page: Page,\n private toastrQueueService: ToastrQueueService,\n private cookieService: CookieService,\n private geoLocationService: GeolocationService,\n private dslService: DslService,\n private logger: Logger,\n private trackingService: LabelSwitcherTrackingService,\n private user: UserService,\n private nativeAppService: NativeAppService,\n private authService: AuthService,\n private navigationService: NavigationService,\n private urlService: UrlService,\n private eventsService: EventsService,\n private dateTimeService: DateTimeService,\n ) {}\n\n /** Gets label switcher item event based on current label. */\n get currentLabelItemEvent$(): Observable {\n return this.currentLabelItemEvent;\n }\n\n /** Gets label switcher item based on user's geo location. */\n get currentGeoLocationItem(): LabelSwitcherItem | undefined {\n return this.items.find(\n (i: LabelSwitcherItem) => i.region?.toLowerCase() === this.currentPosition?.mappedLocation?.stateClient?.toLowerCase(),\n );\n }\n\n get messages(): { [attr: string]: string } {\n return this.config.resources.messages;\n }\n\n private _items: LabelSwitcherItem[] = [];\n\n /** Gets all label switcher items. */\n get items(): LabelSwitcherItem[] {\n return this._items;\n }\n\n private _currentLabelItem: LabelSwitcherItem | undefined;\n\n /** Gets label switcher item based on current label. */\n get currentLabelItem(): LabelSwitcherItem | undefined {\n return this._currentLabelItem;\n }\n\n init() {\n this.prepareItems();\n this.checkForContentErrors();\n this.geoLocationService.whenReady.subscribe(() =>\n this.geoLocationService.positionChanges\n .pipe(distinctUntilChanged((prev, curr) => prev.mappedLocation?.stateClient == curr.mappedLocation?.stateClient))\n .subscribe((position: GeolocationPosition) => {\n this.unsubscribe.next();\n this.currentPosition = position;\n this.showToasters();\n }),\n );\n\n if (this.config.persistStayInState) {\n this.eventsService.newEvents\n .pipe(\n filter(\n (event: SimpleEvent) =>\n event.eventName === VanillaEventNames.ToastrClosed && event.data?.toastrContent?.name?.toLowerCase() === 'changelabel',\n ),\n )\n .subscribe(() => {\n const state = this.currentPosition?.mappedLocation?.stateClient;\n if (state)\n this.cookieService.put(this.getCookieName(state), state, {\n expires: this.setCookieExpiration(),\n });\n });\n }\n }\n\n async switchLabel(item: LabelSwitcherItem) {\n this.trackingService.trackConfirmationOverlay('click', `${item.text}, ${this.currentLabelItem?.text}`, this.messages.Overlay_Ok_Epcot || '');\n await this.logout();\n this.cookieService.put(CookieName.StateChanged, '1');\n const url = this.urlService.parse(item.url);\n url.search.append('_showChangeLabelSuccess', 'true');\n\n if (this.nativeAppService.isNative) {\n this.nativeAppService.sendToNative({\n eventName: NativeEventType.LOCATION,\n parameters: {\n label: item.name,\n countryCode: item.country,\n stateCode: item.regionCode,\n state: item.region,\n url: item.url,\n },\n });\n } else {\n this.navigationService.goTo(url);\n }\n }\n\n private async logout(): Promise {\n return this.user.isAuthenticated ? this.authService.logout({ redirectAfterLogout: false }) : Promise.resolve();\n }\n\n private prepareItems() {\n this.config.main.children.forEach((item: MenuContentItem) => {\n this._items.push({\n name: item.name,\n text: item.text,\n region: item.parameters.region,\n regionCode: item.parameters.regionCode,\n country: item.parameters.country,\n url: item.url,\n isActive: this.page.domain.replace(/\\./g, '').trim() == item.name.replace(/\\./g, '').trim(),\n image: item.image,\n });\n });\n\n this._currentLabelItem = this.items.find((i: LabelSwitcherItem) => i.isActive);\n this.currentLabelItemEvent.next(this._currentLabelItem);\n }\n\n private checkForContentErrors() {\n if (!this.currentLabelItem) {\n this.logger.error('Current label is not present in label-switcher items!');\n }\n }\n\n private showToasters() {\n this.logger.infoRemote('LabelSwitcher: Location changed, initializing show toasters.');\n const state = this.currentPosition?.mappedLocation?.stateClient;\n this.dslService\n .evaluateExpression(this.config.showChangeLabelToaster)\n .pipe(\n tap((show) => {\n this.logger.infoRemote(`LabelSwitcher: showChangeLabelToaster evaluated to ${show}`);\n if (this.cookieService.get(CookieName.ShowChangeLabelSuccess) && !show) {\n this.toastrQueueService.add(ToastrType.ChangeLabelSuccess, {\n schedule: ToastrSchedule.Immediate,\n placeholders: { label: this.currentLabelItem?.text || '' },\n });\n this.cookieService.remove(CookieName.ShowChangeLabelSuccess);\n }\n }),\n takeUntil(this.unsubscribe),\n filter(Boolean),\n take(1),\n catchError((error) => {\n this.logger.errorRemote('LabelSwitcher: failed to evaluate showChangeLabelToaster expression.', error);\n throw error;\n }),\n )\n .subscribe(() => {\n if (state && !this.stayInStateAlreadyChosen(state)) {\n this.logger.infoRemote('LabelSwitcher: adding toaster to the queue');\n this.toastrQueueService.add(ToastrType.ChangeLabel, {\n schedule: ToastrSchedule.Immediate,\n placeholders: {\n state: this.currentGeoLocationItem?.text || '',\n originstate: this.currentLabelItem?.text || '',\n },\n });\n } else {\n this.logger.infoRemote('LabelSwitcher: toaster will not be added to the queue due to condition not met.');\n }\n });\n\n this.dslService\n .evaluateExpression(this.config.isRestrictedAccessCondition)\n .pipe(takeUntil(this.unsubscribe), filter(Boolean), take(1))\n .subscribe(() => {\n if (!this.isToastAlreadyShownInState(ToastrType.RestrictedAccess, state)) {\n this.toastrQueueService.add(ToastrType.RestrictedAccess, {\n schedule: ToastrSchedule.Immediate,\n placeholders: {\n label: this.currentLabelItem?.name || '',\n state: this.currentGeoLocationItem?.text || '',\n },\n });\n this.addStateToToast(ToastrType.RestrictedAccess, state);\n }\n });\n }\n\n private stayInStateAlreadyChosen(state: string): boolean {\n const stateName = this.cookieService.get(this.getCookieName(state));\n\n this.logger.infoRemote(`LabelSwitcher: stay in state already chosen for ${state}: ${!!stateName}`);\n return !!stateName;\n }\n\n private setCookieExpiration(): Date {\n const expireDate = this.dateTimeService.now();\n expireDate.setHours(23, 59, 59, 999);\n\n return expireDate;\n }\n\n private getCookieName(state: string): string {\n const stateNameWithoutSpace = state.replace(/\\s/g, '');\n return `vn_ls_${stateNameWithoutSpace}`;\n }\n\n private addStateToToast(toastKey: string, state: string | undefined | null) {\n if (state && !this.isToastAlreadyShownInState(toastKey, state)) {\n this.cookieService.addToQueryCollection(CookieName.ToastShownInStates, toastKey, state, { expires: PERMANENT_COOKIE_EXPIRATION });\n }\n }\n\n private isToastAlreadyShownInState(toastKey: string, state: string | undefined | null): boolean {\n if (!state) return false;\n\n const states = this.cookieService.getQueryCollection(CookieName.ToastShownInStates, toastKey);\n this.logger.infoRemote(`LabelSwitcher: toaster already shown in ${state}: ${states?.includes(state)}`);\n return states?.includes(state);\n }\n}\n","import { Injectable } from '@angular/core';\n\nimport { Logger, MenuAction, MenuActionsService, OnFeatureInit } from '@frontend/vanilla/core';\nimport { firstValueFrom } from 'rxjs';\n\nimport { LabelSwitcherConfig } from './label-switcher.client-config';\nimport { LabelSwitcherService } from './label-switcher.service';\n\n@Injectable()\nexport class LabelSwitcherBootstrapService implements OnFeatureInit {\n constructor(\n private config: LabelSwitcherConfig,\n private service: LabelSwitcherService,\n private menuActionsService: MenuActionsService,\n private logger: Logger,\n ) {}\n\n async onFeatureInit() {\n await firstValueFrom(this.config.whenReady);\n this.service.init();\n this.menuActionsService.register(MenuAction.SHOW_LABEL_SWITCHER_OVERLAY, async () => {\n const item = this.service.currentGeoLocationItem;\n if (item) {\n await this.service.switchLabel(item);\n } else {\n this.logger.warn(`No content found for current GEO IP region.`);\n }\n });\n }\n}\n","import { runOnFeatureInit } from '@frontend/vanilla/core';\n\nimport { LabelSwitcherBootstrapService } from './label-switcher-bootstrap.service';\n\nexport function provide() {\n return [runOnFeatureInit(LabelSwitcherBootstrapService)];\n}\n","@if (labelSwitcherService.items.length) {\n
\n @if (labelSwitcherConfig.resources.messages.Label_Switcher_Heading; as heading) {\n
\n {{ heading }}\n
\n }\n @if (labelSwitcherService.currentLabelItem; as item) {\n
\n @if (item.image && !hideFlag) {\n \n }\n {{ item.text }}\n \n
\n }\n @if (showLabels) {\n
\n @for (item of labelSwitcherService.items; track trackByName($index, item)) {\n {{ item.text }}\n }\n
\n }\n
\n}\n","import { OverlayModule } from '@angular/cdk/overlay';\nimport { CommonModule } from '@angular/common';\nimport { Component, Input, OnInit, ViewEncapsulation } from '@angular/core';\n\nimport { HtmlNode, trackByProp } from '@frontend/vanilla/core';\nimport { IconCustomComponent } from '@frontend/vanilla/shared/icons';\n\nimport { LabelSwitcherTrackingService } from './label-switcher-tracking.service';\nimport { LabelSwitcherConfig } from './label-switcher.client-config';\nimport { LabelSwitcherItem } from './label-switcher.models';\nimport { LabelSwitcherService } from './label-switcher.service';\n\n/**\n * @stable\n */\n@Component({\n standalone: true,\n imports: [CommonModule, OverlayModule, IconCustomComponent],\n selector: 'vn-label-switcher',\n templateUrl: 'label-switcher.html',\n styleUrls: ['../../../../../themepark/themes/whitelabel/components/label-switcher/styles.scss'],\n encapsulation: ViewEncapsulation.None,\n})\nexport class LabelSwitcherComponent implements OnInit {\n showLabels: boolean;\n\n @Input() hideFlag: boolean;\n\n readonly trackByName = trackByProp('name');\n\n constructor(\n public labelSwitcherService: LabelSwitcherService,\n public labelSwitcherConfig: LabelSwitcherConfig,\n private trackingService: LabelSwitcherTrackingService,\n private htmlNode: HtmlNode,\n ) {}\n\n ngOnInit() {\n if (this.labelSwitcherService.items.length) {\n this.htmlNode.setCssClass('label-switcher-shown', true);\n }\n }\n\n toggle() {\n this.showLabels = !this.showLabels;\n\n if (this.showLabels) {\n const positionEvent = this.labelSwitcherService.currentGeoLocationItem?.text;\n this.trackingService.trackDropDown('Click', positionEvent || '', 'Footer State Switcher');\n }\n }\n\n async switchLabel(item: LabelSwitcherItem) {\n if (item.isActive) {\n return;\n }\n\n this.trackingService.trackDropDown(\n 'Switch',\n `${this.labelSwitcherService.currentGeoLocationItem?.text}, ${this.labelSwitcherService.currentLabelItem?.text}`,\n item.text,\n item.url,\n );\n\n this.showLabels = false;\n await this.labelSwitcherService.switchLabel(item);\n }\n}\n","import { FocusMonitor } from '@angular/cdk/a11y';\nimport {\n AfterContentInit,\n AfterViewInit,\n ChangeDetectionStrategy,\n Component,\n ContentChildren,\n DestroyRef,\n ElementRef,\n EventEmitter,\n Input,\n OnChanges,\n OnDestroy,\n Output,\n QueryList,\n SimpleChanges,\n ViewChild,\n ViewEncapsulation,\n forwardRef,\n inject,\n signal,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\n\nimport { rxHostPressedListener } from '@frontend/ui/rx-host-listener';\n\nexport const DS_RADIO_SIZE_ARRAY = ['medium', 'large'] as const;\nexport const DS_RADIO_POSITION_ARRAY = ['left', 'right'] as const;\nexport type DsRadioSize = (typeof DS_RADIO_SIZE_ARRAY)[number];\nexport type DsRadioLabelPosition = (typeof DS_RADIO_POSITION_ARRAY)[number];\n\n@Component({\n selector: 'ds-radio-button',\n template: `\n \n `,\n styleUrls: ['./radio-button.component.scss'],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n standalone: true,\n host: {\n 'class': 'ds-radio-button',\n '(focus)': 'onFocus()',\n '[class.ds-radio-selected]': 'checkedSignal()',\n '[class.ds-radio-focused]': 'focused()',\n '[class.ds-radio-unselected]': '!checkedSignal()',\n '[class.ds-radio-disabled]': 'disabledSignal()',\n '[attr.tabindex]': 'tabIndex()',\n '[attr.aria-disabled]': 'disabledSignal()',\n '[attr.aria-label]': 'null',\n '[attr.aria-labelledby]': 'null',\n '[attr.aria-describedby]': 'null',\n '[attr.data-focus-visible]': 'focusVisible()',\n '[class.data-focus-visible]': 'focusVisible()',\n '[attr.data-focus]': 'focused()',\n },\n})\nexport class DsRadioButton implements AfterContentInit, OnDestroy {\n @Input() value: any;\n @Input({ required: true }) name!: string;\n @Input() ariaLabel: string | null = null;\n @Input() ariaLabelledby: string | null = null;\n @Input() ariaDescribedby: string | null = null;\n @Input() id?: string;\n position = 1;\n setSize = 1;\n\n private static nextUniqueId = 0;\n private _uniqueId = `ds-radio-${DsRadioButton.nextUniqueId++}`;\n\n get inputId(): string {\n return `${this.id || this._uniqueId}-input`;\n }\n\n getAriaLabel(): string {\n return this.ariaLabel || `Option ${this.value}`;\n }\n\n @ViewChild('input') _inputElement!: ElementRef;\n\n private _focusMonitor = inject(FocusMonitor);\n private _elementRef = inject(ElementRef);\n private destroyRef = inject(DestroyRef);\n public radioGroup = inject(DsRadioGroup, { optional: true });\n\n checkedSignal = signal(false);\n disabledSignal = signal(false);\n focusVisible = signal(false);\n focused = signal(false);\n tabIndex = signal(-1);\n\n @Input() set disabled(value: boolean) {\n this.disabledSignal.set(value);\n }\n\n @Input() set checked(value: boolean) {\n this.checkedSignal.set(value);\n }\n\n updatePositionAndSize(position: number, size: number) {\n this.position = position;\n this.setSize = size;\n }\n\n ngOnDestroy() {\n this._focusMonitor.stopMonitoring(this._elementRef);\n }\n\n ngAfterContentInit() {\n this._focusMonitor\n .monitor(this._elementRef, true)\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe((focusOrigin) => {\n this.focused.set(!!focusOrigin);\n if (focusOrigin === 'keyboard') {\n this.focusVisible.set(true);\n } else {\n this.focusVisible.set(false);\n }\n });\n }\n\n constructor() {\n rxHostPressedListener()\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe((event) => {\n if (event.target === this._inputElement.nativeElement) {\n this.onInputChange();\n }\n });\n }\n\n onInputClick(event: Event) {\n event.stopPropagation();\n }\n\n onInputChange(event?: Event) {\n event?.stopPropagation();\n\n if (!this.checkedSignal() && !this.disabledSignal()) {\n const groupValueChanged = this.radioGroup && this.value !== this.radioGroup.valueSignal();\n this.checkedSignal.set(true);\n\n if (this.radioGroup) {\n this.radioGroup.selectButton(this);\n if (groupValueChanged) {\n this.radioGroup.emitChangeEvent();\n }\n }\n }\n }\n\n setTabIndex(value: number) {\n this.tabIndex.set(value);\n }\n\n focus() {\n this.focused.set(true);\n this.focusVisible.set(true);\n this._focusMonitor.focusVia(this._inputElement, 'keyboard');\n }\n\n registerOnInputChange(fn: () => void) {\n this.onInputChange = fn;\n }\n\n onFocus() {\n this._inputElement.nativeElement.focus();\n }\n}\n\n@Component({\n selector: 'ds-radio-group',\n template: ` `,\n host: {\n '[class]': `hostClass`,\n '(keydown)': 'handleKeydown($event)',\n 'role': 'radiogroup',\n },\n styleUrls: ['./radio-button.component.scss'],\n standalone: true,\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => DsRadioGroup),\n multi: true,\n },\n ],\n})\nexport class DsRadioGroup implements OnChanges, AfterContentInit, AfterViewInit, ControlValueAccessor {\n @Input() size: DsRadioSize = 'large';\n @Input() labelPosition: DsRadioLabelPosition = 'right';\n valueSignal = signal('');\n disabledSignal = signal(false);\n @Output() valueChange = new EventEmitter();\n\n @Input() set value(value: string) {\n this.valueSignal.set(value);\n }\n\n @Input() set disabled(value: boolean) {\n this.disabledSignal.set(value);\n }\n\n @ContentChildren(DsRadioButton) radioButtons!: QueryList;\n\n private onChange: (value: any) => void = () => {};\n private onTouched: () => void = () => {};\n\n ngOnChanges(changes: SimpleChanges) {\n if (changes['value'] || changes['disabled']) {\n this.updateButtonsState();\n }\n }\n\n ngAfterViewInit() {\n if (this.radioButtons) {\n this.radioButtons.changes.subscribe(() => {\n this.updatePositionsAndSizes();\n this.updateButtonsState();\n this.radioButtons.forEach((button) => {\n button.registerOnInputChange(() => {\n this.selectButton(button);\n });\n });\n });\n }\n }\n\n private updateButtonsState() {\n if (this.radioButtons) {\n this.radioButtons.forEach((btn) => {\n btn.checkedSignal.set(btn.value === this.valueSignal());\n btn.disabledSignal.set(this.disabledSignal() || btn.disabledSignal());\n btn.setTabIndex(btn.checkedSignal() ? 0 : -1);\n });\n }\n }\n\n private updatePositionsAndSizes() {\n this.radioButtons.forEach((button, index) => {\n button.updatePositionAndSize(index + 1, this.radioButtons.length);\n });\n }\n\n selectButton(selectedBtn: DsRadioButton) {\n if (!this.disabledSignal() && !selectedBtn.disabledSignal() && this.radioButtons) {\n this.radioButtons.forEach((btn) => {\n btn.checkedSignal.set(btn === selectedBtn);\n btn.setTabIndex(btn.checkedSignal() && !btn.disabledSignal() ? 0 : -1);\n });\n this.valueSignal.set(selectedBtn.value);\n this.emitChangeEvent();\n this.onChange(this.valueSignal());\n this.onTouched();\n }\n }\n\n ngAfterContentInit() {\n if (this.radioButtons) {\n this.updatePositionsAndSizes();\n this.updateButtonsState();\n this.radioButtons.forEach((button) => {\n button.registerOnInputChange(() => {\n this.selectButton(button);\n });\n });\n }\n }\n\n emitChangeEvent() {\n this.valueChange.emit(this.valueSignal());\n }\n\n handleKeydown(event: KeyboardEvent) {\n const { key } = event;\n if (this.radioButtons) {\n const buttonsArray = this.radioButtons.toArray().filter((button) => !button.disabledSignal());\n const focusedIndex = buttonsArray.findIndex((button) => button.focused());\n let nextIndex = -1;\n\n if (buttonsArray.length === 0) {\n return;\n }\n if (key === 'ArrowRight' || key === 'ArrowDown') {\n nextIndex = focusedIndex < buttonsArray.length - 1 ? focusedIndex + 1 : 0;\n } else if (key === 'ArrowLeft' || key === 'ArrowUp') {\n nextIndex = focusedIndex > 0 ? focusedIndex - 1 : buttonsArray.length - 1;\n }\n\n if (nextIndex !== -1) {\n buttonsArray.forEach((button) => {\n button.focused.set(false);\n button.focusVisible.set(false);\n });\n event.preventDefault();\n const nextButton = buttonsArray[nextIndex];\n if (nextButton != null) {\n nextButton.focus();\n }\n }\n\n if ((key === 'Space' || key === 'Enter') && focusedIndex !== -1) {\n event.preventDefault();\n const focusedButton = buttonsArray[focusedIndex];\n if (focusedButton != null && !focusedButton.checkedSignal()) {\n this.selectButton(focusedButton); // Ensure no redundant emits\n }\n }\n }\n }\n\n writeValue(value: string): void {\n this.valueSignal.set(value);\n this.updateButtonsState();\n }\n\n registerOnChange(fn: (value: any) => void): void {\n this.onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this.disabledSignal.set(isDisabled);\n this.updateButtonsState();\n }\n\n get hostClass() {\n const sizeClass = this.size === 'large' ? 'ds-radio-large' : 'ds-radio-medium';\n const labelPositionClass = this.labelPosition === 'left' ? 'ds-radio-label-left' : '';\n return `ds-radio-group ${sizeClass} ${labelPositionClass}`;\n }\n}\n","import { NgModule } from '@angular/core';\n\nimport { DsRadioButton, DsRadioGroup } from './radio-button.component';\n\nexport { FormsModule } from '@angular/forms';\nexport { DS_RADIO_SIZE_ARRAY, DS_RADIO_POSITION_ARRAY, DsRadioButton, DsRadioGroup } from './radio-button.component';\n\n@NgModule({\n imports: [DsRadioButton, DsRadioGroup],\n exports: [DsRadioButton, DsRadioGroup],\n})\nexport class DsRadioModule {}\n","import { Injectable } from '@angular/core';\n\nimport { ClientConfigProductName, LazyClientConfig, LazyClientConfigBase, LazyClientConfigService } from '@frontend/vanilla/core';\n\n@LazyClientConfig({ key: 'vnLanguageSwitcher', product: ClientConfigProductName.SF })\n@Injectable({\n providedIn: 'root',\n deps: [LazyClientConfigService],\n useFactory: configFactory,\n})\nexport class LanguageSwitcherConfig extends LazyClientConfigBase {\n isEnabledDslExpression: string;\n openPopupDslExpression: string;\n showHeaderDslExpression: string;\n version: number;\n useFastIcons: boolean;\n}\n\nexport function configFactory(service: LazyClientConfigService) {\n return service.get(LanguageSwitcherConfig);\n}\n","@if (version === 1) {\n @if (useFastIcon) {\n @if (lang.routeValue; as src) {\n \n }\n } @else {\n @if (lang.image; as src) {\n \n }\n }\n\n {{ lang.nativeName }}\n} @else {\n @if (displayRadioButton) {\n \n {{ lang.nativeName }}\n \n }\n\n @if (!displayRadioButton) {\n \n }\n}\n","import { CommonModule } from '@angular/common';\nimport { Component, Input, OnInit } from '@angular/core';\n\nimport { DsRadioModule } from '@frontend/ui/radio-button';\nimport { IconCustomComponent } from '@frontend/vanilla/shared/icons';\nimport { ImageComponent } from '@frontend/vanilla/shared/image';\n\nimport { LanguageSwitcherConfig } from './language-switcher.client-config';\nimport { LanguageSwitcherItem } from './language-switcher.models';\n\n@Component({\n standalone: true,\n selector: 'vn-language-item',\n templateUrl: 'language-item.html',\n host: {},\n imports: [CommonModule, ImageComponent, IconCustomComponent, DsRadioModule],\n})\nexport class LanguageItemComponent implements OnInit {\n @Input() lang: LanguageSwitcherItem;\n @Input() displayRadioButton = true;\n\n version: number;\n useFastIcon: boolean = false;\n constructor(public config: LanguageSwitcherConfig) {}\n\n ngOnInit() {\n this.config.whenReady.subscribe(() => {\n this.version = this.config.version;\n this.useFastIcon = this.config.useFastIcons;\n });\n }\n}\n","import { Injectable } from '@angular/core';\n\nimport { TrackingService } from '@frontend/vanilla/core';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class LanguageSwitcherTrackingService {\n constructor(private trackingService: TrackingService) {}\n\n trackDisplay(openedByLanguageSelector: boolean) {\n this.trackingService.triggerEvent('Event.Tracking', {\n 'component.CategoryEvent': 'language selector',\n 'component.LabelEvent': openedByLanguageSelector ? 'standard language selector' : 'default language selector',\n 'component.ActionEvent': 'load',\n 'component.PositionEvent': 'not applicable',\n 'component.LocationEvent': openedByLanguageSelector ? 'not applicable' : 'pop up',\n 'component.EventDetails': 'language selector',\n 'component.URLClicked': 'not applicable',\n });\n }\n\n trackChangeLanguage(openedByLanguageSelector: boolean, previousLang: string, newLang: string) {\n return this.trackingService.triggerEvent('Event.Tracking', {\n 'component.CategoryEvent': 'language selector',\n 'component.LabelEvent': openedByLanguageSelector ? 'standard language selector' : 'default language selector',\n 'component.ActionEvent': 'select',\n 'component.PositionEvent': previousLang,\n 'component.LocationEvent': openedByLanguageSelector ? 'standard language selector' : 'not applicable',\n 'component.EventDetails': newLang,\n 'component.URLClicked': 'not applicable',\n });\n }\n\n trackOpenLanguageSwitcherMenu() {\n this.trackingService.triggerEvent('Event.Tracking', {\n 'component.CategoryEvent': 'language selector',\n 'component.LabelEvent': 'standard language selector',\n 'component.ActionEvent': 'click',\n 'component.PositionEvent': 'not applicable',\n 'component.LocationEvent': 'not applicable',\n 'component.EventDetails': 'language selector',\n 'component.URLClicked': 'not applicable',\n });\n }\n}\n","import { Injectable, inject } from '@angular/core';\n\nimport { IconsModel, IconsetConfig } from '@frontend/vanilla/shared/icons';\nimport { Observable, map } from 'rxjs';\n\n/**\n * @whatItDoes Provides functionality to fetch flags based on culture route value.\n *\n * @stable\n */\n@Injectable({\n providedIn: 'root',\n})\nexport class FlagsService {\n private config = inject(IconsetConfig);\n\n /** Gets all available flags. */\n get available(): Observable {\n return this.config.whenReady.pipe(\n map(() => {\n const flags = this.config.iconItems?.filter((x: any) => x.iconName.includes('-flag'));\n return flags.length > 0 ? flags : [];\n }),\n );\n }\n\n /** Finds flag image url by key. */\n find(routeValue: string) {\n return this.available.pipe(\n map((flags) => {\n const imageUrl = flags?.find((x: any) => x.iconName === `${routeValue}-flag`)?.imageUrl;\n return imageUrl ? imageUrl : '';\n }),\n );\n }\n}\n","import { Injectable } from '@angular/core';\n\nimport { ParsedUrl } from '@frontend/vanilla/core';\nimport { Observable, of } from 'rxjs';\n\nimport { LanguageSwitcherUrlsProvider } from './language-switcher-urls-provider';\n\n/**\n * @stable\n */\n@Injectable({\n providedIn: 'root',\n})\nexport class DefaultLanguageSwitcherUrlsProvider implements LanguageSwitcherUrlsProvider {\n getUrls(url: ParsedUrl, languages: string[]): Observable> {\n const map = new Map();\n\n languages.forEach((language: string) => {\n url.changeCulture(language);\n map.set(language, url.url());\n });\n\n return of(map);\n }\n}\n","import { InjectionToken, inject } from '@angular/core';\n\nimport { ParsedUrl } from '@frontend/vanilla/core';\nimport { Observable } from 'rxjs';\n\nimport { DefaultLanguageSwitcherUrlsProvider } from './default-language-switcher-urls-provider';\n\n/**\n * @whatItDoes Providers urls for language switcher.\n *\n * @howToUse\n *\n * ```\n * @Injectable\n * export class CustomLanguageSwitcherUrlsProvider implements LanguageSwitcherUrlsProvider {\n * constructor() {\n * }\n *\n * getUrls(url: ParsedUrl, languages: string[]): Observable> {\n * const map = new Map();\n * languages.forEach(l => {\n * map.set(l, getCustomUrl(url, l));\n * })\n *\n * return of(map);\n * }\n *\n * private getCustomUrl(url: ParsedUrl, lang: string) {\n * // your logic\n * }\n * }\n *\n * @NgModule()\n * export class LanguageSwitcherModule {\n * static forRoot(): ModuleWithProviders {\n * return {\n * ngModule: LanguageSwitcherModule,\n * providers: [\n * { provide: LANGUAGE_SWITCHER_URLS_PROVIDER, useClass: CustomLanguageSwitcherUrlsProvider }\n * ]\n * }\n * }\n * }\n * ```\n *\n * @stable\n */\nexport interface LanguageSwitcherUrlsProvider {\n getUrls(url: ParsedUrl, languages: string[]): Observable>;\n}\n\n/**\n * @stable\n */\nexport const LANGUAGE_SWITCHER_URLS_PROVIDER = new InjectionToken('language-switcher-urls-provider', {\n providedIn: 'root',\n factory: () => inject(DefaultLanguageSwitcherUrlsProvider),\n});\n","import { Inject, Injectable, signal } from '@angular/core';\n\nimport { DslService, LanguageInfo, NavigationService, Page } from '@frontend/vanilla/core';\nimport { FlagsService } from '@frontend/vanilla/features/flags';\nimport { Observable, combineLatest, of } from 'rxjs';\nimport { first, map, switchMap } from 'rxjs/operators';\n\nimport { LANGUAGE_SWITCHER_URLS_PROVIDER, LanguageSwitcherUrlsProvider } from './language-switcher-urls-provider';\nimport { LanguageSwitcherConfig } from './language-switcher.client-config';\nimport { LanguageSwitcherItem } from './language-switcher.models';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class LanguageSwitcherService {\n readonly headerEnabled = signal(false);\n\n private languages: string[];\n private cachedUrl: string;\n private cachedData: Observable | null = null;\n\n constructor(\n private page: Page,\n private flagsService: FlagsService,\n private navigationService: NavigationService,\n private config: LanguageSwitcherConfig,\n dslService: DslService,\n @Inject(LANGUAGE_SWITCHER_URLS_PROVIDER) private languageSwitcherUrlsProvider: LanguageSwitcherUrlsProvider,\n ) {\n this.languages = this.page.uiLanguages.map((language: LanguageInfo) => language.routeValue);\n\n this.config.whenReady\n .pipe(first())\n .subscribe(() =>\n dslService\n .evaluateExpression(this.config.showHeaderDslExpression)\n .subscribe((enabled: boolean) => this.headerEnabled.set(enabled)),\n );\n }\n\n getLanguageSwitcherData(): Observable {\n const currentUrl = this.navigationService.location.absUrl();\n\n if (!this.cachedData || this.cachedUrl !== currentUrl) {\n this.cachedData = this.createLanguageSwitcherData();\n this.cachedUrl = currentUrl;\n }\n\n return this.cachedData;\n }\n\n private createLanguageSwitcherData(): Observable {\n return this.config.whenReady.pipe(\n first(),\n switchMap(() => {\n return combineLatest([\n this.languageSwitcherUrlsProvider.getUrls(this.navigationService.location.clone(), this.languages),\n this.config.version === 1 ? this.flagsService.available : of([]),\n ]).pipe(\n map((data: any[]) => {\n const urls = data[0];\n const flags = data[1];\n\n return this.page.uiLanguages.map((language: LanguageInfo) => {\n const url = urls.get(language.routeValue);\n\n if (!url) {\n throw new Error(`LanguageSwitcherUrlsProvider did not return an url value for language ${language.routeValue}`);\n }\n\n const languageSwitcherItem: LanguageSwitcherItem = {\n url,\n routeValue: language.routeValue,\n nativeName: language.nativeName,\n image: flags?.find((x: any) => x.iconName === `${language.routeValue}-flag`)?.imageUrl,\n isActive: language.routeValue === this.page.lang,\n culture: language.culture,\n };\n\n return languageSwitcherItem;\n });\n }),\n );\n }),\n );\n }\n}\n","import { InjectionToken } from '@angular/core';\n\nimport { LanguageSwitcherMenuData } from './language-switcher.models';\n\n/**\n * @internal\n */\nexport const LANGUAGE_SWITCHER_MENU_DATA = new InjectionToken('vn-language-switcher-menu-data');\n","@if (languageSwitcherService.headerEnabled()) {\n \n}\n
\n @if (languages) {\n @for (lang of languages; track trackByNativeName($index, lang)) {\n
\n @if (lang.isActive) {\n
\n \n
\n }\n @if (!lang.isActive) {\n \n \n \n }\n
\n }\n }\n
\n","import { OverlayRef } from '@angular/cdk/overlay';\nimport { CommonModule } from '@angular/common';\nimport { Component, Inject, OnDestroy, OnInit } from '@angular/core';\n\nimport { CommonMessages, DeviceService, NativeAppService, NativeEventType, NavigationService, Page, trackByProp } from '@frontend/vanilla/core';\nimport { HeaderBarComponent } from '@frontend/vanilla/features/header-bar';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n\nimport { LanguageItemComponent } from './language-item.component';\nimport { LanguageSwitcherTrackingService } from './language-switcher-tracking.service';\nimport { LanguageSwitcherItem, LanguageSwitcherMenuData } from './language-switcher.models';\nimport { LanguageSwitcherService } from './language-switcher.service';\nimport { LANGUAGE_SWITCHER_MENU_DATA } from './language-switcher.tokens';\n\n@Component({\n standalone: true,\n imports: [CommonModule, HeaderBarComponent, LanguageItemComponent],\n selector: 'vn-language-switcher-menu',\n templateUrl: 'language-switcher-menu.html',\n})\nexport class LanguageSwitcherMenuComponent implements OnInit, OnDestroy {\n languages: LanguageSwitcherItem[];\n gridRows: number;\n readonly trackByNativeName = trackByProp('nativeName');\n\n private unsubscribe = new Subject();\n\n constructor(\n public commonMessages: CommonMessages,\n public languageSwitcherService: LanguageSwitcherService,\n private overlayRef: OverlayRef,\n private page: Page,\n private trackingService: LanguageSwitcherTrackingService,\n private navigation: NavigationService,\n private nativeAppService: NativeAppService,\n private deviceService: DeviceService,\n @Inject(LANGUAGE_SWITCHER_MENU_DATA) private languageSwitcherMenuData: LanguageSwitcherMenuData,\n ) {}\n\n ngOnInit() {\n this.trackingService.trackDisplay(this.languageSwitcherMenuData.openedByLanguageSelector);\n\n this.languageSwitcherService\n .getLanguageSwitcherData()\n .pipe(takeUntil(this.unsubscribe))\n .subscribe((languages: LanguageSwitcherItem[]) => {\n this.languages = languages;\n });\n\n this.gridRows = this.setGridRows();\n }\n\n ngOnDestroy() {\n this.unsubscribe.next();\n this.unsubscribe.complete();\n }\n\n close() {\n this.overlayRef.detach();\n }\n\n change(lang: LanguageSwitcherItem) {\n this.nativeAppService.sendToNative({\n eventName: NativeEventType.LANGUAGEUPDATED,\n parameters: { newLanguage: lang.culture, routeValue: lang.routeValue },\n });\n\n this.trackingService.trackChangeLanguage(this.languageSwitcherMenuData.openedByLanguageSelector, this.page.lang, lang.routeValue).then(() => {\n this.navigation.goTo(lang.url);\n });\n }\n\n private setGridRows(): number {\n if (this.languages?.length === 6) {\n return 3;\n }\n\n if ([7, 8].includes(this.languages?.length)) {\n return 4;\n }\n\n const denominator = this.deviceService.isMobile || this.deviceService.isTablet ? 2 : 3;\n\n if (denominator === 3 && [11, 12].includes(this.languages?.length)) {\n return 4;\n }\n\n return Math.ceil(this.languages?.length / denominator) > 5 ? Math.ceil(this.languages?.length / denominator) : 5;\n }\n}\n","import { OverlayRef } from '@angular/cdk/overlay';\nimport { ComponentPortal } from '@angular/cdk/portal';\nimport { ElementRef, Injectable, Injector } from '@angular/core';\n\nimport { OverlayFactory } from '@frontend/vanilla/shared/overlay-factory';\n\nimport { LanguageSwitcherMenuComponent } from './language-switcher-menu.component';\nimport { LanguageSwitcherMenuData } from './language-switcher.models';\nimport { LANGUAGE_SWITCHER_MENU_DATA } from './language-switcher.tokens';\n\n@Injectable({\n providedIn: 'root',\n})\nexport class LanguageSwitcherOverlayService {\n constructor(\n private overlay: OverlayFactory,\n private injector: Injector,\n ) {}\n\n openMenu(elementRef?: ElementRef) {\n const languageSwitcherMenuData: LanguageSwitcherMenuData = {\n openedByLanguageSelector: !!elementRef,\n };\n\n const overlayRef = this.overlay.create({\n panelClass: elementRef ? ['vn-language-switcher'] : ['vn-language-switcher', 'full-view'],\n positionStrategy: this.createPositionStrategy(elementRef),\n });\n overlayRef.backdropClick().subscribe(() => this.overlay.dispose(overlayRef));\n overlayRef.detachments().subscribe(() => {\n this.overlay.dispose(overlayRef);\n });\n\n const portal = new ComponentPortal(\n LanguageSwitcherMenuComponent,\n null,\n Injector.create({\n providers: [\n { provide: OverlayRef, useValue: overlayRef },\n { provide: LANGUAGE_SWITCHER_MENU_DATA, useValue: languageSwitcherMenuData },\n ],\n parent: this.injector,\n }),\n );\n overlayRef.attach(portal);\n }\n\n private createPositionStrategy(elementRef?: ElementRef) {\n if (elementRef) {\n return this.overlay.position\n .flexibleConnectedTo(elementRef)\n .withPositions([\n { originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'bottom' },\n { originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'top' },\n ])\n .withPush(false)\n .withFlexibleDimensions(false);\n } else {\n return this.overlay.position.global().centerHorizontally().centerVertically();\n }\n }\n}\n","import { Injectable } from '@angular/core';\n\nimport { CookieName, CookieService, DslService, MenuAction, MenuActionsService, OnFeatureInit } from '@frontend/vanilla/core';\nimport { first, firstValueFrom } from 'rxjs';\n\nimport { LanguageSwitcherOverlayService } from './language-switcher-overlay.service';\nimport { LanguageSwitcherConfig } from './language-switcher.client-config';\n\n@Injectable()\nexport class LanguageSwitcherBootstrapService implements OnFeatureInit {\n constructor(\n private cookieService: CookieService,\n private languageSwitcherOverlayService: LanguageSwitcherOverlayService,\n private dslService: DslService,\n private config: LanguageSwitcherConfig,\n private menuActionsService: MenuActionsService,\n ) {}\n\n async onFeatureInit() {\n await firstValueFrom(this.config.whenReady);\n this.menuActionsService.register(MenuAction.TOGGLE_LANGUAGE_SWITCHER, () => {\n this.languageSwitcherOverlayService.openMenu();\n });\n\n this.dslService\n .evaluateExpression(this.config.openPopupDslExpression)\n .pipe(first())\n .subscribe((isEnabled: boolean) => {\n if (isEnabled) {\n this.languageSwitcherOverlayService.openMenu();\n this.cookieService.remove(CookieName.UnsupportedBrowserLanguage);\n }\n });\n }\n}\n","import { runOnFeatureInit } from '@frontend/vanilla/core';\n\nimport { LanguageSwitcherBootstrapService } from './language-switcher-bootstrap.service';\n\n/**\n * @stable\n */\nexport function provide() {\n return [runOnFeatureInit(LanguageSwitcherBootstrapService)];\n}\n","
\n @if (languageSwitcherService.getLanguageSwitcherData() | async; as languages) {\n @for (lang of languages; track trackByNativeName($index, lang)) {\n
\n @if (lang.isActive) {\n
\n \n
\n }\n @if (!lang.isActive) {\n \n \n \n }\n
\n }\n }\n
\n","import { CommonModule } from '@angular/common';\nimport { Component, OnInit } from '@angular/core';\n\nimport { CommonMessages, NativeAppService, NativeEventType, NavigationService, Page, trackByProp } from '@frontend/vanilla/core';\n\nimport { LanguageItemComponent } from './language-item.component';\nimport { LanguageSwitcherTrackingService } from './language-switcher-tracking.service';\nimport { LanguageSwitcherItem } from './language-switcher.models';\nimport { LanguageSwitcherService } from './language-switcher.service';\n\n@Component({\n standalone: true,\n imports: [CommonModule, LanguageItemComponent],\n selector: 'vn-language-switcher-radio-menu',\n templateUrl: 'language-switcher-radio-menu.html',\n})\nexport class LanguageSwitcherRadioMenuComponent implements OnInit {\n readonly trackByNativeName = trackByProp('nativeName');\n\n constructor(\n public languageSwitcherService: LanguageSwitcherService,\n public commonMessages: CommonMessages,\n private page: Page,\n private languageSwitcherTrackingService: LanguageSwitcherTrackingService,\n private nativeAppService: NativeAppService,\n private navigationService: NavigationService,\n ) {}\n\n ngOnInit() {\n this.languageSwitcherTrackingService.trackDisplay(true);\n }\n\n change(lang: LanguageSwitcherItem) {\n this.nativeAppService.sendToNative({\n eventName: NativeEventType.LANGUAGEUPDATED,\n parameters: { newLanguage: lang.culture, routeValue: lang.routeValue },\n });\n\n this.languageSwitcherTrackingService.trackChangeLanguage(true, this.page.lang, lang.routeValue).then(() => {\n this.navigationService.goTo(lang.url);\n });\n }\n}\n","
\n @for (lang of languages; track trackByNativeName($index, lang)) {\n {{ lang.nativeName }}\n }\n
\n","import { CommonModule } from '@angular/common';\nimport { ChangeDetectorRef, Component, OnInit } from '@angular/core';\n\nimport { trackByProp } from '@frontend/vanilla/core';\nimport { first } from 'rxjs/operators';\n\nimport { LanguageSwitcherItem } from './language-switcher.models';\nimport { LanguageSwitcherService } from './language-switcher.service';\n\n@Component({\n standalone: true,\n imports: [CommonModule],\n selector: 'vn-seo-language-links',\n templateUrl: 'seo-language-links.html',\n})\nexport class SeoLanguageLinksComponent implements OnInit {\n languages: LanguageSwitcherItem[];\n readonly trackByNativeName = trackByProp('nativeName');\n\n constructor(\n private languageSwitcherService: LanguageSwitcherService,\n private changeDetectorRef: ChangeDetectorRef,\n ) {}\n\n ngOnInit() {\n this.languageSwitcherService\n .getLanguageSwitcherData()\n .pipe(first())\n .subscribe((languages: LanguageSwitcherItem[]) => {\n this.languages = languages;\n this.changeDetectorRef.detectChanges();\n });\n }\n}\n","@if (!deviceService.isRobot) {\n
\n
\n @if (commonMessages.LanguageSwitcherHeading; as heading) {\n
{{ heading }}
\n }\n @if (version === 1) {\n
\n @if (currentLanguage) {\n \n }\n \n
\n }\n @if (version === 2) {\n
\n @if (currentLanguage) {\n \n }\n \n @if (showV2) {\n \n }\n
\n }\n
\n
\n}\n@if (deviceService.isRobot) {\n \n}\n","import { CommonModule, DOCUMENT } from '@angular/common';\nimport { ChangeDetectorRef, Component, ElementRef, OnInit, ViewEncapsulation, inject } from '@angular/core';\n\nimport { CommonMessages, DeviceService, LanguageInfo, Page } from '@frontend/vanilla/core';\nimport { FlagsService } from '@frontend/vanilla/features/flags';\nimport { IconCustomComponent } from '@frontend/vanilla/shared/icons';\nimport { firstValueFrom } from 'rxjs';\nimport { first } from 'rxjs/operators';\n\nimport { LanguageItemComponent } from './language-item.component';\nimport { LanguageSwitcherOverlayService } from './language-switcher-overlay.service';\nimport { LanguageSwitcherRadioMenuComponent } from './language-switcher-radio-menu.component';\nimport { LanguageSwitcherTrackingService } from './language-switcher-tracking.service';\nimport { LanguageSwitcherConfig } from './language-switcher.client-config';\nimport { LanguageSwitcherItem } from './language-switcher.models';\nimport { SeoLanguageLinksComponent } from './seo-language-links.component';\n\n/**\n * @whatItDoes Displays the language switcher.\n *\n * @stable\n */\n@Component({\n standalone: true,\n imports: [CommonModule, SeoLanguageLinksComponent, LanguageItemComponent, LanguageSwitcherRadioMenuComponent, IconCustomComponent],\n selector: 'vn-responsive-language-switcher',\n templateUrl: 'responsive-language-switcher.html',\n styleUrls: ['../../../../../themepark/themes/whitelabel/components/language-switcher/styles.scss'],\n encapsulation: ViewEncapsulation.None,\n})\nexport class ResponsiveLanguageSwitcherComponent implements OnInit {\n currentLanguage: LanguageSwitcherItem;\n version: number;\n showV2: boolean;\n\n private readonly _doc = inject(DOCUMENT);\n\n constructor(\n public commonMessages: CommonMessages,\n public deviceService: DeviceService,\n private page: Page,\n private elementRef: ElementRef,\n private languageSwitcherOverlayService: LanguageSwitcherOverlayService,\n private flagsService: FlagsService,\n private trackingService: LanguageSwitcherTrackingService,\n private changeDetectorRef: ChangeDetectorRef,\n private config: LanguageSwitcherConfig,\n ) {}\n\n async ngOnInit() {\n const currentUiLanguage = this.page.uiLanguages.find((l: LanguageInfo) => l.routeValue == this.page.lang)!;\n\n this.flagsService\n .find(this.page.lang)\n .pipe(first())\n .subscribe((image: string | null) => {\n this.currentLanguage = Object.assign({ image: image, isActive: true, url: '' }, currentUiLanguage);\n this.changeDetectorRef.detectChanges();\n });\n\n await firstValueFrom(this.config.whenReady);\n\n this.version = this.config.version;\n }\n\n openMenu() {\n this.trackingService.trackOpenLanguageSwitcherMenu();\n this.languageSwitcherOverlayService.openMenu(this.elementRef);\n }\n\n openRadioMenu() {\n this.trackingService.trackOpenLanguageSwitcherMenu();\n this.showV2 = !this.showV2;\n const toggleDiv = this._doc.querySelector('[menu-toggle=closed]');\n\n if (toggleDiv) {\n if (this.showV2) {\n toggleDiv.classList.remove('current');\n toggleDiv.classList.add('language-switcher-open');\n } else {\n toggleDiv.classList.remove('language-switcher-open');\n toggleDiv.classList.add('current');\n }\n }\n }\n}\n","import { Injectable } from '@angular/core';\n\nimport {\n ClientConfigProductName,\n ContentItem,\n LazyClientConfig,\n LazyClientConfigBase,\n LazyClientConfigService,\n MenuContentItem,\n MenuContentSection,\n ViewTemplateForClient,\n} from '@frontend/vanilla/core';\n\n/**\n * @stable\n */\n@LazyClientConfig({ key: 'vnFooter', product: ClientConfigProductName.SF })\n@Injectable({\n providedIn: 'root',\n useFactory: footerContentFactory,\n deps: [LazyClientConfigService],\n})\nexport class ResponsiveFooterContent extends LazyClientConfigBase {\n isEnabledCondition: string;\n expandableModeEnabled: boolean;\n showHelpButton: boolean;\n links: MenuContentSection;\n seoLinks: MenuContentSection[];\n logos: { left: MenuContentSection; right: MenuContentSection };\n contentMessages: ContentItem[];\n copyright: ViewTemplateForClient;\n showLanguageSwitcherDslCondition: string;\n helpButton: MenuContentItem;\n showLabelSwitcher: boolean;\n footerTopItems: ContentItem[];\n expandableModeIcons: { expanded: string; collapsed: string };\n}\n\nexport function footerContentFactory(service: LazyClientConfigService) {\n return service.get(ResponsiveFooterContent);\n}\n","import { CommonModule } from '@angular/common';\nimport { Component, Input } from '@angular/core';\n\nimport { MenuContentItem, MenuSection } from '@frontend/vanilla/core';\nimport { MenuItemComponent } from '@frontend/vanilla/features/menus';\n\n@Component({\n standalone: true,\n imports: [MenuItemComponent, CommonModule],\n selector: 'vn-footer-menu-item',\n templateUrl: 'footer-menu-item.html',\n})\nexport class FooterMenuItemComponent {\n @Input() item: MenuContentItem;\n\n MenuSection = MenuSection;\n}\n","\n","@if (section().title) {\n
\n @if (config.expandableModeEnabled) {\n \n }\n {{ section().title }}\n
\n}\n@if (expanded()) {\n @for (item of section().items; track 'text') {\n \n }\n}\n","import { CommonModule } from '@angular/common';\nimport { ChangeDetectionStrategy, Component, OnInit, computed, inject, input, signal } from '@angular/core';\n\nimport { MenuContentSection } from '@frontend/vanilla/core';\n\nimport { FooterMenuItemComponent } from './footer-menu-item.component';\nimport { ResponsiveFooterContent } from './footer.client-config';\n\n@Component({\n standalone: true,\n imports: [CommonModule, FooterMenuItemComponent],\n selector: 'vn-footer-menu-section',\n templateUrl: 'footer-menu-section.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class]': 'footerClass()',\n },\n})\nexport class FooterMenuSectionComponent implements OnInit {\n section = input.required();\n\n config = inject(ResponsiveFooterContent);\n expanded = signal(true);\n sectionClass = computed(() => this.section().class);\n footerClass = computed(() =>\n [this.expanded() && this.config.expandableModeEnabled ? 'footer-nav-expanded' : '', 'footer-nav', this.sectionClass()]\n .filter((c) => c)\n .join(' '),\n );\n\n ngOnInit() {\n this.expanded.set(!this.config.expandableModeEnabled);\n }\n\n toggle() {\n if (this.config.expandableModeEnabled) {\n this.expanded.update((e) => !e);\n }\n }\n}\n","@if (item) {\n \n}\n","import { CommonModule } from '@angular/common';\nimport { Component, Input } from '@angular/core';\n\nimport { MenuContentItem, MenuSection } from '@frontend/vanilla/core';\nimport { MenuItemComponent } from '@frontend/vanilla/features/menus';\n\n@Component({\n standalone: true,\n imports: [MenuItemComponent, CommonModule],\n selector: 'vn-f-help-button',\n templateUrl: 'help-button.html',\n})\nexport class HelpButtonComponent {\n @Input() item?: MenuContentItem;\n MenuSection = MenuSection;\n}\n","@if (configReady && footerSlot.display()) {\n
\n
\n
\n @if (showResponsiveLanguageSwitcher) {\n \n }\n @if (config.showLabelSwitcher) {\n \n }\n @for (item of config.links.items | dsl | async; track trackByText($index, item)) {\n \n }\n \n @if (config.showHelpButton) {\n \n }\n
\n @if (config.footerTopItems.length) {\n @if (config.footerTopItems | dsl | async; as topItems) {\n \n }\n }\n
\n @for (seoSection of config.seoLinks | dsl | async; track trackBySectionName($index, seoSection)) {\n \n }\n
\n @if (config.contentMessages.length) {\n @if (config.contentMessages | dsl | async; as messages) {\n \n }\n }\n @if (logoSections.length) {\n
\n @for (logoSection of logoSections | dsl | async; track trackBySectionName($index, logoSection)) {\n \n }\n
\n }\n \n
\n
\n}\n","import { OverlayModule } from '@angular/cdk/overlay';\nimport { CommonModule } from '@angular/common';\nimport { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core';\n\nimport {\n DslService,\n DynamicLayoutService,\n DynamicLayoutSlotComponent,\n HtmlNode,\n MenuContentItem,\n MenuContentSection,\n Page,\n SingleSlot,\n SlotName,\n SlotType,\n trackByProp,\n} from '@frontend/vanilla/core';\nimport { ContentMessagesComponent } from '@frontend/vanilla/features/content-messages';\nimport { LabelSwitcherComponent } from '@frontend/vanilla/features/label-switcher';\nimport { ResponsiveLanguageSwitcherComponent } from '@frontend/vanilla/features/language-switcher';\nimport { DslPipe } from '@frontend/vanilla/shared/browser';\nimport { Subject, firstValueFrom, takeUntil } from 'rxjs';\n\nimport { FooterMenuItemComponent } from './footer-menu-item.component';\nimport { FooterMenuSectionComponent } from './footer-menu-section.component';\nimport { ResponsiveFooterContent } from './footer.client-config';\nimport { HelpButtonComponent } from './sub-components/help-button.component';\n\n/** @stable */\n@Component({\n standalone: true,\n imports: [\n CommonModule,\n DslPipe,\n ContentMessagesComponent,\n LabelSwitcherComponent,\n ResponsiveLanguageSwitcherComponent,\n DynamicLayoutSlotComponent,\n OverlayModule,\n HelpButtonComponent,\n FooterMenuSectionComponent,\n FooterMenuItemComponent,\n ],\n selector: 'vn-footer',\n templateUrl: 'footer.html',\n styleUrls: ['../../../../../themepark/themes/whitelabel/components/footer/styles.scss'],\n encapsulation: ViewEncapsulation.None,\n})\nexport class FooterComponent implements OnInit, OnDestroy {\n footerSlot: SingleSlot;\n logoSections: MenuContentSection[] = [];\n showResponsiveLanguageSwitcher: boolean;\n configReady: boolean = false;\n\n SlotName = SlotName;\n\n helpButton: MenuContentItem | undefined;\n readonly trackByText = trackByProp('text');\n readonly trackByName = trackByProp('name');\n readonly trackBySectionName = trackByProp('name');\n\n private unsubscribe = new Subject();\n\n constructor(\n public config: ResponsiveFooterContent,\n private htmlNode: HtmlNode,\n private page: Page,\n private dslService: DslService,\n private dynamicLayoutService: DynamicLayoutService,\n ) {}\n\n async ngOnInit() {\n await firstValueFrom(this.config.whenReady);\n this.configReady = true;\n\n this.footerSlot = this.dynamicLayoutService.getSlot(SlotName.Footer, SlotType.Single);\n\n this.showResponsiveLanguageSwitcher = this.page.uiLanguages.length > 1;\n\n if (this.config.showHelpButton) {\n this.dslService\n .evaluateContent(this.config.helpButton)\n .pipe(takeUntil(this.unsubscribe))\n .subscribe((item: MenuContentItem) => {\n if (item?.name) {\n this.helpButton = item;\n }\n });\n }\n\n if (this.showResponsiveLanguageSwitcher) {\n this.dslService.evaluateExpression(this.config.showLanguageSwitcherDslCondition).subscribe((isEnabled: boolean) => {\n this.showResponsiveLanguageSwitcher = isEnabled;\n\n if (this.showResponsiveLanguageSwitcher) {\n this.setContactHtmlClass(false);\n this.setLanguageSwitcherHtmlClass(true);\n } else if (this.config.showHelpButton) {\n this.setContactHtmlClass(true);\n this.setLanguageSwitcherHtmlClass(false);\n }\n });\n } else if (this.config.showHelpButton) {\n this.setContactHtmlClass(true);\n }\n\n if (this.config.logos.left) {\n this.logoSections.push(this.config.logos.left);\n }\n\n if (this.config.logos.right) {\n this.logoSections.push(this.config.logos.right);\n }\n }\n\n ngOnDestroy() {\n this.setContactHtmlClass(false);\n this.setLanguageSwitcherHtmlClass(false);\n this.unsubscribe.next();\n this.unsubscribe.complete();\n }\n\n private setContactHtmlClass(add: boolean) {\n this.htmlNode.setCssClass('footer_items-help-contact-shown', add);\n }\n\n private setLanguageSwitcherHtmlClass(add: boolean) {\n this.htmlNode.setCssClass('language-switcher-shown', add);\n }\n}\n","import { Injectable } from '@angular/core';\n\nimport {\n DateTimeService,\n DslService,\n DynamicLayoutService,\n EventsService,\n OnFeatureInit,\n SimpleEvent,\n SingleSlot,\n SlotName,\n SlotType,\n VanillaEventNames,\n ViewTemplateForClient,\n} from '@frontend/vanilla/core';\nimport { CopyrightComponent } from '@frontend/vanilla/shared/copy-right';\nimport { filter, first, firstValueFrom } from 'rxjs';\n\nimport { ResponsiveFooterContent } from './footer.client-config';\nimport { FooterComponent } from './footer.component';\n\n@Injectable()\nexport class FooterBootstrapService implements OnFeatureInit {\n constructor(\n private config: ResponsiveFooterContent,\n private dynamicLayoutService: DynamicLayoutService,\n private dslService: DslService,\n private dateTimeService: DateTimeService,\n private eventsService: EventsService,\n ) {}\n\n async onFeatureInit() {\n await firstValueFrom(this.config.whenReady);\n\n this.dynamicLayoutService.setComponent(SlotName.Footer, FooterComponent, null);\n this.eventsService.raise({ eventName: VanillaEventNames.FooterLoaded });\n\n this.eventsService.allEvents\n .pipe(\n filter((e: SimpleEvent) => e?.eventName === VanillaEventNames.FooterSlotLoaded),\n first(),\n )\n .subscribe(() => this.toggleFooter());\n\n if (this.config.copyright) {\n this.dslService\n .evaluateContent(this.config.copyright)\n .pipe(first())\n .subscribe((item: ViewTemplateForClient) => {\n if (item?.title) {\n const copyright = item.title.replace('{year}', this.dateTimeService.now().getFullYear().toString());\n this.dynamicLayoutService.addComponent(SlotName.FooterItems, CopyrightComponent, { copyright: copyright });\n }\n });\n }\n }\n\n toggleFooter() {\n const footerSlot = this.dynamicLayoutService.getSlot(SlotName.Footer, SlotType.Single);\n this.dslService.evaluateExpression(this.config.isEnabledCondition).subscribe((isEnabled: boolean) => {\n if (isEnabled) {\n footerSlot.show();\n } else {\n footerSlot.hide();\n }\n });\n }\n}\n","import { runOnFeatureInit } from '@frontend/vanilla/core';\n\nimport { FooterBootstrapService } from './footer-bootstrap.service';\n\nexport function provide() {\n return [runOnFeatureInit(FooterBootstrapService)];\n}\n","import { Injectable } from '@angular/core';\n\nimport { BehaviorSubject, Observable } from 'rxjs';\n\nimport { NavigationScrollEvent } from './models';\n\n/**\n * @whatItDoes This service is used to manage scroll related activities in the navigation layout.\n *\n * @stable\n */\n@Injectable({\n providedIn: 'root',\n})\nexport class NavigationLayoutScrollService {\n get scrollEvents(): Observable {\n return this.scrollEventsSubject.asObservable();\n }\n\n private scrollEventsSubject = new BehaviorSubject(null);\n\n /** @internal */\n sendScrollEvent(element: HTMLElement, scrolledToBottomPadding: number = 0) {\n const isAtBottom = element.scrollTop >= element.scrollHeight - (element.offsetHeight + scrolledToBottomPadding);\n this.scrollEventsSubject.next({ element, isAtBottom });\n }\n}\n","import { Injectable } from '@angular/core';\n\nimport { ClientConfigProductName, LazyClientConfig, LazyClientConfigBase, LazyClientConfigService, MenuContentItem } from '@frontend/vanilla/core';\n\n@LazyClientConfig({ key: 'vnNavigationLayout', product: ClientConfigProductName.SF })\n@Injectable({\n providedIn: 'root',\n deps: [LazyClientConfigService],\n useFactory: navigationLayoutConfigFactory,\n})\nexport class NavigationLayoutConfig extends LazyClientConfigBase {\n version: number;\n navigation: MenuContentItem;\n elements: { [key: string]: MenuContentItem };\n leftMenuEnabledOnCustomerHub: string[];\n}\n\nexport function navigationLayoutConfigFactory(service: LazyClientConfigService) {\n return service.get(NavigationLayoutConfig);\n}\n","import { Injectable } from '@angular/core';\n\nimport { DslService, MenuContentItem, toBoolean } from '@frontend/vanilla/core';\nimport { HeaderBarConfig } from '@frontend/vanilla/features/header-bar';\nimport { BehaviorSubject, Observable } from 'rxjs';\nimport { distinctUntilChanged } from 'rxjs/operators';\n\nimport { NavigationItem } from './models';\nimport { NavigationLayoutConfig } from './navigation-layout.client-config';\n\n/**\n * @whatItDoes This service is used to control the navigation layout\n *\n * @stable\n */\n@Injectable({\n providedIn: 'root',\n})\nexport class NavigationLayoutService {\n showTopMenu: BehaviorSubject = new BehaviorSubject(null);\n get initialized(): Observable {\n return this.initializedEvents;\n }\n\n private initializedEvents: BehaviorSubject = new BehaviorSubject(false);\n private headerEnabledEvents = new BehaviorSubject(true);\n private lookup = new Map();\n\n get headerEnabled(): Observable {\n return this.headerEnabledEvents;\n }\n\n get isV1orV4(): boolean {\n return [1, 4].includes(this.config.version);\n }\n\n constructor(\n private config: NavigationLayoutConfig,\n private dslService: DslService,\n private headerBarConfig: HeaderBarConfig,\n ) {}\n\n init() {\n if (this.isV1orV4) {\n this.config.navigation.children.forEach((level1: MenuContentItem) => {\n level1.children.forEach((top: MenuContentItem) => {\n this.addToLookup(top, null, level1.children, top.name, top.children, null);\n if (top.children) {\n top.children.forEach((item: MenuContentItem) => {\n this.addToLookup(item, top, level1.children, top.name, top.children, item.name);\n if (item.children) {\n item.children.forEach((subitem: MenuContentItem) => {\n this.addToLookup(subitem, top, level1.children, top.name, top.children, item.name);\n });\n }\n });\n }\n });\n });\n }\n\n this.initializedEvents.next(true);\n\n this.headerBarConfig.whenReady.subscribe(() => {\n this.dslService\n .evaluateExpression(this.headerBarConfig.isEnabledCondition)\n .pipe(distinctUntilChanged())\n .subscribe((enabled) => {\n this.headerEnabledEvents.next(enabled);\n });\n });\n }\n\n /** get navigation item */\n getItem(item: string): NavigationItem | null {\n return this.lookup.get(item.toLowerCase()) || null;\n }\n\n private addToLookup(\n item: MenuContentItem,\n parent: MenuContentItem | null,\n topMenuItems: MenuContentItem[],\n selectedTopItem: string,\n leftMenuItems: MenuContentItem[],\n selectedLeftItem: string | null,\n ) {\n this.lookup.set(item.name.toLowerCase(), {\n name: item.name,\n pageTitle: item.text,\n headerTitle: null,\n parent: parent,\n leftMenuTitle: parent ? parent.text : null,\n selectedLeftItem: selectedLeftItem,\n selectedTopItem: selectedTopItem,\n leftMenuItems: leftMenuItems,\n topMenuItems: topMenuItems.filter((t) => t.parameters['hideTopMenuItem'] != 'true'),\n hideHeaderCloseButton: !!toBoolean(item.parameters['hide-close']),\n });\n }\n}\n","
\n @if (item) {\n \n }\n
\n","import { CommonModule } from '@angular/common';\nimport { Component, Input, OnInit } from '@angular/core';\n\nimport { MenuActionsService, MenuContentItem, trackByProp } from '@frontend/vanilla/core';\nimport { DslPipe } from '@frontend/vanilla/shared/browser';\n\nimport { NavigationItem } from './models';\nimport { NavigationLayoutService } from './navigation-layout.service';\n\n@Component({\n standalone: true,\n imports: [CommonModule, DslPipe],\n selector: 'lh-navigation-layout-left-menu',\n templateUrl: 'navigation-layout-left-menu.component.html',\n})\nexport class NavigationLayoutLeftMenuComponent implements OnInit {\n @Input() sourceItem: string;\n @Input() itemsParent: string;\n item: NavigationItem | null;\n readonly trackByText = trackByProp('text');\n\n constructor(\n private menuActionsService: MenuActionsService,\n public navigationLayoutService: NavigationLayoutService,\n ) {}\n\n ngOnInit(): void {\n this.item = this.navigationLayoutService.getItem(this.sourceItem ? this.sourceItem : this.itemsParent);\n }\n\n processClick(event: Event, item: MenuContentItem) {\n this.menuActionsService.processClick(event, item, 'LeftNavigation');\n }\n}\n","import { Directive, Input, OnInit, inject } from '@angular/core';\n\nimport { MenuActionsService, MenuContentItem, TimerService, trackByProp } from '@frontend/vanilla/core';\nimport { AccountMenuDataService } from '@frontend/vanilla/shared/account-menu';\n\nimport { NavigationItem } from './models';\nimport { NavigationLayoutService } from './navigation-layout.service';\n\n@Directive()\nexport class NavigationLayoutTopMenuBaseComponent implements OnInit {\n @Input() item: NavigationItem | null;\n readonly trackByText = trackByProp('text');\n\n private menuActionsService = inject(MenuActionsService);\n private accountMenuService = inject(AccountMenuDataService);\n private navigationLayoutService = inject(NavigationLayoutService);\n\n get topMenuItems(): MenuContentItem[] {\n return this.accountMenuService.topMenuItems;\n }\n\n constructor(private timerService: TimerService) {}\n\n ngOnInit() {\n if (this.navigationLayoutService.isV1orV4) {\n this.navigationLayoutService.showTopMenu.subscribe((s: NavigationItem | null) => this.timerService.setTimeout(() => (this.item = s)));\n }\n }\n\n processClick(event: Event, item: MenuContentItem) {\n this.menuActionsService.processClick(event, item, 'TopNavigation');\n }\n}\n","@if (topMenuItems) {\n \n}\n","import { CommonModule } from '@angular/common';\nimport { Component } from '@angular/core';\n\nimport { TimerService } from '@frontend/vanilla/core';\n\nimport { NavigationLayoutTopMenuBaseComponent } from './navigation-layout-top-menu-base.component';\n\n/**\n * @stable\n */\n@Component({\n standalone: true,\n imports: [CommonModule],\n selector: 'lh-navigation-layout-top-menu-v2',\n templateUrl: 'navigation-layout-top-menu-v2.html',\n})\nexport class NavigationLayoutTopMenuV2Component extends NavigationLayoutTopMenuBaseComponent {\n constructor(timerService: TimerService) {\n super(timerService);\n }\n}\n","@if (version === 1 || version === 4) {\n
\n @if (!hideLeftSection) {\n
\n \n
\n }\n
\n \n
\n @if (!hideRightSection) {\n
\n \n
\n }\n
\n}\n@if (version === 2) {\n
\n \n @if (!hideMenu) {\n
\n \n
\n
\n \n
\n }\n
\n}\n@if (version === 3) {\n
\n @if (!hideMenu) {\n \n \n
\n }\n \n \n}\n@if (version === 5) {\n
\n @if (!hideMenu) {\n
\n \n \n @if (isProfilePage()) {\n \n } @else {\n
\n \n \n
\n }\n \n
\n }\n \n
\n}\n\n \n \n \n\n","import { BreakpointState } from '@angular/cdk/layout';\nimport { CommonModule, DOCUMENT } from '@angular/common';\nimport { AfterViewInit, Component, Input, OnDestroy, OnInit, Renderer2, ViewEncapsulation, inject, input } from '@angular/core';\n\nimport { ElementKeyDirective, ElementRepositoryService, MediaQueryService, TimerService, VanillaElements, WINDOW } from '@frontend/vanilla/core';\nimport { AccountMenuComponent } from '@frontend/vanilla/shared/account-menu';\nimport { Subject } from 'rxjs';\nimport { debounceTime, takeUntil } from 'rxjs/operators';\n\nimport { NavigationLayoutScrollService } from './navigation-layout-scroll.service';\nimport { NavigationLayoutService } from './navigation-layout.service';\n\n@Component({\n standalone: true,\n imports: [CommonModule, AccountMenuComponent, ElementKeyDirective],\n selector: 'lh-navigation-layout',\n templateUrl: 'navigation-layout.component.html',\n styleUrls: ['../../../../../themepark/themes/whitelabel/components/navigation-layout/styles.scss'],\n encapsulation: ViewEncapsulation.None,\n})\nexport class NavigationLayoutComponent implements OnInit, OnDestroy, AfterViewInit {\n @Input() bodyClass: string;\n @Input() hideLeftXs: boolean;\n @Input() hideRightXs: boolean;\n @Input() hideRightSection: boolean = false;\n @Input() sourceItem: string;\n @Input() hideLeftSection: boolean = false;\n @Input() hideMenu: boolean = false;\n @Input() scrolledToBottomPadding: number = 0; // To control when the scroll is considered at bottom\n @Input() version: number;\n @Input() mediaQueries: string[] = [];\n isProfilePage = input(false);\n\n height: string;\n isMediaQueryActive: boolean = false;\n VanillaElements = VanillaElements;\n\n private unsubscribe = new Subject();\n private onScrollSubject: Subject = new Subject();\n\n readonly #window = inject(WINDOW);\n private readonly _doc = inject(DOCUMENT);\n\n constructor(\n private renderer: Renderer2,\n private navigationLayoutService: NavigationLayoutService,\n private navigationLayoutScrollService: NavigationLayoutScrollService,\n private elementRepositoryService: ElementRepositoryService,\n private mediaQueryService: MediaQueryService,\n private timerService: TimerService,\n ) {}\n\n ngAfterViewInit() {\n if (this.version === 3 || this.version === 5) {\n this.timerService.setTimeout(() => {\n const containerTopOffset = this.elementRepositoryService.get('NAV_LAYOUT_CONTAINER')?.getBoundingClientRect().top || 0;\n this.height = `${this.#window.innerHeight - containerTopOffset}px`;\n });\n }\n\n this.onScrollSubject.pipe(debounceTime(300)).subscribe((element: HTMLElement) => {\n this.navigationLayoutScrollService.sendScrollEvent(element, this.scrolledToBottomPadding);\n });\n }\n\n ngOnInit() {\n switch (this.version) {\n case 5:\n case 3:\n if (this.mediaQueries.length > 0) {\n this.mediaQueryService\n .observe(this.mediaQueries)\n .pipe(takeUntil(this.unsubscribe))\n .subscribe((result: BreakpointState) => {\n this.isMediaQueryActive = result.matches;\n });\n }\n break;\n case 4:\n if (this.bodyClass) {\n this.renderer.addClass(this._doc.body, this.bodyClass);\n }\n const item = this.navigationLayoutService.getItem(this.sourceItem);\n this.hideLeftSection = this.hideLeftSection || !item || !item.leftMenuItems || item.leftMenuItems.length === 0;\n break;\n }\n }\n\n ngOnDestroy() {\n this.renderer.removeClass(this._doc.body, this.bodyClass);\n this.unsubscribe.next();\n this.unsubscribe.complete();\n }\n\n onScroll(event: Event) {\n const element = event.target as HTMLElement;\n this.onScrollSubject.next(element);\n }\n}\n","@if (version === 1 || version === 4) {\n
\n \n \n
\n

{{ item?.leftMenuTitle }}

\n \n
\n
\n @if (showTitle) {\n

{{ title ? title : item?.pageTitle }}

\n }\n \n
\n
\n \n
\n}\n@if (version === 2) {\n
\n \n
\n @if (headerImage) {\n \n } @else {\n \n }\n {{ user.displayName }}\n
\n \n \n \n @if (showTitle) {\n
{{ title ? title : item?.pageTitle }}
\n }\n @if (!hideTopMenu && showTopMenuItems) {\n \n }\n @if (showLoadingIndicator) {\n
\n {{ commonMessages.LoadingIndicatorFallbackMessage }}\n
\n }\n
\n
\n \n
\n
\n
\n
\n}\n@if (version === 3) {\n
\n \n \n \n \n \n \n
\n}\n\n@if (version === 5) {\n
\n \n \n \n \n @if (showTitle) {\n
{{ title ? title : item?.pageTitle }}
\n }\n @if (!hideTopMenu && showTopMenuItems) {\n \n }\n @if (showLoadingIndicator) {\n
\n {{ commonMessages.LoadingIndicatorFallbackMessage }}\n
\n }\n
\n \n
\n
\n \n \n \n}\n\n\n \n\n","import { CommonModule, DOCUMENT } from '@angular/common';\nimport { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, computed, inject, input } from '@angular/core';\n\nimport {\n AccountMenuService,\n CommonMessages,\n ContentImage,\n DynamicLayoutService,\n DynamicLayoutSlotComponent,\n EventsService,\n HeaderService,\n HtmlNode,\n MediaQueryService,\n MenuContentItem,\n NativeAppService,\n NativeEventType,\n NavigationService,\n Page,\n SimpleEvent,\n SlotName,\n TimerService,\n TrackingEventData,\n UserService,\n VanillaEventNames,\n WINDOW,\n toBoolean,\n} from '@frontend/vanilla/core';\nimport { FooterComponent } from '@frontend/vanilla/features/footer';\nimport { HeaderBarComponent, HeaderBarService, LhHeaderBarComponent } from '@frontend/vanilla/features/header-bar';\nimport { AccountMenuDataService } from '@frontend/vanilla/shared/account-menu';\nimport { IconCustomComponent } from '@frontend/vanilla/shared/icons';\nimport { Subject, combineLatest } from 'rxjs';\nimport { filter, first, takeUntil } from 'rxjs/operators';\n\nimport { NavigationItem } from './models';\nimport { NavigationLayoutLeftMenuComponent } from './navigation-layout-left-menu.component';\nimport { NavigationLayoutTopMenuV2Component } from './navigation-layout-top-menu-v2.component';\nimport { NavigationLayoutConfig } from './navigation-layout.client-config';\nimport { NavigationLayoutComponent } from './navigation-layout.component';\nimport { NavigationLayoutService } from './navigation-layout.service';\n\n/**\n * @stable\n */\nexport enum TopMenuVisibility {\n Never = 'Never',\n Always = 'Always',\n Desktop = 'Desktop',\n}\n\n/**\n * @whatItDoes This is the layout for all settings pages.\n *\n * @howToUse\n *\n * Create a page, add the settings page layout and set the content of the page.\n * ```\n * \n * Your page content\n * \n * ```\n *\n * @description\n *\n * This layout will add the top-settings-menu and left-settings-menu to the page.\n * It is responsive, when the page is in mobile view the menus are hidden and the header-bar will show.\n *\n * @stable\n */\n@Component({\n standalone: true,\n imports: [\n CommonModule,\n NavigationLayoutTopMenuV2Component,\n NavigationLayoutComponent,\n HeaderBarComponent,\n LhHeaderBarComponent,\n NavigationLayoutLeftMenuComponent,\n DynamicLayoutSlotComponent,\n IconCustomComponent,\n ],\n selector: 'lh-navigation-layout-page',\n templateUrl: 'navigation-layout-page.component.html',\n host: {\n '[class.ch]': 'version === 5',\n },\n})\nexport class NavigationLayoutPageComponent implements OnInit, OnChanges, OnDestroy {\n /** Source navigation item name configured in sitecore */\n @Input() sourceItem: string;\n /** Allows to hide close button in the header (mobile view). */\n @Input() hideCloseButton: boolean;\n /** Allows to add right section (desktop view). */\n @Input() showRightSection: boolean = false;\n /** Allows showing/hiding of title in desktop view */\n @Input() showTitle: boolean = true;\n /** Page Title. If not set, it will use sourceItem's text property */\n @Input() title?: string;\n /** Allows back button to be hidden when used in responsive view */\n @Input() hideBackButton: boolean = false;\n /** Top menu visibility. Supported values 'Always', 'Never', 'Desktop' */\n @Input() topMenuVisibility: string = TopMenuVisibility.Always;\n /** Top menu visibility. Supported values 'Always', 'Never', 'Desktop' */\n @Input() contentContainerClassV2: string = 'portal-center-wrapper';\n /** Allows manual highlighting of item in product switcher */\n @Input() highlightProduct: string;\n /** Allows to hide left menu (desktop view). */\n @Input() hideLeftMenu: boolean = false;\n /** Allows to hide menu (desktop view) on v2. */\n @Input() hideMenu: boolean = false;\n /** Allows to suppress default close button behaviour */\n @Input() suppressDefaultCloseBehaviour: boolean = false;\n /** Allows to suppress default back button behaviour */\n @Input() suppressDefaultBackBehaviour: boolean = false;\n /** Allows to show loading indicator */\n @Input() showLoadingIndicator: boolean = false;\n /** Allows to control when the scroll for `lh-navigation-layout` content is considered at bottom */\n @Input() scrolledToBottomPadding: number = 10;\n /** Indicates if rendered page is profile page */\n isProfilePage = input(false);\n /** Indicates if footer should be moved to navigation layout slot for version 3 and 5 */\n swapFooterComponent = input(true);\n /** Indicates if confirmation popup should be shown when leaving the page */\n showConfirmPopup = input(false);\n /** Data to be tracked when confirm popup is opened */\n confirmPopupTrackLoad = input();\n /** Data to be tracked when button is clicked in confirm popup */\n confirmPopupTrackClick = input();\n /** Data to be tracked when back is clicked */\n trackBackClickEvent = input();\n /** Data to be tracked when close is clicked */\n trackCloseClickEvent = input();\n /** Specifies callback when back button is clicked */\n @Output() onBack: EventEmitter = new EventEmitter();\n /** Specifies callback when close button is clicked */\n @Output() onClose: EventEmitter = new EventEmitter();\n\n item: NavigationItem | null;\n version: number;\n headerImage: ContentImage | undefined;\n headerEnabled: boolean;\n mediaQueries: string[] = [];\n titleClass: string = 'px-4 text-dark h';\n\n SlotName = SlotName;\n\n private shouldSwapFooter = computed(() => this.swapFooterComponent() && (this.version === 3 || this.version === 5));\n private unsubscribe = new Subject();\n\n readonly #window = inject(WINDOW);\n private readonly _doc = inject(DOCUMENT);\n\n constructor(\n public navigation: NavigationService,\n public commonMessages: CommonMessages,\n public user: UserService,\n private navigationLayoutService: NavigationLayoutService,\n private config: NavigationLayoutConfig,\n private headerService: HeaderService,\n private accountMenuDataService: AccountMenuDataService,\n private accountMenuService: AccountMenuService,\n private htmlNode: HtmlNode,\n private headerBarService: HeaderBarService,\n private nativeApplication: NativeAppService,\n private page: Page,\n private media: MediaQueryService,\n private dynamicLayoutService: DynamicLayoutService,\n private timerService: TimerService,\n private eventsService: EventsService,\n ) {}\n\n get hideTopMenu(): boolean {\n if (this.version === 2 && this.isMobile) return true;\n if (this.topMenuVisibility === TopMenuVisibility.Never) return true;\n if (this.topMenuVisibility === TopMenuVisibility.Desktop) return this.isMobile;\n\n return false;\n }\n\n get showTopMenuItems() {\n return this.item?.topMenuItems && this.item.topMenuItems.length > 1;\n }\n\n private get isMobile(): boolean {\n return this.media.isActive('xs');\n }\n\n ngOnInit() {\n combineLatest([\n this.accountMenuService.whenReady,\n this.config.whenReady,\n this.navigationLayoutService.initialized.pipe(filter((e) => e)),\n ]).subscribe(() => {\n this.mediaQueries = this.config.leftMenuEnabledOnCustomerHub;\n this.versionBasedInit();\n this.accountMenuDataService.content.pipe(takeUntil(this.unsubscribe)).subscribe(() => {\n this.versionBasedInit();\n });\n if (this.version === 1 || this.version === 4) {\n this.setTitleCssClass();\n }\n\n if (this.shouldSwapFooter()) {\n this.eventsService.allEvents\n .pipe(\n filter((e: SimpleEvent) => e?.eventName === VanillaEventNames.FooterLoaded),\n first(),\n )\n .subscribe(() => this.dynamicLayoutService.swap(SlotName.Footer, SlotName.NavLayoutFooter, FooterComponent));\n }\n if (this.highlightProduct) {\n this.timerService.setTimeout(() => this.headerService.highlightProduct(this.highlightProduct));\n }\n\n this.navigationLayoutService.headerEnabled.pipe(takeUntil(this.unsubscribe)).subscribe((enabled) => {\n this.headerEnabled = enabled;\n });\n });\n }\n\n ngOnChanges(changes: SimpleChanges) {\n //Force reinit when sourceItem is changed for same route (e.g cashier pages on iframe)\n if (!changes.sourceItem?.firstChange && changes.sourceItem?.currentValue != changes.sourceItem?.previousValue) {\n this.ngOnInit();\n }\n }\n\n ngOnDestroy() {\n this.accountMenuService.whenReady.subscribe(() => this.accountMenuService.setActiveItem(''));\n this.htmlNode.setCssClass('navigation-layout-open', false);\n this.navigationLayoutService.showTopMenu.next(null);\n\n if (this.highlightProduct) {\n this.timerService.setTimeout(() => this.headerService.highlightProduct(null));\n }\n\n if (this.shouldSwapFooter()) {\n this.dynamicLayoutService.swap(SlotName.NavLayoutFooter, SlotName.Footer, FooterComponent);\n }\n\n this.unsubscribe.next();\n this.unsubscribe.complete();\n }\n\n setTitleCssClass() {\n const data = this.config.elements;\n if (data) {\n const titleItem = Object.keys(data).find((key) => data[key]?.text === 'theme-names') || null;\n\n if (titleItem != null) {\n this.titleClass =\n data[titleItem]?.parameters[this.page.theme]?.toString() || data[titleItem]?.parameters.default?.toString() || 'px-4 text-dark h';\n }\n }\n }\n\n back() {\n this.onBack.next(null);\n\n if (!this.suppressDefaultBackBehaviour) {\n if (this.accountMenuDataService.routerModeReturnUrl || this._doc.referrer) {\n this.#window.history.back();\n } else if (this.item && this.item.parent) {\n this.navigation.goTo('/settings/navigation/' + this.item.parent.name, { isBackNavigation: true });\n return;\n } else {\n this.navigation.goToLastKnownProduct();\n }\n }\n }\n\n close() {\n if (this.onClose.observers.length > 0) {\n this.onClose.emit();\n }\n\n if (!this.suppressDefaultCloseBehaviour) {\n this.headerBarService.close();\n }\n\n this.nativeApplication.sendToNative({\n eventName: NativeEventType.PAGECLOSED,\n parameters: { product: this.page.product },\n });\n }\n\n private versionBasedInit() {\n this.version = this.accountMenuDataService.version;\n\n if (this.version === 2 || this.version === 3 || this.version === 5) {\n this.htmlNode.setCssClass('navigation-layout-open', true);\n this.headerImage = this.config.elements.header?.image;\n const sourceItem = this.accountMenuDataService.getItem(this.sourceItem?.toLowerCase());\n\n if (sourceItem) {\n const menuItem = this.getMenuItem(sourceItem);\n\n if (!this.accountMenuService.routerMode) {\n this.accountMenuService.setActiveItem(menuItem.parameters['active-item'] || menuItem.name);\n }\n\n this.item = {\n pageTitle: this.hideTopMenu ? sourceItem.text : menuItem.text,\n headerTitle: sourceItem.text,\n selectedTopItem: sourceItem.name,\n topMenuItems: menuItem.children,\n } as NavigationItem;\n\n this.accountMenuDataService.topItemsLoaded.next(this.item.topMenuItems);\n }\n } else {\n this.item = this.navigationLayoutService.getItem(this.sourceItem);\n\n if (!this.item) {\n return;\n }\n\n if (!this.hideTopMenu) {\n this.navigationLayoutService.showTopMenu.next(this.item);\n }\n\n this.hideLeftMenu = this.hideLeftMenu || !this.item.leftMenuItems || this.item.leftMenuItems.length === 0;\n this.hideBackButton =\n this.hideBackButton || (!this.accountMenuDataService.routerModeReturnUrl && !this._doc.referrer && this.item.parent === null);\n }\n }\n\n private findParent(object: any, item: string, parent: string | null): any {\n if (object.hasOwnProperty(item.toLowerCase())) {\n return parent;\n }\n\n for (const property of Object.keys(object)) {\n if (object[property]) {\n const parent = this.findParent(object[property], item, property);\n\n if (parent) {\n return parent;\n }\n }\n }\n }\n\n private getMenuItem(sourceItem: MenuContentItem): MenuContentItem {\n let item: MenuContentItem | null = sourceItem;\n\n do {\n if (toBoolean(item.parameters.highlightable)) {\n return item;\n }\n\n const parentItem = this.findParent(this.accountMenuDataService.hierarchy, item.name, null);\n item = this.accountMenuDataService.getItem(parentItem);\n } while (item);\n\n throw new Error(`Cant find parent menu item of ${sourceItem.name}.`);\n }\n}\n","@if (item && item.topMenuItems) {\n \n}\n","import { CommonModule } from '@angular/common';\nimport { Component, ViewEncapsulation } from '@angular/core';\n\nimport { TimerService } from '@frontend/vanilla/core';\nimport { DslPipe } from '@frontend/vanilla/shared/browser';\n\nimport { NavigationLayoutTopMenuBaseComponent } from './navigation-layout-top-menu-base.component';\n\n/**\n * @stable\n */\n@Component({\n standalone: true,\n imports: [CommonModule, DslPipe],\n selector: 'lh-navigation-layout-top-menu',\n templateUrl: 'navigation-layout-top-menu.component.html',\n styleUrls: ['../../../../../themepark/themes/whitelabel/components/nav-main/styles.scss'],\n encapsulation: ViewEncapsulation.None,\n})\nexport class NavigationLayoutTopMenuComponent extends NavigationLayoutTopMenuBaseComponent {\n constructor(timerService: TimerService) {\n super(timerService);\n }\n}\n","import { inject } from '@angular/core';\n\nimport { AccountMenuConfig } from '@frontend/vanilla/shared/account-menu';\nimport { firstValueFrom } from 'rxjs';\n\nexport const darkModeGuard = async () => {\n const config = inject(AccountMenuConfig);\n await firstValueFrom(config.whenReady);\n return true;\n};\n","import { CommonModule } from '@angular/common';\nimport { Component, EventEmitter, OnInit, Output } from '@angular/core';\n\nimport { DsSwitch } from '@frontend/ui/switch';\nimport { CommonMessages, HtmlNode } from '@frontend/vanilla/core';\nimport { AccountMenuDataService } from '@frontend/vanilla/shared/account-menu';\nimport { DarkModeService } from '@frontend/vanilla/shared/dark-mode';\n\n/**\n * @stable\n */\n@Component({\n standalone: true,\n imports: [CommonModule, DsSwitch],\n selector: 'vn-dark-mode',\n templateUrl: 'dark-mode.html',\n})\nexport class DarkModeComponent implements OnInit {\n @Output() onChange = new EventEmitter();\n\n constructor(\n public content: CommonMessages,\n public service: DarkModeService,\n private accountMenuDataService: AccountMenuDataService,\n private htmlNode: HtmlNode,\n ) {}\n\n ngOnInit(): void {\n if (this.accountMenuDataService.version === 3) {\n this.htmlNode.setCssClass('navigation-layout-page-card', true);\n }\n }\n\n toggleDarkMode() {\n this.onChange.emit(!this.service.isEnabled);\n this.service.toggle();\n }\n}\n","
\n
\n \n
\n","import { CommonModule } from '@angular/common';\nimport { Component } from '@angular/core';\n\nimport { TrackingService } from '@frontend/vanilla/core';\n\nimport { NavigationLayoutPageComponent } from '../navigation-layout-page.component';\nimport { DarkModeComponent } from './dark-mode.component';\n\n/**\n * @stable\n */\n@Component({\n standalone: true,\n imports: [CommonModule, DarkModeComponent, NavigationLayoutPageComponent],\n selector: 'lh-navigation-layout-dark-mode',\n templateUrl: 'navigation-layout-dark-mode.component.html',\n})\nexport class NavigationLayoutDarkModeComponent {\n constructor(private trackingService: TrackingService) {}\n\n track(enabled: boolean) {\n this.trackingService.triggerEvent('Event.Tracking', {\n 'component.CategoryEvent': 'Night Mode',\n 'component.LabelEvent': 'Night Mode Settings Page',\n 'component.ActionEvent': `Turn Night Mode: ${enabled ? 'ON' : 'OFF'}`,\n 'component.PositionEvent': 'not applicable',\n 'component.LocationEvent': 'Settings Page',\n 'component.EventDetails': 'not applicable',\n 'component.URLClicked': 'not applicable',\n });\n }\n}\n","\n \n\n","import { Routes } from '@angular/router';\n\nimport { darkModeGuard } from './dark-mode.guard';\nimport { NavigationLayoutDarkModeComponent } from './navigation-layout-dark-mode.component';\n\nexport const DARKMODE_ROUTES: Routes = [\n {\n path: 'dark-mode',\n canActivate: [darkModeGuard],\n component: NavigationLayoutDarkModeComponent,\n },\n];\n","import { Component, OnDestroy, OnInit } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\n\nimport { HtmlNode } from '@frontend/vanilla/core';\nimport { CashierIframeComponent } from '@frontend/vanilla/features/cashier';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n\nimport { NavigationLayoutPageComponent } from './navigation-layout-page.component';\n\n/**\n * @stable\n */\n@Component({\n standalone: true,\n imports: [NavigationLayoutPageComponent, CashierIframeComponent],\n selector: 'lh-navigation-layout-cashier',\n templateUrl: 'navigation-layout-cashier.html',\n})\nexport class NavigationLayoutCashierComponent implements OnInit, OnDestroy {\n page: string;\n showLoadingIndicator: boolean = true;\n private unsubscribe = new Subject();\n\n constructor(\n private activatedRoute: ActivatedRoute,\n private htmlNode: HtmlNode,\n ) {}\n\n ngOnInit() {\n this.htmlNode.setCssClass('has-cashier-iframe', true);\n this.page = this.activatedRoute.snapshot.params['page'] || '';\n this.activatedRoute.params.pipe(takeUntil(this.unsubscribe)).subscribe((params) => {\n this.page = params['page'] || '';\n });\n }\n\n ngOnDestroy() {\n this.htmlNode.setCssClass('has-cashier-iframe', false);\n this.unsubscribe.next();\n this.unsubscribe.complete();\n }\n\n hideLoadingIndicator() {\n this.showLoadingIndicator = false;\n }\n}\n","\n \n\n","@if (item) {\n @if (isDesktop) {\n \n }\n @if (!isDesktop) {\n \n \n }\n}\n","import { CommonModule } from '@angular/common';\nimport { Component, OnDestroy, OnInit } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\n\nimport { MediaQueryService, NavigationService } from '@frontend/vanilla/core';\nimport { LhHeaderBarComponent } from '@frontend/vanilla/features/header-bar';\nimport { Subscription, filter } from 'rxjs';\n\nimport { NavigationItem } from './models';\nimport { NavigationLayoutLeftMenuComponent } from './navigation-layout-left-menu.component';\nimport { NavigationLayoutPageComponent } from './navigation-layout-page.component';\nimport { NavigationLayoutService } from './navigation-layout.service';\n\n@Component({\n standalone: true,\n imports: [CommonModule, NavigationLayoutLeftMenuComponent, LhHeaderBarComponent, NavigationLayoutPageComponent],\n selector: 'lh-navigation-layout-menu-page',\n templateUrl: 'navigation-layout-menu-page.component.html',\n})\nexport class NavigationLayoutMenuPageComponent implements OnInit, OnDestroy {\n item: NavigationItem | null;\n showHeader: boolean;\n isDesktop: boolean;\n private watcher: Subscription;\n\n constructor(\n private media: MediaQueryService,\n private navigationService: NavigationService,\n public navigationLayoutService: NavigationLayoutService,\n private activatedRoute: ActivatedRoute,\n ) {}\n\n ngOnInit() {\n this.navigationLayoutService.initialized.pipe(filter((isInitialized: boolean) => isInitialized)).subscribe(() => {\n const itemName = this.activatedRoute.snapshot.params['itemName'];\n this.item = this.navigationLayoutService.getItem(itemName);\n\n this.redirectToFirstMenuItem();\n this.watcher = this.media.observe().subscribe(() => {\n this.showHeader = this.media.isActive('xs');\n this.redirectToFirstMenuItem();\n });\n });\n }\n\n ngOnDestroy() {\n if (this.watcher) {\n this.watcher.unsubscribe();\n }\n }\n\n private redirectToFirstMenuItem() {\n this.isDesktop = this.media.isActive('gt-xs');\n\n if (this.isDesktop && this.item) {\n this.navigationService.goTo(this.item.leftMenuItems[0]!.url);\n }\n }\n}\n","import { Routes } from '@angular/router';\n\nimport { routeData } from '@frontend/vanilla/core';\n\nimport { NavigationLayoutCashierComponent } from './navigation-layout-cashier.component';\nimport { NavigationLayoutMenuPageComponent } from './navigation-layout-menu-page.component';\n\nexport const NAVIGATIONLAYOUT_ROUTES: Routes = [\n {\n path: 'cashier/:page',\n component: NavigationLayoutCashierComponent,\n data: routeData({ authorized: true }),\n },\n {\n path: 'navigation/:itemName', // note: not sure if this one is needed anymore\n component: NavigationLayoutMenuPageComponent,\n data: routeData({ authorized: true }),\n },\n];\n","import { Injectable } from '@angular/core';\n\nimport { DynamicLayoutService, OnFeatureInit, SingleSlot, SlotName, SlotType } from '@frontend/vanilla/core';\nimport { firstValueFrom } from 'rxjs';\n\nimport { NavigationLayoutTopMenuComponent } from './navigation-layout-top-menu.component';\nimport { NavigationLayoutConfig } from './navigation-layout.client-config';\nimport { NavigationLayoutService } from './navigation-layout.service';\n\n@Injectable()\nexport class NavigationLayoutBootstrapService implements OnFeatureInit {\n constructor(\n private config: NavigationLayoutConfig,\n private navigationLayoutService: NavigationLayoutService,\n private dynamicLayoutService: DynamicLayoutService,\n ) {}\n\n async onFeatureInit() {\n await firstValueFrom(this.config.whenReady);\n\n this.navigationLayoutService.init();\n\n if (this.navigationLayoutService.isV1orV4) {\n const headerSubNavSlot = this.dynamicLayoutService.getSlot(SlotName.HeaderSubNav, SlotType.Single);\n\n if (!headerSubNavSlot.component) {\n this.dynamicLayoutService.setComponent(SlotName.HeaderSubNav, NavigationLayoutTopMenuComponent, null);\n }\n }\n }\n}\n","import { runOnFeatureInit } from '@frontend/vanilla/core';\n\nimport { NavigationLayoutBootstrapService } from './navigation-layout-bootstrap.service';\n\nexport function provide() {\n return [runOnFeatureInit(NavigationLayoutBootstrapService)];\n}\n","@if (item) {\n @if (accountMenuDataService.version === 5) {\n
\n \n \n
\n } @else if (accountMenuDataService.version === 3) {\n
\n \n
\n @for (child of item.children; track trackByText($index, child)) {\n @if (useFastIconType) {\n \n } @else {\n \n }\n }\n
\n
\n }\n}\n","import { CommonModule } from '@angular/common';\nimport { Component, Input, OnInit, inject } from '@angular/core';\n\nimport { MenuContentItem, MenuDisplayMode, MenuSection, Page, TrackingService, UtilsService, trackByProp } from '@frontend/vanilla/core';\nimport { MenuItemComponent } from '@frontend/vanilla/features/menus';\nimport { AccountMenuDataService, AccountMenuTasksService } from '@frontend/vanilla/shared/account-menu';\n\n@Component({\n standalone: true,\n imports: [CommonModule, MenuItemComponent],\n selector: 'vn-common-actions-card',\n templateUrl: 'common-actions-card.html',\n})\nexport class CommonActionsCardComponent implements OnInit {\n @Input() item: MenuContentItem;\n\n accountMenuDataService = inject(AccountMenuDataService);\n MenuSection = MenuSection;\n readonly trackByText = trackByProp('text');\n private accountMenuTasksService = inject(AccountMenuTasksService);\n private trackingService = inject(TrackingService);\n private pageConfig = inject(Page);\n get useFastIconType(): boolean {\n return this.pageConfig.htmlSourceTypeReplace\n ? UtilsService.indexableTypeContainsKey(this.pageConfig.htmlSourceTypeReplace, 'navigation-layout')\n : false;\n }\n ngOnInit() {\n this.trackingService.triggerEvent('contentView', {\n 'component.CategoryEvent': 'my profile',\n 'component.LabelEvent': 'my hub',\n 'component.ActionEvent': 'load',\n 'component.PositionEvent': `pending tasks ${this.accountMenuTasksService.totalCount} - urgent tasks ${this.accountMenuTasksService.totalUrgentCount}`,\n 'component.LocationEvent': 'my hub page',\n 'component.EventDetails': 'my common actions section',\n 'component.URLClicked': 'not applicable',\n });\n }\n\n protected readonly MenuDisplayMode = MenuDisplayMode;\n}\n","@if (item) {\n
\n
\n @if (!item.image) {\n \n }\n @if (item.image; as image) {\n \n }\n
\n
\n \n \n
\n
\n}\n","import { CommonModule } from '@angular/common';\nimport { Component, Input, OnInit } from '@angular/core';\n\nimport { MenuActionsService, MenuContentItem, TrackingService } from '@frontend/vanilla/core';\nimport { TrustAsHtmlPipe } from '@frontend/vanilla/shared/browser';\nimport { IconCustomComponent } from '@frontend/vanilla/shared/icons';\nimport { ImageComponent } from '@frontend/vanilla/shared/image';\n\n@Component({\n standalone: true,\n imports: [CommonModule, TrustAsHtmlPipe, ImageComponent, IconCustomComponent],\n selector: 'vn-help-card',\n templateUrl: 'help-card.html',\n})\nexport class HelpCardComponent implements OnInit {\n @Input() item: MenuContentItem;\n\n constructor(\n private menuActionsService: MenuActionsService,\n private trackingService: TrackingService,\n ) {}\n\n ngOnInit() {\n this.trackingService.triggerEvent('contentView', {\n 'component.CategoryEvent': 'my profile',\n 'component.LabelEvent': 'my hub',\n 'component.ActionEvent': 'load',\n 'component.PositionEvent': 'not applicable',\n 'component.LocationEvent': 'my hub page',\n 'component.EventDetails': 'help & contact section',\n 'component.URLClicked': 'not applicable',\n });\n }\n\n itemClick(event: Event, item: MenuContentItem, origin: string) {\n this.menuActionsService.processClick(event, item, origin);\n }\n}\n","@if (item) {\n
\n
\n
\n
\n
\n
\n \n
\n
\n}\n","import { CommonModule } from '@angular/common';\nimport { Component, Input, OnDestroy, OnInit } from '@angular/core';\n\nimport { InboxService, MenuContentItem, TrackingService } from '@frontend/vanilla/core';\nimport { MenuItemComponent } from '@frontend/vanilla/features/menus';\nimport { AccountMenuTasksService } from '@frontend/vanilla/shared/account-menu';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n\n@Component({\n standalone: true,\n imports: [MenuItemComponent, CommonModule],\n selector: 'vn-inbox-card',\n templateUrl: 'inbox-card.html',\n})\nexport class InboxCardComponent implements OnInit, OnDestroy {\n @Input() item: MenuContentItem;\n inboxMessagesText: string | undefined;\n private unsubscribe = new Subject();\n\n constructor(\n private inboxService: InboxService,\n private accountMenuTasksService: AccountMenuTasksService,\n private trackingService: TrackingService,\n ) {}\n\n ngOnInit() {\n this.inboxService.whenReady.subscribe(() => {\n this.inboxService.count.pipe(takeUntil(this.unsubscribe)).subscribe((count: number) => {\n this.inboxMessagesText = this.item.resources['Text']!.replace('_COUNT_', (count || 0).toString());\n });\n });\n\n this.trackingService.triggerEvent('contentView', {\n 'component.CategoryEvent': 'my profile',\n 'component.LabelEvent': 'my hub',\n 'component.ActionEvent': 'load',\n 'component.PositionEvent': `pending tasks ${this.accountMenuTasksService.totalCount} - urgent tasks ${this.accountMenuTasksService.totalUrgentCount}`,\n 'component.LocationEvent': 'my hub page',\n 'component.EventDetails': 'my inbox section',\n 'component.URLClicked': 'not applicable',\n });\n }\n\n ngOnDestroy() {\n this.unsubscribe.next();\n this.unsubscribe.complete();\n }\n}\n","import { Injectable } from '@angular/core';\n\nimport {\n CookieDBService,\n CookieList,\n CookieName,\n DslService,\n MenuContentItem,\n UserLogoutEvent,\n UserService,\n UserSessionExpiredEvent,\n} from '@frontend/vanilla/core';\nimport { AccountMenuDataService } from '@frontend/vanilla/shared/account-menu';\nimport { ReplaySubject } from 'rxjs';\nimport { filter } from 'rxjs/operators';\n\n/** @stable */\n@Injectable({\n providedIn: 'root',\n})\nexport class ProfilePageNudgesService {\n displayItems: ReplaySubject = new ReplaySubject();\n private items: MenuContentItem[] = [];\n private db: CookieList;\n\n constructor(\n private accountMenuDataService: AccountMenuDataService,\n private user: UserService,\n dslService: DslService,\n cookieDBService: CookieDBService,\n ) {\n this.db = cookieDBService.createList(CookieName.AmHiddenNudges);\n const item = this.accountMenuDataService.getItem('nudges');\n\n if (!item) return;\n\n dslService.evaluateContent(item.children).subscribe((items: MenuContentItem[]) => {\n this.items = items;\n this.refreshItems();\n });\n\n this.user.events\n .pipe(filter((e) => e instanceof UserSessionExpiredEvent || e instanceof UserLogoutEvent))\n .subscribe(() => this.db.deleteAll());\n }\n\n /** Hides nudges item. */\n hide(item: MenuContentItem) {\n this.db.insert(item.name);\n this.refreshItems();\n }\n\n private refreshItems() {\n this.displayItems.next(this.items.filter((t) => !this.db.getAll().includes(t.name)));\n }\n}\n","@if (items.length) {\n @for (child of items; track trackByText($index, child)) {\n \n }\n}\n","import { CommonModule } from '@angular/common';\nimport { Component, OnDestroy, OnInit } from '@angular/core';\n\nimport { DynamicHtmlDirective, MenuContentItem, TrackingService, trackByProp } from '@frontend/vanilla/core';\nimport { TrustAsHtmlPipe } from '@frontend/vanilla/shared/browser';\nimport { IconCustomComponent } from '@frontend/vanilla/shared/icons';\nimport { Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\n\nimport { ProfilePageNudgesService } from './profile-page-nudges.service';\n\n@Component({\n standalone: true,\n imports: [CommonModule, TrustAsHtmlPipe, DynamicHtmlDirective, IconCustomComponent],\n selector: 'vn-profile-page-nudges',\n templateUrl: 'profile-page-nudges.html',\n})\nexport class ProfilePageNudgesComponent implements OnInit, OnDestroy {\n items: MenuContentItem[] = [];\n private unsubscribe = new Subject();\n readonly trackByText = trackByProp('text');\n\n constructor(\n private profilePageNudgesService: ProfilePageNudgesService,\n private trackingService: TrackingService,\n ) {}\n ngOnInit() {\n this.profilePageNudgesService.displayItems.pipe(takeUntil(this.unsubscribe)).subscribe((items) => {\n this.items = items;\n });\n\n this.trackingService.triggerEvent('contentView', {\n 'component.CategoryEvent': 'my profile',\n 'component.LabelEvent': 'my hub',\n 'component.ActionEvent': 'load',\n 'component.PositionEvent': 'not applicable',\n 'component.LocationEvent': 'my hub page',\n 'component.EventDetails': 'dotted learning & onboarding section',\n 'component.URLClicked': 'not applicable',\n });\n }\n\n hide(item: MenuContentItem) {\n this.profilePageNudgesService.hide(item);\n }\n\n ngOnDestroy() {\n this.unsubscribe.next();\n this.unsubscribe.complete();\n }\n}\n","@if (accountMenuDataService.version === 3) {\n \n \n @if (accountMenuRoutesAvailable) {\n \n }\n @if (help) {\n \n }\n \n} @else if (accountMenuDataService.version === 5) {\n \n
\n @if (content) {\n
{{ content!.resources.Title }}
\n
{{ content!.resources.Description }}
\n }\n
\n @if (accountMenuRoutesAvailable) {\n @if (profilePageItemsPositionCount()) {\n
\n \n \n \n @if (inbox && inboxConfig.enabled) {\n \n }\n @if (commonActions) {\n \n }\n @if (help) {\n \n }\n
\n } @else {\n
\n
\n \n @if (commonActions) {\n \n }\n @if (inbox && inboxConfig.enabled) {\n \n }\n
\n
\n \n \n
\n
\n @if (help) {\n \n }\n }\n }\n
\n}\n","import { CommonModule } from '@angular/common';\nimport { Component, OnInit, computed, signal } from '@angular/core';\n\nimport { MenuContentItem, TrackingService, UserService } from '@frontend/vanilla/core';\nimport { InboxConfig } from '@frontend/vanilla/features/inbox';\nimport { AccountMenuComponent, AccountMenuDataService, AccountMenuTasksService } from '@frontend/vanilla/shared/account-menu';\nimport { first, firstValueFrom } from 'rxjs';\n\nimport { NavigationLayoutPageComponent } from '../navigation-layout-page.component';\nimport { CommonActionsCardComponent } from './common-actions-card.compontent';\nimport { HelpCardComponent } from './help-card.component';\nimport { InboxCardComponent } from './inbox-card.component';\nimport { ProfilePageNudgesComponent } from './profile-page-nudges.component';\n\n/**\n * @whatItDoes Displays the profile page a.k.a. Customer Hub page.\n *\n * @stable\n */\n@Component({\n standalone: true,\n imports: [\n CommonModule,\n AccountMenuComponent,\n CommonActionsCardComponent,\n HelpCardComponent,\n InboxCardComponent,\n ProfilePageNudgesComponent,\n NavigationLayoutPageComponent,\n ],\n selector: 'vn-profile-page',\n templateUrl: 'profile-page.html',\n})\nexport class ProfilePageComponent implements OnInit {\n readonly profilePageItemsPosition = signal<{ [key: string]: number }>(this.accountMenuDataService.profilePageItemsPosition);\n readonly profilePageItemsPositionCount = computed(() => Object.keys(this.profilePageItemsPosition()).length);\n accountMenuRoutesAvailable: boolean;\n\n constructor(\n public accountMenuDataService: AccountMenuDataService,\n public user: UserService,\n public inboxConfig: InboxConfig,\n private accountMenuTasksService: AccountMenuTasksService,\n private trackingService: TrackingService,\n ) {}\n\n get content(): MenuContentItem | null {\n return this.accountMenuDataService.getItem('profile');\n }\n\n get commonActions(): MenuContentItem | null {\n return this.accountMenuDataService.getItem('commonactions');\n }\n\n get inbox(): MenuContentItem | null {\n return this.accountMenuDataService.getItem('inboxcard');\n }\n\n get help(): MenuContentItem | null {\n return this.accountMenuDataService.getItem('helpcard');\n }\n\n async ngOnInit() {\n await firstValueFrom(this.inboxConfig.whenReady);\n\n this.accountMenuDataService.content.pipe(first()).subscribe(() => {\n this.accountMenuRoutesAvailable = true;\n });\n this.trackingService.triggerEvent('contentView', {\n 'component.CategoryEvent': 'my profile',\n 'component.LabelEvent': 'my hub',\n 'component.ActionEvent': 'load',\n 'component.PositionEvent': `pending tasks ${this.accountMenuTasksService.totalCount} - urgent tasks ${this.accountMenuTasksService.totalUrgentCount}`,\n 'component.LocationEvent': 'my hub page',\n 'component.EventDetails': 'my hub page',\n 'component.URLClicked': 'not applicable',\n });\n }\n}\n","import { inject } from '@angular/core';\n\nimport { AccountMenuConfig } from '@frontend/vanilla/shared/account-menu';\nimport { firstValueFrom } from 'rxjs';\n\nexport const profilePageGuard = async () => {\n const accountMenuConfig = inject(AccountMenuConfig);\n\n await firstValueFrom(accountMenuConfig.whenReady);\n\n return true;\n};\n","import { Routes } from '@angular/router';\n\nimport { routeData } from '@frontend/vanilla/core';\n\nimport { ProfilePageComponent } from './profile-page.component';\nimport { profilePageGuard } from './profile-page.guard';\n\nexport const PROFILEPAGE_ROUTES: Routes = [\n {\n path: '',\n component: ProfilePageComponent,\n data: routeData({ authorized: true }),\n canActivate: [profilePageGuard],\n },\n];\n","export class initDataModel {\n handHistoryContent: any;\n gameRoundMetaData: any;\n}\n\nexport class HandHistoryInputModel {\n RoundNumber: string;\n GameType: number;\n GameCodeType: number;\n LimitType: number;\n MonetaryType: number;\n MinStake: number;\n MaxStake: number;\n Time: Date;\n\n /* Player Actions */\n WonHand: boolean;\n AllIn: boolean;\n PreflopRaise: boolean;\n PreflopCall: boolean;\n ShowHand: boolean;\n RiverFold: boolean;\n WereKnockedOut: boolean;\n KnockedOutOthers: boolean;\n\n MinPotSize: number;\n FinalHandMatch: number;\n FinalHand: number;\n PocketCardSuited: boolean;\n PocketCardOne: string;\n PocketCardTwo: string;\n SearchDate: string;\n Page: number;\n\n SortAscending: boolean;\n SortBy: number;\n StakeType: number;\n BuyInType: number;\n\n //Tournament search\n MinBuyIn: number;\n MaxBuyIn: number;\n\n TournamentType: number;\n TournamentGameType: number;\n TournamentSearchDate: string;\n\n TournamentPocketCardSuited: boolean;\n TournamentPocketCardOne: string;\n TournamentPocketCardTwo: string;\n\n TournamentFinalHandMatch: number;\n TournamentFinalHand: number;\n\n TournamnetMinPotSize: number;\n}\n\nexport class HandHistoryRoundInputModel {\n RoundId: string;\n}\n","import { Injectable } from '@angular/core';\n\nimport { MessageQueueService } from '@frontend/vanilla/core';\nimport { PokerApiService } from '@pokercore/module/core';\nimport { Observable } from 'rxjs';\n\nimport { HandHistoryInputModel } from './hand-history.models';\n\n@Injectable({ providedIn: 'root' })\nexport class HandHistoryService {\n totalCount: number;\n allCgLimits: any;\n allCgActions: any;\n allTrActions: any;\n handHistory: any = {};\n cashGames: any;\n tournaments: any;\n gameTypeCG: any = 1;\n gameTypeTR: any = 1;\n content: any;\n popupToggle: boolean;\n replayHandPosition: number;\n filterGroupedHandsCG: boolean = false;\n filterHandsCG: boolean = false;\n filterGroupedHandsTR: boolean = false;\n filterHandsTR: boolean = false;\n lazyloading: boolean = false;\n singleHand: boolean = false;\n singleGameRound: any;\n nodataCG: boolean = false;\n nodataTR: boolean = false;\n hhGames: string = 'cashgames';\n TodayHandsCG: any = [];\n YesterdayHandsCG: any = [];\n Last7daysHandsCG: any = [];\n Last2weeksHandsCG: any = [];\n Last30daysHandsCG: any = [];\n Last3monthsHandsCG: any = [];\n TodayHandsTR: any = [];\n YesterdayHandsTR: any = [];\n Last7daysHandsTR: any = [];\n Last2weeksHandsTR: any = [];\n Last30daysHandsTR: any = [];\n Last3monthsHandsTR: any = [];\n singleHandStatus: boolean = false;\n activeHandID: any;\n PocketCardOneCG: string;\n PocketCardTwoCG: string;\n PocketCardOneTR: string;\n PocketCardTwoTR: string;\n lazyLoad: boolean = false;\n pageTR: number = 0;\n pageCG: number = 0;\n noHands: boolean = false;\n disableTextView: boolean;\n isLego: any;\n isMobile: boolean; //for mobile potraite replayer\n //isTablet: boolean;\n Idevices: boolean;\n showBottomNavForIdevice: boolean = true;\n isTenSeaterGame: boolean = false;\n showErrorMessage: boolean = false;\n handstoReplayerDashBoard: any = [];\n serverErrorpage: boolean = false;\n [key: string]: any;\n\n constructor(\n private api: PokerApiService,\n private messageQueue: MessageQueueService,\n ) {}\n\n getHandHistory(handHistoryInputModel: HandHistoryInputModel): Observable {\n return this.api.post('handhistory/GetInitData', handHistoryInputModel);\n }\n\n getPrimaryAssets() {\n return this.api.get('handhistory/GetPrimaryAssets');\n }\n\n getSecondaryAssets() {\n return this.api.get('handhistory/GetSecondaryAssets');\n }\n\n getRoundTextViewService(roundModel: any) {\n return this.api.post('handhistory/Round', roundModel);\n }\n\n getCashGamesActions(gameType: number) {\n return this.api.get('handhistory/GetActions', { gameType: gameType });\n }\n\n getCashGamesLimits(gameType: number) {\n return this.api.get('handhistory/GetLimits', { gameType: gameType });\n }\n\n getTournamentActions(gameType: string) {\n return this.api.get('handhistory/GetTournamentActions', { gameType: gameType });\n }\n\n getDate(time: number) {\n const dateValue: any = time;\n return dateValue.substring(6, 7) + '/' + dateValue.substring(9, 10) + '/' + dateValue.substring(0, 4);\n }\n\n getReplayer(roundId: string) {\n return this.api.get('handhistory/GetRoundDetails', { Id: roundId });\n }\n\n getTodayHands(handHistory: any) {\n let hands = handHistory.gameRounds,\n length = hands.length,\n currentDate,\n todayHandsCount = 0;\n currentDate = new Date();\n currentDate = currentDate.toLocaleDateString();\n for (let i = 0; i < length; i++) {\n const d = this.getDate(hands[i].gameRoundTime.start);\n if (d == currentDate) {\n todayHandsCount++;\n }\n }\n return todayHandsCount;\n }\n\n checkSuitedCards(holeCards: any) {\n const pocketCards: any = [],\n cardOneSet: any = [],\n cardTwoSet: any = [];\n if (this.hhGames === 'cashgames') {\n pocketCards.push(this.PocketCardOneCG, this.PocketCardTwoCG);\n } else {\n pocketCards.push(this.PocketCardOneTR, this.PocketCardTwoTR);\n }\n if (holeCards.length === 2 && holeCards[0].split('')[1] === holeCards[1].split('')[1]) {\n return true;\n } else if (holeCards.length > 2) {\n const hcardsLength = holeCards.length;\n for (let i = 0; i < hcardsLength - 1; i++) {\n for (let j = i + 1; j < hcardsLength; j++) {\n if (holeCards[i].split('')[1] === holeCards[j].split('')[1]) {\n return true;\n }\n }\n }\n }\n for (let i = 0; i < pocketCards.length; i++) {\n holeCards.forEach((hCard: string) => {\n const holeCard = hCard.split('')[0];\n if (pocketCards[i].indexOf(holeCard) > -1) {\n if (i === 0) {\n cardOneSet.push(hCard.split('')[1]);\n } else {\n cardTwoSet.push(hCard.split('')[1]);\n }\n }\n });\n }\n cardOneSet.forEach((cardOne: string) => {\n cardTwoSet.forEach((cardTwo: string) => {\n if (cardOne === cardTwo) {\n return true;\n } else {\n return false;\n }\n });\n });\n return false;\n }\n\n getTournaments() {\n const handHistoryInputModel: HandHistoryInputModel = new HandHistoryInputModel();\n handHistoryInputModel.TournamentPocketCardOne = 'XX';\n handHistoryInputModel.TournamentPocketCardTwo = 'XX';\n handHistoryInputModel.TournamentPocketCardSuited = false;\n handHistoryInputModel.TournamentFinalHand = 0;\n handHistoryInputModel.TournamentFinalHandMatch = 0;\n handHistoryInputModel.TournamentType = 0;\n handHistoryInputModel.TournamentGameType = 1;\n handHistoryInputModel.BuyInType = 0;\n handHistoryInputModel.TournamentSearchDate = 'All';\n handHistoryInputModel.Page = 0;\n handHistoryInputModel.SortAscending = false;\n handHistoryInputModel.SortBy = 0;\n handHistoryInputModel.GameCodeType = 2;\n handHistoryInputModel.WonHand = false;\n handHistoryInputModel.AllIn = false;\n handHistoryInputModel.PreflopRaise = false;\n handHistoryInputModel.PreflopCall = false;\n handHistoryInputModel.ShowHand = false;\n handHistoryInputModel.RiverFold = false;\n handHistoryInputModel.WereKnockedOut = false;\n handHistoryInputModel.KnockedOutOthers = false;\n\n this.getHandHistory(handHistoryInputModel).subscribe(\n (data) => {\n this.totalCount = data.gameRoundMetaData.totalCount;\n this.tournaments = data.gameRoundMetaData;\n this.groupRounds(this.tournaments, 'tournaments');\n },\n (error) => {\n this.messageQueue.clear();\n if (error.errorCode === '403') {\n this.messageQueue.add(error.vnMessages[0].html);\n } else if (!error.hasOwnProperty('errorCode')) {\n this.messageQueue.add(error.message);\n }\n },\n );\n }\n\n groupRounds(handHistory: any, hhGames: string) {\n let currentDate: any = new Date(),\n yesterdayDate: any = new Date(),\n last7Days: any = new Date(),\n last2Weeks: any = new Date(),\n last30Days: any = new Date(),\n last3Months: any = new Date(),\n todayHands: any = [],\n yesterdayHands: any = [],\n last7daysHands: any = [],\n last2weeksHands: any = [],\n last30daysHands: any = [],\n last3monthsHands: any = [],\n handsCount = 0, //this.initialHandCount,\n trimmedHands: any = [],\n totalHandsCount = 0;\n handHistory = handHistory.gameRounds;\n if (hhGames === 'cashgames' && this.pageCG > 0) {\n handsCount = this.pageCG * 100;\n } else if (hhGames === 'tournaments' && this.pageTR > 0) {\n handsCount = this.pageTR * 100;\n }\n if (!this.lazyLoad) {\n trimmedHands = handHistory.slice(0, handsCount + 50);\n } else {\n trimmedHands = handHistory.slice(0, handsCount + 100);\n }\n this.handstoReplayerDashBoard = trimmedHands;\n yesterdayDate.setDate(yesterdayDate.getDate() - 1);\n yesterdayDate = yesterdayDate.toLocaleDateString();\n last7Days.setDate(last7Days.getDate() - 6);\n last2Weeks.setDate(last2Weeks.getDate() - 13);\n last30Days.setDate(last30Days.getDate() - 29);\n last3Months.setDate(last3Months.getDate() - 89);\n for (let i = 0; i < trimmedHands.length; i++) {\n let dateValue = trimmedHands[i].gameRoundTime.start,\n handDate = trimmedHands[i].gameRoundTime.start,\n suitedElement: any,\n holeCards = trimmedHands[i].playerHoleCards,\n flag = false,\n handsDate: any = new Date(handDate),\n currentDateString = this.getCurrentDateString(currentDate.toLocaleDateString(), 'today'),\n yestarDateString = this.getCurrentDateString(currentDate.toLocaleDateString(), 'yestarday'),\n d = dateValue.substring(5, 7) + '/' + dateValue.substring(8, 10) + '/' + dateValue.substring(0, 4);\n if (hhGames === 'cashgames') {\n suitedElement = document.getElementById('pocketSuitedCG');\n } else {\n suitedElement = document.getElementById('pocketSuitedTR');\n }\n if (suitedElement && suitedElement.checked) {\n flag = this.checkSuitedCards(holeCards);\n } else {\n flag = true;\n }\n if (flag) {\n totalHandsCount++;\n if (d === currentDateString) {\n todayHands.push(trimmedHands[i]);\n } else if (d === yestarDateString) {\n yesterdayHands.push(trimmedHands[i]);\n } else if (\n handsDate.getMonth() == currentDate.getMonth() - 1 ||\n (currentDate.getMonth() == 0 && handsDate.getYear() === currentDate.getYear() - 1)\n ) {\n if (last7Days.getDate() <= handsDate.getDate() && last7Days.getMonth() == handsDate.getMonth()) {\n last7daysHands.push(trimmedHands[i]);\n } else if (last2Weeks.getDate() <= handsDate.getDate() && last2Weeks.getMonth() == handsDate.getMonth()) {\n last2weeksHands.push(trimmedHands[i]);\n } else if (last30Days.getDate() <= handsDate.getDate() && last30Days.getMonth() == handsDate.getMonth()) {\n last30daysHands.push(trimmedHands[i]);\n } else if (last30Days.getDate() > handsDate.getDate() && last30Days.getMonth() == handsDate.getMonth()) {\n last3monthsHands.push(trimmedHands[i]);\n }\n } else if (handsDate.getMonth() == currentDate.getMonth()) {\n if (handsDate.getDate() >= last7Days.getDate() && last7Days.getMonth() == handsDate.getMonth()) {\n last7daysHands.push(trimmedHands[i]);\n } else if (handsDate.getDate() <= last7Days.getDate() && last7Days.getMonth() != handsDate.getMonth()) {\n last7daysHands.push(trimmedHands[i]);\n } else if (handsDate.getDate() >= last2Weeks.getDate() && last2Weeks.getMonth() == handsDate.getMonth()) {\n last2weeksHands.push(trimmedHands[i]);\n } else if (handsDate.getDate() <= last2Weeks.getDate() && last2Weeks.getMonth() != handsDate.getMonth()) {\n last2weeksHands.push(trimmedHands[i]);\n } else if (handsDate.getDate() >= last30Days.getDate() && last30Days.getMonth() == handsDate.getMonth()) {\n last30daysHands.push(trimmedHands[i]);\n } else if (handsDate.getDate() <= last30Days.getDate() && last30Days.getMonth() != handsDate.getMonth()) {\n last30daysHands.push(trimmedHands[i]);\n }\n } else if (\n (handsDate.getMonth() <= currentDate.getMonth() - 2 && handsDate.getYear() == currentDate.getYear()) ||\n handsDate.getYear() < currentDate.getYear()\n ) {\n last3monthsHands.push(trimmedHands[i]);\n }\n }\n }\n if (hhGames === 'cashgames') {\n this.TodayHandsCG = todayHands;\n this.YesterdayHandsCG = yesterdayHands;\n this.Last7daysHandsCG = last7daysHands;\n this.Last2weeksHandsCG = last2weeksHands;\n this.Last30daysHandsCG = last30daysHands;\n this.Last3monthsHandsCG = last3monthsHands;\n } else if (hhGames === 'tournaments') {\n this.TodayHandsTR = todayHands;\n this.YesterdayHandsTR = yesterdayHands;\n this.Last7daysHandsTR = last7daysHands;\n this.Last2weeksHandsTR = last2weeksHands;\n this.Last30daysHandsTR = last30daysHands;\n this.Last3monthsHandsTR = last3monthsHands;\n }\n if (totalHandsCount === 0) {\n this.noHands = true;\n } else {\n this.noHands = false;\n }\n return totalHandsCount;\n }\n\n //Changes made for modifying the currentdate and yestarday\n\n getCurrentDateString(value: any, day: any) {\n let changedDate: any;\n let changedMonth: any;\n let changedYear: any;\n if (day === 'today') {\n if (value.substring(0, value.indexOf('/')).length === 1) {\n changedMonth = '0' + value.substring(0, value.indexOf('/'));\n } else {\n changedMonth = value.substring(0, value.indexOf('/'));\n }\n if (value.substring(value.indexOf('/') + 1, value.lastIndexOf('/')).length === 1) {\n changedDate = '0' + value.substring(value.indexOf('/') + 1, value.lastIndexOf('/'));\n } else {\n changedDate = value.substring(value.indexOf('/') + 1, value.lastIndexOf('/'));\n }\n } else if (day === 'yestarday') {\n if (value.substring(0, value.indexOf('/')).length === 1) {\n changedMonth = '0' + value.substring(0, value.indexOf('/'));\n } else {\n changedMonth = value.substring(0, value.indexOf('/'));\n }\n if (value.substring(value.indexOf('/') + 1, value.lastIndexOf('/')).length === 1) {\n changedDate = '0' + value.substring(value.indexOf('/') + 1, value.lastIndexOf('/'));\n const x: any = parseInt(changedDate);\n changedDate = x - 1;\n } else {\n changedDate = value.substring(value.indexOf('/') + 1, value.lastIndexOf('/'));\n const x: any = parseInt(changedDate);\n changedDate = x - 1;\n }\n }\n changedYear = value.substring(value.lastIndexOf('/') + 1, value.lastIndexOf('/') + 5);\n if (changedDate === 0) {\n return this.calculateChangeDate(changedDate, changedMonth, changedYear);\n }\n\n return changedMonth + '/' + changedDate + '/' + changedYear;\n }\n calculateChangeDate(changedDate: any, changedMonth: any, changedYear: any) {\n const array1: any = ['01', '02', '05', '07', '08', '10', '12'];\n const array2: any = ['04', '06', '09', '11'];\n const month: any = changedMonth;\n if (changedDate === 0) {\n array1.forEach((element: any) => {\n if (element === changedMonth) {\n changedDate = 31;\n }\n });\n } else if (changedMonth === '03' && changedDate === 1) {\n const year: any = parseInt(changedYear);\n if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {\n changedDate = 29;\n } else {\n changedDate = 28;\n }\n } else {\n array2.forEach((element: any) => {\n if (element === changedMonth) {\n changedDate = 30;\n }\n });\n }\n if (changedDate === 0 && month === '01') {\n changedMonth = '12';\n changedYear = parseInt(changedYear) - 1;\n } else {\n changedMonth = parseInt(changedMonth) - 1;\n if (changedMonth.toString().length === 1) {\n changedMonth = '0' + changedMonth.toString();\n }\n }\n return changedMonth + '/' + changedDate + '/' + changedYear;\n }\n}\n","
\n \n

{{ serve.content.messages.Filters }}

\n {{ serve.content.messages.Reset }}\n
\n
\n
\n
    \n
  • \n {{ serve.content.messages.CashGames }}\n
  • \n
  • \n {{ serve.content.messages.Tournaments }}\n
  • \n
\n
\n
\n \n
\n \n
  • \n \n {{ SearchDateTextCG }}\n \n \n
    \n
    \n \n

    {{ serve.content.messages.SearchDate }}

    \n {{ serve.content.messages.Reset }}\n
    \n
      \n \n {{ searchDate.text }}\n \n
    \n
    \n
  • \n
  • \n \n {{ ActionText }}\n \n \n
    \n
    \n \n

    {{ serve.content.messages.AllActions }}

    \n {{ serve.content.messages.Reset }}\n
    \n
      \n
    • \n \n {{ action.text }}\n
    • \n
    \n
    \n
  • \n
  • \n \n {{ StakeTypeTextCG }}\n \n \n
    \n
    \n \n

    {{ serve.content.messages.StakesBlinds }}

    \n

    {{ serve.content.messages.Antes }}

    \n {{ serve.content.messages.Reset }}\n
    \n \n \n {{ stakeType.text }}\n
  • \n \n \n \n {{ anteType.text }}\n \n \n
    \n \n
  • \n {{ PotRangeText\n }}{{ serve.content.messages.Any }} 0\">{{ potrangeCG }}\n
    \n
    \n \n
    \n
    \n
  • \n
  • \n {{ FinalHandText }}\n ( 0\">{{ FinalSelectedTextCG }} : {{ FinalHandTextCG }})\n
    \n
    \n
    \n \n

    {{ serve.content.messages.FinalHandCard }}

    \n {{ serve.content.messages.Reset }}\n
    \n
      \n \n \n {{ finalHand.text }}\n \n \n \n \n {{ finalHand.text }}\n \n \n
    \n

    {{ finalHandMatchText }}

    \n
      \n
    • \n \n
    • \n
    \n
    \n
    \n
  • \n
  • \n {{ PocketHandText }}\n
    \n
    \n
    \n \n

    {{ serve.content.messages.PocketHandCardOne }}

    \n

    {{ serve.content.messages.PocketHandCardTwo }}

    \n {{ serve.content.messages.Reset }}\n {{ serve.content.messages.Reset }}\n
    \n \n \n \n {{ pocketHand.text }}\n
  • \n
    \n \n \n {{ pocketHand.text }}\n \n \n \n \n \n \n {{ pocketHand.text }}\n \n \n \n \n {{ pocketHand.text }}\n \n \n \n \n \n \n {{ pocketHand.text }}\n \n \n