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 @@ - + @@ -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 @@ +