Improve account history formatting.
Build and Deploy Web App / build-and-deploy (push) Successful in 19s
Details
Build and Deploy Web App / build-and-deploy (push) Successful in 19s
Details
This commit is contained in:
parent
30764ba624
commit
efd51d7f53
|
|
@ -22,6 +22,10 @@
|
|||
font-weight: bold;
|
||||
}
|
||||
|
||||
.font-italic {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.font-size-normal {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,18 @@
|
|||
<script setup lang="ts">
|
||||
import { AccountApiClient, AccountHistoryItemType, type AccountHistoryItem, type AccountHistoryJournalEntryItem, type AccountHistoryValueRecordItem } from '@/api/account';
|
||||
import { AccountApiClient, AccountHistoryItemType, type Account, type AccountHistoryItem, type AccountHistoryJournalEntryItem, type AccountHistoryValueRecordItem } from '@/api/account';
|
||||
import type { PageRequest } from '@/api/pagination';
|
||||
import { onMounted, ref, type Ref } from 'vue';
|
||||
import ValueRecordHistoryItem from './ValueRecordHistoryItem.vue';
|
||||
import JournalEntryHistoryItem from './JournalEntryHistoryItem.vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import AppButton from '../common/AppButton.vue';
|
||||
import AppBadge from '../common/AppBadge.vue';
|
||||
import HistoryItemDivider from './HistoryItemDivider.vue';
|
||||
import { getSelectedProfile } from '@/api/profile';
|
||||
|
||||
const route = useRoute()
|
||||
const props = defineProps<{ accountId: number }>()
|
||||
const router = useRouter()
|
||||
const props = defineProps<{ account: Account }>()
|
||||
const historyItems: Ref<AccountHistoryItem[]> = ref([])
|
||||
const canLoadMore = ref(true)
|
||||
const nextPage: Ref<PageRequest> = ref({ page: 1, size: 10, sorts: [{ attribute: 'timestamp', dir: 'DESC' }] })
|
||||
|
|
@ -21,7 +24,7 @@ onMounted(async () => {
|
|||
async function loadNextPage() {
|
||||
const api = new AccountApiClient(route)
|
||||
try {
|
||||
const page = await api.getHistory(props.accountId, nextPage.value)
|
||||
const page = await api.getHistory(props.account.id, nextPage.value)
|
||||
historyItems.value.push(...page.items)
|
||||
canLoadMore.value = !page.isLast
|
||||
if (canLoadMore.value) {
|
||||
|
|
@ -56,21 +59,44 @@ function asJE(i: AccountHistoryItem): AccountHistoryJournalEntryItem {
|
|||
return i as AccountHistoryJournalEntryItem
|
||||
}
|
||||
|
||||
function canView(item: AccountHistoryItem) {
|
||||
return item.type === AccountHistoryItemType.JOURNAL_ENTRY ||
|
||||
item.type === AccountHistoryItemType.VALUE_RECORD
|
||||
}
|
||||
|
||||
function viewItem(item: AccountHistoryItem) {
|
||||
const profile = getSelectedProfile(route)
|
||||
if (item.type === AccountHistoryItemType.VALUE_RECORD) {
|
||||
router.push(`/profiles/${profile}/accounts/${props.account.id}/value-records/${asVR(item).valueRecordId}`)
|
||||
} else if (item.type === AccountHistoryItemType.JOURNAL_ENTRY) {
|
||||
router.push(`/profiles/${getSelectedProfile(route)}/transactions/${asJE(item).transactionId}`)
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({ reload })
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<div v-for="item in historyItems" :key="item.timestamp" class="history-item">
|
||||
<div class="history-item-header">
|
||||
<div class="font-mono font-size-xsmall text-muted">{{ new Date(item.timestamp).toLocaleString() }}</div>
|
||||
<div v-for="item, idx in historyItems" :key="idx">
|
||||
<div class="history-item">
|
||||
<!-- The main body on the left. -->
|
||||
<div style="flex-grow: 1;">
|
||||
<div class="font-mono font-size-xsmall text-muted" style="margin-bottom: 0.25rem;">
|
||||
{{ new Date(item.timestamp).toLocaleString() }}
|
||||
</div>
|
||||
|
||||
<ValueRecordHistoryItem v-if="item.type === AccountHistoryItemType.VALUE_RECORD" :item="asVR(item)"
|
||||
:account-id="account.id" />
|
||||
|
||||
<JournalEntryHistoryItem v-if="item.type === AccountHistoryItemType.JOURNAL_ENTRY" :item="asJE(item)" />
|
||||
</div>
|
||||
<!-- A "view item" button on the right. -->
|
||||
<div>
|
||||
<AppButton icon="eye" size="sm" @click="viewItem(item)" v-if="canView(item)">View</AppButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ValueRecordHistoryItem v-if="item.type === AccountHistoryItemType.VALUE_RECORD" :item="asVR(item)"
|
||||
:account-id="accountId" />
|
||||
|
||||
<JournalEntryHistoryItem v-if="item.type === AccountHistoryItemType.JOURNAL_ENTRY" :item="asJE(item)" />
|
||||
|
||||
<hr class="m0" />
|
||||
<HistoryItemDivider v-if="idx + 1 < historyItems.length" />
|
||||
</div>
|
||||
<div class="align-center">
|
||||
<AppButton size="md" @click="loadNextPage()" v-if="canLoadMore">Load more history...</AppButton>
|
||||
|
|
@ -81,19 +107,9 @@ defineExpose({ reload })
|
|||
</template>
|
||||
<style lang="css">
|
||||
.history-item {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
padding: 0.25rem 1rem;
|
||||
background-color: var(--bg-lighter);
|
||||
border-radius: 1rem;
|
||||
}
|
||||
|
||||
.history-item-header {
|
||||
float: right;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.history-item-content {
|
||||
padding: 0.5rem 0;
|
||||
padding: 0 0.5rem;
|
||||
margin: 1rem 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
<script setup lang="ts">
|
||||
</script>
|
||||
<template>
|
||||
<div class="history-item-divider">
|
||||
<div class="history-item-divider-line"></div>
|
||||
<div class="history-item-divider-label">
|
||||
|
||||
</div>
|
||||
<div class="history-item-divider-line"></div>
|
||||
</div>
|
||||
</template>
|
||||
<style lang="css">
|
||||
.history-item-divider {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin: 0.5rem 2rem;
|
||||
}
|
||||
|
||||
.history-item-divider-line {
|
||||
flex-grow: 1;
|
||||
background-color: var(--text-muted);
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
.history-item-divider-label {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,28 +1,24 @@
|
|||
<script setup lang="ts">
|
||||
import type { AccountHistoryJournalEntryItem } from '@/api/account'
|
||||
import { AccountJournalEntryType, type AccountHistoryJournalEntryItem } from '@/api/account'
|
||||
import { formatMoney } from '@/api/data';
|
||||
import { getSelectedProfile } from '@/api/profile';
|
||||
import { useRoute } from 'vue-router';
|
||||
import AppBadge from '../common/AppBadge.vue';
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
defineProps<{ item: AccountHistoryJournalEntryItem }>()
|
||||
</script>
|
||||
<template>
|
||||
<div class="history-item-content">
|
||||
<div>
|
||||
<RouterLink :to="`/profiles/${getSelectedProfile(route)}/transactions/${item.transactionId}`">
|
||||
Transaction #{{ item.transactionId }}
|
||||
</RouterLink>
|
||||
entered as a
|
||||
<strong>{{ item.journalEntryType.toLowerCase() }}</strong>
|
||||
for this account with a value of
|
||||
<AppBadge class="font-mono">{{ formatMoney(item.amount, item.currency) }}</AppBadge>
|
||||
<br />
|
||||
<p class="font-size-small m0 mt-1">
|
||||
{{ item.transactionDescription }}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<AppBadge class="font-mono">{{ formatMoney(item.amount, item.currency) }}</AppBadge>
|
||||
<span v-if="item.journalEntryType === AccountJournalEntryType.DEBIT" class="font-bold text-positive">
|
||||
debited
|
||||
</span>
|
||||
<span v-if="item.journalEntryType === AccountJournalEntryType.CREDIT" class="font-bold text-negative">
|
||||
credited
|
||||
</span>
|
||||
to this account via Transaction #{{ item.transactionId }}.
|
||||
|
||||
<br />
|
||||
<p class="font-size-xsmall m0 mt-1">
|
||||
<span class="text-muted">Description: </span>{{ item.transactionDescription }}
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,26 +1,16 @@
|
|||
<script setup lang="ts">
|
||||
import { type AccountHistoryValueRecordItem } from '@/api/account';
|
||||
import { formatMoney } from '@/api/data';
|
||||
import { useRoute } from 'vue-router';
|
||||
import AppBadge from '../common/AppBadge.vue';
|
||||
import { computed } from 'vue';
|
||||
import { getSelectedProfile } from '@/api/profile';
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const props = defineProps<{ item: AccountHistoryValueRecordItem, accountId: number }>()
|
||||
|
||||
const valueRecordRoute = computed(() => `/profiles/${getSelectedProfile(route)}/accounts/${props.accountId}/value-records/${props.item.valueRecordId}`)
|
||||
|
||||
defineProps<{ item: AccountHistoryValueRecordItem, accountId: number }>()
|
||||
|
||||
</script>
|
||||
<template>
|
||||
<div class="history-item-content">
|
||||
<div>
|
||||
<RouterLink :to="valueRecordRoute">Value recorded</RouterLink> as <AppBadge class="font-mono">{{
|
||||
formatMoney(item.value,
|
||||
item.currency) }}
|
||||
</AppBadge>
|
||||
</div>
|
||||
<div>
|
||||
Value recorded as <AppBadge class="font-mono">{{
|
||||
formatMoney(item.value,
|
||||
item.currency) }}
|
||||
</AppBadge>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ async function addValueRecord() {
|
|||
<AppButton icon="trash" @click="deleteAccount()">Delete</AppButton>
|
||||
</ButtonBar>
|
||||
|
||||
<AccountHistory :account-id="account.id" v-if="account" ref="history" />
|
||||
<AccountHistory :account="account" v-if="account" ref="history" />
|
||||
|
||||
<AddValueRecordModal v-if="account" :account="account" ref="addValueRecordModal" />
|
||||
</AppPage>
|
||||
|
|
|
|||
Loading…
Reference in New Issue