From bb8a9f6ba50d40951eb7c2c554aa53dc88ac5ec0 Mon Sep 17 00:00:00 2001 From: Rainer Killinger Date: Tue, 3 Aug 2021 15:02:59 +0200 Subject: [PATCH] refactor: add opening hours --- package-lock.json | 43 ++++++++++ package.json | 1 + src/app/app.module.ts | 9 +-- .../data/detail/data-detail-content.html | 53 ++++++++----- .../date-series/date-series-list-item.html | 2 +- .../data/types/place/place-list-item.html | 32 ++++++-- .../mensa/place-mensa-detail.component.ts | 2 +- src/app/translation/common-string-pipes.ts | 78 +++++++++++++++++++ src/app/translation/thing-translate.module.ts | 4 +- src/assets/i18n/de.json | 8 ++ src/assets/i18n/en.json | 8 ++ 11 files changed, 204 insertions(+), 36 deletions(-) diff --git a/package-lock.json b/package-lock.json index f1719f05..6aa40f76 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11310,6 +11310,24 @@ "@babel/runtime": "^7.3.1" } }, + "i18next-browser-languagedetector": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-6.1.2.tgz", + "integrity": "sha512-YDzIGHhMRvr7M+c8B3EQUKyiMBhfqox4o1qkFvt4QXuu5V2cxf74+NCr+VEkUuU0y+RwcupA238eeolW1Yn80g==", + "requires": { + "@babel/runtime": "^7.14.6" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.14.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.6.tgz", + "integrity": "sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + } + } + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -14533,6 +14551,26 @@ "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", "dev": true }, + "opening_hours": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/opening_hours/-/opening_hours-3.6.0.tgz", + "integrity": "sha512-ETHEchqvpZxJiLznNSdYHiGyeIMikJVfYEjMjYe0oRAxcQejilyXWWGjJBcIOXLwgU6LaATeFb6LRTgEguz0yw==", + "requires": { + "i18next": "^20.2.1", + "i18next-browser-languagedetector": "^6.1.0", + "suncalc": "^1.8.0" + }, + "dependencies": { + "i18next": { + "version": "20.3.2", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-20.3.2.tgz", + "integrity": "sha512-e8CML2R9Ng2sSQOM80wb/PrM2j8mDm84o/T4Amzn9ArVyNX5/ENWxxAXkRpZdTQNDaxKImF93Wep4mAoozFrKw==", + "requires": { + "@babel/runtime": "^7.12.0" + } + } + } + }, "opn": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", @@ -18613,6 +18651,11 @@ } } }, + "suncalc": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/suncalc/-/suncalc-1.8.0.tgz", + "integrity": "sha1-HZiYEJVjB4dQ9JlKlZ5lTYdqy/U=" + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", diff --git a/package.json b/package.json index a3cc0ad3..688a0aee 100644 --- a/package.json +++ b/package.json @@ -89,6 +89,7 @@ "ngx-logger": "4.1.9", "ngx-markdown": "9.1.1", "ngx-moment": "5.0.0", + "opening_hours": "3.6.0", "rxjs": "6.6.3", "tslib": "1.14.1", "zone.js": "0.11.2" diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 24e6b13e..64f20a7a 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -12,12 +12,7 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ -import { - CommonModule, - HashLocationStrategy, - LocationStrategy, - registerLocaleData, -} from '@angular/common'; +import {CommonModule, LocationStrategy, PathLocationStrategy, registerLocaleData} from '@angular/common'; import {HttpClient} from '@angular/common/http'; import localeDe from '@angular/common/locales/de'; import {APP_INITIALIZER, NgModule, Provider} from '@angular/core'; @@ -116,7 +111,7 @@ const providers: Provider[] = [ }, { provide: LocationStrategy, - useClass: HashLocationStrategy, + useClass: PathLocationStrategy, }, { provide: APP_INITIALIZER, diff --git a/src/app/modules/data/detail/data-detail-content.html b/src/app/modules/data/detail/data-detail-content.html index 39210555..62e427ef 100644 --- a/src/app/modules/data/detail/data-detail-content.html +++ b/src/app/modules/data/detail/data-detail-content.html @@ -1,19 +1,36 @@ - -
- - - - - - - - - - - - - - - - +
+ + + + + + + + + + + + + + + + + + + + + + + +
+

{{item.name}}

+ {{item.type}} +
+
+
+
+
+ +
+ diff --git a/src/app/modules/data/types/date-series/date-series-list-item.html b/src/app/modules/data/types/date-series/date-series-list-item.html index 2514889d..3c29b41a 100644 --- a/src/app/modules/data/types/date-series/date-series-list-item.html +++ b/src/app/modules/data/types/date-series/date-series-list-item.html @@ -5,7 +5,7 @@

{{ 'name' | thingTranslate: item }}

- + {{ item.repeatFrequency | amDuration }}, {{ item.dates[0] | dateFormat: 'weekday:long' }} diff --git a/src/app/modules/data/types/place/place-list-item.html b/src/app/modules/data/types/place/place-list-item.html index 7b9e7af1..2131cf74 100644 --- a/src/app/modules/data/types/place/place-list-item.html +++ b/src/app/modules/data/types/place/place-list-item.html @@ -2,9 +2,26 @@

-

{{ 'name' | thingTranslate: item }}

+ {{'name' | thingTranslate: item}} + +

+ + {{item.openingHours | openingHours}} + +

+

+ + {{'categories' | thingTranslate: item | join:', ' | titlecase }} + +

+ + + {{'type' | thingTranslate: item}} + + +

- {{ 'description' | thingTranslate: item }} + {{'description' | thingTranslate: item}}

    @@ -17,11 +34,10 @@
- - - {{ 'name' | thingTranslate: item.inPlace }} - - +
+ + {{'name' | thingTranslate: item.inPlace}} + +
diff --git a/src/app/modules/data/types/place/special/mensa/place-mensa-detail.component.ts b/src/app/modules/data/types/place/special/mensa/place-mensa-detail.component.ts index 8f2f1ed0..8200a291 100644 --- a/src/app/modules/data/types/place/special/mensa/place-mensa-detail.component.ts +++ b/src/app/modules/data/types/place/special/mensa/place-mensa-detail.component.ts @@ -39,7 +39,7 @@ export class PlaceMensaDetailComponent implements AfterViewInit { /** * number of days to display mensa menus for */ - @Input() displayRange = 5; + @Input() displayRange = 7; /** * TODO diff --git a/src/app/translation/common-string-pipes.ts b/src/app/translation/common-string-pipes.ts index 1787b362..3c736226 100644 --- a/src/app/translation/common-string-pipes.ts +++ b/src/app/translation/common-string-pipes.ts @@ -15,9 +15,15 @@ import {Injectable, OnDestroy, Pipe, PipeTransform} from '@angular/core'; import {LangChangeEvent, TranslateService} from '@ngx-translate/core'; +import moment from 'moment'; import {Subscription} from 'rxjs'; import {logger} from '../_helpers/ts-logger'; +// tslint:disable-next-line: no-var-requires +const openingHoursFn = require('opening_hours'); + +// tslint:disable: completed-docs + @Injectable() @Pipe({ name: 'join', @@ -89,6 +95,78 @@ export class StringSplitPipe implements PipeTransform { } } +@Injectable() +@Pipe({ + name: 'openingHours', + pure: false, // required to update the value when the promise is resolved +}) +export class OpeningHoursPipe implements PipeTransform { + locale: string; + onLangChange?: Subscription; + value = ''; + + constructor(private readonly translate: TranslateService) { + this.locale = translate.currentLang; + } + + private _dispose(): void { + if (this.onLangChange?.closed === false) { + this.onLangChange?.unsubscribe(); + } + } + + + transform(aString: string | unknown): string { + this.updateValue(aString); + this._dispose(); + if (this.onLangChange?.closed === true) { + this.onLangChange = this.translate.onLangChange.subscribe((event: LangChangeEvent) => { + this.locale = event.lang; + this.updateValue(aString); + }); + } + + return this.value; + } + + updateValue(aString: string | unknown) { + if (typeof aString !== 'string'){ + logger.warn(`openingHours pipe unable to parse input: ${aString}`); + + return; + } + const openingHours = new openingHoursFn(aString); + + if ((openingHours.getWarnings() as string[]).length > 0){ + logger.warn((openingHours.getWarnings() as string[]).join('. ')); + + return; + } + + const isOpen: boolean = openingHours.getState(); + const nextChange: Date = openingHours.getNextChange(); + + let prefixKey = isOpen ? + 'common.openingHours.open_until' : + 'common.openingHours.closed_until'; + + let formattedCalender = moment(nextChange) + .calendar(); + + if (moment(nextChange) + .isBefore(moment() + .add(1, 'hours'))) { + prefixKey= isOpen ? + 'common.openingHours.closing_soon' : + 'common.openingHours.opening_soon'; + formattedCalender = formattedCalender.substr(0,1) + .toUpperCase() + formattedCalender.substr(1); + } + this.value = `${this.translate.instant(prefixKey)} ${formattedCalender}`; + } +} + + @Injectable() @Pipe({ name: 'numberLocalized', diff --git a/src/app/translation/thing-translate.module.ts b/src/app/translation/thing-translate.module.ts index 3434fe47..bb8b72b1 100644 --- a/src/app/translation/thing-translate.module.ts +++ b/src/app/translation/thing-translate.module.ts @@ -14,7 +14,7 @@ */ import {ModuleWithProviders, NgModule, Provider} from '@angular/core'; -import {ArrayJoinPipe, DateLocalizedFormatPipe, NumberLocalizedPipe, SentenceCasePipe, StringSplitPipe} from './common-string-pipes'; +import {ArrayJoinPipe, DateLocalizedFormatPipe, NumberLocalizedPipe, SentenceCasePipe, StringSplitPipe, OpeningHoursPipe} from './common-string-pipes'; import {ThingTranslateDefaultParser, ThingTranslateParser} from './thing-translate.parser'; import {ThingPropertyNameTranslatePipe, ThingTranslatePipe} from './thing-translate.pipe'; import {ThingTranslateService} from './thing-translate.service'; @@ -31,6 +31,7 @@ export interface ThingTranslateModuleConfig { ThingPropertyNameTranslatePipe, ThingTranslatePipe, DateLocalizedFormatPipe, + OpeningHoursPipe, SentenceCasePipe, ], exports: [ @@ -40,6 +41,7 @@ export interface ThingTranslateModuleConfig { ThingPropertyNameTranslatePipe, ThingTranslatePipe, DateLocalizedFormatPipe, + OpeningHoursPipe, SentenceCasePipe, ], }) diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json index b2bcc5f5..96b5598e 100644 --- a/src/assets/i18n/de.json +++ b/src/assets/i18n/de.json @@ -9,6 +9,14 @@ "UNKNOWN": "Unbekannter Fehler" } }, + "common": { + "openingHours": { + "closed_until": "Geschlossen bis", + "closing_soon": "Schließt bald!", + "open_until": "Geöffnet bis", + "opening_soon": "Öffnet" + } + }, "data": { "REFRESH_ACTION": "Aktualisieren", "REFRESHING": "Aktualisierung läuft...", diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 320c2a06..6d7c86ba 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -9,6 +9,14 @@ "UNKNOWN": "Unknown problem" } }, + "common": { + "openingHours": { + "closed_until": "Closed until", + "closing_soon": "Closing soon!", + "open_until": "Open until", + "opening_soon": "Opens" + } + }, "data": { "REFRESH_ACTION": "Refresh", "REFRESHING": "Refreshing...",