From 9d808902b3def1293bf069fac794e5346cde6581 Mon Sep 17 00:00:00 2001
From: Florent Poittevin <florent.poittevin@unige.ch>
Date: Fri, 24 Jan 2020 12:53:21 +0100
Subject: [PATCH] feat: 1077 display only collection or file tab on deposit

---
 .../deposit-detail-edit.routable.html         |  40 +-----
 .../deposit-detail-edit.routable.ts           | 110 ++++++++-------
 .../deposit/deposit-routing.module.ts         |  13 +-
 .../shared-tabs/shared-tabs.container.html    |  38 +++++
 .../shared-tabs/shared-tabs.container.scss    |  48 +++++++
 .../shared-tabs/shared-tabs.container.ts      | 130 ++++++++++++++++++
 .../shared-button-spinner.directive.ts        |   2 +-
 .../deposit-detail-tab-guard.service.ts       |  80 +++++++++++
 src/app/shared/shared.module.ts               |   2 +
 src/assets/i18n/de.json                       |   5 +-
 src/assets/i18n/en.json                       |   5 +-
 src/assets/i18n/fr.json                       |   5 +-
 12 files changed, 383 insertions(+), 95 deletions(-)
 create mode 100644 src/app/shared/components/containers/shared-tabs/shared-tabs.container.html
 create mode 100644 src/app/shared/components/containers/shared-tabs/shared-tabs.container.scss
 create mode 100644 src/app/shared/components/containers/shared-tabs/shared-tabs.container.ts
 create mode 100644 src/app/shared/guards/deposit-detail-tab-guard.service.ts

diff --git a/src/app/features/deposit/components/routables/deposit-detail-edit/deposit-detail-edit.routable.html b/src/app/features/deposit/components/routables/deposit-detail-edit/deposit-detail-edit.routable.html
index 61dc5e323..a951cface 100644
--- a/src/app/features/deposit/components/routables/deposit-detail-edit/deposit-detail-edit.routable.html
+++ b/src/app/features/deposit/components/routables/deposit-detail-edit/deposit-detail-edit.routable.html
@@ -4,9 +4,9 @@
 ></dlcm-deposit-banner>
 <dlcm-shared-banner-edit-mode [isEdit]="isEdit"></dlcm-shared-banner-edit-mode>
 
+<!--                            [editAvailable]="canDoAlterationActions && tabSelected === depositTabEnum.metadata && ((currentObs| async)?.status === depositStatusEnum.INPROGRESS)"-->
 <dlcm-button-toolbar-detail [mode]="isEdit ? 'edit' : 'detail'"
                             [currentModel]="currentObs | async"
-                            [editAvailable]="canDoAlterationActions && tabSelected === depositTabEnum.metadata && ((currentObs| async)?.status === depositStatusEnum.INPROGRESS)"
                             [deleteAvailable]="canDoAlterationActions"
                             [listExtraButtons]="listExtraButtons"
                             (editChange)="edit()"
@@ -18,39 +18,9 @@
 >
 </dlcm-button-toolbar-detail>
 
-<mat-tab-group *ngIf="initialRightComputed"
-               #matTabGroup
-               mat-align-tabs="center"
-               animationDuration="0ms"
-               [selectedIndex]="tabSelected"
-               (selectedIndexChange)="navigateToTab($event)"
+<dlcm-shared-tabs-container [tabs]="listTabs"
+                            [suffixUrlMatcher]="depositHelper.getTabRouteSelected"
+                            (tabChange)="setCurrentTab($event)"
 >
