refactor(data): adjust data detail component

This commit is contained in:
Jovan Krunić
2019-02-12 14:09:09 +01:00
parent 017fc67765
commit 8c3c2810e5
9 changed files with 134 additions and 50 deletions

View File

@@ -12,16 +12,15 @@
* You should have received a copy of the GNU General Public License along with
* 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 {BrowserModule} from '@angular/platform-browser';
import {RouteReuseStrategy} from '@angular/router';
import {SplashScreen} from '@ionic-native/splash-screen/ngx';
import {StatusBar} from '@ionic-native/status-bar/ngx';
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 {TranslateHttpLoader} from '@ngx-translate/http-loader';
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 {StorageModule} from './modules/storage/storage.module';
registerLocaleData(localeDe);
export function createTranslateLoader(http: HttpClient) {
return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}

View File

@@ -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
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
@@ -19,16 +19,15 @@ import {DataListComponent} from './list/data-list.component';
const dataRoutes: Routes = [
{path: 'search', component: DataListComponent},
{path: 'data-detail/:uid', component: DataDetailComponent}
{path: 'data-detail/:uid', component: DataDetailComponent},
];
@NgModule({
imports: [
RouterModule.forChild(dataRoutes)
],
// tslint:disable-next-line:object-literal-sort-keys
exports: [
RouterModule
]
RouterModule,
],
imports: [
RouterModule.forChild(dataRoutes),
],
})
export class DataRoutingModule {}

View File

@@ -17,6 +17,7 @@ import {HttpClientModule} from '@angular/common/http';
import {NgModule} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {IonicModule} from '@ionic/angular';
import {TranslateModule} from '@ngx-translate/core';
import {StorageModule} from '../storage/storage.module';
import {DataRoutingModule} from './data-routing.module';
import {DataProvider} from './data.provider';
@@ -50,10 +51,12 @@ import {EventListItemComponent} from './types/event/event-list-item.component';
DataRoutingModule,
HttpClientModule,
StorageModule,
TranslateModule.forChild(),
],
providers: [
DataProvider,
StAppsWebHttpClient,
],
})
export class DataModule {}
export class DataModule {
}

View File

@@ -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
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, version 3.
@@ -15,54 +15,98 @@
import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
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 {DataListComponent} from '../list/data-list.component';
import {DataModule} from '../data.module';
import {DataProvider} from '../data.provider';
import {DataDetailComponent} from './data-detail.component';
import {TranslateModule, TranslateLoader, TranslateFakeLoader} from '@ngx-translate/core';
describe('DataDetailComponent', () => {
let comp: DataDetailComponent;
let fixture: ComponentFixture<DataDetailComponent>;
let detailPage: HTMLElement;
let dataProvider: DataProvider;
let refresher: IonRefresher;
// @Component({ selector: 'stapps-data-list-item', template: '' })
// 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 = {
snapshot: {
paramMap: {
get: (url) => {
return url;
}
}
}
} as ActivatedRoute;
get: () => {
return sampleThing.uid;
},
},
},
};
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [DataListComponent, DataDetailComponent],
imports: [RouterModule, DataRoutingModule],
imports: [RouterModule.forRoot([]), DataRoutingModule, DataModule,
TranslateModule.forRoot({
loader: {provide: TranslateLoader, useClass: TranslateFakeLoader},
})],
providers: [{provide: ActivatedRoute, useValue: fakeActivatedRoute}],
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);
comp = fixture.componentInstance;
fixture.detectChanges();
detailPage = fixture.nativeElement;
await dataProvider.deleteAll();
});
it('should create component', () =>
expect(comp).toBeDefined(),
);
it('should have apropriate title', () => {
detailPage = fixture.nativeElement;
it('should have apropriate title', async () => {
await fixture.whenStable();
const title: HTMLIonTitleElement | null = detailPage.querySelector('ion-title');
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();
});
});

View File

@@ -14,7 +14,8 @@
*/
import {Component} from '@angular/core';
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';
@Component({
@@ -27,8 +28,26 @@ export class DataDetailComponent {
constructor(private route: ActivatedRoute, 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() {
const uid = this.route.snapshot.paramMap.get('uid') || '';
this.item = (await this.dataProvider.get(uid, DataScope.Remote));
this.item = await this.getItem(this.route.snapshot.paramMap.get('uid') || '');
}
/**
* 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();
}
}

View File

@@ -4,11 +4,15 @@
<ion-back-button></ion-back-button>
<ion-menu-button></ion-menu-button>
</ion-buttons>
<ion-title>Detailansicht</ion-title>
<ion-title>{{'data.detail.TITLE' | translate}}</ion-title>
</ion-toolbar>
</ion-header>
<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>
<div [ngSwitch]="item.type">

View File

@@ -29,15 +29,15 @@
<ion-grid *ngFor="let offer of item.offers">
<ion-row>
<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-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-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-grid>
</ion-card-content>

View File

@@ -1,10 +1,17 @@
{
"types": {
"dish": {
"detailPage": {
"DESCRIPTION_TITLE": "Description",
"CATEGORY_TITLE": "Category",
"CHARACTERISTICS_TITLE": "Characteristics"
"data": {
"REFRESH_ACTION": "Aktualisieren",
"REFRESHING": "Aktualisierung läuft...",
"detail": {
"TITLE": "Detailansicht"
},
"types": {
"dish": {
"detailPage": {
"DESCRIPTION_TITLE": "Description",
"CATEGORY_TITLE": "Category",
"CHARACTERISTICS_TITLE": "Characteristics"
}
}
}
},

View File

@@ -1,10 +1,17 @@
{
"types": {
"dish": {
"detailPage": {
"DESCRIPTION_TITLE": "Description",
"CATEGORY_TITLE": "Category",
"CHARACTERISTICS_TITLE": "Characteristics"
"data": {
"REFRESH_ACTION": "Refresh",
"REFRESHING": "Refreshing...",
"detail": {
"TITLE": "Details"
},
"types": {
"dish": {
"detailPage": {
"DESCRIPTION_TITLE": "Description",
"CATEGORY_TITLE": "Category",
"CHARACTERISTICS_TITLE": "Characteristics"
}
}
}
},