Frontend remembers state.

This commit is contained in:
James Cole
2021-01-17 19:52:53 +01:00
parent c86791950d
commit 79c00548df
22 changed files with 239 additions and 258 deletions

View File

@@ -18,13 +18,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
let date = new Date;
const lodashClonedeep = require('lodash.clonedeep'); const lodashClonedeep = require('lodash.clonedeep');
// initial state // initial state
const state = () => ({ const state = () => ({
transactionType: 'any', transactionType: 'any',
date: new Date,
transactions: [], transactions: [],
allowedOpposingTypes: {}, allowedOpposingTypes: {},
accountToTransaction: {}, accountToTransaction: {},
@@ -41,8 +40,6 @@ const state = () => ({
defaultTransaction: { defaultTransaction: {
// basic // basic
description: '', description: '',
date: date.toISOString().split('T')[0],
time: ('0' + date.getHours()).slice(-2) + ':' + ('0' + date.getMinutes()).slice(-2) + ':' + ('0' + date.getSeconds()).slice(-2),
// accounts: // accounts:
source_account: { source_account: {
@@ -99,6 +96,9 @@ const getters = {
transactions: state => { transactions: state => {
return state.transactions; return state.transactions;
}, },
date: state => {
return state.date;
},
transactionType: state => { transactionType: state => {
return state.transactionType; return state.transactionType;
}, },
@@ -176,6 +176,9 @@ const mutations = {
let newTransaction = lodashClonedeep(state.defaultTransaction); let newTransaction = lodashClonedeep(state.defaultTransaction);
state.transactions.push(newTransaction); state.transactions.push(newTransaction);
}, },
setDate(state, payload) {
state.date = payload.date;
},
setCustomDateFields(state, payload) { setCustomDateFields(state, payload) {
state.customDateFields = payload; state.customDateFields = payload;
}, },

View File

@@ -35,7 +35,7 @@
</div> </div>
<!-- /.card-header --> <!-- /.card-header -->
<div class="card-body"> <div class="card-body">
<h4>{{ $t('firefly.basic_journal_information') }}: {{ transaction.description }}</h4> <h4>{{ $t('firefly.basic_journal_information') }}</h4>
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<p class="d-block d-sm-none">XS</p> <p class="d-block d-sm-none">XS</p>
@@ -50,19 +50,18 @@
<div class="col"> <div class="col">
Description: Description:
<TransactionDescription <TransactionDescription
v-bind:description.sync="transaction.description" v-model="transaction.description"
:index="index" :index="index"
></TransactionDescription> ></TransactionDescription>
</div> </div>
</div> </div>
<!-- source and destination --> <!-- source and destination -->
<div class="row"> <div class="row">
<div class="col-xl-5 col-lg-5 col-md-10 col-sm-12 col-xs-12"> <div class="col-xl-5 col-lg-5 col-md-10 col-sm-12 col-xs-12">
<!-- SOURCE --> <!-- SOURCE -->
<TransactionAccount <TransactionAccount
:selectedAccount="transaction.source_account" v-model="transaction.source_account"
direction="source" direction="source"
:index="index" :index="index"
/> />
@@ -78,7 +77,7 @@
<div class="col-xl-5 col-lg-5 col-md-12 col-sm-12 col-xs-12"> <div class="col-xl-5 col-lg-5 col-md-12 col-sm-12 col-xs-12">
<!-- DESTINATION --> <!-- DESTINATION -->
<TransactionAccount <TransactionAccount
:selectedAccount="transaction.destination_account" v-model="transaction.destination_account"
direction="destination" direction="destination"
:index="index" :index="index"
/> />
@@ -106,14 +105,12 @@
<div class="row"> <div class="row">
<div class="col-xl-5 col-lg-5 col-md-12 col-sm-12 col-xs-12"> <div class="col-xl-5 col-lg-5 col-md-12 col-sm-12 col-xs-12">
<TransactionDate <TransactionDate
:date="transaction.date"
:time="transaction.time"
:index="index" :index="index"
/> />
</div> </div>
<div class="col-xl-5 col-lg-5 col-md-12 col-sm-12 col-xs-12 offset-xl-2 offset-lg-2"> <div class="col-xl-5 col-lg-5 col-md-12 col-sm-12 col-xs-12 offset-xl-2 offset-lg-2">
<TransactionCustomDates :index="index" :enabled-dates="customDateFields"/> <TransactionCustomDates :index="index" :enabled-dates="customDateFields" />
</div> </div>
</div> </div>
@@ -123,29 +120,26 @@
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<TransactionBudget <TransactionBudget
:budget_id="transactions[index].budget_id" v-model="transaction.budget_id"
:index="index" :index="index"
/> />
<TransactionCategory <TransactionCategory
:category="transaction.category" v-model="transaction.category"
:index="index" :index="index"
/> />
</div> </div>
<div class="col"> <div class="col">
<TransactionBill <TransactionBill
:bill_id="transactions[index].bill_id" v-model="transaction.bill_id"
:index="index" :index="index"
/> />
<TransactionTags <TransactionTags
:index="index" :index="index"
:tags="transactions[index].tags" v-model="transaction.tags"
/> />
<TransactionPiggyBank <TransactionPiggyBank
:index="index" :index="index"
:piggy_bank_id="transactions[index].piggy_bank_id" v-model="transaction.piggy_bank_id"
/> />
</div> </div>
</div> </div>
@@ -156,16 +150,16 @@
<div class="col"> <div class="col">
<TransactionInternalReference <TransactionInternalReference
:index="index" :index="index"
:internalReference="transaction.internal_reference" v-model="transaction.internal_reference"
/> />
<TransactionExternalUrl <TransactionExternalUrl
:index="index" :index="index"
:externalUrl="transaction.external_url" v-model="transaction.external_url"
/> />
<TransactionNotes <TransactionNotes
:index="index" :index="index"
:notes="transaction.notes" v-model="transaction.notes"
/> />
</div> </div>
<div class="col"> <div class="col">
@@ -205,6 +199,8 @@
</div> </div>
</div> </div>
</div> </div>
<!-- /.card-body --> <!-- /.card-body -->
</div> </div>
@@ -289,7 +285,8 @@ export default {
...mapGetters([ ...mapGetters([
'transactionType', // -> this.someGetter 'transactionType', // -> this.someGetter
'transactions', // -> this.someOtherGetter 'transactions', // -> this.someOtherGetter
'customDateFields' 'customDateFields',
'date'
]) ])
}, },
methods: { methods: {

View File

@@ -24,15 +24,15 @@
{{ $t('firefly.' + this.direction + '_account') }} {{ $t('firefly.' + this.direction + '_account') }}
</div> </div>
<vue-typeahead-bootstrap <vue-typeahead-bootstrap
v-model="account" v-model="value.name"
:data="accounts" :data="accounts"
:showOnFocus=true :showOnFocus=true
:inputName="direction + '[]'" :inputName="direction + '[]'"
:serializer="item => item.name_with_balance" :serializer="item => item.name_with_balance"
@hit="selectedAccount = $event"
:minMatchingChars="3" :minMatchingChars="3"
:placeholder="$t('firefly.' + this.direction + '_account')" :placeholder="$t('firefly.' + this.direction + '_account')"
@input="lookupAccount" @input="lookupAccount"
@hit="selectedAccount = $event"
> >
<template slot="append"> <template slot="append">
<div class="input-group-append"> <div class="input-group-append">
@@ -46,21 +46,6 @@
</template> </template>
<script> <script>
/*
<template slot="suggestion" slot-scope="{ data, htmlText }">
<div class="d-flex align-items-center">
<span v-html="htmlText"></span>
</div>
</template>
- you get an object from the parent.
- this is the selected account.
<!-- Note: the v-html binding is used, as htmlText contains
the suggestion text highlighted with <strong> tags -->
*/
import VueTypeaheadBootstrap from 'vue-typeahead-bootstrap'; import VueTypeaheadBootstrap from 'vue-typeahead-bootstrap';
import {debounce} from 'lodash'; import {debounce} from 'lodash';
@@ -71,19 +56,18 @@ const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers
export default { export default {
name: "TransactionAccount", name: "TransactionAccount",
components: {VueTypeaheadBootstrap}, components: {VueTypeaheadBootstrap},
props: ['index', 'direction'], props: ['index', 'direction', 'value'],
data() { data() {
return { return {
query: '', query: '',
accounts: [], accounts: [],
account: '',
accountTypes: [], accountTypes: [],
initialSet: [] initialSet: [],
selectedAccount: {}
} }
}, },
created() { created() {
this.createInitialSet(); this.createInitialSet();
}, },
methods: { methods: {
...mapMutations( ...mapMutations(
@@ -99,35 +83,25 @@ export default {
] ]
), ),
getACURL: function (types, query) { getACURL: function (types, query) {
// update autocomplete URL:
// console.log('getACURL query = ' + query);
// console.log(types);
return document.getElementsByTagName('base')[0].href + 'api/v1/autocomplete/accounts?types=' + types.join(',') + '&query=' + query; return document.getElementsByTagName('base')[0].href + 'api/v1/autocomplete/accounts?types=' + types.join(',') + '&query=' + query;
}, },
clearAccount: function () { clearAccount: function () {
// console.log('clearAccount in ' + this.direction);
this.account = '';
this.selectedAccount = this.defaultTransaction.source_account; // can be either source or dest, does not matter.
// console.log('clearAccount. Selected account (' + this.direction + ') is now:');
// console.log(this.defaultTransaction.source_account);
this.accounts = this.initialSet; this.accounts = this.initialSet;
this.value = {name: ''};
}, },
lookupAccount: debounce(function () { lookupAccount: debounce(function () {
// console.log('lookup account in ' + this.direction)
if (0 === this.accountTypes.length) { if (0 === this.accountTypes.length) {
// set the types from the default types for this direction: // set the types from the default types for this direction:
this.accountTypes = 'source' === this.direction ? this.sourceAllowedTypes : this.destinationAllowedTypes; this.accountTypes = 'source' === this.direction ? this.sourceAllowedTypes : this.destinationAllowedTypes;
} }
// update autocomplete URL: // update autocomplete URL:
axios.get(this.getACURL(this.accountTypes, this.account)) axios.get(this.getACURL(this.accountTypes, this.value.name))
.then(response => { .then(response => {
this.accounts = response.data; this.accounts = response.data;
}) })
}, 300), }, 300),
createInitialSet: function () { createInitialSet: function () {
// console.log('createInitialSet ' + this.direction);
// initial list of accounts:
let types = this.sourceAllowedTypes; let types = this.sourceAllowedTypes;
if ('destination' === this.direction) { if ('destination' === this.direction) {
types = this.destinationAllowedTypes; types = this.destinationAllowedTypes;
@@ -143,14 +117,12 @@ export default {
}, },
watch: { watch: {
selectedAccount: function (value) { selectedAccount: function (value) {
// console.log('watch selectedAccount ' + this.direction); this.value = value;
// console.log(value); this.value.name = this.value.name_with_balance;
this.account = value ? value.name_with_balance : null; },
// console.log('this.account (' + this.direction + ') = "' + this.account + '"'); value: function (value) {
this.calcTransactionType(); this.updateField({field: this.accountKey, index: this.index, value: value});
// set the opposing account allowed set. // set the opposing account allowed set.
// console.log('opposing:');
let opposingAccounts = []; let opposingAccounts = [];
let type = value.type ? value.type : 'no_type'; let type = value.type ? value.type : 'no_type';
if ('undefined' !== typeof this.allowedOpposingTypes[this.direction]) { if ('undefined' !== typeof this.allowedOpposingTypes[this.direction]) {
@@ -165,21 +137,57 @@ export default {
if ('destination' === this.direction) { if ('destination' === this.direction) {
this.setSourceAllowedTypes(opposingAccounts); this.setSourceAllowedTypes(opposingAccounts);
} }
this.calcTransactionType();
}, },
sourceAllowedTypes: function (value) { // account: function (value) {
if ('source' === this.direction) { // //this.value.name = value;
// console.log('do update initial set in direction ' + this.direction + ' because allowed types changed'); // //console.log('watch account in direction ' + this.direction + ' change to "' + value + '"');
// update initial set: // // this.account = value ? value.name_with_balance : null;
this.createInitialSet(); // // // console.log('this.account (' + this.direction + ') = "' + this.account + '"');
} // //
}, // //
destinationAllowedTypes: function (value) { // // // set the opposing account allowed set.
if ('destination' === this.direction) { // // // console.log('opposing:');
// console.log('do update initial set in direction ' + this.direction + ' because allowed types changed'); // // let opposingAccounts = [];
// update initial set: // // let type = value.type ? value.type : 'no_type';
this.createInitialSet(); // // if ('undefined' !== typeof this.allowedOpposingTypes[this.direction]) {
} // // if ('undefined' !== typeof this.allowedOpposingTypes[this.direction][type]) {
} // // opposingAccounts = this.allowedOpposingTypes[this.direction][type];
// // }
// // }
// //
// // if ('source' === this.direction) {
// // this.setDestinationAllowedTypes(opposingAccounts);
// // }
// // if ('destination' === this.direction) {
// // this.setSourceAllowedTypes(opposingAccounts);
// // }
//
//
// //
// // this.calcTransactionType();
//
//
// }
// selectedAccount: function (value) {
// },
// sourceAllowedTypes: function (value) {
// if ('source' === this.direction) {
// // console.log('do update initial set in direction ' + this.direction + ' because allowed types changed');
// // update initial set:
// this.createInitialSet();
// }
// },
// destinationAllowedTypes: function (value) {
// if ('destination' === this.direction) {
// // console.log('do update initial set in direction ' + this.direction + ' because allowed types changed');
// // update initial set:
// this.createInitialSet();
// }
// }
}, },
computed: { computed: {
...mapGetters([ ...mapGetters([
@@ -195,16 +203,16 @@ export default {
return 'source' === this.direction ? 'source_account' : 'destination_account'; return 'source' === this.direction ? 'source_account' : 'destination_account';
} }
}, },
selectedAccount: { // selectedAccount: {
get() { // get() {
return this.transactions[this.index][this.accountKey]; // return this.transactions[this.index][this.accountKey];
}, // },
set(value) { // set(value) {
// console.log('set selectedAccount for ' + this.direction); // // console.log('set selectedAccount for ' + this.direction);
// console.log(value); // // console.log(value);
this.updateField({field: this.accountKey, index: this.index, value: value}); // this.updateField({field: this.accountKey, index: this.index, value: value});
} // }
} // }
} }
} }
</script> </script>

View File

@@ -27,7 +27,7 @@
<select <select
ref="bill" ref="bill"
:title="$t('firefly.bill')" :title="$t('firefly.bill')"
v-model="bill_id" v-model="value"
autocomplete="off" autocomplete="off"
class="form-control" class="form-control"
name="bill_id[]" name="bill_id[]"
@@ -47,7 +47,7 @@ import {createNamespacedHelpers} from "vuex";
const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('transactions/create') const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('transactions/create')
export default { export default {
props: ['index'], props: ['value', 'index'],
name: "TransactionBill", name: "TransactionBill",
data() { data() {
return { return {
@@ -93,19 +93,18 @@ export default {
} }
}, },
}, },
watch: {
value: function(value) {
this.updateField({field: 'bill_id', index: this.index, value: value});
}
},
computed: { computed: {
...mapGetters([ ...mapGetters(
[
'transactionType', 'transactionType',
'transactions', 'transactions',
]), ]
bill_id: { )
get() {
return this.transactions[this.index].bill_id;
},
set(value) {
this.updateField({field: 'bill_id', index: this.index, value: value});
}
}
} }
} }
</script> </script>

View File

@@ -27,14 +27,13 @@
<select <select
ref="budget" ref="budget"
:title="$t('firefly.budget')" :title="$t('firefly.budget')"
v-model="budget_id" v-model="value"
autocomplete="off" autocomplete="off"
class="form-control" class="form-control"
name="budget_id[]" name="budget_id[]"
v-on:submit.prevent v-on:submit.prevent
> >
<option v-for="budget in this.budgetList" :value="budget.id" :label="budget.name">{{ budget.name }}</option> <option v-for="budget in this.budgetList" :value="budget.id" :label="budget.name">{{ budget.name }}</option>
</select> </select>
</div> </div>
</div> </div>
@@ -47,7 +46,7 @@ import {createNamespacedHelpers} from "vuex";
const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('transactions/create') const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('transactions/create')
export default { export default {
props: ['index'], props: ['index', 'value'],
name: "TransactionBudget", name: "TransactionBudget",
data() { data() {
return { return {
@@ -93,19 +92,18 @@ export default {
} }
}, },
}, },
computed: { watch: {
...mapGetters([ value: function (value) {
'transactionType', this.updateField({field: 'budget_id', index: this.index, value: value});
'transactions',
]),
budget_id: {
get() {
return this.transactions[this.index].budget_id;
},
set(value) {
this.updateField({field: 'budget_id', index: this.index, value: value});
}
} }
},
computed: {
...mapGetters(
[
'transactionType',
'transactions',
]
)
} }
} }
</script> </script>

View File

@@ -26,7 +26,7 @@
<vue-typeahead-bootstrap <vue-typeahead-bootstrap
inputName="category[]" inputName="category[]"
v-model="category" v-model="value"
:data="categories" :data="categories"
:placeholder="$t('firefly.category')" :placeholder="$t('firefly.category')"
:showOnFocus=true :showOnFocus=true
@@ -54,15 +54,13 @@ import {debounce} from "lodash";
const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('transactions/create') const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('transactions/create')
export default { export default {
props: ['index'], props: ['value', 'index'],
components: {VueTypeaheadBootstrap}, components: {VueTypeaheadBootstrap},
name: "TransactionCategory", name: "TransactionCategory",
data() { data() {
return { return {
categories: [], categories: [],
initialSet: [], initialSet: []
category: '',
} }
}, },
@@ -83,7 +81,7 @@ export default {
], ],
), ),
clearCategory: function () { clearCategory: function () {
this.category = ''; this.value = '';
}, },
getACURL: function (query) { getACURL: function (query) {
// update autocomplete URL: // update autocomplete URL:
@@ -91,29 +89,30 @@ export default {
}, },
lookupCategory: debounce(function () { lookupCategory: debounce(function () {
// update autocomplete URL: // update autocomplete URL:
axios.get(this.getACURL(this.category)) axios.get(this.getACURL(this.value))
.then(response => { .then(response => {
this.categories = response.data; this.categories = response.data;
}) })
}, 300) }, 300)
}, },
watch: { watch: {
category: function (value) { value: function (value) {
console.log('Watch category: "' + value + '"');
this.updateField({field: 'category', index: this.index, value: value}); this.updateField({field: 'category', index: this.index, value: value});
} }
}, },
computed: { computed: {
...mapGetters([ ...mapGetters(
[
'transactionType', 'transactionType',
'transactions', 'transactions',
]), ]
),
selectedCategory: { selectedCategory: {
get() { get() {
return this.categories[this.index].name; return this.categories[this.index].name;
}, },
set(value) { set(value) {
this.updateField({field: 'category', index: this.index, value: value.name}); this.value = value.name;
} }
} }
} }

View File

@@ -49,32 +49,21 @@ const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers
export default { export default {
name: "TransactionCustomDates", name: "TransactionCustomDates",
props: ['enabledDates', 'index'], props: ['enabledDates', 'index'],
data() {
return {
dates: {
interest_date: '',
book_date: '',
process_date: '',
due_date: '',
payment_date: '',
invoice_date: '',
}
}
},
created() {
},
methods: { methods: {
...mapGetters(
[
'transactions'
]
),
...mapMutations( ...mapMutations(
[ [
'updateField', 'updateField',
], ],
), ),
getFieldValue(field) { getFieldValue(field) {
return this.dates[field]; return this.transactions()[parseInt(this.index)][field] ?? '';
}, },
setFieldValue(event, field) { setFieldValue(event, field) {
this.dates[field] = event.target.value;
this.updateField({index: this.index, field: field, value: event.target.value}); this.updateField({index: this.index, field: field, value: event.target.value});
} }
} }

View File

@@ -29,11 +29,11 @@
type="date" type="date"
ref="date" ref="date"
:title="$t('firefly.date')" :title="$t('firefly.date')"
v-model="date" v-model="localDate"
:disabled="index > 0" :disabled="index > 0"
autocomplete="off" autocomplete="off"
name="date[]" name="date[]"
:placeholder="date" :placeholder="localDate"
v-on:submit.prevent v-on:submit.prevent
> >
<input <input
@@ -41,11 +41,11 @@
type="time" type="time"
ref="time" ref="time"
:title="$t('firefly.time')" :title="$t('firefly.time')"
v-model="time" v-model="localTime"
:disabled="index > 0" :disabled="index > 0"
autocomplete="off" autocomplete="off"
name="time[]" name="time[]"
:placeholder="time" :placeholder="localTime"
v-on:submit.prevent v-on:submit.prevent
> >
</div> </div>
@@ -60,35 +60,46 @@ const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers
export default { export default {
name: "TransactionDate", name: "TransactionDate",
props: ['value', 'index'], props: ['index'],
methods: { methods: {
...mapMutations( ...mapMutations(
[ [
'updateField', 'updateField',
'setDate'
], ],
), ),
}, },
computed: { computed: {
...mapGetters([ ...mapGetters([
'transactionType', 'transactionType',
'transactions', 'date'
]), ]),
date: { localDate: {
get() { get() {
// always return first index. return this.date.toISOString().split('T')[0];
return this.transactions[0].date;
}, },
set(value) { set(value) {
this.updateField({field: 'date', index: this.index, value: value}); // bit of a hack but meh.
let newDate = new Date(value);
let current = new Date(this.date.getTime());
current.setFullYear(newDate.getFullYear());
current.setMonth(newDate.getMonth());
current.setDate(newDate.getDate());
this.setDate({date: current});
} }
}, },
time: { localTime: {
get() { get() {
// always return first index. return ('0' + this.date.getHours()).slice(-2) + ':' + ('0' + this.date.getMinutes()).slice(-2) + ':' + ('0' + this.date.getSeconds()).slice(-2);
return this.transactions[0].time;
}, },
set(value) { set(value) {
this.updateField({field: 'time', index: this.index, value: value}); // bit of a hack but meh.
let current = new Date(this.date.getTime());
let parts = value.split(':');
current.setHours(parseInt(parts[0]));
current.setMinutes(parseInt(parts[1]));
current.setSeconds(parseInt(parts[2]));
this.setDate({date: current});
} }
} }
} }

View File

@@ -25,7 +25,7 @@
</div> </div>
<vue-typeahead-bootstrap <vue-typeahead-bootstrap
inputName="description[]" inputName="description[]"
v-model="description" v-model="value"
:data="descriptions" :data="descriptions"
:placeholder="$t('firefly.description')" :placeholder="$t('firefly.description')"
:showOnFocus=true :showOnFocus=true
@@ -54,7 +54,7 @@ import {debounce} from "lodash";
const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('transactions/create') const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('transactions/create')
export default { export default {
props: ['index', 'description'], props: ['index', 'value'],
components: {VueTypeaheadBootstrap}, components: {VueTypeaheadBootstrap},
name: "TransactionDescription", name: "TransactionDescription",
data() { data() {
@@ -65,8 +65,6 @@ export default {
}, },
created() { created() {
// initial list of accounts:
axios.get(this.getACURL('')) axios.get(this.getACURL(''))
.then(response => { .then(response => {
this.descriptions = response.data; this.descriptions = response.data;
@@ -81,41 +79,32 @@ export default {
], ],
), ),
clearDescription: function () { clearDescription: function () {
this.description = ''; this.value = '';
}, },
getACURL: function (query) { getACURL: function (query) {
// update autocomplete URL: // update autocomplete URL:
return document.getElementsByTagName('base')[0].href + 'api/v1/autocomplete/transactions?query=' + query; return document.getElementsByTagName('base')[0].href + 'api/v1/autocomplete/transactions?query=' + query;
}, },
lookupDescription: debounce(function () { lookupDescription: debounce(function () {
console.log('lookupDescription');
// update autocomplete URL: // update autocomplete URL:
axios.get(this.getACURL(this.description)) axios.get(this.getACURL(this.value))
.then(response => { .then(response => {
this.descriptions = response.data; this.descriptions = response.data;
}) })
}, 300) }, 300)
}, },
watch: { watch: {
description: function (value) { value: function (value) {
console.log('Index ' + this.index + ': ' + value); this.updateField({field: 'description', index: this.index, value: value});
//this.updateField({field: 'description', index: this.index, value: value});
} }
}, },
computed: { computed: {
...mapGetters([ ...mapGetters(
'transactionType', [
'transactions', 'transactionType',
]), 'transactions',
selectedDescription: { ]
get() { )
//return this.description;
},
set(value) {
this.description = value.description;
//this.updateField({field: 'description', index: this.index, value: value.description});
}
}
} }
} }
</script> </script>

View File

@@ -28,7 +28,7 @@
type="url" type="url"
name="external_url[]" name="external_url[]"
:placeholder="$t('firefly.external_url')" :placeholder="$t('firefly.external_url')"
v-model="externalUrl" v-model="value"
class="form-control"/> class="form-control"/>
<div class="input-group-append"> <div class="input-group-append">
<button type="button" class="btn btn-outline-secondary"><i class="far fa-trash-alt"></i></button> <button type="button" class="btn btn-outline-secondary"><i class="far fa-trash-alt"></i></button>
@@ -43,7 +43,7 @@ import {createNamespacedHelpers} from "vuex";
const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('transactions/create') const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('transactions/create')
export default { export default {
props: ['index'], props: ['index', 'value'],
name: "TransactionExternalUrl", name: "TransactionExternalUrl",
methods: { methods: {
...mapMutations( ...mapMutations(
@@ -52,13 +52,8 @@ export default {
], ],
), ),
}, },
data() {
return {
externalUrl: '',
}
},
watch: { watch: {
externalUrl: function (value) { value: function (value) {
this.updateField({field: 'external_url', index: this.index, value: value}); this.updateField({field: 'external_url', index: this.index, value: value});
} }
} }

View File

@@ -27,7 +27,7 @@
<input <input
type="text" type="text"
name="internal_reference[]" name="internal_reference[]"
v-model="internalReference" v-model="value"
:placeholder="$t('firefly.internal_reference')" :placeholder="$t('firefly.internal_reference')"
class="form-control"/> class="form-control"/>
<div class="input-group-append"> <div class="input-group-append">
@@ -43,7 +43,7 @@ import {createNamespacedHelpers} from "vuex";
const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('transactions/create') const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('transactions/create')
export default { export default {
props: ['index'], props: ['index', 'value'],
name: "TransactionInternalReference", name: "TransactionInternalReference",
methods: { methods: {
...mapMutations( ...mapMutations(
@@ -52,13 +52,8 @@ export default {
], ],
), ),
}, },
data() {
return {
internalReference: '',
}
},
watch: { watch: {
internalReference: function (value) { value: function (value) {
this.updateField({field: 'internal_reference', index: this.index, value: value}); this.updateField({field: 'internal_reference', index: this.index, value: value});
} }
} }

View File

@@ -25,7 +25,7 @@
{{ $t('firefly.notes') }} {{ $t('firefly.notes') }}
</div> </div>
<div class="input-group"> <div class="input-group">
<textarea v-model="notes" class="form-control" placeholder="Notes"></textarea> <textarea v-model="value" class="form-control" :placeholder="$t('firefly.notes')"></textarea>
</div> </div>
</div> </div>
@@ -37,7 +37,7 @@ import {createNamespacedHelpers} from "vuex";
const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('transactions/create') const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('transactions/create')
export default { export default {
props: ['index'], props: ['index', 'value'],
name: "TransactionNotes", name: "TransactionNotes",
methods: { methods: {
...mapMutations( ...mapMutations(
@@ -46,13 +46,8 @@ export default {
], ],
), ),
}, },
data() {
return {
notes: '',
}
},
watch: { watch: {
notes: function (value) { value: function (value) {
this.updateField({field: 'notes', index: this.index, value: value}); this.updateField({field: 'notes', index: this.index, value: value});
} }
} }

View File

@@ -18,7 +18,6 @@
- along with this program. If not, see <https://www.gnu.org/licenses/>. - along with this program. If not, see <https://www.gnu.org/licenses/>.
--> -->
<template> <template>
<div class="form-group"> <div class="form-group">
<div class="text-xs d-none d-lg-block d-xl-block"> <div class="text-xs d-none d-lg-block d-xl-block">
@@ -28,7 +27,7 @@
<select <select
ref="piggy_bank_id" ref="piggy_bank_id"
:title="$t('firefly.piggy_bank')" :title="$t('firefly.piggy_bank')"
v-model="piggy_bank_id" v-model="value"
autocomplete="off" autocomplete="off"
class="form-control" class="form-control"
name="piggy_bank_id[]" name="piggy_bank_id[]"
@@ -48,7 +47,7 @@ import {createNamespacedHelpers} from "vuex";
const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('transactions/create') const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('transactions/create')
export default { export default {
props: ['index'], props: ['index', 'value'],
name: "TransactionPiggyBank", name: "TransactionPiggyBank",
data() { data() {
return { return {
@@ -94,19 +93,16 @@ export default {
} }
}, },
}, },
watch: {
value: function (value) {
this.updateField({field: 'piggy_bank_id', index: this.index, value: value});
}
},
computed: { computed: {
...mapGetters([ ...mapGetters([
'transactionType', 'transactionType',
'transactions', 'transactions',
]), ])
piggy_bank_id: {
get() {
return this.transactions[this.index].piggy_bank_id;
},
set(value) {
this.updateField({field: 'piggy_bank_id', index: this.index, value: value});
}
}
} }
} }
</script> </script>

View File

@@ -25,40 +25,63 @@
</div> </div>
<div class="input-group"> <div class="input-group">
<vue-tags-input <vue-tags-input
v-model="tag" v-model="currentTag"
:add-only-from-autocomplete="false" :add-only-from-autocomplete="false"
:autocomplete-items="autocompleteItems" :autocomplete-items="autocompleteItems"
:tags="tags" :tags="tags"
:title="$t('firefly.tags')" :title="$t('firefly.tags')"
v-bind:placeholder="$t('firefly.tags')" v-bind:placeholder="$t('firefly.tags')"
@tags-changed="update"/> @tags-changed="newTags => this.tags = newTags"
/>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import {createNamespacedHelpers} from "vuex"; import {createNamespacedHelpers} from "vuex";
const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('transactions/create')
import VueTagsInput from "@johmun/vue-tags-input"; import VueTagsInput from "@johmun/vue-tags-input";
import axios from "axios"; import axios from "axios";
const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('transactions/create')
export default { export default {
name: "TransactionTags", name: "TransactionTags",
components: { components: {
VueTagsInput VueTagsInput
}, },
props: ['value', 'error', 'index'], props: ['value', 'index'],
data() { data() {
return { return {
tag: '',
autocompleteItems: [], autocompleteItems: [],
debounce: null, debounce: null,
tags: this.value, tags: [],
currentTag: '',
updateTags: true // the idea is that this is always true, except when the tags-function sets the value.
}; };
}, },
watch: { watch: {
'tag': 'initItems', 'currentTag': 'initItems',
value: function (value) {
console.log('watch: value');
console.log(value);
this.updateField({field: 'tags', index: this.index, value: value});
this.updateTags = false;
this.tags = value;
},
tags: function (value) {
if (this.updateTags) {
console.log('watch: tags');
let shortList = [];
for (let key in value) {
if (value.hasOwnProperty(key)) {
shortList.push({text: value[key].text});
}
}
this.value = shortList;
}
this.updateTags = true;
}
}, },
methods: { methods: {
...mapMutations( ...mapMutations(
@@ -66,36 +89,20 @@ export default {
'updateField', 'updateField',
], ],
), ),
update(newTags) {
this.autocompleteItems = [];
this.tags = newTags;
// create array for update field thing:
let shortList = [];
for(let key in newTags) {
if (newTags.hasOwnProperty(key)) {
shortList.push(newTags[key].text);
}
}
this.updateField({field: 'tags', index: this.index, value: shortList});
},
hasError: function () {
return this.error.length > 0;
},
initItems() { initItems() {
// console.log('Now in initItems'); if (this.currentTag.length < 2) {
if (this.tag.length < 2) {
return; return;
} }
const url = document.getElementsByTagName('base')[0].href + `api/v1/autocomplete/tags?query=${this.tag}`; const url = document.getElementsByTagName('base')[0].href + `api/v1/autocomplete/tags?query=${this.currentTag}`;
clearTimeout(this.debounce); clearTimeout(this.debounce);
this.debounce = setTimeout(() => { this.debounce = setTimeout(() => {
axios.get(url).then(response => { axios.get(url).then(response => {
this.autocompleteItems = response.data.map(a => { this.autocompleteItems = response.data.map(item => {
return {text: a.tag}; return {text: item.tag};
}); });
}).catch(() => console.warn('Oh. Something went wrong loading tags.')); }).catch(() => console.warn('Oh. Something went wrong loading tags.'));
}, 600); }, 300);
}, },
}, },

View File

@@ -22,8 +22,8 @@
"bill": "Rechnung", "bill": "Rechnung",
"no_bill": "(keine Belege)", "no_bill": "(keine Belege)",
"tags": "Schlagw\u00f6rter", "tags": "Schlagw\u00f6rter",
"internal_reference": "Internal reference", "internal_reference": "Interner Verweis",
"external_url": "External URL", "external_url": "Externe URL",
"no_piggy_bank": "(kein Sparschwein)", "no_piggy_bank": "(kein Sparschwein)",
"paid": "Bezahlt", "paid": "Bezahlt",
"notes": "Notizen", "notes": "Notizen",

View File

@@ -22,8 +22,8 @@
"bill": "Facture", "bill": "Facture",
"no_bill": "(aucune facture)", "no_bill": "(aucune facture)",
"tags": "Tags", "tags": "Tags",
"internal_reference": "Internal reference", "internal_reference": "R\u00e9f\u00e9rence interne",
"external_url": "External URL", "external_url": "URL externe",
"no_piggy_bank": "(aucune tirelire)", "no_piggy_bank": "(aucune tirelire)",
"paid": "Pay\u00e9", "paid": "Pay\u00e9",
"notes": "Notes", "notes": "Notes",

View File

@@ -22,8 +22,8 @@
"bill": "Rachunek", "bill": "Rachunek",
"no_bill": "(brak rachunku)", "no_bill": "(brak rachunku)",
"tags": "Tagi", "tags": "Tagi",
"internal_reference": "Internal reference", "internal_reference": "Wewn\u0119trzny nr referencyjny",
"external_url": "External URL", "external_url": "Zewn\u0119trzny adres URL",
"no_piggy_bank": "(brak skarbonki)", "no_piggy_bank": "(brak skarbonki)",
"paid": "Zap\u0142acone", "paid": "Zap\u0142acone",
"notes": "Notatki", "notes": "Notatki",

View File

@@ -22,8 +22,8 @@
"bill": "Fatura", "bill": "Fatura",
"no_bill": "(sem fatura)", "no_bill": "(sem fatura)",
"tags": "Tags", "tags": "Tags",
"internal_reference": "Internal reference", "internal_reference": "Refer\u00eancia interna",
"external_url": "External URL", "external_url": "URL externa",
"no_piggy_bank": "(nenhum cofrinho)", "no_piggy_bank": "(nenhum cofrinho)",
"paid": "Pago", "paid": "Pago",
"notes": "Notas", "notes": "Notas",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long