\r\n Due {{ milestone.timeToDueDtDescription }}\r\n
\r\n
\r\n
\r\n
\r\n On {{ milestone.milestoneDueDt }}\r\n
\r\n
\r\n
","import { Component, OnInit, OnDestroy, HostListener\r\n} from '@angular/core';\r\nimport * as moment from 'moment';\r\nimport { Title } from '@angular/platform-browser';\r\nimport { Subscription } from 'rxjs';\r\nimport { TabNotificationService } from '../../../services/notifications/tab-notification.service';\r\nimport { CourtOrderNotifyService } from '../../../services/notifications/court-order-notify.service';\r\nimport { WorkTracker } from 'app/shared/loading-pane';\r\nimport { FeatureLoggerService } from 'services';\r\nimport { UserInfoService } from '../../../services/user-info.service';\r\nimport { FocusCheck } from '../../shared/FocusCheck';\r\nimport { PersonaSwitcherService } from 'services/api/persona-switcher.service';\r\nimport { CourtOrderService } from 'services/court-order.service';\r\nimport { FeatureName } from \"api/website_enum\";\r\n// import { ToastrService } from 'ngx-toastr';\r\n\r\n@Component({\r\n selector: 'app-court-order',\r\n templateUrl: './court-order.component.html',\r\n styleUrls: ['./court-order.component.scss']\r\n})\r\nexport class CourtOrderComponent extends FocusCheck implements OnInit, OnDestroy {\r\n selectedTab: FeatureName;\r\n \r\n // This data is updated via notifications\r\n orderData: Api.SelectedCourtOrderData;\r\n\r\n // This is the data we will display in relation to pagination\r\n ordersToShow: Api.GroupedCourtOrders[];\r\n\r\n // The collection of orders that have been toggled to full view. This is just used to track what is/not open.\r\n selectedOrders: Api.CourtOrder[] = [];\r\n personaSwitcherSelectedUpn: string = null;\r\n tracker: WorkTracker;\r\n intervalSubscription: Subscription;\r\n tabNotificationSubscription: Subscription;\r\n courtOrderNotifySubscription: Subscription;\r\n personaChangedSubscription: Subscription;\r\n isDestroyed: boolean = false;\r\n officersUpn: string = '';\r\n\r\n // Pagination settings\r\n currentPageExpiryInThreeMonths: number = 0;\r\n pageSizeExpiryInThreeMonths: number = 10;\r\n orderCountExpiryInThreeMonths: number = 0;\r\n\r\n currentPageExpiryInSixMonths: number = 0;\r\n pageSizeExpiryInSixMonths: number = 10;\r\n orderCountExpiryInSixMonths: number = 0;\r\n\r\n courtOrderStyle: string = 'court-order';\r\n\r\n get expiryInThreeMonthsTabSelected(): boolean {\r\n return this.selectedTab && this.selectedTab === FeatureName.CourtOrders3Months\r\n }\r\n get expiryInSixMonthsTabSelected(): boolean {\r\n return this.selectedTab && this.selectedTab === FeatureName.CourtOrders6Months\r\n }\r\n get errorMsgAppSectionText(): string {\r\n return (this.expiryInThreeMonthsTabSelected ? 'court orders due in 3 months' : 'court orders due in 3 months');\r\n }\r\n get errorMsgHeaderText(): string {\r\n if(this.expiryInThreeMonthsTabSelected === true) return 'There are no children or young people with court orders expiring in the next 3 months.';\r\n\r\n if(!this.orderData.countOfOrdersMovedFromSubsequentToNextThreeMonths || this.orderData.countOfOrdersMovedFromSubsequentToNextThreeMonths === 0)\r\n {\r\n return 'There are no children or young people with court orders expiring between 3 to 6 months in the future.';\r\n }\r\n else if(this.orderData.countOfOrdersMovedFromSubsequentToNextThreeMonths === 1)\r\n {\r\n return 'There is one order expiring between 3 to 6 months in the future. This was moved to the 0 to 3 month tab to be shown with the associated child.';\r\n }\r\n else if(this.orderData.countOfOrdersMovedFromSubsequentToNextThreeMonths > 1 && \r\n this.orderData.countOfUniqueChildrenInNextThreeMonths === 1)\r\n {\r\n return 'There are ' + this.orderData.countOfOrdersMovedFromSubsequentToNextThreeMonths + ' orders expiring between 3 to 6 months in the future. These were moved to the 0 to 3 month tab to be shown with the associated child.';\r\n }\r\n else // > 1 moved and > 2 child\r\n {\r\n return 'There are ' + this.orderData.countOfOrdersMovedFromSubsequentToNextThreeMonths + ' orders expiring between 3 to 6 months in the future. These were moved to the 0 to 3 month tab to be shown with the associated children.';\r\n }\r\n }\r\n\r\n constructor(\r\n private titleService: Title,\r\n private tabNotificationService: TabNotificationService,\r\n private courtOrderNotifyService: CourtOrderNotifyService,\r\n private featureLogger: FeatureLoggerService,\r\n private personaSwitcherService: PersonaSwitcherService, \r\n private courtOrderService: CourtOrderService,\r\n private userInfoService: UserInfoService,\r\n // private toastr: ToastrService\r\n ) {\r\n super();\r\n this.tracker = new WorkTracker(true);\r\n this.officersUpn = userInfoService.upn();\r\n this.orderCountExpiryInThreeMonths = 0;\r\n this.orderCountExpiryInSixMonths = 0;\r\n this.titleService.setTitle('CS Portal - Dashboard');\r\n this.subscribeToPersonaChangedNotifications();\r\n }\r\n\r\n async ngOnInit(): Promise {\r\n this.updatePagedOrdersToShow();\r\n\r\n this.tabNotificationSubscription = this.tabNotificationService.selectedTabChanged.subscribe((tab) => {\r\n if (this.selectedTab != tab) {\r\n this.selectedTab = tab;\r\n this.updatePagedOrdersToShow();\r\n }\r\n });\r\n\r\n this.courtOrderNotifySubscription = this.courtOrderNotifyService.courtOrdersChanged.subscribe((orders) => {\r\n this.orderData = orders;\r\n this.updatePagedOrdersToShow();\r\n });\r\n }\r\n\r\n ngOnDestroy() {\r\n // Make sure the periodic api call is stopped.\r\n if (this.intervalSubscription) {\r\n this.intervalSubscription.unsubscribe();\r\n }\r\n if (this.tabNotificationSubscription) {\r\n this.tabNotificationSubscription.unsubscribe();\r\n }\r\n if (this.personaChangedSubscription) {\r\n this.personaChangedSubscription.unsubscribe();\r\n }\r\n\r\n this.isDestroyed = true;\r\n }\r\n\r\n haveStaff(): boolean {\r\n if(!!this.personaSwitcherSelectedUpn && this.personaSwitcherSelectedUpn != this.officersUpn)\r\n {\r\n // We are masquerading. Even if masquerading as a team leader, return false\r\n return false;\r\n }\r\n\r\n return this.orderData.officerHasStaff;\r\n }\r\n\r\n onPageChangedEvent(pageNumber: number)\r\n {\r\n if(this.expiryInThreeMonthsTabSelected)\r\n {\r\n this.currentPageExpiryInThreeMonths = pageNumber;\r\n }\r\n else \r\n {\r\n this.currentPageExpiryInSixMonths = pageNumber;\r\n }\r\n this.updatePagedOrdersToShow();\r\n }\r\n\r\n onPageSizeChangedEvent(pageSize: number)\r\n {\r\n if(this.expiryInThreeMonthsTabSelected)\r\n {\r\n this.pageSizeExpiryInThreeMonths = pageSize;\r\n }\r\n else \r\n {\r\n this.pageSizeExpiryInSixMonths = pageSize;\r\n }\r\n this.updatePagedOrdersToShow();\r\n }\r\n\r\n updatePagedOrdersToShow()\r\n {\r\n var pageSizeToUse = this.expiryInThreeMonthsTabSelected ? this.pageSizeExpiryInThreeMonths : this.pageSizeExpiryInSixMonths;\r\n var currentPageToUse = this.expiryInThreeMonthsTabSelected ? this.currentPageExpiryInThreeMonths : this.currentPageExpiryInSixMonths;\r\n var firstElToShow = pageSizeToUse * currentPageToUse;\r\n var lastElToShow = firstElToShow + pageSizeToUse;\r\n\r\n if(this.expiryInThreeMonthsTabSelected)\r\n {\r\n this.orderCountExpiryInThreeMonths = !!this.orderData && this.orderData.groupedOrders ? this.orderData.groupedOrders.length : 0;\r\n }\r\n else\r\n {\r\n this.orderCountExpiryInSixMonths = !!this.orderData && this.orderData.groupedOrders ? this.orderData.groupedOrders.length : 0;\r\n }\r\n\r\n // Update the values that are displayed. All data is already pre-loaded. Just paginate in-memory\r\n if(!this.orderData || !this.orderData.groupedOrders || this.orderData.groupedOrders.length < 1) \r\n {\r\n this.ordersToShow = []; \r\n }\r\n else\r\n {\r\n this.ordersToShow = this.orderData.groupedOrders.slice(firstElToShow, lastElToShow);\r\n }\r\n }\r\n\r\n trackBy(index: number, item: Api.CourtOrder) {\r\n return item.orderExpiryDtm;\r\n }\r\n\r\n // When court orders are of type ‘TAO’, ‘CAO’ or ‘TCO’ then do not present a ‘View More’ button.\r\n enableViewMore(courtOrder: Api.CourtOrder)\r\n {\r\n return this.courtOrderService.enableViewMore(courtOrder);\r\n }\r\n\r\n formatShortDate(date: string): string {\r\n return !!date\r\n ? moment(date)\r\n .local()\r\n .format('DD/MM/YYYY')\r\n : 'n/a';\r\n }\r\n\r\n nextMilestone(courtOrder: Api.CourtOrder)\r\n {\r\n return this.courtOrderService.getNextMilestone(courtOrder);\r\n }\r\n\r\n isEven(item: Api.GroupedCourtOrders): boolean {\r\n if (!this.orderData) return false;\r\n\r\n let index = this.orderData.groupedOrders.indexOf(item, 0);\r\n\r\n return index % 2 === 0;\r\n }\r\n \r\n // Add or remove the selected court order from the collection of orders that should be open\r\n\r\n // Add or remove the selected court order from the collection of orders that should be open\r\n toggleSelectCourtOrder(order: Api.CourtOrder): void {\r\n let matchedSelectedOrders = this.getMatchingSelectedCourtOrders(order);\r\n if (matchedSelectedOrders && matchedSelectedOrders.length > 0) {\r\n let foundOrder = matchedSelectedOrders[0];\r\n if (foundOrder) {\r\n const index = this.selectedOrders.indexOf(foundOrder, 0);\r\n if (index > -1) {\r\n // Selected and already shown. Close.\r\n this.selectedOrders.splice(index, 1);\r\n }\r\n return;\r\n }\r\n }\r\n\r\n // Selected and not yet shown. Show\r\n if(this.selectedTab === FeatureName.CourtOrders3Months)\r\n {\r\n this.featureLogger.logFeatureUsage(FeatureName.CourtOrders3MonthsShowMore);\r\n }\r\n else\r\n {\r\n this.featureLogger.logFeatureUsage(FeatureName.CourtOrders6MonthsShowMore);\r\n }\r\n this.selectedOrders.push(order);\r\n }\r\n\r\n private subscribeToPersonaChangedNotifications() {\r\n this.personaSwitcherService.enable();\r\n if (!this.personaChangedSubscription) {\r\n this.personaChangedSubscription = this.personaSwitcherService.currentPersonaUpnChanged.subscribe(async (upn) => {\r\n this.personaSwitcherSelectedUpn = upn; // When persona switcher is de-activated this will be called with a null upn\r\n this.clearSelectedOrders();\r\n this.updatePagedOrdersToShow();\r\n });\r\n }\r\n }\r\n\r\n private clearSelectedOrders() {\r\n this.selectedOrders = [];\r\n }\r\n\r\n isOrderSelected(order: Api.CourtOrder): boolean {\r\n if(!order || !this.selectedOrders) return false;\r\n let matches = this.getMatchingSelectedCourtOrders(order);\r\n return (matches && matches.length > 0);\r\n }\r\n\r\n getMatchingSelectedCourtOrders(order: Api.CourtOrder): Api.CourtOrder[] {\r\n if (!order || !this.selectedOrders) return null;\r\n\r\n let app = this;\r\n return this.selectedOrders.filter(o => app.ordersMatch(o, order));\r\n }\r\n\r\n ordersMatch(orderA: Api.CourtOrder, orderB: Api.CourtOrder): boolean\r\n {\r\n return (orderA.subjectChildId === orderB.subjectChildId \r\n && orderA.orderType === orderB.orderType \r\n && orderA.orderTypeDisplay === orderB.orderTypeDisplay \r\n && orderA.orderExpiryDtm === orderB.orderExpiryDtm);\r\n }\r\n\r\n @HostListener('window:beforeunload ', ['$event'])\r\n beforeUnload(event: any): void {\r\n this.ngOnDestroy();\r\n }\r\n}\r\n","
\r\n \r\n \r\n \r\n","\r\nimport { interval as observableInterval, Subscription } from 'rxjs';\r\nimport { Component, OnInit, OnDestroy, HostListener, EventEmitter, Input, Output } from '@angular/core';\r\nimport { homeVisitsSettings } from '../../../settings';\r\nimport { WorkTracker } from 'app/shared/loading-pane';\r\nimport { IdleDetectionService } from 'services';\r\nimport { FocusCheck } from '../../shared/FocusCheck';\r\nimport { FeatureName, filterDateRangeSummaryDescription } from \"api/website_enum\";\r\nimport { HomeVisitUpcomingCountNotifyService, HomeVisitOverdueCountNotifyService, TabNotificationService, PromiseNotifyService } from '../../../services/notifications';\r\n\r\n@Component({\r\n selector: 'app-home-visits-summary',\r\n templateUrl: './home-visits-summary.component.html',\r\n styleUrls: ['./home-visits-summary.component.scss']\r\n})\r\nexport class HomeVisitsSummaryComponent extends FocusCheck implements OnInit, OnDestroy {\r\n // 'haveHomeVisitsToDisplay' is used in 'hero' to determine whether to display the Home Visits Summary tile\r\n @Output() haveHomeVisitsToDisplay: EventEmitter = new EventEmitter();\r\n \r\n upcomingCountsHasError: boolean;\r\n overdueCountsHasError: boolean;\r\n overdueHomeVisitCount: number;\r\n childHomeVisitCount: number;\r\n dateRangeType: number;\r\n\r\n selectedTab: FeatureName;\r\n overdueVisits: FeatureName = FeatureName.OverdueVisits;\r\n upcomingVisits: FeatureName = FeatureName.UpcomingVisits;\r\n refreshIntervalInMilliseconds: number;\r\n userIsIdle: boolean = false;\r\n isDestroyed: boolean = false;\r\n\r\n overdueTracker: WorkTracker;\r\n upcomingTracker: WorkTracker;\r\n tabNotificationSubscription: Subscription;\r\n idleDetectionSubscription: Subscription;\r\n homeVisitUpcomingCountSubscription: Subscription;\r\n homeVisitOverdueCountSubscription: Subscription;\r\n promiseSubscription: Subscription;\r\n\r\n constructor(\r\n private tabNotificationService: TabNotificationService,\r\n private idleDetectionService: IdleDetectionService,\r\n private homeVisitUpcomingCountNotifyService: HomeVisitUpcomingCountNotifyService, \r\n private homeVisitOverdueCountNotifyService: HomeVisitOverdueCountNotifyService, \r\n private promiseNotifyService: PromiseNotifyService\r\n ) {\r\n super();\r\n this.refreshIntervalInMilliseconds = homeVisitsSettings.refreshIntervalInSeconds * 1000;\r\n this.overdueTracker = new WorkTracker(true);\r\n this.upcomingTracker = new WorkTracker(true);\r\n this.upcomingCountsHasError = false;\r\n this.overdueCountsHasError = false;\r\n\r\n this.subscribeToTabNotifications();\r\n this.subscribeToUpcomingHomeVisitCountChangeNotifications();\r\n this.subscribeToOverdueHomeVisitCountChangeNotifications();\r\n this.subscribeToPromiseNotifications();\r\n }\r\n\r\n async ngOnInit() {\r\n this.idleDetectionService.reset();\r\n this.idleDetectionSubscription = this.idleDetectionService.isIdleChanged.subscribe(isIdle => this.userIsIdle = isIdle);\r\n }\r\n\r\n get overdueVisitsTabSelected(): boolean {\r\n return !this.selectedTab || this.selectedTab === FeatureName.OverdueVisits\r\n }\r\n get upcomingVisitsTabSelected(): boolean {\r\n return this.selectedTab && this.selectedTab === FeatureName.UpcomingVisits\r\n }\r\n\r\n ngOnDestroy() {\r\n // Make sure the periodic api call is stopped.\r\n if (this.tabNotificationSubscription) {\r\n this.tabNotificationSubscription.unsubscribe();\r\n }\r\n if (this.idleDetectionSubscription) {\r\n this.idleDetectionSubscription.unsubscribe();\r\n }\r\n if (this.homeVisitUpcomingCountSubscription) {\r\n this.homeVisitUpcomingCountSubscription.unsubscribe();\r\n }\r\n if (this.homeVisitOverdueCountSubscription) {\r\n this.homeVisitOverdueCountSubscription.unsubscribe();\r\n }\r\n if (this.promiseSubscription) {\r\n this.promiseSubscription.unsubscribe();\r\n }\r\n\r\n this.idleDetectionService.ngOnDestroy();\r\n\r\n this.isDestroyed = true;\r\n }\r\n\r\n selectInfoPanel(panel: FeatureName) {\r\n this.tabNotificationService.ChangeSelectedTab(panel);\r\n }\r\n\r\n getUpcomingHomeVisitSummarySentence(): string {\r\n var suffix = filterDateRangeSummaryDescription(this.dateRangeType);\r\n if (this.childHomeVisitCount === 0) {\r\n return `No children or young people are due for a visit ${suffix}.`;\r\n }\r\n else if (this.childHomeVisitCount === 1) {\r\n return `1 child or young person is due for a visit ${suffix}.`;\r\n }\r\n else if (this.childHomeVisitCount > 1) {\r\n return `${this.childHomeVisitCount} children or young people are due for a visit ${suffix}.`;\r\n }\r\n else if (!this.childHomeVisitCount) {\r\n return `? children or young people are due for a visit ${suffix}.`;\r\n }\r\n }\r\n\r\n getOverdueVisitSummarySentence(): string {\r\n if (this.overdueHomeVisitCount === 0) {\r\n return 'No children or young people have a visit overdue.';\r\n }\r\n else if (this.overdueHomeVisitCount === 1) {\r\n return '1 child or young person has a visit overdue.';\r\n }\r\n else if (this.overdueHomeVisitCount > 1) {\r\n return `${this.overdueHomeVisitCount} children or young people have a visit overdue.`;\r\n }\r\n else if (!this.overdueHomeVisitCount) {\r\n return '? children or young people have a visit overdue.';\r\n }\r\n }\r\n\r\n private subscribeToUpcomingHomeVisitCountChangeNotifications() {\r\n if (!this.homeVisitUpcomingCountSubscription) {\r\n this.homeVisitUpcomingCountSubscription = this.homeVisitUpcomingCountNotifyService.upcomingVisitCountDataChanged.subscribe(async (countData) => {\r\n this.childHomeVisitCount = countData.recordCount;\r\n this.upcomingCountsHasError = countData.hasError;\r\n this.dateRangeType = countData.dateRangeType;\r\n // This allows the 'hero' component to show that we do/not have a home visit tile to show\r\n this.haveHomeVisitsToDisplay.emit(this.overdueHomeVisitCount > 0 || this.childHomeVisitCount > 0);\r\n });\r\n }\r\n }\r\n\r\n private subscribeToOverdueHomeVisitCountChangeNotifications() {\r\n if (!this.homeVisitOverdueCountSubscription) {\r\n this.homeVisitOverdueCountSubscription = this.homeVisitOverdueCountNotifyService.overdueVisitCountDataChanged.subscribe(async (countData) => {\r\n this.overdueHomeVisitCount = countData.recordCount;\r\n this.overdueCountsHasError = countData.hasError;\r\n // This allows the 'hero' component to show that we do/not have a home visit tile to show\r\n this.haveHomeVisitsToDisplay.emit(this.overdueHomeVisitCount > 0 || this.childHomeVisitCount > 0);\r\n });\r\n }\r\n }\r\n\r\n upcomingVisitsPromise: Api.HomeVisitPromise;\r\n overdueVisitsPromise: Api.HomeVisitPromise;\r\n private subscribeToPromiseNotifications()\r\n {\r\n if(!this.promiseSubscription)\r\n {\r\n this.promiseSubscription = this.promiseNotifyService.promiseTrackerChanged.subscribe(async (thePromise) => {\r\n if(thePromise.visitType == 'upcoming-visits')\r\n {\r\n if (this.upcomingVisitsPromise != thePromise) {\r\n this.upcomingVisitsPromise = thePromise;\r\n await this.upcomingTracker.track(this.upcomingVisitsPromise.thePromise);\r\n }\r\n }\r\n else if(thePromise.visitType == 'overdue-visits')\r\n {\r\n if (this.overdueVisitsPromise != thePromise) {\r\n this.overdueVisitsPromise = thePromise;\r\n await this.overdueTracker.track(this.overdueVisitsPromise.thePromise);\r\n }\r\n }\r\n });\r\n }\r\n }\r\n\r\n private subscribeToTabNotifications() {\r\n if(!this.tabNotificationSubscription)\r\n {\r\n this.tabNotificationSubscription = this.tabNotificationService.selectedTabChanged.subscribe((tab) => {\r\n if (this.selectedTab != tab) {\r\n this.selectedTab = tab;\r\n }\r\n });\r\n }\r\n }\r\n\r\n @HostListener('window:beforeunload ', ['$event'])\r\n beforeUnload(event: any): void {\r\n this.ngOnDestroy();\r\n }\r\n}","\r\n \r\n","export * from './hero.component';\r\nexport * from './activity-feed/activity-feed.component';\r\nexport * from './home-visits-summary/home-visits-summary.component';\r\nexport * from './court-order-summary/court-order-summary.component';\r\nexport * from './staff-whereabouts-summary/staff-whereabouts-summary.component';","import { Component, Input } from '@angular/core';\r\n\r\n@Component({\r\n selector: 'app-staff-whereabouts-summary',\r\n templateUrl: './staff-whereabouts-summary.component.html',\r\n styleUrls: ['./staff-whereabouts-summary.component.scss']\r\n})\r\nexport class StaffWhereaboutsSummaryComponent {\r\n @Input() staffCheckedOut: number;\r\n @Input() staffOverdueForCheckIn: number;\r\n\r\n getCheckedOutSentence(): string {\r\n if (this.staffCheckedOut === 0) {\r\n return 'There are no staff members currently checked out.';\r\n }\r\n else if (this.staffCheckedOut === 1) {\r\n return 'There is 1 staff member currently checked out.';\r\n }\r\n else if (this.staffCheckedOut > 1) {\r\n return `There are ${this.staffCheckedOut} staff members currently checked out.`;\r\n }\r\n else if (!this.staffCheckedOut) {\r\n return 'There are ? staff members currently checked out.';\r\n }\r\n }\r\n\r\n getOverdueForCheckinSentence(): string {\r\n if (this.staffCheckedOut === 0) {\r\n return 'There are no staff members currently overdue for check-in.';\r\n }\r\n else if (this.staffCheckedOut === 1) {\r\n return 'There is 1 staff member currently overdue for check-in.';\r\n }\r\n else if (this.staffCheckedOut > 1) {\r\n return `There are ${this.staffCheckedOut} staff members currently overdue for check-in.`;\r\n }\r\n else if (!this.staffCheckedOut) {\r\n return 'There are ? staff members currently overdue for check-in.';\r\n }\r\n }\r\n}\r\n","","import { HeroSection } from \"api/website_enum\";\r\n\r\n/*\r\n Note, we cannot use a simple count of tiles, current index and tiles per page to implement this pagination.\r\n This pagination will dynamically show or hide a tile based on whether it has data to present or not.\r\n Due to this, we use a tile type; see 'HeroSection'. The UI calls 'showTile' with its enumeration value.\r\n Only if this is present in 'allTiles' will we return true.\r\n The population of allTiles is driven by calls to: ensureTile and removeTile and is based \r\n on the results of calls to a backend for data.\r\n*/\r\nexport class TilePagination {\r\n allTiles: HeroSection[];\r\n\r\n // Initial first page\r\n currentPageIndex: 0;\r\n\r\n // The count of tiles to display at any one time\r\n visibleTileCount: 4;\r\n\r\n constructor() {\r\n this.initialiseValues();\r\n this.currentPageIndex = 0;\r\n this.visibleTileCount = 4;\r\n }\r\n \r\n initialiseValues()\r\n {\r\n this.allTiles = [];\r\n }\r\n \r\n ensureTile(section: HeroSection, index: number) : void\r\n {\r\n var indexOffsetFromZero = index - 1;\r\n var indexOfSection = this.allTiles.indexOf(section);\r\n if(indexOfSection >= 0)\r\n {\r\n if(indexOfSection == index) return; // Nothing to do\r\n\r\n this.allTiles.splice(indexOfSection, 1); // Remove at current place\r\n this.allTiles.splice(indexOffsetFromZero, 0, section); // Add to desired place\r\n }\r\n else\r\n {\r\n // Not currently present. Add\r\n if(this.allTiles.length > indexOffsetFromZero)\r\n {\r\n this.allTiles.splice(indexOffsetFromZero, 0, section);\r\n }\r\n else\r\n {\r\n this.allTiles.push(section);\r\n }\r\n }\r\n }\r\n\r\n removeTile(section: HeroSection)\r\n {\r\n var indexOfSection = this.allTiles.indexOf(section);\r\n if(indexOfSection >= 0)\r\n {\r\n this.allTiles.splice(indexOfSection, 1);\r\n }\r\n }\r\n\r\n public showTile(section: HeroSection) : boolean \r\n {\r\n var countOfGroupsOfData = this.countOfHeroSections();\r\n var indexOfSection = this.allTiles.indexOf(section);\r\n if(indexOfSection < 0) {\r\n //if(section == 'Home Visits')\r\n // console.log('pagination.showTile. Returning false for section: ' + JSON.stringify(section));\r\n return false;\r\n }\r\n \r\n // Determine the last visible index\r\n var lastVisibleIndex = this.currentPageIndex + this.visibleTileCount - 1;\r\n if(lastVisibleIndex >= countOfGroupsOfData) lastVisibleIndex -=1;\r\n\r\n var response = indexOfSection >= this.currentPageIndex && indexOfSection <= lastVisibleIndex;\r\n //if(section == 'Home Visits')\r\n // console.log('showTile: ' + section + '. response: ' + response + '. indexOfSection: ' + indexOfSection + '. this.currentPageIndex: ' + this.currentPageIndex + '. lastVisibleIndex: ' + lastVisibleIndex);\r\n return response;\r\n }\r\n\r\n public countOfHeroSections() : number \r\n {\r\n return (!!this.allTiles ? this.allTiles.length : 0);\r\n }\r\n\r\n // Logic to reflect:\r\n // When there are less than 4 sections with data, return false. Do not show pagination buttons.\r\n // When there are 4 or more sections, all with data. Show.\r\n public showButtons() : boolean\r\n {\r\n return this.countOfHeroSections() > this.visibleTileCount;\r\n }\r\n\r\n // Return true when currentPageIndex is > 0. Meaning: they have paged to the right and have at least one page to return to\r\n public leftButtonIsEnabled() : boolean \r\n {\r\n return this.currentPageIndex > 0;\r\n }\r\n\r\n // Return true when showRight is true and currentPageIndex + 3 (max count of pages) < count of available groups of data.\r\n public rightButtonIsEnabled() : boolean \r\n {\r\n // A sliding window returning true up until the window is displaying all remaining items\r\n var countOfGroupsOfData = this.countOfHeroSections();\r\n return countOfGroupsOfData > this.visibleTileCount && (this.currentPageIndex < (countOfGroupsOfData - this.visibleTileCount));\r\n }\r\n\r\n public pageLeft()\r\n {\r\n if(!this.leftButtonIsEnabled()) return;\r\n\r\n this.currentPageIndex -= 1;\r\n }\r\n\r\n public pageRight()\r\n {\r\n if(!this.rightButtonIsEnabled()) return;\r\n\r\n this.currentPageIndex += 1;\r\n }\r\n}\r\n","\r\nimport {throwError as observableThrowError, Observable } from 'rxjs';\r\n\r\nimport {catchError} from 'rxjs/operators';\r\nimport { Injectable } from \"@angular/core\";\r\nimport { HttpEvent, HttpHandler, HttpInterceptor, HttpErrorResponse } from \"@angular/common/http\";\r\nimport { HttpRequest } from \"@angular/common/http\";\r\nimport { Router } from \"@angular/router\";\r\nimport { MsalService } from \"services\";\r\n\r\n@Injectable()\r\nexport class FailedAuthorizationInterceptor implements HttpInterceptor {\r\n\r\n constructor(private router: Router, private adalService: MsalService) { }\r\n\r\n intercept(request: HttpRequest, next: HttpHandler): Observable> {\r\n\r\n return next.handle(request).pipe(catchError((err: any) => {\r\n if (err instanceof HttpErrorResponse) {\r\n if (err.status === 401 || err.status === 403 || err.message.indexOf(\"AADSTS50105\") >= 0) {\r\n this.adalService.clearCache();\r\n this.router.navigate(['unauthorised']);\r\n };\r\n }\r\n\r\n return observableThrowError(err);\r\n }));\r\n }\r\n}\r\n","\r\nimport {from as observableFrom, Observable } from 'rxjs';\r\n\r\nimport {mergeMap} from 'rxjs/operators';\r\nimport { Injectable } from \"@angular/core\";\r\nimport { HttpEvent, HttpHandler, HttpInterceptor } from \"@angular/common/http\";\r\nimport { HttpRequest } from \"@angular/common/http\";\r\nimport { MsalService } from \"services\";\r\n\r\n@Injectable()\r\nexport class TokenInterceptor implements HttpInterceptor {\r\n\r\n constructor(private adalService: MsalService) { }\r\n\r\n intercept(request: HttpRequest, next: HttpHandler): Observable> {\r\n\r\n return this.getToken().pipe(mergeMap((token: string) => {\r\n\r\n request = request.clone({\r\n setHeaders: {\r\n Authorization: `bearer ${token}`,\r\n ApplicationName: 'CSPortal'\r\n }\r\n });\r\n\r\n return next.handle(request);\r\n }));\r\n }\r\n\r\n private getToken(): Observable {\r\n return observableFrom(this.adalService.getAccessToken());\r\n }\r\n}\r\n","import { Component, ElementRef, Input, OnInit, OnDestroy } from '@angular/core';\r\n\r\nimport { ModalService } from '../../services';\r\n\r\n@Component({\r\n selector: 'jw-modal',\r\n templateUrl: './modal.component.html',\r\n styleUrls: ['./modal.component.scss']\r\n})\r\nexport class ModalComponent implements OnInit {\r\n @Input() id: string;\r\n private element: any;\r\n\r\n constructor(private modalService: ModalService, private el: ElementRef) {\r\n this.element = el.nativeElement;\r\n }\r\n\r\n ngOnInit(): void {\r\n let modal = this;\r\n\r\n // ensure id attribute exists\r\n if (!this.id) {\r\n console.error('modal must have an id');\r\n return;\r\n }\r\n\r\n // move element to bottom of page (just before