forked from Kispi/Core
feat(webapp): support old iPadOS version
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
7089d0397f
commit
dc3c065d1a
12 changed files with 150 additions and 24 deletions
|
@ -2,7 +2,7 @@
|
||||||
"name": "hgoe-sas",
|
"name": "hgoe-sas",
|
||||||
"private": true,
|
"private": true,
|
||||||
"author": "Simon Giesel",
|
"author": "Simon Giesel",
|
||||||
"version": "1.0.0",
|
"version": "1.1.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vue-tsc --noEmit && vite build",
|
"build": "vue-tsc --noEmit && vite build",
|
||||||
|
@ -17,6 +17,7 @@
|
||||||
"@vueuse/core": "^10.2.1",
|
"@vueuse/core": "^10.2.1",
|
||||||
"canvas-confetti": "^1.6.0",
|
"canvas-confetti": "^1.6.0",
|
||||||
"daisyui": "^3.2.1",
|
"daisyui": "^3.2.1",
|
||||||
|
"date-fns": "^2.30.0",
|
||||||
"pocketbase": "^0.15.3",
|
"pocketbase": "^0.15.3",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
"vue-router": "4.2.4"
|
"vue-router": "4.2.4"
|
||||||
|
|
|
@ -17,6 +17,9 @@ dependencies:
|
||||||
daisyui:
|
daisyui:
|
||||||
specifier: ^3.2.1
|
specifier: ^3.2.1
|
||||||
version: 3.2.1
|
version: 3.2.1
|
||||||
|
date-fns:
|
||||||
|
specifier: ^2.30.0
|
||||||
|
version: 2.30.0
|
||||||
pocketbase:
|
pocketbase:
|
||||||
specifier: ^0.15.3
|
specifier: ^0.15.3
|
||||||
version: 0.15.3
|
version: 0.15.3
|
||||||
|
@ -111,6 +114,13 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/types': 7.18.8
|
'@babel/types': 7.18.8
|
||||||
|
|
||||||
|
/@babel/runtime@7.22.6:
|
||||||
|
resolution: {integrity: sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ==}
|
||||||
|
engines: {node: '>=6.9.0'}
|
||||||
|
dependencies:
|
||||||
|
regenerator-runtime: 0.13.11
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@babel/types@7.18.8:
|
/@babel/types@7.18.8:
|
||||||
resolution: {integrity: sha512-qwpdsmraq0aJ3osLJRApsc2ouSJCdnMeZwB0DhbtHAtRpZNZCdlbRnHIgcRKzdE1g0iOGg644fzjOBcdOz9cPw==}
|
resolution: {integrity: sha512-qwpdsmraq0aJ3osLJRApsc2ouSJCdnMeZwB0DhbtHAtRpZNZCdlbRnHIgcRKzdE1g0iOGg644fzjOBcdOz9cPw==}
|
||||||
engines: {node: '>=6.9.0'}
|
engines: {node: '>=6.9.0'}
|
||||||
|
@ -1216,6 +1226,13 @@ packages:
|
||||||
- ts-node
|
- ts-node
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/date-fns@2.30.0:
|
||||||
|
resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==}
|
||||||
|
engines: {node: '>=0.11'}
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.22.6
|
||||||
|
dev: false
|
||||||
|
|
||||||
/de-indent@1.0.2:
|
/de-indent@1.0.2:
|
||||||
resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
|
resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -2526,6 +2543,10 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
picomatch: 2.3.1
|
picomatch: 2.3.1
|
||||||
|
|
||||||
|
/regenerator-runtime@0.13.11:
|
||||||
|
resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/resolve-from@4.0.0:
|
/resolve-from@4.0.0:
|
||||||
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
|
92
webapp/src/components/atoms/AtomLegacyModal.vue
Normal file
92
webapp/src/components/atoms/AtomLegacyModal.vue
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
<template>
|
||||||
|
<Teleport to="body">
|
||||||
|
<input
|
||||||
|
:id="id"
|
||||||
|
type="checkbox"
|
||||||
|
class="modal-toggle"
|
||||||
|
@change="($event.target as HTMLInputElement).checked ? $emit('close') : null"
|
||||||
|
/>
|
||||||
|
<div class="modal">
|
||||||
|
<form
|
||||||
|
method="dialog"
|
||||||
|
class="modal-box"
|
||||||
|
:class="{
|
||||||
|
'bg-base-300': darker,
|
||||||
|
'w-auto': wAuto,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
v-if="closeButton"
|
||||||
|
class="btn-ghost btn-sm btn-circle btn absolute right-2 top-2"
|
||||||
|
>
|
||||||
|
✕
|
||||||
|
</button>
|
||||||
|
<h3
|
||||||
|
v-if="title"
|
||||||
|
class="text-lg font-bold"
|
||||||
|
>
|
||||||
|
{{ title }}
|
||||||
|
</h3>
|
||||||
|
<p class="py-4"><slot /></p>
|
||||||
|
<div class="modal-action">
|
||||||
|
<slot name="action" />
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<form
|
||||||
|
method="dialog"
|
||||||
|
class="modal-backdrop"
|
||||||
|
>
|
||||||
|
<button>close</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</Teleport>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
const props = defineProps({
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
darker: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
closeButton: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
wAuto: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
function show(): void {
|
||||||
|
(document.getElementById(props.id) as HTMLInputElement).checked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function close(): void {
|
||||||
|
(document.getElementById(props.id) as HTMLInputElement).checked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isOpen(): boolean {
|
||||||
|
return (document.getElementById(props.id) as HTMLInputElement).checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
defineEmits(['close']);
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
show,
|
||||||
|
close,
|
||||||
|
isOpen,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
</style>
|
|
@ -30,7 +30,7 @@
|
||||||
{{ DateService.toShortString(entry[header.key]) }}
|
{{ DateService.toShortString(entry[header.key]) }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else-if="header.type === TableHeaderType.DATETIME">
|
<span v-else-if="header.type === TableHeaderType.DATETIME">
|
||||||
{{ entry[header.key] ? DateService.toString(new Date(entry[header.key])): 'N/A' }}
|
{{ entry[header.key] ? DateService.toString(parseISO(entry[header.key])): 'N/A' }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else-if="header.type === TableHeaderType.CURRENCY">
|
<span v-else-if="header.type === TableHeaderType.CURRENCY">
|
||||||
{{ CurrencyService.toString(entry[header.key]) }}
|
{{ CurrencyService.toString(entry[header.key]) }}
|
||||||
|
@ -104,6 +104,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { PropType, onMounted, ref } from 'vue';
|
import { PropType, onMounted, ref } from 'vue';
|
||||||
|
import { parseISO } from 'date-fns';
|
||||||
import { SettingsResponse } from '../../types/pocketbase.types';
|
import { SettingsResponse } from '../../types/pocketbase.types';
|
||||||
import { DateService } from '../../services/date.service';
|
import { DateService } from '../../services/date.service';
|
||||||
import { CurrencyService } from '../../services/currency.service';
|
import { CurrencyService } from '../../services/currency.service';
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { ArrowRightOnRectangleIcon, XCircleIcon } from '@heroicons/vue/24/outline';
|
import { ArrowRightOnRectangleIcon, XCircleIcon } from '@heroicons/vue/24/outline';
|
||||||
import AtomModal from '../atoms/AtomModal.vue';
|
import AtomModal from '../atoms/AtomLegacyModal.vue';
|
||||||
import AtomInput from '../atoms/AtomInput.vue';
|
import AtomInput from '../atoms/AtomInput.vue';
|
||||||
|
|
||||||
const modal = ref<InstanceType<typeof AtomModal>>();
|
const modal = ref<InstanceType<typeof AtomModal>>();
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<div>
|
<div>
|
||||||
<div class="font-bold">{{ transaction.label }}</div>
|
<div class="font-bold">{{ transaction.label }}</div>
|
||||||
<div>{{ DateService.toString(new Date(transaction.created)) }}</div>
|
<div>{{ DateService.toString(parseISO(transaction.created)) }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
@ -35,6 +35,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { PropType } from 'vue';
|
import { PropType } from 'vue';
|
||||||
|
import { parseISO } from 'date-fns';
|
||||||
import { CurrencyService } from '../../services/currency.service';
|
import { CurrencyService } from '../../services/currency.service';
|
||||||
import { DateService } from '../../services/date.service';
|
import { DateService } from '../../services/date.service';
|
||||||
import { TransactionsResponse } from '../../types/pocketbase.types';
|
import { TransactionsResponse } from '../../types/pocketbase.types';
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn gap-2"
|
class="btn gap-2"
|
||||||
@click="$emit('confirm')"
|
@click.prevent="$emit('confirm')"
|
||||||
>
|
>
|
||||||
<CheckCircleIcon class="h-6 w-6" />
|
<CheckCircleIcon class="h-6 w-6" />
|
||||||
Bestätigen
|
Bestätigen
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { CheckCircleIcon, XCircleIcon } from '@heroicons/vue/24/outline';
|
import { CheckCircleIcon, XCircleIcon } from '@heroicons/vue/24/outline';
|
||||||
import AtomModal from '../atoms/AtomModal.vue';
|
import AtomModal from '../atoms/AtomLegacyModal.vue';
|
||||||
|
|
||||||
const modal = ref<InstanceType<typeof AtomModal>>();
|
const modal = ref<InstanceType<typeof AtomModal>>();
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { onKeyStroke, promiseTimeout } from '@vueuse/core';
|
import { onKeyStroke, promiseTimeout } from '@vueuse/core';
|
||||||
|
import { parseISO } from 'date-fns';
|
||||||
import { AccountService } from '../../services/account.service';
|
import { AccountService } from '../../services/account.service';
|
||||||
import { DateService } from '../../services/date.service';
|
import { DateService } from '../../services/date.service';
|
||||||
import { XCircleIcon } from '@heroicons/vue/24/outline';
|
import { XCircleIcon } from '@heroicons/vue/24/outline';
|
||||||
|
@ -31,7 +32,7 @@ onKeyStroke(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'Enter'], async (
|
||||||
try {
|
try {
|
||||||
const account = await AccountService.checkIn(accountId.value);
|
const account = await AccountService.checkIn(accountId.value);
|
||||||
accountId.value = '';
|
accountId.value = '';
|
||||||
message.value = `${account.firstName} ${account.lastName} um ${DateService.toTime(new Date(account.lastCheckIn))}`;
|
message.value = `${account.firstName} ${account.lastName} um ${DateService.toTime(parseISO(account.lastCheckIn))}`;
|
||||||
await promiseTimeout(5000);
|
await promiseTimeout(5000);
|
||||||
message.value = DEFAULT_MESSAGE;
|
message.value = DEFAULT_MESSAGE;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
|
|
@ -71,10 +71,13 @@
|
||||||
<div class="stat-desc">in Spätschicht</div>
|
<div class="stat-desc">in Spätschicht</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-center justify-center gap-4">
|
<div
|
||||||
|
v-if="company"
|
||||||
|
class="flex items-center justify-center gap-4"
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
class="btn-primary btn"
|
class="btn-primary btn"
|
||||||
:class="{'btn-disabled': (getBalance() < getTotalCostsByShifts(Shifts.EARLY) || DateService.isToday(new Date(company.earlyShiftPayed)))}"
|
:class="{'btn-disabled': (getBalance() < getTotalCostsByShifts(Shifts.EARLY) || DateService.isToday(parseISO(company.earlyShiftPayed)))}"
|
||||||
@click="wageType = Shifts.EARLY; verifyModal?.show()"
|
@click="wageType = Shifts.EARLY; verifyModal?.show()"
|
||||||
>
|
>
|
||||||
<SunIcon class="h-6 w-6" />
|
<SunIcon class="h-6 w-6" />
|
||||||
|
@ -82,7 +85,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn-primary btn"
|
class="btn-primary btn"
|
||||||
:class="{'btn-disabled': (getBalance() < getTotalCostsByShifts(Shifts.LATE) || DateService.isToday(new Date(company.lateShiftPayed)))}"
|
:class="{'btn-disabled': (getBalance() < getTotalCostsByShifts(Shifts.LATE) || DateService.isToday(parseISO(company.lateShiftPayed)))}"
|
||||||
@click="wageType = Shifts.LATE; verifyModal?.show()"
|
@click="wageType = Shifts.LATE; verifyModal?.show()"
|
||||||
>
|
>
|
||||||
<MoonIcon class="h-6 w-6" />
|
<MoonIcon class="h-6 w-6" />
|
||||||
|
@ -91,14 +94,14 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex flex-col gap-2">
|
||||||
<div
|
<div
|
||||||
v-if="DateService.isToday(new Date(company.earlyShiftPayed))"
|
v-if="DateService.isToday(parseISO(company.earlyShiftPayed))"
|
||||||
class="alert alert-info"
|
class="alert alert-info"
|
||||||
>
|
>
|
||||||
<InformationCircleIcon class="h-6 w-6" />
|
<InformationCircleIcon class="h-6 w-6" />
|
||||||
Die Frühschicht wurde heute bereits bezahlt.
|
Die Frühschicht wurde heute bereits bezahlt.
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="DateService.isToday(new Date(company.lateShiftPayed))"
|
v-if="DateService.isToday(parseISO(company.lateShiftPayed))"
|
||||||
class="alert alert-info"
|
class="alert alert-info"
|
||||||
>
|
>
|
||||||
<InformationCircleIcon class="h-6 w-6" />
|
<InformationCircleIcon class="h-6 w-6" />
|
||||||
|
@ -131,14 +134,7 @@
|
||||||
id="verify-modal"
|
id="verify-modal"
|
||||||
ref="verifyModal"
|
ref="verifyModal"
|
||||||
title="Lohnauszahlung bestätigen"
|
title="Lohnauszahlung bestätigen"
|
||||||
@confirm="async () => {
|
@confirm="confirmWage"
|
||||||
verifyModal?.close();
|
|
||||||
if(wageType) {
|
|
||||||
await CompanyService.payWage(wageType);
|
|
||||||
}
|
|
||||||
wageType = undefined;
|
|
||||||
init();
|
|
||||||
}"
|
|
||||||
>
|
>
|
||||||
<div class="flex flex-col gap-1">
|
<div class="flex flex-col gap-1">
|
||||||
<p>Lohn wirklich für die {{ wageType == Shifts.EARLY ? 'Frühschicht' : 'Spätschicht' }} auszahlen?</p>
|
<p>Lohn wirklich für die {{ wageType == Shifts.EARLY ? 'Frühschicht' : 'Spätschicht' }} auszahlen?</p>
|
||||||
|
@ -166,6 +162,7 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onUnmounted, ref, watch } from 'vue';
|
import { onMounted, onUnmounted, ref, watch } from 'vue';
|
||||||
import { RecordSubscription, UnsubscribeFunc } from 'pocketbase';
|
import { RecordSubscription, UnsubscribeFunc } from 'pocketbase';
|
||||||
|
import { parseISO } from 'date-fns';
|
||||||
import { AccountsResponse, CompaniesResponse, SettingsResponse, TransactionsResponse } from '../../types/pocketbase.types';
|
import { AccountsResponse, CompaniesResponse, SettingsResponse, TransactionsResponse } from '../../types/pocketbase.types';
|
||||||
import { AccountService } from '../../services/account.service';
|
import { AccountService } from '../../services/account.service';
|
||||||
import { BankService } from '../../services/bank.service';
|
import { BankService } from '../../services/bank.service';
|
||||||
|
@ -324,6 +321,15 @@ function logout() {
|
||||||
getData();
|
getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function confirmWage() {
|
||||||
|
verifyModal.value?.close();
|
||||||
|
if(wageType.value) {
|
||||||
|
await CompanyService.payWage(wageType.value);
|
||||||
|
}
|
||||||
|
wageType.value = undefined;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
accountsSubscription.value?.();
|
accountsSubscription.value?.();
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { RecordSubscription, UnsubscribeFunc } from 'pocketbase';
|
import { RecordSubscription, UnsubscribeFunc } from 'pocketbase';
|
||||||
|
import { parseISO } from 'date-fns';
|
||||||
import { AccountsListResponse, AccountsRecord, AccountsResponse, Collections } from '../types/pocketbase.types';
|
import { AccountsListResponse, AccountsRecord, AccountsResponse, Collections } from '../types/pocketbase.types';
|
||||||
import { DateService } from './date.service';
|
import { DateService } from './date.service';
|
||||||
import { PocketbaseService } from './pocketbase.service';
|
import { PocketbaseService } from './pocketbase.service';
|
||||||
|
@ -34,7 +35,7 @@ export class AccountService {
|
||||||
}
|
}
|
||||||
public static async getMissingStudents(): Promise<AccountsResponse[]> {
|
public static async getMissingStudents(): Promise<AccountsResponse[]> {
|
||||||
return ((await COLLECTION.getFullList<AccountsResponse>()).filter(
|
return ((await COLLECTION.getFullList<AccountsResponse>()).filter(
|
||||||
(account: AccountsResponse) => !DateService.isToday(new Date(account.lastCheckIn)),
|
(account: AccountsResponse) => !DateService.isToday(parseISO(account.lastCheckIn)),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
public static async subscribeToAccountChanges(
|
public static async subscribeToAccountChanges(
|
||||||
|
|
|
@ -40,7 +40,7 @@ export class CompanyService {
|
||||||
}
|
}
|
||||||
public static async getCompany(): Promise<CompaniesResponse> {
|
public static async getCompany(): Promise<CompaniesResponse> {
|
||||||
if(this.isAuthenticated()) {
|
if(this.isAuthenticated()) {
|
||||||
return API.authStore.model as unknown as CompaniesResponse;
|
return COLLECTION.getFirstListItem(`id="${API.authStore.model?.id}"`);
|
||||||
}
|
}
|
||||||
throw new Error('Not authenticated');
|
throw new Error('Not authenticated');
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,6 @@ export class CompanyService {
|
||||||
promises.push(BankService.addTransaction(
|
promises.push(BankService.addTransaction(
|
||||||
account.id,
|
account.id,
|
||||||
(((account.wageFactor * settings.minWage) * (1 - (settings.incomeTax / 100)))) / 100,
|
(((account.wageFactor * settings.minWage) * (1 - (settings.incomeTax / 100)))) / 100,
|
||||||
// 300 - 1 * -
|
|
||||||
`Lohn für ${shift} bei ${company.name}`,
|
`Lohn für ${shift} bei ${company.name}`,
|
||||||
));
|
));
|
||||||
taxes += (account.wageFactor * settings.minWage) * (settings.incomeTax / 100);
|
taxes += (account.wageFactor * settings.minWage) * (settings.incomeTax / 100);
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { parseISO } from 'date-fns';
|
||||||
|
|
||||||
let serverTime: Date;
|
let serverTime: Date;
|
||||||
|
|
||||||
export class DateService {
|
export class DateService {
|
||||||
|
@ -27,6 +29,7 @@ export class DateService {
|
||||||
}
|
}
|
||||||
public static isToday(date: Date): boolean {
|
public static isToday(date: Date): boolean {
|
||||||
this.getServerTime();
|
this.getServerTime();
|
||||||
|
console.log('isToday', date, serverTime);
|
||||||
if(!serverTime) { return false; }
|
if(!serverTime) { return false; }
|
||||||
return date.getDate() === serverTime.getDate() &&
|
return date.getDate() === serverTime.getDate() &&
|
||||||
date.getMonth() === serverTime.getMonth() &&
|
date.getMonth() === serverTime.getMonth() &&
|
||||||
|
@ -37,7 +40,7 @@ export class DateService {
|
||||||
}
|
}
|
||||||
public static async getServerTime(): Promise<Date> {
|
public static async getServerTime(): Promise<Date> {
|
||||||
if(!serverTime || this.isOlderThanAMinute(serverTime)) {
|
if(!serverTime || this.isOlderThanAMinute(serverTime)) {
|
||||||
serverTime = new Date(await (await fetch(
|
serverTime = parseISO(await (await fetch(
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
(import.meta as any).env.MODE === 'development' ? 'http://127.0.0.1:8090/api/time' : '/api/time',
|
(import.meta as any).env.MODE === 'development' ? 'http://127.0.0.1:8090/api/time' : '/api/time',
|
||||||
)).text());
|
)).text());
|
||||||
|
|
Loading…
Reference in a new issue