Merged balance actions into one page
This commit is contained in:
parent
17e640892a
commit
502c40329c
|
@ -1,6 +1,4 @@
|
||||||
<template>
|
<template>
|
||||||
<q-page padding class="fit row justify-left q-col-gutter-sm">
|
|
||||||
<div class="col-12">
|
|
||||||
<q-card>
|
<q-card>
|
||||||
<BalanceHeader @update:user="userUpdated" :showSelector="showSelector" />
|
<BalanceHeader @update:user="userUpdated" :showSelector="showSelector" />
|
||||||
<q-separator />
|
<q-separator />
|
||||||
|
@ -56,12 +54,6 @@
|
||||||
</div>
|
</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
</div>
|
|
||||||
<div v-for="(transaction, index) in transactions" v-bind:key="index" class="col-md-4 col-sm-6">
|
|
||||||
<!-- TODO: In Vue3 use v-model:transaction="..." -->
|
|
||||||
<Transaction :transaction.sync="transactions[index]" />
|
|
||||||
</div>
|
|
||||||
</q-page>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
@ -69,20 +61,25 @@ import { computed, ref, defineComponent, onBeforeMount } from '@vue/composition-
|
||||||
import { hasPermission } from 'src/utils/permission';
|
import { hasPermission } from 'src/utils/permission';
|
||||||
import { StateInterfaceBalance } from '../store/balance';
|
import { StateInterfaceBalance } from '../store/balance';
|
||||||
import { Store } from 'vuex';
|
import { Store } from 'vuex';
|
||||||
import Transaction from '../components/Transaction.vue';
|
|
||||||
import BalanceHeader from '../components/BalanceHeader.vue';
|
import BalanceHeader from '../components/BalanceHeader.vue';
|
||||||
import PERMISSIONS from '../permissions';
|
import PERMISSIONS from '../permissions';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'BalanceAdd',
|
name: 'BalanceAdd',
|
||||||
components: { Transaction, BalanceHeader },
|
components: { BalanceHeader },
|
||||||
setup(_, { root }) {
|
setup(_, { root }) {
|
||||||
onBeforeMount(() => void store.dispatch('balance/getShortcuts'));
|
onBeforeMount(() => {
|
||||||
|
void store.dispatch('balance/getShortcuts');
|
||||||
|
if (store.state.balance.transactions.length == 0)
|
||||||
|
// No transaction, load at most six since yesterday
|
||||||
|
void store.dispatch('balance/getTransactions', {
|
||||||
|
filter: { limit: 6, from: new Date(new Date().setDate(new Date().getDate() - 1)) }
|
||||||
|
});
|
||||||
|
});
|
||||||
const store = <Store<StateInterfaceBalance>>root.$store;
|
const store = <Store<StateInterfaceBalance>>root.$store;
|
||||||
|
|
||||||
const amount = ref<number>(0);
|
const amount = ref<number>(0);
|
||||||
const showAddShortcut = ref(false);
|
const showAddShortcut = ref(false);
|
||||||
const transactions = computed(() => store.state.balance.transactions.slice().reverse());
|
|
||||||
const user = ref(store.state.user.currentUser);
|
const user = ref(store.state.user.currentUser);
|
||||||
const shortCuts = ref(store.state.balance.shortcuts);
|
const shortCuts = ref(store.state.balance.shortcuts);
|
||||||
|
|
||||||
|
@ -113,7 +110,6 @@ export default defineComponent({
|
||||||
removeShortcut,
|
removeShortcut,
|
||||||
showAddShortcut,
|
showAddShortcut,
|
||||||
changeBalance,
|
changeBalance,
|
||||||
transactions,
|
|
||||||
amount,
|
amount,
|
||||||
showSelector,
|
showSelector,
|
||||||
shortCuts,
|
shortCuts,
|
||||||
|
|
|
@ -1,19 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<q-page padding class="fit row justify-left q-col-gutter-sm">
|
|
||||||
<div class="col-12">
|
|
||||||
<q-card>
|
<q-card>
|
||||||
<BalanceHeader @update:user="senderUpdated" :showSelector="showSelector" />
|
<BalanceHeader @update:user="senderUpdated" :showSelector="showSelector" />
|
||||||
<q-separator />
|
<q-separator />
|
||||||
<q-card-section class="row q-col-gutter-md items-center">
|
<q-card-section class="row q-col-gutter-md items-center">
|
||||||
<div class="col-sm-4 col-xs-12">
|
<div class="col-sm-4 col-xs-12">
|
||||||
<q-input
|
<q-input v-model.number="amount" type="number" filled label="Betrag" step="0.1" min="0" />
|
||||||
v-model.number="amount"
|
|
||||||
type="number"
|
|
||||||
filled
|
|
||||||
label="Betrag"
|
|
||||||
step="0.1"
|
|
||||||
min="0"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4 col-xs-6">
|
<div class="col-sm-4 col-xs-6">
|
||||||
<UserSelector :user="receiver" @update:user="receiverUpdated" label="Empfänger" />
|
<UserSelector :user="receiver" @update:user="receiverUpdated" label="Empfänger" />
|
||||||
|
@ -29,11 +20,6 @@
|
||||||
</div>
|
</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
</div>
|
|
||||||
<div v-for="(transaction, index) in transactions" v-bind:key="index" class="col-sm-4 col-xs-6">
|
|
||||||
<Transaction :transaction.sync="transactions[index]" />
|
|
||||||
</div>
|
|
||||||
</q-page>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
@ -42,13 +28,12 @@ import { hasPermission } from 'src/utils/permission';
|
||||||
import { StateInterfaceBalance } from '../store/balance';
|
import { StateInterfaceBalance } from '../store/balance';
|
||||||
import { Store } from 'vuex';
|
import { Store } from 'vuex';
|
||||||
import UserSelector from 'src/plugins/user/components/UserSelector.vue';
|
import UserSelector from 'src/plugins/user/components/UserSelector.vue';
|
||||||
import Transaction from '../components/Transaction.vue';
|
|
||||||
import BalanceHeader from '../components/BalanceHeader.vue';
|
import BalanceHeader from '../components/BalanceHeader.vue';
|
||||||
import PERMISSIONS from '../permissions';
|
import PERMISSIONS from '../permissions';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'BalanceTransfer',
|
name: 'BalanceTransfer',
|
||||||
components: { Transaction, BalanceHeader, UserSelector },
|
components: { BalanceHeader, UserSelector },
|
||||||
setup(_, { root }) {
|
setup(_, { root }) {
|
||||||
const store: Store<StateInterfaceBalance> = <Store<StateInterfaceBalance>>root.$store;
|
const store: Store<StateInterfaceBalance> = <Store<StateInterfaceBalance>>root.$store;
|
||||||
|
|
||||||
|
@ -56,7 +41,6 @@ export default defineComponent({
|
||||||
const sender = ref(store.state.user.currentUser);
|
const sender = ref(store.state.user.currentUser);
|
||||||
const receiver = ref<FG.User | undefined>(undefined);
|
const receiver = ref<FG.User | undefined>(undefined);
|
||||||
const amount = ref<number>(0);
|
const amount = ref<number>(0);
|
||||||
const transactions = computed(() => store.state.balance.transactions.slice().reverse());
|
|
||||||
|
|
||||||
const sendDisabled = computed(() => {
|
const sendDisabled = computed(() => {
|
||||||
return !(
|
return !(
|
||||||
|
@ -90,7 +74,6 @@ export default defineComponent({
|
||||||
receiver,
|
receiver,
|
||||||
amount,
|
amount,
|
||||||
sendAmount,
|
sendAmount,
|
||||||
transactions,
|
|
||||||
showSelector,
|
showSelector,
|
||||||
senderUpdated,
|
senderUpdated,
|
||||||
receiverUpdated,
|
receiverUpdated,
|
||||||
|
|
|
@ -1,48 +1,112 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<q-page padding v-if="checkMain">
|
<q-tabs v-model="tab" v-if="$q.screen.gt.sm">
|
||||||
<q-card>
|
<q-tab
|
||||||
<q-card-section>
|
v-for="(tabindex, index) in tabs"
|
||||||
<q-list v-for="(mainRoute, index) in mainRoutes" :key="'mainRoute' + index">
|
:key="'tab' + index"
|
||||||
<essential-link
|
:name="tabindex.name"
|
||||||
v-for="(route, index2) in mainRoute.children"
|
:label="tabindex.label"
|
||||||
:key="'route' + index2"
|
|
||||||
:title="route.title"
|
|
||||||
:icon="route.icon"
|
|
||||||
:link="route.name"
|
|
||||||
:permissions="route.meta.permissions"
|
|
||||||
/>
|
/>
|
||||||
|
</q-tabs>
|
||||||
|
<div class="fit row justify-end" v-else>
|
||||||
|
<q-btn flat round icon="mdi-menu" @click="showDrawer = !showDrawer" />
|
||||||
|
</div>
|
||||||
|
<q-drawer side="right" v-model="showDrawer" @click="showDrawer = !showDrawer" behavior="mobile">
|
||||||
|
<q-list v-model="tab">
|
||||||
|
<q-item
|
||||||
|
v-for="(tabindex, index) in tabs"
|
||||||
|
:key="'tab' + index"
|
||||||
|
:active="tab == tabindex.name"
|
||||||
|
clickable
|
||||||
|
@click="tab = tabindex.name"
|
||||||
|
>
|
||||||
|
<q-item-label>{{ tabindex.label }}</q-item-label>
|
||||||
|
</q-item>
|
||||||
</q-list>
|
</q-list>
|
||||||
</q-card-section>
|
</q-drawer>
|
||||||
</q-card>
|
<q-page padding class="fit row justify-left q-col-gutter-sm">
|
||||||
|
<q-tab-panels
|
||||||
|
v-model="tab"
|
||||||
|
style="background-color: transparent"
|
||||||
|
class="q-pa-none col-12"
|
||||||
|
animated
|
||||||
|
>
|
||||||
|
<q-tab-panel name="add" class="q-px-xs">
|
||||||
|
<BalanceAdd />
|
||||||
|
</q-tab-panel>
|
||||||
|
<q-tab-panel name="transfer" class="q-px-xs">
|
||||||
|
<BalanceTransfer />
|
||||||
|
</q-tab-panel>
|
||||||
|
</q-tab-panels>
|
||||||
|
<div
|
||||||
|
v-for="(transaction, index) in transactions"
|
||||||
|
v-bind:key="index"
|
||||||
|
class="col-md-4 col-sm-6"
|
||||||
|
>
|
||||||
|
<!-- TODO: In Vue3 use v-model:transaction="..." -->
|
||||||
|
<Transaction :transaction.sync="transactions[index]" />
|
||||||
|
</div>
|
||||||
</q-page>
|
</q-page>
|
||||||
<router-view />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineComponent } from '@vue/composition-api';
|
import { computed, defineComponent, ref } from '@vue/composition-api';
|
||||||
import EssentialLink from 'src/components/navigation/EssentialLink.vue';
|
|
||||||
import mainRoutes from 'src/plugins/balance/routes';
|
|
||||||
import { Store } from 'vuex';
|
import { Store } from 'vuex';
|
||||||
import { BalanceInterface } from 'src/plugins/balance/store/balance';
|
import { hasPermissions, hasSomePermissions } from 'src/utils/permission';
|
||||||
import setLoadingBar from 'src/utils/loading';
|
import PERMISSIONS from '../permissions';
|
||||||
import { StateInterface } from 'src/store';
|
import { Screen } from 'quasar';
|
||||||
|
import BalanceAdd from '../components/BalanceAdd.vue';
|
||||||
|
import BalanceTransfer from '../components/BalanceTransfer.vue';
|
||||||
|
import Transaction from '../components/Transaction.vue';
|
||||||
|
import { StateInterfaceBalance } from '../store/balance';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
// name: 'PageName'
|
name: 'BalanceManage',
|
||||||
components: { EssentialLink },
|
components: { BalanceAdd, BalanceTransfer, Transaction },
|
||||||
setup(_, { root }) {
|
setup(_, { root }) {
|
||||||
const store = <Store<StateInterface>>root.$store;
|
const store = <Store<StateInterfaceBalance>>root.$store;
|
||||||
const loading = computed(() => {
|
|
||||||
return (<BalanceInterface>store.state.balance).loading > 0;
|
const transactions = computed(() =>
|
||||||
});
|
store.state.balance.transactions
|
||||||
const checkMain = computed(() => {
|
.filter(t => t.original_id == undefined)
|
||||||
return root.$route.matched.length == 2;
|
.sort((a, b) => (a.time >= b.time ? -1 : 1))
|
||||||
|
);
|
||||||
|
|
||||||
|
const canAdd = () =>
|
||||||
|
hasSomePermissions([PERMISSIONS.DEBIT, PERMISSIONS.CREDIT, PERMISSIONS.DEBIT_OWN], store);
|
||||||
|
|
||||||
|
interface Tab {
|
||||||
|
name: string;
|
||||||
|
label: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tabs: Tab[] = [
|
||||||
|
...(canAdd() ? [{ name: 'add', label: 'Anschreiben' }] : []),
|
||||||
|
...(hasSomePermissions([PERMISSIONS.SEND, PERMISSIONS.SEND_OTHER], store)
|
||||||
|
? [{ name: 'transfer', label: 'Übertragen' }]
|
||||||
|
: [])
|
||||||
|
];
|
||||||
|
|
||||||
|
const drawer = ref<boolean>(false);
|
||||||
|
|
||||||
|
const showDrawer = computed({
|
||||||
|
get: () => {
|
||||||
|
return !Screen.gt.sm && drawer.value;
|
||||||
|
},
|
||||||
|
set: (val: boolean) => {
|
||||||
|
drawer.value = val;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setLoadingBar(loading);
|
const tab = ref<string>(canAdd() ? 'add' : 'transfer');
|
||||||
|
|
||||||
return { checkMain, mainRoutes };
|
return {
|
||||||
|
showDrawer,
|
||||||
|
tab,
|
||||||
|
tabs,
|
||||||
|
transactions
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -7,32 +7,32 @@ const mainRoutes: FG_Plugin.PluginRouteConfig[] = [
|
||||||
icon: 'mdi-cash-100',
|
icon: 'mdi-cash-100',
|
||||||
path: 'balance',
|
path: 'balance',
|
||||||
name: 'balance',
|
name: 'balance',
|
||||||
redirect: { name: 'balance-add' },
|
redirect: { name: 'balance-view' },
|
||||||
meta: { permissions: ['user'] },
|
meta: { permissions: ['user'] },
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
title: 'Anschreiben',
|
title: 'Übersicht',
|
||||||
icon: 'mdi-cash-plus',
|
icon: 'mdi-cash-plus',
|
||||||
path: 'add',
|
path: 'overview',
|
||||||
name: 'balance-add',
|
name: 'balance-view',
|
||||||
shortcut: true,
|
meta: { permissions: [permissions.SHOW] },
|
||||||
meta: { permissions: [permissions.DEBIT_OWN, permissions.SHOW] },
|
component: () => import('../pages/Overview.vue')
|
||||||
component: () => import('../pages/Add.vue')
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Übertragen',
|
title: 'Buchen',
|
||||||
icon: 'mdi-cash-refund',
|
icon: 'mdi-cash-plus',
|
||||||
path: 'transfer',
|
path: 'change',
|
||||||
name: 'balance-transfer',
|
name: 'balance-change',
|
||||||
meta: { permissions: [permissions.SEND] },
|
shortcut: true,
|
||||||
component: () => import('../pages/Transfer.vue')
|
meta: { permissions: [permissions.DEBIT_OWN, permissions.SHOW] },
|
||||||
|
component: () => import('../pages/MainPage.vue')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Verwaltung',
|
title: 'Verwaltung',
|
||||||
icon: 'mdi-account-cash',
|
icon: 'mdi-account-cash',
|
||||||
path: 'admin',
|
path: 'admin',
|
||||||
name: 'balance-admin',
|
name: 'balance-admin',
|
||||||
meta: { permissions: [permissions.DEBIT_OWN, permissions.SHOW] },
|
meta: { permissions: [permissions.SET_LIMIT, permissions.SHOW_OTHER] },
|
||||||
component: () => import('../pages/Admin.vue')
|
component: () => import('../pages/Admin.vue')
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,25 +1,5 @@
|
||||||
import { FG_Plugin } from 'src/plugins';
|
import { FG_Plugin } from 'src/plugins';
|
||||||
|
|
||||||
/*const permissions = {
|
|
||||||
// Show own and others balance
|
|
||||||
SHOW: 'balance_show',
|
|
||||||
SHOW_OTHER: 'balance_show_others',
|
|
||||||
// Credit balance (give)
|
|
||||||
CREDIT: 'balance_credit',
|
|
||||||
// Debit balance (take)
|
|
||||||
DEBIT: 'balance_debit',
|
|
||||||
// Debit own balance only
|
|
||||||
DEBIT_OWN: 'balance_debit_own',
|
|
||||||
// Send from to other
|
|
||||||
SEND: 'balance_send',
|
|
||||||
// Send from other to another
|
|
||||||
SEND_OTHER: 'balance_send_others',
|
|
||||||
// Can set limit for users
|
|
||||||
SET_LIMIT: 'balance_set_limit',
|
|
||||||
//Allow sending / sub while exceeding the set limit
|
|
||||||
EXCEED_LIMIT: 'balance_exceed_limit'
|
|
||||||
};*/
|
|
||||||
|
|
||||||
const mainRoutes: FG_Plugin.PluginRouteConfig[] = [
|
const mainRoutes: FG_Plugin.PluginRouteConfig[] = [
|
||||||
{
|
{
|
||||||
title: 'Dienste',
|
title: 'Dienste',
|
||||||
|
|
|
@ -31,12 +31,7 @@
|
||||||
label="Zeit"
|
label="Zeit"
|
||||||
filled
|
filled
|
||||||
/>
|
/>
|
||||||
<q-select
|
<q-select class="col-xs-12 col-sm-6 q-px-sm" :options="options" v-model="option" filled />
|
||||||
class="col-xs-12 col-sm-6 q-px-sm"
|
|
||||||
:options="options"
|
|
||||||
v-model="option"
|
|
||||||
filled
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-actions align="right" v-if="!isEdit">
|
<q-card-actions align="right" v-if="!isEdit">
|
||||||
|
@ -59,10 +54,10 @@ export default defineComponent({
|
||||||
name: 'Sessions',
|
name: 'Sessions',
|
||||||
props: {
|
props: {
|
||||||
session: {
|
session: {
|
||||||
required: true,
|
required: true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
setup(props: { session: FG.Session }, { root }) {
|
||||||
setup(props: {session: FG.Session}, { root }) {
|
|
||||||
const store = <Store<StateInterface>>root.$store;
|
const store = <Store<StateInterface>>root.$store;
|
||||||
const options = ref(['Minuten', 'Stunden', 'Tage']);
|
const options = ref(['Minuten', 'Stunden', 'Tage']);
|
||||||
const option = ref<string>(options.value[0]);
|
const option = ref<string>(options.value[0]);
|
||||||
|
@ -92,7 +87,7 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
|
|
||||||
function deleteSession(token: string) {
|
function deleteSession(token: string) {
|
||||||
store.dispatch('session/deleteSession', token).catch((error) => {
|
store.dispatch('session/deleteSession', token).catch(error => {
|
||||||
console.warn(error);
|
console.warn(error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -113,7 +108,7 @@ export default defineComponent({
|
||||||
return (lifetime.value / (60 * 60 * 24)).toFixed(2);
|
return (lifetime.value / (60 * 60 * 24)).toFixed(2);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
set: (val) => {
|
set: val => {
|
||||||
if (val) {
|
if (val) {
|
||||||
switch (option.value) {
|
switch (option.value) {
|
||||||
case options.value[0]:
|
case options.value[0]:
|
||||||
|
@ -127,7 +122,7 @@ export default defineComponent({
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function edit(value: boolean) {
|
function edit(value: boolean) {
|
||||||
|
@ -139,11 +134,8 @@ export default defineComponent({
|
||||||
console.log(lifetime.value);
|
console.log(lifetime.value);
|
||||||
isEdit.value = false;
|
isEdit.value = false;
|
||||||
void store
|
void store
|
||||||
.dispatch(
|
.dispatch('session/updateSession', { lifetime: lifetime.value, token: props.session.token })
|
||||||
'session/updateSession',
|
.catch(error => {
|
||||||
{lifetime: lifetime.value, token: props.session.token}
|
|
||||||
)
|
|
||||||
.catch((error) => {
|
|
||||||
console.log(error);
|
console.log(error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -159,8 +151,8 @@ export default defineComponent({
|
||||||
option,
|
option,
|
||||||
lifetime,
|
lifetime,
|
||||||
computedLifetime,
|
computedLifetime,
|
||||||
save,
|
save
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Reference in New Issue