Rename 'child categories' to subcategories, code formatting

This commit is contained in:
Andrew Lalis 2026-02-12 12:11:06 -05:00
parent 6fd3e10d55
commit 711e420c61
6 changed files with 154 additions and 40 deletions

View File

@ -30,10 +30,13 @@ function goToTransaction() {
} }
</script> </script>
<template> <template>
<div class="transaction-card" @click="goToTransaction()"> <div
class="transaction-card"
@click="goToTransaction()"
>
<div> <div>
<!-- Top row contains timestamp and amount. --> <!-- Top row contains timestamp and amount. -->
<div style="display: flex; justify-content: space-between;"> <div style="display: flex; justify-content: space-between">
<div> <div>
<div class="font-mono font-size-xsmall text-normal">Transaction #{{ tx.id }}</div> <div class="font-mono font-size-xsmall text-normal">Transaction #{{ tx.id }}</div>
<div class="text-muted font-mono font-size-xsmall"> <div class="text-muted font-mono font-size-xsmall">
@ -41,16 +44,25 @@ function goToTransaction() {
</div> </div>
</div> </div>
<div> <div>
<div class="font-mono align-right font-size-small" :class="{ <div
'text-positive': moneyStyle === 'positive', class="font-mono align-right font-size-small"
'text-negative': moneyStyle === 'negative', :class="{
}"> 'text-positive': moneyStyle === 'positive',
'text-negative': moneyStyle === 'negative',
}"
>
{{ formatMoney(tx.amount, tx.currency) }} {{ formatMoney(tx.amount, tx.currency) }}
</div> </div>
<div v-if="tx.creditedAccount !== null" class="font-size-small text-muted"> <div
v-if="tx.creditedAccount !== null"
class="font-size-small text-muted"
>
Credited to <span class="text-normal font-bold">{{ tx.creditedAccount.name }}</span> Credited to <span class="text-normal font-bold">{{ tx.creditedAccount.name }}</span>
</div> </div>
<div v-if="tx.debitedAccount !== null" class="font-size-small text-muted"> <div
v-if="tx.debitedAccount !== null"
class="font-size-small text-muted"
>
Debited to <span class="text-normal font-bold">{{ tx.debitedAccount.name }}</span> Debited to <span class="text-normal font-bold">{{ tx.debitedAccount.name }}</span>
</div> </div>
</div> </div>
@ -65,13 +77,25 @@ function goToTransaction() {
<!-- Bottom row contains other links. --> <!-- Bottom row contains other links. -->
<div style="display: flex; justify-content: space-between"> <div style="display: flex; justify-content: space-between">
<div> <div>
<CategoryLabel :category="tx.category" v-if="tx.category" style="margin-left: 0" /> <CategoryLabel
:category="tx.category"
v-if="tx.category"
style="margin-left: 0"
/>
<AppBadge v-if="tx.vendor">{{ tx.vendor.name }}</AppBadge> <AppBadge v-if="tx.vendor">{{ tx.vendor.name }}</AppBadge>
</div> </div>
<div> <div>
<!-- Only show the first 3 tags, and add a "+N" badge for any more. --> <!-- Only show the first 3 tags, and add a "+N" badge for any more. -->
<TagLabel v-for="tag in tx.tags.slice(0, 3)" :key="tag" :tag="tag" /> <TagLabel
<AppBadge v-if="tx.tags.length > 3" class="text-muted">+{{ tx.tags.length - 3 }}</AppBadge> v-for="tag in tx.tags.slice(0, 3)"
:key="tag"
:tag="tag"
/>
<AppBadge
v-if="tx.tags.length > 3"
class="text-muted"
>+{{ tx.tags.length - 3 }}</AppBadge
>
</div> </div>
</div> </div>
</div> </div>

View File

@ -28,18 +28,40 @@ function incrementPage(step: number) {
<template> <template>
<div> <div>
<div v-if="page && page.totalElements > 0"> <div v-if="page && page.totalElements > 0">
<AppButton size="sm" icon="backward-step" :disabled="!page || page.isFirst" @click="updatePage(1)" /> <AppButton
size="sm"
icon="backward-step"
:disabled="!page || page.isFirst"
@click="updatePage(1)"
/>
<AppButton size="sm" icon="chevron-left" :disabled="!page || page.isFirst" @click="incrementPage(-1)" /> <AppButton
size="sm"
icon="chevron-left"
:disabled="!page || page.isFirst"
@click="incrementPage(-1)"
/>
<span style="min-width: 100px; text-align: center; display: inline-block" class="font-size-xsmall"> <span
style="min-width: 100px; text-align: center; display: inline-block"
class="font-size-xsmall"
>
Page <span class="font-bold">{{ page?.pageRequest.page }}</span> of {{ page?.totalPages }} Page <span class="font-bold">{{ page?.pageRequest.page }}</span> of {{ page?.totalPages }}
</span> </span>
<AppButton size="sm" icon="chevron-right" :disabled="!page || page.isLast" @click="incrementPage(1)" /> <AppButton
size="sm"
icon="chevron-right"
:disabled="!page || page.isLast"
@click="incrementPage(1)"
/>
<AppButton size="sm" icon="forward-step" :disabled="!page || page.isLast" <AppButton
@click="updatePage(page?.totalPages ?? 0)" /> size="sm"
icon="forward-step"
:disabled="!page || page.isLast"
@click="updatePage(page?.totalPages ?? 0)"
/>
</div> </div>
</div> </div>
</template> </template>

View File

@ -104,7 +104,7 @@ async function fetchPage(pg: number) {
</p> </p>
<div v-if="childCategories.length > 0"> <div v-if="childCategories.length > 0">
<h3>Child Categories</h3> <h3>Subcategories</h3>
<ul> <ul>
<li <li
v-for="child in childCategories" v-for="child in childCategories"
@ -120,7 +120,7 @@ async function fetchPage(pg: number) {
<div> <div>
<h3 class="mb-0">Transactions</h3> <h3 class="mb-0">Transactions</h3>
<p class="text-muted font-size-small mt-0"> <p class="text-muted font-size-small mt-0">
Below is a list of all transactions recorded with this category, or any child category. Below is a list of all transactions recorded with this category, or any subcategory.
</p> </p>
<PaginationControls <PaginationControls
:page="relatedTransactionsPage" :page="relatedTransactionsPage"

View File

@ -108,33 +108,61 @@ onMounted(async () => {
<FormGroup> <FormGroup>
<FormControl label="Chart"> <FormControl label="Chart">
<select v-model="selectedChart"> <select v-model="selectedChart">
<option v-for="ct in AnalyticsChartTypes" :key="ct.id" :value="ct"> <option
v-for="ct in AnalyticsChartTypes"
:key="ct.id"
:value="ct"
>
{{ ct.name }} {{ ct.name }}
</option> </option>
</select> </select>
</FormControl> </FormControl>
</FormGroup> </FormGroup>
<BalanceTimeSeriesChart v-if="currency && balanceTimeSeriesData && selectedChart.id === 'account-balances'" <BalanceTimeSeriesChart
title="Account Balances" :currency="currency" :time-frame="timeFrame" :data="accountBalancesData" /> v-if="currency && balanceTimeSeriesData && selectedChart.id === 'account-balances'"
title="Account Balances"
:currency="currency"
:time-frame="timeFrame"
:data="accountBalancesData"
/>
<BalanceTimeSeriesChart v-if="currency && balanceTimeSeriesData && selectedChart.id === 'total-balances'" <BalanceTimeSeriesChart
title="Total Balances" :currency="currency" :time-frame="timeFrame" :data="totalBalancesData" /> v-if="currency && balanceTimeSeriesData && selectedChart.id === 'total-balances'"
title="Total Balances"
:currency="currency"
:time-frame="timeFrame"
:data="totalBalancesData"
/>
<CategorySpendPieChart v-if="currency && categorySpendTimeSeriesData && selectedChart.id === 'category-spend'" <CategorySpendPieChart
:currency="currency" :time-frame="timeFrame" :data="categorySpendTimeSeriesData" /> v-if="currency && categorySpendTimeSeriesData && selectedChart.id === 'category-spend'"
:currency="currency"
:time-frame="timeFrame"
:data="categorySpendTimeSeriesData"
/>
<FormGroup> <FormGroup>
<FormControl label="Currency"> <FormControl label="Currency">
<select v-model="currency" :disabled="availableCurrencies.length < 2"> <select
<option v-for="currency in availableCurrencies" :key="currency.code" :value="currency"> v-model="currency"
:disabled="availableCurrencies.length < 2"
>
<option
v-for="currency in availableCurrencies"
:key="currency.code"
:value="currency"
>
{{ currency.code }} {{ currency.code }}
</option> </option>
</select> </select>
</FormControl> </FormControl>
<FormControl label="Time Frame"> <FormControl label="Time Frame">
<select v-model="timeFrame"> <select v-model="timeFrame">
<option :value="{}" selected> <option
:value="{}"
selected
>
All Time All Time
</option> </option>
<option :value="{ start: sub(new Date(), { days: 30 }) }">Last 30 days</option> <option :value="{ start: sub(new Date(), { days: 30 }) }">Last 30 days</option>

View File

@ -43,12 +43,25 @@ async function downloadData() {
} }
</script> </script>
<template> <template>
<HomeModule title="Profile" v-if="profile"> <HomeModule
title="Profile"
v-if="profile"
>
<template v-slot:default> <template v-slot:default>
<p>Your currently selected profile is: <strong>{{ profile.name }}</strong></p>
<p> <p>
<AppButton size="sm" @click="router.push(`/profiles/${profile.name}/vendors`)">Vendors</AppButton> Your currently selected profile is: <strong>{{ profile.name }}</strong>
<AppButton size="sm" @click="router.push(`/profiles/${profile.name}/categories`)">Categories</AppButton> </p>
<p>
<AppButton
size="sm"
@click="router.push(`/profiles/${profile.name}/vendors`)"
>Vendors</AppButton
>
<AppButton
size="sm"
@click="router.push(`/profiles/${profile.name}/categories`)"
>Categories</AppButton
>
</p> </p>
<ConfirmModal ref="confirmDeleteModal"> <ConfirmModal ref="confirmDeleteModal">
@ -60,9 +73,24 @@ async function downloadData() {
</ConfirmModal> </ConfirmModal>
</template> </template>
<template v-slot:actions> <template v-slot:actions>
<AppButton icon="folder-open" @click="router.push('/profiles')">Choose another profile</AppButton> <AppButton
<AppButton icon="download" @click="downloadData()" size="sm">Download Data</AppButton> icon="folder-open"
<AppButton button-style="secondary" icon="trash" @click="deleteProfile()" size="sm">Delete</AppButton> @click="router.push('/profiles')"
>Choose another profile</AppButton
>
<AppButton
icon="download"
@click="downloadData()"
size="sm"
>Download Data</AppButton
>
<AppButton
button-style="secondary"
icon="trash"
@click="deleteProfile()"
size="sm"
>Delete</AppButton
>
</template> </template>
</HomeModule> </HomeModule>
</template> </template>

View File

@ -40,13 +40,25 @@ function goToSearch() {
<template> <template>
<HomeModule title="Transactions"> <HomeModule title="Transactions">
<template v-slot:default> <template v-slot:default>
<PaginationControls :page="transactions" @update="(pr) => fetchPage(pr)" class="align-right" /> <PaginationControls
<TransactionCard v-for="tx in transactions.items" :key="tx.id" :tx="tx" /> :page="transactions"
@update="(pr) => fetchPage(pr)"
class="align-right"
/>
<TransactionCard
v-for="tx in transactions.items"
:key="tx.id"
:tx="tx"
/>
<p v-if="transactions.totalElements === 0">You haven't added any transactions.</p> <p v-if="transactions.totalElements === 0">You haven't added any transactions.</p>
</template> </template>
<template v-slot:actions> <template v-slot:actions>
<AppButton icon="plus" @click="router.push(`/profiles/${getSelectedProfile(route)}/add-transaction`)"> <AppButton
Add Transaction</AppButton> icon="plus"
@click="router.push(`/profiles/${getSelectedProfile(route)}/add-transaction`)"
>
Add Transaction</AppButton
>
<AppButton @click="goToSearch()">Search</AppButton> <AppButton @click="goToSearch()">Search</AppButton>
</template> </template>
</HomeModule> </HomeModule>