added pwa + dienstreise support

This commit is contained in:
2024-08-30 22:16:31 +02:00
parent 53eb287b0a
commit 70e3818170
13 changed files with 128 additions and 22 deletions

View File

@@ -6,7 +6,7 @@
</ion-toolbar>
</ion-header>
<ion-content [fullscreen]="true" [scrollY]="false">
<ion-content [fullscreen]="true">
<ion-header collapse="condense">
<ion-toolbar>
<ion-title size="large">Zeiterfassung</ion-title>
@@ -27,7 +27,7 @@
<section class="time-entries">
<ion-item class="entry" *ngFor="let entry of getEntriesOfToday(); let index = index" (click)="removeEntry(index)" [ngClass]="{'animate': shouldAnimate[index]}">
<div class="circle"></div>
<ion-label class="type">{{entry.type === 'login' ? "Eingestempelt" : "Ausgestempelt"}}</ion-label>
<ion-label class="type">{{getTypeText(entry.type)}}</ion-label>
<span class="time">{{entry.registeredAt.toLocaleTimeString()}}</span>
<span *ngIf="index !== 0" class="between">
<span class="between-content">{{generateSeparatorText(data[index - 1], entry)}}</span>
@@ -37,7 +37,7 @@
<div class="button-container">
<ion-button (click)="addEntry()">{{currentAction === 'login' ? "Einstempeln" : "Ausstempeln"}}</ion-button>
<ion-button shape="round" id="open-modal">
<ion-button shape="round" id="open-modal" class="icon-button">
<ion-icon slot="icon-only" name="add"></ion-icon>
</ion-button>
</div>
@@ -70,6 +70,8 @@
<ion-select label="Stempeltyp" value="login" [(ngModel)]="modalMode">
<ion-select-option value="login">Einstempeln</ion-select-option>
<ion-select-option value="logout">Ausstempeln</ion-select-option>
<ion-select-option value="start-drive">Dienstreise starten</ion-select-option>
<ion-select-option value="end-drive">Dienstreise beenden</ion-select-option>
</ion-select>
</ion-item>
</ion-content>

View File

@@ -1,6 +1,6 @@
.button-container {
position: absolute;
bottom: 75px;
position: fixed;
bottom: 25px;
left: 0;
right: 0;
display: flex;
@@ -13,6 +13,7 @@
flex-direction: column;
gap: 65px;
margin: 20px;
padding-bottom: 75px;
.entry {
--inner-border-width: 0 0 0 0;

View File

@@ -57,23 +57,45 @@ export class TimePage {
return this.data.filter(entry => entry.registeredAt.getDay() === today);
}
public getTypeText(type: TimeType): string {
switch (type) {
case "login":
return "Eingestempelt";
case "logout":
return "Ausgestempelt";
case "start-drive":
return "Dienstreise gestartet";
case "end-drive":
return "Dienstreise beendet";
}
}
public generateSeparatorText(entry1: TimeEntry, entry2: TimeEntry): string {
const difference = +entry2.registeredAt.getTime() - +entry1.registeredAt.getTime() - 3600000;
const date = new Date(difference);
const text = entry1.type === 'login' ? "Arbeit " : "Pause ";
let text = entry1.type === 'login' ? "Arbeit " : "Pause ";
if (entry1.type === 'start-drive' && entry2.type === 'end-drive') {
text = "Dienstreise";
}
return text + `(${date.toLocaleTimeString()})`;
}
public addEntry(): void {
const animateIndex = this.shouldAnimate.length;
this.shouldAnimate.push(true)
setTimeout(() => this.shouldAnimate[this.shouldAnimate.length - 1] = false, 5000);
setTimeout(() => this.shouldAnimate[animateIndex] = false, 2000);
this.data.push({
registeredAt: new Date(Date.now()),
type: this.currentAction
});
this.saveData();
this.currentAction = this.currentAction === 'login' ? 'logout' : 'login';
this.updateCurrentAction();
}
public removeEntry(index: number): void {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 930 B

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -35,3 +35,7 @@
/* @import "@ionic/angular/css/palettes/dark.always.css"; */
/* @import "@ionic/angular/css/palettes/dark.class.css"; */
@import '@ionic/angular/css/palettes/dark.system.css';
.ios .icon-button {
width: 50px;
}

View File

@@ -2,25 +2,28 @@
<html lang="en">
<head>
<meta charset="utf-8" />
<meta charset="utf-8"/>
<title>Zeiterfassung</title>
<base href="/" />
<base href="/"/>
<meta name="color-scheme" content="light dark" />
<meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta name="format-detection" content="telephone=no" />
<meta name="msapplication-tap-highlight" content="no" />
<meta name="color-scheme" content="light dark"/>
<meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
<meta name="format-detection" content="telephone=no"/>
<meta name="msapplication-tap-highlight" content="no"/>
<link rel="icon" type="image/png" href="assets/icon/favicon.png" />
<link rel="icon" type="image/png" href="assets/icon/favicon.png"/>
<!-- add to homescreen for ios -->
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta name="apple-mobile-web-app-status-bar-style" content="black"/>
<link rel="manifest" href="manifest.webmanifest">
<meta name="theme-color" content="#1976d2">
</head>
<body>
<app-root></app-root>
<noscript>Please enable JavaScript to continue using this application.</noscript>
</body>
</html>

View File

@@ -4,11 +4,16 @@ import { IonicRouteStrategy, provideIonicAngular } from '@ionic/angular/standalo
import { routes } from './app/app.routes';
import { AppComponent } from './app/app.component';
import { isDevMode } from '@angular/core';
import { provideServiceWorker } from '@angular/service-worker';
bootstrapApplication(AppComponent, {
providers: [
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
provideIonicAngular(),
provideRouter(routes, withPreloading(PreloadAllModules)),
provideRouter(routes, withPreloading(PreloadAllModules)), provideServiceWorker('ngsw-worker.js', {
enabled: !isDevMode(),
registrationStrategy: 'registerWhenStable:30000'
}),
],
});

17
src/manifest.webmanifest Normal file
View File

@@ -0,0 +1,17 @@
{
"name": "Zeiterfassung",
"short_name": "Zeiterfassung",
"theme_color": "#121212",
"background_color": "#121212",
"display": "standalone",
"scope": "./",
"start_url": "./",
"icons": [
{
"src": "assets/icon/favicon.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable any"
}
]
}

View File

@@ -3,4 +3,4 @@ export interface TimeEntry {
type: TimeType;
}
export type TimeType = 'login' | 'logout';
export type TimeType = 'login' | 'logout' | 'start-drive' | 'end-drive';