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

View File

@@ -26,15 +26,24 @@ ion-card {
--background: var(--ion-color-primary); --background: var(--ion-color-primary);
padding: 0 var(--spacing-md); padding: 0 var(--spacing-md);
ion-card-content { ion-card-header {
padding: var(--spacing-sm) 0 var(--header-spacing-bottom); padding: 0;
h1 { h1 {
color: var(--ion-color-primary-contrast); color: var(--ion-color-primary-contrast);
font-weight: var(--font-weight-bold); 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 * { .description * {
color: var(--ion-color-light); 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> <ion-label class="title">{{ 'name' | thingTranslate: item }}</ion-label>
<ng-container *ngIf="item.type !== 'floor'"> <ng-container *ngIf="item.type !== 'floor'">
<p class="title-sub" *ngIf="item.openingHours"> <p class="title-sub" *ngIf="item.openingHours">
{{ item.openingHours | openingHours }} <span>
<stapps-opening-hours
[openingHours]="item.openingHours"
></stapps-opening-hours>
</span>
</p> </p>
<p> <p>
<ion-note <ion-note

View File

@@ -126,7 +126,7 @@ export class OpeningHoursPipe implements PipeTransform, OnDestroy {
onLangChange?: Subscription; onLangChange?: Subscription;
value = ''; value: string[] = [];
constructor(private readonly translate: TranslateService) { constructor(private readonly translate: TranslateService) {
this.locale = translate.currentLang; this.locale = translate.currentLang;
@@ -142,7 +142,7 @@ export class OpeningHoursPipe implements PipeTransform, OnDestroy {
this._dispose(); this._dispose();
} }
transform(aString: string | unknown): string { transform(aString: string | unknown): string[] {
this.updateValue(aString); this.updateValue(aString);
this._dispose(); this._dispose();
if (this.onLangChange?.closed === true) { if (this.onLangChange?.closed === true) {
@@ -176,29 +176,87 @@ export class OpeningHoursPipe implements PipeTransform, OnDestroy {
}); });
} catch (error) { } catch (error) {
logger.warn(error); logger.warn(error);
this.value = ''; this.value = [];
return; return;
} }
const isOpen: boolean = openingHours.getState(); const isOpen: boolean = openingHours.getState();
const nextChange: Date = openingHours.getNextChange(); const isUnknown: boolean = openingHours.getUnknown();
let prefixKey = isOpen const nextChange: Date = openingHours.getNextChange();
? 'common.openingHours.open_until' const nextChangeIsOpen: boolean = openingHours.getState(nextChange);
: 'common.openingHours.closed_until'; 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(); let formattedCalender = moment(nextChange).calendar();
if (moment(nextChange).isBefore(moment().add(1, 'hours'))) { if (moment(nextChange).isBefore(moment().add(1, 'hours'))) {
prefixKey = isOpen this.value[0] = 'warning';
? 'common.openingHours.closing_soon' nextChangeKey = nextChangeIsOpen
: 'common.openingHours.opening_soon'; ? 'common.openingHours.opening_soon_warning'
formattedCalender = : 'common.openingHours.closing_soon_warning';
formattedCalender.slice(0, 1).toUpperCase() + this.value.push(
formattedCalender.slice(1); `${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 {IonicModule} from '@ionic/angular';
import {TranslateModule} from '@ngx-translate/core'; import {TranslateModule} from '@ngx-translate/core';
import {ElementSizeChangeDirective} from './element-size-change.directive'; import {ElementSizeChangeDirective} from './element-size-change.directive';
import {OpeningHoursComponent} from './opening-hours.component';
import {ThingTranslateModule} from '../translation/thing-translate.module';
@NgModule({ @NgModule({
imports: [BrowserModule, IonicModule, TranslateModule], imports: [
BrowserModule,
IonicModule,
TranslateModule,
ThingTranslateModule.forChild(),
],
declarations: [ declarations: [
ElementSizeChangeDirective, ElementSizeChangeDirective,
ArrayLastPipe, ArrayLastPipe,
@@ -38,6 +45,7 @@ import {ElementSizeChangeDirective} from './element-size-change.directive';
DaytimeKeyPipe, DaytimeKeyPipe,
NextDateInListPipe, NextDateInListPipe,
EditModalComponent, EditModalComponent,
OpeningHoursComponent,
], ],
exports: [ exports: [
ElementSizeChangeDirective, ElementSizeChangeDirective,
@@ -49,6 +57,7 @@ import {ElementSizeChangeDirective} from './element-size-change.directive';
DaytimeKeyPipe, DaytimeKeyPipe,
NextDateInListPipe, NextDateInListPipe,
EditModalComponent, EditModalComponent,
OpeningHoursComponent,
], ],
}) })
export class UtilModule {} export class UtilModule {}

View File

@@ -54,10 +54,15 @@
}, },
"common": { "common": {
"openingHours": { "openingHours": {
"closed_until": "Geschlossen bis", "closing": "Schließt {{relativeDateTime}}",
"closing_soon": "Schließt bald!", "closing_soon_warning": "Schließt bald! Um {{time}} Uhr",
"open_until": "Geöffnet bis", "closing_today": "Schließt um {{time}} Uhr",
"opening_soon": "Öffnet" "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": { "dashboard": {

View File

@@ -54,10 +54,15 @@
}, },
"common": { "common": {
"openingHours": { "openingHours": {
"closed_until": "Closed until", "closing": "Closing {{relativeDateTime}}",
"closing_soon": "Closing soon!", "closing_soon_warning": "Closing soon! At {{time}}",
"open_until": "Open until", "closing_today": "Closing at {{time}}",
"opening_soon": "Opens" "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": { "dashboard": {

View File

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