refactor: remove default data from search page

Closes #151
This commit is contained in:
Jovan Krunić
2021-11-03 12:41:04 +00:00
parent d3188f5090
commit d6cb7e1d3b
13 changed files with 101 additions and 47 deletions

View File

@@ -24,7 +24,7 @@
</ion-refresher> </ion-refresher>
<div [ngSwitch]="true"> <div [ngSwitch]="true">
<ng-container *ngSwitchCase="!item && isDisconnected()"> <ng-container *ngSwitchCase="!item && isDisconnected()">
<div class="notFoundContainer"> <div class="centeredMessageContainer">
<ion-icon name="no-connection"> </ion-icon> <ion-icon name="no-connection"> </ion-icon>
<ion-label> <ion-label>
{{ 'data.detail.COULD_NOT_CONNECT' | translate }} {{ 'data.detail.COULD_NOT_CONNECT' | translate }}
@@ -32,7 +32,7 @@
</div> </div>
</ng-container> </ng-container>
<ng-container *ngSwitchCase="item === null"> <ng-container *ngSwitchCase="item === null">
<div class="notFoundContainer"> <div class="centeredMessageContainer">
<ion-icon name="broken-link"> </ion-icon> <ion-icon name="broken-link"> </ion-icon>
<ion-label> <ion-label>
{{ 'data.detail.NOT_FOUND' | translate }} {{ 'data.detail.NOT_FOUND' | translate }}

View File

