mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 01:46:07 +00:00
feat(frontend): add transaction link in latest transactions (#3375)
* fix(frontend): post migration fixes * fix(frontend): align with stylelint * fix(frontend): fix tests and dashboard layout * feat(frontend): add link to transactions * feat(frontend): remove unused code * feat(frontend): let dynamic keys in translations * feat(frontend): fix stylelint * feat(frontend): add missing styles for breadcrumb --------- Co-authored-by: einhornimmond <dario.rekowski@gmx.de>
This commit is contained in:
parent
ec964020c4
commit
b69d2273ae
@ -50,7 +50,6 @@ module.exports = {
|
||||
'vue/v-on-event-hyphenation': 0, // TODO remove at the end of migration and fix
|
||||
'vue/require-default-prop': 0, // TODO remove at the end of migration and fix
|
||||
'vue/no-computed-properties-in-data': 0, // TODO remove at the end of migration and fix
|
||||
'@intlify/vue-i18n/no-dynamic-keys': 'error',
|
||||
'@intlify/vue-i18n/no-missing-keys': 0, // TODO remove at the end of migration and fix
|
||||
'@intlify/vue-i18n/no-unused-keys': [
|
||||
'error',
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="breadcrumb bg-transparent">
|
||||
<div class="page-breadcrumb breadcrumb bg-transparent">
|
||||
<h1>{{ pageTitle }}</h1>
|
||||
</div>
|
||||
</template>
|
||||
@ -17,3 +17,10 @@ export default {
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page-breadcrumb {
|
||||
margin-bottom: 1rem;
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -24,27 +24,18 @@
|
||||
</transaction-list-item>
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
<div v-for="({ id, typeId }, index) in transactions" :key="`l2-` + id">
|
||||
<div v-for="transaction in transactions" :key="`l2-` + transaction.id">
|
||||
<transaction-list-item
|
||||
v-if="typeId !== 'DECAY'"
|
||||
:type-id="typeId"
|
||||
v-if="transaction.typeId !== 'DECAY'"
|
||||
:type-id="transaction.typeId"
|
||||
class="pointer mb-3 bg-white app-box-shadow gradido-border-radius p-3 test-list-group-item"
|
||||
>
|
||||
<template #SEND>
|
||||
<transaction-send v-bind="transactions[index]" />
|
||||
<template v-if="transaction.typeId !== 'LINK_SUMMARY'" #item>
|
||||
<gdd-transaction :transaction="transaction" />
|
||||
</template>
|
||||
|
||||
<template #RECEIVE>
|
||||
<transaction-receive v-bind="transactions[index]" />
|
||||
</template>
|
||||
|
||||
<template #CREATION>
|
||||
<transaction-creation v-bind="transactions[index]" />
|
||||
</template>
|
||||
|
||||
<template #LINK_SUMMARY>
|
||||
<template v-else #LINK_SUMMARY>
|
||||
<transaction-link-summary
|
||||
v-bind="transactions[index]"
|
||||
v-bind="transaction"
|
||||
:transaction-link-count="transactionLinkCount"
|
||||
@update-transactions="updateTransactions"
|
||||
/>
|
||||
@ -75,19 +66,15 @@
|
||||
<script>
|
||||
import TransactionListItem from '@/components/TransactionListItem'
|
||||
import TransactionDecay from '@/components/Transactions/TransactionDecay'
|
||||
import TransactionSend from '@/components/Transactions/TransactionSend'
|
||||
import TransactionReceive from '@/components/Transactions/TransactionReceive'
|
||||
import TransactionCreation from '@/components/Transactions/TransactionCreation'
|
||||
import TransactionLinkSummary from '@/components/Transactions/TransactionLinkSummary'
|
||||
import GddTransaction from '@/components/Transactions/GddTransaction.vue'
|
||||
|
||||
export default {
|
||||
name: 'GddTransactionList',
|
||||
components: {
|
||||
GddTransaction,
|
||||
TransactionListItem,
|
||||
TransactionDecay,
|
||||
TransactionSend,
|
||||
TransactionReceive,
|
||||
TransactionCreation,
|
||||
TransactionLinkSummary,
|
||||
},
|
||||
props: {
|
||||
|
||||
@ -140,3 +140,9 @@ button.navbar-toggler > span.navbar-toggler-icon {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style scoped>
|
||||
:deep(.container-fluid) {
|
||||
padding: 0 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -4,17 +4,8 @@
|
||||
<BCol class="h3">{{ $t('transaction.lastTransactions') }}</BCol>
|
||||
</BRow>
|
||||
|
||||
<div v-for="(transaction, index) in transactions" :key="transaction.id">
|
||||
<BRow
|
||||
v-if="
|
||||
index <= 8 &&
|
||||
transaction.typeId !== 'DECAY' &&
|
||||
transaction.typeId !== 'LINK_SUMMARY' &&
|
||||
transaction.typeId !== 'CREATION'
|
||||
"
|
||||
align-v="center"
|
||||
class="mb-4"
|
||||
>
|
||||
<div v-for="transaction in filteredTransactions" :key="transaction.id">
|
||||
<BRow align-v="center" class="mb-4">
|
||||
<BCol cols="auto">
|
||||
<div class="align-items-center">
|
||||
<avatar
|
||||
@ -31,14 +22,19 @@
|
||||
<div class="fw-bold">
|
||||
<name :linked-user="transaction.linkedUser" font-color="text-dark" />
|
||||
</div>
|
||||
<div class="d-flex mt-3">
|
||||
<div class="small">
|
||||
<button
|
||||
class="transaction-details-link d-flex mt-3"
|
||||
role="link"
|
||||
:data-href="`/transactions#transaction-${transaction.id}`"
|
||||
@click="handleRedirect(transaction.id)"
|
||||
>
|
||||
<span class="small">
|
||||
{{ $filters.GDD(transaction.amount) }}
|
||||
</div>
|
||||
<div class="small ms-3 text-end">
|
||||
</span>
|
||||
<span class="small ms-3 text-end">
|
||||
{{ $d(new Date(transaction.balanceDate), 'short') }}
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</button>
|
||||
</BCol>
|
||||
</BRow>
|
||||
</BCol>
|
||||
@ -46,23 +42,50 @@
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
<script setup>
|
||||
import Avatar from 'vue-avatar'
|
||||
import Name from '@/components/TransactionRows/Name'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { useStore } from 'vuex'
|
||||
import { computed } from 'vue'
|
||||
const props = defineProps({
|
||||
transactions: {
|
||||
default: () => [],
|
||||
type: Array,
|
||||
},
|
||||
})
|
||||
|
||||
export default {
|
||||
name: 'LastTransactions',
|
||||
components: {
|
||||
Avatar,
|
||||
Name,
|
||||
},
|
||||
props: {
|
||||
transactions: {
|
||||
default: () => [],
|
||||
type: Array,
|
||||
},
|
||||
transactionCount: { type: Number, default: 0 },
|
||||
transactionLinkCount: { type: Number, default: 0 },
|
||||
},
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const store = useStore()
|
||||
|
||||
const handleRedirect = (id) => {
|
||||
store.dispatch('changeTransactionToHighlightId', id)
|
||||
if (route.name !== 'Transactions') router.replace({ name: 'Transactions' })
|
||||
}
|
||||
|
||||
const filteredTransactions = computed(() => {
|
||||
return props.transactions
|
||||
.filter(
|
||||
(transaction) =>
|
||||
transaction.typeId !== 'DECAY' &&
|
||||
transaction.typeId !== 'LINK_SUMMARY' &&
|
||||
transaction.typeId !== 'CREATION',
|
||||
)
|
||||
.slice(0, 8)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.transaction-details-link {
|
||||
color: var(--bs-body-color) !important;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
border-bottom: 1px solid transparent;
|
||||
transition: border-bottom-color 0.15s ease-in-out;
|
||||
}
|
||||
|
||||
.transaction-details-link:hover {
|
||||
border-color: #383838;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -245,6 +245,7 @@ import { BAvatar, BCol, BCollapse, BRow } from 'bootstrap-vue-next'
|
||||
import TransactionCollapse from '@/components/TransactionCollapse.vue'
|
||||
import { GdtEntryType } from '@/graphql/enums'
|
||||
import VariantIcon from '@/components/VariantIcon.vue'
|
||||
import { createStore } from 'vuex'
|
||||
|
||||
const mockToastError = vi.fn()
|
||||
vi.mock('@/composables/useToast', () => ({
|
||||
@ -268,6 +269,13 @@ describe('Transaction', () => {
|
||||
const Wrapper = () => {
|
||||
return mount(Transaction, {
|
||||
global: {
|
||||
plugins: [
|
||||
createStore({
|
||||
state: {
|
||||
transactionToHighlightId: '',
|
||||
},
|
||||
}),
|
||||
],
|
||||
mocks: {
|
||||
$d: (value) => value?.toString() ?? '',
|
||||
$n: (value) => value?.toString() ?? '',
|
||||
|
||||
@ -49,11 +49,12 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, getCurrentInstance } from 'vue'
|
||||
import { ref, computed, onMounted, getCurrentInstance, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import CollapseIcon from './TransactionRows/CollapseIcon'
|
||||
import TransactionCollapse from './TransactionCollapse'
|
||||
import { GdtEntryType } from '../graphql/enums'
|
||||
import { useStore } from 'vuex'
|
||||
|
||||
const props = defineProps({
|
||||
amount: Number,
|
||||
@ -71,10 +72,14 @@ const props = defineProps({
|
||||
const collapseStatus = ref([])
|
||||
const visible = ref(false)
|
||||
|
||||
const store = useStore()
|
||||
|
||||
const { t, n } = useI18n()
|
||||
|
||||
const collapseId = computed(() => 'gdt-collapse-' + String(props.id))
|
||||
|
||||
const transactionToHighlightId = computed(() => store.state.transactionToHighlightId)
|
||||
|
||||
const getLinesByType = computed(() => {
|
||||
switch (props.gdtEntryType) {
|
||||
case GdtEntryType.FORM:
|
||||
@ -116,6 +121,12 @@ const getLinesByType = computed(() => {
|
||||
}
|
||||
})
|
||||
|
||||
watch(transactionToHighlightId, () => {
|
||||
if (parseInt(transactionToHighlightId.value) === props.id) {
|
||||
visible.value = true
|
||||
}
|
||||
})
|
||||
|
||||
// onMounted(() => {
|
||||
// // Note: This event listener setup might need to be adjusted for Vue 3
|
||||
// const root = getCurrentInstance().appContext.config.globalProperties
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<slot name="item" />
|
||||
<slot :name="typeId"></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
167
frontend/src/components/Transactions/GddTransaction.vue
Normal file
167
frontend/src/components/Transactions/GddTransaction.vue
Normal file
@ -0,0 +1,167 @@
|
||||
<template>
|
||||
<div
|
||||
:id="`transaction-${props.transaction.id}`"
|
||||
ref="gddTransaction"
|
||||
:class="`transaction-slot-${props.transaction.type}`"
|
||||
:data-transaction-id="`transaction-${props.transaction.id}`"
|
||||
@click="toggleVisible"
|
||||
>
|
||||
<BRow class="align-items-center">
|
||||
<BCol cols="3" lg="2" md="2">
|
||||
<component :is="avatarComponent" v-bind="avatarProps">
|
||||
<variant-icon v-if="isCreationType" icon="gift" variant="white" />
|
||||
</component>
|
||||
</BCol>
|
||||
<BCol>
|
||||
<div>
|
||||
<component :is="nameComponent" v-bind="nameProps" />
|
||||
</div>
|
||||
<span class="small">{{ $d(new Date(props.transaction.balanceDate), 'short') }}</span>
|
||||
<span class="ms-4 small">{{ $d(new Date(props.transaction.balanceDate), 'time') }}</span>
|
||||
</BCol>
|
||||
<BCol cols="8" lg="3" md="3" sm="8" offset="3" offset-md="0" offset-lg="0">
|
||||
<div class="small mb-2">
|
||||
{{ $t(`decay.types.${props.transaction.typeId.toLowerCase()}`) }}
|
||||
</div>
|
||||
<div
|
||||
:class="[
|
||||
'fw-bold',
|
||||
{
|
||||
'gradido-global-color-accent': props.transaction.typeId === 'RECEIVE',
|
||||
'text-140': props.transaction.typeId === 'SEND',
|
||||
},
|
||||
]"
|
||||
data-test="transaction-amount"
|
||||
>
|
||||
{{ $filters.GDD(props.transaction.amount) }}
|
||||
</div>
|
||||
<div v-if="props.transaction.linkId" class="small">
|
||||
{{ $t('via_link') }}
|
||||
<variant-icon icon="link45deg" variant="muted" class="m-mb-1" />
|
||||
</div>
|
||||
</BCol>
|
||||
<BCol cols="12" md="1" lg="1" class="text-end">
|
||||
<collapse-icon class="text-end" :visible="visible" />
|
||||
</BCol>
|
||||
</BRow>
|
||||
<BCollapse :model-value="visible" class="pb-4 pt-lg-3">
|
||||
<decay-information
|
||||
:type-id="props.transaction.typeId"
|
||||
:decay="props.transaction.decay"
|
||||
:amount="props.transaction.amount"
|
||||
:memo="props.transaction.memo"
|
||||
:balance="props.transaction.balance"
|
||||
:previous-balance="props.transaction.previousBalance"
|
||||
/>
|
||||
</BCollapse>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import Avatar from 'vue-avatar'
|
||||
import CollapseIcon from '../TransactionRows/CollapseIcon'
|
||||
import Name from '../TransactionRows/Name'
|
||||
import DecayInformation from '../DecayInformations/DecayInformation'
|
||||
import { BAvatar, BRow } from 'bootstrap-vue-next'
|
||||
|
||||
const props = defineProps({
|
||||
transaction: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
const gddTransaction = ref(null)
|
||||
|
||||
const store = useStore()
|
||||
const visible = ref(false)
|
||||
|
||||
const toggleVisible = () => {
|
||||
visible.value = !visible.value
|
||||
}
|
||||
|
||||
const username = computed(() => ({
|
||||
username: `${props.transaction?.linkedUser?.firstName} ${props.transaction?.linkedUser?.lastName}`,
|
||||
initials: `${props.transaction?.linkedUser?.firstName[0]}${props.transaction.linkedUser?.lastName[0]}`,
|
||||
}))
|
||||
|
||||
const isCreationType = computed(() => {
|
||||
return props.transaction.typeId === 'CREATION'
|
||||
})
|
||||
|
||||
const avatarComponent = computed(() => {
|
||||
return isCreationType.value ? BAvatar : Avatar
|
||||
})
|
||||
|
||||
const avatarProps = computed(() => {
|
||||
if (isCreationType.value) {
|
||||
return {
|
||||
size: 42,
|
||||
rounded: 'lg',
|
||||
variant: 'success',
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
username: username.value.username,
|
||||
initials: username.value.initials,
|
||||
color: '#fff',
|
||||
size: 42,
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const nameComponent = computed(() => {
|
||||
return isCreationType.value ? 'div' : Name
|
||||
})
|
||||
|
||||
const nameProps = computed(() => {
|
||||
if (isCreationType.value) {
|
||||
return {
|
||||
class: 'fw-bold',
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
class: 'fw-bold',
|
||||
amount: props.transaction.amount,
|
||||
linkedUser: props.transaction.linkedUser,
|
||||
linkId: props.transaction.linkId,
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const handleOpenAfterScroll = (scrollY) => {
|
||||
const handleScrollEnd = () => {
|
||||
window.removeEventListener('scrollend', handleScrollEnd)
|
||||
}
|
||||
|
||||
window.addEventListener('scrollend', handleScrollEnd)
|
||||
window.scrollTo(0, scrollY)
|
||||
}
|
||||
|
||||
const transactionToHighlightId = computed(() => store.state.transactionToHighlightId)
|
||||
|
||||
watch(
|
||||
transactionToHighlightId,
|
||||
async (newValue) => {
|
||||
if (parseInt(newValue) === props.transaction.id) {
|
||||
visible.value = true
|
||||
setTimeout(() => {
|
||||
const element = document.getElementById(`transaction-${props.transaction.id}`)
|
||||
const yVal = element.getBoundingClientRect().top + window.pageYOffset - 16
|
||||
handleOpenAfterScroll(yVal)
|
||||
}, 300)
|
||||
await store.dispatch('changeTransactionToHighlightId', '')
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.b-avatar-custom > svg) {
|
||||
height: 2em;
|
||||
width: 2em;
|
||||
}
|
||||
</style>
|
||||
@ -309,6 +309,7 @@ const setVisible = (bool) => {
|
||||
<style>
|
||||
.breadcrumb {
|
||||
background-color: transparent;
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
|
||||
.main-page {
|
||||
|
||||
@ -48,7 +48,6 @@ const transactionsGdt = ref([])
|
||||
const transactionGdtCount = ref(0)
|
||||
const currentPage = ref(1)
|
||||
const pageSize = ref(25)
|
||||
// const tabIndex = ref(0)
|
||||
|
||||
const { toastError } = useAppToast()
|
||||
|
||||
|
||||
@ -38,6 +38,7 @@ const routes = [
|
||||
// },
|
||||
// },
|
||||
{
|
||||
name: 'Transactions',
|
||||
path: '/transactions',
|
||||
component: () => import('@/pages/Transactions'),
|
||||
props: { gdt: false },
|
||||
|
||||
@ -75,6 +75,9 @@ export const mutations = {
|
||||
redirectPath: (state, redirectPath) => {
|
||||
state.redirectPath = redirectPath || '/overview'
|
||||
},
|
||||
setTransactionToHighlightId: (state, id) => {
|
||||
state.transactionToHighlightId = id
|
||||
},
|
||||
}
|
||||
|
||||
export const actions = {
|
||||
@ -119,6 +122,9 @@ export const actions = {
|
||||
commit('redirectPath', '/overview')
|
||||
localStorage.clear()
|
||||
},
|
||||
changeTransactionToHighlightId({ commit }, id) {
|
||||
commit('setTransactionToHighlightId', id)
|
||||
},
|
||||
}
|
||||
|
||||
let store
|
||||
@ -153,6 +159,7 @@ try {
|
||||
email: '',
|
||||
darkMode: false,
|
||||
redirectPath: '/overview',
|
||||
transactionToHighlightId: '',
|
||||
},
|
||||
getters: {},
|
||||
// Synchronous mutation of the state
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user