Skip to content

Commit

Permalink
feat(client): improve stats navigation
Browse files Browse the repository at this point in the history
  • Loading branch information
avine committed Oct 28, 2024
1 parent 18e72bf commit 8b24c0d
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 11 deletions.
3 changes: 1 addition & 2 deletions client/src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,7 @@ export const routes: Routes = [
},
{
path: 'stats',
loadComponent: () => import('./stats/stats.component'),
title: 'FeedZback - Stats',
loadChildren: () => import('./stats/stats.routes'),
},
{
path: 'demo',
Expand Down
4 changes: 2 additions & 2 deletions client/src/app/stats/stats-summary/stats-summary.component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Component, input, signal, ViewEncapsulation } from '@angular/core';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { FeedbackPeriod, FeedbackStats } from '../stats.types';
import { FeedbackStats, FeedbackStatsPeriod } from '../stats.types';

@Component({
selector: 'app-stats-summary',
Expand All @@ -14,7 +14,7 @@ import { FeedbackPeriod, FeedbackStats } from '../stats.types';
export class StatsSummaryComponent {
summary = input.required<FeedbackStats>();

period = input.required<FeedbackPeriod>();
period = input.required<FeedbackStatsPeriod>();

protected showLegend = signal(false);

Expand Down
14 changes: 14 additions & 0 deletions client/src/app/stats/stats-tab.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Note: this file contains all types and constants related to stats tabs

import { InputSignal } from '@angular/core';

export type SelectedStatsTab = 'summary' | 'details';

/**
* List of tabs as they appear in the user interface
*/
export const ORDERED_STATS_TABS = ['summary' satisfies SelectedStatsTab, 'details' satisfies SelectedStatsTab] as const;

export const STATS_TAB_PARAM = 'tab';

export type StatsTabData = Record<typeof STATS_TAB_PARAM, InputSignal<SelectedStatsTab>>;
2 changes: 1 addition & 1 deletion client/src/app/stats/stats.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<h1 class="gbl-page-title mat-headline-large"><mat-icon>monitoring</mat-icon> Stats</h1>

@if (status() === 'fetched') {
<mat-tab-group animationDuration="0ms">
<mat-tab-group animationDuration="0ms" [selectedIndex]="tabIndex()" (selectedIndexChange)="tabIndexChange($event)">
<mat-tab label="Summary">
<app-stats-summary [summary]="summary()" [period]="summaryPeriod()" />
</mat-tab>
Expand Down
22 changes: 17 additions & 5 deletions client/src/app/stats/stats.component.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { HttpClient } from '@angular/common/http';
import { Component, computed, inject, OnInit, signal, ViewEncapsulation } from '@angular/core';
import { Component, computed, inject, input, OnInit, signal, ViewEncapsulation } from '@angular/core';
import { MatIconModule } from '@angular/material/icon';
import { MatSliderModule } from '@angular/material/slider';
import { MatTabsModule } from '@angular/material/tabs';
import { Router } from '@angular/router';
import { environment } from '../../environments/environment';
import { LanguageService } from '../shared/i18n/language';
import { MessageComponent } from '../shared/message';
import { StatsDetailsComponent } from './stats-details/stats-details.component';
import { StatsSummaryComponent } from './stats-summary/stats-summary.component';
import { FeedbackPeriod, FeedbackStats, FeedbackStatsData } from './stats.types';
import { ORDERED_STATS_TABS, SelectedStatsTab, StatsTabData } from './stats-tab';
import { FeedbackStats, FeedbackStatsData, FeedbackStatsPeriod } from './stats.types';
import { formatMonth } from './stats.utils';

@Component({
Expand All @@ -30,7 +32,9 @@ import { formatMonth } from './stats.utils';
styleUrl: './stats.component.scss',
encapsulation: ViewEncapsulation.None,
})
export default class StatsComponent implements OnInit {
export class StatsComponent implements OnInit, StatsTabData {
protected router = inject(Router);

protected isFrenchLocale = inject(LanguageService).localeId === 'fr';

protected status = signal<undefined | 'fetching' | 'noDataYet' | 'fetched'>(undefined);
Expand All @@ -48,6 +52,14 @@ export default class StatsComponent implements OnInit {
this.sentimentIconsIndex.update((index) => (index + 1) % this.sentimentIcons.length);
}

tab = input.required<SelectedStatsTab>();

protected tabIndex = computed(() => ORDERED_STATS_TABS.indexOf(this.tab()));

protected tabIndexChange(index: number) {
this.router.navigate(['/stats', ORDERED_STATS_TABS[index]]); // `index` values are: 0 or 1
}

protected data = signal<FeedbackStatsData>({
summary: {} as FeedbackStats,
details: [],
Expand Down Expand Up @@ -84,7 +96,7 @@ export default class StatsComponent implements OnInit {

protected summary = computed(() => this.data().summary);

protected summaryPeriod = computed<FeedbackPeriod>(() => {
protected summaryPeriod = computed<FeedbackStatsPeriod>(() => {
const formattedMonths = this.formattedMonths();
return {
start: formattedMonths[0].long,
Expand All @@ -109,7 +121,7 @@ export default class StatsComponent implements OnInit {

protected details = computed(() => this.data().details.slice(this.sliderStart(), this.sliderEndBuilder()() + 1));

protected detailsPeriod = computed<FeedbackPeriod>(() => {
protected detailsPeriod = computed<FeedbackStatsPeriod>(() => {
const formattedMonths = this.formattedMonths();
return {
start: formattedMonths[this.sliderStart()].long,
Expand Down
10 changes: 10 additions & 0 deletions client/src/app/stats/stats.guard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { inject } from '@angular/core';
import { CanActivateFn, RedirectCommand, Router } from '@angular/router';
import { ORDERED_STATS_TABS, STATS_TAB_PARAM } from './stats-tab';

export const statsGuard: CanActivateFn = (route) => {
if (ORDERED_STATS_TABS.includes(route.params[STATS_TAB_PARAM])) {
return true;
}
return new RedirectCommand(inject(Router).parseUrl('/stats'));
};
18 changes: 18 additions & 0 deletions client/src/app/stats/stats.routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Routes } from '@angular/router';
import { STATS_TAB_PARAM } from './stats-tab';
import { StatsComponent } from './stats.component';
import { statsGuard } from './stats.guard';

export default [
{
path: '',
pathMatch: 'full',
redirectTo: '/stats/summary',
},
{
path: `:${STATS_TAB_PARAM}`,
component: StatsComponent,
canActivate: [statsGuard],
title: 'FeedZback - Stats',
},
] satisfies Routes;
2 changes: 1 addition & 1 deletion client/src/app/stats/stats.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export type FeedbackDetailsPlucked = {
sharedFeedback: number[];
};

export type FeedbackPeriod = {
export type FeedbackStatsPeriod = {
start: string;
end: string;
};
Expand Down

0 comments on commit 8b24c0d

Please sign in to comment.