Update frontend.

This commit is contained in:
James Cole 2021-02-14 07:53:20 +01:00
parent 45f918963e
commit 70aaa67cfc
No known key found for this signature in database
GPG Key ID: B5669F9493CDE38D
44 changed files with 479 additions and 452 deletions

View File

@ -118,6 +118,7 @@ REDIS_CACHE_DB="1"
COOKIE_PATH="/"
COOKIE_DOMAIN=
COOKIE_SECURE=false
COOKIE_SAMESITE=lax
# If you want Firefly III to mail you, update these settings
# For instructions, see: https://docs.firefly-iii.org/advanced-installation/email

View File

@ -36,5 +36,5 @@ return [
'domain' => env('COOKIE_DOMAIN', null),
'secure' => env('COOKIE_SECURE', null),
'http_only' => true,
'same_site' => null,
'same_site' => env('COOKIE_SAMESITE','lax'),
];

View File

@ -1,22 +1,12 @@
{
"/public/js/manifest.js": "/public/js/manifest.js",
"/public/js/manifest.js.map": "/public/js/manifest.js.map",
"/public/js/vendor.js": "/public/js/vendor.js",
"/public/js/vendor.js.map": "/public/js/vendor.js.map",
"/public/js/accounts/index.js": "/public/js/accounts/index.js",
"/public/js/accounts/index.js.map": "/public/js/accounts/index.js.map",
"/public/js/accounts/show.js": "/public/js/accounts/show.js",
"/public/js/accounts/show.js.map": "/public/js/accounts/show.js.map",
"/public/js/dashboard.js": "/public/js/dashboard.js",
"/public/css/app.css": "/public/css/app.css",
"/public/js/dashboard.js.map": "/public/js/dashboard.js.map",
"/public/css/app.css.map": "/public/css/app.css.map",
"/public/js/empty.js": "/public/js/empty.js",
"/public/js/empty.js.map": "/public/js/empty.js.map",
"/public/js/manifest.js": "/public/js/manifest.js",
"/public/js/new-user/index.js": "/public/js/new-user/index.js",
"/public/js/new-user/index.js.map": "/public/js/new-user/index.js.map",
"/public/js/register.js": "/public/js/register.js",
"/public/js/register.js.map": "/public/js/register.js.map",
"/public/js/transactions/create.js": "/public/js/transactions/create.js",
"/public/js/transactions/create.js.map": "/public/js/transactions/create.js.map"
"/public/js/vendor.js": "/public/js/vendor.js"
}

View File

@ -50,7 +50,7 @@
<div class="progress-bar bg-danger progress-bar-striped" role="progressbar"
:aria-valuenow="budgetLimit.pctRed" aria-valuemin="0" aria-valuemax="100" :style="'width: '+ budgetLimit.pctRed + '%;'">
<span v-if="budgetLimit.pctOrange <= 50 && budgetLimit.pctRed > 35">
<span v-if="budgetLimit.pctOrange <= 50 && budgetLimit.pctRed > 35" class="text-muted">
Spent
{{ Intl.NumberFormat(locale, {style: 'currency', currency: budgetLimit.currency_code}).format(budgetLimit.spent) }}
of
@ -59,7 +59,7 @@
</div>
<!-- amount if bar is very small -->
<span v-if="budgetLimit.pctGreen <= 35 && 0 === budgetLimit.pctOrange && 0 === budgetLimit.pctRed">
<span v-if="budgetLimit.pctGreen <= 35 && 0 === budgetLimit.pctOrange && 0 === budgetLimit.pctRed && 0 !== budgetLimit.pctGreen">
&nbsp;
Spent
{{ Intl.NumberFormat(locale, {style: 'currency', currency: budgetLimit.currency_code}).format(budgetLimit.spent) }}

View File

@ -18,6 +18,7 @@
- along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<template>
<tr>
<td style="width:25%;">

View File

@ -31,7 +31,7 @@
<date-picker
v-model="range"
mode="date"
rows="2"
:rows="2"
is-range
>
<template v-slot="{ inputValue, inputEvents, isDragging, togglePopover }">
@ -40,7 +40,7 @@
<div class="btn-group btn-group-sm d-flex">
<button
class="btn btn-secondary btn-sm" :title="$t('firefly.custom_period')"
@click="togglePopover({ placement: 'auto-start', positionFixed:true })"
@click="togglePopover({ placement: 'auto-start', positionFixed: true })"
><i class="fas fa-calendar-alt"></i></button>
<button
class="btn btn-secondary"
@ -78,6 +78,7 @@
</template>
<script>
import {createNamespacedHelpers} from "vuex";
const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('dashboard/index')
@ -88,7 +89,14 @@ export default {
this.ready = true;
this.locale = localStorage.locale ?? 'en-US';
},
methods: {
...mapMutations(
[
'setEnd',
'setStart',
],
),
},
computed: {
...mapGetters([
'viewRange',
@ -106,6 +114,11 @@ export default {
this.range.end = new Date(this.end);
}
},
range: function(value) {
console.log('User updated range');
this.setStart(value.start);
this.setEnd(value.end);
}
},
data() {
return {

View File

@ -60,31 +60,7 @@
</template>
<script>
import {createNamespacedHelpers} from "vuex";
const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('dashboard/index')
export default {
name: "Dashboard",
created() {
},
computed: {
...mapGetters([
'viewRange',
'start',
'end'
])
},
methods: {},
watch: {
start: function (value) {
// console.log('Value of start is now ' + value);
},
end: function (value) {
// console.log('Value of end is now ' + value);
},
}
}
</script>

View File

@ -25,7 +25,7 @@
</div>
<div class="card-body">
<div v-if="!loading">
<MainAccountChart :chart-data="dataCollection" :options="chartOptions" v-if="!loading && !error" />
<MainAccountChart :chart-data="dataCollection" :options="chartOptions" v-if="!loading && !error"/>
</div>
<div v-if="loading && !error" class="text-center">
<i class="fas fa-spinner fa-spin"></i>
@ -41,11 +41,13 @@
</template>
<script>
import DataConverter from "../charts/DataConverter";
import DefaultLineOptions from "../charts/DefaultLineOptions";
import {createNamespacedHelpers} from "vuex";
import MainAccountChart from "./MainAccountChart";
const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('dashboard/index')
export default {
@ -61,7 +63,7 @@ export default {
}
},
created() {
this.ready= true;
this.ready = true;
this.chartOptions = DefaultLineOptions.methods.getDefaultOptions();
},
computed: {
@ -79,10 +81,17 @@ export default {
// console.log(this.chartOptions);
this.initialiseChart();
}
}
},
start: function () {
this.initialiseChart();
},
end: function () {
this.initialiseChart();
},
},
methods: {
initialiseChart: function () {
this.loading = true;
let startStr = this.start.toISOString().split('T')[0];
let endStr = this.end.toISOString().split('T')[0];
let url = './api/v1/chart/account/overview?start=' + startStr + '&end=' + endStr;

View File

@ -20,6 +20,7 @@
-->
<script>
import { Line, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins

View File

@ -19,29 +19,53 @@
-->
<template>
<div class="row">
<div v-bind:class="{ 'col-lg-12': 1 === accounts.length, 'col-lg-6': 2 === accounts.length, 'col-lg-4': accounts.length > 2 }"
v-for="account in accounts">
<div class="card">
<div class="card-header">
<h3 class="card-title"><a :href="account.url">{{ account.title }}</a></h3>
<div class="card-tools">
<div>
<!-- row if loading -->
<div class="row" v-if="loading && !error">
<div class="col">
<div class="card">
<div class="card-body">
<div class="text-center">
<i class="fas fa-spinner fa-spin"></i>
</div>
</div>
</div>
</div>
</div>
<!-- row if error -->
<div class="row" v-if="error">
<div class="col">
<div class="card">
<div class="card-body">
<div class="text-center">
<i class="fas fa-exclamation-triangle text-danger"></i>
</div>
</div>
</div>
</div>
</div>
<!-- row if normal -->
<div class="row" v-if="!loading && !error">
<div
v-bind:class="{ 'col-lg-12': 1 === accounts.length, 'col-lg-6': 2 === accounts.length, 'col-lg-4': accounts.length > 2 }"
v-for="account in accounts">
<div class="card">
<div class="card-header">
<h3 class="card-title"><a :href="account.url">{{ account.title }}</a></h3>
<div class="card-tools">
<span :class="parseFloat(account.current_balance) < 0 ? 'text-danger' : 'text-success'">
{{ Intl.NumberFormat(locale, {style: 'currency', currency: account.currency_code}).format(parseFloat(account.current_balance)) }}
</span>
</div>
</div>
</div>
<div class="card-body table-responsive p-0">
<div v-if="!loading && !error">
<transaction-list-large :transactions="account.transactions" v-if="1===accounts.length" :account_id="account.id"/>
<transaction-list-medium :transactions="account.transactions" v-if="2===accounts.length" :account_id="account.id"/>
<transaction-list-small :transactions="account.transactions" v-if="accounts.length > 2" :account_id="account.id"/>
</div>
<div v-if="loading && !error" class="text-center">
<i class="fas fa-spinner fa-spin"></i>
</div>
<div v-if="error" class="text-center">
<i class="fas fa-exclamation-triangle text-danger"></i>
<div class="card-body table-responsive p-0">
<div>
<transaction-list-large :transactions="account.transactions" v-if="1===accounts.length" :account_id="account.id"/>
<transaction-list-medium :transactions="account.transactions" v-if="2===accounts.length" :account_id="account.id"/>
<transaction-list-small :transactions="account.transactions" v-if="accounts.length > 2" :account_id="account.id"/>
</div>
</div>
</div>
</div>
@ -50,6 +74,10 @@
</template>
<script>
import {createNamespacedHelpers} from "vuex";
const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('dashboard/index')
export default {
name: "MainAccountList",
data() {
@ -63,52 +91,72 @@ export default {
},
created() {
this.locale = localStorage.locale ?? 'en-US';
axios.get('./api/v1/preferences/frontpageAccounts')
.then(response => {
this.loadAccounts(response);
}
);
this.ready = true;
},
methods:
{
loadAccounts(response) {
let accountIds = response.data.data.attributes.data;
for (let key in accountIds) {
if (accountIds.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
this.accounts.push({
id: accountIds[key],
title: '',
url: '',
current_balance: '',
currency_code: '',
transactions: []
});
this.loadSingleAccount(key, accountIds[key]);
}
}
},
loadSingleAccount(key, accountId) {
axios.get('./api/v1/accounts/' + accountId)
.then(response => {
this.accounts[key].title = response.data.data.attributes.name;
this.accounts[key].url = './accounts/show/' + response.data.data.id;
this.accounts[key].current_balance = response.data.data.attributes.current_balance;
this.accounts[key].currency_code = response.data.data.attributes.currency_code;
this.loadTransactions(key, accountId);
}
);
},
loadTransactions(key, accountId) {
axios.get('./api/v1/accounts/' + accountId + '/transactions?page=1&limit=10')
.then(response => {
this.accounts[key].transactions = response.data.data;
this.loading = false;
this.error = false;
}
);
},
computed: {
...mapGetters([
'start',
'end'
]),
'datesReady': function () {
return null !== this.start && null !== this.end && this.ready;
}
},
watch: {
datesReady: function (value) {
if (true === value) {
this.initialiseList();
}
}
},
methods: {
initialiseList: function () {
axios.get('./api/v1/preferences/frontpageAccounts')
.then(response => {
this.loadAccounts(response);
}
);
},
loadAccounts(response) {
let accountIds = response.data.data.attributes.data;
for (let key in accountIds) {
if (accountIds.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
this.accounts.push({
id: accountIds[key],
title: '',
url: '',
current_balance: '',
currency_code: 'EUR',
transactions: []
});
this.loadSingleAccount(key, accountIds[key]);
}
}
},
loadSingleAccount(key, accountId) {
axios.get('./api/v1/accounts/' + accountId)
.then(response => {
this.accounts[key].title = response.data.data.attributes.name;
this.accounts[key].url = './accounts/show/' + response.data.data.id;
this.accounts[key].current_balance = response.data.data.attributes.current_balance;
this.accounts[key].currency_code = response.data.data.attributes.currency_code;
this.loadTransactions(key, accountId);
}
);
},
loadTransactions(key, accountId) {
let startStr = this.start.toISOString().split('T')[0];
let endStr = this.end.toISOString().split('T')[0];
axios.get('./api/v1/accounts/' + accountId + '/transactions?page=1&limit=10&start=' + startStr + '&end=' + endStr)
.then(response => {
this.accounts[key].transactions = response.data.data;
this.loading = false;
this.error = false;
}
);
},
}
}
</script>

View File

@ -23,7 +23,20 @@
<div class="card-header">
<h3 class="card-title">{{ $t('firefly.bills') }}</h3>
</div>
<div class="card-body table-responsive p-0">
<!-- body if loading -->
<div class="card-body" v-if="loading && !error">
<div class="text-center">
<i class="fas fa-spinner fa-spin"></i>
</div>
</div>
<!-- body if error -->
<div class="card-body" v-if="error">
<div class="text-center">
<i class="fas fa-exclamation-triangle text-danger"></i>
</div>
</div>
<!-- body if normal -->
<div class="card-body table-responsive p-0" v-if="!loading && !error">
<table class="table table-striped">
<caption style="display:none;">{{ $t('firefly.bills') }}</caption>
<thead>
@ -67,6 +80,15 @@ import {createNamespacedHelpers} from "vuex";
const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('dashboard/index')
export default {
name: "MainBillsList",
data() {
return {
bills: [],
locale: 'en-US',
ready: false,
loading: true,
error: false
}
},
computed: {
...mapGetters([
'start',
@ -79,7 +101,6 @@ export default {
watch: {
datesReady: function (value) {
if (true === value) {
// console.log(this.chartOptions);
this.initialiseBills();
}
}
@ -98,7 +119,10 @@ export default {
.then(response => {
this.loadBills(response.data.data);
}
);
).catch(error => {
this.error = true;
this.loading = false;
});
},
renderPaidDate: function (obj) {
let dateStr = new Intl.DateTimeFormat(this.locale, {year: 'numeric', month: 'long', day: 'numeric'}).format(new Date(obj.date));
@ -116,14 +140,9 @@ export default {
}
}
}
this.error = false;
this.loading = false;
}
},
data() {
return {
bills: [],
locale: 'en-US',
ready: false
}
},
}
}
</script>

View File

@ -1,60 +0,0 @@
<!--
- MainBudgetChart.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>
<div class="card">
<div class="card-header">
<h3 class="card-title">{{ $t('firefly.budgets') }}</h3>
</div>
<div class="card-body">
<div style="position: relative;">
<canvas id="mainBudgetChart" style="min-height: 400px; height: 400px; max-height: 400px; max-width: 100%;"></canvas>
</div>
</div>
<div class="card-footer">
<a href="./budgets" class="btn btn-default button-sm"><i class="far fa-money-bill-alt"></i> {{ $t('firefly.go_to_budgets') }}</a>
</div>
</div>
</template>
<script>
import DefaultBarOptions from "../charts/DefaultBarOptions";
import DataConverter from "../charts/DataConverter";
export default {
name: "MainBudget",
created() {
axios.get('./api/v1/chart/budget/overview?start=' + window.sessionXStart + '&end=' + window.sessionXEnd)
.then(response => {
let chartData = DataConverter.methods.convertChart(response.data);
let stackedBarChartCanvas = $('#mainBudgetChart').get(0).getContext('2d')
new Chart(stackedBarChartCanvas, {
type: 'bar',
data: chartData,
options: DefaultBarOptions.methods.getDefaultOptions()
});
});
},
}
</script>
<style scoped>
</style>

View File

@ -21,7 +21,7 @@
<template>
<div>
<!-- daily budgets (will be the exception, I expect) -->
<div class="row">
<div class="row" v-if="!loading">
<div class="col-xl-6 col-lg-12 col-md-12 col-sm-12 col-xs-12" v-if="budgetLimits.daily.length > 0">
<BudgetListGroup :title="$t('firefly.daily_budgets')" :budgetLimits=budgetLimits.daily
/>
@ -51,13 +51,24 @@
/>
</div>
</div>
<div class="row" v-if="loading && !error">
<div class="col">
<div class="card">
<div class="card-body">
<div class="text-center">
<i class="fas fa-spinner fa-spin"></i>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import BudgetListGroup from "./BudgetListGroup";
import {createNamespacedHelpers} from "vuex";
const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('dashboard/index')
export default {
@ -78,7 +89,9 @@ export default {
budgets: {},
rawBudgets: [],
locale: 'en-US',
ready: false
ready: false,
loading: true,
error: false
}
},
created() {
@ -112,6 +125,7 @@ export default {
axios.get('./api/v1/budgets?start=' + startStr + '&end=' + endStr)
.then(response => {
this.parseBudgets(response.data);
this.loading = false;
}
);
},
@ -197,53 +211,8 @@ export default {
let period = data.data[key].attributes.period ?? 'other';
this.budgetLimits[period].push(obj);
}
}
// // loop budgets (and do what?)
// for (let key in data.included) {
// if (data.included.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
// let obj = {
// name: data.included[key].attributes.name,
// id: data.included[key].id,
// };
// this.budgets[data.included[key].id] = obj;
// }
// }
// loop budget limits:
// for (let key in data.data) {
// if (data.data.hasOwnProperty(key) && /^0$|^[1-9]\d*$/.test(key) && key <= 4294967294) {
// let pctGreen = 0;
// let pctOrange = 0;
// let pctRed = 0;
//
//
// let obj = {
// id: data.data[key].id,
// amount: data.data[key].attributes.amount,
// budget_id: data.data[key].attributes.budget_id,
// currency_id: data.data[key].attributes.currency_id,
// currency_code: data.data[key].attributes.currency_code,
// period: data.data[key].attributes.period,
// start: new Date(data.data[key].attributes.start),
// end: new Date(data.data[key].attributes.end),
// spent: data.data[key].attributes.spent,
// pctGreen: pctGreen,
// pctOrange: pctOrange,
// pctRed: pctRed,
// };
//
//
//
// let period = data.data[key].attributes.period ?? 'other';
// this.budgetLimits[period].push(obj);
// }
// }
},
filterBudgets(budgetId, currencyId) {
for (let key in this.rawBudgets) {

View File

@ -1,60 +0,0 @@
<!--
- MainCategoryChart.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>
<div class="card">
<div class="card-header">
<h3 class="card-title">{{ $t('firefly.categories') }}</h3>
</div>
<div class="card-body">
<div>
<canvas id="mainCategoryChart" style="min-height: 400px; height: 400px; max-height: 400px; max-width: 100%;"></canvas>
</div>
</div>
<div class="card-footer">
<a href="./categories" class="btn btn-default button-sm"><i class="far fa-money-bill-alt"></i> {{ $t('firefly.go_to_categories') }}</a>
</div>
</div>
</template>
<script>
import DefaultBarOptions from "../charts/DefaultBarOptions";
import DataConverter from "../charts/DataConverter";
export default {
name: "MainCategory",
created() {
axios.get('./api/v1/chart/category/overview?start=' + window.sessionStart + '&end=' + window.sessionEnd)
.then(response => {
let chartData = DataConverter.methods.convertChart(response.data);
chartData = DataConverter.methods.colorizeLineData(chartData);
let stackedBarChartCanvas = $('#mainCategoryChart').get(0).getContext('2d')
new Chart(stackedBarChartCanvas, {
type: 'bar',
data: chartData,
options: DefaultBarOptions.methods.getDefaultOptions()
});
});
},
}
</script>
<style scoped>
</style>

View File

@ -23,15 +23,25 @@
<div class="card-header">
<h3 class="card-title">{{ $t('firefly.categories') }}</h3>
</div>
<div class="card-body table-responsive p-0">
<!-- body if loading -->
<div class="card-body" v-if="loading && !error">
<div class="text-center">
<i class="fas fa-spinner fa-spin"></i>
</div>
</div>
<!-- body if error -->
<div class="card-body" v-if="error">
<div class="text-center">
<i class="fas fa-exclamation-triangle text-danger"></i>
</div>
</div>
<!-- body if normal -->
<div class="card-body table-responsive p-0" v-if="!loading && !error">
<table class="table table-sm">
<tbody>
<tr v-for="category in sortedList">
<td style="width:20%;">
<a :href="'./categories/show/' + category.id">{{ category.name }}</a>
<!--<p>Spent: {{ category.spentPct }}</p>
<p>earned: {{ category.earnedPct }}</p>
-->
</td>
<td class="align-middle">
<!-- SPENT -->
@ -53,7 +63,8 @@
<span v-if="category.earnedPct <= 20">
{{ Intl.NumberFormat(locale, {style: 'currency', currency: category.currency_code}).format(category.earned) }}
&nbsp;</span>
<div class="progress-bar progress-bar-striped bg-success" role="progressbar" :aria-valuenow="category.earnedPct" :style="{ width: category.earnedPct + '%'}" aria-valuemin="0"
<div class="progress-bar progress-bar-striped bg-success" role="progressbar" :aria-valuenow="category.earnedPct"
:style="{ width: category.earnedPct + '%'}" aria-valuemin="0"
aria-valuemax="100" title="hello">
<span v-if="category.earnedPct > 20">
{{ Intl.NumberFormat(locale, {style: 'currency', currency: category.currency_code}).format(category.earned) }}
@ -70,12 +81,16 @@
</template>
<script>
import {createNamespacedHelpers} from "vuex";
const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('dashboard/index')
export default {
name: "MainCategoryList",
created() {
this.locale = localStorage.locale ?? 'en-US';
this.getCategories();
this.ready = true;
},
data() {
return {
@ -83,17 +98,40 @@ export default {
categories: [],
sortedList: [],
spent: 0,
earned: 0
earned: 0,
loading: true,
error: false
}
},
computed: {
...mapGetters([
'start',
'end'
]),
'datesReady': function () {
return null !== this.start && null !== this.end && this.ready;
}
},
watch: {
datesReady: function (value) {
if (true === value) {
this.getCategories();
}
}
},
methods:
{
getCategories() {
axios.get('./api/v1/categories?start=' + window.sessionStart + '&end=' + window.sessionEnd)
let startStr = this.start.toISOString().split('T')[0];
let endStr = this.end.toISOString().split('T')[0];
axios.get('./api/v1/categories?start=' + startStr + '&end=' + endStr)
.then(response => {
this.parseCategories(response.data);
this.loading = false;
}
);
).catch(error => {
this.error = true;
});
},
parseCategories(data) {
for (let key in data.data) {

View File

@ -1,56 +0,0 @@
<!--
- MainCrebitChart.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>
<div class="card">
<div class="card-header">
<!-- debit = expense -->
<h3 class="card-title">{{ $t('firefly.income') }}</h3>
</div>
<div class="card-body table-responsive p-0">
<transaction-list-small :transactions="this.transactions" />
</div>
<div class="card-footer">
<a href="./accounts/revenue" class="btn btn-default button-sm"><i class="far fa-money-bill-alt"></i> {{ $t('firefly.go_to_deposits') }}</a>
</div>
</div>
</template>
<script>
export default {
name: "MainCredit",
components: {},
data() {
return {
transactions: []
}
},
created() {
axios.get('./api/v1/transactions?type=deposit&limit=10&start=' + window.sessionStart + '&end=' + window.sessionEnd)
.then(response => {
this.transactions = response.data.data;
}
);
},
methods: {
},
computed: {},
}
</script>

View File

@ -23,7 +23,20 @@
<div class="card-header">
<h3 class="card-title">{{ $t('firefly.revenue_accounts') }}</h3>
</div>
<div class="card-body table-responsive p-0">
<!-- body if loading -->
<div class="card-body" v-if="loading && !error">
<div class="text-center">
<i class="fas fa-spinner fa-spin"></i>
</div>
</div>
<!-- body if error -->
<div class="card-body" v-if="error">
<div class="text-center">
<i class="fas fa-exclamation-triangle text-danger"></i>
</div>
</div>
<!-- body if normal -->
<div class="card-body table-responsive p-0" v-if="!loading && !error">
<table class="table table-sm">
<tbody>
<tr v-for="entry in income">
@ -53,28 +66,57 @@
</template>
<script>
import {createNamespacedHelpers} from "vuex";
const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('dashboard/index')
export default {
name: "MainCreditList",
data() {
return {
locale: 'en-US',
income: [],
max: 0
max: 0,
loading: true,
error: false
}
},
created() {
this.locale = localStorage.locale ?? 'en-US';
this.getExpenses();
this.ready = true;
},
computed: {
...mapGetters([
'start',
'end'
]),
'datesReady': function () {
return null !== this.start && null !== this.end && this.ready;
}
},
watch: {
datesReady: function (value) {
if (true === value) {
this.getIncome();
}
}
},
methods: {
getExpenses() {
axios.get('./api/v1/insight/income/date/basic?start=' + window.sessionStart + '&end=' + window.sessionEnd)
getIncome() {
let startStr = this.start.toISOString().split('T')[0];
let endStr = this.end.toISOString().split('T')[0];
axios.get('./api/v1/insight/income/date/basic?start=' + startStr + '&end=' + endStr)
.then(response => {
// do something with response.
this.parseExpenses(response.data);
});
this.parseIncome(response.data);
this.loading = false;
}).catch(error => {
this.error = true
});
},
parseExpenses(data) {
parseIncome(data) {
for (let mainKey in data) {
if (data.hasOwnProperty(mainKey) && /^0$|^[1-9]\d*$/.test(mainKey) && mainKey <= 4294967294) {
// contains currency info and entries.
@ -83,12 +125,11 @@ export default {
this.max = data[mainKey].difference_float;
current.pct = 100;
}
if(0 !== parseInt(mainKey)) {
if (0 !== parseInt(mainKey)) {
// calc percentage:
current.pct = (data[mainKey].difference_float / this.max) * 100;
}
this.income.push(current);
}
}
}

View File

@ -1,62 +0,0 @@
<!--
- MainDebit.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>
<div class="card">
<div class="card-header">
<!-- debit = expense -->
<h3 class="card-title">{{ $t('firefly.expense_accounts') }}</h3>
</div>
<div class="card-body">
<div>
<canvas id="mainDebitChart" style="min-height: 400px; height: 400px; max-height: 400px; max-width: 100%;"></canvas>
</div>
</div>
<div class="card-footer">
<a href="./transactions/withdrawals" class="btn btn-default button-sm"><i class="far fa-money-bill-alt"></i> {{ $t('firefly.go_to_expenses') }}</a>
</div>
</div>
</template>
<script>
import DefaultBarOptions from "../charts/DefaultBarOptions";
import DataConverter from "../charts/DataConverter";
export default {
name: "MainDebit",
created() {
axios.get('./api/v1/chart/account/expense?start=' + window.sessionStart + '&end=' + window.sessionEnd)
.then(response => {
let chartData = DataConverter.methods.convertChart(response.data);
chartData = DataConverter.methods.colorizeLineData(chartData);
let stackedBarChartCanvas = $('#mainDebitChart').get(0).getContext('2d')
new Chart(stackedBarChartCanvas, {
type: 'bar',
data: chartData,
options: DefaultBarOptions.methods.getDefaultOptions()
});
});
},
}
</script>
<style scoped>
</style>

View File

@ -23,7 +23,20 @@
<div class="card-header">
<h3 class="card-title">{{ $t('firefly.expense_accounts') }}</h3>
</div>
<div class="card-body table-responsive p-0">
<!-- body if loading -->
<div class="card-body" v-if="loading && !error">
<div class="text-center">
<i class="fas fa-spinner fa-spin"></i>
</div>
</div>
<!-- body if error -->
<div class="card-body" v-if="error">
<div class="text-center">
<i class="fas fa-exclamation-triangle text-danger"></i>
</div>
</div>
<!-- body if normal -->
<div class="card-body table-responsive p-0" v-if="!loading && !error">
<table class="table table-sm">
<tbody>
<tr v-for="entry in expenses">
@ -53,26 +66,55 @@
</template>
<script>
import {createNamespacedHelpers} from "vuex";
const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('dashboard/index')
export default {
name: "MainDebitList",
data() {
return {
locale: 'en-US',
expenses: [],
max: 0
max: 0,
loading: true,
error: false
}
},
created() {
this.locale = localStorage.locale ?? 'en-US';
this.getExpenses();
this.ready = true;
},
computed: {
...mapGetters([
'start',
'end'
]),
'datesReady': function () {
return null !== this.start && null !== this.end && this.ready;
}
},
watch: {
datesReady: function (value) {
if (true === value) {
this.getExpenses();
}
}
},
methods: {
getExpenses() {
axios.get('./api/v1/insight/expense/date/basic?start=' + window.sessionStart + '&end=' + window.sessionEnd)
let startStr = this.start.toISOString().split('T')[0];
let endStr = this.end.toISOString().split('T')[0];
axios.get('./api/v1/insight/expense/date/basic?start=' + startStr + '&end=' + endStr)
.then(response => {
// do something with response.
this.parseExpenses(response.data);
});
this.loading = false
}).catch(error => {
this.error = true
});
},
parseExpenses(data) {
for (let mainKey in data) {
@ -83,7 +125,7 @@ export default {
this.max = data[mainKey].difference_float;
current.pct = 100;
}
if(0 !== parseInt(mainKey)) {
if (0 !== parseInt(mainKey)) {
// calc percentage:
current.pct = (data[mainKey].difference_float / this.max) * 100;
}

View File

@ -23,7 +23,21 @@
<div class="card-header">
<h3 class="card-title">{{ $t('firefly.piggy_banks') }}</h3>
</div>
<div class="card-body table-responsive p-0">
<!-- body if loading -->
<div class="card-body" v-if="loading && !error">
<div class="text-center">
<i class="fas fa-spinner fa-spin"></i>
</div>
</div>
<!-- body if error -->
<div class="card-body" v-if="error">
<div class="text-center">
<i class="fas fa-exclamation-triangle text-danger"></i>
</div>
</div>
<!-- body if normal -->
<div class="card-body table-responsive p-0" v-if="!loading && !error">
<table class="table table-striped">
<caption style="display:none;">{{ $t('firefly.piggy_banks') }}</caption>
<thead>
@ -45,7 +59,8 @@
<div class="progress-group">
<div class="progress progress-sm">
<div class="progress-bar progress-bar-striped primary" v-if="piggy.attributes.pct < 100" :style="{'width': piggy.attributes.pct + '%'}"></div>
<div class="progress-bar progress-bar-striped bg-success" v-if="100 === piggy.attributes.pct" :style="{'width': piggy.attributes.pct + '%'}"></div>
<div class="progress-bar progress-bar-striped bg-success" v-if="100 === piggy.attributes.pct"
:style="{'width': piggy.attributes.pct + '%'}"></div>
</div>
</div>
<span class="text-success">
@ -74,17 +89,24 @@
<script>
export default {
name: "MainPiggyList",
data() {
return {
piggy_banks: [],
loading: true,
error: false,
locale: 'en-US'
}
},
created() {
this.locale = localStorage.locale ?? 'en-US';
axios.get('./api/v1/piggy_banks')
.then(response => {
this.loadPiggyBanks(response.data.data);
this.loading = false;
}
);
},
computed: {
locale() {
return this.$store.getters.locale;
}
).catch(error => {
this.error = true
});
},
methods: {
loadPiggyBanks(data) {
@ -101,11 +123,6 @@ export default {
return b.attributes.pct - a.attributes.pct;
});
}
},
data() {
return {
piggy_banks: []
}
}
}
</script>

View File

@ -25,7 +25,9 @@
<span class="info-box-icon"><i class="far fa-bookmark text-info"></i></span>
<div class="info-box-content">
<span class="info-box-text">{{ $t("firefly.balance") }}</span>
<span class="info-box-text" v-if="!loading && !error">{{ $t("firefly.balance") }}</span>
<span class="info-box-text" v-if="loading && !error"><i class="fas fa-spinner fa-spin"></i></span>
<span class="info-box-text" v-if="error"><i class="fas fa-exclamation-triangle text-danger"></i></span>
<!-- balance in preferred currency -->
<span class="info-box-number" v-for="balance in prefCurrencyBalances" :title="balance.sub_title">{{ balance.value_parsed }}</span>
@ -48,8 +50,9 @@
<span class="info-box-icon"><i class="far fa-calendar-alt text-teal"></i></span>
<div class="info-box-content">
<span class="info-box-text">{{ $t('firefly.bills_to_pay') }}</span>
<span class="info-box-text" v-if="!loading && !error">{{ $t('firefly.bills_to_pay') }}</span>
<span class="info-box-text" v-if="loading && !error"><i class="fas fa-spinner fa-spin"></i></span>
<span class="info-box-text" v-if="error"><i class="fas fa-exclamation-triangle text-danger"></i></span>
<!-- bills unpaid, in preferred currency. -->
<span class="info-box-number" v-for="balance in prefBillsUnpaid">{{ balance.value_parsed }}</span>
@ -72,8 +75,9 @@
<span class="info-box-icon"><i class="fas fa-money-bill text-success"></i></span>
<div class="info-box-content">
<span class="info-box-text">{{ $t('firefly.left_to_spend') }}</span>
<span class="info-box-text" v-if="!loading && !error">{{ $t('firefly.left_to_spend') }}</span>
<span class="info-box-text" v-if="loading && !error"><i class="fas fa-spinner fa-spin"></i></span>
<span class="info-box-text" v-if="error"><i class="fas fa-exclamation-triangle text-danger"></i></span>
<!-- left to spend in preferred currency -->
<span class="info-box-number" v-for="left in prefLeftToSpend" :title="left.sub_title">{{ left.value_parsed }}</span>
@ -97,7 +101,9 @@
<span class="info-box-icon"><i class="fas fa-money-bill text-success"></i></span>
<div class="info-box-content">
<span class="info-box-text"><span>{{ $t('firefly.net_worth') }}</span></span>
<span class="info-box-text" v-if="!loading && !error">{{ $t('firefly.net_worth') }}</span>
<span class="info-box-text" v-if="loading && !error"><i class="fas fa-spinner fa-spin"></i></span>
<span class="info-box-text" v-if="error"><i class="fas fa-exclamation-triangle text-danger"></i></span>
<span class="info-box-number" v-for="nw in prefNetWorth" :title="nw.sub_title">{{ nw.value_parsed }}</span>
<div class="progress bg-success">
@ -117,6 +123,9 @@
</template>
<script>
import {createNamespacedHelpers} from "vuex";
const {mapState, mapGetters, mapActions, mapMutations} = createNamespacedHelpers('dashboard/index')
export default {
name: "TopBoxes",
props: {},
@ -128,9 +137,19 @@ export default {
billsUnpaid: [],
leftToSpend: [],
netWorth: [],
loading: true,
error: false,
ready: false
}
},
computed: {
...mapGetters([
'start',
'end'
]),
'datesReady': function () {
return null !== this.start && null !== this.end && this.ready;
},
// contains only balances with preferred currency.
prefCurrencyBalances: function () {
@ -170,8 +189,15 @@ export default {
return this.$store.getters.currencyId;
}
},
watch: {
datesReady: function (value) {
if (true === value) {
this.prepareComponent();
}
}
},
created() {
this.prepareComponent();
this.ready = true;
},
methods: {
filterOnCurrency(array) {
@ -205,11 +231,16 @@ export default {
* Prepare the component.
*/
prepareComponent() {
axios.get('./api/v1/summary/basic?start=' + window.sessionStart + '&end=' + window.sessionEnd)
let startStr = this.start.toISOString().split('T')[0];
let endStr = this.end.toISOString().split('T')[0];
axios.get('./api/v1/summary/basic?start=' + startStr + '&end=' + endStr)
.then(response => {
this.summary = response.data;
this.buildComponent();
});
this.loading = false
}).catch(error => {
this.error = true
});
},
buildComponent() {
this.getBalanceEntries();

View File

@ -76,6 +76,9 @@
"first_split_overrules_source": "The first split may overrule the source account",
"first_split_overrules_destination": "The first split may overrule the destination account",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">\u0422\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f #{ID}(\"{title}\")<\/a> \u0431\u0435\u0448\u0435 \u0437\u0430\u043f\u0438\u0441\u0430\u043d\u0430.",
"custom_period": "Custom period",
"reset_to_current": "Reset to current period",
"select_period": "Select a period",
"other_budgets": "\u0412\u0440\u0435\u043c\u0435\u0432\u043e \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0430\u043d\u0438 \u0431\u044e\u0434\u0436\u0435\u0442\u0438",
"journal_links": "\u0412\u0440\u044a\u0437\u043a\u0438 \u043d\u0430 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f",
"go_to_withdrawals": "\u0412\u0438\u0436\u0442\u0435 \u0442\u0435\u0433\u043b\u0435\u043d\u0438\u044f\u0442\u0430 \u0441\u0438",

View File

@ -76,6 +76,9 @@
"first_split_overrules_source": "The first split may overrule the source account",
"first_split_overrules_destination": "The first split may overrule the destination account",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Transaction #{ID} (\"{title}\")<\/a> has been stored.",
"custom_period": "Custom period",
"reset_to_current": "Reset to current period",
"select_period": "Select a period",
"other_budgets": "Custom timed budgets",
"journal_links": "Transaction links",
"go_to_withdrawals": "Go to your withdrawals",

View File

@ -76,6 +76,9 @@
"first_split_overrules_source": "The first split may overrule the source account",
"first_split_overrules_destination": "The first split may overrule the destination account",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Buchung #{ID} (\"{title}\")<\/a> wurde gespeichert.",
"custom_period": "Custom period",
"reset_to_current": "Reset to current period",
"select_period": "Select a period",
"other_budgets": "Zeitlich befristete Budgets",
"journal_links": "Buchungsverkn\u00fcpfungen",
"go_to_withdrawals": "Ausgaben anzeigen",

View File

@ -76,6 +76,9 @@
"first_split_overrules_source": "The first split may overrule the source account",
"first_split_overrules_destination": "The first split may overrule the destination account",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">\u0397 \u03c3\u03c5\u03bd\u03b1\u03bb\u03bb\u03b1\u03b3\u03ae #{ID} (\"{title}\")<\/a> \u03ad\u03c7\u03b5\u03b9 \u03b1\u03c0\u03bf\u03b8\u03b7\u03ba\u03b5\u03c5\u03c4\u03b5\u03af.",
"custom_period": "Custom period",
"reset_to_current": "Reset to current period",
"select_period": "Select a period",
"other_budgets": "\u03a0\u03c1\u03bf\u03cb\u03c0\u03bf\u03bb\u03bf\u03b3\u03b9\u03c3\u03bc\u03bf\u03af \u03bc\u03b5 \u03c7\u03c1\u03bf\u03bd\u03b9\u03ba\u03ae \u03c0\u03c1\u03bf\u03c3\u03b1\u03c1\u03bc\u03bf\u03b3\u03ae",
"journal_links": "\u03a3\u03c5\u03bd\u03b4\u03ad\u03c3\u03b5\u03b9\u03c2 \u03c3\u03c5\u03bd\u03b1\u03bb\u03bb\u03b1\u03b3\u03ce\u03bd",
"go_to_withdrawals": "\u03a0\u03b7\u03b3\u03b1\u03af\u03bd\u03b5\u03c4\u03b5 \u03c3\u03c4\u03b9\u03c2 \u03b1\u03bd\u03b1\u03bb\u03ae\u03c8\u03b5\u03b9\u03c2 \u03c3\u03b1\u03c2",

View File

@ -76,6 +76,9 @@
"first_split_overrules_source": "The first split may overrule the source account",
"first_split_overrules_destination": "The first split may overrule the destination account",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Transaction #{ID} (\"{title}\")<\/a> has been stored.",
"custom_period": "Custom period",
"reset_to_current": "Reset to current period",
"select_period": "Select a period",
"other_budgets": "Custom timed budgets",
"journal_links": "Transaction links",
"go_to_withdrawals": "Go to your withdrawals",

View File

@ -76,6 +76,9 @@
"first_split_overrules_source": "The first split may overrule the source account",
"first_split_overrules_destination": "The first split may overrule the destination account",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Transaction #{ID} (\"{title}\")<\/a> has been stored.",
"custom_period": "Custom period",
"reset_to_current": "Reset to current period",
"select_period": "Select a period",
"other_budgets": "Custom timed budgets",
"journal_links": "Transaction links",
"go_to_withdrawals": "Go to your withdrawals",

View File

@ -76,6 +76,9 @@
"first_split_overrules_source": "The first split may overrule the source account",
"first_split_overrules_destination": "The first split may overrule the destination account",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">La transacci\u00f3n #{ID} (\"{title}\")<\/a> ha sido almacenada.",
"custom_period": "Custom period",
"reset_to_current": "Reset to current period",
"select_period": "Select a period",
"other_budgets": "Presupuestos de tiempo personalizado",
"journal_links": "Enlaces de transacciones",
"go_to_withdrawals": "Ir a tus retiradas",

View File

@ -76,6 +76,9 @@
"first_split_overrules_source": "The first split may overrule the source account",
"first_split_overrules_destination": "The first split may overrule the destination account",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Transaction #{ID} (\"{title}\")<\/a> has been stored.",
"custom_period": "Custom period",
"reset_to_current": "Reset to current period",
"select_period": "Select a period",
"other_budgets": "Custom timed budgets",
"journal_links": "Tapahtuman linkit",
"go_to_withdrawals": "Go to your withdrawals",

View File

@ -76,6 +76,9 @@
"first_split_overrules_source": "The first split may overrule the source account",
"first_split_overrules_destination": "The first split may overrule the destination account",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">L'op\u00e9ration n\u00b0{ID} (\"{title}\")<\/a> a \u00e9t\u00e9 enregistr\u00e9e.",
"custom_period": "Custom period",
"reset_to_current": "Reset to current period",
"select_period": "Select a period",
"other_budgets": "Budgets \u00e0 p\u00e9riode personnalis\u00e9e",
"journal_links": "Liens d'op\u00e9ration",
"go_to_withdrawals": "Acc\u00e9der \u00e0 vos retraits",

View File

@ -76,6 +76,9 @@
"first_split_overrules_source": "The first split may overrule the source account",
"first_split_overrules_destination": "The first split may overrule the destination account",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Transaction #{ID} (\"{title}\")<\/a> mentve.",
"custom_period": "Custom period",
"reset_to_current": "Reset to current period",
"select_period": "Select a period",
"other_budgets": "Custom timed budgets",
"journal_links": "Tranzakci\u00f3 \u00f6sszekapcsol\u00e1sok",
"go_to_withdrawals": "Ugr\u00e1s a k\u00f6lts\u00e9gekhez",

View File

@ -76,6 +76,9 @@
"first_split_overrules_source": "The first split may overrule the source account",
"first_split_overrules_destination": "The first split may overrule the destination account",
"transaction_stored_link": "La <a href=\"transactions\/show\/{ID}\">transazione #{ID} (\"{title}\")<\/a> \u00e8 stata salvata.",
"custom_period": "Custom period",
"reset_to_current": "Reset to current period",
"select_period": "Select a period",
"other_budgets": "Budget a periodi personalizzati",
"journal_links": "Collegamenti della transazione",
"go_to_withdrawals": "Vai ai tuoi prelievi",

View File

@ -76,6 +76,9 @@
"first_split_overrules_source": "The first split may overrule the source account",
"first_split_overrules_destination": "The first split may overrule the destination account",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Transaction #{ID} (\"{title}\")<\/a> has been stored.",
"custom_period": "Custom period",
"reset_to_current": "Reset to current period",
"select_period": "Select a period",
"other_budgets": "Custom timed budgets",
"journal_links": "Transaksjonskoblinger",
"go_to_withdrawals": "Go to your withdrawals",

View File

@ -76,6 +76,9 @@
"first_split_overrules_source": "The first split may overrule the source account",
"first_split_overrules_destination": "The first split may overrule the destination account",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Transactie #{ID} (\"{title}\")<\/a> is opgeslagen.",
"custom_period": "Custom period",
"reset_to_current": "Reset to current period",
"select_period": "Select a period",
"other_budgets": "Aangepaste budgetten",
"journal_links": "Transactiekoppelingen",
"go_to_withdrawals": "Ga naar je uitgaven",

View File

@ -76,6 +76,9 @@
"first_split_overrules_source": "The first split may overrule the source account",
"first_split_overrules_destination": "The first split may overrule the destination account",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Transakcja #{ID} (\"{title}\")<\/a> zosta\u0142a zapisana.",
"custom_period": "Custom period",
"reset_to_current": "Reset to current period",
"select_period": "Select a period",
"other_budgets": "Bud\u017cety niestandardowe",
"journal_links": "Powi\u0105zane transakcje",
"go_to_withdrawals": "Przejd\u017a do swoich wydatk\u00f3w",

View File

@ -76,6 +76,9 @@
"first_split_overrules_source": "The first split may overrule the source account",
"first_split_overrules_destination": "The first split may overrule the destination account",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Transa\u00e7\u00e3o #{ID} (\"{title}\")<\/a> foi salva.",
"custom_period": "Custom period",
"reset_to_current": "Reset to current period",
"select_period": "Select a period",
"other_budgets": "Custom timed budgets",
"journal_links": "Transa\u00e7\u00f5es ligadas",
"go_to_withdrawals": "V\u00e1 para seus saques",

View File

@ -76,6 +76,9 @@
"first_split_overrules_source": "The first split may overrule the source account",
"first_split_overrules_destination": "The first split may overrule the destination account",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Transa\u00e7\u00e3o #{ID} (\"{title}\")<\/a> foi guardada.",
"custom_period": "Custom period",
"reset_to_current": "Reset to current period",
"select_period": "Select a period",
"other_budgets": "Or\u00e7amentos de tempo personalizado",
"journal_links": "Liga\u00e7\u00f5es de transac\u00e7\u00e3o",
"go_to_withdrawals": "Ir para os seus levantamentos",

View File

@ -76,6 +76,9 @@
"first_split_overrules_source": "The first split may overrule the source account",
"first_split_overrules_destination": "The first split may overrule the destination account",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Tranzac\u021bia #{ID} (\"{title}\")<\/a> a fost stocat\u0103.",
"custom_period": "Custom period",
"reset_to_current": "Reset to current period",
"select_period": "Select a period",
"other_budgets": "Custom timed budgets",
"journal_links": "Link-uri de tranzac\u021bii",
"go_to_withdrawals": "Go to your withdrawals",

View File

@ -76,6 +76,9 @@
"first_split_overrules_source": "The first split may overrule the source account",
"first_split_overrules_destination": "The first split may overrule the destination account",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">\u0422\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u044f #{ID} (\"{title}\")<\/a> \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0430.",
"custom_period": "Custom period",
"reset_to_current": "Reset to current period",
"select_period": "Select a period",
"other_budgets": "\u0411\u044e\u0434\u0436\u0435\u0442\u044b \u043d\u0430 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u044b\u0439 \u043e\u0442\u0440\u0435\u0437\u043e\u043a \u0432\u0440\u0435\u043c\u0435\u043d\u0438",
"journal_links": "\u0421\u0432\u044f\u0437\u0438 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438",
"go_to_withdrawals": "\u041f\u0435\u0440\u0435\u0439\u0442\u0438 \u043a \u0432\u0430\u0448\u0438\u043c \u0440\u0430\u0441\u0445\u043e\u0434\u0430\u043c",

View File

@ -76,6 +76,9 @@
"first_split_overrules_source": "The first split may overrule the source account",
"first_split_overrules_destination": "The first split may overrule the destination account",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Transakcia #{ID} (\"{title}\")<\/a> bola ulo\u017een\u00e1.",
"custom_period": "Custom period",
"reset_to_current": "Reset to current period",
"select_period": "Select a period",
"other_budgets": "\u0160pecifick\u00e9 \u010dasovan\u00e9 rozpo\u010dty",
"journal_links": "Prepojenia transakcie",
"go_to_withdrawals": "Zobrazi\u0165 v\u00fdbery",

View File

@ -76,6 +76,9 @@
"first_split_overrules_source": "The first split may overrule the source account",
"first_split_overrules_destination": "The first split may overrule the destination account",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Transaktion #{ID} (\"{title}\")<\/a> sparades.",
"custom_period": "Custom period",
"reset_to_current": "Reset to current period",
"select_period": "Select a period",
"other_budgets": "Anpassade tidsinst\u00e4llda budgetar",
"journal_links": "Transaktionsl\u00e4nkar",
"go_to_withdrawals": "G\u00e5 till dina uttag",

View File

@ -76,6 +76,9 @@
"first_split_overrules_source": "The first split may overrule the source account",
"first_split_overrules_destination": "The first split may overrule the destination account",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Giao d\u1ecbch #{ID} (\"{title}\")<\/a> \u0111\u00e3 \u0111\u01b0\u1ee3c l\u01b0u tr\u1eef.",
"custom_period": "Custom period",
"reset_to_current": "Reset to current period",
"select_period": "Select a period",
"other_budgets": "Custom timed budgets",
"journal_links": "Li\u00ean k\u1ebft giao d\u1ecbch",
"go_to_withdrawals": "Go to your withdrawals",

View File

@ -76,6 +76,9 @@
"first_split_overrules_source": "The first split may overrule the source account",
"first_split_overrules_destination": "The first split may overrule the destination account",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Transaction #{ID} (\"{title}\")<\/a> has been stored.",
"custom_period": "Custom period",
"reset_to_current": "Reset to current period",
"select_period": "Select a period",
"other_budgets": "Custom timed budgets",
"journal_links": "\u4ea4\u6613\u8fde\u7ed3",
"go_to_withdrawals": "Go to your withdrawals",

View File

@ -76,6 +76,9 @@
"first_split_overrules_source": "The first split may overrule the source account",
"first_split_overrules_destination": "The first split may overrule the destination account",
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">Transaction #{ID} (\"{title}\")<\/a> has been stored.",
"custom_period": "Custom period",
"reset_to_current": "Reset to current period",
"select_period": "Select a period",
"other_budgets": "Custom timed budgets",
"journal_links": "\u4ea4\u6613\u9023\u7d50",
"go_to_withdrawals": "Go to your withdrawals",