diff --git a/app/Http/Controllers/HomeController.php b/app/Http/Controllers/HomeController.php
index de4bc902e3..ac440035af 100644
--- a/app/Http/Controllers/HomeController.php
+++ b/app/Http/Controllers/HomeController.php
@@ -88,7 +88,7 @@ final class HomeController extends Controller
$end = Carbon::now()->endOfMonth();
}
- $label = $request->get('label');
+ $label = $request->input('label');
$isCustomRange = false;
Log::debug('dateRange: Received dateRange', ['start' => $stringStart, 'end' => $stringEnd, 'label' => $request->get('label')]);
diff --git a/package-lock.json b/package-lock.json
index 44c30c0536..b4bf43fff6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7,7 +7,8 @@
"hasInstallScript": true,
"workspaces": [
"resources/assets/v1",
- "resources/assets/v2"
+ "resources/assets/v2",
+ "resources/assets/v3"
],
"dependencies": {
"patch-package": "^8.0.1"
@@ -1754,6 +1755,23 @@
"tslib": "^2.4.0"
}
},
+ "node_modules/@eonasdan/tempus-dominus": {
+ "version": "6.10.4",
+ "resolved": "https://registry.npmjs.org/@eonasdan/tempus-dominus/-/tempus-dominus-6.10.4.tgz",
+ "integrity": "sha512-aR1QkKUEFyfpqKuRs3ZnIfMhhB4aAS6WO3CpHn4FTLABe2ia3tm4pb7w+ium3w5b/d+mIKSi6VcbDukU+dtnYA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://ko-fi.com/eonasdan"
+ },
+ "peerDependencies": {
+ "@popperjs/core": "^2.11.6"
+ },
+ "peerDependenciesMeta": {
+ "@popperjs/core\"": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@epic-web/invariant": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@epic-web/invariant/-/invariant-1.0.0.tgz",
@@ -4476,6 +4494,60 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/concurrently": {
+ "version": "9.2.1",
+ "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz",
+ "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "4.1.2",
+ "rxjs": "7.8.2",
+ "shell-quote": "1.8.3",
+ "supports-color": "8.1.1",
+ "tree-kill": "1.2.2",
+ "yargs": "17.7.2"
+ },
+ "bin": {
+ "conc": "dist/bin/concurrently.js",
+ "concurrently": "dist/bin/concurrently.js"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
+ }
+ },
+ "node_modules/concurrently/node_modules/shell-quote": {
+ "version": "1.8.3",
+ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz",
+ "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/concurrently/node_modules/supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
"node_modules/connect-history-api-fallback": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz",
@@ -9923,6 +9995,16 @@
"queue-microtask": "^1.2.2"
}
},
+ "node_modules/rxjs": {
+ "version": "7.8.2",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
+ "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^2.1.0"
+ }
+ },
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -10716,6 +10798,13 @@
"node": ">=10.13.0"
}
},
+ "node_modules/tailwindcss": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.0.tgz",
+ "integrity": "sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/tapable": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
@@ -10995,6 +11084,16 @@
"node": ">=0.6"
}
},
+ "node_modules/tree-kill": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
+ "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "tree-kill": "cli.js"
+ }
+ },
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
@@ -11240,6 +11339,10 @@
"resolved": "resources/assets/v2",
"link": true
},
+ "node_modules/v3": {
+ "resolved": "resources/assets/v3",
+ "link": true
+ },
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@@ -12243,6 +12346,21 @@
"vite": "=8.0.14",
"vite-plugin-manifest-sri": "^0.2.0"
}
+ },
+ "resources/assets/v3": {
+ "dependencies": {
+ "@eonasdan/tempus-dominus": "^6.10.4",
+ "@popperjs/core": "^2.11.8",
+ "admin-lte": "^4.0.0",
+ "alpinejs": "^3.15.12"
+ },
+ "devDependencies": {
+ "concurrently": "^9.0.1",
+ "laravel-vite-plugin": "^3.1",
+ "tailwindcss": "^4.0.0",
+ "vite": "^8.0.0",
+ "vite-plugin-manifest-sri": "^0.2.0"
+ }
}
}
}
diff --git a/public/v1/js/ff/auth/register.js b/public/v1/js/ff/auth/register.js
index 8aa4244496..5e7417ef50 100644
--- a/public/v1/js/ff/auth/register.js
+++ b/public/v1/js/ff/auth/register.js
@@ -18,7 +18,7 @@
* along with this program. If not, see .
*/
-$(function () {
+(function () {
"use strict";
const form = document.querySelector('form[action="'+route+'"]');
const errorBox = document.getElementById('client-errors');
diff --git a/public/v1/js/ff/firefly.js b/public/v1/js/ff/firefly.js
index 4f67a38244..4093f43f2e 100644
--- a/public/v1/js/ff/firefly.js
+++ b/public/v1/js/ff/firefly.js
@@ -57,7 +57,7 @@ $(function () {
});
// save sidebar collapsed state when page loads.
- $('[data-toggle="push-menu"]').click(function () {
+ $('[data-lte-toggle="sidebar"]').click(function () {
localStorage.setItem('ff3_sidebar_collapsed', (!$('body').hasClass('sidebar-collapse')).toString());
});
@@ -70,50 +70,50 @@ $(function () {
// when you click on a currency, this happens:
- $('.currency-option').on('click', currencySelect);
+ // $('.currency-option').on('click', currencySelect);
// build the data range:
- $('#daterange').text(dateRangeMeta.title).daterangepicker(
- {
- ranges: dateRangeConfig.ranges,
- opens: 'left',
- locale: {
- applyLabel: dateRangeMeta.labels.apply,
- cancelLabel: dateRangeMeta.labels.cancel,
- fromLabel: dateRangeMeta.labels.from,
- toLabel: dateRangeMeta.labels.to,
- weekLabel: 'W',
- customRangeLabel: dateRangeMeta.labels.customRange,
- daysOfWeek: moment.weekdaysMin(),
- monthNames: moment.monthsShort(),
- firstDay: moment.localeData()._week.dow
- },
- format: 'YYYY-MM-DD',
- startDate: dateRangeConfig.startDate,
- endDate: dateRangeConfig.endDate
- },
- function (start, end, label) {
-
- // send post.
- $.ajax({
- url: dateRangeMeta.url,
- data: {
- start: start.format('YYYY-MM-DD'),
- end: end.format('YYYY-MM-DD'),
- label: label
- },
- type: 'POST',
- headers: {
- 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content'),
- 'Content-Type': 'application/x-www-form-urlencoded'
- }
- }).done(function () {
- window.location.reload(true);
- }).fail(function () {
- console.error('Could not change date range');
- });
- }
- );
+ // $('#daterange').text(dateRangeMeta.title).daterangepicker(
+ // {
+ // ranges: dateRangeConfig.ranges,
+ // opens: 'left',
+ // locale: {
+ // applyLabel: dateRangeMeta.labels.apply,
+ // cancelLabel: dateRangeMeta.labels.cancel,
+ // fromLabel: dateRangeMeta.labels.from,
+ // toLabel: dateRangeMeta.labels.to,
+ // weekLabel: 'W',
+ // customRangeLabel: dateRangeMeta.labels.customRange,
+ // daysOfWeek: moment.weekdaysMin(),
+ // monthNames: moment.monthsShort(),
+ // firstDay: moment.localeData()._week.dow
+ // },
+ // format: 'YYYY-MM-DD',
+ // startDate: dateRangeConfig.startDate,
+ // endDate: dateRangeConfig.endDate
+ // },
+ // function (start, end, label) {
+ //
+ // // send post.
+ // $.ajax({
+ // url: dateRangeMeta.url,
+ // data: {
+ // start: start.format('YYYY-MM-DD'),
+ // end: end.format('YYYY-MM-DD'),
+ // label: label
+ // },
+ // type: 'POST',
+ // headers: {
+ // 'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content'),
+ // 'Content-Type': 'application/x-www-form-urlencoded'
+ // }
+ // }).done(function () {
+ // window.location.reload(true);
+ // }).fail(function () {
+ // console.error('Could not change date range');
+ // });
+ // }
+ // );
// trigger list thing
diff --git a/public/v1/js/ff/help.js b/public/v1/js/ff/help.js
index 30c0f76c0f..086e6f5d0c 100644
--- a/public/v1/js/ff/help.js
+++ b/public/v1/js/ff/help.js
@@ -20,7 +20,7 @@
/** global: token, helpPageTitle, anonymous */
$(function () {
"use strict";
- $('#help').click(showHelp);
+ // $('#help').click(showHelp);
$('#anonymous').click(changeAnonymity)
});
diff --git a/resources/assets/v3/js/pages/dashboard/dashboard.js b/resources/assets/v3/js/pages/dashboard/dashboard.js
index 7269b8972a..a24e5b3154 100644
--- a/resources/assets/v3/js/pages/dashboard/dashboard.js
+++ b/resources/assets/v3/js/pages/dashboard/dashboard.js
@@ -28,6 +28,7 @@ import "bootstrap-icons/font/bootstrap-icons.css"
import '../../boot/bootstrap.js';
import sidebar from '../../pages/shared/sidebar.js';
import boxes from './boxes.js';
+import dates from '../shared/dates.js';
let index = function () {
return {
@@ -42,7 +43,8 @@ let index = function () {
const comps = {
index,
sidebar,
- boxes
+ boxes,
+ dates
};
function loadPage(comps) {
diff --git a/resources/assets/v3/js/pages/shared/dates.js b/resources/assets/v3/js/pages/shared/dates.js
new file mode 100644
index 0000000000..3124254983
--- /dev/null
+++ b/resources/assets/v3/js/pages/shared/dates.js
@@ -0,0 +1,197 @@
+/*
+ * dates.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 {
+ addMonths,
+ endOfDay,
+ endOfMonth,
+ endOfQuarter,
+ endOfWeek,
+ startOfDay,
+ startOfMonth,
+ startOfQuarter,
+ startOfWeek,
+ startOfYear,
+ subDays,
+ subMonths
+} from "date-fns";
+import format from '../../util/format'
+import i18next from "i18next";
+import { TempusDominus } from '@eonasdan/tempus-dominus';
+
+
+export default () => ({
+ range: {
+ start: null, end: null
+ },
+ defaultRange: {
+ start: null, end: null
+ },
+ language: 'en_US',
+
+ init() {
+ console.log('init on dates');
+ this.range = {
+ start: new Date(window.store.get('start')),
+ end: new Date(window.store.get('end'))
+ };
+ this.defaultRange = {
+ start: new Date(window.store.get('start')),
+ end: new Date(window.store.get('end'))
+ };
+ this.language = window.store.get('language');
+ this.locale = window.store.get('locale');
+ this.locale = 'equal' === this.locale ? this.language : this.locale;
+ window.__localeId__ = this.language;
+ this.buildDateRange();
+
+ window.store.observe('start', (newValue) => {
+ this.range.start = new Date(newValue);
+ });
+ window.store.observe('end', (newValue) => {
+ this.range.end = new Date(newValue);
+ this.buildDateRange();
+ });
+ },
+
+
+ buildDateRange() {
+ console.log('Dates buildDateRange');
+
+ // generate ranges
+ let nextRange = this.getNextRange();
+ let prevRange = this.getPrevRange();
+ let last7 = this.lastDays(7);
+ let last30 = this.lastDays(30);
+ let mtd = this.mtd();
+ let ytd = this.ytd();
+
+ // set the title:
+ let element = document.getElementsByClassName('daterange-holder')[0];
+ console.log('element', element);
+ 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'));
+
+ // set the current one
+ element = document.getElementsByClassName('daterange-current')[0];
+ 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];
+ element.textContent = format(nextRange.start) + ' - ' + format(nextRange.end);
+ element.setAttribute('data-start', format(nextRange.start, 'yyyy-MM-dd'));
+ element.setAttribute('data-end', format(nextRange.end, 'yyyy-MM-dd'));
+ //
+ // // previous range.
+ element = document.getElementsByClassName('daterange-prev')[0];
+ element.textContent = format(prevRange.start) + ' - ' + format(prevRange.end);
+ element.setAttribute('data-start', format(prevRange.start, 'yyyy-MM-dd'));
+ element.setAttribute('data-end', format(prevRange.end, 'yyyy-MM-dd'));
+ //
+ // // last 7
+ element = document.getElementsByClassName('daterange-7d')[0];
+ element.setAttribute('data-start', format(last7.start, 'yyyy-MM-dd'));
+ element.setAttribute('data-end', format(last7.end, 'yyyy-MM-dd'));
+ //
+ // // last 30
+ element = document.getElementsByClassName('daterange-30d')[0];
+ element.setAttribute('data-start', format(last30.start, 'yyyy-MM-dd'));
+ element.setAttribute('data-end', format(last30.end, 'yyyy-MM-dd'));
+ //
+ // // MTD
+ element = document.getElementsByClassName('daterange-mtd')[0];
+ element.setAttribute('data-start', format(mtd.start, 'yyyy-MM-dd'));
+ element.setAttribute('data-end', format(mtd.end, 'yyyy-MM-dd'));
+ //
+ // // YTD
+ element = document.getElementsByClassName('daterange-ytd')[0];
+ element.setAttribute('data-start', format(ytd.start, 'yyyy-MM-dd'));
+ element.setAttribute('data-end', format(ytd.end, 'yyyy-MM-dd'));
+
+ // // custom range.
+ // // console.log('MainApp: buildDateRange end');
+ // new TempusDominus(document.getElementById('datetimepicker1'), {
+ // dateRange: true,
+ // display: {
+ // components: {
+ // decades: false,
+ // year: true,
+ // month: true,
+ // date: true,
+ // hours: false,
+ // minutes: false,
+ // seconds: false
+ // }
+ // }
+ // });
+ },
+
+ getNextRange() {
+ let start = startOfMonth(this.range.start);
+ let nextMonth = addMonths(start, 1);
+ let end = endOfMonth(nextMonth);
+ return {start: nextMonth, end: end};
+ },
+
+ getPrevRange() {
+ let start = startOfMonth(this.range.start);
+ let prevMonth = subMonths(start, 1);
+ let end = endOfMonth(prevMonth);
+ return {start: prevMonth, end: end};
+ },
+
+ ytd() {
+ let end = new Date;
+ let start = startOfYear(this.range.start);
+ return {start: start, end: end};
+ },
+
+ mtd() {
+
+ let end = new Date;
+ let start = startOfMonth(this.range.start);
+ return {start: start, end: end};
+ },
+
+ lastDays(days) {
+ let end = new Date;
+ let start = subDays(end, days);
+ return {start: start, end: end};
+ },
+
+ changeDateRange(e) {
+ e.preventDefault();
+ // console.log('MainApp: changeDateRange');
+ let target = e.currentTarget;
+
+ let start = new Date(target.getAttribute('data-start'));
+ let end = new Date(target.getAttribute('data-end'));
+ // console.log('MainApp: Change date range', start, end);
+
+ window.store.set('start', start);
+ window.store.set('end', end);
+ //this.buildDateRange();
+ return false;
+ },
+
+});
diff --git a/resources/assets/v3/js/util/format.js b/resources/assets/v3/js/util/format.js
new file mode 100644
index 0000000000..93018b5901
--- /dev/null
+++ b/resources/assets/v3/js/util/format.js
@@ -0,0 +1,99 @@
+/*
+ * format.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 {format} from 'date-fns'
+import {
+ bg,
+ cs,
+ da,
+ de,
+ el,
+ enGB,
+ enUS,
+ es,
+ ca,
+ fi,
+ fr,
+ hu,
+ id,
+ it,
+ ja,
+ ko,
+ nb,
+ nn,
+ nl,
+ pl,
+ ptBR,
+ pt,
+ ro,
+ ru,
+ sk,
+ sl,
+ sv,
+ tr,
+ uk,
+ vi,
+ zhTW,
+ zhCN
+} from 'date-fns/locale'
+
+const locales = {
+ bg,
+ cs,
+ da,
+ de,
+ el,
+ enGB,
+ enUS,
+ es,
+ ca,
+ fi,
+ fr,
+ hu,
+ id,
+ it,
+ ja,
+ ko,
+ nb,
+ nn,
+ nl,
+ pl,
+ ptBR,
+ pt,
+ ro,
+ ru,
+ sk,
+ sl,
+ sv,
+ tr,
+ uk,
+ vi,
+ zhTW,
+ zhCN
+}
+
+// by providing a default string of 'PP' or any of its variants for `formatStr`
+// it will format dates in whichever way is appropriate to the locale
+export default function (date, formatStr = 'PP') {
+ let locale = window.__localeId__.replace('_', '');
+ return format(date, formatStr, {
+ locale: locales[locale] ?? locales[locale.slice(0, 2)] ?? locales['enUS'] // or global.__localeId__
+ })
+}
diff --git a/resources/assets/v3/package.json b/resources/assets/v3/package.json
index 653d4eee13..6e8ab48612 100644
--- a/resources/assets/v3/package.json
+++ b/resources/assets/v3/package.json
@@ -3,6 +3,8 @@
"name": "v3",
"private": true,
"dependencies": {
+ "@eonasdan/tempus-dominus": "^6.10.4",
+ "@popperjs/core": "^2.11.8",
"admin-lte": "^4.0.0",
"alpinejs": "^3.15.12"
},
diff --git a/resources/views/layout/v3/session.blade.php b/resources/views/layout/v3/session.blade.php
index 616a69881d..62f960bbc7 100644
--- a/resources/views/layout/v3/session.blade.php
+++ b/resources/views/layout/v3/session.blade.php
@@ -53,7 +53,13 @@
-
+{{-- this entry is in the header so it's loaded early --}}
+
@@ -87,12 +93,74 @@
-
-
-
+
+
+
+
+
+
+
@@ -109,9 +177,8 @@
-
-
+
+
@@ -259,6 +326,33 @@
+
+
+
+
+
+
+
+
+
+
+
@yield('content')
@@ -300,7 +394,7 @@
{{-- Moment JS --}}
-
+
{{-- All kinds of variables. --}}
@@ -311,6 +405,7 @@
{{-- date range picker, current template, etc. --}}
+
{{-- Firefly III code --}}
@@ -397,6 +492,7 @@
+
@@ -428,6 +524,7 @@
+