Fix Regression - Show calendar popup at set due date.

Thanks to xet7 !

Fixes #5978
This commit is contained in:
Lauri Ojansivu 2025-11-06 02:32:34 +02:00
parent b02af27ac3
commit 581733d605
5 changed files with 77 additions and 126 deletions

View file

@ -97,6 +97,12 @@ template(name="minicardCustomFieldDate")
template(name="editCardReceivedDatePopup") template(name="editCardReceivedDatePopup")
form.edit-card-received-date form.edit-card-received-date
.datepicker .datepicker
// Date input field (existing)
// Insert calendar selector right after date input
.calendar-selector
label(for="calendar-received") 🗓️
input#calendar-received.js-calendar-date(type="date")
// Time input field (if present)
.clear-date .clear-date
a.js-clear-date {{_ 'clear'}} a.js-clear-date {{_ 'clear'}}
.datepicker-actions .datepicker-actions
@ -106,6 +112,11 @@ template(name="editCardReceivedDatePopup")
template(name="editCardStartDatePopup") template(name="editCardStartDatePopup")
form.edit-card-start-date form.edit-card-start-date
.datepicker .datepicker
// Date input field (existing)
.calendar-selector
label(for="calendar-start") 🗓️
input#calendar-start.js-calendar-date(type="date")
// Time input field (if present)
.clear-date .clear-date
a.js-clear-date {{_ 'clear'}} a.js-clear-date {{_ 'clear'}}
.datepicker-actions .datepicker-actions
@ -115,6 +126,11 @@ template(name="editCardStartDatePopup")
template(name="editCardDueDatePopup") template(name="editCardDueDatePopup")
form.edit-card-due-date form.edit-card-due-date
.datepicker .datepicker
// Date input field (existing)
.calendar-selector
label(for="calendar-due") 🗓️
input#calendar-due.js-calendar-date(type="date")
// Time input field (if present)
.clear-date .clear-date
a.js-clear-date {{_ 'clear'}} a.js-clear-date {{_ 'clear'}}
.datepicker-actions .datepicker-actions
@ -124,6 +140,11 @@ template(name="editCardDueDatePopup")
template(name="editCardEndDatePopup") template(name="editCardEndDatePopup")
form.edit-card-end-date form.edit-card-end-date
.datepicker .datepicker
// Date input field (existing)
.calendar-selector
label(for="calendar-end") 🗓️
input#calendar-end.js-calendar-date(type="date")
// Time input field (if present)
.clear-date .clear-date
a.js-clear-date {{_ 'clear'}} a.js-clear-date {{_ 'clear'}}
.datepicker-actions .datepicker-actions

View file

@ -50,6 +50,17 @@ import {
onRendered() { onRendered() {
super.onRendered(); super.onRendered();
// DatePicker base class handles initialization with native HTML inputs // DatePicker base class handles initialization with native HTML inputs
const self = this;
this.$('.js-calendar-date').on('change', function(evt) {
const currentUser = ReactiveCache.getCurrentUser && ReactiveCache.getCurrentUser();
const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
const value = evt.target.value;
if (value) {
// Format date according to user preference
const formatted = formatDateByUserPreference(new Date(value), dateFormat, true);
self._storeDate(new Date(value));
}
});
} }
_storeDate(date) { _storeDate(date) {

View file

@ -4,7 +4,7 @@ template(name="datepicker")
.fields .fields
.left .left
label(for="date") {{_ 'date'}} label(for="date") {{_ 'date'}}
input.js-date-field#date(type="text" name="date" value=showDate autofocus placeholder=dateFormat) input.js-date-field#date(type="date" name="date" value=showDate autofocus)
.right .right
label(for="time") {{_ 'time'}} label(for="time") {{_ 'time'}}
input.js-time-field#time(type="time" name="time" value=showTime) input.js-time-field#time(type="time" name="time" value=showTime)

View file

@ -293,6 +293,8 @@
overflow-y: auto !important; overflow-y: auto !important;
} }
.pop-over[data-popup="editCardReceivedDatePopup"] .edit-date button, .pop-over[data-popup="editCardReceivedDatePopup"] .edit-date button,
.pop-over[data-popup="editCardStartDatePopup"] .edit-date button, .pop-over[data-popup="editCardStartDatePopup"] .edit-date button,
.pop-over[data-popup="editCardDueDatePopup"] .edit-date button, .pop-over[data-popup="editCardDueDatePopup"] .edit-date button,
@ -387,9 +389,6 @@
margin: 0; margin: 0;
visibility: hidden; visibility: hidden;
} }
.pop-over .quiet {
/* padding: 6px 6px 4px;*/
}
.pop-over.search-over { .pop-over.search-over {
background: #f0f0f0; background: #f0f0f0;
min-height: 14vh; min-height: 14vh;

View file

@ -1,33 +1,27 @@
import { ReactiveCache } from '/imports/reactiveCache'; import { ReactiveCache } from '/imports/reactiveCache';
import { TAPi18n } from '/imports/i18n'; import { TAPi18n } from '/imports/i18n';
import {
formatDateTime,
formatDate,
formatDateByUserPreference,
formatTime,
getISOWeek,
isValidDate,
isBefore,
isAfter,
isSame,
add,
subtract,
startOf,
endOf,
format,
parseDate,
now,
createDate,
fromNow,
calendar
} from '/imports/lib/dateUtils';
// Helper function to get time format for 24 hours // Helper to check if a date is valid
function adjustedTimeFormat() { function isValidDate(date) {
return 'HH:mm'; return date instanceof Date && !isNaN(date);
} }
// .replace(/HH/i, 'H'); // Format date as YYYY-MM-DD
function formatDate(date) {
if (!isValidDate(date)) return '';
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
// Format time as HH:mm
function formatTime(date) {
if (!isValidDate(date)) return '';
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
return `${hours}:${minutes}`;
}
export class DatePicker extends BlazeComponent { export class DatePicker extends BlazeComponent {
template() { template() {
@ -51,35 +45,25 @@ export class DatePicker extends BlazeComponent {
} }
onRendered() { onRendered() {
// Set initial values for text and time inputs // Set initial values for native HTML inputs
if (isValidDate(this.date.get())) { if (isValidDate(this.date.get())) {
const dateInput = this.find('#date'); const dateInput = this.find('#date');
const timeInput = this.find('#time'); const timeInput = this.find('#time');
if (dateInput) { if (dateInput) {
// Use user's preferred format for text input dateInput.value = formatDate(this.date.get());
const currentUser = ReactiveCache.getCurrentUser();
const userFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
dateInput.value = formatDateByUserPreference(this.date.get(), userFormat, false);
} }
if (timeInput) { if (timeInput && !timeInput.value && this.defaultTime) {
if (!timeInput.value && this.defaultTime) { const defaultDate = new Date(this.defaultTime);
const defaultDate = new Date(this.defaultTime); timeInput.value = formatTime(defaultDate);
timeInput.value = formatTime(defaultDate); } else if (timeInput && isValidDate(this.date.get())) {
} else if (isValidDate(this.date.get())) { timeInput.value = formatTime(this.date.get());
timeInput.value = formatTime(this.date.get());
}
} }
} }
} }
showDate() { showDate() {
if (isValidDate(this.date.get())) { if (isValidDate(this.date.get())) return formatDate(this.date.get());
// Use user's preferred format for display, but HTML date input needs YYYY-MM-DD
const currentUser = ReactiveCache.getCurrentUser();
const userFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
return formatDateByUserPreference(this.date.get(), userFormat, false);
}
return ''; return '';
} }
showTime() { showTime() {
@ -87,56 +71,22 @@ export class DatePicker extends BlazeComponent {
return ''; return '';
} }
dateFormat() { dateFormat() {
const currentUser = ReactiveCache.getCurrentUser(); return 'YYYY-MM-DD';
const userFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
// Convert format to localized placeholder
switch (userFormat) {
case 'DD-MM-YYYY':
return TAPi18n.__('date-format-dd-mm-yyyy') || 'PP-KK-VVVV';
case 'MM-DD-YYYY':
return TAPi18n.__('date-format-mm-dd-yyyy') || 'KK-PP-VVVV';
case 'YYYY-MM-DD':
default:
return TAPi18n.__('date-format-yyyy-mm-dd') || 'VVVV-KK-PP';
}
} }
timeFormat() { timeFormat() {
return 'LT'; return 'HH:mm';
} }
events() { events() {
return [ return [
{ {
'change .js-date-field'() { 'change .js-date-field'() {
// Text input date validation // Native HTML date input validation
const dateInput = this.find('#date'); const dateValue = this.find('#date').value;
if (!dateInput) return;
const dateValue = dateInput.value;
if (dateValue) { if (dateValue) {
// Try to parse different date formats // HTML date input format is always YYYY-MM-DD
const formats = [ const dateObj = new Date(dateValue + 'T12:00:00');
'YYYY-MM-DD', if (isValidDate(dateObj)) {
'DD-MM-YYYY',
'MM-DD-YYYY',
'DD/MM/YYYY',
'MM/DD/YYYY',
'DD.MM.YYYY',
'MM.DD.YYYY'
];
let parsedDate = null;
for (const format of formats) {
parsedDate = parseDate(dateValue, [format], true);
if (parsedDate) break;
}
// Fallback to native Date parsing
if (!parsedDate) {
parsedDate = new Date(dateValue);
}
if (isValidDate(parsedDate)) {
this.error.set(''); this.error.set('');
} else { } else {
this.error.set('invalid-date'); this.error.set('invalid-date');
@ -145,12 +95,10 @@ export class DatePicker extends BlazeComponent {
}, },
'change .js-time-field'() { 'change .js-time-field'() {
// Native HTML time input validation // Native HTML time input validation
const timeInput = this.find('#time'); const timeValue = this.find('#time').value;
if (!timeInput) return;
const timeValue = timeInput.value;
if (timeValue) { if (timeValue) {
const timeObj = new Date(`1970-01-01T${timeValue}`); // HTML time input format is always HH:mm
const timeObj = new Date(`1970-01-01T${timeValue}:00`);
if (isValidDate(timeObj)) { if (isValidDate(timeObj)) {
this.error.set(''); this.error.set('');
} else { } else {
@ -170,44 +118,16 @@ export class DatePicker extends BlazeComponent {
return; return;
} }
// Try to parse different date formats // Combine date and time: HTML date input is YYYY-MM-DD, time input is HH:mm
const formats = [ const dateTimeString = `${dateValue}T${timeValue}:00`;
'YYYY-MM-DD', const newCompleteDate = new Date(dateTimeString);
'DD-MM-YYYY',
'MM-DD-YYYY',
'DD/MM/YYYY',
'MM/DD/YYYY',
'DD.MM.YYYY',
'MM.DD.YYYY'
];
let parsedDate = null; if (!isValidDate(newCompleteDate)) {
for (const format of formats) {
parsedDate = parseDate(dateValue, [format], true);
if (parsedDate) break;
}
// Fallback to native Date parsing
if (!parsedDate) {
parsedDate = new Date(dateValue);
}
if (!isValidDate(parsedDate)) {
this.error.set('invalid'); this.error.set('invalid');
return; return;
} }
// Combine with time this._storeDate(newCompleteDate);
const timeObj = new Date(`1970-01-01T${timeValue}`);
if (!isValidDate(timeObj)) {
this.error.set('invalid-time');
return;
}
// Set the time on the parsed date
parsedDate.setHours(timeObj.getHours(), timeObj.getMinutes(), 0, 0);
this._storeDate(parsedDate);
Popup.back(); Popup.back();
}, },
'click .js-delete-date'(evt) { 'click .js-delete-date'(evt) {