diff --git a/app/Http/Controllers/Transaction/CreateController.php b/app/Http/Controllers/Transaction/CreateController.php index 8a38cf7a57..dbae963b8d 100644 --- a/app/Http/Controllers/Transaction/CreateController.php +++ b/app/Http/Controllers/Transaction/CreateController.php @@ -100,7 +100,7 @@ class CreateController extends Controller $repository = app(AccountRepositoryInterface::class); $cash = $repository->getCashAccount(); $preFilled = session()->has('preFilled') ? session('preFilled') : []; - $subTitle = (string)trans('breadcrumbs.create_new_transaction'); + $subTitle = (string)trans(sprintf('breadcrumbs.create_%s', strtolower((string)$objectType))); $subTitleIcon = 'fa-plus'; $optionalFields = app('preferences')->get('transaction_journal_optional_fields', [])->data; $allowedOpposingTypes = config('firefly.allowed_opposing_types'); diff --git a/changelog.md b/changelog.md index 2712ea3250..a76e77323c 100644 --- a/changelog.md +++ b/changelog.md @@ -4,10 +4,12 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## 5.5.8 (API 1.5.2) 2021-04-17 +This update fixes some of the more annoying issues in the new experimental v2 layout (see also [GitHub](https://github.com/firefly-iii/firefly-iii/issues/4618)), but some minor other issues as well. + ### Fixed - [Issue 4656](https://github.com/firefly-iii/firefly-iii/issues/4656) [issue 4660](https://github.com/firefly-iii/firefly-iii/issues/4660) Various fixes in the v2 layout. - [Issue 4663](https://github.com/firefly-iii/firefly-iii/issues/4663) It was possible to assign a budget to a transfer. -- [Issue 4664](https://github.com/firefly-iii/firefly-iii/issues/4664) Nullpointer in bulk editor +- [Issue 4664](https://github.com/firefly-iii/firefly-iii/issues/4664) Null pointer in bulk editor - [Issue 4668](https://github.com/firefly-iii/firefly-iii/issues/4668) Inactive rule groups would not be listed. ## 5.5.7 (API 1.5.2) 2021-04-11 diff --git a/frontend/src/components/dashboard/MainAccount.vue b/frontend/src/components/dashboard/MainAccount.vue index 19c65b4ede..8ef7b9e611 100644 --- a/frontend/src/components/dashboard/MainAccount.vue +++ b/frontend/src/components/dashboard/MainAccount.vue @@ -49,12 +49,10 @@ import DataConverter from "../charts/DataConverter"; import DefaultLineOptions from "../charts/DefaultLineOptions"; import {mapGetters} from "vuex"; import * as ChartJs from 'chart.js' + ChartJs.Chart.register.apply(null, Object.values(ChartJs).filter((chartClass) => (chartClass.id))); - - - export default { name: "MainAccount", components: {}, // MainAccountChart @@ -63,6 +61,7 @@ export default { loading: true, error: false, ready: false, + initialised: false, dataCollection: {}, chartOptions: {}, _chart: null, @@ -71,18 +70,18 @@ export default { } }, created() { - this.ready = true; this.chartOptions = DefaultLineOptions.methods.getDefaultOptions(); this.localTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone; this.systemTimeZone = this.timezone; + this.ready = true; }, computed: { - ...mapGetters('dashboard/index',['start', 'end']), - ...mapGetters('root',['timezone']), + ...mapGetters('dashboard/index', ['start', 'end']), + ...mapGetters('root', ['timezone']), 'datesReady': function () { return null !== this.start && null !== this.end && this.ready; }, - timezoneDifference: function() { + timezoneDifference: function () { return this.localTimeZone !== this.systemTimeZone; } }, @@ -93,10 +92,10 @@ export default { } }, start: function () { - //this.initialiseChart(); + this.updateChart(); }, end: function () { - //this.initialiseChart(); + this.updateChart(); }, }, methods: { @@ -116,18 +115,38 @@ export default { this.drawChart(); }) .catch(error => { - // console.log('Has error!'); - // console.log(error); + console.log('Has error!'); + console.log(error); this.error = true; }); }, drawChart: function () { - this._chart = new ChartJs.Chart(this.$refs.canvas.getContext('2d'), { - type: 'line', - data: this.dataCollection, - options: this.chartOptions - } - ); + //console.log('drawChart'); + if ('undefined' !== typeof this._chart) { + //console.log('destroy or update!'); + this._chart.data = this.dataCollection; + this._chart.update(); + } + + if ('undefined' === typeof this._chart) { + //console.log('new!'); + this._chart = new ChartJs.Chart(this.$refs.canvas.getContext('2d'), { + type: 'line', + data: this.dataCollection, + options: this.chartOptions + } + ); + this.initialised = true; + } + }, + updateChart: function () { + //console.log('updateChart'); + if (this.initialised) { + //console.log('MUST Update chart!'); + // reset some vars so it wont trigger again: + this.initialised = false; + this.initialiseChart(); + } } }, } diff --git a/frontend/src/components/store/modules/transactions/create.js b/frontend/src/components/store/modules/transactions/create.js index a432e80d24..899c93b893 100644 --- a/frontend/src/components/store/modules/transactions/create.js +++ b/frontend/src/components/store/modules/transactions/create.js @@ -46,6 +46,9 @@ const getters = { transactions: state => { return state.transactions; }, + defaultErrors: state => { + return state.defaultErrors; + }, groupTitle: state => { return state.groupTitle; }, diff --git a/frontend/src/components/transactions/Create.vue b/frontend/src/components/transactions/Create.vue index 5f315e9285..4692e4d8f7 100644 --- a/frontend/src/components/transactions/Create.vue +++ b/frontend/src/components/transactions/Create.vue @@ -119,6 +119,7 @@ import SplitPills from "./SplitPills"; import TransactionGroupTitle from "./TransactionGroupTitle"; import SplitForm from "./SplitForm"; import {mapGetters, mapMutations} from "vuex"; +import {getDefaultErrors} from "../../shared/transactions"; export default { @@ -198,13 +199,11 @@ export default { /** * Grabbed from the store. */ - ...mapGetters('transactions/create', ['transactionType', 'transactions', 'groupTitle']), + ...mapGetters('transactions/create', ['transactionType', 'transactions', 'groupTitle','defaultErrors']), ...mapGetters('root', ['listPageSize']) }, watch: { submittedAttachments: function () { - // console.log('Watch submittedAttachments'); - this.finaliseSubmission(); } }, @@ -235,63 +234,11 @@ export default { // console.log('Triggered to remove transaction ' + payload.index); this.$store.commit('transactions/create/deleteTransaction', payload); }, - /** - * Submitting a transaction consists of 3 steps: submitting the transaction, uploading attachments - * and creating links. Only once all three steps are executed may the message be shown or the user be - * forwarded. - */ - finalizeSubmitXX() { - // console.log('finalizeSubmit (' + this.submittedTransaction + ', ' + this.submittedAttachments + ', ' + this.submittedLinks + ')'); - if (this.submittedTransaction && this.submittedAttachments && this.submittedLinks) { - // console.log('all true'); - // console.log('createAnother = ' + this.createAnother); - // console.log('inError = ' + this.inError); - if (false === this.createAnother && false === this.inError) { - // console.log('redirect'); - window.location.href = (window.previousURL ?? '/') + '?transaction_group_id=' + this.returnedGroupId + '&message=created'; - return; - } - - if (false === this.inError) { - // show message: - this.errorMessage = ''; - this.successMessage = this.$t('firefly.transaction_stored_link', {ID: this.returnedGroupId, title: this.returnedGroupTitle}); - } - - // enable flags: - this.enableSubmit = true; - this.submittedTransaction = false; - this.submittedLinks = false; - //this.submittedAttachments = false; - this.inError = false; - - - // reset attachments (always do this) - for (let i in this.transactions) { - if (this.transactions.hasOwnProperty(i) && /^0$|^[1-9]\d*$/.test(i) && i <= 4294967294) { - if (this.transactions.hasOwnProperty(i)) { - this.updateField({index: i, field: 'clearTrigger', value: true}); - } - } - } - this.submittedAttCount = []; - - // reset the form: - if (this.resetFormAfter) { - this.resetTransactions(); - // do a short time out? - setTimeout(() => this.addTransaction(), 50); - } - // console.log('Done with finalizeSubmit!'); - // return; - } - // console.log('Did nothing in finalizeSubmit'); - }, - submitData: function (url, data) { return axios.post(url, data); }, handleSubmissionResponse: function (response) { + //console.log('In handleSubmissionResponse()'); // save some meta data: this.returnedGroupId = parseInt(response.data.data.id); this.returnedGroupTitle = null === response.data.data.attributes.group_title ? response.data.data.attributes.transactions[0].description : response.data.data.attributes.group_title; @@ -381,11 +328,13 @@ export default { // console.log('submittedAttachments = ' + this.submittedAttachments); return; } - // console.log('finaliseSubmission'); + //console.log('In finaliseSubmission'); if (false === this.createAnother) { window.location.href = (window.previousURL ?? '/') + '?transaction_group_id=' + this.returnedGroupId + '&message=created'; return; } + //console.log('Is in error?'); + //console.log(this.inError); if (false === this.inError) { // show message: this.errorMessage = ''; @@ -397,13 +346,15 @@ export default { this.submittedTransaction = false; this.submittedAttachments = -1; - // reset attachments + // reset attachments + errors if (!this.resetFormAfter) { for (let i in this.transactions) { if (this.transactions.hasOwnProperty(i) && /^0$|^[1-9]\d*$/.test(i) && i <= 4294967294) { if (this.transactions.hasOwnProperty(i)) { + //this. // console.log('Reset attachment #' + i); this.updateField({index: i, field: 'transaction_journal_id', value: 0}); + this.updateField({index: i, field: 'errors', value: this.defaultErrors}) } } } @@ -422,6 +373,7 @@ export default { }); }, handleSubmissionError: function (error) { + //console.log('in handleSubmissionError'); // oh noes Firefly III has something to bitch about. this.enableSubmit = true; @@ -439,6 +391,13 @@ export default { // disable the submit button: this.enableSubmit = false; + // assume nothing breaks + this.inError = false; + + // remove old warnings etc. + this.successMessage = ''; + this.errorMessage = ''; + // convert the data so its ready to be submitted: const url = './api/v1/transactions'; const data = this.convertData(); @@ -452,63 +411,7 @@ export default { .then(this.finaliseSubmission) .catch(this.handleSubmissionError); - // // console.log('Will submit:'); - // // console.log(data); - // - // // POST the transaction. - // axios.post(url, data) - // .then(response => { - // // console.log('Response is OK!'); - // // report the transaction is submitted. - // this.submittedTransaction = true; - // - // // submit links and attachments (can only be done when the transaction is created) - // this.submitTransactionLinks(data, response); - // this.submitAttachments(data, response); - // - // // meanwhile, store the ID and the title in some easy to access variables. - // this.returnedGroupId = parseInt(response.data.data.id); - // this.returnedGroupTitle = null === response.data.data.attributes.group_title ? response.data.data.attributes.transactions[0].description : response.data.data.attributes.group_title; - // // console.log('Group title is now "' + this.groupTitle + '"'); - // }) - // .catch(error => { - // // oh noes Firefly III has something to bitch about. - // this.enableSubmit = true; - // // console.log('enable submit = true'); - // // report the transaction is submitted. - // this.submittedTransaction = true; - // // also report attachments and links are submitted: - // this.submittedAttachments = true; - // this.submittedLinks = true; - // - // // but report an error because error: - // this.inError = true; - // this.parseErrors(error.response.data); - // }); - } - , - - /** - * Submitting transactions means we will give each TransactionAttachment component - * the ID of the transaction journal (so it works for multiple splits). Each component - * will then start uploading their transactions (so its a separated concern) and report - * back to the "uploadedAttachment" function below via an event emitter. - * - * The ID is set via the store. - */ - submitAttachmentsX: function (data, response) { - // console.log('submitAttachments()'); - let result = response.data.data.attributes.transactions - for (let i in data.transactions) { - if (data.transactions.hasOwnProperty(i) && /^0$|^[1-9]\d*$/.test(i) && i <= 4294967294) { - if (result.hasOwnProperty(i)) { - // console.log('updateField(' + i + ', transaction_journal_id, ' + result[i].transaction_journal_id + ')'); - this.updateField({index: i, field: 'transaction_journal_id', value: result[i].transaction_journal_id}); - } - } - } - } - , + }, /** * When a attachment component is done uploading it ends up here. We create an object where we count how many * attachment components have reported back they're done uploading. Of course if they have nothing to upload @@ -529,8 +432,7 @@ export default { // mark the attachments as stored: this.submittedAttachments = 1; } - } - , + }, /** * Responds to changed location. */ @@ -706,6 +608,7 @@ export default { //console.log('Group title is: "' + this.groupTitle + '"'); if (this.groupTitle.length > 0) { data.group_title = this.groupTitle; + //console.log('1) data.group_title is now "'+data.group_title+'"'); } for (let i in this.transactions) { @@ -713,8 +616,9 @@ export default { data.transactions.push(this.convertSplit(i, this.transactions[i])); } } - if (data.transactions.length > 1 && '' !== data.transactions[0].description) { + if (data.transactions.length > 1 && '' !== data.transactions[0].description && (null === data.group_title || '' === data.group_title)) { data.group_title = data.transactions[0].description; + //console.log('2) data.group_title is now "'+data.group_title+'"'); } // depending on the transaction type for this thing, we need to @@ -764,27 +668,6 @@ export default { }, - // switchAccounts: function (index) { - // // console.log('user wants to switch Accounts'); - // let origSourceId = this.transactions[index].source_account_id; - // let origSourceName = this.transactions[index].source_account_name; - // let origSourceType = this.transactions[index].source_account_type; - // - // let origDestId = this.transactions[index].destination_account_id; - // let origDestName = this.transactions[index].destination_account_name; - // let origDestType = this.transactions[index].destination_account_type; - // - // this.updateField({index: 0, field: 'source_account_id', value: origDestId}); - // this.updateField({index: 0, field: 'source_account_name', value: origDestName}); - // this.updateField({index: 0, field: 'source_account_type', value: origDestType}); - // - // this.updateField({index: 0, field: 'destination_account_id', value: origSourceId}); - // this.updateField({index: 0, field: 'destination_account_name', value: origSourceName}); - // this.updateField({index: 0, field: 'destination_account_type', value: origSourceType}); - // this.calculateTransactionType(0); - // }, - - /** * * @param key diff --git a/frontend/src/components/transactions/TransactionAccount.vue b/frontend/src/components/transactions/TransactionAccount.vue index eedd9a5267..258c0612ed 100644 --- a/frontend/src/components/transactions/TransactionAccount.vue +++ b/frontend/src/components/transactions/TransactionAccount.vue @@ -23,7 +23,7 @@
{{ $t('list.name') }} | \n{{ $t('list.next_expected_match') }} | \n
---|---|
{{ bill.attributes.name }}\n (~ {{\n Intl.NumberFormat(locale, {style: 'currency', currency: bill.attributes.currency_code}).format((parseFloat(bill.attributes.amount_min) +\n parseFloat(bill.attributes.amount_max)) / -2)\n }})\n \n \n {{ bill.attributes.object_group_title }}\n \n | \n \n \n \n \n \n {{ new Intl.DateTimeFormat(locale, {year: 'numeric', month: 'long', day: 'numeric'}).format(new Date(payDate)) }}\n \n \n | \n
{{ $t('firefly.budget') }} | \n{{ $t('firefly.spent') }} | \n{{ $t('firefly.left') }} | \n
---|
{{ $t('firefly.category') }} | \n{{ $t('firefly.spent') }} | \n
---|---|
{{ entry.name }} | \n\n 0\" class=\"progress\">\n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: entry.currency_code}).format(entry.difference_float) }}\n \n \n \n | \n
{{ $t('firefly.category') }} | \n{{ $t('firefly.spent') }} | \n
---|---|
{{ entry.name }} | \n\n 0\" class=\"progress\">\n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: entry.currency_code}).format(entry.difference_float) }}\n \n \n \n | \n
{{ $t('list.piggy_bank') }} | \n{{ $t('list.percentage') }} / {{ $t('list.amount') }} | \n
---|---|
\n {{ piggy.attributes.name }}\n \n \n {{ piggy.attributes.object_group_title }}\n \n | \n \n \n \n \n {{\n Intl.NumberFormat(locale, {style: 'currency', currency: piggy.attributes.currency_code}).format(piggy.attributes.current_amount)\n }}\n \n of\n {{\n Intl.NumberFormat(locale, {\n style: 'currency',\n currency: piggy.attributes.currency_code\n }).format(piggy.attributes.target_amount)\n }}\n \n \n \n \n | \n
{{ $t('firefly.description') }} | \n{{ $t('firefly.opposing_account') }} | \n{{ $t('firefly.amount') }} | \n{{ $t('firefly.category') }} | \n{{ $t('firefly.budget') }} | \n
---|---|---|---|---|
\n \n 1\">{{ transaction.attributes.group_title }}\n {{ transaction.attributes.transactions[0].description }}\n \n | \n\n \n {{ tr.destination_name }}\n {{ tr.source_name }}\n {{ tr.destination_name }}\n {{ tr.source_name }}\n \n \n | \n \n \n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: tr.currency_code}).format(tr.amount * -1) }} \n \n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: tr.currency_code}).format(tr.amount) }} \n \n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: tr.currency_code}).format(tr.amount * -1) }} \n \n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: tr.currency_code}).format(tr.amount) }} \n \n \n | \n \n \n {{ tr.category_name }} \n \n | \n \n \n {{ tr.budget_name }} \n \n | \n
{{ $t('firefly.description') }} | \n{{ $t('firefly.opposing_account') }} | \n{{ $t('firefly.amount') }} | \n
---|---|---|
\n \n 1\">{{ transaction.attributes.group_title }}\n {{ transaction.attributes.transactions[0].description }}\n \n | \n\n \n {{ tr.destination_name }}\n {{ tr.source_name }}\n {{ tr.destination_name }}\n {{ tr.source_name }}\n \n \n | \n \n \n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: tr.currency_code}).format(tr.amount * -1) }} \n \n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: tr.currency_code}).format(tr.amount) }} \n \n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: tr.currency_code}).format(tr.amount * -1) }} \n \n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: tr.currency_code}).format(tr.amount) }} \n \n \n | \n
{{ $t('firefly.description') }} | \n{{ $t('firefly.amount') }} | \n
---|---|
\n \n 1\">{{ transaction.attributes.group_title }}\n {{ transaction.attributes.transactions[0].description }}\n \n | \n\n \n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: tr.currency_code}).format(tr.amount * -1) }} \n \n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: tr.currency_code}).format(tr.amount) }} \n \n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: tr.currency_code}).format(tr.amount * -1) }} \n \n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: tr.currency_code}).format(tr.amount) }} \n \n \n | \n
{{ $t('firefly.category') }} | \n{{ $t('firefly.spent') }} | \n
---|---|
\n {{ category.name }}\n | \n\n \n 0\" class=\"progress\">\n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: category.currency_code}).format(category.spent) }}\n \n\n \n\n \n \n 0\" class=\"progress justify-content-end\" title=\"hello2\">\n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: category.currency_code}).format(category.earned) }}\n \n \n \n\n | \n
{{ $t('list.name') }} | \n{{ $t('list.next_expected_match') }} | \n
---|---|
{{ bill.attributes.name }}\n (~ {{\n Intl.NumberFormat(locale, {style: 'currency', currency: bill.attributes.currency_code}).format((parseFloat(bill.attributes.amount_min) +\n parseFloat(bill.attributes.amount_max)) / -2)\n }})\n \n \n {{ bill.attributes.object_group_title }}\n \n | \n \n \n \n \n \n {{ new Intl.DateTimeFormat(locale, {year: 'numeric', month: 'long', day: 'numeric'}).format(new Date(payDate)) }}\n \n \n | \n
{{ $t('firefly.budget') }} | \n{{ $t('firefly.spent') }} | \n{{ $t('firefly.left') }} | \n
---|
{{ $t('firefly.category') }} | \n{{ $t('firefly.spent') }} | \n
---|---|
{{ entry.name }} | \n\n 0\" class=\"progress\">\n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: entry.currency_code}).format(entry.difference_float) }}\n \n \n \n | \n
{{ $t('firefly.category') }} | \n{{ $t('firefly.spent') }} | \n
---|---|
{{ entry.name }} | \n\n 0\" class=\"progress\">\n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: entry.currency_code}).format(entry.difference_float) }}\n \n \n \n | \n
{{ $t('list.piggy_bank') }} | \n{{ $t('list.percentage') }} / {{ $t('list.amount') }} | \n
---|---|
\n {{ piggy.attributes.name }}\n \n \n {{ piggy.attributes.object_group_title }}\n \n | \n \n \n \n \n {{\n Intl.NumberFormat(locale, {style: 'currency', currency: piggy.attributes.currency_code}).format(piggy.attributes.current_amount)\n }}\n \n of\n {{\n Intl.NumberFormat(locale, {\n style: 'currency',\n currency: piggy.attributes.currency_code\n }).format(piggy.attributes.target_amount)\n }}\n \n \n \n \n | \n
{{ $t('firefly.description') }} | \n{{ $t('firefly.opposing_account') }} | \n{{ $t('firefly.amount') }} | \n{{ $t('firefly.category') }} | \n{{ $t('firefly.budget') }} | \n
---|---|---|---|---|
\n \n 1\">{{ transaction.attributes.group_title }}\n {{ transaction.attributes.transactions[0].description }}\n \n | \n\n \n {{ tr.destination_name }}\n {{ tr.source_name }}\n {{ tr.destination_name }}\n {{ tr.source_name }}\n \n \n | \n \n \n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: tr.currency_code}).format(tr.amount * -1) }} \n \n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: tr.currency_code}).format(tr.amount) }} \n \n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: tr.currency_code}).format(tr.amount * -1) }} \n \n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: tr.currency_code}).format(tr.amount) }} \n \n \n | \n \n \n {{ tr.category_name }} \n \n | \n \n \n {{ tr.budget_name }} \n \n | \n
{{ $t('firefly.description') }} | \n{{ $t('firefly.opposing_account') }} | \n{{ $t('firefly.amount') }} | \n
---|---|---|
\n \n 1\">{{ transaction.attributes.group_title }}\n {{ transaction.attributes.transactions[0].description }}\n \n | \n\n \n {{ tr.destination_name }}\n {{ tr.source_name }}\n {{ tr.destination_name }}\n {{ tr.source_name }}\n \n \n | \n \n \n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: tr.currency_code}).format(tr.amount * -1) }} \n \n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: tr.currency_code}).format(tr.amount) }} \n \n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: tr.currency_code}).format(tr.amount * -1) }} \n \n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: tr.currency_code}).format(tr.amount) }} \n \n \n | \n
{{ $t('firefly.description') }} | \n{{ $t('firefly.amount') }} | \n
---|---|
\n \n 1\">{{ transaction.attributes.group_title }}\n {{ transaction.attributes.transactions[0].description }}\n \n | \n\n \n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: tr.currency_code}).format(tr.amount * -1) }} \n \n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: tr.currency_code}).format(tr.amount) }} \n \n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: tr.currency_code}).format(tr.amount * -1) }} \n \n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: tr.currency_code}).format(tr.amount) }} \n \n \n | \n
{{ $t('firefly.category') }} | \n{{ $t('firefly.spent') }} | \n
---|---|
\n {{ category.name }}\n | \n\n \n 0\" class=\"progress\">\n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: category.currency_code}).format(category.spent) }}\n \n\n \n\n \n \n 0\" class=\"progress justify-content-end\" title=\"hello2\">\n \n {{ Intl.NumberFormat(locale, {style: 'currency', currency: category.currency_code}).format(category.earned) }}\n \n \n \n\n | \n
\n \n
\n\n
\n \n
\n\n
\n \n
\n\n
\n \n
\n\n