forked from Kispi/Core
feat(webapp): show min and max wage and fix permission issues
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
dd59408c82
commit
6d6418858b
5 changed files with 40 additions and 14 deletions
|
@ -398,7 +398,7 @@
|
||||||
"indexes": [],
|
"indexes": [],
|
||||||
"listRule": "@request.auth.id != \"\" && @collection.bankers.id ?= @request.auth.id",
|
"listRule": "@request.auth.id != \"\" && @collection.bankers.id ?= @request.auth.id",
|
||||||
"viewRule": "@request.auth.id != \"\" && @collection.bankers.id ?= @request.auth.id",
|
"viewRule": "@request.auth.id != \"\" && @collection.bankers.id ?= @request.auth.id",
|
||||||
"createRule": "@request.auth.id != \"\" && @collection.bankers.id ?= @request.auth.id",
|
"createRule": "(@request.auth.id != \"\" && @collection.bankers.id ?= @request.auth.id) || (@request.auth.id != \"\" && @collection.companies.id ?= @request.auth.id && amount > 0)",
|
||||||
"updateRule": null,
|
"updateRule": null,
|
||||||
"deleteRule": null,
|
"deleteRule": null,
|
||||||
"options": {}
|
"options": {}
|
||||||
|
@ -450,7 +450,7 @@
|
||||||
"indexes": [],
|
"indexes": [],
|
||||||
"listRule": "",
|
"listRule": "",
|
||||||
"viewRule": "",
|
"viewRule": "",
|
||||||
"createRule": "@request.auth.id != \"\" && @collection.bankers.id ?= @request.auth.id",
|
"createRule": "(@request.auth.id != \"\" && @collection.bankers.id ?= @request.auth.id) || (@request.auth.id != \"\" && @collection.companies.id ?= @request.auth.id)",
|
||||||
"updateRule": null,
|
"updateRule": null,
|
||||||
"deleteRule": null,
|
"deleteRule": null,
|
||||||
"options": {}
|
"options": {}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "hgoe-sas",
|
"name": "hgoe-sas",
|
||||||
"private": true,
|
"private": true,
|
||||||
"author": "Simon Giesel",
|
"author": "Simon Giesel",
|
||||||
"version": "1.2.1",
|
"version": "1.3.1",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vue-tsc --noEmit && vite build",
|
"build": "vue-tsc --noEmit && vite build",
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<input
|
<input
|
||||||
ref="input"
|
v-model="modelValue"
|
||||||
:value="value"
|
|
||||||
type="number"
|
type="number"
|
||||||
class="input w-full border-primary text-right"
|
class="input w-full border-primary text-right"
|
||||||
:class="{
|
:class="{
|
||||||
'pr-[5.5rem]': !perHour,
|
'pr-[5.5rem]': !perHour,
|
||||||
'pr-[7rem]': perHour,
|
'pr-[7rem]': perHour,
|
||||||
|
'!border-error': error,
|
||||||
}"
|
}"
|
||||||
step="1"
|
step="1"
|
||||||
:min="min"
|
:min="min"
|
||||||
:max="max"
|
:max="max"
|
||||||
@keyup="onKeyDown"
|
@keyup="onKeyUp"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
class="pointer-events-none absolute top-2/4 text-[1rem] opacity-50"
|
class="pointer-events-none absolute top-2/4 text-[1rem] opacity-50"
|
||||||
|
@ -30,6 +30,7 @@
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
|
||||||
const input = ref<InstanceType<typeof HTMLInputElement>>();
|
const input = ref<InstanceType<typeof HTMLInputElement>>();
|
||||||
|
const error = ref(false);
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
suffixMargin?: boolean,
|
suffixMargin?: boolean,
|
||||||
|
@ -45,14 +46,20 @@ const props = withDefaults(defineProps<{
|
||||||
value: undefined,
|
value: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
function onKeyDown(event: KeyboardEvent) {
|
/* global defineModel */
|
||||||
|
const modelValue = defineModel();
|
||||||
|
|
||||||
|
function onKeyUp(event: KeyboardEvent) {
|
||||||
|
error.value = false;
|
||||||
|
// eslint-disable-next-line vue/no-mutating-props
|
||||||
const value = parseInt((event.target as HTMLInputElement).value);
|
const value = parseInt((event.target as HTMLInputElement).value);
|
||||||
if(value < props.min) {
|
|
||||||
emit('change', props.min);
|
if(isNaN(value)) {
|
||||||
(event.target as HTMLInputElement).value = props.min.toString();
|
error.value = true;
|
||||||
|
} else if(value < props.min) {
|
||||||
|
error.value = true;
|
||||||
} else if(value > props.max) {
|
} else if(value > props.max) {
|
||||||
emit('change', props.max);
|
error.value = true;
|
||||||
(event.target as HTMLInputElement).value = props.max.toString();
|
|
||||||
} else {
|
} else {
|
||||||
emit('change', value);
|
emit('change', value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,7 +87,7 @@
|
||||||
class="flex items-center gap-2"
|
class="flex items-center gap-2"
|
||||||
>
|
>
|
||||||
<AtomCurrencyInput
|
<AtomCurrencyInput
|
||||||
:value="entry[header.key] / 100"
|
v-model="entry.wage"
|
||||||
suffix-margin
|
suffix-margin
|
||||||
per-hour
|
per-hour
|
||||||
class="min-w-[11rem]"
|
class="min-w-[11rem]"
|
||||||
|
|
|
@ -71,6 +71,21 @@
|
||||||
<div class="stat-desc">in Spätschicht</div>
|
<div class="stat-desc">in Spätschicht</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="settings"
|
||||||
|
class="stats shadow"
|
||||||
|
>
|
||||||
|
<div class="stat place-items-center">
|
||||||
|
<div class="stat-title">Aktueller Mindestlohn</div>
|
||||||
|
<div class="stat-value">{{ CurrencyService.toString(settings.minWage, false) }} / h</div>
|
||||||
|
<div class="stat-desc">Batzen</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat place-items-center">
|
||||||
|
<div class="stat-title">Aktueller Maximallohn</div>
|
||||||
|
<div class="stat-value">{{ CurrencyService.toString(settings.maxWage, false) }} / h</div>
|
||||||
|
<div class="stat-desc">Batzen</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="company"
|
v-if="company"
|
||||||
class="flex items-center justify-center gap-4"
|
class="flex items-center justify-center gap-4"
|
||||||
|
@ -263,10 +278,14 @@ async function init() {
|
||||||
company.value = await CompanyService.getCompany();
|
company.value = await CompanyService.getCompany();
|
||||||
accounts.value = await AccountService.getAccountsByCompanyId(company.value.id);
|
accounts.value = await AccountService.getAccountsByCompanyId(company.value.id);
|
||||||
transactions.value = await BankService.getCompanyTransactions(company.value.id);
|
transactions.value = await BankService.getCompanyTransactions(company.value.id);
|
||||||
|
accounts.value.forEach((account) => {
|
||||||
|
account.wage = account.wage / 100;
|
||||||
|
});
|
||||||
accountsSubscription.value = await AccountService.subscribeToAccountChanges(async (data: RecordSubscription<AccountsResponse>) => {
|
accountsSubscription.value = await AccountService.subscribeToAccountChanges(async (data: RecordSubscription<AccountsResponse>) => {
|
||||||
if(data.action === 'update') {
|
if(data.action === 'update') {
|
||||||
accounts.value = accounts.value.map((account) => {
|
accounts.value = accounts.value.map((account) => {
|
||||||
if(account.id === data.record.id) {
|
if(account.id === data.record.id) {
|
||||||
|
data.record.wage = data.record.wage / 100;
|
||||||
return data.record;
|
return data.record;
|
||||||
}
|
}
|
||||||
return account;
|
return account;
|
||||||
|
@ -281,7 +300,7 @@ function getBalance(): number {
|
||||||
|
|
||||||
function getTotalCostsByShifts(shift: Shifts): number {
|
function getTotalCostsByShifts(shift: Shifts): number {
|
||||||
return accounts.value?.filter(
|
return accounts.value?.filter(
|
||||||
(account) => account.shift === shift).reduce((acc, account) => acc + account.wage, 0,
|
(account) => account.shift === shift).reduce((acc, account) => acc + account.wage * 100, 0,
|
||||||
) ?? 0;
|
) ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue