import { Component, OnDestroy, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { UnsavedChangesModalComponent } from '@core/components/unsaved-changes-modal/unsaved-changes-modal.component'; import { AppShellService } from '@core/services/app-shell.service'; import { PolicyService } from '@core/services/policy.service'; import { SpinnerService } from '@core/services/spinner.service'; import { TimeZoneService } from '@core/services/time-zone.service'; import { FooterState } from '@core/states/footer.state'; import { ArrayHelpersService, Tab, TabAction } from '@yourcause/common'; import { I18nService } from '@yourcause/common/i18n'; import { ModalFactory } from '@yourcause/common/modals'; import moment from 'moment'; import { Subscription } from 'rxjs'; import { DashboardTabActionsService } from '../dashboard-tab-actions.service'; import { DashboardsService } from '../dashboards.service'; import { GCDashboards } from '../dashboards.typing'; @Component({ selector: 'gc-dashboard-wrapper-page', templateUrl: './dashboard-wrapper-page.component.html', styleUrls: ['./dashboard-wrapper-page.component.scss'] }) export class DashboardWrapperPageComponent implements OnInit, OnDestroy { // TODO: remove useNewNavTabComp once comp migration is complete useNewNavTabComp = false; tabs: Tab[] = []; editingDashboard = false; sub = new Subscription(); allowNavigation = false; editingDashId: number; canManageDashboard = this.policyService.dataExport.canManageDashboards(); constructor ( private policyService: PolicyService, private arrayHelper: ArrayHelpersService, private dashboardService: DashboardsService, private i18n: I18nService, private modalFactory: ModalFactory, private spinnerService: SpinnerService, private router: Router, private footerState: FooterState, private timezoneService: TimeZoneService, private appShellService: AppShellService, private dashboardTabActions: DashboardTabActionsService ) { this.sub.add( this.dashboardService.changesTo$('editing') .subscribe((editing) => { this.editingDashboard = editing; this.setFooter(editing); this.prepareTabs(); })); this.sub.add( this.dashboardService.changesTo$('editingDashId') .subscribe((editingId) => { this.editingDashId = editingId; }) ); } get myDashboards () { return this.dashboardService.visibleDashboards; } ngOnInit () { this.appShellService.setShowHeaderButtons(false); this.prepareTabs(); } setFooter (editing: boolean) { if (editing) { this.footerState.set('footerState', this.footerState.FOOTER_STATES.ACTION); this.footerState.set('footerAction', async () => await this.saveChanges()); this.footerState.set('footerActionLabel', this.i18n.translate('common:btnSave')); this.footerState.set('footerCancelAction', async () => await this.cancelChanges()); this.footerState.set('footerCancelLabel', this.i18n.translate('common:btnCancel')); } else { this.footerState.clearAll(); } } prepareTabs () { this.setTabs(); this.sortTabs(); this.setTabActions(); } setTabs () { this.tabs = this.myDashboards.map((dashboard) => { return { link: `/management/home/${dashboard.aliasRoute || dashboard.dashboardId}`, order: dashboard.order, label: dashboard.name, disabled: this.editingDashboard && (this.editingDashId !== dashboard.dashboardId), actions: [], context: dashboard }; }); } setTabActions () { this.tabs.forEach((tab, index) => { const addWidget: TabAction = { icon: 'plus', iconClass: 'text-link', showPrimaryButton: true, labelKey: 'DASHBOARD:textAddWidget', label: 'Add widget', action: () => { this.addWidget(tab.context.dashboardId); } }; const editDashboard: TabAction = { icon: 'pencil', iconClass: 'text-link', showPrimaryButton: false, labelKey: 'common:textEdit', label: 'Edit', disabled: this.editingDashboard, action: () => { this.activateEditing(tab.context.dashboardId); } }; const renameDashboard = { icon: 'font', labelKey: 'common:textRename', iconClass: 'text-link', showPrimaryButton: false, label: 'Rename', action: async () => { await this.dashboardTabActions .openManageDashboardNameModal(tab.context); this.prepareTabs(); } }; const deleteDashboard = { icon: 'times', iconClass: 'text-danger', showPrimaryButton: false, labelKey: 'common:btnDelete', label: 'Delete', action: () => { this.deleteDashboard(tab.context); } }; const refreshDashboardData = { icon: 'sync', iconClass: 'text-link', showPrimaryButton: false, labelKey: 'DASHBOARD:textRefreshData', label: 'Refresh data', subActionContent: this.getSubActionContent(tab), action: () => { this.refreshDashboardData(tab); } }; const isCustom = tab.context.dashboardType === GCDashboards.DashboardTypes.CUSTOM; tab.actions = tab.context.isDashboardOwner || !isCustom ? [renameDashboard] : []; if (tab.order !== 1) { tab.actions = tab.actions.concat({ icon: 'arrow-left', labelKey: 'DASHBOARD:lblMoveTabLeft', iconClass: 'text-link', showPrimaryButton: false, label: 'Move tab left', action: () => { this.moveNavTabLeft(index); } }); } if (tab.order !== this.tabs.length) { tab.actions = tab.actions.concat({ icon: 'arrow-right', labelKey: 'DASHBOARD:lblMoveTabRight', iconClass: 'text-link', showPrimaryButton: false, label: 'Move tab right', action: () => { this.moveNavTabRight(index); }, hideAction: this.tabs[this.tabs.length - 1].context.dashboardId === tab.context.dashboardId }); } if (isCustom) { if (!tab.context.isDashboardOwner) { tab.actions = [ ...tab.actions, refreshDashboardData ]; } else if (this.editingDashboard) { tab.actions = [ ...tab.actions, addWidget, deleteDashboard ]; } else { tab.actions = [ ...tab.actions, editDashboard, addWidget, refreshDashboardData, deleteDashboard ]; } } const primaryActions = tab.actions.filter((ta) => !!ta.showPrimaryButton); const secondaryActions = tab.actions.filter((ta) => !ta.showPrimaryButton); tab.actions = [ ...primaryActions, ...secondaryActions ]; }); } sortTabs () { this.tabs = this.arrayHelper.sort(this.tabs, 'order'); } activateEditing (id: number) { this.dashboardService.setEditing(true, id); } refreshDashboardData (tab: Tab) { this.dashboardService.refreshDashboardData(tab.context.dashboardId); this.prepareTabs(); } getSubActionContent (tab: Tab) { const dateString = this.dashboardService.lastRefreshMap[tab.context.dashboardId]; const lastRefreshDate = this.timezoneService.returnLocalDateTimeAndTZ(moment(dateString).format(), 'lll'); const lastRefreshedText = this.i18n.translate( 'DASHBOARD:txtLastRefreshed', { date: lastRefreshDate }, 'Last refreshed __date__' ); return `${lastRefreshedText}`; } async moveNavTabLeft (index: number) { const thisTab = this.tabs[index]; const leftTab = this.tabs[index - 1]; await this.updateTabOrder( thisTab, leftTab, false ); } async moveNavTabRight (index: number) { const thisTab = this.tabs[index]; const rightTab = this.tabs[index + 1]; await this.updateTabOrder( thisTab, rightTab, true ); } async updateTabOrder ( thisTab: Tab, otherTab: Tab, moveRight = true ) { this.spinnerService.startSpinner(); await Promise.all([ this.dashboardService.handleUpdateTabOrder( thisTab.context.dashboardId, thisTab.context.name, moveRight ? thisTab.order + 1 : thisTab.order - 1, thisTab.context.isDashboardOwner ), this.dashboardService.handleUpdateTabOrder( otherTab.context.dashboardId, otherTab.context.name, moveRight ? otherTab.order - 1 : otherTab.order + 1, otherTab.context.isDashboardOwner ) ]); this.prepareTabs(); this.spinnerService.stopSpinner(); } async newTabCreated () { const id = await this.dashboardTabActions.openManageDashboardNameModal(); if (id) { this.activateEditing(id); this.dashboardTabActions.navigateToDashboard(id); } } async deleteDashboard (dashboard: GCDashboards.DashboardTab) { const didDeleteDashboard = await this.dashboardTabActions .deleteDashboard(dashboard); if (didDeleteDashboard) { this.prepareTabs(); this.router.navigate([this.dashboardService.homeRoute]); } } async addWidget (dashboardId: number) { await this.dashboardTabActions.addWidget(dashboardId); } async saveChanges () { this.spinnerService.startSpinner(); await this.dashboardService.saveDashboardEdits(); this.dashboardService.cancelEditMode(); this.editingDashId = null; this.spinnerService.stopSpinner(); } async cancelChanges () { this.spinnerService.startSpinner(); await this.dashboardService.getDashboardDetail( this.editingDashId ); this.dashboardService.cancelEditMode(); this.editingDashId = null; this.spinnerService.stopSpinner(); } async canDeactivate () { if (this.editingDashboard) { if (this.dashboardService.shouldPromptForUnsavedChanges()) { const response = await this.modalFactory.open( UnsavedChangesModalComponent, {} ); const canDeactivate = response !== GCDashboards.UnsavedChangesResponse.STAY; if (canDeactivate) { if (response === GCDashboards.UnsavedChangesResponse.SAVE_AND_LEAVE) { await this.saveChanges(); } else { this.dashboardService.cancelEditMode(); this.editingDashId = null; } } return canDeactivate; } else { this.dashboardService.cancelEditMode(); return true; } } else { return true; } } ngOnDestroy () { this.sub.unsubscribe(); this.appShellService.setShowHeaderButtons(true); } }