Clean up profile handling again!
This commit is contained in:
parent
a674421337
commit
074b4ded1d
|
|
@ -1,3 +1,4 @@
|
|||
import { type RouteLocation } from 'vue-router'
|
||||
import { ApiClient } from './base'
|
||||
import type { Currency } from './data'
|
||||
import type { Page, PageRequest } from './pagination'
|
||||
|
|
@ -125,9 +126,9 @@ export interface AccountHistoryJournalEntryItem extends AccountHistoryItem {
|
|||
export class AccountApiClient extends ApiClient {
|
||||
readonly path: string
|
||||
|
||||
constructor() {
|
||||
constructor(route: RouteLocation) {
|
||||
super()
|
||||
this.path = `/profiles/${getSelectedProfile()}/accounts`
|
||||
this.path = `/profiles/${getSelectedProfile(route)}/accounts`
|
||||
}
|
||||
|
||||
getAccounts(): Promise<Account[]> {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useRoute, type RouteLocation } from 'vue-router'
|
||||
import { type RouteLocation } from 'vue-router'
|
||||
import { ApiClient } from './base'
|
||||
|
||||
export interface Profile {
|
||||
|
|
@ -35,11 +35,10 @@ export class ProfileApiClient extends ApiClient {
|
|||
/**
|
||||
* Gets the currently selected profile. Throws an error in any case where
|
||||
* the route doesn't contain profile name information.
|
||||
* @param route The route to get the profile from. Defaults to getting it from
|
||||
* Vue's `useRoute()` which is available in component contexts.
|
||||
* @param route The route to get the profile from.
|
||||
* @returns The currently selected profile name, via the current route.
|
||||
*/
|
||||
export function getSelectedProfile(route: RouteLocation = useRoute()): string {
|
||||
export function getSelectedProfile(route: RouteLocation): string {
|
||||
if (!('profileName' in route.params)) {
|
||||
throw new Error('No "profileName" route property available.')
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { ApiClient } from './base'
|
||||
import type { Currency } from './data'
|
||||
import { type Page, type PageRequest } from './pagination'
|
||||
import { getSelectedProfile } from './profile'
|
||||
|
||||
export interface TransactionVendor {
|
||||
id: number
|
||||
|
|
@ -144,9 +143,9 @@ export interface CreateCategoryPayload {
|
|||
export class TransactionApiClient extends ApiClient {
|
||||
readonly path: string
|
||||
|
||||
constructor() {
|
||||
constructor(profileName: string) {
|
||||
super()
|
||||
this.path = `/profiles/${getSelectedProfile()}`
|
||||
this.path = `/profiles/${profileName}`
|
||||
}
|
||||
|
||||
getVendors(): Promise<TransactionVendor[]> {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ import AppButton from './AppButton.vue';
|
|||
import { AccountApiClient, AccountValueRecordType, type Account, type AccountValueRecord, type AccountValueRecordCreationPayload } from '@/api/account';
|
||||
import { datetimeLocalToISO, getDatetimeLocalValueForNow } from '@/util/time';
|
||||
import FileSelector from './FileSelector.vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
const route = useRoute()
|
||||
const props = defineProps<{ account: Account }>()
|
||||
const modal = useTemplateRef('modal')
|
||||
const savedValueRecord: Ref<AccountValueRecord | undefined> = ref(undefined)
|
||||
|
|
@ -36,7 +38,7 @@ async function addValueRecord() {
|
|||
type: AccountValueRecordType.BALANCE,
|
||||
value: amount.value
|
||||
}
|
||||
const api = new AccountApiClient()
|
||||
const api = new AccountApiClient(route)
|
||||
try {
|
||||
savedValueRecord.value = await api.createValueRecord(props.account.id, payload, attachments.value)
|
||||
modal.value?.close('saved')
|
||||
|
|
|
|||
|
|
@ -1,17 +1,35 @@
|
|||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
|
||||
defineProps<{
|
||||
buttonStyle?: string,
|
||||
|
||||
export type ButtonTheme = "primary" | "secondary"
|
||||
export type ButtonType = "button" | "submit" | "reset"
|
||||
export type ButtonSize = "sm" | "md" | "lg"
|
||||
|
||||
interface Props {
|
||||
theme?: ButtonTheme,
|
||||
size?: ButtonSize,
|
||||
icon?: string,
|
||||
buttonType?: "button" | "submit" | "reset" | undefined,
|
||||
type?: ButtonType,
|
||||
disabled?: boolean
|
||||
}>()
|
||||
}
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
buttonStyle: "primary",
|
||||
buttonType: "button",
|
||||
size: "md",
|
||||
disabled: false
|
||||
})
|
||||
defineEmits(['click'])
|
||||
|
||||
const buttonStyle = computed(() => ({
|
||||
'app-button-theme-secondary': props.theme === "secondary",
|
||||
'app-button-disabled': props.disabled,
|
||||
'app-button-size-sm': props.size === "sm",
|
||||
'app-button-size-lg': props.size === "lg"
|
||||
}))
|
||||
</script>
|
||||
<template>
|
||||
<button class="app-button"
|
||||
:class="{ 'app-button-secondary': buttonStyle === 'secondary', 'app-button-disabled': disabled ?? false }"
|
||||
@click="$emit('click')" :type="buttonType" :disabled="disabled ?? false">
|
||||
<button class="app-button" :class="buttonStyle" :type="type" :disabled="disabled" @click="$emit('click')">
|
||||
<span v-if="icon">
|
||||
<font-awesome-icon :icon="'fa-' + icon"
|
||||
:class="{ 'app-button-icon-with-text': $slots.default !== undefined, 'app-button-icon-without-text': $slots.default === undefined }"></font-awesome-icon>
|
||||
|
|
@ -51,6 +69,17 @@ defineEmits(['click'])
|
|||
cursor: inherit;
|
||||
}
|
||||
|
||||
.app-button-size-sm {
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.app-button-size-lg {
|
||||
padding: 1rem 2rem;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.app-button:hover:not(.app-button-disabled) {
|
||||
background-color: #374151;
|
||||
}
|
||||
|
|
@ -65,13 +94,7 @@ defineEmits(['click'])
|
|||
background-color: #3b4968;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.app-button {
|
||||
padding: .75rem 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.app-button-secondary {
|
||||
.app-button-theme-secondary {
|
||||
background-color: #1d2330;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
<script setup lang="ts">
|
||||
import { getSelectedProfile } from '@/api/profile';
|
||||
import type { TransactionCategory } from '@/api/transaction';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const props = defineProps<{ category: TransactionCategory, clickable?: boolean }>()
|
||||
|
||||
function onClicked() {
|
||||
if (props.clickable) {
|
||||
router.push(`/profiles/${getSelectedProfile()}/categories`)
|
||||
router.push(`/profiles/${getSelectedProfile(route)}/categories`)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
<script setup lang="ts">
|
||||
import { getSelectedProfile } from '@/api/profile';
|
||||
import { TransactionApiClient, type TransactionCategoryTree } from '@/api/transaction';
|
||||
import { onMounted, ref, type Ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
|
||||
const route = useRoute()
|
||||
const model = defineModel<number | null>({ required: true })
|
||||
defineProps<{ required?: boolean }>()
|
||||
defineEmits<{ categorySelected: [TransactionCategoryTree | null] }>()
|
||||
const categories: Ref<TransactionCategoryTree[]> = ref([])
|
||||
|
||||
onMounted(() => {
|
||||
const api = new TransactionApiClient()
|
||||
const api = new TransactionApiClient(getSelectedProfile(route))
|
||||
api.getCategoriesFlattened()
|
||||
.then(c => categories.value = c)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -7,7 +7,10 @@ import FormGroup from './form/FormGroup.vue';
|
|||
import FormControl from './form/FormControl.vue';
|
||||
import AppButton from './AppButton.vue';
|
||||
import CategorySelect from './CategorySelect.vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { getSelectedProfile } from '@/api/profile';
|
||||
|
||||
const route = useRoute()
|
||||
const props = defineProps<{
|
||||
category?: TransactionCategory
|
||||
}>()
|
||||
|
|
@ -52,7 +55,7 @@ function canSave() {
|
|||
}
|
||||
|
||||
async function doSave() {
|
||||
const api = new TransactionApiClient()
|
||||
const api = new TransactionApiClient(getSelectedProfile(route))
|
||||
const payload = {
|
||||
name: name.value.trim(),
|
||||
description: description.value.trim(),
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@ import FormGroup from './form/FormGroup.vue';
|
|||
import ModalWrapper from './ModalWrapper.vue';
|
||||
import { TransactionApiClient, type TransactionVendor } from '@/api/transaction';
|
||||
import AppButton from './AppButton.vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { getSelectedProfile } from '@/api/profile';
|
||||
|
||||
const route = useRoute()
|
||||
const props = defineProps<{
|
||||
vendor?: TransactionVendor
|
||||
}>()
|
||||
|
|
@ -35,7 +38,7 @@ function canSave() {
|
|||
}
|
||||
|
||||
async function doSave() {
|
||||
const api = new TransactionApiClient()
|
||||
const api = new TransactionApiClient(getSelectedProfile(route))
|
||||
const payload = {
|
||||
name: name.value.trim(),
|
||||
description: description.value.trim()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import type { Page, PageRequest } from '@/api/pagination';
|
||||
import AppButton from './AppButton.vue';
|
||||
|
||||
|
||||
const props = defineProps<{ page?: Page<unknown> }>()
|
||||
|
|
@ -27,22 +28,24 @@ function incrementPage(step: number) {
|
|||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<button :disabled="!page || page.isFirst" @click="updatePage(1)">
|
||||
<div v-if="page && page.totalElements > 0">
|
||||
<AppButton size="sm" :disabled="!page || page.isFirst" @click="updatePage(1)">
|
||||
First Page
|
||||
</button>
|
||||
</AppButton>
|
||||
|
||||
<button :disabled="!page || page.isFirst" @click="incrementPage(-1)">
|
||||
<AppButton size="sm" :disabled="!page || page.isFirst" @click="incrementPage(-1)">
|
||||
Previous Page
|
||||
</button>
|
||||
</AppButton>
|
||||
|
||||
<span>Page {{ page?.pageRequest.page }} / {{ page?.totalPages }}</span>
|
||||
|
||||
<button :disabled="!page || page.isLast" @click="incrementPage(1)">
|
||||
<AppButton size="sm" :disabled="!page || page.isLast" @click="incrementPage(1)">
|
||||
Next Page
|
||||
</button>
|
||||
</AppButton>
|
||||
|
||||
<button :disabled="!page || page.isLast" @click="updatePage(page?.totalPages ?? 0)">
|
||||
<AppButton size="sm" :disabled="!page || page.isLast" @click="updatePage(page?.totalPages ?? 0)">
|
||||
Last Page
|
||||
</button>
|
||||
</AppButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -4,13 +4,15 @@ 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';
|
||||
|
||||
const route = useRoute()
|
||||
const props = defineProps<{ accountId: number }>()
|
||||
const historyItems: Ref<AccountHistoryItem[]> = ref([])
|
||||
|
||||
onMounted(async () => {
|
||||
const pageRequest: PageRequest = { page: 1, size: 10, sorts: [{ attribute: 'timestamp', dir: 'DESC' }] }
|
||||
const api = new AccountApiClient()
|
||||
const api = new AccountApiClient(route)
|
||||
while (true) {
|
||||
try {
|
||||
const page = await api.getHistory(props.accountId, pageRequest)
|
||||
|
|
|
|||
|
|
@ -2,13 +2,16 @@
|
|||
import type { AccountHistoryJournalEntryItem } from '@/api/account'
|
||||
import { formatMoney } from '@/api/data';
|
||||
import { getSelectedProfile } from '@/api/profile';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
defineProps<{ item: AccountHistoryJournalEntryItem }>()
|
||||
</script>
|
||||
<template>
|
||||
<div class="history-item-content">
|
||||
<div>
|
||||
<RouterLink :to="`/profiles/${getSelectedProfile()}/transactions/${item.transactionId}`">
|
||||
<RouterLink :to="`/profiles/${getSelectedProfile(route)}/transactions/${item.transactionId}`">
|
||||
Transaction #{{ item.transactionId }}
|
||||
</RouterLink>
|
||||
entered as a
|
||||
|
|
|
|||
|
|
@ -3,13 +3,16 @@ import { AccountApiClient, type AccountHistoryValueRecordItem } from '@/api/acco
|
|||
import { formatMoney } from '@/api/data';
|
||||
import AppButton from '../AppButton.vue';
|
||||
import { showConfirm } from '@/util/alert';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const props = defineProps<{ item: AccountHistoryValueRecordItem, accountId: number }>()
|
||||
|
||||
async function deleteValueRecord(id: number) {
|
||||
const confirm = await showConfirm('Are you sure you want to delete this value record?')
|
||||
if (!confirm) return
|
||||
const api = new AccountApiClient()
|
||||
const api = new AccountApiClient(route)
|
||||
try {
|
||||
await api.deleteValueRecord(props.accountId, id)
|
||||
} catch (err) {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ const account: Ref<Account | null> = ref(null)
|
|||
onMounted(async () => {
|
||||
const accountId = parseInt(route.params.id as string)
|
||||
try {
|
||||
const api = new AccountApiClient()
|
||||
const api = new AccountApiClient(route)
|
||||
account.value = await api.getAccount(accountId)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
|
|
@ -32,9 +32,9 @@ async function deleteAccount() {
|
|||
if (!account.value) return
|
||||
if (await showConfirm('Are you sure you want to delete this account? This will permanently remove the account and all associated transactions.')) {
|
||||
try {
|
||||
const api = new AccountApiClient()
|
||||
const api = new AccountApiClient(route)
|
||||
await api.deleteAccount(account.value.id)
|
||||
await router.replace(`/profiles/${getSelectedProfile()}`)
|
||||
await router.replace(`/profiles/${getSelectedProfile(route)}`)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
|
|
@ -90,7 +90,8 @@ async function addValueRecord() {
|
|||
</PropertiesTable>
|
||||
<div>
|
||||
<AppButton @click="addValueRecord()">Record Value</AppButton>
|
||||
<AppButton icon="wrench" @click="router.push(`/profiles/${getSelectedProfile()}/accounts/${account?.id}/edit`)">
|
||||
<AppButton icon="wrench"
|
||||
@click="router.push(`/profiles/${getSelectedProfile(route)}/accounts/${account?.id}/edit`)">
|
||||
Edit</AppButton>
|
||||
<AppButton icon="trash" @click="deleteAccount()">Delete</AppButton>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { getSelectedProfile } from '@/api/profile';
|
||||
import { TransactionApiClient, type TransactionCategory, type TransactionCategoryTree } from '@/api/transaction';
|
||||
import AppButton from '@/components/AppButton.vue';
|
||||
import AppPage from '@/components/AppPage.vue';
|
||||
|
|
@ -7,6 +8,9 @@ import EditCategoryModal from '@/components/EditCategoryModal.vue';
|
|||
import { showConfirm } from '@/util/alert';
|
||||
import { hideLoader, showLoader } from '@/util/loader';
|
||||
import { nextTick, onMounted, ref, useTemplateRef, type Ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
const editCategoryModal = useTemplateRef('editCategoryModal')
|
||||
|
||||
|
|
@ -18,13 +22,13 @@ onMounted(async () => {
|
|||
})
|
||||
|
||||
async function loadCategories() {
|
||||
const api = new TransactionApiClient()
|
||||
const api = new TransactionApiClient(getSelectedProfile(route))
|
||||
categories.value = await api.getCategories()
|
||||
}
|
||||
|
||||
async function editCategory(categoryId: number) {
|
||||
try {
|
||||
const api = new TransactionApiClient()
|
||||
const api = new TransactionApiClient(getSelectedProfile(route))
|
||||
editedCategory.value = await api.getCategory(categoryId)
|
||||
await nextTick()
|
||||
const result = await editCategoryModal.value?.show()
|
||||
|
|
@ -41,7 +45,7 @@ async function deleteCategory(categoryId: number) {
|
|||
if (result) {
|
||||
try {
|
||||
showLoader()
|
||||
const api = new TransactionApiClient()
|
||||
const api = new TransactionApiClient(getSelectedProfile(route))
|
||||
await api.deleteCategory(categoryId)
|
||||
await loadCategories()
|
||||
} catch (err) {
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ function generateSampleData() {
|
|||
</FormControl>
|
||||
</FormGroup>
|
||||
<div style="display: flex; margin-left: 1rem; margin-right: 1rem;">
|
||||
<AppButton button-type="submit" :disabled="disableForm || !isDataValid()" style="flex-grow: 1;">Login
|
||||
<AppButton type="submit" :disabled="disableForm || !isDataValid()" style="flex-grow: 1;">Login
|
||||
</AppButton>
|
||||
<AppButton button-type="button" button-style="secondary" :disabled="disableForm || !isDataValid()"
|
||||
@click="doRegister()">Register</AppButton>
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ async function doChangePassword() {
|
|||
</template>
|
||||
<template v-slot:buttons>
|
||||
<AppButton @click="doChangePassword()">Change</AppButton>
|
||||
<AppButton button-style="secondary" @click="changePasswordModal?.close()">Cancel</AppButton>
|
||||
<AppButton theme="secondary" @click="changePasswordModal?.close()">Cancel</AppButton>
|
||||
</template>
|
||||
</ModalWrapper>
|
||||
</AppPage>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ onMounted(async () => {
|
|||
}
|
||||
|
||||
try {
|
||||
const api = new AccountApiClient()
|
||||
const api = new AccountApiClient(route)
|
||||
accounts.value = await api.getAccounts()
|
||||
} catch (err) {
|
||||
console.error('Failed to load accounts', err)
|
||||
|
|
|
|||
|
|
@ -31,10 +31,10 @@ function selectProfile(profile: Profile) {
|
|||
async function addProfile() {
|
||||
try {
|
||||
const api = new ProfileApiClient()
|
||||
api.createProfile(newProfileName.value)
|
||||
const newProfile = await api.createProfile(newProfileName.value)
|
||||
newProfileName.value = ''
|
||||
addProfileModal.value?.close()
|
||||
await fetchProfiles()
|
||||
await router.push('/profiles/' + newProfile.name)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
|
|
@ -45,8 +45,8 @@ async function addProfile() {
|
|||
<div class="profile-card" v-for="profile in profiles" :key="profile.name" @click="selectProfile(profile)">
|
||||
<span>{{ profile.name }}</span>
|
||||
</div>
|
||||
<div class="profile-card" @click="addProfileModal?.show()">
|
||||
<span>Add a new profile...</span>
|
||||
<div style="text-align: right;">
|
||||
<AppButton icon="plus" @click="addProfileModal?.show()">Add a new profile</AppButton>
|
||||
</div>
|
||||
|
||||
<ModalWrapper ref="addProfileModal">
|
||||
|
|
|
|||
|
|
@ -14,14 +14,14 @@ import { useRoute, useRouter } from 'vue-router';
|
|||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const transactionApi = new TransactionApiClient(getSelectedProfile(route))
|
||||
|
||||
const transaction: Ref<TransactionDetail | undefined> = ref()
|
||||
|
||||
onMounted(async () => {
|
||||
const transactionId = parseInt(route.params.id as string)
|
||||
try {
|
||||
const api = new TransactionApiClient()
|
||||
transaction.value = await api.getTransaction(transactionId)
|
||||
transaction.value = await transactionApi.getTransaction(transactionId)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
await router.replace('/')
|
||||
|
|
@ -36,8 +36,8 @@ async function deleteTransaction() {
|
|||
const conf = await showConfirm('Are you sure you want to delete this transaction? This will permanently delete all data pertaining to this transaction, and it cannot be recovered.')
|
||||
if (!conf) return
|
||||
try {
|
||||
await new TransactionApiClient().deleteTransaction(transaction.value.id)
|
||||
await router.replace(`/profiles/${getSelectedProfile()}`)
|
||||
await transactionApi.deleteTransaction(transaction.value.id)
|
||||
await router.replace(`/profiles/${getSelectedProfile(route)}`)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
|
|
@ -119,7 +119,7 @@ async function deleteTransaction() {
|
|||
</div>
|
||||
<div>
|
||||
<AppButton icon="wrench"
|
||||
@click="router.push(`/profiles/${getSelectedProfile()}/transactions/${transaction.id}/edit`)">
|
||||
@click="router.push(`/profiles/${getSelectedProfile(route)}/transactions/${transaction.id}/edit`)">
|
||||
Edit
|
||||
</AppButton>
|
||||
<AppButton icon="trash" @click="deleteTransaction()">Delete</AppButton>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,15 @@
|
|||
<script setup lang="ts">
|
||||
import { getSelectedProfile } from '@/api/profile';
|
||||
import { TransactionApiClient, type TransactionVendor } from '@/api/transaction';
|
||||
import AppButton from '@/components/AppButton.vue';
|
||||
import AppPage from '@/components/AppPage.vue';
|
||||
import EditVendorModal from '@/components/EditVendorModal.vue';
|
||||
import { showConfirm } from '@/util/alert';
|
||||
import { onMounted, ref, useTemplateRef, type Ref } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
const route = useRoute()
|
||||
const transactionApi = new TransactionApiClient(getSelectedProfile(route))
|
||||
|
||||
const vendors: Ref<TransactionVendor[]> = ref([])
|
||||
const editVendorModal = useTemplateRef('editVendorModal')
|
||||
|
|
@ -15,8 +20,7 @@ onMounted(async () => {
|
|||
})
|
||||
|
||||
async function loadVendors() {
|
||||
const api = new TransactionApiClient()
|
||||
vendors.value = await api.getVendors()
|
||||
vendors.value = await transactionApi.getVendors()
|
||||
}
|
||||
|
||||
async function addVendor() {
|
||||
|
|
@ -38,8 +42,7 @@ async function editVendor(vendor: TransactionVendor) {
|
|||
async function deleteVendor(vendor: TransactionVendor) {
|
||||
const confirmed = await showConfirm('Are you sure you want to delete this vendor? It will be permanently removed from all associated transactions.')
|
||||
if (!confirmed) return
|
||||
const api = new TransactionApiClient()
|
||||
await api.deleteVendor(vendor.id)
|
||||
await transactionApi.deleteVendor(vendor.id)
|
||||
await loadVendors()
|
||||
}
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ onMounted(async () => {
|
|||
const accountId = parseInt(accountIdStr)
|
||||
try {
|
||||
loading.value = true
|
||||
const api = new AccountApiClient()
|
||||
const api = new AccountApiClient(route)
|
||||
existingAccount.value = await api.getAccount(accountId)
|
||||
accountName.value = existingAccount.value.name
|
||||
accountType.value = AccountTypes.of(existingAccount.value.type)
|
||||
|
|
@ -55,12 +55,12 @@ async function doSubmit() {
|
|||
}
|
||||
|
||||
try {
|
||||
const api = new AccountApiClient()
|
||||
const api = new AccountApiClient(route)
|
||||
loading.value = true
|
||||
const account = editing.value
|
||||
? await api.updateAccount(existingAccount.value?.id ?? 0, payload)
|
||||
: await api.createAccount(payload)
|
||||
await router.replace(`/profiles/${getSelectedProfile()}/accounts/${account.id}`)
|
||||
await router.replace(`/profiles/${getSelectedProfile(route)}/accounts/${account.id}`)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
} finally {
|
||||
|
|
@ -101,7 +101,7 @@ async function doSubmit() {
|
|||
</FormControl>
|
||||
</FormGroup>
|
||||
|
||||
<FormActions @cancel="router.replace(`/profiles/${getSelectedProfile()}`)" :disabled="loading"
|
||||
<FormActions @cancel="router.replace(`/profiles/${getSelectedProfile(route)}`)" :disabled="loading"
|
||||
:submit-text="editing ? 'Save' : 'Add'" />
|
||||
</AppForm>
|
||||
</AppPage>
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ import { useRoute, useRouter, } from 'vue-router';
|
|||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const transactionApi = new TransactionApiClient(getSelectedProfile(route))
|
||||
const accountApi = new AccountApiClient(route)
|
||||
|
||||
const existingTransaction: Ref<TransactionDetail | null> = ref(null)
|
||||
const editing = computed(() => {
|
||||
return existingTransaction.value !== null || route.meta.title === 'Edit Transaction'
|
||||
|
|
@ -80,14 +83,12 @@ watch(availableCurrencies, (newValue: Currency[]) => {
|
|||
|
||||
onMounted(async () => {
|
||||
const dataClient = new DataApiClient()
|
||||
const transactionClient = new TransactionApiClient()
|
||||
const accountClient = new AccountApiClient()
|
||||
|
||||
// Fetch various collections of data needed for different user choices.
|
||||
dataClient.getCurrencies().then(currencies => allCurrencies.value = currencies)
|
||||
transactionClient.getVendors().then(vendors => availableVendors.value = vendors)
|
||||
transactionClient.getAllTags().then(t => allTags.value = t)
|
||||
accountClient.getAccounts().then(accounts => allAccounts.value = accounts)
|
||||
transactionApi.getVendors().then(vendors => availableVendors.value = vendors)
|
||||
transactionApi.getAllTags().then(t => allTags.value = t)
|
||||
accountApi.getAccounts().then(accounts => allAccounts.value = accounts)
|
||||
|
||||
|
||||
const transactionIdStr = route.params.id
|
||||
|
|
@ -95,7 +96,7 @@ onMounted(async () => {
|
|||
const transactionId = parseInt(transactionIdStr)
|
||||
try {
|
||||
loading.value = true
|
||||
existingTransaction.value = await transactionClient.getTransaction(transactionId)
|
||||
existingTransaction.value = await transactionApi.getTransaction(transactionId)
|
||||
loadValuesFromExistingTransaction(existingTransaction.value)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
|
|
@ -133,7 +134,6 @@ async function doSubmit() {
|
|||
attachmentIdsToRemove: removedAttachmentIds.value
|
||||
}
|
||||
|
||||
const transactionApi = new TransactionApiClient()
|
||||
let savedTransaction = null
|
||||
try {
|
||||
loading.value = true
|
||||
|
|
@ -142,7 +142,7 @@ async function doSubmit() {
|
|||
} else {
|
||||
savedTransaction = await transactionApi.addTransaction(payload, attachmentsToUpload.value)
|
||||
}
|
||||
await router.replace(`/profiles/${getSelectedProfile()}/transactions/${savedTransaction.id}`)
|
||||
await router.replace(`/profiles/${getSelectedProfile(route)}/transactions/${savedTransaction.id}`)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
} finally {
|
||||
|
|
@ -156,9 +156,9 @@ async function doSubmit() {
|
|||
*/
|
||||
function doCancel() {
|
||||
if (editing.value) {
|
||||
router.replace(`/profiles/${getSelectedProfile()}/transactions/${existingTransaction.value?.id}`)
|
||||
router.replace(`/profiles/${getSelectedProfile(route)}/transactions/${existingTransaction.value?.id}`)
|
||||
} else {
|
||||
router.replace(`/profiles/${getSelectedProfile()}`)
|
||||
router.replace(`/profiles/${getSelectedProfile(route)}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,14 +5,15 @@ import { getSelectedProfile } from '@/api/profile'
|
|||
import AppButton from '@/components/AppButton.vue'
|
||||
import HomeModule from '@/components/HomeModule.vue'
|
||||
import { onMounted, ref, type Ref } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
const accounts: Ref<Account[]> = ref([])
|
||||
|
||||
onMounted(async () => {
|
||||
const accountApi = new AccountApiClient()
|
||||
const accountApi = new AccountApiClient(route)
|
||||
accountApi.getAccounts().then(result => accounts.value = result)
|
||||
.catch(err => console.error(err))
|
||||
})
|
||||
|
|
@ -33,7 +34,7 @@ onMounted(async () => {
|
|||
<tbody>
|
||||
<tr v-for="account in accounts" :key="account.id">
|
||||
<td>
|
||||
<RouterLink :to="`/profiles/${getSelectedProfile()}/accounts/${account.id}`">{{ account.name }}
|
||||
<RouterLink :to="`/profiles/${getSelectedProfile(route)}/accounts/${account.id}`">{{ account.name }}
|
||||
</RouterLink>
|
||||
</td>
|
||||
<td>{{ account.currency.code }}</td>
|
||||
|
|
@ -48,7 +49,7 @@ onMounted(async () => {
|
|||
</table>
|
||||
</template>
|
||||
<template v-slot:actions>
|
||||
<AppButton icon="plus" @click="router.push(`/profiles/${getSelectedProfile()}/add-account`)">Add Account
|
||||
<AppButton icon="plus" @click="router.push(`/profiles/${getSelectedProfile(route)}/add-account`)">Add Account
|
||||
</AppButton>
|
||||
</template>
|
||||
</HomeModule>
|
||||
|
|
|
|||
|
|
@ -5,16 +5,17 @@ import ConfirmModal from '@/components/ConfirmModal.vue';
|
|||
import HomeModule from '@/components/HomeModule.vue';
|
||||
import { showAlert } from '@/util/alert';
|
||||
import { onMounted, ref, useTemplateRef, type Ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const confirmDeleteModal = useTemplateRef('confirmDeleteModal')
|
||||
|
||||
const profile: Ref<Profile | undefined> = ref()
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
profile.value = await new ProfileApiClient().getProfile(getSelectedProfile())
|
||||
profile.value = await new ProfileApiClient().getProfile(getSelectedProfile(route))
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
await showAlert("Failed to get profile.")
|
||||
|
|
@ -23,7 +24,7 @@ onMounted(async () => {
|
|||
})
|
||||
|
||||
async function deleteProfile() {
|
||||
const currentProfileName = getSelectedProfile()
|
||||
const currentProfileName = getSelectedProfile(route)
|
||||
if (await confirmDeleteModal.value?.confirm()) {
|
||||
const api = new ProfileApiClient()
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -7,9 +7,10 @@ import AppButton from '@/components/AppButton.vue';
|
|||
import HomeModule from '@/components/HomeModule.vue';
|
||||
import PaginationControls from '@/components/PaginationControls.vue';
|
||||
import { onMounted, ref, type Ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const transactions: Ref<Page<TransactionsListItem>> = ref({ items: [], pageRequest: { page: 1, size: 10, sorts: [] }, totalElements: 0, totalPages: 0, isFirst: true, isLast: true })
|
||||
|
||||
onMounted(async () => {
|
||||
|
|
@ -17,7 +18,7 @@ onMounted(async () => {
|
|||
})
|
||||
|
||||
async function fetchPage(pageRequest: PageRequest) {
|
||||
const api = new TransactionApiClient()
|
||||
const api = new TransactionApiClient(getSelectedProfile(route))
|
||||
try {
|
||||
transactions.value = await api.getTransactions(pageRequest)
|
||||
} catch (err) {
|
||||
|
|
@ -50,18 +51,18 @@ async function fetchPage(pageRequest: PageRequest) {
|
|||
<td>{{ tx.description }}</td>
|
||||
<td>
|
||||
<RouterLink v-if="tx.creditedAccount"
|
||||
:to="`/profiles/${getSelectedProfile()}/accounts/${tx.creditedAccount.id}`">
|
||||
:to="`/profiles/${getSelectedProfile(route)}/accounts/${tx.creditedAccount.id}`">
|
||||
{{ tx.creditedAccount?.name }}
|
||||
</RouterLink>
|
||||
</td>
|
||||
<td>
|
||||
<RouterLink v-if="tx.debitedAccount"
|
||||
:to="`/profiles/${getSelectedProfile()}/accounts/${tx.debitedAccount.id}`">
|
||||
:to="`/profiles/${getSelectedProfile(route)}/accounts/${tx.debitedAccount.id}`">
|
||||
{{ tx.debitedAccount?.name }}
|
||||
</RouterLink>
|
||||
</td>
|
||||
<td>
|
||||
<RouterLink :to="`/profiles/${getSelectedProfile()}/transactions/${tx.id}`">View</RouterLink>
|
||||
<RouterLink :to="`/profiles/${getSelectedProfile(route)}/transactions/${tx.id}`">View</RouterLink>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
@ -69,7 +70,8 @@ async function fetchPage(pageRequest: PageRequest) {
|
|||
<PaginationControls :page="transactions" @update="pr => fetchPage(pr)"></PaginationControls>
|
||||
</template>
|
||||
<template v-slot:actions>
|
||||
<AppButton icon="plus" @click="router.push(`/profiles/${getSelectedProfile()}/add-transaction`)">Add
|
||||
<AppButton size="sm" icon="plus" @click="router.push(`/profiles/${getSelectedProfile(route)}/add-transaction`)">
|
||||
Add
|
||||
Transaction</AppButton>
|
||||
</template>
|
||||
</HomeModule>
|
||||
|
|
|
|||
Loading…
Reference in New Issue