From 075ba0f3305e127dafd2494d4f80776bd42aab9b Mon Sep 17 00:00:00 2001 From: ralf Date: Tue, 11 Oct 2022 16:19:58 +0200 Subject: [PATCH] WIP timesheet timers: do not allow to enter a time before the last time entered eg. a stop- or pause-time before the start-time or a start-time before the last stop- or pause-time --- api/js/jsapi/egw_timer.js | 75 +++++++++++++++++++++++++++++++++----- timesheet/lang/egw_de.lang | 3 +- timesheet/lang/egw_en.lang | 3 +- timesheet/src/Events.php | 7 ++++ 4 files changed, 77 insertions(+), 11 deletions(-) diff --git a/api/js/jsapi/egw_timer.js b/api/js/jsapi/egw_timer.js index c3f3025ff8..2bd2385ece 100644 --- a/api/js/jsapi/egw_timer.js +++ b/api/js/jsapi/egw_timer.js @@ -55,6 +55,7 @@ egw.extend('timer', egw.MODULE_GLOBAL, function() { stopTimer(overall); } + overall.last = _state.overall.last ? new Date(_state.overall.last) : undefined; // initiate specific timer, only if running or paused if (_state.specific?.start || _state.specific?.paused) @@ -70,6 +71,7 @@ egw.extend('timer', egw.MODULE_GLOBAL, function() stopTimer(specific); } } + specific.last = _state.specific.last ? new Date(_state.specific.last) : undefined; } /** @@ -256,15 +258,14 @@ egw.extend('timer', egw.MODULE_GLOBAL, function() */ function startTimer(_timer, _start, _offset) { + const time = _start ? new Date(_start) : new Date(); + if (_timer.last && time.valueOf() < _timer.last.valueOf()) + { + throw egw.lang('Start-time can not be before last stop- or pause-time %1!', formatUTCTime(_timer.last)); + } // update _timer state object - if (_start) - { - _timer.start = new Date(_start); - } - else if(typeof _timer.start === 'undefined') - { - _timer.start = new Date(); - } + _timer.last = _timer.start = time; + if (_offset || _timer.offset && _timer.paused) { _timer.start.setMilliseconds(_timer.start.getMilliseconds()-(_offset || _timer.offset)); @@ -296,17 +297,29 @@ egw.extend('timer', egw.MODULE_GLOBAL, function() function stopTimer(_timer, _pause, _time) { const time = _time ? new Date(_time) : new Date(); + if (time.valueOf() < _timer.last.valueOf()) + { + const last_time = formatUTCTime(_timer.last); + if (_timer.start) + { + throw egw.lang('Stop- or pause-time can not be before the start-time %1!', last_time); + } + else + { + throw egw.lang('Start-time can not be before last stop- or pause-time %1!', last_time); + } + } // update _timer state object if (_timer.start) { if (time.valueOf() < _timer.start.valueOf()) { - throw egw.lang('Stop- or pause-time can not be before the start-time!'); } _timer.offset = time.valueOf() - _timer.start.valueOf(); _timer.start = undefined; } _timer.paused = _pause || false; + _timer.last = time; // update timer display updateTimer(timer, _timer); @@ -333,6 +346,50 @@ egw.extend('timer', egw.MODULE_GLOBAL, function() } } + /** + * Format a time according to user preference + * + * Cant import from DateTime.ts, gives an error ;) + * + * @param {Date} date + * @param {Object|undefined} options object containing attribute timeFormat=12|24, default user preference + * @returns {string} + */ + function formatTime(date, options) + { + if(!date || !(date instanceof Date)) + { + return ""; + } + let _value = ''; + + let timeformat = options?.timeFormat || egw.preference("timeformat") || "24"; + let hours = (timeformat == "12" && date.getUTCHours() > 12) ? (date.getUTCHours() - 12) : date.getUTCHours(); + if(timeformat == "12" && hours == 0) + { + // 00:00 is 12:00 am + hours = 12; + } + + _value = (timeformat == "24" && hours < 10 ? "0" : "") + hours + ":" + + (date.getUTCMinutes() < 10 ? "0" : "") + (date.getUTCMinutes()) + + (timeformat == "24" ? "" : (date.getUTCHours() < 12 ? " am" : " pm")); + + return _value; + } + + /** + * Format a UTC time according to user preference + * + * @param {Date} date + * @returns {string} + */ + function formatUTCTime(date) + { + // eT2 operates in user-time, while timers here always operate in UTC + return formatTime(new Date(date.valueOf() - egw.getTimezoneOffset() * 60000)); + } + return { /** * Start timer for given app and id diff --git a/timesheet/lang/egw_de.lang b/timesheet/lang/egw_de.lang index 853b42e768..bfd1fc4b05 100644 --- a/timesheet/lang/egw_de.lang +++ b/timesheet/lang/egw_de.lang @@ -131,6 +131,7 @@ skip record timesheet de Eintrag überspringen start timesheet de Start start & stop timer common de Zeitnehmer starten & stoppen start timer common de Zeitnehmer starten +start-time can not be before last stop- or pause-time %1! common de Start-Zeit kann nicht vor der letzen Stop- oder Pausen-Zeit %1 liegen! starttime timesheet de Startzeit starttime has to be before endtime !!! timesheet de Startzeit muss vor der Endzeit liegen !!! status timesheet de Status @@ -138,7 +139,7 @@ status deleted. timesheet de Status gelöscht status of created timesheets timesheet de Status für neue Stundenzettel status updated. timesheet de Status geändert stop common de Stop -stop- or pause-time can not be before the start-time! common de Stop- oder Pause-Zeit kann nicht vor der Start-Zeit liegen! +stop- or pause-time can not be before the start-time %1! common de Stop- oder Pausen-Zeit kann nicht for der Start-Zeit %1 liegen! sum timesheet de Summe sum %1: timesheet de Summe %1: tag to mark positions for address labels timesheet de Platzhalter, um die Position der Adresslabels festzulegen diff --git a/timesheet/lang/egw_en.lang b/timesheet/lang/egw_en.lang index 673939e0e3..4758a255db 100644 --- a/timesheet/lang/egw_en.lang +++ b/timesheet/lang/egw_en.lang @@ -131,6 +131,7 @@ skip record timesheet en Skip record start timesheet en Start start & stop timer common en Start & stop timer start timer common en Start timer +start-time can not be before last stop- or pause-time %1! common en Start-time can not be before last stop- or pause-time %1! starttime timesheet en Start time starttime has to be before endtime !!! timesheet en Start time has to be before endtime! status timesheet en Status @@ -138,7 +139,7 @@ status deleted. timesheet en Status deleted. status of created timesheets timesheet en Status of created timesheets status updated. timesheet en Status updated. stop common en Stop -stop- or pause-time can not be before the start-time! common en Stop- or pause-time can not be before the start-time! +stop- or pause-time can not be before the start-time %1! common en Stop- or pause-time can not be before the start-time %1! sum timesheet en Sum sum %1: timesheet en Sum %1: tag to mark positions for address labels timesheet en Tag to mark positions for address labels diff --git a/timesheet/src/Events.php b/timesheet/src/Events.php index 5c067cbbac..82dac4314e 100644 --- a/timesheet/src/Events.php +++ b/timesheet/src/Events.php @@ -201,11 +201,13 @@ class Events extends Api\Storage\Base 'offset' => 0, 'start' => null, 'paused' => false, + 'last' => null, ], 'specific' => [ 'offset' => 0, 'start' => null, 'paused' => false, + 'last' => null, ], ]; foreach(self::getInstance()->search('', false, 'tse_id', '', '', false, 'AND', false, [ @@ -244,6 +246,10 @@ class Events extends Api\Storage\Base { $timer['start'] = (new Api\DateTime($timer['start'], new \DateTimeZone('UTC')))->format(Api\DateTime::ET2); } + if (isset($timer['last'])) + { + $timer['last'] = (new Api\DateTime($timer['last'], new \DateTimeZone('UTC')))->format(Api\DateTime::ET2); + } } // send timer configuration to client-side $config = Api\Config::read(self::APP); @@ -280,6 +286,7 @@ class Events extends Api\Storage\Base { $timer['paused'] = ($row['tse_type'] & self::PAUSE) === self::PAUSE; } + $timer['last'] = $row['tse_time']; return $time ?? null; }