diff --git a/resources/assets/v2/api/v2/model/piggy-bank/get.js b/resources/assets/v2/api/v2/model/piggy-bank/get.js
new file mode 100644
index 0000000000..9ecf33fff6
--- /dev/null
+++ b/resources/assets/v2/api/v2/model/piggy-bank/get.js
@@ -0,0 +1,35 @@
+/*
+ * get.js
+ * Copyright (c) 2023 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 .
+ */
+
+
+import {api} from "../../../../boot/axios";
+
+export default class Get {
+
+ /**
+ *
+ * @param params
+ * @returns {Promise>}
+ */
+ get(params) {
+ return api.get('/api/v2/piggy-banks', {params: params});
+ }
+
+}
diff --git a/resources/assets/v2/dashboard.js b/resources/assets/v2/dashboard.js
index 28c041f87e..e972b8decb 100644
--- a/resources/assets/v2/dashboard.js
+++ b/resources/assets/v2/dashboard.js
@@ -26,8 +26,9 @@ import budgets from './pages/dashboard/budgets.js';
import categories from './pages/dashboard/categories.js';
import sankey from './pages/dashboard/sankey.js';
import subscriptions from './pages/dashboard/subscriptions.js';
+import piggies from './pages/dashboard/piggies.js';
-const comps = {dates, boxes, accounts, budgets, categories, sankey, subscriptions};
+const comps = {dates, boxes, accounts, budgets, categories, sankey, subscriptions, piggies};
function loadPage(comps) {
Object.keys(comps).forEach(comp => {
diff --git a/resources/assets/v2/pages/dashboard/piggies.js b/resources/assets/v2/pages/dashboard/piggies.js
new file mode 100644
index 0000000000..333ab279d9
--- /dev/null
+++ b/resources/assets/v2/pages/dashboard/piggies.js
@@ -0,0 +1,126 @@
+/*
+ * budgets.js
+ * Copyright (c) 2023 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 .
+ */
+import {getVariable} from "../../store/get-variable.js";
+import Get from "../../api/v2/model/piggy-bank/get.js";
+
+let currencies = [];
+
+let apiData = {};
+
+export default () => ({
+ loading: false,
+ autoConversion: false,
+ sankeyGrouping: 'account',
+ piggies: [],
+ getFreshData() {
+ let params = {
+ start: window.store.get('start').slice(0, 10),
+ end: window.store.get('end').slice(0, 10),
+ page: 1
+ };
+ this.downloadPiggyBanks(params);
+ },
+ downloadPiggyBanks(params) {
+ console.log('Downloading page ' + params.page + '...');
+ const getter = new Get();
+ getter.get(params).then((response) => {
+ apiData = [...apiData, ...response.data.data];
+ if (parseInt(response.data.meta.pagination.total_pages) > params.page) {
+ params.page++;
+ this.downloadPiggyBanks(params);
+ return;
+ }
+ this.parsePiggies();
+ this.loading = false;
+ });
+ },
+ parsePiggies() {
+ let dataSet = [];
+ for (let i in apiData) {
+ if (apiData.hasOwnProperty(i)) {
+ let current = apiData[i];
+ if (current.attributes.percentage >= 100) {
+ continue;
+ }
+ if (0 === current.attributes.percentage) {
+ continue;
+ }
+ let groupName = current.object_group_title ?? '(TODO ungrouped)';
+ if (!dataSet.hasOwnProperty(groupName)) {
+ dataSet[groupName] = {
+ id: current.object_group_id ?? 0,
+ title: groupName,
+ order: current.object_group_order ?? 0,
+ piggies: [],
+ };
+ }
+ let piggy = {
+ id: current.id,
+ name: current.attributes.name,
+ percentage: parseInt(current.attributes.percentage),
+ amount: this.autoConversion ? current.attributes.native_current_amount : current.attributes.current_amount,
+ // left to save
+ left_to_save: this.autoConversion ? current.attributes.native_left_to_save : current.attributes.left_to_save,
+ // target amount
+ target_amount: this.autoConversion ? current.attributes.native_target_amount : current.attributes.target_amount,
+ // save per month
+ save_per_month: this.autoConversion ? current.attributes.native_save_per_month : current.attributes.save_per_month,
+ currency_code: this.autoConversion ? current.attributes.native_code : current.attributes.currency_code,
+
+ };
+ dataSet[groupName].piggies.push(piggy);
+ }
+ }
+ this.piggies = Object.values(dataSet);
+ console.log(this.piggies);
+ },
+
+ loadPiggyBanks() {
+ if (true === this.loading) {
+ return;
+ }
+ this.loading = true;
+
+ if (0 !== this.piggies.length) {
+ this.parsePiggies();
+ this.loading = false;
+ return;
+ }
+ this.getFreshData();
+ },
+ init() {
+ apiData = [];
+ Promise.all([getVariable('autoConversion', false)]).then((values) => {
+ this.autoConversion = values[0];
+ this.loadPiggyBanks();
+ });
+ window.store.observe('end', () => {
+ apiData = [];
+ this.loadPiggyBanks();
+ });
+ window.store.observe('autoConversion', (newValue) => {
+ this.autoConversion = newValue;
+ this.loadPiggyBanks();
+ });
+ },
+
+});
+
+