WIP timeframes

urls
Max 4 years ago
parent 010025325e
commit 2fc902403e

@ -10,6 +10,7 @@ generates:
- "typescript-apollo-angular" - "typescript-apollo-angular"
config: config:
immutableTypes: false immutableTypes: false
preResolveTypes: true
src/generated/graphql.schema.json: src/generated/graphql.schema.json:
plugins: plugins:
- "introspection" - "introspection"

@ -9,6 +9,7 @@ import { EquipmentTypesComponent } from './pages/tables/equipment-types/equipmen
import { EquipmentComponent } from './pages/tables/equipment/equipment.component'; import { EquipmentComponent } from './pages/tables/equipment/equipment.component';
import { LendingStationsComponent } from './pages/tables/lending-stations/lending-stations.component'; import { LendingStationsComponent } from './pages/tables/lending-stations/lending-stations.component';
import { ParticipantsComponent } from './pages/tables/participants/participants.component'; import { ParticipantsComponent } from './pages/tables/participants/participants.component';
import { TimeFramesComponent } from './pages/tables/time-frames/time-frames.component';
const routes: Routes = [ const routes: Routes = [
{ path: 'login', component: LoginComponent }, { path: 'login', component: LoginComponent },
@ -20,6 +21,7 @@ const routes: Routes = [
{ path: 'table/equipmentTypes', component: EquipmentTypesComponent }, { path: 'table/equipmentTypes', component: EquipmentTypesComponent },
{ path: 'table/engagementTypes', component: EngagementTypesComponent }, { path: 'table/engagementTypes', component: EngagementTypesComponent },
{ path: 'table/equipment', component: EquipmentComponent }, { path: 'table/equipment', component: EquipmentComponent },
{ path: 'table/timeFrames', component: TimeFramesComponent },
{ path: '', redirectTo: 'tableOverview', pathMatch: 'full' }, { path: '', redirectTo: 'tableOverview', pathMatch: 'full' },
{ path: 'table', redirectTo: 'tableOverview', pathMatch: 'full' }, { path: 'table', redirectTo: 'tableOverview', pathMatch: 'full' },
{ path: '**', redirectTo: 'tableOverview' }, { path: '**', redirectTo: 'tableOverview' },

@ -1,5 +1,5 @@
<div id="page-wrapper"> <div id="page-wrapper">
<mat-toolbar id="navbar"> <mat-toolbar id="navbar" color="primary">
<button mat-icon-button (click)="navService.openNav()" *ngIf="loggedIn"> <button mat-icon-button (click)="navService.openNav()" *ngIf="loggedIn">
<mat-icon>menu</mat-icon> <mat-icon>menu</mat-icon>
</button> </button>

@ -6,6 +6,8 @@ import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { DragDropModule } from '@angular/cdk/drag-drop'; import { DragDropModule } from '@angular/cdk/drag-drop';
import { FlexLayoutModule } from '@angular/flex-layout'; import { FlexLayoutModule } from '@angular/flex-layout';
import { DatePipe } from '@angular/common'
// Angular Material Components // Angular Material Components
import { MatToolbarModule } from '@angular/material/toolbar'; import { MatToolbarModule } from '@angular/material/toolbar';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
@ -20,15 +22,16 @@ import { MatFormFieldModule } from '@angular/material/form-field';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatProgressBarModule } from '@angular/material/progress-bar'; import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatCheckboxModule } from '@angular/material/checkbox';
import {MatCardModule} from '@angular/material/card'; import { MatCardModule } from '@angular/material/card';
import {MatGridListModule} from '@angular/material/grid-list'; import { MatGridListModule } from '@angular/material/grid-list';
import {MatTooltipModule} from '@angular/material/tooltip'; import { MatTooltipModule } from '@angular/material/tooltip';
import {MatSelectModule} from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatPaginatorModule } from '@angular/material/paginator'; import { MatPaginatorModule } from '@angular/material/paginator';
import { MatSortModule } from '@angular/material/sort'; import { MatSortModule } from '@angular/material/sort';
import {MatDialogModule} from '@angular/material/dialog'; import { MatDialogModule } from '@angular/material/dialog';
import {MatAutocompleteModule} from '@angular/material/autocomplete'; import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatNativeDateModule, MAT_DATE_LOCALE } from '@angular/material/core';
import { AppRoutingModule } from './app-routing.module'; import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
@ -41,18 +44,23 @@ import { LendingStationsComponent } from './pages/tables/lending-stations/lendin
import { TableOverviewComponent } from './pages/table-overview/table-overview.component'; import { TableOverviewComponent } from './pages/table-overview/table-overview.component';
import { CellComponent } from './components/tableComponents/cell/cell.component'; import { CellComponent } from './components/tableComponents/cell/cell.component';
import { MenuListItemComponent } from './components/menu-list-item/menu-list-item.component'; import { MenuListItemComponent } from './components/menu-list-item/menu-list-item.component';
import {SidenavProfileComponent} from './components/sidenav-profile/sidenav-profile.component'; import { SidenavProfileComponent } from './components/sidenav-profile/sidenav-profile.component';
import { NavService }from './components/menu-list-item/nav.service'; import { NavService } from './components/menu-list-item/nav.service';
import { TokenInterceptor } from './helper/token.interceptor'; import { TokenInterceptor } from './helper/token.interceptor';
import { BikeComponent } from './pages/dataPages/bike/bike.component'; import { BikeComponent } from './pages/dataPages/bike/bike.component';
import { TableComponent, DeleteConfirmationDialog } from './components/table/table.component'; import {
TableComponent,
DeleteConfirmationDialog,
} from './components/table/table.component';
import { DataPageComponent } from './components/data-page/data-page.component'; import { DataPageComponent } from './components/data-page/data-page.component';
import { EquipmentTypesComponent } from './pages/tables/equipment-types/equipment-types.component'; import { EquipmentTypesComponent } from './pages/tables/equipment-types/equipment-types.component';
import { EngagementTypesComponent } from './pages/tables/engagement-types/engagement-types.component'; import { EngagementTypesComponent } from './pages/tables/engagement-types/engagement-types.component';
import { WorkshopsComponent } from './pages/tables/workshops/workshops.component'; import { WorkshopsComponent } from './pages/tables/workshops/workshops.component';
import { ReferenceTableComponent } from './components/reference-table/reference-table.component' import { ReferenceTableComponent } from './components/reference-table/reference-table.component';
import { MatSnackBarModule } from '@angular/material/snack-bar'; import { MatSnackBarModule } from '@angular/material/snack-bar';
import { EquipmentComponent } from './pages/tables/equipment/equipment.component'; import { EquipmentComponent } from './pages/tables/equipment/equipment.component';
import { TimeFramesComponent } from './pages/tables/time-frames/time-frames.component';
@NgModule({ @NgModule({
@ -74,7 +82,8 @@ import { EquipmentComponent } from './pages/tables/equipment/equipment.component
EngagementTypesComponent, EngagementTypesComponent,
WorkshopsComponent, WorkshopsComponent,
ReferenceTableComponent, ReferenceTableComponent,
EquipmentComponent EquipmentComponent,
TimeFramesComponent,
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
@ -107,12 +116,19 @@ import { EquipmentComponent } from './pages/tables/equipment/equipment.component
MatPaginatorModule, MatPaginatorModule,
MatSortModule, MatSortModule,
MatDialogModule, MatDialogModule,
MatAutocompleteModule MatAutocompleteModule,
MatDatepickerModule,
MatNativeDateModule
], ],
providers: [NavService, providers: [
{ provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true }], NavService,
MatNativeDateModule,
MatDatepickerModule,
DatePipe,
{ provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true },
{provide: MAT_DATE_LOCALE, useValue: 'de-DE'},
],
bootstrap: [AppComponent], bootstrap: [AppComponent],
}) })
export class AppModule { export class AppModule {}
}

