Commit ccd71763 authored by Janik Münzenberger's avatar Janik Münzenberger
Browse files

Added some loading and error handling

parent 296d54d2
......@@ -11,7 +11,7 @@
"/assets/i18n/*.json",
"/*.css",
"/*.js",
"/*.js"
"/*.js",
],
"urls":[
"https://use.fontawesome.com/releases/v5.0.13/css/*"
......@@ -24,6 +24,7 @@
"updateMode": "lazy",
"resources": {
"files": [
"/*.jpg",
"/assets/img/*.jpg",
"/assets/img/*.webp",
"/assets/icons/*.png"
......
......@@ -2,6 +2,8 @@ import {Component} from '@angular/core';
import {TranslateService} from '@ngx-translate/core';
import {SwPush} from '@angular/service-worker';
import {NotificationService} from './services/notification.service';
import { UserDataService } from './services/user-data.service';
import { AuthService } from './services/auth.service';
@Component({
selector: 'app-root',
......@@ -12,9 +14,15 @@ export class AppComponent {
constructor(translate: TranslateService,
private notificationService: NotificationService) {
private notificationService: NotificationService,
private authService: AuthService,
private userDataService: UserDataService) {
translate.setDefaultLang('en');
translate.use('en');
this.notificationService.subscribeToNotifications();
if(this.authService.isAuthentificated()){
this.userDataService.getUser().catch(err => console.error(err));
}
}
}
......@@ -47,6 +47,8 @@ import {GardenerService} from './services/gardener.service';
import {StringifyPipe} from './pipes/stringify.pipe';
import {LanguageSwitchComponent} from './components/language-switch/language-switch.component';
import {NotificationService} from "./services/notification.service";
import { UserDataService } from './services/user-data.service';
import { TimeoutDirective } from './directives/timeout.directive';
export function HttpLoaderFactory(http: HttpClient) {
......@@ -76,7 +78,8 @@ export function HttpLoaderFactory(http: HttpClient) {
MapComponent,
ListmapComponent,
StringifyPipe,
LanguageSwitchComponent
LanguageSwitchComponent,
TimeoutDirective
],
imports: [
......@@ -107,7 +110,7 @@ export function HttpLoaderFactory(http: HttpClient) {
],
providers: [AnalysisService, ApiService, AuthService,
AuthguardService, UserService, GardenerService,
MapService, NotificationService],
MapService, NotificationService, UserDataService],
bootstrap: [AppComponent]
})
export class AppModule {
......
import { TimeoutDirective } from './timeout.directive';
describe('TimeoutDirective', () => {
it('should create an instance', () => {
const directive = new TimeoutDirective();
expect(directive).toBeTruthy();
});
});
import { Directive, Input, ElementRef, AfterViewInit } from '@angular/core';
@Directive({
selector: '[appTimeout]'
})
export class TimeoutDirective implements AfterViewInit {
@Input() timeout: number;
displayStyle: string;
constructor(private el: ElementRef) { }
ngAfterViewInit() {
let styles = getComputedStyle(this.el.nativeElement);
this.displayStyle = styles.display
if (this.timeout) {
this.hide();
setTimeout(() => {
this.show();
}, this.timeout);
}
}
hide() {
this.el.nativeElement.style.display = 'none';
}
show() {
this.el.nativeElement.style.display = this.displayStyle;
}
}
......@@ -17,7 +17,12 @@
</div>
<div>
<div class="col-md-12">
<div class="col-md-12 mt-4" *ngIf="errorMessage">
<div class="col-md-12 alert alert-danger mx-auto">
{{errorMessage | translate}}
</div>
</div>
<div class="col-md-12" *ngIf="diseases.length">
<ul class="list-group">
<li style="cursor:pointer;" class="list-group-item list-group-item-action" *ngFor="let disease of diseases | sort | filter: filterValue"
[routerLink]="['/disease', disease._id]">
......
......@@ -13,6 +13,7 @@ export class DiseaseListComponent implements OnInit {
filterValue = '';
diseases: IDisease[] = [];
errorMessage: string;
constructor(private route: Router, private diseaseService: DiseaseService) {
......@@ -24,7 +25,11 @@ export class DiseaseListComponent implements OnInit {
getDiseases(){
this.diseaseService.getAllDiseases()
.then(diseases => this.diseases = diseases);
.then(diseases => this.diseases = diseases)
.catch(err => {
console.error(err);
this.errorMessage = "ERRORS.DISEASES";
});
}
onShowDetails(disease: IDisease) {
......
<div class="container">
<div class="loader mx-auto my-5" *ngIf="!disease" appTimeout [timeout]="1000"></div>
<div class="col-md-12" *ngIf="!disease && error">
<div class="col-md-12 alert alert-warning mx-auto">
{{"ERRORS.DISEASE" | translate}}
</div>
</div>
<div class="container" *ngIf="disease">
<h1>{{disease?.name}}</h1>
<div class="row align-items-start mt-5">
<img
[src]="disease?.example_url || './assets/img/' + disease?.crop_id.name +'.jpg'"
class="img-fluid col-md-6"
alt="Responsive image">
<img [src]="disease?.example_url || './assets/img/' + disease?.crop_id.name +'.jpg'" class="img-fluid col-md-6" alt="Disease image">
<div class="col-md-6 my-5 my-md-0">
<h3>{{"DISEASE.INFORMATION" | translate}}</h3>
<table class="table">
<tbody>
<tr>
<th scope="row">{{"DISEASE.NAME" | translate}}</th>
<td>{{disease?.name}}</td>
</tr>
<tr *ngIf="disease?.eppo_code">
<th scope="row">{{"DISEASE.EPPO_CODE" | translate}}</th>
<td>{{disease.eppo_code}}</td>
</tr>
<tr *ngIf="disease?.symptoms">
<th scope="row">{{"DISEASE.SYMPTOMS" | translate}}</th>
<td>{{disease.symptoms}}</td>
</tr>
<tr>
<th scope="row">{{"DISEASE.CROP" | translate}}</th>
<td>{{disease?.crop_id?.name}}</td>
</tr>
<tr *ngIf="disease?.leaf_wetness">
<th scope="row">{{"DISEASE.LEAF_WETNESS" | translate}}</th>
<td>{{disease.leaf_wetness}}</td>
</tr>
<tr *ngIf="disease?.bbch_from">
<th scope="row">{{"DISEASE.BBCH" | translate}}</th>
<td>{{disease.bbch_from}} - {{disease.bbch_to}}</td>
</tr>
<tr *ngIf="disease?.celsius_low">
<th scope="row">{{"DISEASE.TEMPERATURE" | translate}}</th>
<td>{{disease.celsius_low}} - {{disease.celsius_high}}°C</td>
</tr>
<tr *ngIf="disease?.humidity_from">
<th scope="row">{{"DISEASE.HUMIDITY" | translate}}</th>
<td>{{disease.humidity_from}} - {{disease.humidity_to}}%</td>
</tr>
<tr>
<th scope="row">{{"DISEASE.DETECTION_SUPPORTED" | translate}}</th>
<td>{{(disease?.detection_supported ? "YES": "NO") | translate}}</td>
</tr>
</tbody>
</table>
<h3>{{"DISEASE.INFORMATION" | translate}}</h3>
<table class="table">
<tbody>
<tr>
<th scope="row">{{"DISEASE.NAME" | translate}}</th>
<td>{{disease?.name}}</td>
</tr>
<tr *ngIf="disease?.eppo_code">
<th scope="row">{{"DISEASE.EPPO_CODE" | translate}}</th>
<td>{{disease.eppo_code}}</td>
</tr>
<tr *ngIf="disease?.symptoms">
<th scope="row">{{"DISEASE.SYMPTOMS" | translate}}</th>
<td>{{disease.symptoms}}</td>
</tr>
<tr>
<th scope="row">{{"DISEASE.CROP" | translate}}</th>
<td>{{disease?.crop_id?.name}}</td>
</tr>
<tr *ngIf="disease?.leaf_wetness">
<th scope="row">{{"DISEASE.LEAF_WETNESS" | translate}}</th>
<td>{{disease.leaf_wetness}}</td>
</tr>
<tr *ngIf="disease?.bbch_from">
<th scope="row">{{"DISEASE.BBCH" | translate}}</th>
<td>{{disease.bbch_from}} - {{disease.bbch_to}}</td>
</tr>
<tr *ngIf="disease?.celsius_low">
<th scope="row">{{"DISEASE.TEMPERATURE" | translate}}</th>
<td>{{disease.celsius_low}} - {{disease.celsius_high}}°C</td>
</tr>
<tr *ngIf="disease?.humidity_from">
<th scope="row">{{"DISEASE.HUMIDITY" | translate}}</th>
<td>{{disease.humidity_from}} - {{disease.humidity_to}}%</td>
</tr>
<tr>
<th scope="row">{{"DISEASE.DETECTION_SUPPORTED" | translate}}</th>
<td>{{(disease?.detection_supported ? "YES": "NO") | translate}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
......@@ -13,6 +13,7 @@ import { ActivatedRoute, Params } from '@angular/router';
export class DiseaseComponent implements OnInit, OnDestroy {
disease: IDisease;
sub: Subscription;
error: boolean;
constructor(private dService: DiseaseService, private route: ActivatedRoute) {}
......@@ -30,6 +31,7 @@ export class DiseaseComponent implements OnInit, OnDestroy {
getPlant(id) {
this.dService.getSingleDisease(id)
.then(disease => this.disease = disease)
.catch(err => console.log(err));
.catch(err => console.log(err))
.catch(() => this.error = true);
}
}
<div class="container">
<h3 class="row col-md-12">{{"GARDENERS.NEARBY" | translate}}</h3>
<h2 class="row col-md-12">{{"GARDENERS.NEARBY" | translate}}</h2>
<hr>
<mat-tab-group>
<mat-tab label="Google Maps">
......
<div class="list-group">
<div class="list-group" *ngIf="mapservice.data.length">
<a class="list-group-item list-group-item-action flex-column align-items-start" *ngFor="let g of mapservice.data">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1">{{g.name}}</h5>
......@@ -24,3 +24,4 @@
</p>
</a>
</div>
<div class="list-group" *ngIf="!mapservice.data.length">{{"ERRORS.GARDENERS" | translate}}</div>
\ No newline at end of file
......@@ -46,11 +46,8 @@ export class LoginComponent implements OnInit {
});
this.router.navigate(['/profile']);
}).catch(err => {
this.snackBar.open('Login', 'failed', {
duration: 3000,
});
this.error = true;
this.errorResponse = err.error.error.message;
this.errorResponse = err.error.error.message || "Sorry could not login";
});
}
......
<div class="container">
<div class="loader mx-auto my-5" *ngIf="!plant" appTimeout [timeout]="1000"></div>
<div class="col-md-12" *ngIf="!plant && error">
<div class="col-md-12 alert alert-warning mx-auto">
{{"ERRORS.PLANTS" | translate}}
</div>
</div>
<div class="container" *ngIf="plant">
<!-- As a heading -->
<nav class="navbar navbar-light bg-light mt-2">
<h2 class="mb-0 h1">{{plant?.name}}</h2>
<button type="button" class="btn btn-success ml-auto" (click)="onShowAnalyse()">Analyse</button>
</nav>
<div class="row two mt-md-2">
<img [src]="plant?.image_url || './assets/img/' + plant?.name +'.jpg'"
class="img-fluid col-md-6" alt="Responsive image">
<img [src]="plant?.image_url || './assets/img/' + plant?.name +'.jpg'" class="img-fluid col-md-6" alt="Plantimage">
<div class="col-md-6">
<h3 class="mt-5 mt-md-0">{{"PLANT.INFORMATION" | translate}}</h3>
<table class="table">
......@@ -38,7 +43,5 @@
</div>
</section>
</div>
</div>
</div>
......@@ -13,6 +13,7 @@ import { Subscription } from 'rxjs';
export class PlantdetailsComponent implements OnInit, OnDestroy {
plant: IPlant;
sub: Subscription;
error: boolean = false;
constructor(private router: Router,
private route: ActivatedRoute,
......@@ -33,7 +34,10 @@ export class PlantdetailsComponent implements OnInit, OnDestroy {
getPlant(id){
this.plantService.getSinglePlant(id)
.then(plant => this.plant = plant)
.catch(err => console.log(err));
.catch(err => {
console.error(err);
this.error = true;
});
}
onShowAnalyse() {
......
......@@ -17,13 +17,17 @@
</div>
<div>
<div class="col-md-12 mt-4" *ngIf="errorMessage">
<div class="col-md-12 alert alert-danger mx-auto">
{{errorMessage | translate}}
</div>
</div>
<div class="col-md-12">
<ul class="list-group">
<li style="cursor:pointer;" class="list-group-item list-group-item-action d-flex flex-row align-items-center" *ngFor="let plant of plants | sort | filter: filterValue"
[routerLink]="['/details', plant?._id]">
<img [src]="plant.image_url || './assets/img/' + plant.name +'-icon.jpg'"
class="img-fluid mr-5 profile-img" [alt]="plant.name">
<h4>{{plant.name}}</h4>
<img [src]="plant.image_url || './assets/img/' + plant.name +'-icon.jpg'" class="img-fluid mr-5 profile-img" [alt]="plant?.name">
<h4>{{plant?.name}}</h4>
</li>
</ul>
</div>
......
import {Component, OnInit} from '@angular/core';
import {Route, Router} from '@angular/router';
import { IPlant } from '../../model/IPlant';
import { PlantService } from '../../services/plant.service';
......@@ -13,7 +12,7 @@ export class PlantsComponent implements OnInit {
filterValue = '';
plants: IPlant[] = [];
errorMessage: string;
constructor(private plantService: PlantService) {}
ngOnInit() {
......@@ -21,7 +20,12 @@ export class PlantsComponent implements OnInit {
}
getPlants(){
this.errorMessage = null;
this.plantService.getAllPlants()
.then(plants => this.plants = plants);
.then(plants => this.plants = plants)
.catch(err => {
console.error(err);
this.errorMessage = "ERRORS.PLANTS";
});
}
}
import {Component, OnInit} from '@angular/core';
import {FormControl, FormGroup, Validators} from '@angular/forms';
import {AuthService} from '../../services/auth.service';
import {MatSnackBar} from '@angular/material';
import {Router} from '@angular/router';
import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { AuthService } from '../../services/auth.service';
import { MatSnackBar } from '@angular/material';
import { Router } from '@angular/router';
@Component({
selector: 'app-register',
......@@ -31,14 +31,11 @@ export class RegisterComponent implements OnInit {
this.authservice.register(this.registerForm.value)
.then(message => {
this.registerForm.reset();
this.route.navigate(['/login'], {queryParams: {reason: 'registered'}});
this.route.navigate(['/login'], { queryParams: { reason: 'registered' } });
}).catch(err => {
this.snackBar.open('Registration', 'failed', {
duration: 3000,
});
this.error = true;
this.errorResponse = err.error.error.message;
console.log(err);
this.error = true;
this.errorResponse = err.error.error.message || "Could not be registered";
console.error(err);
});
}
......
......@@ -2,24 +2,9 @@
cursor: pointer;
}
.cover {
z-index: 999;
width: 100%;
height: 100%;
display: flex;
position: fixed;
top: 0;
left: 0;
align-items: center;
flex-direction: column;
justify-content: center;
background-color: rgba(0, 0, 0, 0.8);
color: #fff;
}
button {
height: auto;
word-break: normal;
white-space: normal;
max-width: 100%;
}
\ No newline at end of file
}
<div class="container">
<div class="cover" tabindex="-1" *ngIf="!job">
<div class="loader"></div>
<h3 class="m-4 text-center">{{"ANALYSIS.PROGRESS" | translate}}</h3>
</div>
<div class="container" *ngIf="job">
<h2>{{"RESULT.FOR" | translate}} {{job?.plant.name}}</h2>
<hr />
<div class="row align-items-start mt-4">
<img [src]="apiHost + job?.image_url || './assets/img/' + job?.plant.name +'.jpg'" class="img-fluid col-md-6" [alt]="'Job-' + job?._id">
<div class="col-md-6">
......@@ -10,16 +15,12 @@
<h3>{{"RESULT.DISEASES" | translate}}</h3>
<div class="list-group">
<li *ngFor="let result of job?.result" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center"
[routerLink]="['/disease', result?.disease_id?._id]">{{result?.disease_id?.name || ("RESULT.NONE" | translate)}}
[routerLink]="result?.disease_id?._id ? ['/disease', result.disease_id._id] : []">{{result?.disease_id?.name || ("RESULT.NONE" | translate)}}
<span class="badge badge-primary badge-pill">{{result?.confidence * 100 | number: '1.2'}}%</span>
</li>
</div>
</div>
</div>
</div>
<div class="cover" tabindex="1" #loader>
<div class="loader"></div>
<h3 class="mx-4 text-center">{{"ANALYSIS.PROGRESS" | translate}}</h3>
</div>
<app-email [receivers]="gardeners" [message]="job?.result | stringify" #email></app-email>
\ No newline at end of file
......@@ -20,8 +20,6 @@ export class ResultComponent implements OnInit {
apiHost: string = environment.API_HOST;
gardeners: IGardener[] = [];
@ViewChild('loader') loader;
@ViewChild('email') email: EmailComponent;
constructor(private router: Router,
......@@ -30,7 +28,6 @@ export class ResultComponent implements OnInit {
private gService: GardenerService) { }
ngOnInit() {
this.stopAnalysis();
this.sub = this.route.params.subscribe((params: Params) => {
let id = params['id'];
this.getResult(id);
......@@ -42,19 +39,13 @@ export class ResultComponent implements OnInit {
this.email.open();
}
startAnalysis() { this.loader.nativeElement.style.display = 'flex'; }
stopAnalysis() { this.loader.nativeElement.style.display = 'none'; }
getResult(id: string) {
let interval = setInterval(() => {
this.aService.getResult(id)
.then(res => {
if(res.success){
this.job = res.data;
this.stopAnalysis();
clearInterval(interval);
}else{
this.startAnalysis();
}
})
.catch(err => console.error(err));
......@@ -64,6 +55,6 @@ export class ResultComponent implements OnInit {
getGardeners() {
this.gService.getAllGardeners()
.then(gardeners => this.gardeners = gardeners)
.catch(err => console.error("Fehler"));
.catch(err => console.error(err));
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment