Rebuild frontend.

This commit is contained in:
James Cole
2021-01-03 07:11:44 +01:00
parent ff2640276c
commit d24a046570
42 changed files with 939 additions and 185 deletions

View File

@@ -28,8 +28,16 @@ const state = () => ({
transactions: [],
allowedOpposingTypes: {},
accountToTransaction: {},
sourceAllowedTypes: ['Asset account','Loan','Debt','Mortgage','Revenue account'],
destinationAllowedTypes: ['Asset account','Loan','Debt','Mortgage','Expense account'],
sourceAllowedTypes: ['Asset account', 'Loan', 'Debt', 'Mortgage', 'Revenue account'],
destinationAllowedTypes: ['Asset account', 'Loan', 'Debt', 'Mortgage', 'Expense account'],
customDateFields: {
interest_date: false,
book_date: false,
process_date: false,
due_date: false,
payment_date: false,
invoice_date: false,
},
defaultTransaction: {
// basic
description: '',
@@ -57,10 +65,22 @@ const state = () => ({
currency_decimal_places: 2
},
source_allowed_types: ['Asset account', 'Revenue account', 'Loan', 'Debt', 'Mortgage'],
// amount:
amount: '',
currency_id: 0,
foreign_amount: '',
foreign_currency_id: 0,
// meta data
budget_id: 0
budget_id: 0,
// optional date fields (6x):
interest_date: null,
book_date: null,
process_date: null,
due_date: null,
payment_date: null,
invoice_date: null,
},
}
)
@@ -86,6 +106,9 @@ const getters = {
allowedOpposingTypes: state => {
return state.allowedOpposingTypes;
},
customDateFields: state => {
return state.customDateFields;
}
// // `getters` is localized to this module's getters
// // you can use rootGetters via 4th argument of getters
// someGetter (state, getters, rootState, rootGetters) {
@@ -123,13 +146,13 @@ const actions = {
}
}
// console.log('Found no type for ' + source.type + ' --> ' + dest.type);
if('Asset account' !== source.type) {
if ('Asset account' !== source.type) {
console.log('Drop ID from source. TODO');
// source.id =null
// context.commit('updateField', {field: 'source_account',index: })
// context.state.transactions[0].source_account.id = null;
}
if('Asset account' !== dest.type) {
if ('Asset account' !== dest.type) {
console.log('Drop ID from destination. TODO');
//context.state.transactions[0].destination_account.id = null;
}
@@ -144,6 +167,9 @@ const mutations = {
let newTransaction = lodashClonedeep(state.defaultTransaction);
state.transactions.push(newTransaction);
},
setCustomDateFields(state, payload) {
state.customDateFields = payload;
},
deleteTransaction(state, index) {
state.transactions.splice(index, 1);
},

View File

@@ -56,7 +56,6 @@
</div>
<!-- source and destination -->
<div class="row">
<div class="col-xl-5 col-lg-5 col-md-10 col-sm-12 col-xs-12">
@@ -70,7 +69,7 @@
<!-- switcharoo! -->
<div class="col-xl-2 col-lg-2 col-md-2 col-sm-12 text-center d-none d-sm-block">
<SwitchAccount
:index="index"
:index="index"
/>
</div>
@@ -89,22 +88,16 @@
<div class="row">
<div class="col-xl-5 col-lg-5 col-md-10 col-sm-12 col-xs-12">
<!-- AMOUNT -->
<TransactionAmount />
<TransactionAmount :index="index"/>
<!--
-->
</div>
<div class="col-xl-2 col-lg-2 col-md-2 col-sm-12 text-center d-none d-sm-block">
<!-- SELECT FOR FOREIGN -->
<!--
(select)
-->
<TransactionForeignCurrency :index="index"/>
</div>
<div class="col-xl-5 col-lg-5 col-md-12 col-sm-12 col-xs-12">
<!-- FOREIGN AMOUNT -->
<!--
Foreign
-->
<TransactionForeignAmount :index="index"/>
</div>
</div>
@@ -119,23 +112,7 @@
</div>
<div class="col-xl-5 col-lg-5 col-md-12 col-sm-12 col-xs-12 offset-xl-2 offset-lg-2">
<!-- TODO other time slots -->
<div class="form-group">
<div class="text-xs d-none d-lg-block d-xl-block">
other dates
</div>
<div class="input-group">
<input class="form-control" type="date" value="2020-12-12">
</div>
</div>
<div class="form-group">
<div class="text-xs d-none d-lg-block d-xl-block">
other dates
</div>
<div class="input-group">
<input class="form-control" type="date" value="2020-12-12">
</div>
</div>
<TransactionCustomDates :index="index" :enabled-dates="customDateFields"/>
</div>
</div>
@@ -206,7 +183,6 @@
<input
title="Category"
autocomplete="off"
autofocus
class="form-control"
name="something[]"
type="text"
@@ -219,7 +195,6 @@
<input
title="Bill"
autocomplete="off"
autofocus
class="form-control"
name="something[]"
type="text"
@@ -230,7 +205,6 @@
<input
title="Tags"
autocomplete="off"
autofocus
class="form-control"
name="something[]"
type="text"
@@ -241,7 +215,6 @@
<input
title="Piggy"
autocomplete="off"
autofocus
class="form-control"
name="something[]"
type="text"
@@ -259,7 +232,6 @@
<input
title="internal ref"
autocomplete="off"
autofocus
class="form-control"
name="something[]"
type="text"
@@ -270,7 +242,6 @@
<input
title="Piggy"
autocomplete="off"
autofocus
class="form-control"
name="something[]"
type="text"
@@ -286,7 +257,6 @@
<input
title="Piggy"
autocomplete="off"
autofocus
class="form-control"
name="something[]"
type="text"
@@ -297,7 +267,6 @@
<input
title="Piggy"
autocomplete="off"
autofocus
class="form-control"
name="something[]"
type="text"
@@ -346,16 +315,24 @@ import {createNamespacedHelpers} from 'vuex'
import TransactionAccount from "./TransactionAccount";
import SwitchAccount from "./SwitchAccount";
import TransactionAmount from "./TransactionAmount";
import TransactionForeignAmount from "./TransactionForeignAmount";
import TransactionForeignCurrency from "./TransactionForeignCurrency";
import TransactionCustomDates from "./TransactionCustomDates";
const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('transactions/create')
export default {
name: "Create",
components: {TransactionAmount, SwitchAccount, TransactionAccount, TransactionBudget, TransactionDescription, TransactionDate},
components: {
TransactionCustomDates,
TransactionForeignCurrency,
TransactionForeignAmount, TransactionAmount, SwitchAccount, TransactionAccount, TransactionBudget, TransactionDescription, TransactionDate
},
created() {
this.storeAllowedOpposingTypes();
this.storeAccountToTransaction();
this.storeCustomDateFields();
this.addTransaction();
},
data() {
@@ -368,6 +345,7 @@ export default {
...mapGetters([
'transactionType', // -> this.someGetter
'transactions', // -> this.someOtherGetter
'customDateFields'
])
},
methods: {
@@ -379,13 +357,36 @@ export default {
'setAccountToTransaction',
],
),
storeCustomDateFields: function () {
// TODO may include all custom fields in the future.
axios.get('./api/v1/preferences/transaction_journal_optional_fields').then(response => {
let fields = response.data.data.attributes.data;
let allDateFields = ['interest_date', 'book_date', 'process_date', 'due_date', 'payment_date', 'invoice_date'];
let selectedDateFields = {
interest_date: false,
book_date: false,
process_date: false,
due_date: false,
payment_date: false,
invoice_date: false,
};
for (let key in fields) {
if (fields.hasOwnProperty(key)) {
if(-1 !== allDateFields.indexOf(key)) {
selectedDateFields[key] = fields[key];
}
}
}
this.$store.commit('transactions/create/setCustomDateFields', selectedDateFields);
});
},
/**
*
*/
storeAllowedOpposingTypes: function () {
this.setAllowedOpposingTypes(window.allowedOpposingTypes);
},
storeAccountToTransaction: function() {
storeAccountToTransaction: function () {
this.setAccountToTransaction(window.accountToTransaction);
},
/**
@@ -428,7 +429,7 @@ export default {
let currentSplit = {
// basic
description: array.description,
date: array.date + ' ' + array.time,
date: (array.date + ' ' + array.time).trim(),
// account
source_id: array.source_account.id ?? null,
@@ -436,6 +437,13 @@ export default {
destination_id: array.destination_account.id ?? null,
destination_name: array.destination_account.name ?? null,
// amount:
currency_id: array.currency_id,
amount: array.amount,
foreign_currency_id: array.foreign_currency_id,
foreign_amount: array.foreign_amount,
// meta
budget_id: array.budget_id,

View File

@@ -23,16 +23,17 @@
<div class="text-xs">{{ $t('firefly.amount') }}</div>
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text">{{ this.currencySymbol }}</div>
<div class="input-group-text">{{ currencySymbol }}</div>
</div>
<input type="hidden" name="currency_id[]" :value="currencyId"/>
<input
title="Amount"
:title="$t('firefly.amount')"
autocomplete="off"
autofocus
class="form-control"
name="amount[]"
type="number"
placeholder="Amount"
v-model="amount"
:placeholder="$t('firefly.amount')"
>
</div>
</div>
@@ -48,26 +49,65 @@ const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers
export default {
name: "TransactionAmount",
props: ['index'],
data() {
return {
currencySymbol: '',
currencySymbol: ''
}
},
watch: {
selectedTransactionType: function (value) {
console.log('TransactionAmount just noticed transaction type is now ' + value);
}
transactionType: function (value) {
switch (value) {
case 'Transfer':
case 'Withdrawal':
// take currency from source:
this.currencyId = this.transactions[this.index].source_account.currency_id;
this.currencySymbol = this.transactions[this.index].source_account.currency_symbol;
return;
case 'Deposit':
// take currency from destination:
this.currencyId = this.transactions[this.index].destination_account.currency_id;
this.currencySymbol = this.transactions[this.index].destination_account.currency_symbol;
return;
}
},
destinationAllowedTypes: function (value) {
// aka source was updated. if source is asset/loan/debt/mortgage use it to set the currency:
if ('undefined' !== typeof this.transactions[this.index].source_account.type) {
if (['Asset account', 'Loan', 'Debt', 'Mortgage'].indexOf(this.transactions[this.index].source_account.type) !== -1) {
// get currency pref from source account
this.currencyId = this.transactions[this.index].source_account.currency_id;
this.currencySymbol = this.transactions[this.index].source_account.currency_symbol;
}
}
},
sourceAllowedTypes: function (value) {
// aka destination was updated. if destination is asset/loan/debt/mortgage use it to set the currency:
// unless its already known to be a transfer
if ('undefined' !== typeof this.transactions[this.index].destination_account.type && 'Transfer' !== this.transactionType) {
if (['Asset account', 'Loan', 'Debt', 'Mortgage'].indexOf(this.transactions[this.index].destination_account.type) !== -1) {
// get currency pref from destination account
this.currencyId = this.transactions[this.index].destination_account.currency_id;
this.currencySymbol = this.transactions[this.index].destination_account.currency_symbol;
}
}
},
},
created: function() {
console.log('TransactionAmount is created.');
created: function () {
this.updateCurrency();
},
methods: {
updateCurrency: function() {
if('any' === this.transactionType) {
...mapMutations(
[
'updateField',
],
),
updateCurrency: function () {
if (0 === this.currencyId) {
// use default currency from store.
this.currencySymbol = this.currencyPreference.symbol;
this.currencyId = this.currencyPreference.id;
}
}
},
@@ -80,7 +120,25 @@ export default {
...mapGetters([
'transactionType',
'transactions',
'destinationAllowedTypes',
'sourceAllowedTypes',
]),
amount: {
get() {
return this.transactions[this.index].amount;
},
set(value) {
this.updateField({field: 'amount', index: this.index, value: value});
}
},
currencyId: {
get() {
return this.transactions[this.index].currency_id;
},
set(value) {
this.updateField({field: 'currency_id', index: this.index, value: value});
}
},
selectedTransactionType: {
get() {
return this.transactionType;

View File

@@ -0,0 +1,86 @@
<!--
- TransactionCustomDates.vue
- Copyright (c) 2021 james@firefly-iii.org
-
- This file is part of Firefly III (https://github.com/firefly-iii).
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<template>
<div>
<div class="form-group" v-for="(enabled, name) in enabledDates">
<div class="text-xs d-none d-lg-block d-xl-block" v-if="enabled">
{{ $t('form.' + name) }}
</div>
<div class="input-group" v-if="enabled">
<input
class="form-control"
type="date"
:ref="name"
:title="$t('form.' + name)"
:value="getFieldValue(name)"
@change="setFieldValue($event, name)"
autocomplete="off"
:name="name + '[]'"
:placeholder="$t('form.' + name)"
v-on:submit.prevent
>
</div>
</div>
</div>
</template>
<script>
import {createNamespacedHelpers} from "vuex";
const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('transactions/create')
export default {
name: "TransactionCustomDates",
props: ['enabledDates', 'index'],
data() {
return {
dates: {
interest_date: '',
book_date: '',
process_date: '',
due_date: '',
payment_date: '',
invoice_date: '',
}
}
},
created() {
},
methods: {
...mapMutations(
[
'updateField',
],
),
getFieldValue(field) {
return this.dates[field];
},
setFieldValue(event, field) {
this.dates[field] = event.target.value;
this.updateField({index: this.index, field: field, value: event.target.value});
}
}
}
</script>
<style scoped>
</style>

View File

@@ -29,6 +29,7 @@
:data="descriptions"
:placeholder="$t('firefly.description')"
:showOnFocus=true
autofocus
:minMatchingChars="3"
:serializer="item => item.description"
@hit="selectedDescription = $event"

View File

@@ -0,0 +1,159 @@
<!--
- TransactionForeignAmount.vue
- Copyright (c) 2020 james@firefly-iii.org
-
- This file is part of Firefly III (https://github.com/firefly-iii).
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<template>
<!-- FOREIGN AMOUNT -->
<div class="form-group">
<input type="hidden" name="foreign_currency_id[]" :value="currencyId"/>
<div class="text-xs">{{ $t('form.foreign_amount') }}</div>
<div class="input-group">
<input
:title="$t('form.foreign_amount')"
autocomplete="off"
class="form-control"
:disabled="0===currencyId"
name="foreign_amount[]"
type="number"
v-model="amount"
:placeholder="$t('form.foreign_amount')"
>
</div>
</div>
</template>
<script>
import {createNamespacedHelpers} from "vuex";
const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('transactions/create')
//const {mapRootState, mapRootGetters, mapRootActions, mapRootMutations} = createHelpers('');
export default {
name: "TransactionForeignAmount",
props: ['index'],
data() {
return {
currencySymbol: '',
allCurrencies: [],
selectableCurrencies: [],
}
},
watch: {
transactionType: function (value) {
// switch (value) {
// case 'Transfer':
// case 'Withdrawal':
// // take currency from source:
// //this.currencyId = this.transactions[this.index].source_account.currency_id;
// this.currencySymbol = this.transactions[this.index].source_account.currency_symbol;
// return;
// case 'Deposit':
// // take currency from destination:
// this.currencyId = this.transactions[this.index].destination_account.currency_id;
// this.currencySymbol = this.transactions[this.index].destination_account.currency_symbol;
// return;
// }
},
destinationAllowedTypes: function (value) {
// // aka source was updated. if source is asset/loan/debt/mortgage use it to set the currency:
// if ('undefined' !== typeof this.transactions[this.index].source_account.type) {
// if (['Asset account', 'Loan', 'Debt', 'Mortgage'].indexOf(this.transactions[this.index].source_account.type) !== -1) {
// // get currency pref from source account
// this.currencyId = this.transactions[this.index].source_account.currency_id;
// this.currencySymbol = this.transactions[this.index].source_account.currency_symbol;
// }
// }
},
sourceAllowedTypes: function (value) {
// // aka destination was updated. if destination is asset/loan/debt/mortgage use it to set the currency:
// // unless its already known to be a transfer
// if ('undefined' !== typeof this.transactions[this.index].destination_account.type && 'Transfer' !== this.transactionType) {
// if (['Asset account', 'Loan', 'Debt', 'Mortgage'].indexOf(this.transactions[this.index].destination_account.type) !== -1) {
// // get currency pref from destination account
// this.currencyId = this.transactions[this.index].destination_account.currency_id;
// this.currencySymbol = this.transactions[this.index].destination_account.currency_symbol;
// }
// }
},
},
created: function () {
},
methods: {
...mapMutations(
[
'updateField',
],
),
// updateCurrency: function () {
// if (0 === this.currencyId) {
// // use default currency from store.
// this.currencySymbol = this.currencyPreference.symbol;
// this.currencyId = this.currencyPreference.id;
// }
// }
},
computed: {
currencyPreference: {
get() {
return this.$store.state.currencyPreference;
}
},
...mapGetters([
'transactionType',
'transactions',
'destinationAllowedTypes',
'sourceAllowedTypes',
]),
amount: {
get() {
return this.transactions[this.index].foreign_amount;
},
set(value) {
this.updateField({field: 'foreign_amount', index: this.index, value: value});
}
},
currencyId: {
get() {
return this.transactions[this.index].foreign_currency_id;
},
set(value) {
this.updateField({field: 'foreign_currency_id', index: this.index, value: value});
}
},
selectedTransactionType: {
get() {
return this.transactionType;
},
set(value) {
// console.log('set selectedAccount for ' + this.direction);
// console.log(value);
// this.updateField({field: this.accountKey, index: this.index, value: value});
}
}
}
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,201 @@
<!--
- TransactionForeignCurrency.vue
- Copyright (c) 2020 james@firefly-iii.org
-
- This file is part of Firefly III (https://github.com/firefly-iii).
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Affero General Public License for more details.
-
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<template>
<!-- FOREIGN Currency -->
<div class="form-group" v-if="selectIsVisible">
<div class="text-xs">&nbsp;</div>
<div class="input-group">
<select name="foreign_currency_id[]" v-model="currencyId" class="form-control">
<option v-for="currency in selectableCurrencies" :label="currency.name" :value="currency.id">{{ currency.name }}</option>
</select>
</div>
</div>
</template>
<script>
import {createNamespacedHelpers} from "vuex";
const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('transactions/create')
export default {
name: "TransactionForeignCurrency",
props: ['index'],
data() {
return {
allCurrencies: [],
selectableCurrencies: [],
lockedCurrency: 0,
selectIsVisible: true
}
},
watch: {
transactionType: function (value) {
this.lockedCurrency = 0;
if ('Transfer' === value) {
// take currency from destination:
this.currencyId = this.transactions[this.index].destination_account.currency_id;
this.currencySymbol = this.transactions[this.index].destination_account.currency_symbol;
this.lockedCurrency = this.currencyId;
}
this.filterCurrencies();
this.checkVisibility();
},
destinationAllowedTypes: function (value) {
this.lockedCurrency = 0;
if ('Transfer' === this.transactionType) {
// take currency from destination:
this.currencyId = this.transactions[this.index].destination_account.currency_id;
this.currencySymbol = this.transactions[this.index].destination_account.currency_symbol;
this.lockedCurrency = this.currencyId;
}
this.filterCurrencies();
this.checkVisibility();
},
sourceAllowedTypes: function (value) {
this.lockedCurrency = 0;
if ('Transfer' === this.transactionType) {
// take currency from destination:
this.currencyId = this.transactions[this.index].destination_account.currency_id;
this.currencySymbol = this.transactions[this.index].destination_account.currency_symbol;
this.lockedCurrency = this.currencyId;
}
this.filterCurrencies();
this.checkVisibility();
},
},
created: function () {
this.getAllCurrencies();
},
methods: {
...mapMutations(
[
'updateField',
],
),
checkVisibility: function () {
// have the same currency ID, but not zero, and is a transfer
let sourceId = this.transactions[this.index].source_account.currency_id;
let destId = this.transactions[this.index].destination_account.currency_id;
this.selectIsVisible = true;
if (sourceId === destId && 0 !== sourceId && 'Transfer' === this.transactionType) {
this.selectIsVisible = false;
this.currencyId = 0;
}
},
getAllCurrencies: function () {
axios.get('./api/v1/autocomplete/currencies')
.then(response => {
this.allCurrencies = response.data;
this.filterCurrencies();
}
);
},
filterCurrencies() {
// if a currency is locked only that currency can (and must) be selected:
if (0 !== this.lockedCurrency) {
for (let key in this.allCurrencies) {
if (this.allCurrencies.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
let current = this.allCurrencies[key];
if (current.id === this.lockedCurrency) {
this.selectableCurrencies = [current];
this.currencyId = current.id;
}
}
}
return;
}
this.selectableCurrencies = [
{
"id": 0,
"name": this.$t('firefly.no_currency')
}
];
for (let key in this.allCurrencies) {
if (this.allCurrencies.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
let current = this.allCurrencies[key];
// add to array if not "locked" in place:
if (this.transactions[this.index].currency_id !== current.id) {
this.selectableCurrencies.push(current);
}
// deselect impossible currency.
if (this.transactions[this.index].currency_id === current.id && this.currencyId === current.id) {
this.currencyId = 0;
}
}
}
//currency_id
// always add empty currency:
// this.selectableCurrencies = this.allCurrencies;
// this.selectableCurrencies.reverse();
// this.selectableCurrencies.push(
// ;
// this.selectableCurrencies.reverse();
// remove
}
// updateCurrency: function () {
// if (0 === this.currencyId) {
// // use default currency from store.
// this.currencySymbol = this.currencyPreference.symbol;
// this.currencyId = this.currencyPreference.id;
// }
// }
},
computed: {
currencyPreference: {
get() {
return this.$store.state.currencyPreference;
}
},
...mapGetters([
'transactionType',
'transactions',
'destinationAllowedTypes',
'sourceAllowedTypes',
]),
currencyId: {
get() {
return this.transactions[this.index].foreign_currency_id;
},
set(value) {
this.updateField({field: 'foreign_currency_id', index: this.index, value: value});
}
},
normalCurrencyId: {
get() {
return this.transactions[this.index].currency_id;
},
},
}
}
</script>
<style scoped>
</style>