mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2026-01-04 20:42:52 +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
|
||||
* 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');
|
||||
}
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user