Reformatted source code.
This commit is contained in:
parent
110eb2c912
commit
44ead22c4f
|
|
@ -12,7 +12,7 @@ defineEmits<{ categorySelected: [TransactionCategoryTree | null] }>()
|
||||||
const categories: Ref<TransactionCategoryTree[]> = ref([])
|
const categories: Ref<TransactionCategoryTree[]> = ref([])
|
||||||
const selectedCategory: Ref<TransactionCategoryTree | null> = ref(null)
|
const selectedCategory: Ref<TransactionCategoryTree | null> = ref(null)
|
||||||
const options: Ref<Option<TransactionCategoryTree>[]> = computed(() => {
|
const options: Ref<Option<TransactionCategoryTree>[]> = computed(() => {
|
||||||
return categories.value.map(c => {
|
return categories.value.map((c) => {
|
||||||
return { label: c.name, value: c }
|
return { label: c.name, value: c }
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -37,8 +37,14 @@ function getCategoryById(id: number): TransactionCategoryTree | null {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<VueSelect class="category-select" v-model="selectedCategory" :options="options" placeholder="Select a category"
|
<VueSelect
|
||||||
@option-selected="model = selectedCategory?.id ?? null" @option-deselected="model = null">
|
class="category-select"
|
||||||
|
v-model="selectedCategory"
|
||||||
|
:options="options"
|
||||||
|
placeholder="Select a category"
|
||||||
|
@option-selected="model = selectedCategory?.id ?? null"
|
||||||
|
@option-deselected="model = null"
|
||||||
|
>
|
||||||
<template #option="{ option }">
|
<template #option="{ option }">
|
||||||
{{ ' '.repeat(option.value.depth * 4) }} {{ option.label }}
|
{{ ' '.repeat(option.value.depth * 4) }} {{ option.label }}
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -32,10 +32,7 @@ function canSave() {
|
||||||
if (!inputValid) return false
|
if (!inputValid) return false
|
||||||
if (props.vendor) {
|
if (props.vendor) {
|
||||||
const newDesc = description.value.trim().length === 0 ? null : description.value.trim()
|
const newDesc = description.value.trim().length === 0 ? null : description.value.trim()
|
||||||
return (
|
return props.vendor.name.trim() !== name.value.trim() || props.vendor.description !== newDesc
|
||||||
props.vendor.name.trim() !== name.value.trim() ||
|
|
||||||
props.vendor.description !== newDesc
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -70,17 +67,31 @@ defineExpose({ show })
|
||||||
<AppForm>
|
<AppForm>
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormControl label="Name">
|
<FormControl label="Name">
|
||||||
<input type="text" v-model="name" />
|
<input
|
||||||
|
type="text"
|
||||||
|
v-model="name"
|
||||||
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormControl label="Description" style="min-width: 300px">
|
<FormControl
|
||||||
|
label="Description"
|
||||||
|
style="min-width: 300px"
|
||||||
|
>
|
||||||
<textarea v-model="description"></textarea>
|
<textarea v-model="description"></textarea>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
</AppForm>
|
</AppForm>
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:buttons>
|
<template v-slot:buttons>
|
||||||
<AppButton :disabled="!canSave()" @click="doSave()">Save</AppButton>
|
<AppButton
|
||||||
<AppButton button-style="secondary" @click="modal?.close()">Cancel</AppButton>
|
:disabled="!canSave()"
|
||||||
|
@click="doSave()"
|
||||||
|
>Save</AppButton
|
||||||
|
>
|
||||||
|
<AppButton
|
||||||
|
button-style="secondary"
|
||||||
|
@click="modal?.close()"
|
||||||
|
>Cancel</AppButton
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</ModalWrapper>
|
</ModalWrapper>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,12 @@ defineEmits<{ deleted: void }>()
|
||||||
<AppBadge>
|
<AppBadge>
|
||||||
<span class="tag-label-hashtag">#</span>
|
<span class="tag-label-hashtag">#</span>
|
||||||
{{ tag }}
|
{{ tag }}
|
||||||
<font-awesome-icon v-if="deletable" icon="fa-x" class="tag-label-delete"
|
<font-awesome-icon
|
||||||
@click="$emit('deleted')"></font-awesome-icon>
|
v-if="deletable"
|
||||||
|
icon="fa-x"
|
||||||
|
class="tag-label-delete"
|
||||||
|
@click="$emit('deleted')"
|
||||||
|
></font-awesome-icon>
|
||||||
</AppBadge>
|
</AppBadge>
|
||||||
</template>
|
</template>
|
||||||
<style lang="css">
|
<style lang="css">
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,20 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { getSelectedProfile } from '@/api/profile';
|
import { getSelectedProfile } from '@/api/profile'
|
||||||
import { TransactionApiClient } from '@/api/transaction';
|
import { TransactionApiClient } from '@/api/transaction'
|
||||||
import { computed, onMounted, ref, type Ref } from 'vue';
|
import { computed, onMounted, ref, type Ref } from 'vue'
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router'
|
||||||
import TagLabel from './TagLabel.vue';
|
import TagLabel from './TagLabel.vue'
|
||||||
import AppButton from './common/AppButton.vue';
|
import AppButton from './common/AppButton.vue'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const model = defineModel<string[]>({ required: true })
|
const model = defineModel<string[]>({ required: true })
|
||||||
const existingTags: Ref<string[]> = ref([])
|
const existingTags: Ref<string[]> = ref([])
|
||||||
const availableTags = computed(() => {
|
const availableTags = computed(() => {
|
||||||
return existingTags.value.filter(t => !model.value.includes(t))
|
return existingTags.value.filter((t) => !model.value.includes(t))
|
||||||
})
|
})
|
||||||
|
|
||||||
const tagSelect: Ref<string | null> = ref(null)
|
const tagSelect: Ref<string | null> = ref(null)
|
||||||
const enteringCustomTag = computed(() => tagSelect.value == "--CUSTOM_TAG--")
|
const enteringCustomTag = computed(() => tagSelect.value == '--CUSTOM_TAG--')
|
||||||
const customTagInput: Ref<string> = ref('')
|
const customTagInput: Ref<string> = ref('')
|
||||||
const customTagInputValid = computed(() => {
|
const customTagInputValid = computed(() => {
|
||||||
const result = customTagInput.value.match('^[a-z0-9-_]{3,32}$')
|
const result = customTagInput.value.match('^[a-z0-9-_]{3,32}$')
|
||||||
|
|
@ -44,21 +44,38 @@ function addTag() {
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div style="margin-top: 0.5rem; margin-bottom: 0.5rem; font-weight: normal;">
|
<div style="margin-top: 0.5rem; margin-bottom: 0.5rem; font-weight: normal">
|
||||||
<TagLabel v-for="t in model" :key="t" :tag="t" deletable @deleted="model = model.filter((tg) => tg !== t)" />
|
<TagLabel
|
||||||
|
v-for="t in model"
|
||||||
|
:key="t"
|
||||||
|
:tag="t"
|
||||||
|
deletable
|
||||||
|
@deleted="model = model.filter((tg) => tg !== t)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<select v-model="tagSelect">
|
<select v-model="tagSelect">
|
||||||
<option v-for="tag in availableTags" :key="tag" :value="tag">
|
<option
|
||||||
|
v-for="tag in availableTags"
|
||||||
|
:key="tag"
|
||||||
|
:value="tag"
|
||||||
|
>
|
||||||
{{ tag }}
|
{{ tag }}
|
||||||
</option>
|
</option>
|
||||||
<option value="--CUSTOM_TAG--">
|
<option value="--CUSTOM_TAG--">Add a new tag</option>
|
||||||
Add a new tag
|
|
||||||
</option>
|
|
||||||
</select>
|
</select>
|
||||||
<input style="margin-left: 0.25rem;" v-model="customTagInput" v-if="enteringCustomTag"
|
<input
|
||||||
placeholder="Custom tag..." />
|
style="margin-left: 0.25rem"
|
||||||
<AppButton size="sm" style="margin-left: 0.25rem;" @click="addTag()" :disabled="!canAddTag">
|
v-model="customTagInput"
|
||||||
|
v-if="enteringCustomTag"
|
||||||
|
placeholder="Custom tag..."
|
||||||
|
/>
|
||||||
|
<AppButton
|
||||||
|
size="sm"
|
||||||
|
style="margin-left: 0.25rem"
|
||||||
|
@click="addTag()"
|
||||||
|
:disabled="!canAddTag"
|
||||||
|
>
|
||||||
Add Tag
|
Add Tag
|
||||||
</AppButton>
|
</AppButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,34 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { TransactionVendor } from '@/api/transaction';
|
import type { TransactionVendor } from '@/api/transaction'
|
||||||
import AppButton from './common/AppButton.vue';
|
import AppButton from './common/AppButton.vue'
|
||||||
|
|
||||||
defineProps<{ vendor: TransactionVendor }>()
|
defineProps<{ vendor: TransactionVendor }>()
|
||||||
defineEmits<{ 'edit': void, 'delete': void }>()
|
defineEmits<{ edit: void; delete: void }>()
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="vendor-card">
|
<div class="vendor-card">
|
||||||
<div style="flex-shrink: 1;">
|
<div style="flex-shrink: 1">
|
||||||
<div>
|
<div>
|
||||||
{{ vendor.name }}
|
{{ vendor.name }}
|
||||||
</div>
|
</div>
|
||||||
<div v-if="vendor.description !== null" class="font-size-small text-muted">
|
<div
|
||||||
|
v-if="vendor.description !== null"
|
||||||
|
class="font-size-small text-muted"
|
||||||
|
>
|
||||||
{{ vendor.description }}
|
{{ vendor.description }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<AppButton icon="wrench" size="sm" @click="$emit('edit')"></AppButton>
|
<AppButton
|
||||||
<AppButton icon="trash" size="sm" @click="$emit('delete')"></AppButton>
|
icon="wrench"
|
||||||
|
size="sm"
|
||||||
|
@click="$emit('edit')"
|
||||||
|
></AppButton>
|
||||||
|
<AppButton
|
||||||
|
icon="trash"
|
||||||
|
size="sm"
|
||||||
|
@click="$emit('delete')"
|
||||||
|
></AppButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -56,11 +56,25 @@ async function deleteVendor(vendor: TransactionVendor) {
|
||||||
Vendors are businesses and other entities with which you exchange money. Adding a vendor to
|
Vendors are businesses and other entities with which you exchange money. Adding a vendor to
|
||||||
Finnow allows you to track when you interact with that vendor on a transaction.
|
Finnow allows you to track when you interact with that vendor on a transaction.
|
||||||
</p>
|
</p>
|
||||||
<VendorCard v-for="v in vendors" :key="v.id" :vendor="v" @edit="editVendor(v)" @delete="deleteVendor(v)" />
|
<VendorCard
|
||||||
|
v-for="v in vendors"
|
||||||
|
:key="v.id"
|
||||||
|
:vendor="v"
|
||||||
|
@edit="editVendor(v)"
|
||||||
|
@delete="deleteVendor(v)"
|
||||||
|
/>
|
||||||
<ButtonBar>
|
<ButtonBar>
|
||||||
<AppButton button-type="button" icon="plus" @click="addVendor()">Add Vendor</AppButton>
|
<AppButton
|
||||||
|
button-type="button"
|
||||||
|
icon="plus"
|
||||||
|
@click="addVendor()"
|
||||||
|
>Add Vendor</AppButton
|
||||||
|
>
|
||||||
</ButtonBar>
|
</ButtonBar>
|
||||||
|
|
||||||
<EditVendorModal ref="editVendorModal" :vendor="editedVendor" />
|
<EditVendorModal
|
||||||
|
ref="editVendorModal"
|
||||||
|
:vendor="editedVendor"
|
||||||
|
/>
|
||||||
</AppPage>
|
</AppPage>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -55,12 +55,11 @@ const formValid = computed(() => {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
const unsavedEdits = computed(() => {
|
const unsavedEdits = computed(() => {
|
||||||
console.log("Checking if there are unsaved edits...")
|
console.log('Checking if there are unsaved edits...')
|
||||||
if (!existingTransaction.value) return true
|
if (!existingTransaction.value) return true
|
||||||
const tx = existingTransaction.value
|
const tx = existingTransaction.value
|
||||||
const tagsEqual =
|
const tagsEqual =
|
||||||
tags.value.every((t) => tx.tags.includes(t)) &&
|
tags.value.every((t) => tx.tags.includes(t)) && tx.tags.every((t) => tags.value.includes(t))
|
||||||
tx.tags.every((t) => tags.value.includes(t))
|
|
||||||
let lineItemsEqual = false
|
let lineItemsEqual = false
|
||||||
if (lineItems.value.length === tx.lineItems.length) {
|
if (lineItems.value.length === tx.lineItems.length) {
|
||||||
lineItemsEqual = true
|
lineItemsEqual = true
|
||||||
|
|
@ -82,7 +81,8 @@ const unsavedEdits = computed(() => {
|
||||||
const attachmentsChanged =
|
const attachmentsChanged =
|
||||||
attachmentsToUpload.value.length > 0 || removedAttachmentIds.value.length > 0
|
attachmentsToUpload.value.length > 0 || removedAttachmentIds.value.length > 0
|
||||||
const timestampChanged = new Date(timestamp.value).toISOString() !== tx.timestamp
|
const timestampChanged = new Date(timestamp.value).toISOString() !== tx.timestamp
|
||||||
const amountChanged = amount.value * Math.pow(10, currency.value?.fractionalDigits ?? 0) !== tx.amount
|
const amountChanged =
|
||||||
|
amount.value * Math.pow(10, currency.value?.fractionalDigits ?? 0) !== tx.amount
|
||||||
const currencyChanged = currency.value?.code !== tx.currency.code
|
const currencyChanged = currency.value?.code !== tx.currency.code
|
||||||
const descriptionChanged = description.value !== tx.description
|
const descriptionChanged = description.value !== tx.description
|
||||||
const vendorChanged = vendor.value?.id !== tx.vendor?.id
|
const vendorChanged = vendor.value?.id !== tx.vendor?.id
|
||||||
|
|
@ -281,20 +281,46 @@ function getLocalDateTimeStringFromUTCTimestamp(timestamp: string) {
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<!-- Basic properties -->
|
<!-- Basic properties -->
|
||||||
<FormControl label="Timestamp">
|
<FormControl label="Timestamp">
|
||||||
<input type="datetime-local" v-model="timestamp" step="1" :disabled="loading" style="min-width: 250px" />
|
<input
|
||||||
|
type="datetime-local"
|
||||||
|
v-model="timestamp"
|
||||||
|
step="1"
|
||||||
|
:disabled="loading"
|
||||||
|
style="min-width: 250px"
|
||||||
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormControl label="Amount">
|
<FormControl label="Amount">
|
||||||
<input type="number" v-model="amount" step="0.01" min="0.01" :disabled="loading" style="max-width: 100px" />
|
<input
|
||||||
|
type="number"
|
||||||
|
v-model="amount"
|
||||||
|
step="0.01"
|
||||||
|
min="0.01"
|
||||||
|
:disabled="loading"
|
||||||
|
style="max-width: 100px"
|
||||||
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormControl label="Currency">
|
<FormControl label="Currency">
|
||||||
<select v-model="currency" :disabled="loading || availableCurrencies.length === 1">
|
<select
|
||||||
<option v-for="currency in availableCurrencies" :key="currency.code" :value="currency">
|
v-model="currency"
|
||||||
|
:disabled="loading || availableCurrencies.length === 1"
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
v-for="currency in availableCurrencies"
|
||||||
|
:key="currency.code"
|
||||||
|
:value="currency"
|
||||||
|
>
|
||||||
{{ currency.code }}
|
{{ currency.code }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormControl label="Description" style="min-width: 200px">
|
<FormControl
|
||||||
<textarea v-model="description" :disabled="loading"></textarea>
|
label="Description"
|
||||||
|
style="min-width: 200px"
|
||||||
|
>
|
||||||
|
<textarea
|
||||||
|
v-model="description"
|
||||||
|
:disabled="loading"
|
||||||
|
></textarea>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
|
|
@ -311,16 +337,30 @@ function getLocalDateTimeStringFromUTCTimestamp(timestamp: string) {
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<!-- Accounts -->
|
<!-- Accounts -->
|
||||||
<FormControl label="Credited Account">
|
<FormControl label="Credited Account">
|
||||||
<select v-model="creditedAccountId" :disabled="loading">
|
<select
|
||||||
<option v-for="account in availableAccounts" :key="account.id" :value="account.id">
|
v-model="creditedAccountId"
|
||||||
|
:disabled="loading"
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
v-for="account in availableAccounts"
|
||||||
|
:key="account.id"
|
||||||
|
:value="account.id"
|
||||||
|
>
|
||||||
{{ account.name }} ({{ account.numberSuffix }})
|
{{ account.name }} ({{ account.numberSuffix }})
|
||||||
</option>
|
</option>
|
||||||
<option :value="null">None</option>
|
<option :value="null">None</option>
|
||||||
</select>
|
</select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormControl label="Debited Account">
|
<FormControl label="Debited Account">
|
||||||
<select v-model="debitedAccountId" :disabled="loading">
|
<select
|
||||||
<option v-for="account in availableAccounts" :key="account.id" :value="account.id">
|
v-model="debitedAccountId"
|
||||||
|
:disabled="loading"
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
v-for="account in availableAccounts"
|
||||||
|
:key="account.id"
|
||||||
|
:value="account.id"
|
||||||
|
>
|
||||||
{{ account.name }} ({{ account.numberSuffix }})
|
{{ account.name }} ({{ account.numberSuffix }})
|
||||||
</option>
|
</option>
|
||||||
<option :value="null">None</option>
|
<option :value="null">None</option>
|
||||||
|
|
@ -328,8 +368,12 @@ function getLocalDateTimeStringFromUTCTimestamp(timestamp: string) {
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
<LineItemsEditor v-if="currency" v-model="lineItems" :currency="currency"
|
<LineItemsEditor
|
||||||
:transaction-amount="floatMoneyToInteger(amount, currency)" />
|
v-if="currency"
|
||||||
|
v-model="lineItems"
|
||||||
|
:currency="currency"
|
||||||
|
:transaction-amount="floatMoneyToInteger(amount, currency)"
|
||||||
|
/>
|
||||||
|
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<!-- Tags -->
|
<!-- Tags -->
|
||||||
|
|
@ -340,12 +384,18 @@ function getLocalDateTimeStringFromUTCTimestamp(timestamp: string) {
|
||||||
|
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<h5>Attachments</h5>
|
<h5>Attachments</h5>
|
||||||
<FileSelector :initial-files="existingTransaction?.attachments ?? []"
|
<FileSelector
|
||||||
v-model:uploaded-files="attachmentsToUpload" v-model:removed-files="removedAttachmentIds" />
|
:initial-files="existingTransaction?.attachments ?? []"
|
||||||
|
v-model:uploaded-files="attachmentsToUpload"
|
||||||
|
v-model:removed-files="removedAttachmentIds"
|
||||||
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
<FormActions @cancel="doCancel()" :disabled="loading || !formValid || !unsavedEdits"
|
<FormActions
|
||||||
:submit-text="editing ? 'Save' : 'Add'" />
|
@cancel="doCancel()"
|
||||||
|
:disabled="loading || !formValid || !unsavedEdits"
|
||||||
|
:submit-text="editing ? 'Save' : 'Add'"
|
||||||
|
/>
|
||||||
</AppForm>
|
</AppForm>
|
||||||
</AppPage>
|
</AppPage>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue