init dashboard

This commit is contained in:
Marcel Arndt
2025-04-10 17:31:52 +02:00
parent 98aeb82ff6
commit 52c1a14609
178 changed files with 12306 additions and 401 deletions
@@ -0,0 +1,7 @@
.month-picker .mat-calendar-period-button {
pointer-events: none;
}
.month-picker .mat-calendar-arrow {
display: none;
}
@@ -0,0 +1,141 @@
<ng-container *ngIf="vm$ | async as vm; else loadingTmpl">
<div class="flex flex-col m-0 md:m-4" *ngIf="!vm.isLoading; else loadingTmpl">
<!-- Top row with user input elements -->
<div class="flex flex-wrap md:flex-nowrap justify-between items-center">
<div class="flex items-center m-2">
<button mat-icon-button (click)="addMonthToSelectedDate(-1)">
<mat-icon>chevron_left</mat-icon>
</button>
<div class="flex items-center">
<span class="pr-2">
{{ vm.selectedDate | date : 'MM.yyyy' }}
</span>
<input
[formControl]="selectedDate"
[matDatepicker]="picker"
[matDatepickerFilter]="notSunday"
[min]="minSelectableDate"
class="invisible w-0"
/>
<button mat-icon-button (click)="picker.open()">
<mat-icon>today</mat-icon>
</button>
<mat-datepicker
#picker
startView="multi-year"
(monthSelected)="setMonthAndYear($event, picker)"
class="month-picker"
></mat-datepicker>
</div>
<button mat-icon-button (click)="addMonthToSelectedDate(1)">
<mat-icon>chevron_right</mat-icon>
</button>
</div>
<mat-chip-listbox (change)="changeSelectedType($event)">
<mat-chip-option
[value]="DiagrammType.TimePerTour"
[selected]="vm.selectedMetric === DiagrammType.TimePerTour"
>
Kapazität pro Tour
</mat-chip-option>
<mat-chip-option
[value]="DiagrammType.BreakEven"
[selected]="vm.selectedMetric === DiagrammType.BreakEven"
>
Deckungsbeitrag
</mat-chip-option>
<mat-chip-option
[value]="DiagrammType.AverageRevenue"
[selected]="vm.selectedMetric === DiagrammType.AverageRevenue"
>
Durchschnittsumsatz
</mat-chip-option>
</mat-chip-listbox>
</div>
<div
class="my-5 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-2 lg:gap-4"
>
<dks-view-type-selector
[viewType]="DashboardViewType.BTW"
[currentMetric]="vm.selectedMetric"
[metrics]="vm.btwMetrics"
[selected]="vm.selectedViewType === DashboardViewType.BTW"
(viewTypeSelected)="setSelectedViewType(DashboardViewType.BTW)"
></dks-view-type-selector>
<dks-view-type-selector
[viewType]="DashboardViewType.TSW"
[currentMetric]="vm.selectedMetric"
[metrics]="vm.tswMetrics"
[selected]="vm.selectedViewType === DashboardViewType.TSW"
(viewTypeSelected)="setSelectedViewType(DashboardViewType.TSW)"
></dks-view-type-selector>
<dks-view-type-selector
[viewType]="DashboardViewType.KTW"
[currentMetric]="vm.selectedMetric"
[metrics]="vm.ktwMetrics"
[selected]="vm.selectedViewType === DashboardViewType.KTW"
(viewTypeSelected)="setSelectedViewType(DashboardViewType.KTW)"
></dks-view-type-selector>
<dks-view-type-selector
[viewType]="DashboardViewType.Gesamt"
[currentMetric]="vm.selectedMetric"
[metrics]="vm.combinedMetrics"
[selected]="vm.selectedViewType === DashboardViewType.Gesamt"
(viewTypeSelected)="setSelectedViewType(DashboardViewType.Gesamt)"
></dks-view-type-selector>
</div>
<div
class="grid grid-cols-2 lg:grid-cols-4 gap-2 lg:gap-4"
[ngSwitch]="vm.selectedViewType"
>
<div
*ngSwitchCase="DashboardViewType.BTW"
class="col-span-2 lg:col-span-4 w-full rounded p-2 bg-white shadow"
>
<dks-metric-summary
[metrics]="vm.btwMetrics"
[metricTimeScale]="metricTimeScale"
[selectedMetric]="vm.selectedMetric"
[labelFormat]="'d.M.yy'"
></dks-metric-summary>
</div>
<div
*ngSwitchCase="DashboardViewType.TSW"
class="col-span-2 lg:col-span-4 w-full rounded p-2 bg-white shadow"
>
<dks-metric-summary
[metrics]="vm.tswMetrics"
[metricTimeScale]="metricTimeScale"
[selectedMetric]="vm.selectedMetric"
[labelFormat]="'d.M.yy'"
></dks-metric-summary>
</div>
<div
*ngSwitchCase="DashboardViewType.KTW"
class="col-span-2 lg:col-span-4 w-full rounded p-2 bg-white shadow"
>
<dks-metric-summary
[metrics]="vm.ktwMetrics"
[metricTimeScale]="metricTimeScale"
[selectedMetric]="vm.selectedMetric"
[labelFormat]="'d.M.yy'"
></dks-metric-summary>
</div>
<div
*ngSwitchCase="DashboardViewType.Gesamt"
class="col-span-2 lg:col-span-4 w-full rounded p-2 bg-white shadow"
>
<dks-metric-summary
[metrics]="vm.combinedMetrics"
[metricTimeScale]="metricTimeScale"
[selectedMetric]="vm.selectedMetric"
[labelFormat]="'d.M.yy'"
></dks-metric-summary>
</div>
</div>
</div>
</ng-container>
<ng-template #loadingTmpl>
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
</ng-template>
@@ -0,0 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MonthviewComponent } from './monthview.component';
describe('MonthviewComponent', () => {
let component: MonthviewComponent;
let fixture: ComponentFixture<MonthviewComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [MonthviewComponent],
}).compileComponents();
fixture = TestBed.createComponent(MonthviewComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,139 @@
import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';
import { MatChipListboxChange } from '@angular/material/chips';
import { MatDatepicker } from '@angular/material/datepicker';
import { addDays, addMonths, format, isSunday, startOfMonth } from 'date-fns';
import {
BehaviorSubject,
combineLatest,
map,
startWith,
switchMap,
} from 'rxjs';
import { groupBy } from '../../../core/util/group-by';
import { ManagerDashboardService } from '../manager-dashboard.service';
import {
DashboardViewType,
DiagrammType,
MetricTimeScale,
OrdinanceTypes,
} from '../types';
import { mergeMetrics } from '../util/merge-metric';
@Component({
selector: 'dks-monthview',
templateUrl: './monthview.component.html',
styleUrls: ['./monthview.component.css'],
})
export class MonthviewComponent {
OrdinanceTypes = OrdinanceTypes;
DiagrammType = DiagrammType;
DashboardViewType = DashboardViewType;
minSelectableDate = new Date('2022-08-01');
metricTimeScale = MetricTimeScale.Monthview;
selectedDate = new FormControl<Date>(addDays(startOfMonth(new Date()), 1));
selectedDate$ = this.selectedDate.valueChanges.pipe(
startWith(this.selectedDate.value)
);
selectedMetric$ = new BehaviorSubject<DiagrammType>(DiagrammType.TimePerTour);
selectedViewType$ = new BehaviorSubject<DashboardViewType>(
DashboardViewType.Gesamt
);
vm$;
constructor(
private readonly managerDashboardService: ManagerDashboardService
) {
this.vm$ = combineLatest([
this.selectedDate$.pipe(
switchMap((selectedDate) =>
this.managerDashboardService.getTimePerTourMetricByOrdinanceTypeForMonth(
OrdinanceTypes.BTW,
selectedDate ?? new Date()
)
)
),
this.selectedDate$.pipe(
switchMap((selectedDate) =>
this.managerDashboardService.getTimePerTourMetricByOrdinanceTypeForMonth(
OrdinanceTypes.TSW,
selectedDate ?? new Date()
)
)
),
this.selectedDate$.pipe(
switchMap((selectedDate) =>
this.managerDashboardService.getTimePerTourMetricByOrdinanceTypeForMonth(
OrdinanceTypes.KTW,
selectedDate ?? new Date()
)
)
),
this.selectedMetric$,
this.selectedDate$,
this.managerDashboardService.isLoadingMonthview$,
this.selectedViewType$,
]).pipe(
map(
([
btwMetrics,
tswMetrics,
ktwMetrics,
selectedMetric,
selectedDate,
isLoading,
selectedViewType,
]) => ({
btwMetrics,
tswMetrics,
ktwMetrics,
selectedMetric,
selectedDate,
isLoading,
selectedViewType,
combinedMetrics: mergeMetrics(
Object.values(
groupBy(
[...btwMetrics, ...tswMetrics, ...ktwMetrics],
({ interval: { start } }) => format(new Date(start), 'd.M.yy')
)
)
),
})
)
);
}
notSunday = (date: Date | null): boolean => {
return !isSunday(date ?? new Date());
};
addMonthToSelectedDate(months: number): void {
const nextSelectedDate = addMonths(
this.selectedDate.value ?? new Date(),
months
);
if (isSunday(nextSelectedDate)) {
this.selectedDate.setValue(addDays(nextSelectedDate, 1));
} else {
this.selectedDate.setValue(nextSelectedDate);
}
}
changeSelectedType(event: MatChipListboxChange) {
this.selectedMetric$.next(event.value);
}
setMonthAndYear(
normalizedMonthAndYear: Date,
datepicker: MatDatepicker<Date>
) {
this.selectedDate.setValue(addDays(normalizedMonthAndYear, 1));
datepicker.close();
}
setSelectedViewType(viewType: DashboardViewType) {
this.selectedViewType$.next(viewType);
}
}