From e58da3c41d8709136f8fff2a9705ed809528448b Mon Sep 17 00:00:00 2001 From: James Cole Date: Sat, 15 Jul 2023 15:25:04 +0200 Subject: [PATCH] More work on v4 --- package-lock.json | 13 ++- package.json | 3 +- resources/assets/v4/api/preferences/index.js | 4 +- resources/assets/v4/api/summary/index.js | 28 +++++++ resources/assets/v4/app.js | 55 +++++++++---- resources/assets/v4/bootstrap.js | 4 - resources/assets/v4/index.js | 79 ++++++++++++++++-- resources/assets/v4/store/Basic.js | 78 +++++++++++------- resources/views/index.blade.php | 15 +--- resources/views/layout/v4/default.blade.php | 6 +- .../views/partials/dashboard/boxes.blade.php | 81 +++++++++++++++++++ .../views/partials/layout/v4/head.blade.php | 2 - 12 files changed, 290 insertions(+), 78 deletions(-) create mode 100644 resources/assets/v4/api/summary/index.js create mode 100644 resources/views/partials/dashboard/boxes.blade.php diff --git a/package-lock.json b/package-lock.json index 2a0b519301..3a1e03d2d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,8 @@ "@popperjs/core": "^2.11.8", "alpinejs": "^3.12.3", "bootstrap": "^5.3.0", - "date-fns": "^2.30.0" + "date-fns": "^2.30.0", + "store2": "^2.14.2" }, "devDependencies": { "axios": "^1.1.2", @@ -884,6 +885,11 @@ "node": ">=0.10.0" } }, + "node_modules/store2": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/store2/-/store2-2.14.2.tgz", + "integrity": "sha512-siT1RiqlfQnGqgT/YzXVUNsom9S0H1OX+dpdGN1xkyYATo4I6sep5NmsRD/40s3IIOvlCq6akxkqG82urIZW1w==" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -1460,6 +1466,11 @@ "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "dev": true }, + "store2": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/store2/-/store2-2.14.2.tgz", + "integrity": "sha512-siT1RiqlfQnGqgT/YzXVUNsom9S0H1OX+dpdGN1xkyYATo4I6sep5NmsRD/40s3IIOvlCq6akxkqG82urIZW1w==" + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", diff --git a/package.json b/package.json index 46de4dca9c..bbaafc7517 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@popperjs/core": "^2.11.8", "alpinejs": "^3.12.3", "bootstrap": "^5.3.0", - "date-fns": "^2.30.0" + "date-fns": "^2.30.0", + "store2": "^2.14.2" } } diff --git a/resources/assets/v4/api/preferences/index.js b/resources/assets/v4/api/preferences/index.js index 21dff68292..f02087b82f 100644 --- a/resources/assets/v4/api/preferences/index.js +++ b/resources/assets/v4/api/preferences/index.js @@ -21,8 +21,8 @@ import {api} from "../../boot/axios"; export default class Preferences { - async getByName(name) { - return await api.get('/api/v1/preferences/' + name); + getByName(name) { + return api.get('/api/v1/preferences/' + name); } postByName(name, value) { diff --git a/resources/assets/v4/api/summary/index.js b/resources/assets/v4/api/summary/index.js new file mode 100644 index 0000000000..0744ce9070 --- /dev/null +++ b/resources/assets/v4/api/summary/index.js @@ -0,0 +1,28 @@ +/* + * index.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.js"; + +export default class Summary { + get(start, end, code) { + return api.get('/api/v1/summary/basic', {params: {start: start, end: end, code: code}}); + } +} diff --git a/resources/assets/v4/app.js b/resources/assets/v4/app.js index 7dbb940f35..446f0fe87e 100644 --- a/resources/assets/v4/app.js +++ b/resources/assets/v4/app.js @@ -27,37 +27,48 @@ class MainApp { language = 'en-US'; constructor() { - let start = window.BasicStore.getFromLocalStorage('start'); - let end = window.BasicStore.getFromLocalStorage('end'); + console.log('MainApp constructor'); + let start = window.BasicStore.get('start'); + let end = window.BasicStore.get('end'); if (null !== start && null !== end) { + console.log('start + end is not null, recycle it.'); this.range = { start: new Date(start), end: new Date(end), }; + return; } + console.log('start + end = null!'); + } init() { + console.log('MainApp init'); // get values from store and use them accordingly. - this.viewRange = window.BasicStore.viewRange; - this.locale = window.BasicStore.locale; - this.language = window.BasicStore.language; + this.viewRange = window.BasicStore.get('viewRange'); + this.locale = window.BasicStore.get('locale'); + this.language = window.BasicStore.get('language'); this.locale = 'equal' === this.locale ? this.language : this.locale; window.__localeId__ = this.language; // the range is always null but later on we will store it in BasicStore. - if (null === this.range.start && null === this.range.end && null === this.defaultRange.start && null === this.defaultRange.end) { - this.range.start = new Date; - this.setDatesFromViewRange(); + if (null === this.range.start && null === this.range.end) { + console.log('start + end = null, calling setDatesFromViewRange()'); + this.range = this.setDatesFromViewRange(new Date); } + console.log('MainApp: set defaultRange'); + this.defaultRange = this.setDatesFromViewRange(new Date); + // default range is always the current period (initialized ahead) } - setDatesFromViewRange() { + setDatesFromViewRange(today) { + console.log('MainApp: setDatesFromViewRange'); let start; let end; let viewRange = this.viewRange; - let today = this.range.start; + console.log('MainApp: viewRange: ' + viewRange); + switch (viewRange) { case 'last365': start = startOfDay(subDays(today, 365)); @@ -143,11 +154,12 @@ class MainApp { end = endOfDay(end); break; } - this.range = {start: start, end: end}; - this.defaultRange = {start: start, end: end}; + console.log('MainApp: setDatesFromViewRange done!'); + return {start: start, end: end}; } buildDateRange() { + console.log('MainApp: buildDateRange'); // generate ranges let nextRange = this.getNextRange(); let prevRange = this.getPrevRange(); @@ -164,9 +176,9 @@ class MainApp { // set the current one element = document.getElementsByClassName('daterange-current')[0]; - element.textContent = format(this.range.start) + ' - ' + format(this.range.end); - element.setAttribute('data-start', format(this.range.start, 'yyyy-MM-dd')); - element.setAttribute('data-end', format(this.range.end, 'yyyy-MM-dd')); + element.textContent = format(this.defaultRange.start) + ' - ' + format(this.defaultRange.end); + element.setAttribute('data-start', format(this.defaultRange.start, 'yyyy-MM-dd')); + element.setAttribute('data-end', format(this.defaultRange.end, 'yyyy-MM-dd')); // generate next range element = document.getElementsByClassName('daterange-next')[0]; @@ -201,6 +213,7 @@ class MainApp { element.setAttribute('data-end', format(ytd.end, 'yyyy-MM-dd')); // custom range. + console.log('MainApp: buildDateRange end'); } getNextRange() { @@ -237,23 +250,29 @@ class MainApp { } changeDateRange(e) { + console.log('MainApp: changeDateRange'); let target = e.currentTarget; //alert('OK 3'); let start = new Date(target.getAttribute('data-start')); let end = new Date(target.getAttribute('data-end')); + console.log('MainApp: Change date range', start, end); e.preventDefault(); + // TODO send start + end to the store and trigger this again? window.app.setStart(start); window.app.setEnd(end); window.app.buildDateRange(); + console.log('MainApp: end changeDateRange'); return false; } setStart(date) { + console.log('MainApp: setStart'); this.range.start = date; window.BasicStore.store('start', date); } setEnd(date) { + console.log('MainApp: setEnd'); this.range.end = date; window.BasicStore.store('end', date); } @@ -263,13 +282,19 @@ let app = new MainApp(); // Listen for the basic store, we need it to continue with the document.addEventListener("BasicStoreReady", (e) => { + console.log('MainApp: app.js from event handler'); app.init(); app.buildDateRange(); + const event = new Event("AppReady"); + document.dispatchEvent(event); }, false,); if (window.BasicStore.isReady()) { + console.log('MainApp: app.js from store ready'); app.init(); app.buildDateRange(); + const event = new Event("AppReady"); + document.dispatchEvent(event); } window.app = app; diff --git a/resources/assets/v4/bootstrap.js b/resources/assets/v4/bootstrap.js index 9f1d518ab3..f7c8bb9a3c 100644 --- a/resources/assets/v4/bootstrap.js +++ b/resources/assets/v4/bootstrap.js @@ -40,9 +40,5 @@ import * as bootstrap from 'bootstrap' // }); -window.Alpine = Alpine -Alpine.start() - - window.BasicStore = new BasicStore; window.BasicStore.init(); diff --git a/resources/assets/v4/index.js b/resources/assets/v4/index.js index 699be04403..7d47a4f0ad 100644 --- a/resources/assets/v4/index.js +++ b/resources/assets/v4/index.js @@ -1,15 +1,80 @@ -//import './bootstrap'; +import Summary from "./api/summary/index.js"; +import {format} from 'date-fns' +import Alpine from "alpinejs"; +//let amounts = []; -//import {onDOMContentLoaded} from "./util/index.js"; +class IndexApp { + balanceBox = {foo: 'bar'}; -// alert('hallo'); + constructor() { + console.log('IndexApp constructor'); + } + init() { + console.log('IndexApp init'); + this.loadBoxes(); + } -// onDOMContentLoaded(() => { -// //alert('OK dan!'); -// }) + loadBoxes() { + console.log('IndexApp loadBoxes'); + let getter = new Summary(); + let start = window.BasicStore.get('start'); + let end = window.BasicStore.get('end'); + // check on NULL values: + if (start !== null && end !== null) { + start = new Date(start); + end = new Date(end); + } -//alert('OK dan 2!'); + getter.get(format(start, 'yyyy-MM-dd'), format(end, 'yyyy-MM-dd'), null).then((response) => { + // + console.log('IndexApp done!'); + console.log(response.data); + document.querySelector('#balanceAmount').innerText = 'ok dan'; + //window.$refs.balanceAmount.text = 'bar!'; + for (const i in response.data) { + if (response.data.hasOwnProperty(i)) { + const current = response.data[i]; + if (i.startsWith('balance-in-')) { + //amounts.push(current); + console.log('Balance in: ', current); + } + } + } + }); + + } +} + +let index = new IndexApp(); + +document.addEventListener("AppReady", (e) => { + index.init(); +}, false,); + +if (window.BasicStore.isReady()) { + index.init(); +} +document.addEventListener('alpine:init', () => { + Alpine.data('balanceBox', () => ({ + foo: 'barX' + })) +}) + +export function amounts() { + return { + amounts: ['bar', 'boo', 'baz'], + add() { + this.amounts.push('foo'); + }, + get() { + return this.amounts[1]; + } + } +} + +window.Alpine = Alpine +Alpine.start() diff --git a/resources/assets/v4/store/Basic.js b/resources/assets/v4/store/Basic.js index c13daa1002..428253a9a2 100644 --- a/resources/assets/v4/store/Basic.js +++ b/resources/assets/v4/store/Basic.js @@ -1,55 +1,68 @@ // basic store for preferred date range and some other vars. // used in layout. import Get from '../api/preferences/index.js'; +import store from 'store2'; +/** + * A basic store for Firefly III persistent UI data and preferences. + */ class Basic { + + // currently availabel variables: viewRange = '1M'; darkMode = 'browser'; language = 'en-US'; locale = 'en-US'; + // start and end are used by most pages to allow the user to browse back and forth. + start = null; + end = null; // others, to be used in the future. listPageSize = 10; currencyCode = 'AAA'; currencyId = '0'; ready = false; + + // a very basic way to signal the store now contains all variables. count = 0; readyCount = 4; - start = null; - end = null; + /** + * + */ constructor() { + console.log('Basic constructor') } + /** + * + */ init() { + console.log('Basic init') this.loadVariable('viewRange') this.loadVariable('darkMode') this.loadVariable('language') this.loadVariable('locale') } + /** + * Load a variable, fresh or from storage. + * @param name + */ loadVariable(name) { + + // currently unused, window.X can be used by the blade template + // to make things available quicker than if the store has to grab it through the API. + // then again, it's not that slow. if (window.hasOwnProperty(name)) { this[name] = window[name]; - this.count++; - if (this.count === this.readyCount) { - // trigger event: - const event = new Event("BasicStoreReady"); - document.dispatchEvent(event); - } - + this.triggerReady(); return; } - // load from local storage - if (localStorage.getItem(name)) { - this[name] = localStorage.getItem(name); - this.count++; - if (this.count === this.readyCount) { - // trigger event: - const event = new Event("BasicStoreReady"); - document.dispatchEvent(event); - } - + // load from store2 + if (store.has(name)) { + this[name] = store.get(name); + this.triggerReady(); return; } // grab @@ -58,29 +71,34 @@ class Basic { } parseResponse(name, response) { - this.count++; let value = response.data.data.attributes.data; this[name] = value; - localStorage.setItem(name, value); - if (this.count === this.readyCount) { - // trigger event: - const event = new Event("BasicStoreReady"); - document.dispatchEvent(event); - } + store.set(name, value); + this.triggerReady(); } - store(name, value) { + set(name, value) { this[name] = value; - localStorage.setItem(name, value); + store.set(name, value); } - getFromLocalStorage(name) { - return localStorage.getItem(name); + get(name) { + return store.get(name, this[name]); } isReady() { return this.count === this.readyCount; } + + triggerReady() { + this.count++; + if (this.count === this.readyCount) { + console.log('Basic store is ready!') + // trigger event: + const event = new Event("BasicStoreReady"); + document.dispatchEvent(event); + } + } } export default Basic; diff --git a/resources/views/index.blade.php b/resources/views/index.blade.php index 3514897657..34643e79f9 100644 --- a/resources/views/index.blade.php +++ b/resources/views/index.blade.php @@ -1,28 +1,17 @@ @extends('layout.v4.default') @section('vite') - @vite(['resources/assets/v4/index.js']) + @vite(['resources/assets/v4/sass/app.scss', 'resources/assets/v4/app.js', 'resources/assets/v4/index.js']) @endsection @section('content')
- Here be content. + @include('partials.dashboard.boxes') - -
- - - - -
- Icon:
- - Icon: -
@endsection diff --git a/resources/views/layout/v4/default.blade.php b/resources/views/layout/v4/default.blade.php index 15642f8aff..5e1eef3a74 100644 --- a/resources/views/layout/v4/default.blade.php +++ b/resources/views/layout/v4/default.blade.php @@ -36,11 +36,11 @@ diff --git a/resources/views/partials/dashboard/boxes.blade.php b/resources/views/partials/dashboard/boxes.blade.php new file mode 100644 index 0000000000..c987b5ff29 --- /dev/null +++ b/resources/views/partials/dashboard/boxes.blade.php @@ -0,0 +1,81 @@ +
+ +
+ +
+
+

TODO amount

+ +

+ {{ __('firefly.in_out_period') }} +

+
+ + + + + + TODO amount + amount + +
+ +
+ +
+ +
+
+

TODO amount

+ +

{{ __('firefly.bills_to_pay') }}

+
+ + + + + {{ __('firefly.paid') }}: TODO amount + +
+ +
+ +
+ +
+
+

TODO amount

+ +

{{ __('firefly.left_to_spend') }}

+
+ + + + + {{ __('firefly.per_day') }}: TODO amount + +
+ +
+ +
+ +
+
+

TODO amount

+ +

+ {{ __('firefly.net_worth') }} +

+
+ + + + +   + +
+ +
+ +
+ diff --git a/resources/views/partials/layout/v4/head.blade.php b/resources/views/partials/layout/v4/head.blade.php index 620eed9128..a9603fd061 100644 --- a/resources/views/partials/layout/v4/head.blade.php +++ b/resources/views/partials/layout/v4/head.blade.php @@ -41,8 +41,6 @@ - - @vite(['resources/assets/v4/sass/app.scss', 'resources/assets/v4/app.js']) @yield('vite')