-  <mat-tab>
-    <ng-template mat-tab-label>
-      <mat-icon class="tab-header-icon">assignment</mat-icon>
-      <span class="tab-header-label">{{'deposit.tab.details' | translate}}</span>
-    </ng-template>
-  </mat-tab>
-  <mat-tab>
-    <ng-template mat-tab-label>
-      <mat-icon class="tab-header-icon">insert_drive_file</mat-icon>
-      <span class="tab-header-label">{{'deposit.tab.datafiles' | translate}}</span>
-    </ng-template>
-  </mat-tab>
-  <mat-tab>
-    <ng-template mat-tab-label>
-      <mat-icon class="tab-header-icon">insert_drive_file</mat-icon>
-      <span class="tab-header-label">{{'deposit.tab.collection' | translate}}</span>
-    </ng-template>
-  </mat-tab>
-  <mat-tab *ngIf="canDoAlterationActions && ((currentObs| async)?.status === depositStatusEnum.INPROGRESS)">
-    <ng-template mat-tab-label>
-      <mat-icon class="tab-header-icon">publish</mat-icon>
-      <span class="tab-header-label">{{'deposit.tab.upload' | translate}}</span>
-    </ng-template>
-  </mat-tab>
-</mat-tab-group>
-
-<div class="tab-content">
   <router-outlet></router-outlet>
-</div>
+</dlcm-shared-tabs-container>
diff --git a/src/app/features/deposit/components/routables/deposit-detail-edit/deposit-detail-edit.routable.ts b/src/app/features/deposit/components/routables/deposit-detail-edit/deposit-detail-edit.routable.ts
index 415a9b690..845c04fd1 100644
--- a/src/app/features/deposit/components/routables/deposit-detail-edit/deposit-detail-edit.routable.ts
+++ b/src/app/features/deposit/components/routables/deposit-detail-edit/deposit-detail-edit.routable.ts
@@ -10,8 +10,6 @@ import {MatDialog} from "@angular/material";
 import {MatTabGroup} from "@angular/material/tabs";
 import {
   ActivatedRoute,
-  NavigationCancel,
-  NavigationEnd,
   Router,
 } from "@angular/router";
 import {DepositExtended} from "@app/features/deposit/models/deposits-extended.model";
@@ -42,6 +40,7 @@ import {
   Select,
   Store,
 } from "@ngxs/store";
