mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge branch 'master' into frontend-generate-link-for-send-gdd
This commit is contained in:
commit
c2d1290ae7
@ -21,6 +21,7 @@ export enum RIGHTS {
|
||||
CREATE_TRANSACTION_LINK = 'CREATE_TRANSACTION_LINK',
|
||||
DELETE_TRANSACTION_LINK = 'DELETE_TRANSACTION_LINK',
|
||||
QUERY_TRANSACTION_LINK = 'QUERY_TRANSACTION_LINK',
|
||||
REDEEM_TRANSACTION_LINK = 'REDEEM_TRANSACTION_LINK',
|
||||
LIST_TRANSACTION_LINKS = 'LIST_TRANSACTION_LINKS',
|
||||
// Admin
|
||||
SEARCH_USERS = 'SEARCH_USERS',
|
||||
|
||||
@ -20,6 +20,7 @@ export const ROLE_USER = new Role('user', [
|
||||
RIGHTS.HAS_ELOPAGE,
|
||||
RIGHTS.CREATE_TRANSACTION_LINK,
|
||||
RIGHTS.DELETE_TRANSACTION_LINK,
|
||||
RIGHTS.REDEEM_TRANSACTION_LINK,
|
||||
RIGHTS.LIST_TRANSACTION_LINKS,
|
||||
])
|
||||
export const ROLE_ADMIN = new Role('admin', Object.values(RIGHTS)) // all rights
|
||||
|
||||
@ -10,7 +10,7 @@ Decimal.set({
|
||||
})
|
||||
|
||||
const constants = {
|
||||
DB_VERSION: '0031-remove_sendEmail_from_transaction_link',
|
||||
DB_VERSION: '0032-add-transaction-link-to-transaction',
|
||||
DECAY_START_TIME: new Date('2021-05-13 17:46:31'), // GMT+0
|
||||
}
|
||||
|
||||
|
||||
@ -30,6 +30,7 @@ export class Transaction {
|
||||
this.creationDate = transaction.creationDate
|
||||
this.linkedUser = linkedUser
|
||||
this.linkedTransactionId = transaction.linkedTransactionId
|
||||
this.transactionLinkId = transaction.transactionLinkId
|
||||
}
|
||||
|
||||
@Field(() => Number)
|
||||
@ -67,4 +68,8 @@ export class Transaction {
|
||||
|
||||
@Field(() => Number, { nullable: true })
|
||||
linkedTransactionId?: number | null
|
||||
|
||||
// Links to the TransactionLink when transaction was created by a link
|
||||
@Field(() => Number, { nullable: true })
|
||||
transactionLinkId?: number | null
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ import { RIGHTS } from '@/auth/RIGHTS'
|
||||
import { randomBytes } from 'crypto'
|
||||
import { User } from '@model/User'
|
||||
import { calculateDecay } from '@/util/decay'
|
||||
import { executeTransaction } from './TransactionResolver'
|
||||
import { Order } from '@enum/Order'
|
||||
|
||||
// TODO: do not export, test it inside the resolver
|
||||
@ -132,4 +133,37 @@ export class TransactionLinkResolver {
|
||||
})
|
||||
return transactionLinks.map((tl) => new TransactionLink(tl, new User(user)))
|
||||
}
|
||||
|
||||
@Authorized([RIGHTS.REDEEM_TRANSACTION_LINK])
|
||||
@Mutation(() => Boolean)
|
||||
async redeemTransactionLink(@Arg('id') id: number, @Ctx() context: any): Promise<boolean> {
|
||||
const userRepository = getCustomRepository(UserRepository)
|
||||
const user = await userRepository.findByPubkeyHex(context.pubKey)
|
||||
const transactionLink = await dbTransactionLink.findOneOrFail({ id })
|
||||
const linkedUser = await dbUser.findOneOrFail({ id: transactionLink.userId })
|
||||
|
||||
const now = new Date()
|
||||
|
||||
if (user.id === linkedUser.id) {
|
||||
throw new Error('Cannot redeem own transaction link.')
|
||||
}
|
||||
|
||||
if (transactionLink.validUntil.getTime() < now.getTime()) {
|
||||
throw new Error('Transaction Link is not valid anymore.')
|
||||
}
|
||||
|
||||
if (transactionLink.redeemedBy) {
|
||||
throw new Error('Transaction Link already redeemed.')
|
||||
}
|
||||
|
||||
await executeTransaction(
|
||||
transactionLink.amount,
|
||||
transactionLink.memo,
|
||||
linkedUser,
|
||||
user,
|
||||
transactionLink,
|
||||
)
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,6 +23,7 @@ import { TransactionLinkRepository } from '@repository/TransactionLink'
|
||||
|
||||
import { User as dbUser } from '@entity/User'
|
||||
import { Transaction as dbTransaction } from '@entity/Transaction'
|
||||
import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink'
|
||||
|
||||
import { apiPost } from '@/apis/HttpRequest'
|
||||
import { TransactionTypeId } from '@enum/TransactionTypeId'
|
||||
@ -34,6 +35,96 @@ import { virtualLinkTransaction, virtualDecayTransaction } from '@/util/virtualT
|
||||
import Decimal from 'decimal.js-light'
|
||||
import { calculateDecay } from '@/util/decay'
|
||||
|
||||
export const executeTransaction = async (
|
||||
amount: Decimal,
|
||||
memo: string,
|
||||
sender: dbUser,
|
||||
recipient: dbUser,
|
||||
transactionLink?: dbTransactionLink | null,
|
||||
): Promise<boolean> => {
|
||||
if (sender.id === recipient.id) {
|
||||
throw new Error('Sender and Recipient are the same.')
|
||||
}
|
||||
|
||||
// validate amount
|
||||
const receivedCallDate = new Date()
|
||||
const sendBalance = await calculateBalance(sender.id, amount.mul(-1), receivedCallDate)
|
||||
if (!sendBalance) {
|
||||
throw new Error("user hasn't enough GDD or amount is < 0")
|
||||
}
|
||||
|
||||
const queryRunner = getConnection().createQueryRunner()
|
||||
await queryRunner.connect()
|
||||
await queryRunner.startTransaction('READ UNCOMMITTED')
|
||||
try {
|
||||
// transaction
|
||||
const transactionSend = new dbTransaction()
|
||||
transactionSend.typeId = TransactionTypeId.SEND
|
||||
transactionSend.memo = memo
|
||||
transactionSend.userId = sender.id
|
||||
transactionSend.linkedUserId = recipient.id
|
||||
transactionSend.amount = amount.mul(-1)
|
||||
transactionSend.balance = sendBalance.balance
|
||||
transactionSend.balanceDate = receivedCallDate
|
||||
transactionSend.decay = sendBalance.decay.decay
|
||||
transactionSend.decayStart = sendBalance.decay.start
|
||||
transactionSend.previous = sendBalance.lastTransactionId
|
||||
transactionSend.transactionLinkId = transactionLink ? transactionLink.id : null
|
||||
await queryRunner.manager.insert(dbTransaction, transactionSend)
|
||||
|
||||
const transactionReceive = new dbTransaction()
|
||||
transactionReceive.typeId = TransactionTypeId.RECEIVE
|
||||
transactionReceive.memo = memo
|
||||
transactionReceive.userId = recipient.id
|
||||
transactionReceive.linkedUserId = sender.id
|
||||
transactionReceive.amount = amount
|
||||
const receiveBalance = await calculateBalance(recipient.id, amount, receivedCallDate)
|
||||
transactionReceive.balance = receiveBalance ? receiveBalance.balance : amount
|
||||
transactionReceive.balanceDate = receivedCallDate
|
||||
transactionReceive.decay = receiveBalance ? receiveBalance.decay.decay : new Decimal(0)
|
||||
transactionReceive.decayStart = receiveBalance ? receiveBalance.decay.start : null
|
||||
transactionReceive.previous = receiveBalance ? receiveBalance.lastTransactionId : null
|
||||
transactionReceive.linkedTransactionId = transactionSend.id
|
||||
transactionReceive.transactionLinkId = transactionLink ? transactionLink.id : null
|
||||
await queryRunner.manager.insert(dbTransaction, transactionReceive)
|
||||
|
||||
// Save linked transaction id for send
|
||||
transactionSend.linkedTransactionId = transactionReceive.id
|
||||
await queryRunner.manager.update(dbTransaction, { id: transactionSend.id }, transactionSend)
|
||||
|
||||
if (transactionLink) {
|
||||
transactionLink.redeemedAt = receivedCallDate
|
||||
transactionLink.redeemedBy = recipient.id
|
||||
await queryRunner.manager.update(
|
||||
dbTransactionLink,
|
||||
{ id: transactionLink.id },
|
||||
transactionLink,
|
||||
)
|
||||
}
|
||||
|
||||
await queryRunner.commitTransaction()
|
||||
} catch (e) {
|
||||
await queryRunner.rollbackTransaction()
|
||||
throw new Error(`Transaction was not successful: ${e}`)
|
||||
} finally {
|
||||
await queryRunner.release()
|
||||
}
|
||||
|
||||
// send notification email
|
||||
// TODO: translate
|
||||
await sendTransactionReceivedEmail({
|
||||
senderFirstName: sender.firstName,
|
||||
senderLastName: sender.lastName,
|
||||
recipientFirstName: recipient.firstName,
|
||||
recipientLastName: recipient.lastName,
|
||||
email: recipient.email,
|
||||
amount,
|
||||
memo,
|
||||
})
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@Resolver()
|
||||
export class TransactionResolver {
|
||||
@Authorized([RIGHTS.TRANSACTION_LIST])
|
||||
@ -169,12 +260,6 @@ export class TransactionResolver {
|
||||
if (senderUser.pubKey.length !== 32) {
|
||||
throw new Error('invalid sender public key')
|
||||
}
|
||||
// validate amount
|
||||
const receivedCallDate = new Date()
|
||||
const sendBalance = await calculateBalance(senderUser.id, amount.mul(-1), receivedCallDate)
|
||||
if (!sendBalance) {
|
||||
throw new Error("user hasn't enough GDD or amount is < 0")
|
||||
}
|
||||
|
||||
// validate recipient user
|
||||
const recipientUser = await dbUser.findOne({ email: email }, { withDeleted: true })
|
||||
@ -188,62 +273,7 @@ export class TransactionResolver {
|
||||
throw new Error('invalid recipient public key')
|
||||
}
|
||||
|
||||
const queryRunner = getConnection().createQueryRunner()
|
||||
await queryRunner.connect()
|
||||
await queryRunner.startTransaction('READ UNCOMMITTED')
|
||||
try {
|
||||
// transaction
|
||||
const transactionSend = new dbTransaction()
|
||||
transactionSend.typeId = TransactionTypeId.SEND
|
||||
transactionSend.memo = memo
|
||||
transactionSend.userId = senderUser.id
|
||||
transactionSend.linkedUserId = recipientUser.id
|
||||
transactionSend.amount = amount.mul(-1)
|
||||
transactionSend.balance = sendBalance.balance
|
||||
transactionSend.balanceDate = receivedCallDate
|
||||
transactionSend.decay = sendBalance.decay.decay
|
||||
transactionSend.decayStart = sendBalance.decay.start
|
||||
transactionSend.previous = sendBalance.lastTransactionId
|
||||
await queryRunner.manager.insert(dbTransaction, transactionSend)
|
||||
|
||||
const transactionReceive = new dbTransaction()
|
||||
transactionReceive.typeId = TransactionTypeId.RECEIVE
|
||||
transactionReceive.memo = memo
|
||||
transactionReceive.userId = recipientUser.id
|
||||
transactionReceive.linkedUserId = senderUser.id
|
||||
transactionReceive.amount = amount
|
||||
const receiveBalance = await calculateBalance(recipientUser.id, amount, receivedCallDate)
|
||||
transactionReceive.balance = receiveBalance ? receiveBalance.balance : amount
|
||||
transactionReceive.balanceDate = receivedCallDate
|
||||
transactionReceive.decay = receiveBalance ? receiveBalance.decay.decay : new Decimal(0)
|
||||
transactionReceive.decayStart = receiveBalance ? receiveBalance.decay.start : null
|
||||
transactionReceive.previous = receiveBalance ? receiveBalance.lastTransactionId : null
|
||||
transactionReceive.linkedTransactionId = transactionSend.id
|
||||
await queryRunner.manager.insert(dbTransaction, transactionReceive)
|
||||
|
||||
// Save linked transaction id for send
|
||||
transactionSend.linkedTransactionId = transactionReceive.id
|
||||
await queryRunner.manager.update(dbTransaction, { id: transactionSend.id }, transactionSend)
|
||||
|
||||
await queryRunner.commitTransaction()
|
||||
} catch (e) {
|
||||
await queryRunner.rollbackTransaction()
|
||||
throw new Error(`Transaction was not successful: ${e}`)
|
||||
} finally {
|
||||
await queryRunner.release()
|
||||
}
|
||||
|
||||
// send notification email
|
||||
// TODO: translate
|
||||
await sendTransactionReceivedEmail({
|
||||
senderFirstName: senderUser.firstName,
|
||||
senderLastName: senderUser.lastName,
|
||||
recipientFirstName: recipientUser.firstName,
|
||||
recipientLastName: recipientUser.lastName,
|
||||
email: recipientUser.email,
|
||||
amount,
|
||||
memo,
|
||||
})
|
||||
await executeTransaction(amount, memo, senderUser, recipientUser)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@ -0,0 +1,94 @@
|
||||
import Decimal from 'decimal.js-light'
|
||||
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from 'typeorm'
|
||||
import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer'
|
||||
|
||||
@Entity('transactions')
|
||||
export class Transaction extends BaseEntity {
|
||||
@PrimaryGeneratedColumn('increment', { unsigned: true })
|
||||
id: number
|
||||
|
||||
@Column({ name: 'user_id', unsigned: true, nullable: false })
|
||||
userId: number
|
||||
|
||||
@Column({ type: 'int', unsigned: true, nullable: true, default: null })
|
||||
previous: number | null
|
||||
|
||||
@Column({ name: 'type_id', unsigned: true, nullable: false })
|
||||
typeId: number
|
||||
|
||||
@Column({
|
||||
type: 'decimal',
|
||||
precision: 40,
|
||||
scale: 20,
|
||||
nullable: false,
|
||||
transformer: DecimalTransformer,
|
||||
})
|
||||
amount: Decimal
|
||||
|
||||
@Column({
|
||||
type: 'decimal',
|
||||
precision: 40,
|
||||
scale: 20,
|
||||
nullable: false,
|
||||
transformer: DecimalTransformer,
|
||||
})
|
||||
balance: Decimal
|
||||
|
||||
@Column({
|
||||
name: 'balance_date',
|
||||
type: 'datetime',
|
||||
default: () => 'CURRENT_TIMESTAMP',
|
||||
nullable: false,
|
||||
})
|
||||
balanceDate: Date
|
||||
|
||||
@Column({
|
||||
type: 'decimal',
|
||||
precision: 40,
|
||||
scale: 20,
|
||||
nullable: false,
|
||||
transformer: DecimalTransformer,
|
||||
})
|
||||
decay: Decimal
|
||||
|
||||
@Column({
|
||||
name: 'decay_start',
|
||||
type: 'datetime',
|
||||
nullable: true,
|
||||
default: null,
|
||||
})
|
||||
decayStart: Date | null
|
||||
|
||||
@Column({ length: 255, nullable: false, collation: 'utf8mb4_unicode_ci' })
|
||||
memo: string
|
||||
|
||||
@Column({ name: 'creation_date', type: 'datetime', nullable: true, default: null })
|
||||
creationDate: Date | null
|
||||
|
||||
@Column({
|
||||
name: 'linked_user_id',
|
||||
type: 'int',
|
||||
unsigned: true,
|
||||
nullable: true,
|
||||
default: null,
|
||||
})
|
||||
linkedUserId?: number | null
|
||||
|
||||
@Column({
|
||||
name: 'linked_transaction_id',
|
||||
type: 'int',
|
||||
unsigned: true,
|
||||
nullable: true,
|
||||
default: null,
|
||||
})
|
||||
linkedTransactionId?: number | null
|
||||
|
||||
@Column({
|
||||
name: 'transaction_link_id',
|
||||
type: 'int',
|
||||
unsigned: true,
|
||||
nullable: true,
|
||||
default: null,
|
||||
})
|
||||
transactionLinkId?: number | null
|
||||
}
|
||||
@ -1 +1 @@
|
||||
export { Transaction } from './0029-clean_transaction_table/Transaction'
|
||||
export { Transaction } from './0032-add-transaction-link-to-transaction/Transaction'
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
/* MIGRATION TO ADD transactionLinkId FIELDTO TRANSACTION */
|
||||
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
|
||||
await queryFn(
|
||||
'ALTER TABLE `transactions` ADD COLUMN `transaction_link_id` int UNSIGNED DEFAULT NULL AFTER `linked_transaction_id`;',
|
||||
)
|
||||
}
|
||||
|
||||
export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
|
||||
await queryFn('ALTER TABLE `transactions` DROP COLUMN `transaction_link_id`;')
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<div class="decay-information-box">
|
||||
<decay-information-before-startblock v-if="decay.start === null" />
|
||||
<decay-information-decay-startblock
|
||||
v-else-if="isStartBlock"
|
||||
:amount="amount"
|
||||
:decay="decay"
|
||||
:typeId="typeId"
|
||||
/>
|
||||
<decay-information-long v-else :amount="amount" :decay="decay" :typeId="typeId" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import DecayInformationLong from '../DecayInformations/DecayInformation-Long'
|
||||
import DecayInformationBeforeStartblock from '../DecayInformations/DecayInformation-BeforeStartblock'
|
||||
import DecayInformationDecayStartblock from '../DecayInformations/DecayInformation-DecayStartblock'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
DecayInformationLong,
|
||||
DecayInformationBeforeStartblock,
|
||||
DecayInformationDecayStartblock,
|
||||
},
|
||||
props: {
|
||||
amount: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
decay: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
typeId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
decayStartBlock: {
|
||||
type: Date,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
isStartBlock() {
|
||||
return new Date(this.decay.start).getTime() === this.decayStartBlock.getTime()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -286,18 +286,23 @@ describe('GddTransactionList', () => {
|
||||
it('has a bi-gift icon', () => {
|
||||
expect(transaction.findAll('svg').at(1).classes()).toEqual([
|
||||
'bi-gift',
|
||||
'gradido-global-color-accent',
|
||||
'm-mb-1',
|
||||
'font2em',
|
||||
'b-icon',
|
||||
'bi',
|
||||
'gradido-global-color-accent',
|
||||
])
|
||||
})
|
||||
|
||||
it('has gradido-global-color-accent color', () => {
|
||||
expect(transaction.findAll('svg').at(1).classes()).toContain(
|
||||
expect(transaction.findAll('svg').at(1).classes()).toEqual([
|
||||
'bi-gift',
|
||||
'm-mb-1',
|
||||
'font2em',
|
||||
'b-icon',
|
||||
'bi',
|
||||
'gradido-global-color-accent',
|
||||
)
|
||||
])
|
||||
})
|
||||
|
||||
// operators are renderd by GDD filter
|
||||
@ -348,11 +353,11 @@ describe('GddTransactionList', () => {
|
||||
it('has gradido-global-color-accent color', () => {
|
||||
expect(transaction.findAll('svg').at(1).classes()).toEqual([
|
||||
'bi-arrow-right-circle',
|
||||
'gradido-global-color-accent',
|
||||
'm-mb-1',
|
||||
'font2em',
|
||||
'b-icon',
|
||||
'bi',
|
||||
'gradido-global-color-accent',
|
||||
])
|
||||
})
|
||||
|
||||
@ -400,6 +405,7 @@ describe('GddTransactionList', () => {
|
||||
return {
|
||||
amount: '3.14',
|
||||
balanceDate: '2021-04-29T17:26:40+00:00',
|
||||
decay: {},
|
||||
memo: 'Kreiszahl PI',
|
||||
linkedUser: {
|
||||
firstName: 'Bibi',
|
||||
@ -418,6 +424,7 @@ describe('GddTransactionList', () => {
|
||||
transactions,
|
||||
transactionCount: 42,
|
||||
showPagination: true,
|
||||
decayStartBlock: new Date(),
|
||||
})
|
||||
paginationButtons = wrapper.find('div.pagination-buttons')
|
||||
})
|
||||
|
||||
@ -108,6 +108,10 @@ export default {
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
collaps-icon {
|
||||
width: 95%;
|
||||
position: absolute;
|
||||
}
|
||||
.el-table .cell {
|
||||
padding-left: 0px;
|
||||
padding-right: 0px;
|
||||
|
||||
44
frontend/src/components/TransactionRows/AmountAndNameRow.vue
Normal file
44
frontend/src/components/TransactionRows/AmountAndNameRow.vue
Normal file
@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<div class="amount-and-name-row">
|
||||
<b-row>
|
||||
<b-col cols="5">
|
||||
<div class="text-right">
|
||||
<span class="gdd-transaction-list-item-amount">
|
||||
{{ amount | GDD }}
|
||||
</span>
|
||||
</div>
|
||||
</b-col>
|
||||
<b-col cols="7">
|
||||
<div class="gdd-transaction-list-item-name">
|
||||
{{ itemText }}
|
||||
</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'AmountAndNameRow',
|
||||
props: {
|
||||
amount: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
linkedUser: {
|
||||
type: Object,
|
||||
required: false,
|
||||
},
|
||||
text: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
itemText() {
|
||||
return this.linkedUser
|
||||
? this.linkedUser.firstName + ' ' + this.linkedUser.lastName
|
||||
: this.text
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
19
frontend/src/components/TransactionRows/CollapseIcon.vue
Normal file
19
frontend/src/components/TransactionRows/CollapseIcon.vue
Normal file
@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<div class="collapse-icon">
|
||||
<b-icon
|
||||
:icon="visible ? 'caret-up-square' : 'caret-down-square'"
|
||||
:class="visible ? 'text-black' : 'text-muted'"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'CollapseIcon',
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
26
frontend/src/components/TransactionRows/DateRow.vue
Normal file
26
frontend/src/components/TransactionRows/DateRow.vue
Normal file
@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<div class="date-row">
|
||||
<b-row>
|
||||
<b-col cols="5">
|
||||
<div class="text-right">{{ $t('form.date') }}</div>
|
||||
</b-col>
|
||||
<b-col cols="7">
|
||||
<div class="gdd-transaction-list-item-date">
|
||||
{{ $d(new Date(balanceDate), 'long') }}
|
||||
{{ $i18n.locale === 'de' ? 'Uhr' : '' }}
|
||||
</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'DateRow',
|
||||
props: {
|
||||
balanceDate: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
31
frontend/src/components/TransactionRows/DecayRow.vue
Normal file
31
frontend/src/components/TransactionRows/DecayRow.vue
Normal file
@ -0,0 +1,31 @@
|
||||
<template>
|
||||
<div class="decay-row">
|
||||
<b-row v-if="decay">
|
||||
<b-col cols="5">
|
||||
<div class="text-right">
|
||||
<b-icon icon="droplet-half" height="15" class="mb-1" />
|
||||
</div>
|
||||
</b-col>
|
||||
<b-col cols="7">
|
||||
<div class="gdd-transaction-list-item-decay">
|
||||
<decay-information-short decaytyp="short" :decay="decay" />
|
||||
</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import DecayInformationShort from '../DecayInformations/DecayInformation-Short'
|
||||
export default {
|
||||
name: 'DecayRow',
|
||||
components: {
|
||||
DecayInformationShort,
|
||||
},
|
||||
props: {
|
||||
decay: {
|
||||
type: Object,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
23
frontend/src/components/TransactionRows/MemoRow.vue
Normal file
23
frontend/src/components/TransactionRows/MemoRow.vue
Normal file
@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<div class="memo-row">
|
||||
<b-row>
|
||||
<b-col cols="5">
|
||||
<div class="text-right">{{ $t('form.memo') }}</div>
|
||||
</b-col>
|
||||
<b-col cols="7">
|
||||
<div class="gdd-transaction-list-message">{{ memo }}</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'MemoRow',
|
||||
props: {
|
||||
memo: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
22
frontend/src/components/TransactionRows/TypeIcon.vue
Normal file
22
frontend/src/components/TransactionRows/TypeIcon.vue
Normal file
@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<div class="type-icon">
|
||||
<div class="gdd-transaction-list-item-icon">
|
||||
<b-icon :icon="icon" :class="color" class="m-mb-1 font2em" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: 'TypeIcon',
|
||||
props: {
|
||||
icon: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -2,105 +2,60 @@
|
||||
<div class="transaction-slot-creation">
|
||||
<div @click="visible = !visible">
|
||||
<!-- Collaps Icon -->
|
||||
<div class="text-right gradido-width-95-absolute">
|
||||
<b-icon
|
||||
:icon="visible ? 'caret-up-square' : 'caret-down-square'"
|
||||
:class="visible ? 'text-black' : 'text-muted'"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<collapse-icon class="text-right" :visible="visible" />
|
||||
<div>
|
||||
<b-row>
|
||||
<!-- ICON -->
|
||||
<b-col cols="1">
|
||||
<div class="gdd-transaction-list-item-icon">
|
||||
<b-icon icon="gift" class="gradido-global-color-accent m-mb-1 font2em" />
|
||||
</div>
|
||||
<type-icon color="gradido-global-color-accent" icon="gift" />
|
||||
</b-col>
|
||||
|
||||
<b-col cols="11">
|
||||
<!-- Betrag / Name Email -->
|
||||
<b-row>
|
||||
<b-col cols="5">
|
||||
<div class="text-right">
|
||||
<span class="gdd-transaction-list-item-amount">
|
||||
{{ amount | GDD }}
|
||||
</span>
|
||||
</div>
|
||||
</b-col>
|
||||
<b-col cols="7">
|
||||
<div class="gdd-transaction-list-item-name">
|
||||
{{ linkedUser.firstName + ' ' + linkedUser.lastName }}
|
||||
</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<!-- Amount / Name || Text -->
|
||||
<amount-and-name-row :amount="amount" :linkedUser="linkedUser" />
|
||||
|
||||
<!-- Nachricht Memo -->
|
||||
<b-row>
|
||||
<b-col cols="5">
|
||||
<div class="text-right">{{ $t('form.memo') }}</div>
|
||||
</b-col>
|
||||
<b-col cols="7">
|
||||
<div class="gdd-transaction-list-message">{{ memo }}</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<memo-row :memo="memo" />
|
||||
|
||||
<!-- Datum -->
|
||||
<b-row>
|
||||
<b-col cols="5">
|
||||
<div class="text-right">{{ $t('form.date') }}</div>
|
||||
</b-col>
|
||||
<b-col cols="7">
|
||||
<div class="gdd-transaction-list-item-date">
|
||||
{{ $d(new Date(balanceDate), 'long') }}
|
||||
{{ $i18n.locale === 'de' ? 'Uhr' : '' }}
|
||||
</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<date-row :balanceDate="balanceDate" />
|
||||
|
||||
<!-- Decay -->
|
||||
<b-row v-if="decay">
|
||||
<b-col cols="5">
|
||||
<div class="text-right">
|
||||
<b-icon icon="droplet-half" height="15" class="mb-1" />
|
||||
</div>
|
||||
</b-col>
|
||||
<b-col cols="7">
|
||||
<div class="gdd-transaction-list-item-decay">
|
||||
<decay-information-short decaytyp="short" :decay="decay" />
|
||||
</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<decay-row :decay="decay" />
|
||||
</b-col>
|
||||
</b-row>
|
||||
</div>
|
||||
|
||||
<b-collapse :class="visible ? 'bg-secondary' : ''" class="pb-4 pt-5" v-model="visible">
|
||||
<decay-information-before-startblock v-if="decay.start === null" />
|
||||
<decay-information-decay-startblock
|
||||
v-else-if="isStartBlock"
|
||||
:amount="amount"
|
||||
:decay="decay"
|
||||
<decay-information
|
||||
:typeId="typeId"
|
||||
:decay="decay"
|
||||
:amount="amount"
|
||||
:decayStartBlock="decayStartBlock"
|
||||
/>
|
||||
<decay-information-long v-else :amount="amount" :decay="decay" :typeId="typeId" />
|
||||
</b-collapse>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import DecayInformationShort from '../DecayInformations/DecayInformation-Short'
|
||||
import DecayInformationLong from '../DecayInformations/DecayInformation-Long'
|
||||
import DecayInformationBeforeStartblock from '../DecayInformations/DecayInformation-BeforeStartblock'
|
||||
import DecayInformationDecayStartblock from '../DecayInformations/DecayInformation-DecayStartblock'
|
||||
import CollapseIcon from '../TransactionRows/CollapseIcon'
|
||||
import TypeIcon from '../TransactionRows/TypeIcon'
|
||||
import AmountAndNameRow from '../TransactionRows/AmountAndNameRow'
|
||||
import MemoRow from '../TransactionRows/MemoRow'
|
||||
import DateRow from '../TransactionRows/DateRow'
|
||||
import DecayRow from '../TransactionRows/DecayRow'
|
||||
import DecayInformation from '../DecayInformations/DecayInformation'
|
||||
|
||||
export default {
|
||||
name: 'slot-creation',
|
||||
components: {
|
||||
DecayInformationShort,
|
||||
DecayInformationLong,
|
||||
DecayInformationBeforeStartblock,
|
||||
DecayInformationDecayStartblock,
|
||||
CollapseIcon,
|
||||
TypeIcon,
|
||||
AmountAndNameRow,
|
||||
MemoRow,
|
||||
DateRow,
|
||||
DecayRow,
|
||||
DecayInformation,
|
||||
},
|
||||
props: {
|
||||
amount: {
|
||||
|
||||
@ -2,38 +2,20 @@
|
||||
<div class="transaction-slot-decay">
|
||||
<div @click="visible = !visible">
|
||||
<!-- Collaps Icon -->
|
||||
<div class="text-right gradido-width-95-absolute">
|
||||
<b-icon
|
||||
:icon="visible ? 'caret-up-square' : 'caret-down-square'"
|
||||
:class="visible ? 'text-black' : 'text-muted'"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<collapse-icon class="text-right" :visible="visible" />
|
||||
<div>
|
||||
<b-row>
|
||||
<!-- ICON -->
|
||||
<b-col cols="1">
|
||||
<div class="gdd-transaction-list-item-icon">
|
||||
<b-icon icon="droplet-half" class="gradido-global-color-gray m-mb-1 font2em" />
|
||||
</div>
|
||||
<type-icon color="gradido-global-color-gray" icon="droplet-half" />
|
||||
</b-col>
|
||||
|
||||
<b-col cols="11">
|
||||
<!-- Betrag / Name Email -->
|
||||
<b-row>
|
||||
<b-col cols="5">
|
||||
<div class="text-right">
|
||||
<span class="gdd-transaction-list-item-amount">
|
||||
{{ amount | GDD }}
|
||||
</span>
|
||||
</div>
|
||||
</b-col>
|
||||
<b-col cols="7">
|
||||
<div class="gdd-transaction-list-item-name">
|
||||
{{ $t('decay.decay_since_last_transaction') }}
|
||||
</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<!-- Amount / Name || Text -->
|
||||
<amount-and-name-row
|
||||
:amount="amount"
|
||||
:text="$t('decay.decay_since_last_transaction')"
|
||||
/>
|
||||
</b-col>
|
||||
</b-row>
|
||||
</div>
|
||||
@ -45,11 +27,17 @@
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import CollapseIcon from '../TransactionRows/CollapseIcon'
|
||||
import TypeIcon from '../TransactionRows/TypeIcon'
|
||||
import AmountAndNameRow from '../TransactionRows/AmountAndNameRow'
|
||||
import DecayInformationDecay from '../DecayInformations/DecayInformation-Decay'
|
||||
|
||||
export default {
|
||||
name: 'slot-decay',
|
||||
components: {
|
||||
CollapseIcon,
|
||||
TypeIcon,
|
||||
AmountAndNameRow,
|
||||
DecayInformationDecay,
|
||||
},
|
||||
props: {
|
||||
@ -59,18 +47,9 @@ export default {
|
||||
balance: {
|
||||
type: String,
|
||||
},
|
||||
balanceDate: {
|
||||
type: String,
|
||||
},
|
||||
decay: {
|
||||
type: Object,
|
||||
},
|
||||
id: {
|
||||
type: Number,
|
||||
},
|
||||
typeId: {
|
||||
type: String,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
@ -2,108 +2,61 @@
|
||||
<div class="transaction-slot-receive">
|
||||
<div @click="visible = !visible">
|
||||
<!-- Collaps Icon -->
|
||||
<div class="text-right gradido-width-95-absolute">
|
||||
<b-icon
|
||||
:icon="visible ? 'caret-up-square' : 'caret-down-square'"
|
||||
:class="visible ? 'text-black' : 'text-muted'"
|
||||
/>
|
||||
</div>
|
||||
<collapse-icon class="text-right" :visible="visible" />
|
||||
|
||||
<div>
|
||||
<b-row>
|
||||
<!-- ICON -->
|
||||
<b-col cols="1">
|
||||
<div class="gdd-transaction-list-item-icon">
|
||||
<b-icon
|
||||
icon="arrow-right-circle"
|
||||
class="gradido-global-color-accent m-mb-1 font2em"
|
||||
/>
|
||||
</div>
|
||||
<type-icon color="gradido-global-color-accent" icon="arrow-right-circle" />
|
||||
</b-col>
|
||||
|
||||
<b-col cols="11">
|
||||
<!-- Betrag / Name Email -->
|
||||
<b-row>
|
||||
<b-col cols="5">
|
||||
<div class="text-right">
|
||||
<span class="gdd-transaction-list-item-amount">
|
||||
{{ amount | GDD }}
|
||||
</span>
|
||||
</div>
|
||||
</b-col>
|
||||
<b-col cols="7">
|
||||
<div class="gdd-transaction-list-item-name">
|
||||
{{ linkedUser.firstName + ' ' + linkedUser.lastName }}
|
||||
</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<!-- Amount / Name || Text -->
|
||||
<amount-and-name-row :amount="amount" :linkedUser="linkedUser" />
|
||||
|
||||
<!-- Nachricht Memo -->
|
||||
<b-row>
|
||||
<b-col cols="5">
|
||||
<div class="text-right">{{ $t('form.memo') }}</div>
|
||||
</b-col>
|
||||
<b-col cols="7">
|
||||
<div class="gdd-transaction-list-message">{{ memo }}</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<memo-row :memo="memo" />
|
||||
|
||||
<!-- Datum -->
|
||||
<b-row>
|
||||
<b-col cols="5">
|
||||
<div class="text-right">{{ $t('form.date') }}</div>
|
||||
</b-col>
|
||||
<b-col cols="7">
|
||||
<div class="gdd-transaction-list-item-date">
|
||||
{{ $d(new Date(balanceDate), 'long') }}
|
||||
{{ $i18n.locale === 'de' ? 'Uhr' : '' }}
|
||||
</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<date-row :balanceDate="balanceDate" />
|
||||
|
||||
<!-- Decay -->
|
||||
<b-row v-if="decay">
|
||||
<b-col cols="5">
|
||||
<div class="text-right">
|
||||
<b-icon icon="droplet-half" height="15" class="mb-1" />
|
||||
</div>
|
||||
</b-col>
|
||||
<b-col cols="7">
|
||||
<div class="gdd-transaction-list-item-decay">
|
||||
<decay-information-short decaytyp="short" :decay="decay" />
|
||||
</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<decay-row :decay="decay" />
|
||||
</b-col>
|
||||
</b-row>
|
||||
</div>
|
||||
|
||||
<b-collapse :class="visible ? 'bg-secondary' : ''" class="pb-4 pt-5" v-model="visible">
|
||||
<decay-information-before-startblock v-if="decay.start === null" />
|
||||
<decay-information-decay-startblock
|
||||
v-else-if="isStartBlock"
|
||||
:amount="amount"
|
||||
:decay="decay"
|
||||
<decay-information
|
||||
:typeId="typeId"
|
||||
:decay="decay"
|
||||
:amount="amount"
|
||||
:decayStartBlock="decayStartBlock"
|
||||
/>
|
||||
<decay-information-long v-else :amount="amount" :decay="decay" :typeId="typeId" />
|
||||
</b-collapse>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import DecayInformationShort from '../DecayInformations/DecayInformation-Short'
|
||||
import DecayInformationLong from '../DecayInformations/DecayInformation-Long'
|
||||
import DecayInformationBeforeStartblock from '../DecayInformations/DecayInformation-BeforeStartblock'
|
||||
import DecayInformationDecayStartblock from '../DecayInformations/DecayInformation-DecayStartblock'
|
||||
import CollapseIcon from '../TransactionRows/CollapseIcon'
|
||||
import TypeIcon from '../TransactionRows/TypeIcon'
|
||||
import AmountAndNameRow from '../TransactionRows/AmountAndNameRow'
|
||||
import MemoRow from '../TransactionRows/MemoRow'
|
||||
import DateRow from '../TransactionRows/DateRow'
|
||||
import DecayRow from '../TransactionRows/DecayRow'
|
||||
import DecayInformation from '../DecayInformations/DecayInformation'
|
||||
|
||||
export default {
|
||||
name: 'slot-receive',
|
||||
components: {
|
||||
DecayInformationShort,
|
||||
DecayInformationLong,
|
||||
DecayInformationBeforeStartblock,
|
||||
DecayInformationDecayStartblock,
|
||||
CollapseIcon,
|
||||
TypeIcon,
|
||||
AmountAndNameRow,
|
||||
MemoRow,
|
||||
DateRow,
|
||||
DecayRow,
|
||||
DecayInformation,
|
||||
},
|
||||
props: {
|
||||
amount: {
|
||||
|
||||
@ -2,104 +2,61 @@
|
||||
<div class="transaction-slot-send">
|
||||
<div @click="visible = !visible">
|
||||
<!-- Collaps Icon -->
|
||||
<div class="text-right gradido-width-95-absolute">
|
||||
<b-icon
|
||||
:icon="visible ? 'caret-up-square' : 'caret-down-square'"
|
||||
:class="visible ? 'text-black' : 'text-muted'"
|
||||
/>
|
||||
</div>
|
||||
<collapse-icon class="text-right" :visible="visible" />
|
||||
|
||||
<div>
|
||||
<b-row>
|
||||
<!-- ICON -->
|
||||
<b-col cols="1">
|
||||
<div class="gdd-transaction-list-item-icon">
|
||||
<b-icon icon="arrow-left-circle" class="text-danger m-mb-1 font2em" />
|
||||
</div>
|
||||
<type-icon color="text-danger" icon="arrow-left-circle" />
|
||||
</b-col>
|
||||
|
||||
<b-col cols="11">
|
||||
<!-- Betrag / Name Email -->
|
||||
<b-row>
|
||||
<b-col cols="5">
|
||||
<div class="text-right">
|
||||
<span class="gdd-transaction-list-item-amount">
|
||||
{{ amount | GDD }}
|
||||
</span>
|
||||
</div>
|
||||
</b-col>
|
||||
<b-col cols="7">
|
||||
<div class="gdd-transaction-list-item-name">
|
||||
{{ linkedUser.firstName + ' ' + linkedUser.lastName }}
|
||||
</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<!-- Amount / Name -->
|
||||
<amount-and-name-row :amount="amount" :linkedUser="linkedUser" />
|
||||
|
||||
<!-- Nachricht Memo -->
|
||||
<b-row>
|
||||
<b-col cols="5">
|
||||
<div class="text-right">{{ $t('form.memo') }}</div>
|
||||
</b-col>
|
||||
<b-col cols="7">
|
||||
<div class="gdd-transaction-list-message">{{ memo }}</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<!-- Memo -->
|
||||
<memo-row :memo="memo" />
|
||||
|
||||
<!-- Datum -->
|
||||
<b-row>
|
||||
<b-col cols="5">
|
||||
<div class="text-right">{{ $t('form.date') }}</div>
|
||||
</b-col>
|
||||
<b-col cols="7">
|
||||
<div class="gdd-transaction-list-item-date">
|
||||
{{ $d(new Date(balanceDate), 'long') }}
|
||||
{{ $i18n.locale === 'de' ? 'Uhr' : '' }}
|
||||
</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<date-row :balanceDate="balanceDate" />
|
||||
|
||||
<!-- Decay -->
|
||||
<b-row v-if="decay">
|
||||
<b-col cols="5">
|
||||
<div class="text-right">
|
||||
<b-icon icon="droplet-half" height="15" class="mb-1" />
|
||||
</div>
|
||||
</b-col>
|
||||
<b-col cols="7">
|
||||
<div class="gdd-transaction-list-item-decay">
|
||||
<decay-information-short decaytyp="short" :decay="decay" />
|
||||
</div>
|
||||
</b-col>
|
||||
</b-row>
|
||||
<decay-row :decay="decay" />
|
||||
</b-col>
|
||||
</b-row>
|
||||
</div>
|
||||
|
||||
<b-collapse :class="visible ? 'bg-secondary' : ''" class="pb-4 pt-5" v-model="visible">
|
||||
<decay-information-before-startblock v-if="decay.start === null" />
|
||||
<decay-information-decay-startblock
|
||||
v-else-if="isStartBlock"
|
||||
:amount="amount"
|
||||
:decay="decay"
|
||||
<decay-information
|
||||
:typeId="typeId"
|
||||
:decay="decay"
|
||||
:amount="amount"
|
||||
:decayStartBlock="decayStartBlock"
|
||||
/>
|
||||
<decay-information-long v-else :amount="amount" :decay="decay" :typeId="typeId" />
|
||||
</b-collapse>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import DecayInformationShort from '../DecayInformations/DecayInformation-Short'
|
||||
import DecayInformationLong from '../DecayInformations/DecayInformation-Long'
|
||||
import DecayInformationBeforeStartblock from '../DecayInformations/DecayInformation-BeforeStartblock'
|
||||
import DecayInformationDecayStartblock from '../DecayInformations/DecayInformation-DecayStartblock'
|
||||
import CollapseIcon from '../TransactionRows/CollapseIcon'
|
||||
import TypeIcon from '../TransactionRows/TypeIcon'
|
||||
import AmountAndNameRow from '../TransactionRows/AmountAndNameRow'
|
||||
import MemoRow from '../TransactionRows/MemoRow'
|
||||
import DateRow from '../TransactionRows/DateRow'
|
||||
import DecayRow from '../TransactionRows/DecayRow'
|
||||
import DecayInformation from '../DecayInformations/DecayInformation'
|
||||
|
||||
export default {
|
||||
name: 'slot-send',
|
||||
components: {
|
||||
DecayInformationShort,
|
||||
DecayInformationLong,
|
||||
DecayInformationBeforeStartblock,
|
||||
DecayInformationDecayStartblock,
|
||||
CollapseIcon,
|
||||
TypeIcon,
|
||||
AmountAndNameRow,
|
||||
MemoRow,
|
||||
DateRow,
|
||||
DecayRow,
|
||||
DecayInformation,
|
||||
},
|
||||
props: {
|
||||
amount: {
|
||||
@ -133,10 +90,5 @@ export default {
|
||||
visible: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isStartBlock() {
|
||||
return new Date(this.decay.start).getTime() === this.decayStartBlock.getTime()
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user