diff --git a/src/app/app.module.ts b/src/app/app.module.ts index bb2827b5..d0f22f7b 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -12,16 +12,15 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ +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'); } diff --git a/src/app/modules/data/data-routing.module.ts b/src/app/modules/data/data-routing.module.ts index c46b72a2..6e6c16c6 100644 --- a/src/app/modules/data/data-routing.module.ts +++ b/src/app/modules/data/data-routing.module.ts @@ -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 {} diff --git a/src/app/modules/data/data.module.ts b/src/app/modules/data/data.module.ts index 95d75741..44b17a5a 100644 --- a/src/app/modules/data/data.module.ts +++ b/src/app/modules/data/data.module.ts @@ -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 { +} diff --git a/src/app/modules/data/detail/data-detail.component.spec.ts b/src/app/modules/data/detail/data-detail.component.spec.ts index 3cd05ac6..6d4e3a44 100644 --- a/src/app/modules/data/detail/data-detail.component.spec.ts +++ b/src/app/modules/data/detail/data-detail.component.spec.ts @@ -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; 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(); }); }); diff --git a/src/app/modules/data/detail/data-detail.component.ts b/src/app/modules/data/detail/data-detail.component.ts index 3d90e791..9e444f3f 100644 --- a/src/app/modules/data/detail/data-detail.component.ts +++ b/src/app/modules/data/detail/data-detail.component.ts @@ -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 { + 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(); } } diff --git a/src/app/modules/data/detail/data-detail.html b/src/app/modules/data/detail/data-detail.html index d70cf4b6..a3d6afa8 100644 --- a/src/app/modules/data/detail/data-detail.html +++ b/src/app/modules/data/detail/data-detail.html @@ -4,11 +4,15 @@ - Detailansicht + {{'data.detail.TITLE' | translate}} - + + + +
diff --git a/src/app/modules/data/types/dish/dish-detail-content.html b/src/app/modules/data/types/dish/dish-detail-content.html index f8ae4ecd..c3c31065 100644 --- a/src/app/modules/data/types/dish/dish-detail-content.html +++ b/src/app/modules/data/types/dish/dish-detail-content.html @@ -29,15 +29,15 @@ Student - {{offer.prices.student}} + {{offer.prices.student | currency:'EUR':'symbol':undefined:'de'}} Mitarbeiter - {{offer.prices.employee}} + {{offer.prices.employee | currency:'EUR':'symbol':undefined:'de'}} Standard / Gäste - {{offer.prices.guest}} + {{offer.prices.guest | currency:'EUR':'symbol':undefined:'de'}} diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json index 018192e5..1523d225 100644 --- a/src/assets/i18n/de.json +++ b/src/assets/i18n/de.json @@ -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" + } } } }, diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 2dbb6d2e..9e695cc9 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -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" + } } } },