Clean up account page, fix onCancel for EditAccountPage.
Build and Deploy Web App / build-and-deploy (push) Successful in 20s
Details
Build and Deploy Web App / build-and-deploy (push) Successful in 20s
Details
This commit is contained in:
parent
9763fd7abe
commit
c1193d96fd
|
|
@ -9,6 +9,7 @@ export interface AccountType {
|
||||||
id: string
|
id: string
|
||||||
name: string
|
name: string
|
||||||
debitsPositive: boolean
|
debitsPositive: boolean
|
||||||
|
emoji: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class AccountTypes {
|
export abstract class AccountTypes {
|
||||||
|
|
@ -16,21 +17,25 @@ export abstract class AccountTypes {
|
||||||
id: 'CHECKING',
|
id: 'CHECKING',
|
||||||
name: 'Checking',
|
name: 'Checking',
|
||||||
debitsPositive: true,
|
debitsPositive: true,
|
||||||
|
emoji: '💵',
|
||||||
}
|
}
|
||||||
public static readonly SAVINGS: AccountType = {
|
public static readonly SAVINGS: AccountType = {
|
||||||
id: 'SAVINGS',
|
id: 'SAVINGS',
|
||||||
name: 'Savings',
|
name: 'Savings',
|
||||||
debitsPositive: true,
|
debitsPositive: true,
|
||||||
|
emoji: '💰',
|
||||||
}
|
}
|
||||||
public static readonly CREDIT_CARD: AccountType = {
|
public static readonly CREDIT_CARD: AccountType = {
|
||||||
id: 'CREDIT_CARD',
|
id: 'CREDIT_CARD',
|
||||||
name: 'Credit Card',
|
name: 'Credit Card',
|
||||||
debitsPositive: false,
|
debitsPositive: false,
|
||||||
|
emoji: '💳',
|
||||||
}
|
}
|
||||||
public static readonly BROKERAGE: AccountType = {
|
public static readonly BROKERAGE: AccountType = {
|
||||||
id: 'BROKERAGE',
|
id: 'BROKERAGE',
|
||||||
name: 'Brokerage',
|
name: 'Brokerage',
|
||||||
debitsPositive: true,
|
debitsPositive: true,
|
||||||
|
emoji: '📈',
|
||||||
}
|
}
|
||||||
|
|
||||||
public static of(id: string): AccountType {
|
public static of(id: string): AccountType {
|
||||||
|
|
|
||||||
|
|
@ -34,28 +34,18 @@ function goToAccount() {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div class="account-card" @click="goToAccount()">
|
||||||
class="account-card"
|
|
||||||
@click="goToAccount()"
|
|
||||||
>
|
|
||||||
<!-- A top row for the name on the left, and balance on the right. -->
|
<!-- A top row for the name on the left, and balance on the right. -->
|
||||||
<div class="account-card-top-row">
|
<div class="account-card-top-row">
|
||||||
<div>
|
<div>
|
||||||
<span
|
<span class="font-bold" style="margin-right: 0.5rem">{{ account.name }}</span>
|
||||||
class="font-bold"
|
|
||||||
style="margin-right: 0.5rem"
|
|
||||||
>{{ account.name }}</span
|
|
||||||
>
|
|
||||||
<span class="font-mono font-size-xsmall">#{{ account.numberSuffix }}</span>
|
<span class="font-mono font-size-xsmall">#{{ account.numberSuffix }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div class="font-mono font-size-small" :class="{
|
||||||
class="font-mono font-size-small"
|
'text-positive': isBalancePositive,
|
||||||
:class="{
|
'text-negative': isBalanceNegative,
|
||||||
'text-positive': isBalancePositive,
|
}">
|
||||||
'text-negative': isBalanceNegative,
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<span v-if="account.currentBalance !== null">
|
<span v-if="account.currentBalance !== null">
|
||||||
{{ formatMoney(account.currentBalance, account.currency) }}
|
{{ formatMoney(account.currentBalance, account.currency) }}
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -65,7 +55,7 @@ function goToAccount() {
|
||||||
</div>
|
</div>
|
||||||
<!-- A bottom row for other attributes. -->
|
<!-- A bottom row for other attributes. -->
|
||||||
<div>
|
<div>
|
||||||
<AppBadge size="sm">{{ accountType.name }}</AppBadge>
|
<AppBadge size="sm">{{ accountType.emoji }} {{ accountType.name }}</AppBadge>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { AccountApiClient, type Account } from '@/api/account'
|
import { AccountApiClient, AccountTypes, type Account } from '@/api/account'
|
||||||
import { formatMoney } from '@/api/data'
|
import { formatMoney } from '@/api/data'
|
||||||
import { getSelectedProfile } from '@/api/profile'
|
import { getSelectedProfile } from '@/api/profile'
|
||||||
import AddValueRecordModal from '@/components/AddValueRecordModal.vue'
|
import AddValueRecordModal from '@/components/AddValueRecordModal.vue'
|
||||||
|
import AppBadge from '@/components/common/AppBadge.vue'
|
||||||
import AppButton from '@/components/common/AppButton.vue'
|
import AppButton from '@/components/common/AppButton.vue'
|
||||||
import AppPage from '@/components/common/AppPage.vue'
|
import AppPage from '@/components/common/AppPage.vue'
|
||||||
import ButtonBar from '@/components/common/ButtonBar.vue'
|
import ButtonBar from '@/components/common/ButtonBar.vue'
|
||||||
import AccountHistory from '@/components/history/AccountHistory.vue'
|
import AccountHistory from '@/components/history/AccountHistory.vue'
|
||||||
import PropertiesTable from '@/components/PropertiesTable.vue'
|
import PropertiesTable from '@/components/PropertiesTable.vue'
|
||||||
import { showConfirm } from '@/util/alert'
|
import { showConfirm } from '@/util/alert'
|
||||||
import { onMounted, ref, useTemplateRef, type Ref } from 'vue'
|
import { computed, onMounted, ref, useTemplateRef, type Ref } from 'vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
@ -18,6 +19,10 @@ const router = useRouter()
|
||||||
const addValueRecordModal = useTemplateRef('addValueRecordModal')
|
const addValueRecordModal = useTemplateRef('addValueRecordModal')
|
||||||
const history = useTemplateRef('history')
|
const history = useTemplateRef('history')
|
||||||
const account: Ref<Account | null> = ref(null)
|
const account: Ref<Account | null> = ref(null)
|
||||||
|
const accountType = computed(() => {
|
||||||
|
if (account.value === null) return null
|
||||||
|
return AccountTypes.of(account.value.type)
|
||||||
|
})
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const accountId = parseInt(route.params.id as string)
|
const accountId = parseInt(route.params.id as string)
|
||||||
|
|
@ -55,70 +60,36 @@ async function addValueRecord() {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<AppPage :title="account?.name ?? ''">
|
<AppPage :title="account?.name ?? ''" v-if="account">
|
||||||
<PropertiesTable v-if="account">
|
<div>
|
||||||
<tr>
|
<AppBadge size="lg" v-if="account.currentBalance !== null" class="font-mono">
|
||||||
<th>ID</th>
|
{{ account.currency.code }} {{ formatMoney(account.currentBalance, account.currency) }}
|
||||||
<td>{{ account.id }}</td>
|
</AppBadge>
|
||||||
</tr>
|
<AppBadge size="lg" class="font-mono">#{{ account.numberSuffix }}</AppBadge>
|
||||||
|
<AppBadge size="lg" v-if="accountType" class="font-mono">
|
||||||
|
{{ accountType.emoji }} {{ accountType.name }}
|
||||||
|
</AppBadge>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>{{ account.description }}</p>
|
||||||
|
|
||||||
|
<PropertiesTable>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Created at</th>
|
<th>Created at</th>
|
||||||
<td>{{ new Date(account.createdAt).toLocaleString() }}</td>
|
<td>{{ new Date(account.createdAt).toLocaleString() }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<th>Archived</th>
|
|
||||||
<td>{{ account.archived }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Type</th>
|
|
||||||
<td>{{ account.type }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Name</th>
|
|
||||||
<td>{{ account.name }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Number Suffix</th>
|
|
||||||
<td>{{ account.numberSuffix }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Currency</th>
|
|
||||||
<td>{{ account.currency.code }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Description</th>
|
|
||||||
<td>{{ account.description }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr v-if="account.currentBalance !== null">
|
|
||||||
<th>Current Balance</th>
|
|
||||||
<td>{{ formatMoney(account.currentBalance, account.currency) }}</td>
|
|
||||||
</tr>
|
|
||||||
</PropertiesTable>
|
</PropertiesTable>
|
||||||
|
|
||||||
<ButtonBar>
|
<ButtonBar>
|
||||||
<AppButton @click="addValueRecord()">Record Value</AppButton>
|
<AppButton @click="addValueRecord()" :disabled="account.archived">Record Value</AppButton>
|
||||||
<AppButton
|
<AppButton icon="wrench" :disabled="account.archived"
|
||||||
icon="wrench"
|
@click="router.push(`/profiles/${getSelectedProfile(route)}/accounts/${account?.id}/edit`)">
|
||||||
@click="router.push(`/profiles/${getSelectedProfile(route)}/accounts/${account?.id}/edit`)"
|
Edit</AppButton>
|
||||||
>
|
<AppButton icon="trash" @click="deleteAccount()" :disabled="account.archived">Delete</AppButton>
|
||||||
Edit</AppButton
|
|
||||||
>
|
|
||||||
<AppButton
|
|
||||||
icon="trash"
|
|
||||||
@click="deleteAccount()"
|
|
||||||
>Delete</AppButton
|
|
||||||
>
|
|
||||||
</ButtonBar>
|
</ButtonBar>
|
||||||
|
|
||||||
<AccountHistory
|
<AccountHistory :account="account" v-if="account" ref="history" />
|
||||||
:account="account"
|
|
||||||
v-if="account"
|
|
||||||
ref="history"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<AddValueRecordModal
|
<AddValueRecordModal v-if="account" :account="account" ref="addValueRecordModal" />
|
||||||
v-if="account"
|
|
||||||
:account="account"
|
|
||||||
ref="addValueRecordModal"
|
|
||||||
/>
|
|
||||||
</AppPage>
|
</AppPage>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -67,27 +67,24 @@ async function doSubmit() {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onCancel() {
|
||||||
|
if (editing.value) {
|
||||||
|
router.replace(`/profiles/${getSelectedProfile(route)}/accounts/${existingAccount.value?.id}`)
|
||||||
|
} else {
|
||||||
|
router.replace(`/profiles/${getSelectedProfile(route)}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<AppPage :title="editing ? 'Edit Account' : 'Add Account'">
|
<AppPage :title="editing ? 'Edit Account' : 'Add Account'">
|
||||||
<AppForm @submit="doSubmit()">
|
<AppForm @submit="doSubmit()">
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormControl
|
<FormControl label="Account Name" style="max-width: 200px">
|
||||||
label="Account Name"
|
<input v-model="accountName" :disabled="loading" />
|
||||||
style="max-width: 200px"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
v-model="accountName"
|
|
||||||
:disabled="loading"
|
|
||||||
/>
|
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormControl label="Account Type">
|
<FormControl label="Account Type">
|
||||||
<select
|
<select id="account-type-select" v-model="accountType" :disabled="loading" required>
|
||||||
id="account-type-select"
|
|
||||||
v-model="accountType"
|
|
||||||
:disabled="loading"
|
|
||||||
required
|
|
||||||
>
|
|
||||||
<option :value="AccountTypes.CHECKING">{{ AccountTypes.CHECKING.name }}</option>
|
<option :value="AccountTypes.CHECKING">{{ AccountTypes.CHECKING.name }}</option>
|
||||||
<option :value="AccountTypes.SAVINGS">{{ AccountTypes.SAVINGS.name }}</option>
|
<option :value="AccountTypes.SAVINGS">{{ AccountTypes.SAVINGS.name }}</option>
|
||||||
<option :value="AccountTypes.CREDIT_CARD">{{ AccountTypes.CREDIT_CARD.name }}</option>
|
<option :value="AccountTypes.CREDIT_CARD">{{ AccountTypes.CREDIT_CARD.name }}</option>
|
||||||
|
|
@ -95,46 +92,24 @@ async function doSubmit() {
|
||||||
</select>
|
</select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormControl label="Currency">
|
<FormControl label="Currency">
|
||||||
<select
|
<select id="currency-select" v-model="currency" :disabled="loading" required>
|
||||||
id="currency-select"
|
|
||||||
v-model="currency"
|
|
||||||
:disabled="loading"
|
|
||||||
required
|
|
||||||
>
|
|
||||||
<option value="USD">USD</option>
|
<option value="USD">USD</option>
|
||||||
<option value="EUR">EUR</option>
|
<option value="EUR">EUR</option>
|
||||||
<option value="GBP">GBP</option>
|
<option value="GBP">GBP</option>
|
||||||
</select>
|
</select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormControl
|
<FormControl label="Account Number Suffix" style="max-width: 200px">
|
||||||
label="Account Number Suffix"
|
<input id="account-number-suffix-input" v-model="accountNumberSuffix" minlength="4" maxlength="4"
|
||||||
style="max-width: 200px"
|
:disabled="loading" required />
|
||||||
>
|
|
||||||
<input
|
|
||||||
id="account-number-suffix-input"
|
|
||||||
v-model="accountNumberSuffix"
|
|
||||||
minlength="4"
|
|
||||||
maxlength="4"
|
|
||||||
:disabled="loading"
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormControl label="Description">
|
<FormControl label="Description">
|
||||||
<textarea
|
<textarea id="description-textarea" v-model="description" :disabled="loading"></textarea>
|
||||||
id="description-textarea"
|
|
||||||
v-model="description"
|
|
||||||
:disabled="loading"
|
|
||||||
></textarea>
|
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
<FormActions
|
<FormActions @cancel="onCancel" :disabled="loading" :submit-text="editing ? 'Save' : 'Add'" />
|
||||||
@cancel="router.replace(`/profiles/${getSelectedProfile(route)}`)"
|
|
||||||
:disabled="loading"
|
|
||||||
:submit-text="editing ? 'Save' : 'Add'"
|
|
||||||
/>
|
|
||||||
</AppForm>
|
</AppForm>
|
||||||
</AppPage>
|
</AppPage>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue