594 lines
18 KiB
Vue
594 lines
18 KiB
Vue
<template>
|
|
<div>
|
|
<v-dialog v-model="checkValidate" max-width="290">
|
|
<v-card>
|
|
<v-card-title>
|
|
Willst du wirklich??
|
|
</v-card-title>
|
|
<v-card-text v-if="stornoMessage">
|
|
Willst du wirklich den Betrag
|
|
{{ (stornoMessage.amount / 100).toFixed(2) }}€ von
|
|
{{ stornoMessage.user.firstname }}
|
|
{{ stornoMessage.user.lastname }} stornieren?
|
|
</v-card-text>
|
|
<v-card-actions>
|
|
<v-spacer />
|
|
<v-btn text @click="cancelStorno">Abbrechen</v-btn>
|
|
<v-btn text @click="acceptStorno">Stornieren</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
<v-dialog v-model="dialog" max-width="290">
|
|
<v-card>
|
|
<v-card-title class="headline"
|
|
>Transaktion ist länger als 1 Minute her!</v-card-title
|
|
>
|
|
<v-card-text>
|
|
Da die Transaktion länger als 1 Minuter her ist, kann eine Stornierung
|
|
nicht durchgeführt werden. Wende dich bitte an den Finanzer.
|
|
</v-card-text>
|
|
<v-card-actions>
|
|
<v-spacer />
|
|
<v-btn text @click="dialog = false">
|
|
Verstanden
|
|
</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
<v-dialog
|
|
v-if="overLimitUser"
|
|
v-model="overLimitUser"
|
|
max-width="290"
|
|
persistent
|
|
>
|
|
<v-card>
|
|
<v-card-title>Warnung</v-card-title>
|
|
<v-card-text>
|
|
{{ overLimitUser.firstname }} {{ overLimitUser.lastname }} übersteigt
|
|
das Anschreibelimit von
|
|
{{ (overLimitUser.limit / 100).toFixed(2) }} €. Danach kann dieses
|
|
Mitglied nichts mehr anschreiben. Will er das wirklich?
|
|
</v-card-text>
|
|
<v-card-actions>
|
|
<v-spacer />
|
|
<v-btn text @click="cancel()">Abbrechen</v-btn>
|
|
<v-btn text @click="continueAdd(overLimitUser)">Anschreiben</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
<v-dialog
|
|
v-if="overOverLimit"
|
|
v-model="overOverLimit"
|
|
max-width="290"
|
|
persistent
|
|
>
|
|
<v-card>
|
|
<v-card-title>Anschreiben nicht möglich</v-card-title>
|
|
<v-card-text>
|
|
{{ overOverLimit.firstname }}
|
|
{{ overOverLimit.lastname }} überschreitet das Anschreibelimit zuviel.
|
|
Das Anschreiben wurde daher gestoppt und zurückgesetzt.
|
|
</v-card-text>
|
|
<v-card-actions>
|
|
<v-btn text @click="overOverLimit = null">Verstanden</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
<v-progress-linear v-if="loading && users.length !== 0" indeterminate />
|
|
<v-container>
|
|
<AddAmountSkeleton v-if="loading && users.length === 0" />
|
|
</v-container>
|
|
<v-navigation-drawer v-model="menu" right app clipped>
|
|
<v-list-item-group :key="componentRenderer">
|
|
<v-list-item inactive>
|
|
<v-list-item-title class="headline">
|
|
Verlauf
|
|
</v-list-item-title>
|
|
</v-list-item>
|
|
<v-divider />
|
|
<div
|
|
v-for="message in messages"
|
|
three-line
|
|
:key="messages.indexOf(message)"
|
|
>
|
|
<v-list-item three-line inactive @click="storno(message)">
|
|
<v-list-item-content>
|
|
<v-progress-linear indeterminate v-if="message.loading" />
|
|
<v-list-item-title>{{ now(message.date) }}</v-list-item-title>
|
|
<v-list-item-subtitle>{{
|
|
createMessage(message)
|
|
}}</v-list-item-subtitle>
|
|
<v-list-item-subtitle class="red--text" v-if="message.storno">
|
|
STORNIERT!!!
|
|
</v-list-item-subtitle>
|
|
<v-list-item-subtitle class="red--text" v-else-if="message.error">
|
|
ERROR!
|
|
</v-list-item-subtitle>
|
|
<v-list-item-action-text v-if="under5minutes(message.date)"
|
|
>Klicken um zu Stornieren
|
|
</v-list-item-action-text>
|
|
</v-list-item-content>
|
|
</v-list-item>
|
|
</div>
|
|
</v-list-item-group>
|
|
</v-navigation-drawer>
|
|
<div v-for="user in users" :key="users.indexOf(user)">
|
|
<div v-if="isFiltered(user) && calcLastSeen(user)">
|
|
<v-container>
|
|
<v-card :loading="user.loading">
|
|
<v-card-title>
|
|
<v-list-item-title class="title"
|
|
>{{ user.firstname }} {{ user.lastname }}</v-list-item-title
|
|
>
|
|
</v-card-title>
|
|
<v-card-subtitle v-if="user.limit + user.amount > 0">
|
|
Nur noch {{ ((user.limit + user.amount) / 100).toFixed(2) }} €
|
|
übrig!!
|
|
</v-card-subtitle>
|
|
<v-card-text>
|
|
<v-row v-if="!user.locked">
|
|
<v-col cols="10">
|
|
<v-row>
|
|
<v-col cols="6" xs="5" sm="4">
|
|
<v-btn
|
|
class="creditBtn"
|
|
block
|
|
@click="addingAmount(user, 200)"
|
|
:color="color"
|
|
:disabled="user.locked"
|
|
>2 €
|
|
</v-btn>
|
|
</v-col>
|
|
<v-col cols="6" xs="5" sm="4">
|
|
<v-btn
|
|
class="creditBtn"
|
|
block
|
|
@click="addingAmount(user, 100)"
|
|
:color="color"
|
|
:disabled="user.locked"
|
|
>1 €
|
|
</v-btn>
|
|
</v-col>
|
|
<v-col cols="6" xs="5" sm="4">
|
|
<v-btn
|
|
class="creditBtn"
|
|
block
|
|
@click="addingAmount(user, 50)"
|
|
:color="color"
|
|
:disabled="user.locked"
|
|
>0,50 €
|
|
</v-btn>
|
|
</v-col>
|
|
<v-col cols="6" xs="5" sm="4">
|
|
<v-btn
|
|
class="creditBtn"
|
|
block
|
|
@click="addingAmount(user, 40)"
|
|
:color="color"
|
|
:disabled="user.locked"
|
|
>0,40 €
|
|
</v-btn>
|
|
</v-col>
|
|
<v-col cols="6" xs="5" sm="4">
|
|
<v-btn
|
|
class="creditBtn"
|
|
block
|
|
@click="addingAmount(user, 20)"
|
|
:color="color"
|
|
:disabled="user.locked"
|
|
>0,20 €
|
|
</v-btn>
|
|
</v-col>
|
|
<v-col cols="6" xs="5" sm="4">
|
|
<v-btn
|
|
class="creditBtn"
|
|
block
|
|
@click="addingAmount(user, 10)"
|
|
:color="color"
|
|
:disabled="user.locked"
|
|
>0,10 €
|
|
</v-btn>
|
|
</v-col>
|
|
<v-col cols="8">
|
|
<v-text-field
|
|
outlined
|
|
type="number"
|
|
v-model="user.value"
|
|
label="Benutzerdefinierter Betrag"
|
|
:disabled="user.locked"
|
|
></v-text-field>
|
|
</v-col>
|
|
<v-col cols="4">
|
|
<v-btn
|
|
fab
|
|
:color="color"
|
|
@click="addAmountMore(user)"
|
|
:disabled="user.locked"
|
|
>
|
|
<v-icon>{{ plus }}</v-icon>
|
|
</v-btn>
|
|
</v-col>
|
|
</v-row>
|
|
</v-col>
|
|
<v-col align-self="center">
|
|
<v-row>
|
|
<v-list-item>
|
|
<v-list-item-content class="text-center">
|
|
<v-list-item-action-text :class="getColor(user.type)"
|
|
>{{ (user.amount / 100).toFixed(2) }}
|
|
€
|
|
</v-list-item-action-text>
|
|
<v-list-item-action-text v-if="user.toSetAmount">
|
|
- {{ (user.toSetAmount / 100).toFixed(2) }}
|
|
</v-list-item-action-text>
|
|
</v-list-item-content>
|
|
</v-list-item>
|
|
</v-row>
|
|
</v-col>
|
|
</v-row>
|
|
<v-row>
|
|
<v-col class="hidden-sm-and-down" cols="80">
|
|
<v-alert v-if="user.locked" type="error"
|
|
>{{ user.firstname }} darf nicht mehr anschreiben.
|
|
{{ user.firstname }} sollte sich lieber mal beim Finanzer
|
|
melden.
|
|
</v-alert>
|
|
</v-col>
|
|
<v-col align-self="center" v-if="user.locked">
|
|
<v-row>
|
|
<v-list-item>
|
|
<v-list-item-content class="text-center">
|
|
<v-list-item-action-text :class="getColor(user.type)"
|
|
>{{ (user.amount / 100).toFixed(2) }}
|
|
€
|
|
</v-list-item-action-text>
|
|
</v-list-item-content>
|
|
</v-list-item>
|
|
</v-row>
|
|
</v-col>
|
|
</v-row>
|
|
</v-card-text>
|
|
</v-card>
|
|
<v-snackbar
|
|
:color="
|
|
messages.length > 0
|
|
? messages[0].error
|
|
? 'error'
|
|
: 'success'
|
|
: 'success'
|
|
"
|
|
bottom
|
|
:timeout="0"
|
|
:multi-line="true"
|
|
:value="messages.length > 0 ? messages[0].visible : test"
|
|
vertical
|
|
>
|
|
<v-list-item
|
|
v-for="message in messages"
|
|
:key="messages.indexOf(message)"
|
|
:style="
|
|
message.error
|
|
? 'background-color: #FF5252;'
|
|
: 'background-color: #4CAF50;'
|
|
"
|
|
v-show="message.visible"
|
|
>
|
|
<v-list-item-content>
|
|
<v-list-item-title style="color: white">
|
|
{{ createMessage(message) }}
|
|
</v-list-item-title>
|
|
</v-list-item-content>
|
|
<v-list-item-action v-if="message.error">
|
|
<v-btn icon @click="message.visible = false">
|
|
<v-icon color="white">
|
|
mdi-close
|
|
</v-icon>
|
|
</v-btn>
|
|
</v-list-item-action>
|
|
</v-list-item>
|
|
</v-snackbar>
|
|
</v-container>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { mapGetters, mapActions } from 'vuex'
|
|
import { mdiPlus } from '@mdi/js'
|
|
import AddAmountSkeleton from '../user/Skeleton/AddAmountSkeleton'
|
|
|
|
export default {
|
|
name: 'CreditLists',
|
|
components: { AddAmountSkeleton },
|
|
props: {},
|
|
data() {
|
|
return {
|
|
plus: mdiPlus,
|
|
value: null,
|
|
color: 'green accent-4',
|
|
menu: true,
|
|
dialog: false,
|
|
componentRenderer: 0,
|
|
timer: '',
|
|
stornoMessage: null,
|
|
checkValidate: false,
|
|
test: null,
|
|
overLimitUser: null,
|
|
overOverLimit: null
|
|
}
|
|
},
|
|
created() {
|
|
this.menu = this.menu_from_store
|
|
this.getUsers()
|
|
this.timer = setInterval(this.forceRender, 1000)
|
|
},
|
|
methods: {
|
|
...mapActions({
|
|
addAmount: 'barUsers/addAmount',
|
|
getUsers: 'barUsers/getUsers',
|
|
deactivate: 'barUsers/deactivateMenu',
|
|
commitStorno: 'barUsers/storno'
|
|
}),
|
|
continueAdd(user) {
|
|
this.overLimitUser = null
|
|
user.checkedOverLimit = true
|
|
if (user.value) {
|
|
this.addAmount({
|
|
username: user.username,
|
|
amount: Math.round(Math.abs(user.value * 100)),
|
|
user: user
|
|
})
|
|
setTimeout(() => {
|
|
user.value = null
|
|
user.toSetAmount = null
|
|
}, 300)
|
|
} else {
|
|
user.timeout = setTimeout(() => {
|
|
this.addAmount({
|
|
username: user.username,
|
|
amount: user.toSetAmount,
|
|
user: user
|
|
})
|
|
setTimeout(() => {
|
|
user.toSetAmount = null
|
|
}, 300)
|
|
}, 2000)
|
|
}
|
|
},
|
|
cancel() {
|
|
this.overLimitUser.toSetAmount = null
|
|
this.overLimitUser.value = null
|
|
this.overLimitUser = null
|
|
},
|
|
checkOverLimitIsValid(user) {
|
|
if (user.toSetAmount) {
|
|
if (
|
|
Math.abs(user.amount - Number.parseInt(user.toSetAmount)) >
|
|
user.limit + 500
|
|
) {
|
|
this.overOverLimit = user
|
|
user.toSetAmount = null
|
|
user.value = null
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
},
|
|
checkOverLimit(user) {
|
|
if (user.toSetAmount) {
|
|
if (Math.abs(user.amount - user.toSetAmount) > user.limit) {
|
|
return user.checkedOverLimit ? false : true
|
|
}
|
|
}
|
|
return false
|
|
},
|
|
addingAmount(user, amount) {
|
|
clearTimeout(user.timeout)
|
|
user.toSetAmount = user.toSetAmount ? user.toSetAmount + amount : amount
|
|
if (this.checkOverLimitIsValid(user)) {
|
|
if (this.checkOverLimit(user)) {
|
|
this.overLimitUser = user
|
|
} else {
|
|
user.timeout = setTimeout(() => {
|
|
this.addAmount({
|
|
username: user.username,
|
|
amount: user.toSetAmount,
|
|
user: user
|
|
})
|
|
setTimeout(() => {
|
|
user.toSetAmount = null
|
|
}, 300)
|
|
}, 2000)
|
|
}
|
|
}
|
|
},
|
|
forceRender() {
|
|
this.componentRenderer += 1
|
|
},
|
|
getColor(type) {
|
|
return type === 'credit' ? 'title green--text' : 'title red--text'
|
|
},
|
|
isFiltered(user) {
|
|
try {
|
|
var filters = this.filter.split(' ')
|
|
if (filters.length === 1) {
|
|
if (
|
|
user.firstname.toLowerCase().includes(filters[0].toLowerCase()) ||
|
|
user.lastname.toLowerCase().includes(filters[0].toLowerCase())
|
|
) {
|
|
return true
|
|
}
|
|
} else if (filters.length > 1) {
|
|
if (
|
|
user.firstname.toLowerCase().includes(filters[0].toLowerCase()) &&
|
|
user.lastname.toLowerCase().includes(filters[1].toLowerCase())
|
|
) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
} catch (e) {
|
|
return true
|
|
}
|
|
},
|
|
addAmountMore(user) {
|
|
user.toSetAmount = user.toSetAmount
|
|
? user.toSetAmount + Math.round(Math.abs(user.value * 100))
|
|
: Math.round(Math.abs(user.value * 100))
|
|
if (this.checkOverLimitIsValid(user)) {
|
|
if (this.checkOverLimit(user)) {
|
|
this.overLimitUser = user
|
|
} else {
|
|
this.addAmount({
|
|
username: user.username,
|
|
amount: Math.round(Math.abs(user.value * 100)),
|
|
user: user
|
|
})
|
|
setTimeout(() => {
|
|
user.value = null
|
|
user.toSetAmount = null
|
|
}, 300)
|
|
}
|
|
}
|
|
},
|
|
storno(message) {
|
|
if (!message.error) {
|
|
if (!this.under5minutes(message.date)) this.dialog = true
|
|
else {
|
|
this.checkValidate = true
|
|
this.stornoMessage = message
|
|
}
|
|
}
|
|
},
|
|
acceptStorno() {
|
|
this.commitStorno({
|
|
username: this.stornoMessage.user.username,
|
|
amount: this.stornoMessage.amount,
|
|
date: this.stornoMessage.date
|
|
})
|
|
setTimeout(() => {
|
|
this.cancelStorno()
|
|
}, 300)
|
|
},
|
|
cancelStorno() {
|
|
this.stornoMessage = null
|
|
this.checkValidate = null
|
|
},
|
|
createMessage(message) {
|
|
var text = ''
|
|
if (message.error) {
|
|
text =
|
|
'ERROR: Konnte ' +
|
|
(message.amount / 100).toFixed(2) +
|
|
'€ nicht zu ' +
|
|
message.user.firstname +
|
|
' ' +
|
|
message.user.lastname +
|
|
' hinzufügen.'
|
|
} else {
|
|
text =
|
|
'' +
|
|
(message.amount / 100).toFixed(2) +
|
|
'€ wurde zu ' +
|
|
message.user.firstname +
|
|
' ' +
|
|
message.user.lastname +
|
|
' hinzugefügt.'
|
|
}
|
|
return text
|
|
},
|
|
calcLastSeen(user) {
|
|
if (user.last_seen) {
|
|
let date = new Date()
|
|
if ((date - user.last_seen) / 1000 / 60 / 60 < 72) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
},
|
|
computed: {
|
|
...mapGetters({
|
|
users: 'barUsers/users',
|
|
filter: 'barUsers/filter',
|
|
loading: 'barUsers/usersLoading',
|
|
messages: 'barUsers/messages',
|
|
menu_from_store: 'barUsers/menu'
|
|
}),
|
|
under5minutes() {
|
|
return now => {
|
|
var actual = new Date()
|
|
return actual - now < 60000
|
|
}
|
|
},
|
|
now() {
|
|
return now => {
|
|
var actual = new Date()
|
|
var zero = new Date(0)
|
|
var date = new Date(actual - now)
|
|
if (date.getFullYear() === zero.getFullYear()) {
|
|
if (date.getMonth() === zero.getMonth()) {
|
|
if (date.getDate() === zero.getDate()) {
|
|
if (date.getHours() === zero.getDate()) {
|
|
if (date.getMinutes() < 1) {
|
|
return 'vor ' + date.getSeconds() + ' Sekunden'
|
|
} else if (date.getMinutes() < 10) {
|
|
return 'vor ' + date.getMinutes() + ' Minuten'
|
|
} else {
|
|
return (
|
|
(now.getHours() < 10 ? '0' : '') +
|
|
now.getHours() +
|
|
':' +
|
|
(now.getMinutes() < 10 ? '0' : '') +
|
|
now.getMinutes()
|
|
)
|
|
}
|
|
} else {
|
|
return (
|
|
(now.getHours() < 10 ? '0' : '') +
|
|
now.getHours() +
|
|
':' +
|
|
(now.getMinutes() < 10 ? '0' : '') +
|
|
now.getMinutes()
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return (
|
|
now.getDate() +
|
|
'.' +
|
|
now.getMonth() +
|
|
'.' +
|
|
now.getFullYear() +
|
|
' ' +
|
|
(now.getHours() < 10 ? '0' : '') +
|
|
now.getHours() +
|
|
':' +
|
|
(now.getMinutes() < 10 ? '0' : '') +
|
|
now.getMinutes()
|
|
)
|
|
}
|
|
}
|
|
},
|
|
watch: {
|
|
menu(newValue) {
|
|
if (!newValue) this.deactivate()
|
|
},
|
|
menu_from_store() {
|
|
this.menu = this.menu_from_store
|
|
}
|
|
},
|
|
beforeDestroy() {
|
|
clearInterval(this.timer)
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.creditBtn {
|
|
margin: 2px;
|
|
}
|
|
</style>
|