diff --git a/apps/back-office/src/app/dashboard/pages/dashboard/dashboard.component.ts b/apps/back-office/src/app/dashboard/pages/dashboard/dashboard.component.ts index b3ee5cf14a..cbbf5d5a49 100644 --- a/apps/back-office/src/app/dashboard/pages/dashboard/dashboard.component.ts +++ b/apps/back-office/src/app/dashboard/pages/dashboard/dashboard.component.ts @@ -37,13 +37,7 @@ import { GET_RESOURCE_RECORDS, } from './graphql/queries'; import { TranslateService } from '@ngx-translate/core'; -import { - map, - takeUntil, - filter, - startWith, - debounceTime, -} from 'rxjs/operators'; +import { map, takeUntil, filter, startWith } from 'rxjs/operators'; import { Observable, firstValueFrom } from 'rxjs'; import { FormControl } from '@angular/forms'; import { cloneDeep, isEqual } from 'lodash'; @@ -187,12 +181,7 @@ export class DashboardComponent } ngOnInit(): void { - this.contextId.valueChanges - .pipe(debounceTime(500), takeUntil(this.destroy$)) - .subscribe((value) => { - // Load template, or go back to default one - this.onContextChange(value); - }); + this.setUpContextFieldListeners(); /** Listen to router events navigation end, to get last version of params & queryParams. */ this.router.events .pipe( @@ -217,75 +206,169 @@ export class DashboardComponent pageContainer.scrollTop = 0; } - /** Extract main dashboard id */ - const id = this.route.snapshot.paramMap.get('id'); - /** Extract query id to load template */ - const queryId = this.route.snapshot.queryParamMap.get('id'); - if (id) { + this.handleContextTemplateLoad(); + }); + } + + /** + * Set up all the listeners for the possible context set in the current page + */ + private setUpContextFieldListeners() { + this.contextId.valueChanges + .pipe(takeUntil(this.destroy$)) + .subscribe((value) => { + // Load template, or go back to default one + this.onContextChange(value); + }); + this.regionCode.valueChanges + .pipe(takeUntil(this.destroy$)) + .subscribe((value) => { + // reset country code as it's not possible to have country and region selected + this.countryCode.setValue(value, { emitEvent: false }); + // In case we switch from country to region + // remove previous geographic context country property inside the dashboard object + delete this.dashboard?.page?.geographicContext?.country; + this.onContextChange(value, 'geographic'); + }); + this.countryCode.valueChanges + .pipe(takeUntil(this.destroy$)) + .subscribe((value) => { + // reset region code as it's not possible to have country and region selected + this.regionCode.setValue(value, { emitEvent: false }); + // In case we switch from region to country + // remove previous geographic context region property inside the dashboard object + delete this.dashboard?.page?.geographicContext?.region; + this.onContextChange(value, 'geographic'); + }); + } + + /** + * Load the correct context template for the given context params on the current dashboard + */ + private handleContextTemplateLoad() { + /** Extract main dashboard id */ + const id = this.route.snapshot.paramMap.get('id'); + /** Extract query id to load template */ + const queryId = this.route.snapshot.queryParamMap.get('id'); + const queryGeographic = this.route.snapshot.queryParamMap.get('geographic'); + const context: any = {}; + + if (id) { + // Even if query params exists, we don't want to load/create any template if option is not enabled in the dashboard + if ( + (this.contextType && queryId) || + (this.dashboard?.page?.geographicContext?.enabled && queryGeographic) + ) { + this.loadDashboard(id).then(() => { + const templates = this.dashboard?.page?.contentWithContext; + const type = this.contextType; + let template: any; if (queryId) { - this.loadDashboard(id).then(() => { - const templates = this.dashboard?.page?.contentWithContext; - const type = this.contextType; + // No geographic, then check reference data and record templates + if (!queryGeographic) { + template = templates?.find((d) => { + // If templates use reference data + if (type === 'element') + return ( + 'element' in d && + d.element.toString().trim() === queryId.trim() + ); + // If templates use resource + else if (type === 'record') + return ( + 'record' in d && + d.record.toString().trim() === queryId.trim() + ); + return false; + }); + } else { if (type) { - // Find template from parent's templates, based on query params id - const template = templates?.find((d) => { - // If templates use reference data - if (type === 'element') + template = templates?.find((d) => { + // If templates use reference data with the geographic context + if (type === 'element') { return ( 'element' in d && - d.element.toString().trim() === queryId.trim() + d.element.toString().trim() === queryId.trim() && + 'geographic' in d && + d.geographic && + d.geographic.toString().trim() === queryGeographic.trim() ); - // If templates use resource - else if (type === 'record') + } + // If templates use resource with geographic context + else if (type === 'record') { return ( 'record' in d && - d.record.toString().trim() === queryId.trim() + d.record.toString().trim() === queryId.trim() && + 'geographic' in d && + d.geographic && + d.geographic.toString().trim() === queryGeographic.trim() ); + } return false; }); + } + } + } else { + // If no context data but we have a geographic context + if (queryGeographic) { + template = templates?.find((d) => { + // If templates use geographic context + return ( + 'geographic' in d && + d.geographic && + d.geographic.toString().trim() === queryGeographic.trim() + ); + }); + } + } - if (template) { - // if we found the contextual dashboard, load it - this.loadDashboard(template.content).then( + if (template) { + // if we found the contextual dashboard, load it + this.loadDashboard(template.content).then( + () => (this.loading = false) + ); + } else { + if (this.dashboard?.page && this.canUpdate) { + this.snackBar.openSnackBar( + this.translate.instant( + 'models.dashboard.context.notifications.creatingTemplate' + ) + ); + if (queryGeographic && queryId && type) { + context[type] = queryId; + context['geographic'] = queryGeographic; + } else if (queryId && type) { + context[type] = queryId; + } else if (queryGeographic) { + context['geographic'] = queryGeographic; + } + this.dashboardService + .createDashboardWithContext( + this.dashboard?.page?.id as string, + context + ) + .then(({ data }) => { + if (!data?.addDashboardWithContext?.id) { + return; + } + this.snackBar.openSnackBar( + this.translate.instant( + 'models.dashboard.context.notifications.templateCreated' + ) + ); + // load the contextual dashboard + this.loadDashboard(data.addDashboardWithContext.id).then( () => (this.loading = false) ); - } else { - if (this.dashboard?.page && this.canUpdate) { - this.snackBar.openSnackBar( - this.translate.instant( - 'models.dashboard.context.notifications.creatingTemplate' - ) - ); - this.dashboardService - .createDashboardWithContext( - this.dashboard?.page?.id as string, - type, // type of context - queryId // id of the context - ) - .then(({ data }) => { - if (!data?.addDashboardWithContext?.id) return; - this.snackBar.openSnackBar( - this.translate.instant( - 'models.dashboard.context.notifications.templateCreated' - ) - ); - // load the contextual dashboard - this.loadDashboard( - data.addDashboardWithContext.id - ).then(() => (this.loading = false)); - }); - } - } - } else { - this.loading = false; - } - }); - } else { - // if there is no id, we are not on a contextual dashboard, we simply load the dashboard - this.loadDashboard(id).then(() => (this.loading = false)); + }); + } } - } - }); + }); + } else { + // if there is no id, we are not on a contextual dashboard, we simply load the dashboard + this.loadDashboard(id).then(() => (this.loading = false)); + } + } } /** @@ -322,15 +405,15 @@ export class DashboardComponent scrollToNewItems: false, }; if (this.dashboard.page?.geographicContext?.enabled) { - this.countryCode.setValue( - this.dashboard.page?.geographicContext?.country - ); - this.regionCode.setValue( - this.dashboard.page?.geographicContext?.region - ); - } else { - this.countryCode.setValue(''); - this.regionCode.setValue(''); + if (this.dashboard.page.geographicContext.country) { + this.countryCode.setValue( + this.dashboard.page?.geographicContext?.country + ); + } else { + this.regionCode.setValue( + this.dashboard.page?.geographicContext?.region + ); + } } this.initContext(); this.updateContextOptions(); @@ -682,39 +765,46 @@ export class DashboardComponent } /** - * Handle dashboard context change by simply updating the url. + * Handle dashboard context type change by simply updating the url. * - * @param value id of the element or record + * @param value id of the element or record, + * @param contextType set for the current page */ - private async onContextChange(value: string | number | undefined | null) { + private async onContextChange( + value: string | number | undefined | null, + contextType: 'record' | 'geographic' = 'record' + ) { + const queryParams = { ...this.route.snapshot.queryParams }; if ( !this.dashboard?.id || !this.dashboard?.page?.id || - !this.dashboard.page.context || - !this.contextType - ) + (contextType === 'record' && + (!this.dashboard.page.context || !this.contextType)) || + (contextType === 'geographic' && + !this.dashboard?.page?.geographicContext?.enabled) + ) { return; + } + const queryParamKey = contextType === 'record' ? 'id' : 'geographic'; if (value) { - this.router.navigate(['.'], { - relativeTo: this.route, - queryParams: { - id: value, - }, - }); + // Update the related key parameter if it exists, or set it if it's undefined + queryParams[queryParamKey] = value; // const urlArr = this.router.url.split('/'); // urlArr[urlArr.length - 1] = `${parentDashboardId}?id=${value}`; // this.router.navigateByUrl(urlArr.join('/')); } else { + // remove related key from query params + delete queryParams[queryParamKey]; this.snackBar.openSnackBar( this.translate.instant( 'models.dashboard.context.notifications.loadDefault' ) ); - this.router.navigate(['.'], { relativeTo: this.route }); - // const urlArr = this.router.url.split('/'); - // urlArr[urlArr.length - 1] = parentDashboardId; - // this.router.navigateByUrl(urlArr.join('/')); } + this.router.navigate(['.'], { relativeTo: this.route, queryParams }); + // const urlArr = this.router.url.split('/'); + // urlArr[urlArr.length - 1] = parentDashboardId; + // this.router.navigateByUrl(urlArr.join('/')); } /** Initializes the dashboard context */ @@ -881,8 +971,8 @@ export class DashboardComponent value: string | string[], geographicType: 'region' | 'country' ): void { - const geographicContext = { - ...this.dashboard?.page?.geographicContext, + const geographicContext: PageGeographicContextType = { + enabled: true, ...(value && { [geographicType]: value }), }; const callback = () => { @@ -890,14 +980,14 @@ export class DashboardComponent ...this.dashboard, page: { ...this.dashboard?.page, - geographicContext: geographicContext as PageGeographicContextType, + geographicContext: geographicContext, }, }; }; this.applicationService.updatePageGeographicContext( { id: this.dashboard?.page?.id, - geographicContext: geographicContext as PageGeographicContextType, + geographicContext: geographicContext, }, callback ); diff --git a/libs/shared/src/lib/models/page.model.ts b/libs/shared/src/lib/models/page.model.ts index a495d14d24..13e0f6cf0a 100644 --- a/libs/shared/src/lib/models/page.model.ts +++ b/libs/shared/src/lib/models/page.model.ts @@ -95,6 +95,8 @@ export interface Page { } ) & { content: string; + } & { + geographic?: string; })[]; geographicContext?: PageGeographicContextType; autoDeletedAt?: Date; diff --git a/libs/shared/src/lib/services/application/application.service.ts b/libs/shared/src/lib/services/application/application.service.ts index d506e9e1df..2975e51e5f 100644 --- a/libs/shared/src/lib/services/application/application.service.ts +++ b/libs/shared/src/lib/services/application/application.service.ts @@ -2111,7 +2111,7 @@ export class ApplicationService { }, error: (errors: any) => { this.handleEditionMutationResponse( - errors, + [errors], this.translate.instant('common.page.one') ); }, diff --git a/libs/shared/src/lib/services/dashboard/dashboard.service.ts b/libs/shared/src/lib/services/dashboard/dashboard.service.ts index a05a450875..80c50ebe14 100644 --- a/libs/shared/src/lib/services/dashboard/dashboard.service.ts +++ b/libs/shared/src/lib/services/dashboard/dashboard.service.ts @@ -159,20 +159,15 @@ export class DashboardService { * * @param page Page to copy content from * @param context The type of context to be added to the dashboard - * @param id The id of the context to be added to the dashboard * @returns The newly created dashboard */ - public createDashboardWithContext( - page: string, - context: 'element' | 'record', - id: string | number - ) { + public createDashboardWithContext(page: string, context: any) { return firstValueFrom( this.apollo.mutate({ mutation: CREATE_DASHBOARD_WITH_CONTEXT, variables: { page, - [context]: id, + ...context, }, }) ); diff --git a/libs/shared/src/lib/services/dashboard/graphql/mutations.ts b/libs/shared/src/lib/services/dashboard/graphql/mutations.ts index 0917e4a252..f838b005f0 100644 --- a/libs/shared/src/lib/services/dashboard/graphql/mutations.ts +++ b/libs/shared/src/lib/services/dashboard/graphql/mutations.ts @@ -64,8 +64,18 @@ export const UPDATE_PAGE_CONTEXT = gql` /** GraphQL mutation for creating a dashboard with context */ export const CREATE_DASHBOARD_WITH_CONTEXT = gql` - mutation createDashboardWithContext($page: ID!, $element: JSON, $record: ID) { - addDashboardWithContext(page: $page, element: $element, record: $record) { + mutation createDashboardWithContext( + $page: ID! + $element: JSON + $record: ID + $geographic: String + ) { + addDashboardWithContext( + page: $page + element: $element + record: $record + geographic: $geographic + ) { id structure page {