refactor: display of opening hours

This commit is contained in:
Rainer Killinger
2022-11-04 14:25:32 +01:00
parent e504d8cf6d
commit 3ede650cc5
10 changed files with 198 additions and 34 deletions

View File

@@ -13,8 +13,8 @@
~ this program. If not, see <https://www.gnu.org/licenses/>.
-->
<ion-card>
<ion-card-content>
<ion-text color="dark">
<ion-card-header>
<ion-card-title>
<h1>
<ng-container *ngIf="$any(item).honorificPrefix">{{
'honorificPrefix' | thingTranslate: item
@@ -24,9 +24,15 @@
'honorificSuffix' | thingTranslate: item
}}</ng-container>
</h1>
</ion-text>
</ion-card-title>
</ion-card-header>
<ion-card-content>
<div *ngIf="$any(item).openingHours" class="openingHours">
<stapps-opening-hours
[openingHours]="item.openingHours"
></stapps-opening-hours>
</div>
<div *ngIf="item.description" class="description">
<br />
<div
class="text-accordion"
[style.-webkit-line-clamp]="descriptionLinesToDisplay"

View File

@@ -26,15 +26,24 @@ ion-card {
--background: var(--ion-color-primary);
padding: 0 var(--spacing-md);
ion-card-content {
padding: var(--spacing-sm) 0 var(--header-spacing-bottom);
ion-card-header {
padding: 0;
h1 {
color: var(--ion-color-primary-contrast);
font-weight: var(--font-weight-bold);
margin: var(--spacing-sm) 0 var(--spacing-sm) 0;
}
}
ion-card-content {
padding: 0 0 var(--header-spacing-bottom);
.description * {
color: var(--ion-color-light);
}
.openingHours {
color: var(--ion-color-light);
}
}
}

View File

@@ -20,7 +20,11 @@
<ion-label class="title">{{ 'name' | thingTranslate: item }}</ion-label>
<ng-container *ngIf="item.type !== 'floor'">
<p class="title-sub" *ngIf="item.openingHours">
{{ item.openingHours | openingHours }}
<span>
<stapps-opening-hours
[openingHours]="item.openingHours"
></stapps-opening-hours>
</span>
</p>
<p>
<ion-note

View File

@@ -126,7 +126,7 @@ export class OpeningHoursPipe implements PipeTransform, OnDestroy {
onLangChange?: Subscription;
value = '';
value: string[] = [];
constructor(private readonly translate: TranslateService) {
this.locale = translate.currentLang;
@@ -142,7 +142,7 @@ export class OpeningHoursPipe implements PipeTransform, OnDestroy {
this._dispose();
}
transform(aString: string | unknown): string {
transform(aString: string | unknown): string[] {
this.updateValue(aString);
this._dispose();
if (this.onLangChange?.closed === true) {
@@ -176,29 +176,87 @@ export class OpeningHoursPipe implements PipeTransform, OnDestroy {
});
} catch (error) {
logger.warn(error);
this.value = '';
this.value = [];
return;
}
const isOpen: boolean = openingHours.getState();
const nextChange: Date = openingHours.getNextChange();
const isUnknown: boolean = openingHours.getUnknown();
let prefixKey = isOpen
? 'common.openingHours.open_until'
: 'common.openingHours.closed_until';
const nextChange: Date = openingHours.getNextChange();
const nextChangeIsOpen: boolean = openingHours.getState(nextChange);
const nextChangeUnknown: boolean = openingHours.getUnknown(nextChange);
const nextChangeIsToday: boolean = moment().isSame(nextChange, 'day');
let stateKey = isOpen
? 'common.openingHours.state_open'
: 'common.openingHours.state_closed';
stateKey = isUnknown ? 'common.openingHours.state_maybe' : stateKey;
this.value = [
isOpen ? 'success' : 'danger',
`${this.translate.instant(stateKey)}`,
];
if (isUnknown) {
const comment = openingHours.getComment();
this.value = ['light', `${this.translate.instant(stateKey)}`];
if (typeof comment === 'string') {
this.value.push(comment);
}
return;
}
if (nextChangeUnknown) {
return;
}
let nextChangeKey: string | undefined;
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.slice(0, 1).toUpperCase() +
formattedCalender.slice(1);
this.value[0] = 'warning';
nextChangeKey = nextChangeIsOpen
? 'common.openingHours.opening_soon_warning'
: 'common.openingHours.closing_soon_warning';
this.value.push(
`${this.translate.instant(nextChangeKey, {
time: new Intl.DateTimeFormat(this.locale, {
timeStyle: 'short',
}).format(nextChange),
})}`,
);
return;
}
this.value = `${this.translate.instant(prefixKey)} ${formattedCalender}`;
if (nextChangeIsToday) {
nextChangeKey = nextChangeIsOpen
? 'common.openingHours.opening_today'
: 'common.openingHours.closing_today';
this.value.push(
`${this.translate.instant(nextChangeKey, {
time: new Intl.DateTimeFormat(this.locale, {
timeStyle: 'short',
}).format(nextChange),
})}`,
);
return;
}
nextChangeKey = nextChangeIsOpen
? 'common.openingHours.opening'
: 'common.openingHours.closing';
formattedCalender =
formattedCalender.slice(0, 1).toUpperCase() + formattedCalender.slice(1);
this.value.push(
`${this.translate.instant(nextChangeKey, {
relativeDateTime: formattedCalender,
})}`,
);
return;
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2022 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, ContentChild, Input, TemplateRef} from '@angular/core';
@Component({
selector: 'stapps-opening-hours',
templateUrl: 'opening-hours.html',
})
export class OpeningHoursComponent {
@ContentChild(TemplateRef) content: TemplateRef<unknown>;
@Input() openingHours?: string;
@Input() colorize = true;
@Input() showNextChange = true;
}

View File

@@ -0,0 +1,34 @@
<!--
~ Copyright (C) 2022 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/>.
-->
<ng-container *ngIf="openingHours">
<div>
<ng-template [ngIf]="colorize" [ngIfElse]="blank">
<ion-badge
[color]="openingHours | openingHours | slice: 0:1 | join: ' '"
slot="start"
style="vertical-align: bottom"
>
{{ openingHours | openingHours | slice: 1:2 }}
</ion-badge>
</ng-template>
<ng-template #blank>
{{ openingHours | openingHours | slice: 1:2 }}
</ng-template>
<ng-container *ngIf="showNextChange">
{{ openingHours | openingHours | slice: 2:3 }}
</ng-container>
</div>
</ng-container>

View File

@@ -25,9 +25,16 @@ import {BrowserModule} from '@angular/platform-browser';
import {IonicModule} from '@ionic/angular';
import {TranslateModule} from '@ngx-translate/core';
import {ElementSizeChangeDirective} from './element-size-change.directive';
import {OpeningHoursComponent} from './opening-hours.component';
import {ThingTranslateModule} from '../translation/thing-translate.module';
@NgModule({
imports: [BrowserModule, IonicModule, TranslateModule],
imports: [
BrowserModule,
IonicModule,
TranslateModule,
ThingTranslateModule.forChild(),
],
declarations: [
ElementSizeChangeDirective,
ArrayLastPipe,
@@ -38,6 +45,7 @@ import {ElementSizeChangeDirective} from './element-size-change.directive';
DaytimeKeyPipe,
NextDateInListPipe,
EditModalComponent,
OpeningHoursComponent,
],
exports: [
ElementSizeChangeDirective,
@@ -49,6 +57,7 @@ import {ElementSizeChangeDirective} from './element-size-change.directive';
DaytimeKeyPipe,
NextDateInListPipe,
EditModalComponent,
OpeningHoursComponent,
],
})
export class UtilModule {}

View File

@@ -54,10 +54,15 @@
},
"common": {
"openingHours": {
"closed_until": "Geschlossen bis",
"closing_soon": "Schließt bald!",
"open_until": "Geöffnet bis",
"opening_soon": "Öffnet"
"closing": "Schließt {{relativeDateTime}}",
"closing_soon_warning": "Schließt bald! Um {{time}} Uhr",
"closing_today": "Schließt um {{time}} Uhr",
"state_closed": "Geschlossen",
"state_maybe": "Vielleicht Geöffnet",
"state_open": "Geöffnet",
"opening": "Öffnet {{relativeDateTime}}",
"opening_today": "Öffnet um {{time}} Uhr",
"opening_soon_warning": "Öffnet bald! Um {{time}} Uhr"
}
},
"dashboard": {

View File

@@ -54,10 +54,15 @@
},
"common": {
"openingHours": {
"closed_until": "Closed until",
"closing_soon": "Closing soon!",
"open_until": "Open until",
"opening_soon": "Opens"
"closing": "Closing {{relativeDateTime}}",
"closing_soon_warning": "Closing soon! At {{time}}",
"closing_today": "Closing at {{time}}",
"state_closed": "Closed",
"state_maybe": "Maybe open",
"state_open": "Open",
"opening": "Opens {{relativeDateTime}}",
"opening_today": "Opens at {{time}}",
"opening_soon_warning": "Opens soon! At {{time}}"
}
},
"dashboard": {

View File

@@ -1,14 +1,18 @@
body app-root {
.title,
.title-sub,
.title[class*='sc-ion-label'],
.title-sub[class*='sc-ion-label'] {
.title[class*='sc-ion-label'] {
font-size: var(--font-size-md);
font-weight: var(--font-weight-semi-bold);
// TODO Condensed Font
}
.title-sub,
.title-sub[class*='sc-ion-label'] {
font-size: var(--font-size-md);
font-weight: var(--font-weight-regular);
// TODO Condensed Font
}
.title-sub {
color: var(--ion-color-primary);
color: var(--ion-color-text);
}
}