@@ -80,6 +80,11 @@ export class DataListComponent implements OnChanges, OnInit, OnDestroy {
@ViewChild(CdkVirtualScrollViewport) viewPort: CdkVirtualScrollViewport; @ViewChild(CdkVirtualScrollViewport) viewPort: CdkVirtualScrollViewport;
/**
* Signalizes that the data is being loaded
*/
@Input() loading = true;
/** /**
* Calculate how many items would fill the screen * Calculate how many items would fill the screen
*/ */
@@ -130,10 +135,10 @@ export class DataListComponent implements OnChanges, OnInit, OnDestroy {
/** /**
* Function to call whenever scroll view visible range changed * Function to call whenever scroll view visible range changed
*/ */
scrolled(_index: number) { scrolled(index: number) {
if ( if (
// first condition prevents "load more" to be executed before event having initial items // first condition prevents "load more" to be executed even before scrolling
this.items && index > 0 &&
(this.items?.length ?? 0) - this.viewPort.getRenderedRange().end <= (this.items?.length ?? 0) - this.viewPort.getRenderedRange().end <=
(this.items?.length ?? 0) * this.reloadThreshold (this.items?.length ?? 0) * this.reloadThreshold
) { ) {

View File

@@ -15,12 +15,14 @@
</ion-list> </ion-list>
</cdk-virtual-scroll-viewport> </cdk-virtual-scroll-viewport>
</ng-container> </ng-container>
<div [style.display]="items && items.length === 0 ? 'block' : 'none'"> <div
<ion-label class="notFoundContainer"> [style.display]="!loading && items && items.length === 0 ? 'block' : 'none'"
>
<ion-label class="centeredMessageContainer">
{{ 'search.nothing_found' | translate | titlecase }} {{ 'search.nothing_found' | translate | titlecase }}
</ion-label> </ion-label>
</div> </div>
<ion-list [style.display]="items ? 'none' : 'block'"> <ion-list [style.display]="loading ? 'block' : 'none'">
<stapps-skeleton-list-item <stapps-skeleton-list-item
[hideThumbnail]="singleType" [hideThumbnail]="singleType"
*ngFor="let skeleton of [].constructor(skeletonItems)" *ngFor="let skeleton of [].constructor(skeletonItems)"

View File

@@ -26,6 +26,8 @@ export class FoodDataListComponent extends SearchPageComponent {
* Sets the forced filter to present only places for eating/drinking * Sets the forced filter to present only places for eating/drinking
*/ */
initialize() { initialize() {
this.showDefaultData = true;
if (this.positionService.position) { if (this.positionService.position) {
this.sortQuery = [ this.sortQuery = [
{ {

View File

@@ -40,6 +40,16 @@ import {PositionService} from '../../map/position.service';
providers: [ContextMenuService], providers: [ContextMenuService],
}) })
export class SearchPageComponent implements OnInit, OnDestroy { export class SearchPageComponent implements OnInit, OnDestroy {
/**
* Signalizes that the data is being loaded
*/
loading = false;
/**
* Show default data (e.g. when there is user interaction)
*/
@Input() showDefaultData = false;
/** /**
* Api query filter * Api query filter
*/ */
@@ -166,11 +176,13 @@ export class SearchPageComponent implements OnInit, OnDestroy {
}; };
} }
return this.dataProvider.search(searchOptions).then( this.loading = !append;
async result => {
try {
const result = await this.dataProvider.search(searchOptions);
this.singleTypeResponse = this.singleTypeResponse =
result.facets.find(facet => facet.field === 'type')?.buckets result.facets.find(facet => facet.field === 'type')?.buckets.length ===
.length === 1; 1;
if (append) { if (append) {
let items = await this.items; let items = await this.items;
// append results // append results
@@ -184,8 +196,7 @@ export class SearchPageComponent implements OnInit, OnDestroy {
return result.data; return result.data;
})(); })();
} }
}, } catch (error) {
async error => {
const alert: HTMLIonAlertElement = await this.alertController.create({ const alert: HTMLIonAlertElement = await this.alertController.create({
buttons: ['Dismiss'], buttons: ['Dismiss'],
header: 'Error', header: 'Error',
@@ -193,8 +204,9 @@ export class SearchPageComponent implements OnInit, OnDestroy {
}); });
await alert.present(); await alert.present();
}, } finally {
); this.loading = false;
}
} }
/** /**
@@ -268,8 +280,14 @@ export class SearchPageComponent implements OnInit, OnDestroy {
this.filterQuery = query[1]; this.filterQuery = query[1];
this.sortQuery = query[2]; this.sortQuery = query[2];
this.from = 0; this.from = 0;
if (
typeof this.filterQuery !== 'undefined' ||
this.queryText?.length > 0 ||
this.showDefaultData
) {
await this.fetchAndUpdateItems(); await this.fetchAndUpdateItems();
this.queryChanged.next(); this.queryChanged.next();
}
}), }),
this.settingsProvider.settingsActionChanged$.subscribe( this.settingsProvider.settingsActionChanged$.subscribe(
({type, payload}) => { ({type, payload}) => {

View File

@@ -14,17 +14,26 @@
(ngModelChange)="searchStringChanged($event)" (ngModelChange)="searchStringChanged($event)"
[(ngModel)]="queryText" [(ngModel)]="queryText"
showClearButton="always" showClearButton="always"
placeholder="{{ 'search.search_bar.placeholder' | translate }}"
> >
</ion-searchbar> </ion-searchbar>
</ion-toolbar> </ion-toolbar>
</ion-header> </ion-header>
<ion-content> <ion-content>
<div
[style.display]="!showDefaultData && !items && !loading ? 'block' : 'none'"
>
<ion-label class="centeredMessageContainer">
{{ 'search.instruction' | translate }}
</ion-label>
</div>
<stapps-data-list <stapps-data-list
id="data-list" id="data-list"
[items]="items | async" [items]="items | async"
[singleType]="singleTypeResponse" [singleType]="singleTypeResponse"
(loadmore)="loadMore()" (loadmore)="loadMore()"
[resetToTop]="queryChanged.asObservable()" [resetToTop]="queryChanged.asObservable()"
[loading]="loading"
></stapps-data-list> ></stapps-data-list>
</ion-content> </ion-content>

View File

@@ -35,6 +35,7 @@ export class CatalogDetailContentComponent
} }
initialize() { initialize() {
this.showDefaultData = true;
this.pageSize = 100; this.pageSize = 100;
const nameSort: SCDucetSort = { const nameSort: SCDucetSort = {

View File

@@ -12,7 +12,7 @@
* 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 {Component} from '@angular/core'; import {Component, OnInit} from '@angular/core';
import {FavoritesService} from './favorites.service'; import {FavoritesService} from './favorites.service';
import {DataRoutingService} from '../data/data-routing.service'; import {DataRoutingService} from '../data/data-routing.service';
import {Router} from '@angular/router'; import {Router} from '@angular/router';
@@ -33,7 +33,10 @@ import {take} from 'rxjs/operators';
providers: [ContextMenuService], providers: [ContextMenuService],
styleUrls: ['./favorites-page.component.scss'], styleUrls: ['./favorites-page.component.scss'],
}) })
export class FavoritesPageComponent extends SearchPageComponent { export class FavoritesPageComponent
extends SearchPageComponent
implements OnInit
{
constructor( constructor(
alertController: AlertController, alertController: AlertController,
dataProvider: DataProvider, dataProvider: DataProvider,
@@ -57,7 +60,8 @@ export class FavoritesPageComponent extends SearchPageComponent {
); );
} }
ionViewWillEnter() { ngOnInit() {
super.ngOnInit();
this.subscriptions.push( this.subscriptions.push(
this.favoritesService.favoritesChanged$.subscribe(_favoritesMap => { this.favoritesService.favoritesChanged$.subscribe(_favoritesMap => {
this.fetchAndUpdateItems(); this.fetchAndUpdateItems();
@@ -77,4 +81,8 @@ export class FavoritesPageComponent extends SearchPageComponent {
this.updateContextFilter(result.facets); this.updateContextFilter(result.facets);
}); });
} }
initialize() {
this.showDefaultData = true;
}
} }

View File

@@ -14,7 +14,7 @@
(keyup)="searchKeyUp($event)" (keyup)="searchKeyUp($event)"
[(ngModel)]="queryText" [(ngModel)]="queryText"
(ionClear)="searchStringChanged()" (ionClear)="searchStringChanged()"
placeholder="{{ 'map.page.search.PLACEHOLDER' | translate }}" placeholder="{{ 'map.page.search_bar.placeholder' | translate }}"
showClearButton="always" showClearButton="always"
> >
</ion-searchbar> </ion-searchbar>

View File

@@ -39,7 +39,7 @@
</ion-col> </ion-col>
</ion-row> </ion-row>
</ion-grid> </ion-grid>
<ion-label *ngIf="news.length === 0" class="notFoundContainer"> <ion-label *ngIf="news.length === 0" class="centeredMessageContainer">
{{ 'search.nothing_found' | translate | titlecase }} {{ 'search.nothing_found' | translate | titlecase }}
</ion-label> </ion-label>
<ion-infinite-scroll <ion-infinite-scroll

View File

@@ -126,8 +126,8 @@
"map": { "map": {
"page": { "page": {
"TITLE": "Karte", "TITLE": "Karte",
"search": { "search_bar": {
"PLACEHOLDER": "Gebäude, Points of Interest, Mensen und mehr" "placeholder": "Gebäude, Points of Interest, Mensen und mehr"
}, },
"buttons": { "buttons": {
"SHOW_LIST": "Liste ansehen", "SHOW_LIST": "Liste ansehen",
@@ -177,6 +177,10 @@
"title": "Aktuelles" "title": "Aktuelles"
}, },
"search": { "search": {
"search_bar": {
"placeholder": "Suche ..."
},
"instruction": "Starte oben zu tippen, um Veranstaltungen, Veranstaltungstermine, Personen, Orte, Essen und mehr zu finden ...",
"nothing_found": "Keine Ergebnisse" "nothing_found": "Keine Ergebnisse"
}, },
"schedule": { "schedule": {

View File

@@ -126,8 +126,8 @@
"map": { "map": {
"page": { "page": {
"TITLE": "Map", "TITLE": "Map",
"search": { "search_bar": {
"PLACEHOLDER": "Buildings, points of interests, canteens and more" "placeholder": "Buildings, points of interests, canteens and more"
}, },
"buttons": { "buttons": {
"SHOW_LIST": "Show list", "SHOW_LIST": "Show list",
@@ -177,6 +177,10 @@
"title": "News" "title": "News"
}, },
"search": { "search": {
"search_bar": {
"placeholder": "Search ..."
},
"instruction": "Start typing above to find events, persons, places, food and more ...",
"nothing_found": "No results" "nothing_found": "No results"
}, },
"schedule": { "schedule": {

View File

@@ -41,13 +41,14 @@ ion-item, ion-card.compact {
} }
} }
.notFoundContainer { .centeredMessageContainer {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
text-align: center; text-align: center;
min-height: 50vh; min-height: 50vh;
margin: 20px;
ion-icon { ion-icon {
font-size: 64px; font-size: 64px;