+import {Tab} from "@shared/components/containers/shared-tabs/shared-tabs.container";
 import {SharedHistoryDialog} from "@shared/components/dialogs/shared-history/shared-history.dialog";
 import {SharedAbstractDetailEditRoutable} from "@shared/components/routables/shared-abstract-detail-edit/shared-abstract-detail-edit.routable";
 import {
@@ -63,6 +62,7 @@ import {
   distinctUntilChanged,
   filter,
   flatMap,
+  map,
   take,
 } from "rxjs/operators";
 import {
@@ -100,15 +100,50 @@ export class DepositDetailEditRoutable extends SharedAbstractDetailEditRoutable<
   @ViewChild("matTabGroup", {static: false})
   readonly matTabGroup: MatTabGroup;
 
+  private get rootUrl(): string[] {
+    return [AppRoutesEnum.deposit, this._orgUnitResId, DepositRoutesEnum.detail, this._resId];
+  }
+
+  listTabs: Tab[] = [
+    {
+      id: "METADATA",
+      suffixUrl: DepositRoutesEnum.metadata,
+      icon: "assignment",
+      titleToTranslate: TRANSLATE("deposit.tab.details"),
+      route: () => [...this.rootUrl, DepositRoutesEnum.metadata],
+    },
+    {
+      id: "FILES",
+      suffixUrl: DepositRoutesEnum.files,
+      icon: "insert_drive_file",
+      titleToTranslate: TRANSLATE("deposit.tab.datafiles"),
+      route: () => [...this.rootUrl, DepositRoutesEnum.files],
+      conditionDisplay: () => this.numberCollectionObs.pipe(map(number => number === 0)),
+    },
+    {
+      id: "COLLECTION",
+      suffixUrl: DepositRoutesEnum.collection,
+      icon: "collections_bookmark",
+      titleToTranslate: TRANSLATE("deposit.tab.collection"),
+      route: () => [...this.rootUrl, DepositRoutesEnum.collection],
+      conditionDisplay: () => this.numberFilesObs.pipe(map(number => number === 0)),
+    },
+    {
+      id: "UPLOAD",
+      suffixUrl: DepositRoutesEnum.upload,
+      icon: "publish",
+      titleToTranslate: TRANSLATE("deposit.tab.upload"),
+      route: () => [...this.rootUrl, DepositRoutesEnum.upload],
+      conditionDisplay: () => this.numberCollectionObs.pipe(map(number => (number === 0) && this.canDoAlterationActions)),
+    },
+  ];
+
   messageReasonUnableSubmit: string | undefined;
-  tabSelected: DepositTabEnum;
   canDoValidatorActions: boolean = false;
   canDoAlterationActions: boolean = false;
   canSubmitAction: boolean = false;
   canReserveDoiAction: boolean = false;
 
-  initialRightComputed: boolean = false;
-
   canDoAlterationActionsBS: BehaviorSubject<boolean | undefined> = new BehaviorSubject(undefined);
   readonly canDoAlterationActionsObs: Observable<boolean | undefined> = ObservableUtil.asObservable(this.canDoAlterationActionsBS);
 
@@ -171,6 +206,14 @@ export class DepositDetailEditRoutable extends SharedAbstractDetailEditRoutable<
     return DepositTabEnum;
   }
 
+  get depositRoutesEnum(): typeof DepositRoutesEnum {
+    return DepositRoutesEnum;
+  }
+
+  get depositHelper(): typeof DepositHelper {
+    return DepositHelper;
+  }
+
   constructor(protected readonly _store: Store,
               protected readonly _route: ActivatedRoute,
               protected readonly _actions$: Actions,
@@ -186,28 +229,6 @@ export class DepositDetailEditRoutable extends SharedAbstractDetailEditRoutable<
 
     this.retrieveResource();
     this.retrieveCurrentModelWithUrl();
-
-    this.subscribe(this.canDoAlterationActionsBS.pipe(
-      distinctUntilChanged(),
-      filter(canDoAlterate => !isNullOrUndefined(canDoAlterate)),
-      ),
-      source => this.initialRightComputed = true,
-    );
-
-    this._computeCurrentTab();
-    this.subscribe(this._router.events
-      .pipe(
-        filter(event => event instanceof NavigationCancel || event instanceof NavigationEnd),
-        distinctUntilChanged(),
-        tap(event => {
-          this._computeCurrentTab();
-          if (this.matTabGroup) {
-            this.matTabGroup.selectedIndex = this.tabSelected;
-          }
-        }),
-      ),
-    );
-
     this._computeCurrentUserRight();
     this._computeEditableField();
   }
@@ -222,11 +243,6 @@ export class DepositDetailEditRoutable extends SharedAbstractDetailEditRoutable<
     this._orgUnitResId = this._route.parent.snapshot.paramMap.get(AppRoutesEnum.paramIdOrgUnitWithoutPrefixParam);
   }
 
-  private _computeCurrentTab(): void {
-    const tabRouteSelected = DepositHelper.getTabRouteSelected(this._route);
-    this.tabSelected = DepositHelper.getTabSelectedIndexWithRoute(tabRouteSelected);
-  }
-
   private _computeEditableField(): void {
     this.subscribe(this.canDoAlterationActionsObs.pipe(
       distinctUntilChanged(),
@@ -388,12 +404,6 @@ export class DepositDetailEditRoutable extends SharedAbstractDetailEditRoutable<
     });
   }
 
