feat: show menu for multiple days for canteens and cafes

Closes #19, #79
This commit is contained in:
Wieland Schöbl
2021-01-19 13:50:51 +00:00
committed by Jovan Krunić
parent 66b8720da0
commit 3c079cd189
27 changed files with 1347 additions and 523 deletions

View File

@@ -16,10 +16,12 @@ import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';
import {DataDetailComponent} from './detail/data-detail.component';
import {DataListComponent} from './list/data-list.component';
import {FoodDataListComponent} from './list/food-data-list.component';
const dataRoutes: Routes = [
{path: 'search', component: DataListComponent},
{path: 'data-detail/:uid', component: DataDetailComponent},
{path: 'canteen', component: FoodDataListComponent},
];
/**

View File

@@ -35,9 +35,11 @@ import {OriginDetailComponent} from './elements/origin-detail.component';
import {OriginInListComponent} from './elements/origin-in-list.component';
import {SimpleCardComponent} from './elements/simple-card.component';
import {SkeletonListItem} from './elements/skeleton-list-item.component';
import {SkeletonSegment} from './elements/skeleton-segment-button.component';
import {SkeletonSimpleCard} from './elements/skeleton-simple-card.component';
import {DataListItem} from './list/data-list-item.component';
import {DataListComponent} from './list/data-list.component';
import {FoodDataListComponent} from './list/food-data-list.component';
import {StAppsWebHttpClient} from './stapps-web-http-client.provider';
import {ArticleDetailContentComponent} from './types/article/article-detail-content.component';
import {ArticleListItem} from './types/article/article-list-item.component';
@@ -59,6 +61,7 @@ import {PersonDetailContentComponent} from './types/person/person-detail-content
import {PersonListItem} from './types/person/person-list-item.component';
import {PlaceDetailContentComponent} from './types/place/place-detail-content.component';
import {PlaceListItem} from './types/place/place-list-item.component';
import {PlaceMensaDetailComponent} from './types/place/special/mensa/place-mensa-detail.component';
import {SemesterDetailContentComponent} from './types/semester/semester-detail-content.component';
import {SemesterListItem} from './types/semester/semester-list-item.component';
import {VideoDetailContentComponent} from './types/video/video-detail-content.component';
@@ -80,6 +83,7 @@ import {VideoListItem} from './types/video/video-list-item.component';
CatalogListItem,
DataDetailComponent,
DataDetailContentComponent,
FoodDataListComponent,
DataListComponent,
DataListItem,
DateSeriesDetailContentComponent,
@@ -101,9 +105,11 @@ import {VideoListItem} from './types/video/video-list-item.component';
PersonListItem,
PlaceDetailContentComponent,
PlaceListItem,
PlaceMensaDetailComponent,
SemesterDetailContentComponent,
SemesterListItem,
SkeletonListItem,
SkeletonSegment,
VideoDetailContentComponent,
VideoListItem,
],

View File

@@ -16,9 +16,9 @@ import {Injectable} from '@angular/core';
import {Client} from '@openstapps/api/lib/client';
import {SCSearchQuery, SCSearchResponse, SCThingOriginType, SCThings, SCThingType} from '@openstapps/core';
import {SCSaveableThing} from '@openstapps/core';
import {environment} from '../../../environments/environment';
import {StorageProvider} from '../storage/storage.provider';
import {StAppsWebHttpClient} from './stapps-web-http-client.provider';
import {environment} from './../../../environments/environment';
export enum DataScope {
Local = 'local',

View File

@@ -27,4 +27,5 @@ export class DataDetailContentComponent {
* TODO
*/
@Input() item: SCThings;
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 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.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* 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 {Component} from '@angular/core';
/**
* TODO
*/
@Component({
selector: 'stapps-skeleton-segment-button',
templateUrl: 'skeleton-segment-button.html',
})
export class SkeletonSegment {
}

View File

@@ -0,0 +1,4 @@
<ion-segment-button>
<ion-skeleton-text animated style="width: 85%;"></ion-skeleton-text>
</ion-segment-button>

View File

@@ -22,9 +22,9 @@ import {
SCThing,
} from '@openstapps/core';
import {NGXLogger} from 'ngx-logger';
import {Subject} from 'rxjs';
import {Subject, Subscription} from 'rxjs';
import {debounceTime, distinctUntilChanged} from 'rxjs/operators';
import {MenuService} from '../../menu/menu.service';
import {ContextMenuService} from '../../menu/context/context-menu.service';
import {SettingsProvider} from '../../settings/settings.provider';
import {DataProvider} from '../data.provider';
@@ -34,6 +34,7 @@ import {DataProvider} from '../data.provider';
@Component({
selector: 'stapps-data-list',
templateUrl: 'data-list.html',
providers: [ContextMenuService],
})
export class DataListComponent implements OnInit {
@@ -50,7 +51,7 @@ export class DataListComponent implements OnInit {
/**
* Container for queried things
*/
items: SCThing[];
items: Promise<SCThing[]>;
/**
* Page size of queries
@@ -77,22 +78,27 @@ export class DataListComponent implements OnInit {
*/
sortQuery: SCSearchSort | undefined;
/**
* Array of all subscriptions to Observables
*/
subscriptions: Subscription[] = [];
/**
*
* @param alertController AlertController
* @param dataProvider DataProvider
* @param menuService MenuService
* @param contextMenuService ContextMenuService
* @param settingsProvider SettingsProvider
* @param logger An angular logger
*/
constructor(
private readonly alertController: AlertController,
private readonly dataProvider: DataProvider,
private readonly menuService: MenuService,
private readonly settingsProvider: SettingsProvider,
private readonly logger: NGXLogger,
protected readonly alertController: AlertController,
protected dataProvider: DataProvider,
protected readonly contextMenuService: ContextMenuService,
protected readonly settingsProvider: SettingsProvider,
protected readonly logger: NGXLogger,
) {
this.queryTextChanged
this.subscriptions.push(this.queryTextChanged
.pipe(
debounceTime(this.searchQueryDueTime),
distinctUntilChanged())
@@ -100,30 +106,32 @@ export class DataListComponent implements OnInit {
this.from = 0;
this.queryText = model;
this.fetchAndUpdateItems();
});
}));
this.menuService.filterQueryChanged$.subscribe((query) => {
this.subscriptions.push(this.contextMenuService.filterQueryChanged$.subscribe((query) => {
this.filterQuery = query;
this.from = 0;
this.fetchAndUpdateItems();
});
this.menuService.sortQueryChanged$.subscribe((query) => {
}));
this.subscriptions.push(this.contextMenuService.sortQueryChanged$.subscribe((query) => {
this.sortQuery = query;
this.from = 0;
this.fetchAndUpdateItems();
});
}));
this.fetchAndUpdateItems();
/**
* Subscribe to 'settings.changed' events
*/
this.settingsProvider.settingsActionChanged$.subscribe(({type, payload}) => {
this.subscriptions.push(this.settingsProvider.settingsActionChanged$.subscribe(({type, payload}) => {
if (type === 'stapps.settings.changed') {
const {category, name, value} = payload!;
this.logger.log(`received event "settings.changed" with category:
${category}, name: ${name}, value: ${JSON.stringify(value)}`);
}
},
);
));
}
/**
@@ -131,7 +139,7 @@ export class DataListComponent implements OnInit {
*
* @param append If true fetched data gets appended to existing, override otherwise (default false)
*/
private async fetchAndUpdateItems(append = false): Promise<void> {
protected async fetchAndUpdateItems(append = false): Promise<void> {
// build query search options
const searchOptions: SCSearchQuery = {
from: this.from,
@@ -154,17 +162,17 @@ export class DataListComponent implements OnInit {
}
return this.dataProvider.search(searchOptions)
.then((result) => {
.then(async (result) => {
if (append) {
let items = await this.items;
// append results
this.items = this.items.concat(result.data);
items = items.concat(result.data);
this.items = (async () => items)();
} else {
// override items with results
this.items = result.data;
}
// update filter options if result contains facets
if (typeof result.facets !== 'undefined') {
this.updateContextFilter(result.facets);
this.items = (async () => {
this.updateContextFilter(result.facets);
return result.data} )();
}
}, async (err) => {
const alert: HTMLIonAlertElement = await this.alertController.create({
@@ -188,11 +196,10 @@ export class DataListComponent implements OnInit {
}
/**
* Initialises the sort context of menuService
* Initialises the possible sort options in ContextMenuService
*/
ngOnInit(): void {
// initialise sort option for context menu
this.menuService.setContextSort({
this.contextMenuService.setContextSort({
name: 'sort',
reversed: false,
value: 'relevance',
@@ -213,6 +220,15 @@ export class DataListComponent implements OnInit {
});
}
/**
* Unsubscribe from Observables
*/
ngOnDestroy() {
for (let sub of this.subscriptions) {
sub.unsubscribe();
}
}
/**
* Search event of search bar
*/
@@ -221,9 +237,9 @@ export class DataListComponent implements OnInit {
}
/**
* Updates context filter in menuService with facets
* Updates the possible filter options in ContextMenuService with facets
*/
updateContextFilter(facets: SCFacet[]) {
this.menuService.updateContextFilter(facets);
this.contextMenuService.updateContextFilter(facets);
}
}

View File

@@ -6,7 +6,7 @@
<ion-menu-button></ion-menu-button>
</ion-buttons>
<ion-buttons slot="end">
<ion-menu-button menu="context">
<ion-menu-button menu="context" auto-hide="false">
<ion-icon name="options"></ion-icon>
</ion-menu-button>
</ion-buttons>
@@ -17,13 +17,15 @@
</ion-toolbar>
</ion-header>
<ion-content id="data-list">
<ion-list *ngIf="items">
<stapps-data-list-item [item]="item" *ngFor="let item of items"></stapps-data-list-item>
</ion-list>
<ion-list *ngIf="!items">
<ion-content id="data-list">
<div *ngIf="items | async as items; else loading">
<ion-list>
<stapps-data-list-item [item]="item" *ngFor="let item of items"></stapps-data-list-item>
</ion-list>
</div>
<ng-template #loading>
<stapps-skeleton-list-item *ngFor="let skeleton of [1, 2, 3, 4, 5]"></stapps-skeleton-list-item>
</ion-list>
</ng-template>
<ion-infinite-scroll (ionInfinite)="loadMore($event)">
<ion-infinite-scroll-content></ion-infinite-scroll-content>
</ion-infinite-scroll>

View File

@@ -0,0 +1,126 @@
/*
* Copyright (C) 2018-2020 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.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* 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 {Component} from '@angular/core';
import {
SCSearchQuery, SCThing,
} from '@openstapps/core';
import {DataListComponent} from './data-list.component';
/**
* TODO
*/
@Component({
selector: 'stapps-data-list',
templateUrl: 'data-list.html',
})
export class FoodDataListComponent extends DataListComponent {
/**
* Fetches items with set query configuration
*
* @param append If true fetched data gets appended to existing, override otherwise (default false)
*/
protected async fetchAndUpdateItems(append = false): Promise<void> {
try {
// build query search options
const searchOptions: SCSearchQuery = {
from: this.from,
size: this.pageSize,
};
if (this.queryText && this.queryText.length > 0) {
// add query string
searchOptions.query = this.queryText;
}
if (this.sortQuery) {
// add query sorting
searchOptions.sort = [this.sortQuery];
}
searchOptions.filter = {
arguments: {
filters: [
{
arguments: {
field: 'categories',
value: 'canteen',
},
type: 'value',
},
{
arguments: {
field: 'categories',
value: 'student canteen',
},
type: 'value',
},
{
arguments: {
field: 'categories',
value: 'cafe',
},
type: 'value',
},
{
arguments: {
field: 'categories',
value: 'restaurant',
},
type: 'value',
},
],
operation: 'or',
},
type: 'boolean',
};
if (this.filterQuery !== undefined) {
searchOptions.filter = {
arguments: {
filters: [
searchOptions.filter,
this.filterQuery,
],
operation: 'and',
},
type: 'boolean',
};
}
const result = await this.dataProvider.search(searchOptions);
this.items = (async () => {
this.updateContextFilter(result.facets);
let items: SCThing[];
if(append) {
items = (await this.items).concat(result.data);
} else {
items = result.data;
}
return items;
})();
} catch (err) {
const alert: HTMLIonAlertElement = await this.alertController.create({
buttons: ['Dismiss'],
header: 'Error',
subHeader: err.message,
});
await alert.present();
}
}
}

View File

@@ -14,12 +14,14 @@
*/
import {Component, Input} from '@angular/core';
import {SCBuilding, SCFloor, SCPointOfInterest, SCRoom, SCThing, SCTranslations} from '@openstapps/core';
import {SCThingTranslator} from '@openstapps/core';
import {SCThings, SCThingTranslator} from '@openstapps/core';
import {DataProvider} from '../../data.provider';
/**
* TODO
*/
@Component({
providers: [ DataProvider ],
selector: 'stapps-place-detail-content',
templateUrl: 'place-detail-content.html',
})
@@ -47,4 +49,26 @@ export class PlaceDetailContentComponent {
constructor() {
this.translator = new SCThingTranslator(this.language);
}
/**
* TODO
*
* @param item TODO
*/
// tslint:disable-next-line:completed-docs prefer-function-over-method
hasCategories(item: SCThings): item is SCThings & { categories: string[]; } {
// tslint:disable-next-line:completed-docs
return typeof (item as { categories: string[]; }).categories !== 'undefined';
}
/**
* Helper function as 'typeof' is not accessible in HTML
*
* @param item TODO
*/
isMensaThing(item: SCThings): boolean {
return this.hasCategories(item) &&
((item.categories as string[]).includes('canteen') || (item.categories as string[]).includes('cafe')
|| (item.categories as string[]).includes('student canteen') || (item.categories as string[]).includes('restaurant'));
}
}

View File

@@ -1,3 +1,4 @@
<stapps-place-mensa-detail-content [item]="item" [language]="language" *ngIf="isMensaThing(item)"></stapps-place-mensa-detail-content>
<ng-container *ngIf="item.type !== 'floor'">
<stapps-simple-card *ngIf="item.type !== 'floor' && item.categories" [title]="'Categories'" [content]="translator.translate(item).categories()"></stapps-simple-card>
<stapps-address-detail *ngIf="item.type !== 'floor' && item.address" [address]="item.address"></stapps-address-detail>

View File

@@ -0,0 +1,132 @@
/*
* Copyright (C) 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.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* 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 moment, {Moment} from 'moment';
import {AfterViewInit, ChangeDetectorRef, Component, Input} from '@angular/core';
import {SCDish, SCPlace, SCThing, SCThingTranslator, SCTranslations} from '@openstapps/core';
import {PlaceMensaService} from './place-mensa-service';
/**
* TODO
*/
@Component({
providers: [PlaceMensaService],
selector: 'stapps-place-mensa-detail-content',
templateUrl: 'place-mensa.html',
})
export class PlaceMensaDetailComponent implements AfterViewInit {
/**
* TODO
*/
dishes: Promise<Record<string, SCDish[]>> | null = null;
/**
* number of days to display mensa menus for
*/
displayRange = 5;
/**
* TODO
*/
@Input() item: SCPlace;
/**
* TODO
*/
@Input() language: keyof SCTranslations<SCThing>;
/**
* TODO
*/
selectedDay: string;
/**
* First day to display menu items for
*/
startingDay: Moment;
/**
* TODO
*/
translator: SCThingTranslator;
constructor(private mensaService: PlaceMensaService, private changeDectectorRef: ChangeDetectorRef) {
// TODO: translation
this.translator = new SCThingTranslator(this.language);
this.startingDay = moment();
this.startingDay.hour(0);
this.startingDay.minute(0);
this.startingDay.millisecond(0);
}
/**
* TODO
*/
ngAfterViewInit() {
this.dishes = this.mensaService.getAllDishes(this.item)
.then((dishesResult) => {
const out = this.splitDishes(dishesResult, this.item, this.startingDay, this.displayRange);
for (const key in out) {
if (out.hasOwnProperty(key)) {
this.selectedDay = key;
break;
}
}
this.changeDectectorRef.detectChanges();
return out;
});
}
/**
* Splits a list of dishes with availability start and end into multiple lists by day
*/
// tslint:disable-next-line:prefer-function-over-method
splitDishes(dishes: SCDish[], place: SCPlace, startingDay: Moment, displayRange: number): Record<string, SCDish[]> {
const out: Record<string, SCDish[]> = {};
for (let i = 0; i < displayRange; i++) {
const nextDay: Moment = moment(startingDay)
.add(1, 'days');
const selectedDishes: SCDish[] = [];
for (const dish of dishes) {
// go through all offers
if (dish.offers === undefined) { continue; }
for (const offer of dish.offers) {
if (offer.inPlace === undefined || offer.inPlace.uid !== place.uid) { continue; }
// get availabilities
const availabilityStarts = offer.availabilityStarts === undefined ? undefined : moment(offer.availabilityStarts);
const availabilityEnds = offer.availabilityEnds === undefined ? undefined : moment(offer.availabilityEnds);
if ((availabilityStarts === undefined || availabilityStarts.isBefore(nextDay))
&& (availabilityEnds === undefined || availabilityEnds.isAfter(startingDay))) {
selectedDishes.push(dish);
break;
}
}
}
if (selectedDishes.length) {
out[startingDay.format('YYYY-MM-DD')] = selectedDishes;
}
// tslint:disable-next-line:no-parameter-reassignment
startingDay = nextDay;
}
return out;
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 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.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* 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 {Injectable} from '@angular/core';
import {SCDish, SCPlace, SCThingType} from '@openstapps/core';
import {DataProvider} from '../../../../data.provider';
/**
* TODO
*/
@Injectable({
providedIn: 'root',
})
export class PlaceMensaService {
constructor(private dataProvider: DataProvider) { }
/**
* Fetches all dishes for this building
*/
async getAllDishes(place: SCPlace): Promise<SCDish[]> {
// use filter to get all dishes with the building's uid in one of the offer's inPlace field
// TODO: make sure this actually works with ES
const result = await this.dataProvider.search({
filter: {
arguments: {
filters: [
{
arguments: {
field: 'offers.inPlace.uid',
value: place.uid,
},
type: 'value',
},
{
arguments: {
field: 'type',
value: SCThingType.Dish,
},
type: 'value',
},
],
operation: 'and',
},
type: 'boolean',
},
size: 1000,
});
return result.data as SCDish[];
}
}

View File

@@ -0,0 +1,24 @@
<ng-container>
<div *ngIf="dishes | async as dishes; else loading">
<ion-segment [(ngModel)]="selectedDay">
<ion-segment-button *ngFor="let day of dishes | keyvalue" [value]="day.key">
<ion-label>{{day.key | amParse:'YYYY-MM-DD' | amDateFormat:'dddd, L'}}</ion-label>
</ion-segment-button>
</ion-segment>
<div [ngSwitch]="selectedDay">
<div *ngFor="let day of dishes | keyvalue">
<ion-list *ngSwitchCase="day.key">
<stapps-data-list-item [item]="dish" *ngFor="let dish of day.value"></stapps-data-list-item>
</ion-list>
</div>
</div>
</div>
<ng-template #loading>
<ion-segment>
<stapps-skeleton-segment-button *ngFor="let skeleton of [1, 2, 3]"></stapps-skeleton-segment-button>
</ion-segment>
<ion-list>
<stapps-skeleton-list-item *ngFor="let skeleton of [1, 2]"></stapps-skeleton-list-item>
</ion-list>
</ng-template>
</ng-container>

View File

@@ -21,7 +21,7 @@ import {TranslateModule,} from '@ngx-translate/core';
import {SCFacet, SCThingType} from '@openstapps/core';
import {ContextMenuComponent} from './context-menu.component';
import {SettingsModule} from '../../settings/settings.module';
import {MenuService} from '../menu.service';
import {ContextMenuService} from '../context/context-menu.service';
import {FilterContext, SortContext} from './context-type';
describe('ContextMenuComponent', async () => {
@@ -36,7 +36,7 @@ describe('ContextMenuComponent', async () => {
ChildrenOutletContexts,
Location,
UrlSerializer,
MenuService,
ContextMenuService,
{provide: LocationStrategy, useClass: PathLocationStrategy},
{provide: APP_BASE_HREF, useValue: '/'},
],

View File

@@ -20,8 +20,9 @@ import {
SCThingType,
SCTranslations,
} from '@openstapps/core';
import {MenuService} from '../menu.service';
import {ContextMenuService} from './context-menu.service';
import {FilterContext, SortContext, SortContextOption} from './context-type';
import {Subscription} from 'rxjs';
/**
* The context menu
@@ -68,30 +69,45 @@ export class ContextMenuComponent {
*/
translator: SCThingTranslator;
/**
* Array of all Subscriptions
*/
subscriptions: Subscription[] = [];
constructor(private translateService: TranslateService,
private readonly menuService: MenuService) {
private readonly contextMenuService: ContextMenuService) {
this.language = this.translateService.currentLang as keyof SCTranslations<SCLanguage>;
this.translator = new SCThingTranslator(this.language);
this.translateService.onLangChange.subscribe((event: LangChangeEvent) => {
this.subscriptions.push(this.translateService.onLangChange.subscribe((event: LangChangeEvent) => {
this.language = event.lang as keyof SCTranslations<SCLanguage>;
this.translator = new SCThingTranslator(this.language);
});
}));
this.menuService.filterContextChanged$.subscribe((filterContext) => {
this.subscriptions.push(this.contextMenuService.filterContextChanged$.subscribe((filterContext) => {
this.filterOption = filterContext;
});
}));
this.menuService.sortOptions.subscribe((sortContext) => {
this.subscriptions.push(this.contextMenuService.sortOptions.subscribe((sortContext) => {
this.sortOption = sortContext;
});
}));
}
/**
* Unsubscribe from Observables
*/
ngOnDestroy() {
for (let sub of this.subscriptions) {
sub.unsubscribe();
}
}
/**
* Sets selected filter options and updates listener
*/
filterChanged = () => {
this.menuService.contextFilterChanged(this.filterOption);
this.contextMenuService.contextFilterChanged(this.filterOption);
}
/**
@@ -117,7 +133,7 @@ export class ContextMenuComponent {
option.options.forEach((filterFacet) => filterFacet.buckets.forEach((filterBucket) => {
filterBucket.checked = false;
}));
this.menuService.contextFilterChanged(this.filterOption);
this.contextMenuService.contextFilterChanged(this.filterOption);
}
/**
@@ -134,6 +150,6 @@ export class ContextMenuComponent {
option.reversed = false;
}
}
this.menuService.contextSortChanged(option);
this.contextMenuService.contextSortChanged(option);
}
}

View File

@@ -1,17 +1,17 @@
import {TestBed} from '@angular/core/testing';
import {MenuService} from './menu.service';
import {ContextMenuService} from './context-menu.service';
import {SCFacet} from '@openstapps/core';
import {FilterContext, SortContext} from './context/context-type';
import {FilterContext, SortContext} from './context-type';
describe('MenuService', () => {
let service: MenuService;
describe('ContextMenuService', () => {
let service: ContextMenuService;
beforeEach(() => {
TestBed.configureTestingModule({
providers: [MenuService]
providers: [ContextMenuService]
});
service = TestBed.get(MenuService);
service = TestBed.get(ContextMenuService);
});
it('should be created', () => {

View File

@@ -15,13 +15,13 @@
import {Injectable} from '@angular/core';
import {SCFacet, SCFacetBucket, SCSearchFilter, SCSearchSort} from '@openstapps/core';
import {Subject} from 'rxjs';
import {FilterBucket, FilterContext, FilterFacet, SortContext} from './context/context-type';
import {FilterBucket, FilterContext, FilterFacet, SortContext} from './context-type';
/**
* MenuService provides bidirectional communication of context menu options and search queries
* ContextMenuService provides bidirectional communication of context menu options and search queries
*/
@Injectable()
export class MenuService {
export class ContextMenuService {
/**
* Local filter context object
@@ -82,9 +82,10 @@ export class MenuService {
const filters: SCSearchFilter[] = [];
filterContext.options.forEach((filterFacet) => {
const optionFilters: SCSearchFilter[] = [];
filterFacet.buckets.forEach((filterBucket) => {
if (filterBucket.checked) {
filters.push(
optionFilters.push(
{
arguments: {
field: filterFacet.field,
@@ -94,13 +95,22 @@ export class MenuService {
});
}
});
if (optionFilters.length > 0) {
filters.push({
arguments: {
filters: optionFilters,
operation: 'or',
},
type: 'boolean',
});
}
});
if (filters.length > 0) {
return {
arguments: {
filters: filters,
operation: 'or',
operation: 'and',
},
type: 'boolean',
};

View File

@@ -20,7 +20,7 @@ import {IonicModule} from '@ionic/angular';
import {TranslateModule} from '@ngx-translate/core';
import {SettingsModule} from '../settings/settings.module';
import {ContextMenuComponent} from './context/context-menu.component';
import {MenuService} from './menu.service';
import {ContextMenuService} from './context/context-menu.service';
import {NavigationComponent} from './navigation/navigation.component';
/**
@@ -44,7 +44,7 @@ import {NavigationComponent} from './navigation/navigation.component';
SettingsModule,
],
providers: [
MenuService,
ContextMenuService,
],
})
export class MenuModule {}