diff --git a/package-lock.json b/package-lock.json
index bf9cf289..56803a9a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -28,6 +28,23 @@
"requires": {
"@angular-devkit/core": "13.3.9",
"rxjs": "6.6.7"
+ },
+ "dependencies": {
+ "rxjs": {
+ "version": "6.6.7",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
+ "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+ "dev": true
+ }
}
},
"@angular-devkit/build-angular": {
@@ -240,6 +257,23 @@
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==",
"dev": true
},
+ "rxjs": {
+ "version": "6.6.7",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
+ "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.9.0"
+ },
+ "dependencies": {
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+ "dev": true
+ }
+ }
+ },
"semver": {
"version": "7.3.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
@@ -292,6 +326,23 @@
"requires": {
"@angular-devkit/architect": "0.1303.9",
"rxjs": "6.6.7"
+ },
+ "dependencies": {
+ "rxjs": {
+ "version": "6.6.7",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
+ "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+ "dev": true
+ }
}
},
"@angular-devkit/core": {
@@ -319,6 +370,21 @@
"require-from-string": "^2.0.2",
"uri-js": "^4.2.2"
}
+ },
+ "rxjs": {
+ "version": "6.6.7",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
+ "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+ "dev": true
}
}
},
@@ -340,6 +406,21 @@
"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz",
"integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==",
"dev": true
+ },
+ "rxjs": {
+ "version": "6.6.7",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
+ "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+ "dev": true
}
}
},
@@ -2594,6 +2675,21 @@
"requires": {
"ajv": "^8.0.0"
}
+ },
+ "rxjs": {
+ "version": "6.6.7",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
+ "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+ "dev": true
}
}
},
@@ -2970,6 +3066,23 @@
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0",
"through": "^2.3.6"
+ },
+ "dependencies": {
+ "rxjs": {
+ "version": "6.6.7",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
+ "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+ "dev": true
+ }
}
}
}
@@ -3774,6 +3887,23 @@
"yallist": "^4.0.0"
}
},
+ "rxjs": {
+ "version": "6.6.7",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
+ "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.9.0"
+ },
+ "dependencies": {
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+ "dev": true
+ }
+ }
+ },
"semver": {
"version": "7.3.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
@@ -3841,6 +3971,23 @@
"yallist": "^4.0.0"
}
},
+ "rxjs": {
+ "version": "6.6.7",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
+ "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.9.0"
+ },
+ "dependencies": {
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+ "dev": true
+ }
+ }
+ },
"semver": {
"version": "7.3.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
@@ -15378,18 +15525,11 @@
}
},
"rxjs": {
- "version": "6.6.7",
- "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
- "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz",
+ "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==",
"requires": {
- "tslib": "^1.9.0"
- },
- "dependencies": {
- "tslib": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
- }
+ "tslib": "^2.1.0"
}
},
"rxjs-for-await": {
@@ -16651,6 +16791,15 @@
"integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==",
"dev": true
},
+ "rxjs": {
+ "version": "6.6.7",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
+ "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
+ "dev": true,
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
"strip-ansi": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
@@ -16741,6 +16890,12 @@
"requires": {
"has-flag": "^3.0.0"
}
+ },
+ "tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+ "dev": true
}
}
},
diff --git a/package.json b/package.json
index 24598700..bbcc5dc1 100644
--- a/package.json
+++ b/package.json
@@ -105,7 +105,7 @@
"ngx-markdown": "13.1.0",
"ngx-moment": "6.0.2",
"opening_hours": "3.8.0",
- "rxjs": "6.6.7",
+ "rxjs": "7.8.0",
"swiper": "8.4.5",
"tslib": "2.4.1",
"zone.js": "0.12.0"
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index e3635b8c..a0e23c9a 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 StApps
+ * Copyright (C) 2023 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.
diff --git a/src/app/modules/auth/default-auth.service.spec.ts b/src/app/modules/auth/default-auth.service.spec.ts
index 9579ebe9..693c78da 100644
--- a/src/app/modules/auth/default-auth.service.spec.ts
+++ b/src/app/modules/auth/default-auth.service.spec.ts
@@ -19,10 +19,11 @@ import {DefaultAuthService} from './default-auth.service';
import {Browser} from 'ionic-appauth';
import {nowInSeconds, Requestor, StorageBackend} from '@openid/appauth';
import {TranslateService} from '@ngx-translate/core';
-import {LoggerConfig, LoggerModule, NGXLogger} from 'ngx-logger';
+import {LoggerConfig, LoggerModule, NGXLogger, NgxLoggerLevel} from 'ngx-logger';
import {StAppsWebHttpClient} from '../data/stapps-web-http-client.provider';
import {HttpClientModule} from '@angular/common/http';
import {IonicStorage} from 'ionic-appauth/lib';
+import {RouterModule} from '@angular/router';
describe('AuthService', () => {
let defaultAuthService: DefaultAuthService;
@@ -34,7 +35,11 @@ describe('AuthService', () => {
storageBackendSpy = jasmine.createSpyObj('StorageBackend', ['getItem']);
TestBed.configureTestingModule({
- imports: [HttpClientModule, LoggerModule],
+ imports: [
+ HttpClientModule,
+ LoggerModule.forRoot({level: NgxLoggerLevel.TRACE}),
+ RouterModule.forRoot([]),
+ ],
providers: [
NGXLogger,
StAppsWebHttpClient,
diff --git a/src/app/modules/auth/ng-http.service.ts b/src/app/modules/auth/ng-http.service.ts
index 73032f69..42dceb5c 100644
--- a/src/app/modules/auth/ng-http.service.ts
+++ b/src/app/modules/auth/ng-http.service.ts
@@ -1,8 +1,23 @@
+/*
+ * Copyright (C) 2023 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 .
+ */
+
import {Injectable} from '@angular/core';
import {Requestor} from '@openid/appauth';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {XhrSettings} from 'ionic-appauth/lib/cordova';
-import {Observable} from 'rxjs';
+import {firstValueFrom, Observable} from 'rxjs';
@Injectable({
providedIn: 'root',
@@ -40,7 +55,7 @@ export class NgHttpService implements Requestor {
break;
}
- return observable.toPromise();
+ return firstValueFrom(observable);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
diff --git a/src/app/modules/calendar/schedule.provider.ts b/src/app/modules/calendar/schedule.provider.ts
index 5ad1ff38..46e18ea7 100644
--- a/src/app/modules/calendar/schedule.provider.ts
+++ b/src/app/modules/calendar/schedule.provider.ts
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 StApps
+ * Copyright (C) 2023 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.
@@ -215,14 +215,12 @@ export class ScheduleProvider implements OnDestroy {
if (from || to) {
const bounds: Bounds = {};
if (from) {
- console.log(from);
bounds.lowerBound = {
limit: from,
mode: 'inclusive',
};
}
if (to) {
- console.log(to);
bounds.upperBound = {
limit: to,
mode: 'inclusive',
diff --git a/src/app/modules/dashboard/sections/favorites-section/favorites-section.component.ts b/src/app/modules/dashboard/sections/favorites-section/favorites-section.component.ts
index 6ab7784d..7e885c73 100644
--- a/src/app/modules/dashboard/sections/favorites-section/favorites-section.component.ts
+++ b/src/app/modules/dashboard/sections/favorites-section/favorites-section.component.ts
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 StApps
+ * Copyright (C) 2023 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.
diff --git a/src/app/modules/dashboard/sections/mensa-section/mensa-section.component.ts b/src/app/modules/dashboard/sections/mensa-section/mensa-section.component.ts
index e0f1e88d..f223e978 100644
--- a/src/app/modules/dashboard/sections/mensa-section/mensa-section.component.ts
+++ b/src/app/modules/dashboard/sections/mensa-section/mensa-section.component.ts
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 StApps
+ * Copyright (C) 2023 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.
diff --git a/src/app/modules/data/data.provider.spec.ts b/src/app/modules/data/data.provider.spec.ts
index 2ada5648..d7cfadfb 100644
--- a/src/app/modules/data/data.provider.spec.ts
+++ b/src/app/modules/data/data.provider.spec.ts
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 StApps
+ * Copyright (C) 2023 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.
@@ -31,6 +31,8 @@ import {StorageProvider} from '../storage/storage.provider';
import {DataModule} from './data.module';
import {DataProvider, DataScope} from './data.provider';
import {StAppsWebHttpClient} from './stapps-web-http-client.provider';
+import {LoggerModule, NgxLoggerLevel} from 'ngx-logger';
+import {RouterModule} from '@angular/router';
describe('DataProvider', () => {
let dataProvider: DataProvider;
@@ -82,7 +84,7 @@ describe('DataProvider', () => {
beforeEach(async () => {
TestBed.configureTestingModule({
- imports: [DataModule],
+ imports: [DataModule, LoggerModule.forRoot({level: NgxLoggerLevel.TRACE}), RouterModule.forRoot([])],
providers: [DataProvider, StAppsWebHttpClient],
});
storageProvider = TestBed.inject(StorageProvider);
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 d6435257..c471b7a3 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) 2022 StApps
+ * Copyright (C) 2023 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.
@@ -27,6 +27,7 @@ import {DataDetailComponent} from './data-detail.component';
import {By} from '@angular/platform-browser';
import {Observable, of} from 'rxjs';
import {StorageProvider} from '../../storage/storage.provider';
+import {LoggerModule, NgxLoggerLevel} from 'ngx-logger';
const translations: any = {data: {detail: {TITLE: 'Foo'}}};
@@ -70,6 +71,7 @@ describe('DataDetailComponent', () => {
TranslateModule.forRoot({
loader: {provide: TranslateLoader, useClass: TranslateFakeLoader},
}),
+ LoggerModule.forRoot({level: NgxLoggerLevel.TRACE}),
],
providers: [
{
diff --git a/src/app/modules/data/list/search-page.component.ts b/src/app/modules/data/list/search-page.component.ts
index 614a5868..138557ca 100644
--- a/src/app/modules/data/list/search-page.component.ts
+++ b/src/app/modules/data/list/search-page.component.ts
@@ -229,13 +229,7 @@ export class SearchPageComponent implements OnInit, OnDestroy {
})();
}
} catch (error) {
- const alert: HTMLIonAlertElement = await this.alertController.create({
- buttons: ['Dismiss'],
- header: 'Error',
- subHeader: (error as Error).message,
- });
-
- await alert.present();
+ this.logger.error(error);
} finally {
this.loading = false;
}
diff --git a/src/app/modules/data/stapps-web-http-client.provider.ts b/src/app/modules/data/stapps-web-http-client.provider.ts
index b34f9eb4..17240f21 100644
--- a/src/app/modules/data/stapps-web-http-client.provider.ts
+++ b/src/app/modules/data/stapps-web-http-client.provider.ts
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 StApps
+ * Copyright (C) 2023 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,6 +15,17 @@
import {HttpClient, HttpResponse} from '@angular/common/http';
import {Injectable} from '@angular/core';
import {HttpClientInterface, HttpClientRequest} from '@openstapps/api/lib/http-client-interface';
+import {map, retry} from 'rxjs/operators';
+import {lastValueFrom, Observable} from 'rxjs';
+import {InternetConnectionService} from '../../util/internet-connection.service';
+
+type HttpRequestFunctions = InstanceType['request'];
+type HttpRequestFunction> = Extract<
+ HttpRequestFunctions,
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (...parameters: any[]) => T
+>;
+type HttpRequestParameters> = Parameters>;
/**
* HttpClient that is based on the Angular HttpClient (@TODO: move it to provider or independent package)
@@ -23,9 +34,11 @@ import {HttpClientInterface, HttpClientRequest} from '@openstapps/api/lib/http-c
export class StAppsWebHttpClient implements HttpClientInterface {
/**
*
- * @param http TODO
*/
- constructor(private readonly http: HttpClient) {}
+ constructor(
+ private readonly http: HttpClient,
+ private readonly connectionService: InternetConnectionService,
+ ) {}
/**
* Make a request
@@ -33,42 +46,30 @@ export class StAppsWebHttpClient implements HttpClientInterface {
* @param requestConfig Configuration of the request
*/
async request(requestConfig: HttpClientRequest): Promise> {
- const options: {
- /**
- * TODO
- */
- [key: string]: unknown;
- /**
- * TODO
- */
- observe: 'response';
- } = {
- body: {},
- observe: 'response',
- responseType: 'json',
- };
+ const request: HttpRequestParameters>> = [
+ requestConfig.method || 'GET',
+ requestConfig.url.toString(),
+ {
+ body: (requestConfig.body || {}) as TYPE_OF_BODY,
+ headers: requestConfig.headers,
+ observe: 'response',
+ responseType: 'json',
+ },
+ ];
+ // TODO: cache requests by hashing the parameters.
- if (typeof requestConfig.body !== 'undefined') {
- options.body = requestConfig.body;
- }
+ const response: Observable> = this.http.request(...request).pipe(
+ retry(this.connectionService.retryConfig),
+ map(
+ response =>
+ Object.assign(response, {
+ statusCode: response.status,
+ body: response.body || {},
+ }) as Response,
+ ),
+ );
- if (typeof requestConfig.headers !== 'undefined') {
- options.headers = requestConfig.headers;
- }
-
- try {
- const response: HttpResponse = await this.http
- .request(requestConfig.method || 'GET', requestConfig.url.toString(), options)
- .toPromise();
-
- // eslint-disable-next-line prefer-object-spread
- return Object.assign(response, {
- statusCode: response.status,
- body: response.body || {},
- });
- } catch (error) {
- throw new Error(error as string);
- }
+ return lastValueFrom(response);
}
}
diff --git a/src/app/modules/favorites/favorites-page.component.ts b/src/app/modules/favorites/favorites-page.component.ts
index 58dbe49a..b2141bb9 100644
--- a/src/app/modules/favorites/favorites-page.component.ts
+++ b/src/app/modules/favorites/favorites-page.component.ts
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 StApps
+ * Copyright (C) 2023 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.
diff --git a/src/app/modules/hebis/hebis-detail/hebis-detail.component.spec.ts b/src/app/modules/hebis/hebis-detail/hebis-detail.component.spec.ts
index b5d096df..55a69a31 100644
--- a/src/app/modules/hebis/hebis-detail/hebis-detail.component.spec.ts
+++ b/src/app/modules/hebis/hebis-detail/hebis-detail.component.spec.ts
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 StApps
+ * Copyright (C) 2023 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.
@@ -28,6 +28,7 @@ import {Observable, of} from 'rxjs';
import {StorageProvider} from '../../storage/storage.provider';
import {IonicModule} from '@ionic/angular';
import {IonIconModule} from '../../../util/ion-icon/ion-icon.module';
+import {LoggerModule, NgxLoggerLevel} from 'ngx-logger';
const translations: any = {data: {detail: {TITLE: 'Foo'}}};
@@ -72,6 +73,7 @@ describe('HebisDetailComponent', () => {
TranslateModule.forRoot({
loader: {provide: TranslateLoader, useClass: TranslateFakeLoader},
}),
+ LoggerModule.forRoot({level: NgxLoggerLevel.TRACE}),
],
providers: [
{
diff --git a/src/app/modules/hebis/list/hebis-search-page.component.ts b/src/app/modules/hebis/list/hebis-search-page.component.ts
index e81a3e20..82259bcf 100644
--- a/src/app/modules/hebis/list/hebis-search-page.component.ts
+++ b/src/app/modules/hebis/list/hebis-search-page.component.ts
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 StApps
+ * Copyright (C) 2023 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.
diff --git a/src/app/modules/map/map.provider.spec.ts b/src/app/modules/map/map.provider.spec.ts
index c2455473..566eeaa5 100644
--- a/src/app/modules/map/map.provider.spec.ts
+++ b/src/app/modules/map/map.provider.spec.ts
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019-2021 StApps
+ * Copyright (C) 2023 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.
@@ -20,9 +20,10 @@ import {HttpClientModule} from '@angular/common/http';
import {StorageProvider} from '../storage/storage.provider';
import {MapModule} from './map.module';
import {StorageModule} from '../storage/storage.module';
-import {LoggerConfig, LoggerModule, NGXLogger} from 'ngx-logger';
+import {LoggerModule, NGXLogger, NgxLoggerLevel} from 'ngx-logger';
import {ConfigProvider} from '../config/config.provider';
import {sampleDefaultPolygon} from '../../_helpers/data/sample-configuration';
+import {RouterModule} from '@angular/router';
describe('MapProvider', () => {
let provider: MapProvider;
@@ -31,7 +32,13 @@ describe('MapProvider', () => {
beforeEach(() => {
configProvider = jasmine.createSpyObj('ConfigProvider', ['getValue']);
TestBed.configureTestingModule({
- imports: [MapModule, HttpClientModule, StorageModule, LoggerModule],
+ imports: [
+ MapModule,
+ HttpClientModule,
+ StorageModule,
+ LoggerModule.forRoot({level: NgxLoggerLevel.TRACE}),
+ RouterModule.forRoot([]),
+ ],
providers: [
{
provide: ConfigProvider,
@@ -40,7 +47,6 @@ describe('MapProvider', () => {
StAppsWebHttpClient,
StorageProvider,
NGXLogger,
- LoggerConfig,
],
});
diff --git a/src/app/modules/menu/context/context-menu.service.ts b/src/app/modules/menu/context/context-menu.service.ts
index 300803b2..be0cb799 100644
--- a/src/app/modules/menu/context/context-menu.service.ts
+++ b/src/app/modules/menu/context/context-menu.service.ts
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 StApps
+ * Copyright (C) 2023 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.
@@ -40,7 +40,7 @@ export class ContextMenuService {
/**
* Container for the filter query (SCSearchFilter)
*/
- filterQuery = new Subject();
+ filterQuery = new Subject();
/**
* Observable filterContext streams
@@ -65,7 +65,7 @@ export class ContextMenuService {
/**
* Container for the sort query
*/
- sortQuery = new Subject();
+ sortQuery = new Subject();
/**
* Observable SortContext streams
diff --git a/src/app/modules/menu/navigation/navigation.component.ts b/src/app/modules/menu/navigation/navigation.component.ts
index 8d6370c3..e10a7c83 100644
--- a/src/app/modules/menu/navigation/navigation.component.ts
+++ b/src/app/modules/menu/navigation/navigation.component.ts
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018, 2019 StApps
+ * Copyright (C) 2023 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.
diff --git a/src/app/modules/menu/navigation/navigation.html b/src/app/modules/menu/navigation/navigation.html
index 4dd103fb..59c503b6 100644
--- a/src/app/modules/menu/navigation/navigation.html
+++ b/src/app/modules/menu/navigation/navigation.html
@@ -13,6 +13,7 @@
~ this program. If not, see .
-->
+
diff --git a/src/app/modules/menu/navigation/navigation.module.ts b/src/app/modules/menu/navigation/navigation.module.ts
index fe77d28a..53879654 100644
--- a/src/app/modules/menu/navigation/navigation.module.ts
+++ b/src/app/modules/menu/navigation/navigation.module.ts
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2022 StApps
+ * Copyright (C) 2023 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.
@@ -21,9 +21,10 @@ import {IonicModule} from '@ionic/angular';
import {IonIconModule} from '../../../util/ion-icon/ion-icon.module';
import {TranslateModule} from '@ngx-translate/core';
import {RouterModule} from '@angular/router';
+import {OfflineNoticeComponent} from './offline-notice.component';
@NgModule({
- declarations: [RootLinkDirective, NavigationComponent, TabsComponent],
+ declarations: [RootLinkDirective, NavigationComponent, TabsComponent, OfflineNoticeComponent],
imports: [CommonModule, IonicModule, IonIconModule, TranslateModule, RouterModule],
exports: [TabsComponent, RootLinkDirective, NavigationComponent],
})
diff --git a/src/app/modules/menu/navigation/navigation.scss b/src/app/modules/menu/navigation/navigation.scss
index 51583863..830ebd71 100644
--- a/src/app/modules/menu/navigation/navigation.scss
+++ b/src/app/modules/menu/navigation/navigation.scss
@@ -1,5 +1,5 @@
/*!
- * Copyright (C) 2022 StApps
+ * Copyright (C) 2023 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.
@@ -21,8 +21,14 @@ stapps-navigation-tabs {
}
}
+stapps-offline-notice.has-error ~ ion-split-pane,
+stapps-offline-notice.is-offline ~ ion-split-pane {
+ margin-top: calc(var(--font-size-md) + 2 * var(--spacing-sm));
+}
+
:host {
ion-split-pane {
+ transition: margin-top 150ms ease;
--side-max-width: 256px;
margin-bottom: calc(var(--ion-tabbar-height) + env(safe-area-inset-bottom));
diff --git a/src/app/modules/menu/navigation/offline-notice.component.ts b/src/app/modules/menu/navigation/offline-notice.component.ts
new file mode 100644
index 00000000..758fc8b3
--- /dev/null
+++ b/src/app/modules/menu/navigation/offline-notice.component.ts
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2023 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 .
+ */
+
+import {Component, ElementRef, HostBinding, OnDestroy, ViewChild} from '@angular/core';
+import {InternetConnectionService} from '../../../util/internet-connection.service';
+import {Subscription} from 'rxjs';
+import {Router} from '@angular/router';
+import {NGXLogger} from 'ngx-logger';
+
+@Component({
+ selector: 'stapps-offline-notice',
+ templateUrl: 'offline-notice.html',
+ styleUrls: ['offline-notice.scss'],
+})
+export class OfflineNoticeComponent implements OnDestroy {
+ @HostBinding('class.is-offline') isOffline = false;
+
+ @HostBinding('class.has-error') hasError = false;
+
+ @ViewChild('spinIcon', {read: ElementRef}) spinIcon: ElementRef;
+
+ readonly subscriptions: Subscription[];
+
+ constructor(
+ readonly offlineProvider: InternetConnectionService,
+ readonly router: Router,
+ readonly logger: NGXLogger,
+ ) {
+ this.subscriptions = [
+ this.offlineProvider.offline$.subscribe(isOffline => {
+ this.isOffline = isOffline;
+ }),
+ this.offlineProvider.error$.subscribe(hasError => {
+ this.hasError = hasError;
+ }),
+ ];
+ }
+
+ retry() {
+ this.spinIcon.nativeElement.classList.remove('spin');
+ this.spinIcon.nativeElement.offsetWidth;
+ this.spinIcon.nativeElement.classList.add('spin');
+ this.offlineProvider.retry();
+ }
+
+ ngOnDestroy() {
+ for (const subscription of this.subscriptions) {
+ subscription.unsubscribe();
+ }
+ }
+}
diff --git a/src/app/modules/menu/navigation/offline-notice.html b/src/app/modules/menu/navigation/offline-notice.html
new file mode 100644
index 00000000..ebd5e89a
--- /dev/null
+++ b/src/app/modules/menu/navigation/offline-notice.html
@@ -0,0 +1,25 @@
+
+
+
+ {{ 'app.errors.OFFLINE' | translate }}
+
+
+
+ {{ 'app.errors.CONNECTION_ERROR' | translate }}
+
+
diff --git a/src/app/modules/menu/navigation/offline-notice.scss b/src/app/modules/menu/navigation/offline-notice.scss
new file mode 100644
index 00000000..952651bd
--- /dev/null
+++ b/src/app/modules/menu/navigation/offline-notice.scss
@@ -0,0 +1,77 @@
+/*!
+ * Copyright (C) 2023 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 .
+ */
+:host {
+ display: grid;
+ $height: calc(var(--font-size-md) + 2 * var(--spacing-sm));
+
+ height: $height;
+ width: 100%;
+
+ line-height: var(--font-size-md);
+ font-size: var(--font-size-md);
+ font-weight: bold;
+
+ transform: translateY(calc(-1 * $height));
+
+ transition: all 150ms ease;
+
+ &.is-offline,
+ &.has-error {
+ transform: translateY(0px);
+ }
+
+ > ion-button {
+ grid-row: 1;
+ grid-column: 1;
+ margin: 0;
+ --border-radius: 0;
+ opacity: 0;
+ --padding-top: 0;
+ --padding-bottom: 0;
+ transition: all 150ms ease;
+ z-index: 0;
+
+ &.close {
+ height: 100%;
+ margin: 0;
+ position: absolute;
+ right: 0;
+ top: 50%;
+ bottom: 0;
+ transform: translateY(-50%);
+ z-index: 1;
+ color: var(--ion-color-danger-contrast);
+ }
+ }
+
+ &.is-offline > .offline-button,
+ &.has-error > .close,
+ &.has-error > .error-button {
+ opacity: 1;
+ }
+}
+
+.spin {
+ animation: loading 1s ease running 3;
+}
+
+@keyframes loading {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
diff --git a/src/app/modules/schedule/page/schedule.service.ts b/src/app/modules/schedule/page/schedule.service.ts
deleted file mode 100644
index 3e428058..00000000
--- a/src/app/modules/schedule/page/schedule.service.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 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 .
- */
-import {Injectable} from '@angular/core';
-
-/**
- * MenuService provides bidirectional communication of context menu options and search queries
- */
-@Injectable()
-export class ScheduleService {}
diff --git a/src/app/util/internet-connection.service.ts b/src/app/util/internet-connection.service.ts
new file mode 100644
index 00000000..b07f08c6
--- /dev/null
+++ b/src/app/util/internet-connection.service.ts
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2023 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 .
+ */
+import {fromEvent, merge, ObservableInput, of, race, RetryConfig, share, Subject, takeUntil} from 'rxjs';
+import {Injectable} from '@angular/core';
+import {filter, map, startWith, take, tap} from 'rxjs/operators';
+import {NGXLogger} from 'ngx-logger';
+import {Router} from '@angular/router';
+
+@Injectable({
+ providedIn: 'root',
+})
+export class InternetConnectionService {
+ private readonly manualRetry$ = new Subject();
+
+ private readonly abortRetry$ = new Subject();
+
+ /**
+ * Emits whenever the browser goes online or offline.
+ */
+ readonly offline$ = window
+ ? merge(
+ fromEvent(window, 'online').pipe(map(() => false)),
+ fromEvent(window, 'offline').pipe(map(() => true)),
+ ).pipe(startWith(!window.navigator.onLine), share())
+ : of(true);
+
+ /**
+ * Emits whenever http requests should be retried
+ *
+ * Also keeps track of when a retry is needed, automatically
+ * registering itself.
+ */
+ readonly retryConfig: RetryConfig = {
+ delay: this.doRetry.bind(this),
+ };
+
+ private doRetry(error: unknown, retryCount: number): ObservableInput {
+ return race(
+ this.offline$.pipe(
+ tap(it => console.log(it)),
+ filter(it => !it),
+ take(1),
+ ),
+ this.manualRetry$,
+ ).pipe(
+ tap({
+ subscribe: () => {
+ this.errors.add(error);
+ if (this.errors.size > 0) {
+ this.error$.next(true);
+ }
+ },
+ next: () => {
+ this.logger.error(`${retryCount}x`, error);
+ },
+ unsubscribe: () => {
+ this.errors.delete(error);
+ if (this.errors.size === 0) {
+ this.error$.next(false);
+ }
+ },
+ }),
+ takeUntil(
+ merge(
+ this.abortRetry$.pipe(tap(() => this.logger.warn('HTTP Request retry aborted manually'))),
+ this.router.events.pipe(tap(() => this.logger.warn('HTTP Request retry aborted by routing'))),
+ ),
+ ),
+ );
+ }
+
+ /**
+ * Emits when there are errors
+ */
+ readonly error$ = new Subject();
+
+ private readonly errors = new Set();
+
+ constructor(private readonly logger: NGXLogger, private readonly router: Router) {}
+
+ /**
+ * Retry all failed http requests
+ */
+ retry() {
+ this.manualRetry$.next();
+ }
+
+ /**
+ * Abandon all failed http requests
+ */
+ dismissError() {
+ this.abortRetry$.next();
+ }
+}
diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json
index ae903634..724741af 100644
--- a/src/assets/i18n/de.json
+++ b/src/assets/i18n/de.json
@@ -27,7 +27,9 @@
},
"errors": {
"SERVICE": "Fehler bei Dienstausführung.",
- "UNKNOWN": "Unbekannter Fehler."
+ "UNKNOWN": "Unbekannter Fehler.",
+ "OFFLINE": "Keine Internetverbindung",
+ "CONNECTION_ERROR": "Verbindungsfehler"
}
},
"assessments": {
diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json
index def7fa4f..292e6953 100644
--- a/src/assets/i18n/en.json
+++ b/src/assets/i18n/en.json
@@ -27,7 +27,9 @@
},
"errors": {
"SERVICE": "Service error.",
- "UNKNOWN": "Unknown problem."
+ "UNKNOWN": "Unknown problem.",
+ "OFFLINE": "No internet connection",
+ "CONNECTION_ERROR": "Connection error"
}
},
"assessments": {
diff --git a/src/assets/icons.min.woff2 b/src/assets/icons.min.woff2
index 72a5e5d9..81dd2c19 100644
Binary files a/src/assets/icons.min.woff2 and b/src/assets/icons.min.woff2 differ