-  navigateToTab(tabSelected: DepositTabEnum, isEdit?: boolean | undefined): Observable<any> {
-    const tabRouteSelected = DepositHelper.getTabRouteSelectedWithTabIndex(tabSelected);
-    const path = [AppRoutesEnum.deposit, this._orgUnitResId, DepositRoutesEnum.detail, this._resId, tabRouteSelected];
-    return this._store.dispatch(new Navigate(path));
-  }
-
   approve(): void {
     this.currentObs.pipe(
       take(1),
@@ -421,13 +431,21 @@ export class DepositDetailEditRoutable extends SharedAbstractDetailEditRoutable<
 
   backToDetail(): void {
     const currentUrl = this._store.selectSnapshot((s: LocalStateModel) => s.router.state.url);
-    this.navigateToTab(this.tabSelected, false).subscribe((state: LocalStateModel) => {
-      if (state.router.state.url !== currentUrl) {
-        // this.formPresentational.resetFormToInitialValue();
-        // TODO : Fix don't need to get by id model from backend but fix resetFormToInitialValue with component user role org unit
-        // TODO : Problem currently if redirect to detail page via breadcrumb in case of Deposit
-        this.retrieveCurrentModelWithUrl();
-      }
-    });
+    this._store.dispatch(new Navigate([...this.rootUrl, DepositRoutesEnum.metadata, DepositRoutesEnum.edit]));
+
+    // this.navigateToTab(this.tabSelected, false).subscribe((state: LocalStateModel) => {
+    //   if (state.router.state.url !== currentUrl) {
+    //     // this.formPresentational.resetFormToInitialValue();
+    //     // TODO : Fix don't need to get by id model from backend but fix resetFormToInitialValue with component user role org unit
+    //     // TODO : Problem currently if redirect to detail page via breadcrumb in case of Deposit
+    //     this.retrieveCurrentModelWithUrl();
+    //   }
+    // });
+  }
+
+  private currentTab: Tab;
+
+  setCurrentTab($event: Tab): void {
+    this.currentTab = $event;
   }
 }
diff --git a/src/app/features/deposit/deposit-routing.module.ts b/src/app/features/deposit/deposit-routing.module.ts
index d348e2241..f04acf8e5 100644
--- a/src/app/features/deposit/deposit-routing.module.ts
+++ b/src/app/features/deposit/deposit-routing.module.ts
@@ -22,6 +22,7 @@ import {
   DepositTabStatusName,
 } from "@deposit/enums/deposit-tab-status.enum";
 import {DepositState} from "@deposit/stores/deposit.state";
+import {DepositDetailTabGuardService} from "@shared/guards/deposit-detail-tab-guard.service";
 import {DepositRoleGuardDetailService} from "@shared/guards/deposit-role-guard-detail.service";
 import {DepositRoleGuardEditService} from "@shared/guards/deposit-role-guard-edit.service";
 import {CanDeactivateGuard} from "@shared/services/can-deactivate-guard.service";
@@ -126,6 +127,7 @@ const routes: DlcmRoutes = [
               breadcrumb: TRANSLATE("breadcrumb.deposit.file"),
               noBreadcrumbLink: true,
             },
+            canActivate: [DepositDetailTabGuardService],
           },
           {
             path: DepositRoutesEnum.collection,
@@ -134,16 +136,7 @@ const routes: DlcmRoutes = [
               breadcrumb: TRANSLATE("breadcrumb.deposit.collection"),
               noBreadcrumbLink: true,
             },
-            children: [
-              {
-                path: DepositRoutesEnum.edit,
-                data: {
-                  breadcrumb: TRANSLATE("breadcrumb.deposit.edit"),
-                },
-                canActivate: [DepositRoleGuardEditService],
-                canDeactivate: [CanDeactivateGuard],
-              },
-            ],
+            canActivate: [DepositDetailTabGuardService],
           },
           {
             path: DepositRoutesEnum.upload,
diff --git a/src/app/shared/components/containers/shared-tabs/shared-tabs.container.html b/src/app/shared/components/containers/shared-tabs/shared-tabs.container.html
new file mode 100644
index 000000000..8c66261f5
--- /dev/null
+++ b/src/app/shared/components/containers/shared-tabs/shared-tabs.container.html
@@ -0,0 +1,38 @@
+<mat-tab-group #matTabGroup
+               mat-align-tabs="center"
+               animationDuration="0ms"
+               [selectedIndex]="initialIndexTabSelected"
+               (selectedTabChange)="navigateToTab($event)"
+>
+  <ng-container *ngFor="let tab of tabs">
+    <mat-tab [disabled]="!(isDisplayed(tab) | async)"
+             [label]="tab.id"
+    >
+      <ng-template mat-tab-label>
+        <mat-icon *ngIf="tab.icon"
+                  class="tab-header-icon"
+        >{{tab.icon}}</mat-icon>
+        <span class="tab-header-label">{{tab.titleToTranslate | translate}}</span>
+      </ng-template>
+    </mat-tab>
+  </ng-container>
+</mat-tab-group>
+
+<div class="tab-content">
+  <ng-template [ngIf]="!(getSelectedTabFromTabGroup() | isNullOrUndefined)">
+
+    <ng-template [ngIf]="isDisplayed(getSelectedTabFromTabGroup()) | async"
+                 [ngIfElse]="disableTab"
+    >
+      <ng-content></ng-content>
+    </ng-template>
+    <ng-template #disableTab>
+      <div class="unaccessible-tab">
+        <h2>{{'app.tab.unaccessibleTab' | translate}}</h2>
+      </div>
+    </ng-template>
+  </ng-template>
+</div>
+
+
+<!--{{matTabGroup.tab}}-->
diff --git a/src/app/shared/components/containers/shared-tabs/shared-tabs.container.scss b/src/app/shared/components/containers/shared-tabs/shared-tabs.container.scss
new file mode 100644
index 000000000..9069a3696
--- /dev/null
+++ b/src/app/shared/components/containers/shared-tabs/shared-tabs.container.scss
@@ -0,0 +1,48 @@
+@import "../../../../../sass/abstracts/variables";
+@import "../../../../../sass/abstracts/mixins";
+
+:host {
+  ::ng-deep {
+    .mat-tab-disabled {
+      display: none;
+    }
+
+    .mat-tab-label-active {
+      border-bottom: 2px solid $primary-color;
+      opacity: 1 !important;
+
+      &.mat-tab-label {
+        opacity: 1 !important;
+      }
+    }
+
+    .mat-ink-bar {
+      display: none;
+    }
+  }
+
+  .tab-content {
+    padding-top: 10px;
+
+    .unaccessible-tab {
+      opacity: 0;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      height: 100px;
+      animation: appear 0.5s;
+      animation-delay: 1s;
+      animation-fill-mode: forwards;
+    }
+  }
+
+  @-webkit-keyframes appear {
+    0% {
+      opacity: 0;
+    }
+    100% {
+      opacity: 1;
+    }
+  }
+
+}
diff --git a/src/app/shared/components/containers/shared-tabs/shared-tabs.container.ts b/src/app/shared/components/containers/shared-tabs/shared-tabs.container.ts
new file mode 100644
index 000000000..c62550716
--- /dev/null
+++ b/src/app/shared/components/containers/shared-tabs/shared-tabs.container.ts
@@ -0,0 +1,130 @@
+import {
+  ChangeDetectionStrategy,
+  Component,
+  Input,
+  OnInit,
+  Output,
+  ViewChild,
+} from "@angular/core";
+import {
+  MatTabChangeEvent,
+  MatTabGroup,
+} from "@angular/material/tabs";
+import {
+  ActivatedRoute,
+  NavigationCancel,
+  NavigationEnd,
+  Router,
+} from "@angular/router";
+import {Navigate} from "@ngxs/router-plugin";
+import {Store} from "@ngxs/store";
+import {SharedAbstractContainer} from "@shared/components/containers/shared-abstract/shared-abstract.container";
+import {
+  BehaviorSubject,
+  Observable,
+  of,
+} from "rxjs";
+import {
+  distinctUntilChanged,
+  filter,
+  tap,
+} from "rxjs/operators";
+import {
+  isArray,
+  isNullOrUndefined,
+  isObservable,
+  ObservableUtil,
+} from "solidify-frontend";
+
+@Component({
+  selector: "dlcm-shared-tabs-container",
+  templateUrl: "./shared-tabs.container.html",
+  styleUrls: ["./shared-tabs.container.scss"],
+  changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class SharedTabsContainer extends SharedAbstractContainer implements OnInit {
+  @Input()
+  tabs: Tab[];
+
+  @Input()
+  suffixUrlMatcher: (route: ActivatedRoute) => string;
+
+  private readonly _tabBS: BehaviorSubject<Tab> = new BehaviorSubject<Tab>(undefined);
+  @Output("tabChange")
+  readonly tabObs: Observable<Tab> = ObservableUtil.asObservable(this._tabBS);
+
+  initialIndexTabSelected: number;
+
+  @ViewChild("matTabGroup", {static: false})
+  readonly matTabGroup: MatTabGroup;
+
+  constructor(private readonly _store: Store,
+              private readonly _router: Router,
+              private readonly _route: ActivatedRoute) {
+    super();
+  }
+
+  ngOnInit(): void {
+    super.ngOnInit();
+    this._computeCurrentTabFromRoute();
+    this.subscribe(this._router.events
+      .pipe(
+        filter(event => event instanceof NavigationCancel || event instanceof NavigationEnd),
+        distinctUntilChanged(),
+        tap(event => {
+          this._computeCurrentTabFromRoute();
+          this.matTabGroup.selectedIndex = this.initialIndexTabSelected;
+        }),
+      ),
+    );
+  }
+
+  private _computeCurrentTabFromRoute(initialIndex: number | undefined = undefined): Tab {
+    const tabRouteSelected = this.suffixUrlMatcher(this._route);
+    const tabIndex = this.tabs.findIndex(t => t.suffixUrl === tabRouteSelected);
+    if (this.initialIndexTabSelected !== tabIndex) {
+      this.initialIndexTabSelected = tabIndex;
+      const tab = this.tabs[tabIndex];
+      this._tabBS.next(tab);
+      return tab;
+    }
+    return null;
+  }
+
+  navigateToTab($event: MatTabChangeEvent): Observable<any> {
+    const selectedTab = this.tabs.find(tab => tab.id === $event.tab.textLabel);
+    return this.dispatchActionNavigateToTab(selectedTab);
+  }
+
+  private dispatchActionNavigateToTab(selectedTab: Tab): Observable<any> {
+    const path = selectedTab.route();
+    return this._store.dispatch(new Navigate(isArray(path) ? path : [path]));
+  }
+
+  isDisplayed(tab: Tab): Observable<boolean> {
+    if (isNullOrUndefined(tab.conditionDisplay)) {
+      return of(true);
+    }
+    if (isObservable(tab.conditionDisplay())) {
+      return tab.conditionDisplay() as Observable<boolean>;
+    } else {
+      return of(tab.conditionDisplay() as boolean);
+    }
+  }
+
+  getSelectedTabFromTabGroup(): Tab | undefined {
+    if (isNullOrUndefined(this.matTabGroup) || isNullOrUndefined(this.matTabGroup.selectedIndex) || this.matTabGroup.selectedIndex === -1) {
+      return undefined;
+    }
+    return this.tabs[this.matTabGroup.selectedIndex];
+  }
+}
+
+export interface Tab {
+  id: string;
+  suffixUrl: string;
+  icon?: string;
+  titleToTranslate: string;
+  conditionDisplay?: () => boolean | Observable<boolean> | undefined;
+  route: () => string | string[];
+}
diff --git a/src/app/shared/directives/shared-button-spinner/shared-button-spinner.directive.ts b/src/app/shared/directives/shared-button-spinner/shared-button-spinner.directive.ts
index 9fbad739b..132d70fd8 100644
--- a/src/app/shared/directives/shared-button-spinner/shared-button-spinner.directive.ts
+++ b/src/app/shared/directives/shared-button-spinner/shared-button-spinner.directive.ts
@@ -7,12 +7,12 @@ import {
   Renderer2,
   ViewContainerRef,
 } from "@angular/core";
+import {environment} from "@environments/environment";
 import {SharedAbstractSpinnerDirective} from "@shared/directives/shared-abstract-spinner/shared-abstract-spinner.directive";
 import {
   isNullOrUndefined,
   isTrue,
 } from "solidify-frontend";
-import {environment} from "../../../../environments/environment";
 
 @Directive({
   selector: "[dlcmButtonSpinner]",
diff --git a/src/app/shared/guards/deposit-detail-tab-guard.service.ts b/src/app/shared/guards/deposit-detail-tab-guard.service.ts
new file mode 100644
index 000000000..4b439de97
--- /dev/null
+++ b/src/app/shared/guards/deposit-detail-tab-guard.service.ts
@@ -0,0 +1,80 @@
+import {Injectable} from "@angular/core";
+import {
+  ActivatedRouteSnapshot,
+  CanActivate,
+  Router,
+} from "@angular/router";
+import {DepositAction} from "@app/features/deposit/stores/deposit.action";
+import {DepositState} from "@deposit/stores/deposit.state";
+import {Store} from "@ngxs/store";
+import {
+  AppRoutesEnum,
+  DepositRoutesEnum,
+} from "@shared/enums/routes.enum";
+import {SecurityService} from "@shared/services/security.service";
+import {Observable} from "rxjs";
+import {
+  distinctUntilChanged,
+  filter,
+  map,
+} from "rxjs/operators";
+import {
+  ApiService,
+  isNullOrUndefined,
+  ResourceState,
+} from "solidify-frontend";
+
+@Injectable({
+  providedIn: "root",
+})
+export class DepositDetailTabGuardService implements CanActivate {
+  constructor(public router: Router,
+              private readonly _store: Store,
+              public apiService: ApiService,
+              private readonly _securityService: SecurityService) {
+  }
+
+  canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {
+    const path = route.url[0].path;
+    let depositId: string = route.parent.parent.params[AppRoutesEnum.paramIdWithoutPrefixParam];
+    if (isNullOrUndefined(depositId)) {
+      depositId = route.parent.params[AppRoutesEnum.paramIdWithoutPrefixParam];
+    }
+    // TODO Find a way to optimize this. Maybe by use info in store on not on deposit
+    // NEED TO REFRESH TO GET LAST VERSION OF DATA_FILE_NUMBER AND COLLECTION_SIZE attribute
+    // const depositInState = ResourceState.currentSnapshot(this._store, DepositState);
+    // if (isNullOrUndefined(depositInState) || depositId !== depositInState.resId) {
+    this._store.dispatch(new DepositAction.GetById(depositId));
+    // }
+    return ResourceState.current(this._store, DepositState).pipe(
+      distinctUntilChanged(),
+      filter(deposit => !isNullOrUndefined(deposit) && deposit.resId === depositId),
+      map(deposit => {
+        if (deposit.dataFileNumber > 0 && deposit.collectionSize > 0) {
+          return true;
+        }
+        if (path === DepositRoutesEnum.files && deposit.collectionSize > 0) {
+          const url = this.rebuildUrl(route.pathFromRoot);
+          url[url.length - 1] = DepositRoutesEnum.collection;
+          this.router.navigate(url);
+          return false;
+        }
+        if (path === DepositRoutesEnum.collection && deposit.dataFileNumber > 0) {
+          const url = this.rebuildUrl(route.pathFromRoot);
+          url[url.length - 1] = DepositRoutesEnum.files;
+          this.router.navigate(url);
+          return false;
+        }
+        return true;
+      }),
+    );
+  }
+
+  private rebuildUrl(activatedRouteSnapshot: ActivatedRouteSnapshot[]): string[] {
+    const urlSegmentToParent = [];
+    activatedRouteSnapshot.forEach((activatedRouteSnap) => {
+      urlSegmentToParent.push(...activatedRouteSnap.url);
+    });
+    return urlSegmentToParent.map(u => u.path);
+  }
+}
diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts
index 2fcb05de7..28d3695b0 100644
--- a/src/app/shared/shared.module.ts
+++ b/src/app/shared/shared.module.ts
@@ -33,6 +33,7 @@ import {
 import {fas} from "@fortawesome/free-solid-svg-icons";
 import {TranslateModule} from "@ngx-translate/core";
 import {NgxsModule} from "@ngxs/store";
+import {SharedTabsContainer} from "@shared/components/containers/shared-tabs/shared-tabs.container";
 import {SharedOrganizationalUnitNameContainer} from "@shared/components/containers/shared-organizational-unit-name/shared-organizational-unit-name.container";
 import {SharedAipDetailDialog} from "@shared/components/dialogs/shared-aip-detail/shared-aip-detail.dialog";
 import {SharedBaseActionDialog} from "@shared/components/dialogs/shared-base-action/shared-base-action.dialog";
@@ -83,6 +84,7 @@ import {SharedPaginatorPresentational} from "./components/presentationals/shared
 const routables = [];
 const containers = [
   SharedOrganizationalUnitNameContainer,
+  SharedTabsContainer,
 ];
 const dialogs = [
   SharedHistoryDialog,
diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json
index 147523169..4270635f8 100644
--- a/src/assets/i18n/de.json
+++ b/src/assets/i18n/de.json
@@ -760,6 +760,9 @@
       "newVersionAvailable": "A new version of the application is available",
       "offline": "Your are currently offline"
     },
+    "tab": {
+      "unaccessibleTab": "You cannot be abble access this tab"
+    },
     "token": {
       "access": "Access token",
       "copyToClipboard": "Copy to the clipboard",
@@ -1391,13 +1394,13 @@
     "button": {
       "goToArchivalBrowsing": "Go to archive browsing"
     },
-    "noResultToDisplay": "No result to display...",
     "list": {
       "action": {
         "addToCart": "Add to cart",
         "download": "Download"
       }
     },
+    "noResultToDisplay": "No result to display...",
     "or": "or"
   },
   "homePage": {
diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json
index 147523169..4270635f8 100644
--- a/src/assets/i18n/en.json
+++ b/src/assets/i18n/en.json
@@ -760,6 +760,9 @@
       "newVersionAvailable": "A new version of the application is available",
       "offline": "Your are currently offline"
     },
+    "tab": {
+      "unaccessibleTab": "You cannot be abble access this tab"
+    },
     "token": {
       "access": "Access token",
       "copyToClipboard": "Copy to the clipboard",
@@ -1391,13 +1394,13 @@
     "button": {
       "goToArchivalBrowsing": "Go to archive browsing"
     },
-    "noResultToDisplay": "No result to display...",
     "list": {
       "action": {
         "addToCart": "Add to cart",
         "download": "Download"
       }
     },
+    "noResultToDisplay": "No result to display...",
     "or": "or"
   },
   "homePage": {
diff --git a/src/assets/i18n/fr.json b/src/assets/i18n/fr.json
index 0be198859..2a5830d00 100644
--- a/src/assets/i18n/fr.json
+++ b/src/assets/i18n/fr.json
@@ -760,6 +760,9 @@
       "newVersionAvailable": "Une nouvelle version de l'application est disponible",
       "offline": "Vous êtes actuellement hors ligne"
     },
+    "tab": {
+      "unaccessibleTab": "Vous ne pouvez pas accéder à cet onglet"
+    },
     "token": {
       "access": "Jeton d'accès",
       "copyToClipboard": "Copier dans le presse-papiers",
@@ -1391,13 +1394,13 @@
     "button": {
       "goToArchivalBrowsing": "Navigation dans les archives"
     },
-    "noResultToDisplay": "Aucun résultat à afficher...",
     "list": {
       "action": {
         "addToCart": "Ajouter au panier",
         "download": "Télécharger"
       }
     },
+    "noResultToDisplay": "Aucun résultat à afficher...",
     "or": "ou"
   },
   "homePage": {
-- 
GitLab