mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-01-22 09:32:41 +00:00
refactor(data): adjust data detail component
This commit is contained in:
@@ -12,16 +12,15 @@
|
|||||||
* You should have received a copy of the GNU General Public License along with
|
* You should have received a copy of the GNU General Public License along with
|
||||||
* this program. If not, see <https://www.gnu.org/licenses/>.
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
import {CommonModule, registerLocaleData} from '@angular/common';
|
||||||
|
import {HttpClient} from '@angular/common/http';
|
||||||
|
import localeDe from '@angular/common/locales/de';
|
||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
import {BrowserModule} from '@angular/platform-browser';
|
import {BrowserModule} from '@angular/platform-browser';
|
||||||
import {RouteReuseStrategy} from '@angular/router';
|
import {RouteReuseStrategy} from '@angular/router';
|
||||||
|
|
||||||
import {SplashScreen} from '@ionic-native/splash-screen/ngx';
|
import {SplashScreen} from '@ionic-native/splash-screen/ngx';
|
||||||
import {StatusBar} from '@ionic-native/status-bar/ngx';
|
import {StatusBar} from '@ionic-native/status-bar/ngx';
|
||||||
import {IonicModule, IonicRouteStrategy} from '@ionic/angular';
|
import {IonicModule, IonicRouteStrategy} from '@ionic/angular';
|
||||||
|
|
||||||
import {CommonModule} from '@angular/common';
|
|
||||||
import {HttpClient} from '@angular/common/http';
|
|
||||||
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||||
import {TranslateHttpLoader} from '@ngx-translate/http-loader';
|
import {TranslateHttpLoader} from '@ngx-translate/http-loader';
|
||||||
import {AppRoutingModule} from './app-routing.module';
|
import {AppRoutingModule} from './app-routing.module';
|
||||||
@@ -32,6 +31,8 @@ import {MenuModule} from './modules/menu/menu.module';
|
|||||||
import {SettingsModule} from './modules/settings/settings.module';
|
import {SettingsModule} from './modules/settings/settings.module';
|
||||||
import {StorageModule} from './modules/storage/storage.module';
|
import {StorageModule} from './modules/storage/storage.module';
|
||||||
|
|
||||||
|
registerLocaleData(localeDe);
|
||||||
|
|
||||||
export function createTranslateLoader(http: HttpClient) {
|
export function createTranslateLoader(http: HttpClient) {
|
||||||
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
|
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 StApps
|
* Copyright (C) 2018, 2019 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
@@ -19,16 +19,15 @@ import {DataListComponent} from './list/data-list.component';
|
|||||||
|
|
||||||
const dataRoutes: Routes = [
|
const dataRoutes: Routes = [
|
||||||
{path: 'search', component: DataListComponent},
|
{path: 'search', component: DataListComponent},
|
||||||
{path: 'data-detail/:uid', component: DataDetailComponent}
|
{path: 'data-detail/:uid', component: DataDetailComponent},
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
|
||||||
RouterModule.forChild(dataRoutes)
|
|
||||||
],
|
|
||||||
// tslint:disable-next-line:object-literal-sort-keys
|
|
||||||
exports: [
|
exports: [
|
||||||
RouterModule
|
RouterModule,
|
||||||
]
|
],
|
||||||
|
imports: [
|
||||||
|
RouterModule.forChild(dataRoutes),
|
||||||
|
],
|
||||||
})
|
})
|
||||||
export class DataRoutingModule {}
|
export class DataRoutingModule {}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import {HttpClientModule} from '@angular/common/http';
|
|||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
import {FormsModule} from '@angular/forms';
|
import {FormsModule} from '@angular/forms';
|
||||||
import {IonicModule} from '@ionic/angular';
|
import {IonicModule} from '@ionic/angular';
|
||||||
|
import {TranslateModule} from '@ngx-translate/core';
|
||||||
import {StorageModule} from '../storage/storage.module';
|
import {StorageModule} from '../storage/storage.module';
|
||||||
import {DataRoutingModule} from './data-routing.module';
|
import {DataRoutingModule} from './data-routing.module';
|
||||||
import {DataProvider} from './data.provider';
|
import {DataProvider} from './data.provider';
|
||||||
@@ -50,10 +51,12 @@ import {EventListItemComponent} from './types/event/event-list-item.component';
|
|||||||
DataRoutingModule,
|
DataRoutingModule,
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
StorageModule,
|
StorageModule,
|
||||||
|
TranslateModule.forChild(),
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
DataProvider,
|
DataProvider,
|
||||||
StAppsWebHttpClient,
|
StAppsWebHttpClient,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class DataModule {}
|
export class DataModule {
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 StApps
|
* Copyright (C) 2018, 2019 StApps
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* This program is free software: you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the Free
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
* Software Foundation, version 3.
|
* Software Foundation, version 3.
|
||||||
@@ -15,54 +15,98 @@
|
|||||||
import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
|
import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
|
||||||
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||||
import {ActivatedRoute, RouterModule} from '@angular/router';
|
import {ActivatedRoute, RouterModule} from '@angular/router';
|
||||||
|
import {IonRefresher} from '@ionic/angular';
|
||||||
|
import {SCMessage, SCThingOriginType, SCThingType} from '@openstapps/core';
|
||||||
import {DataRoutingModule} from '../data-routing.module';
|
import {DataRoutingModule} from '../data-routing.module';
|
||||||
import {DataListComponent} from '../list/data-list.component';
|
import {DataModule} from '../data.module';
|
||||||
|
import {DataProvider} from '../data.provider';
|
||||||
import {DataDetailComponent} from './data-detail.component';
|
import {DataDetailComponent} from './data-detail.component';
|
||||||
|
import {TranslateModule, TranslateLoader, TranslateFakeLoader} from '@ngx-translate/core';
|
||||||
|
|
||||||
describe('DataDetailComponent', () => {
|
describe('DataDetailComponent', () => {
|
||||||
let comp: DataDetailComponent;
|
let comp: DataDetailComponent;
|
||||||
let fixture: ComponentFixture<DataDetailComponent>;
|
let fixture: ComponentFixture<DataDetailComponent>;
|
||||||
let detailPage: HTMLElement;
|
let detailPage: HTMLElement;
|
||||||
|
let dataProvider: DataProvider;
|
||||||
|
let refresher: IonRefresher;
|
||||||
|
|
||||||
// @Component({ selector: 'stapps-data-list-item', template: '' })
|
// @Component({ selector: 'stapps-data-list-item', template: '' })
|
||||||
// class DataListItemComponent {
|
// class DataListItemComponent {
|
||||||
// @Input() item;
|
// @Input() item;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
const sampleThing: SCMessage = {
|
||||||
|
audiences: ['students'],
|
||||||
|
message: 'Foo Message',
|
||||||
|
name: 'foo',
|
||||||
|
origin: {
|
||||||
|
indexed: 'SOME-DATE',
|
||||||
|
name: 'some name',
|
||||||
|
type: SCThingOriginType.Remote,
|
||||||
|
},
|
||||||
|
type: SCThingType.Message,
|
||||||
|
uid: '123',
|
||||||
|
};
|
||||||
|
|
||||||
const fakeActivatedRoute = {
|
const fakeActivatedRoute = {
|
||||||
snapshot: {
|
snapshot: {
|
||||||
paramMap: {
|
paramMap: {
|
||||||
get: (url) => {
|
get: () => {
|
||||||
return url;
|
return sampleThing.uid;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
} as ActivatedRoute;
|
};
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
declarations: [DataListComponent, DataDetailComponent],
|
imports: [RouterModule.forRoot([]), DataRoutingModule, DataModule,
|
||||||
imports: [RouterModule, DataRoutingModule],
|
TranslateModule.forRoot({
|
||||||
|
loader: {provide: TranslateLoader, useClass: TranslateFakeLoader},
|
||||||
|
})],
|
||||||
providers: [{provide: ActivatedRoute, useValue: fakeActivatedRoute}],
|
providers: [{provide: ActivatedRoute, useValue: fakeActivatedRoute}],
|
||||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
beforeEach(async() => {
|
beforeEach(async () => {
|
||||||
|
dataProvider = TestBed.get(DataProvider);
|
||||||
|
refresher = jasmine.createSpyObj('refresher', ['complete']);
|
||||||
|
spyOn(dataProvider, 'get').and.returnValue(Promise.resolve(sampleThing));
|
||||||
|
spyOn(DataDetailComponent.prototype, 'getItem').and.callThrough();
|
||||||
fixture = await TestBed.createComponent(DataDetailComponent);
|
fixture = await TestBed.createComponent(DataDetailComponent);
|
||||||
comp = fixture.componentInstance;
|
comp = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
|
detailPage = fixture.nativeElement;
|
||||||
|
await dataProvider.deleteAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should create component', () =>
|
it('should create component', () =>
|
||||||
expect(comp).toBeDefined(),
|
expect(comp).toBeDefined(),
|
||||||
);
|
);
|
||||||
|
|
||||||
it('should have apropriate title', () => {
|
it('should have apropriate title', async () => {
|
||||||
detailPage = fixture.nativeElement;
|
await fixture.whenStable();
|
||||||
const title: HTMLIonTitleElement | null = detailPage.querySelector('ion-title');
|
const title: HTMLIonTitleElement | null = detailPage.querySelector('ion-title');
|
||||||
expect(title).not.toBe(null);
|
expect(title).not.toBe(null);
|
||||||
expect(title!.innerText).toContain('Detailansicht');
|
expect(title!.innerText).toContain('data.detail.TITLE');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get a data item', () => {
|
||||||
|
comp.getItem(sampleThing.uid);
|
||||||
|
expect(DataDetailComponent.prototype.getItem).toHaveBeenCalledWith(sampleThing.uid);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should get a data item when component is accessed', async () => {
|
||||||
|
await fixture.whenStable();
|
||||||
|
expect(DataDetailComponent.prototype.getItem).toHaveBeenCalledWith(sampleThing.uid);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update the data item when refresh is called', async () => {
|
||||||
|
await fixture.whenStable();
|
||||||
|
await comp.refresh(refresher);
|
||||||
|
expect(DataDetailComponent.prototype.getItem).toHaveBeenCalledWith(sampleThing.uid);
|
||||||
|
expect(refresher.complete).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,7 +14,8 @@
|
|||||||
*/
|
*/
|
||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
import {ActivatedRoute} from '@angular/router';
|
import {ActivatedRoute} from '@angular/router';
|
||||||
import {SCThing} from '@openstapps/core';
|
import {IonRefresher} from '@ionic/angular';
|
||||||
|
import {SCThing, SCUuid} from '@openstapps/core';
|
||||||
import {DataProvider, DataScope} from '../data.provider';
|
import {DataProvider, DataScope} from '../data.provider';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -27,8 +28,26 @@ export class DataDetailComponent {
|
|||||||
constructor(private route: ActivatedRoute, dataProvider: DataProvider) {
|
constructor(private route: ActivatedRoute, dataProvider: DataProvider) {
|
||||||
this.dataProvider = dataProvider;
|
this.dataProvider = dataProvider;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Provides data item with given UID
|
||||||
|
*
|
||||||
|
* @param uid Unique identifier of a thing
|
||||||
|
*/
|
||||||
|
async getItem(uid: SCUuid): Promise<SCThing> {
|
||||||
|
return (await this.dataProvider.get(uid, DataScope.Remote));
|
||||||
|
}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
const uid = this.route.snapshot.paramMap.get('uid') || '';
|
this.item = await this.getItem(this.route.snapshot.paramMap.get('uid') || '');
|
||||||
this.item = (await this.dataProvider.get(uid, DataScope.Remote));
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the shown thing
|
||||||
|
*
|
||||||
|
* @param refresher Refresher component the triggers the update
|
||||||
|
*/
|
||||||
|
async refresh(refresher: IonRefresher) {
|
||||||
|
this.item = await this.getItem(this.item.uid);
|
||||||
|
refresher.complete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,15 @@
|
|||||||
<ion-back-button></ion-back-button>
|
<ion-back-button></ion-back-button>
|
||||||
<ion-menu-button></ion-menu-button>
|
<ion-menu-button></ion-menu-button>
|
||||||
</ion-buttons>
|
</ion-buttons>
|
||||||
<ion-title>Detailansicht</ion-title>
|
<ion-title>{{'data.detail.TITLE' | translate}}</ion-title>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content padding *ngIf="item">
|
<ion-content padding *ngIf="item">
|
||||||
|
<ion-refresher slot="fixed" (ionRefresh)="refresh($event.target)">
|
||||||
|
<ion-refresher-content pullingIcon="arrow-dropdown" pullingText="{{'data.REFRESH_ACTION' | translate}}"
|
||||||
|
refreshingText="{{'data.REFRESHING' | translate}}">
|
||||||
|
</ion-refresher-content>
|
||||||
|
</ion-refresher>
|
||||||
<stapps-data-list-item [item]="item"></stapps-data-list-item>
|
<stapps-data-list-item [item]="item"></stapps-data-list-item>
|
||||||
|
|
||||||
<div [ngSwitch]="item.type">
|
<div [ngSwitch]="item.type">
|
||||||
|
|||||||
@@ -29,15 +29,15 @@
|
|||||||
<ion-grid *ngFor="let offer of item.offers">
|
<ion-grid *ngFor="let offer of item.offers">
|
||||||
<ion-row>
|
<ion-row>
|
||||||
<ion-col>Student</ion-col>
|
<ion-col>Student</ion-col>
|
||||||
<ion-col>{{offer.prices.student}}</ion-col>
|
<ion-col>{{offer.prices.student | currency:'EUR':'symbol':undefined:'de'}}</ion-col>
|
||||||
</ion-row>
|
</ion-row>
|
||||||
<ion-row>
|
<ion-row>
|
||||||
<ion-col>Mitarbeiter</ion-col>
|
<ion-col>Mitarbeiter</ion-col>
|
||||||
<ion-col>{{offer.prices.employee}}</ion-col>
|
<ion-col>{{offer.prices.employee | currency:'EUR':'symbol':undefined:'de'}}</ion-col>
|
||||||
</ion-row>
|
</ion-row>
|
||||||
<ion-row>
|
<ion-row>
|
||||||
<ion-col>Standard / Gäste</ion-col>
|
<ion-col>Standard / Gäste</ion-col>
|
||||||
<ion-col>{{offer.prices.guest}}</ion-col>
|
<ion-col>{{offer.prices.guest | currency:'EUR':'symbol':undefined:'de'}}</ion-col>
|
||||||
</ion-row>
|
</ion-row>
|
||||||
</ion-grid>
|
</ion-grid>
|
||||||
</ion-card-content>
|
</ion-card-content>
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
{
|
{
|
||||||
|
"data": {
|
||||||
|
"REFRESH_ACTION": "Aktualisieren",
|
||||||
|
"REFRESHING": "Aktualisierung läuft...",
|
||||||
|
"detail": {
|
||||||
|
"TITLE": "Detailansicht"
|
||||||
|
},
|
||||||
"types": {
|
"types": {
|
||||||
"dish": {
|
"dish": {
|
||||||
"detailPage": {
|
"detailPage": {
|
||||||
@@ -7,6 +13,7 @@
|
|||||||
"CHARACTERISTICS_TITLE": "Characteristics"
|
"CHARACTERISTICS_TITLE": "Characteristics"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"title": "Einstellungen",
|
"title": "Einstellungen",
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
{
|
{
|
||||||
|
"data": {
|
||||||
|
"REFRESH_ACTION": "Refresh",
|
||||||
|
"REFRESHING": "Refreshing...",
|
||||||
|
"detail": {
|
||||||
|
"TITLE": "Details"
|
||||||
|
},
|
||||||
"types": {
|
"types": {
|
||||||
"dish": {
|
"dish": {
|
||||||
"detailPage": {
|
"detailPage": {
|
||||||
@@ -7,6 +13,7 @@
|
|||||||
"CHARACTERISTICS_TITLE": "Characteristics"
|
"CHARACTERISTICS_TITLE": "Characteristics"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"title": "Settings",
|
"title": "Settings",
|
||||||
|
|||||||
Reference in New Issue
Block a user