@ -49,7 +49,7 @@ export class ReferenceTableComponent {
@Input() @Input()
set data(newdata) { set data(newdata) {
if (!newdata) return; if (!newdata) { return; }
this.dataSource.data = []; this.dataSource.data = [];
for (const element of newdata) { for (const element of newdata) {
this.dataSource.data.push(flatten(element)); this.dataSource.data.push(flatten(element));
@ -145,7 +145,7 @@ export class ReferenceTableComponent {
const index = this.dataSource.data.findIndex( const index = this.dataSource.data.findIndex(
(element) => element.id === row.id (element) => element.id === row.id
); );
if (index === -1) return; if (index === -1) { return; }
this.dataSource.data.splice(index, 1); this.dataSource.data.splice(index, 1);
this.dataSource.data = this.dataSource.data; //needed to trigger update lol this.dataSource.data = this.dataSource.data; //needed to trigger update lol
this.filterPossibleValueOptions(); this.filterPossibleValueOptions();

@ -118,6 +118,7 @@
<td mat-cell *matCellDef="let element"> <td mat-cell *matCellDef="let element">
<app-cell <app-cell
*ngIf=" *ngIf="
column.type === 'DateRange' ||
column.type === 'Boolean' || column.type === 'Boolean' ||
element.newObject || element.newObject ||
(!column.readonly && element.isLockedByMe); (!column.readonly && element.isLockedByMe);

@ -9,7 +9,6 @@ import {
ChangeDetectorRef, ChangeDetectorRef,
} from '@angular/core'; } from '@angular/core';
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop'; import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
import { CargoBikeResult } from 'src/app/services/bikes.service';
import { flatten } from 'src/app/helperFunctions/flattenObject'; import { flatten } from 'src/app/helperFunctions/flattenObject';
import { deepen } from 'src/app/helperFunctions/deepenObject'; import { deepen } from 'src/app/helperFunctions/deepenObject';
import { SchemaService } from 'src/app/services/schema.service'; import { SchemaService } from 'src/app/services/schema.service';
@ -64,7 +63,7 @@ export class TableComponent implements AfterViewInit {
/** data source of the table */ /** data source of the table */
data: MatTableDataSource<any> = new MatTableDataSource(); data: MatTableDataSource<any> = new MatTableDataSource();
selection = new SelectionModel<CargoBikeResult>(true, []); selection = new SelectionModel<any>(true, []);
reloadingTable = false; reloadingTable = false;
@ -194,7 +193,7 @@ export class TableComponent implements AfterViewInit {
this.tableDataGQLUpdateInputType, this.tableDataGQLUpdateInputType,
column.dataPath column.dataPath
); );
column.readonly = column.readonly || !typeInformation.isPartOfType; column.readonly = column.readonly !== null ? column.readonly : !typeInformation.isPartOfType;
} }
for (const column of this.columnInfo) { for (const column of this.columnInfo) {
const typeInformation = this.schemaService.getTypeInformation( const typeInformation = this.schemaService.getTypeInformation(

@ -6,12 +6,13 @@
[disabled]="!editable" [disabled]="!editable"
[ngModel]="value" [ngModel]="value"
(ngModelChange)="change($event)" (ngModelChange)="change($event)"
><span *ngIf="label">{{label}}</span></mat-checkbox> ><span *ngIf="label">{{ label }}</span></mat-checkbox
>
</div> </div>
<div #enumInputType *ngIf="htmlInputType === 'enum'"> <div #enumInputType *ngIf="htmlInputType === 'enum'">
<mat-form-field *ngIf="editable || label; else nonEditableText"> <mat-form-field *ngIf="editable || label; else nonEditableText">
<mat-label *ngIf="label">{{label}}</mat-label> <mat-label *ngIf="label">{{ label }}</mat-label>
<mat-select <mat-select
[(ngModel)]="value" [(ngModel)]="value"
(ngModelChange)="change($event)" (ngModelChange)="change($event)"
@ -29,12 +30,62 @@
</ng-template> </ng-template>
</div> </div>
<ng-container *ngIf="htmlInputType === 'dateRange'">
<mat-form-field>
<mat-label>Zeitraum auswählen</mat-label>
<mat-date-range-input [rangePicker]="picker" disabled>
<input
matStartDate
placeholder="Startdatum"
[value]="value?.from"
(dateChange)="startDateChange($event)"
/>
<input
matEndDate
placeholder="Enddatum"
[value]="value?.to"
(dateChange)="endDateChange($event)"
/>
</mat-date-range-input>
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-date-range-picker
#picker
[disabled]="!editable"
></mat-date-range-picker>
</mat-form-field>
</ng-container>
<div *ngIf="htmlInputType === 'numberRange'" class="number-range-wrapper">
<mat-form-field class="number-range-form-field">
<mat-label *ngIf="label">{{ label }}</mat-label>
<input
matInput
type="number"
[disabled]="!editable"
[value]="value.min"
(input)="minValueChange($event)"
[required]="required"
/>
</mat-form-field>
<span class="range-spacer">-</span>
<mat-form-field class="number-range-form-field">
<input
matInput
type="number"
[disabled]="!editable"
[value]="value.max"
(input)="maxValueChange($event)"
[required]="required"
/>
</mat-form-field>
</div>
<div <div
#otherInputType #otherInputType
*ngIf="htmlInputType === 'number' || htmlInputType === 'text'" *ngIf="htmlInputType === 'number' || htmlInputType === 'text'"
> >
<mat-form-field *ngIf="editable || label; else nonEditableText"> <mat-form-field *ngIf="editable || label; else nonEditableText">
<mat-label *ngIf="label">{{label}}</mat-label> <mat-label *ngIf="label">{{ label }}</mat-label>
<input <input
#input="ngModel" #input="ngModel"
matInput matInput
@ -47,6 +98,8 @@
</mat-form-field> </mat-form-field>
<ng-template #nonEditableText> <ng-template #nonEditableText>
<span *ngIf="!link">{{ value }}</span> <span *ngIf="!link">{{ value }}</span>
<a mat-button color="primary" *ngIf="link" [routerLink]="link">{{value}}</a> <a mat-button color="primary" *ngIf="link" [routerLink]="link">{{
value
}}</a>
</ng-template> </ng-template>
</div> </div>

@ -0,0 +1,8 @@
.number-range-wrapper {
display: flex;
flex-direction: row;
align-items: center;
.range-spacer {
margin: 0 0.5em;
}
}

@ -1,3 +1,4 @@
import { DatePipe } from '@angular/common';
import { import {
Component, Component,
Input, Input,
@ -6,6 +7,7 @@ import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
ViewChild, ViewChild,
ChangeDetectorRef, ChangeDetectorRef,
AfterViewInit,
} from '@angular/core'; } from '@angular/core';
@Component({ @Component({
@ -13,10 +15,15 @@ import {
templateUrl: './cell.component.html', templateUrl: './cell.component.html',
styleUrls: ['./cell.component.scss'], styleUrls: ['./cell.component.scss'],
}) })
export class CellComponent { export class CellComponent implements AfterViewInit {
@Input() @Input()
value: number | string | boolean; value: any; // number | string | boolean | { start: string; end: string; };
@Output() valueChange = new EventEmitter<number | string | boolean>(); minValue: number;
maxValue: number;
@Output() valueChange = new EventEmitter<
number | string | boolean | { start: string; end: string }
>();
@Input() @Input()
editable = false; editable = false;
_inputType = 'text'; _inputType = 'text';
@ -29,23 +36,23 @@ export class CellComponent {
this.getHtmlInputType(type); this.getHtmlInputType(type);
} }
@Input() @Input()
required: boolean = false; required = false;
@Input() @Input()
link: string = null; link: string = null;
@Input() @Input()
label: string = null; label: string = null;
@Output() validityChange = new EventEmitter<boolean>(); @Output() validityChange = new EventEmitter<boolean>();
isValid: boolean = true; isValid = true;
enumValues = []; enumValues = [];
htmlInputType: string = 'string'; htmlInputType = 'string';
@ViewChild('input') input: any; @ViewChild('input') input: any;
constructor(private cdr: ChangeDetectorRef) {} constructor(private cdr: ChangeDetectorRef, public datepipe: DatePipe) {}
ngAfterViewInit() { ngAfterViewInit(): void {
if (this.required) { if (this.required) {
this.input?.control?.markAsTouched(); this.input?.control?.markAsTouched();
this.checkIfValid(); this.checkIfValid();
@ -63,7 +70,7 @@ export class CellComponent {
} }
} }
getHtmlInputType(type: string) { getHtmlInputType(type: string): void {
if (type.split('//')[0] === 'Enum') { if (type.split('//')[0] === 'Enum') {
this.enumValues = type.split('//').slice(1); this.enumValues = type.split('//').slice(1);
this.htmlInputType = 'enum'; this.htmlInputType = 'enum';
@ -73,10 +80,23 @@ export class CellComponent {
this.htmlInputType = 'text'; this.htmlInputType = 'text';
} else if (type === 'Boolean') { } else if (type === 'Boolean') {
this.htmlInputType = 'boolean'; this.htmlInputType = 'boolean';
} else if (type === 'Date') {
this.htmlInputType = 'date';
} else if (type === 'DateRange') {
this.htmlInputType = 'dateRange';
} else if (type === 'NumRange') {
this.htmlInputType = 'numberRange';
if (
!this.value ||
this.value.min === undefined ||
this.value.max === undefined
) {
this.value = { min: null, max: null };
}
} }
} }
change(newValue) { change(newValue): void {
if (this.inputType === 'Int') { if (this.inputType === 'Int') {
newValue = newValue.toString().replace('.', ''); newValue = newValue.toString().replace('.', '');
} }
@ -88,10 +108,50 @@ export class CellComponent {
this.checkIfValid(); this.checkIfValid();
} }
startDateChange(event): void {
console.log('start');
console.log(event.value);
console.log(this.transformDate(event.value));
this.value.start = this.transformDate(event.value);
this.valueChange.emit(this.value);
}
endDateChange(event) {
console.log('end');
console.log(event.value);
console.log(this.transformDate(event.value));
this.value.end = this.transformDate(event.value);
this.valueChange.emit(this.value);
}
minValueChange(event) {
this.value.min = this.toNumber(event.target.value);
this.valueChange.emit(this.value);
console.log(this.value);
}
maxValueChange(event) {
this.value.max = this.toNumber(event.target.value);
this.valueChange.emit(this.value);
console.log(this.value);
}
transformDate(date) {
return this.datepipe.transform(date, 'yyyy-MM-dd');
}
checkIfValid() { checkIfValid() {
if (this.required && this.inputType !== 'Boolean') { if (this.required && this.inputType !== 'Boolean') {
this.isValid = this.input?.control?.valid || false; this.isValid = this.input?.control?.valid || false;
this.validityChange.emit(this.isValid); this.validityChange.emit(this.isValid);
} }
} }
toNumber(str: string): number {
if (str === '') {
return null;
}
return +str;
}
} }

@ -33,12 +33,18 @@ fragment CargoBikeFieldsForTable on CargoBike {
bikeLength bikeLength
bikeWeight bikeWeight
bikeWidth bikeWidth
minBoxHeight boxHeightRange {
maxBoxHeight max
minBoxLength min
maxBoxLength }
minBoxWidth boxLengthRange {
maxBoxWidth min
max
}
boxWidthRange {
min
max
}
hasCoverBox hasCoverBox
lockable lockable
maxWeightBox maxWeightBox
@ -77,23 +83,23 @@ fragment CargoBikeFieldsForTable on CargoBike {
} }
fragment CargoBikeFieldsForPage on CargoBike { fragment CargoBikeFieldsForPage on CargoBike {
...CargoBikeFieldsForTable ...CargoBikeFieldsForTable
bikeEvents { bikeEvents {
...BikeEventFieldsForBikePage ...BikeEventFieldsForBikePage
} }
equipment { equipment {
...EquipmentFieldsForBikePage ...EquipmentFieldsForBikePage
} }
equipmentType { equipmentType {
...EquipmentTypeFields ...EquipmentTypeFields
} }
engagement { engagement {
...EngagementFieldsForBikePage ...EngagementFieldsForBikePage
} }
currentEngagements { currentEngagements {
...EngagementFieldsForBikePage ...EngagementFieldsForBikePage
} }
timeFrames { timeFrames {
...TimeFrameFieldsForBikePage ...TimeFrameFieldsForBikePage
}
} }
}

@ -1,13 +1,36 @@
fragment TimeFrameFieldsForBikePage on TimeFrame { fragment TimeFrameFieldsForBikePage on TimeFrame {
id id
from dateRange {
from
to to
note }
lendingStation { note
...LendingStationFieldsForBikePage lendingStation {
} ...LendingStationFieldsForBikePage
isLocked }
isLocked
isLockedByMe
lockedBy
lockedUntil
}
fragment TimeFrameFields on TimeFrame {
id
dateRange {
from
to
}
note
lendingStation {
id
name
}
cargoBike {
id
name
}
isLocked
isLockedByMe isLockedByMe
lockedBy lockedBy
lockedUntil lockedUntil
} }

@ -0,0 +1,33 @@
query GetTimeFrames {
timeFrames {
...TimeFrameFields
}
}
mutation CreateTimeFrame($timeFrame: TimeFrameCreateInput!) {
createTimeFrame(timeFrame: $timeFrame) {
...TimeFrameFields
}
}
mutation UpdateTimeFrame($timeFrame: TimeFrameUpdateInput!) {
updateTimeFrame(timeFrame: $timeFrame) {
...TimeFrameFields
}
}
mutation LockTimeFrame($id: ID!) {
lockTimeFrame(id: $id) {
...TimeFrameFields
}
}
mutation UnlockTimeFrame($id: ID!) {
unlockTimeFrame(id: $id) {
...TimeFrameFields
}
}
mutation DeleteTimeFrame($id: ID!) {
deleteTimeFrame(id: $id)
}

@ -67,28 +67,16 @@ export class BikeComponent implements OnInit {
{ dataPath: 'dimensionsAndLoad.bikeHeight', translation: 'Höhe' }, { dataPath: 'dimensionsAndLoad.bikeHeight', translation: 'Höhe' },
{ dataPath: 'dimensionsAndLoad.bikeWidth', translation: 'Breite' }, { dataPath: 'dimensionsAndLoad.bikeWidth', translation: 'Breite' },
{ {
dataPath: 'dimensionsAndLoad.minBoxHeight', dataPath: 'dimensionsAndLoad.boxHeightRange',
translation: 'Boxhöhe min', translation: 'Boxhöhe',
}, },
{ {
dataPath: 'dimensionsAndLoad.maxBoxHeight', dataPath: 'dimensionsAndLoad.boxLengthRange',
translation: 'Boxhöhe max', translation: 'Boxlänge',
}, },
{ {
dataPath: 'dimensionsAndLoad.minBoxLength', dataPath: 'dimensionsAndLoad.boxWidthRange',
translation: 'Boxlänge min', translation: 'Boxbreite',
},
{
dataPath: 'dimensionsAndLoad.maxBoxLength',
translation: 'Boxlänge max',
},
{
dataPath: 'dimensionsAndLoad.minBoxWidth',
translation: 'Boxbreite min',
},
{
dataPath: 'dimensionsAndLoad.maxBoxWidth',
translation: 'Boxbreite max',
}, },
{ {
dataPath: 'dimensionsAndLoad.hasCoverBox', dataPath: 'dimensionsAndLoad.hasCoverBox',
@ -227,7 +215,7 @@ export class BikeComponent implements OnInit {
}, },
linkToTable: (element) => '/table/equipment', linkToTable: (element) => '/table/equipment',
linkToTableParams: (bike) => { linkToTableParams: (bike) => {
return {filter: bike.name}; return { filter: bike.name };
}, },
propertyNameOfUpdateInput: 'equipmentIds', propertyNameOfUpdateInput: 'equipmentIds',
}, },

@ -49,12 +49,9 @@ export class BikesComponent implements OnInit {
{ dataPath: 'dimensionsAndLoad.bikeWeight', translation: 'Gewicht' }, { dataPath: 'dimensionsAndLoad.bikeWeight', translation: 'Gewicht' },
{ dataPath: 'dimensionsAndLoad.bikeHeight', translation: 'Höhe' }, { dataPath: 'dimensionsAndLoad.bikeHeight', translation: 'Höhe' },
{ dataPath: 'dimensionsAndLoad.bikeWidth', translation: 'Breite' }, { dataPath: 'dimensionsAndLoad.bikeWidth', translation: 'Breite' },
{ dataPath: 'dimensionsAndLoad.minBoxHeight', translation: 'Boxhöhe min' }, { dataPath: 'dimensionsAndLoad.boxHeightRange', translation: 'Boxhöhe' },
{ dataPath: 'dimensionsAndLoad.maxBoxHeight', translation: 'Boxhöhe max' }, { dataPath: 'dimensionsAndLoad.boxLengthRange', translation: 'Boxlänge' },
{ dataPath: 'dimensionsAndLoad.minBoxLength', translation: 'Boxlänge min' }, { dataPath: 'dimensionsAndLoad.boxWidthRange', translation: 'Boxbreite' },
{ dataPath: 'dimensionsAndLoad.maxBoxLength', translation: 'Boxlänge max' },
{ dataPath: 'dimensionsAndLoad.minBoxWidth', translation: 'Boxbreite min' },
{ dataPath: 'dimensionsAndLoad.maxBoxWidth', translation: 'Boxbreite max' },
{ {
dataPath: 'dimensionsAndLoad.hasCoverBox', dataPath: 'dimensionsAndLoad.hasCoverBox',
translation: 'Boxabdeckung j/n', translation: 'Boxabdeckung j/n',

@ -0,0 +1,13 @@
<app-table
[headline]="headline"
[columnInfo]="columnInfo"
[dataService]="dataService"
[tableDataGQLType]="tableDataGQLType"
[tableDataGQLCreateInputType]="tableDataGQLCreateInputType"
[tableDataGQLUpdateInputType]="tableDataGQLUpdateInputType"
(createEvent)="create($event)"
(lockEvent)="lock($event)"
(saveEvent)="save($event)"
(cancelEvent)="cancel($event)"
(deleteEvent)="delete($event)"
></app-table>

@ -0,0 +1,61 @@
import { Component, OnInit } from '@angular/core';
import { TimeFrameService } from 'src/app/services/timeFrame.service';
@Component({
selector: 'app-time-frames',
templateUrl: './time-frames.component.html',
styleUrls: ['./time-frames.component.scss'],
})
export class TimeFramesComponent implements OnInit {
headline = 'Zeitscheiben';
columnInfo = [
{ dataPath: 'dataRange', translation: 'Zeitraum', type: 'DateRange', readonly: false },
{
dataPath: 'cargoBike.name',
translation: 'Lastenrad',
link: (element) => {
return '/bike/' + element['cargoBike.id'];
},
},
{
dataPath: 'lendingStation.name',
translation: 'Ausleihstation',
link: (element) => {
return '/lendingStation/' + element['lendingStation.id'];
},
},
];
dataService: TimeFrameService;
tableDataGQLType: string = 'TimeFrame';
tableDataGQLCreateInputType: string = 'TimeFrameCreateInput';
tableDataGQLUpdateInputType: string = 'TimeFrameUpdateInput';
loadingRowIds: string[] = [];
constructor(private service: TimeFrameService) {}
ngOnInit() {
this.dataService = this.service;
}
create(value: { currentId: string; row: any }) {
this.dataService.create(value.currentId, { timeFrame: value.row });
}
lock(row: any) {
this.dataService.lock({ id: row.id });
}
save(row: any) {
this.dataService.update({ timeFrame: row });
}
cancel(row: any) {
this.dataService.unlock({ id: row.id });
}
delete(row: any) {
this.dataService.delete({ id: row.id });
}
}

@ -2,7 +2,6 @@ import { Injectable } from '@angular/core';
import { BehaviorSubject, Subject } from 'rxjs'; import { BehaviorSubject, Subject } from 'rxjs';
import { import {
GetCargoBikesGQL, GetCargoBikesGQL,
GetCargoBikesQuery,
ReloadCargoBikeByIdGQL, ReloadCargoBikeByIdGQL,
ReloadCargoBikeByIdQueryVariables, ReloadCargoBikeByIdQueryVariables,
UpdateCargoBikeGQL, UpdateCargoBikeGQL,
@ -18,19 +17,13 @@ import {
GetCargoBikeByIdGQL, GetCargoBikeByIdGQL,
GetCargoBikeByIdQueryVariables, GetCargoBikeByIdQueryVariables,
} from 'src/generated/graphql'; } from 'src/generated/graphql';
import { DeepExtractTypeSkipArrays } from 'ts-deep-extract-types';
export type CargoBikeResult = DeepExtractTypeSkipArrays<
GetCargoBikesQuery,
['cargoBikes']
>;
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',
}) })
export class BikesService { export class BikesService {
/** CargoBikes Array */ /** CargoBikes Array */
tableData: BehaviorSubject<CargoBikeResult[]> = new BehaviorSubject(null); tableData: BehaviorSubject<any[]> = new BehaviorSubject(null);
loadingRowIds: BehaviorSubject<string[]> = new BehaviorSubject([]); loadingRowIds: BehaviorSubject<string[]> = new BehaviorSubject([]);
successfullyCreatedRowWithId: Subject<string> = new Subject(); successfullyCreatedRowWithId: Subject<string> = new Subject();
pageData: BehaviorSubject<any> = new BehaviorSubject(null); pageData: BehaviorSubject<any> = new BehaviorSubject(null);
@ -141,7 +134,7 @@ export class BikesService {
this.deleteCargoBikeGQL this.deleteCargoBikeGQL
.mutate(variables) .mutate(variables)
.subscribe((result) => { .subscribe((result) => {
if (result.data.deleteCargoBike) { if (result.data) {
this.tableData.next( this.tableData.next(
[...this.tableData.value].filter((bike) => bike.id !== variables.id) [...this.tableData.value].filter((bike) => bike.id !== variables.id)
); );

@ -103,7 +103,7 @@ export class EquipmentService {
this.deleteEquipmentGQL this.deleteEquipmentGQL
.mutate(variables) .mutate(variables)
.subscribe((result) => { .subscribe((result) => {
if (result.data.deleteEquipment) { if (result.data) {
this.tableData.next( this.tableData.next(
[...this.tableData.value].filter((bike) => bike.id !== variables.id) [...this.tableData.value].filter((bike) => bike.id !== variables.id)
); );

@ -103,7 +103,7 @@ export class EquipmentTypeService {
this.deleteEquipmentTypeGQL this.deleteEquipmentTypeGQL
.mutate(variables) .mutate(variables)
.subscribe((result) => { .subscribe((result) => {
if (result.data.deleteEquipmentType) { if (result.data) {
this.tableData.next( this.tableData.next(
[...this.tableData.value].filter((bike) => bike.id !== variables.id) [...this.tableData.value].filter((bike) => bike.id !== variables.id)
); );

@ -0,0 +1,125 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject, Subject } from 'rxjs';
import {
GetTimeFramesGQL,
CreateTimeFrameGQL,
CreateTimeFrameMutationVariables,
UpdateTimeFrameGQL,
UpdateTimeFrameMutationVariables,
LockTimeFrameGQL,
LockTimeFrameMutationVariables,
UnlockTimeFrameGQL,
UnlockTimeFrameMutationVariables,
DeleteTimeFrameGQL,
DeleteTimeFrameMutationVariables,
} from '../../generated/graphql';
@Injectable({
providedIn: 'root',
})
export class TimeFrameService {
/** TimeFrames Array */
tableData: BehaviorSubject<any[]> = new BehaviorSubject(null);
loadingRowIds: BehaviorSubject<string[]> = new BehaviorSubject([]);
successfullyCreatedRowWithId: Subject<string> = new Subject();
//pageData: BehaviorSubject<any> = new BehaviorSubject([]);
//isLoadingPageData: BehaviorSubject<boolean> = new BehaviorSubject(false);
constructor(
private getTimeFramesGQL: GetTimeFramesGQL,
private createTimeFrameGQL: CreateTimeFrameGQL,
private updateTimeFrameGQL: UpdateTimeFrameGQL,
private lockTimeFrameGQL: LockTimeFrameGQL,
private unlockTimeFrameGQL: UnlockTimeFrameGQL,
private deleteTimeFrameGQL: DeleteTimeFrameGQL
) {}
addLoadingRowId(id: string) {
this.loadingRowIds.next([...this.loadingRowIds.value, id]);
}
removeLoadingRowId(id: string) {
this.loadingRowIds.value.forEach((item, index) => {
if (item === id) {
this.loadingRowIds.value.splice(index, 1);
}
});
this.loadingRowIds.next(this.loadingRowIds.value);
}
loadTableData() {
this.tableData.next(null);
this.getTimeFramesGQL.fetch().subscribe((result) => {
this.tableData.next(result.data.timeFrames);
});
}
create(currentId: string, variables: CreateTimeFrameMutationVariables) {
this.createTimeFrameGQL.mutate(variables).subscribe((result) => {
const newRow = result.data.createTimeFrame;
this.tableData.next([newRow, ...this.tableData.value]);
this.successfullyCreatedRowWithId.next(currentId);
});
}
update(variables: UpdateTimeFrameMutationVariables) {
this.addLoadingRowId(variables.timeFrame.id);
this.updateTimeFrameGQL
.mutate(variables)
.subscribe((result) => {
this.updateDataRowFromResponse(result.data.updateTimeFrame);
})
.add(() => {
this.removeLoadingRowId(variables.timeFrame.id);
});
}
lock(variables: LockTimeFrameMutationVariables) {
this.addLoadingRowId(variables.id);
this.lockTimeFrameGQL
.mutate(variables)
.subscribe((result) => {
this.updateDataRowFromResponse(result.data.lockTimeFrame);
})
.add(() => {
this.removeLoadingRowId(variables.id);
});
}
unlock(variables: UnlockTimeFrameMutationVariables) {
this.addLoadingRowId(variables.id);
this.unlockTimeFrameGQL
.mutate(variables)
.subscribe((result) => {
this.updateDataRowFromResponse(result.data.unlockTimeFrame);
})
.add(() => {
this.removeLoadingRowId(variables.id);
});
}
delete(variables: DeleteTimeFrameMutationVariables) {
this.addLoadingRowId(variables.id);
this.deleteTimeFrameGQL
.mutate(variables)
.subscribe((result) => {
if (result.data) {
this.tableData.next(
[...this.tableData.value].filter((bike) => bike.id !== variables.id)
);
}
})
.add(() => {
this.removeLoadingRowId(variables.id);
});
}
private updateDataRowFromResponse(rowFromResponse: any) {
if (this.tableData.value) {
const newTableData = this.tableData.value.map((row) =>
rowFromResponse.id === row.id ? rowFromResponse : row
);
this.tableData.next(newTableData);
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

11017
yarn.lock

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save