From a1ca8f22f64562c512bdb88bf1e8a05ffe1b16f5 Mon Sep 17 00:00:00 2001 From: Ioannis Igoumenos Date: Sun, 13 Sep 2026 08:26:25 +0000 Subject: [PATCH] Valid From should default to 00:00:00 (on the current date) and Valid Through should default to 23:59:59 --- .../CoreEnroller/templates/element/field.php | 16 ++++++++++- app/src/View/Helper/FieldHelper.php | 16 +++++++---- .../datepicker/cm-datetimepicker.js | 28 +++++++++++-------- 3 files changed, 43 insertions(+), 17 deletions(-) diff --git a/app/plugins/CoreEnroller/templates/element/field.php b/app/plugins/CoreEnroller/templates/element/field.php index 2cd01cc27..c1de67292 100644 --- a/app/plugins/CoreEnroller/templates/element/field.php +++ b/app/plugins/CoreEnroller/templates/element/field.php @@ -37,6 +37,8 @@ // Get the static configuration of my attribute $supportedAttributes = $this->Petition->getSupportedEnrollmentAttribute($attr->attribute); +$tz = $this->get('vv_tz') ?? new \DateTimeZone(date_default_timezone_get()); + // Do we have a default value configured? // Either a value or an Environmental Variable, // Each default value is mutually exclusive to the rest. We do not have to worry about a conflict. @@ -44,6 +46,14 @@ // NOTE: name/address/telephoneNumber are MVEAs and are rendered as grouped sub-fields. // Their per-component defaults must be applied at the sub-field level, not here. $options['default'] = match(true) { + $attr->attribute === 'valid_from' && !empty($attr->default_value_datetime) + => $attr->default_value_datetime, + $attr->attribute === 'valid_from' && empty($attr->default_value_datetime) + => \Cake\I18n\FrozenTime::now($tz)->startOfDay(), + $attr->attribute === 'valid_through' && !empty($attr->default_value) && is_numeric($attr->default_value) + => \Cake\I18n\FrozenTime::now($tz)->addDays((int)$attr->default_value)->setTime(23, 59, 59), + $attr->attribute === 'valid_through' && empty($attr->default_value) + => \Cake\I18n\FrozenTime::now($tz)->setTime(23, 59, 59), isset($attr->default_value) => $attr->default_value, isset($attr->default_value_env_name) && $attr->attribute !== 'name' @@ -116,7 +126,11 @@ // HIDDEN Field // We print directly, we do not delegate to the element for further processing // In case this is a hidden field, we need to get only the value - $attr->hidden && $hidden => $this->Form->hidden($formArguments['fieldName'], ['value' => $options['default']]), + $attr->hidden && $hidden => $this->Form->hidden($formArguments['fieldName'], [ + 'value' => $options['default'] instanceof \DateTimeInterface + ? $options['default']->i18nFormat('yyyy-MM-dd HH:mm:ss') + : $options['default'] + ]), // For the case of xxx_person_id fields, we will render the People a Picker element. str_ends_with($attr->attribute, 'person_id') => $this->element('CoreEnroller.spa-field', [ 'vueElementName' => 'peopleAutocomplete', diff --git a/app/src/View/Helper/FieldHelper.php b/app/src/View/Helper/FieldHelper.php index 5d04bffa8..61a870a54 100644 --- a/app/src/View/Helper/FieldHelper.php +++ b/app/src/View/Helper/FieldHelper.php @@ -312,9 +312,9 @@ public function dateField(string $fieldName, !empty($queryParams[$fieldName]) => FrozenTime::parse($queryParams[$fieldName]), // Petition View/ Value saved as string isset($fieldArgs['default']) && is_string($fieldArgs['default']) => FrozenTime::parse($fieldArgs['default']), - // Petition View/ Value saved a FronzenTime + // Petition View/ Value saved as FrozenTime or DateTime isset($fieldArgs['default']) - && is_a($fieldArgs['default'], 'Cake\I18n\FrozenTime') => $fieldArgs['default'], + && ($fieldArgs['default'] instanceof \DateTimeInterface || is_a($fieldArgs['default'], 'Cake\I18n\FrozenTime')) => $fieldArgs['default'], // Table record/ Retrieve it from the Entity object default => $this->getEntity()?->$fieldName, }; @@ -329,7 +329,7 @@ public function dateField(string $fieldName, // to specify their types in fields.inc. $pickerTypeName = $fieldArgs['fieldNameAlias'] ?? $fieldName; $pickerType = match ($pickerTypeName) { - 'valid_from' => DateTypeEnum::FromTime, + 'valid_from', 'default_value_datetime' => DateTypeEnum::FromTime, 'valid_through' => DateTypeEnum::ThroughTime, default => $dateType }; @@ -343,15 +343,21 @@ public function dateField(string $fieldName, $coptions['id'] = str_replace('_', '-', $fieldName); + $tz = $this->getView()->get('vv_tz'); + // Default the picker date to today - $now = FrozenTime::now(); + $now = FrozenTime::now($tz); + if($pickerType === DateTypeEnum::ThroughTime) { + $now = $now->setTime(23, 59, 59); + } else { + $now = $now->startOfDay(); + } $pickerDate = $now->i18nFormat($dateFormat); // Get the existing values, if present if($date_object !== null) { if($date_object instanceof \Cake\I18n\DateTime) { // Adjust the time back to the user's timezone - $tz = $this->getView()->get('vv_tz'); if($tz) { $date_object = $date_object->setTimezone($tz); } diff --git a/app/webroot/js/comanage/components/datepicker/cm-datetimepicker.js b/app/webroot/js/comanage/components/datepicker/cm-datetimepicker.js index 4d3b79b0e..4a15ace4e 100644 --- a/app/webroot/js/comanage/components/datepicker/cm-datetimepicker.js +++ b/app/webroot/js/comanage/components/datepicker/cm-datetimepicker.js @@ -66,7 +66,7 @@ export default { // A sanity check to see if someone messed up the field. // The pattern is also enforced by the browser via the "pattern" attribute. if(dateTime[1] === undefined || dateTime[1] === '') { - dateTime[1] = '00:00:00'; + dateTime[1] = (this.type == 'throughtime') ? '23:59:59' : '00:00:00'; } dateField.value = dateTime.join(' '); } @@ -121,17 +121,17 @@ export default { let minutesAndSecondsRegex = /^(0\d|[1-5]\d)$/; if(time[1] === undefined) { // The minutes are missing (including the colon). Restore them. - time.push('00'); + time.push(this.type == 'throughtime' ? '59' : '00'); } else if(!minutesAndSecondsRegex.test(time[1])) { - // The minutes are invalid. Set them to zero. - time[1] = '00'; + // The minutes are invalid. Set them to zero or 59. + time[1] = (this.type == 'throughtime') ? '59' : '00'; } if(time[2] === undefined) { // The seconds are missing (including the colon). Restore them. - time.push('00'); + time.push(this.type == 'throughtime' ? '59' : '00'); } else if(!minutesAndSecondsRegex.test(time[2])) { - // The seconds are invalid. Set them to zero. - time[2] = '00'; + // The seconds are invalid. Set them to zero or 59. + time[2] = (this.type == 'throughtime') ? '59' : '00'; } dateTime[1] = time.join(':'); dateField.value = dateTime.join(' '); @@ -139,10 +139,16 @@ export default { }, formatToday() { const today = new Date(); - // zero out the time so we can set it cleanly - today.setHours(0); - today.setMinutes(0); - today.setSeconds(0); + if(this.type == 'throughtime') { + today.setHours(23); + today.setMinutes(59); + today.setSeconds(59); + } else { + // zero out the time so we can set it cleanly + today.setHours(0); + today.setMinutes(0); + today.setSeconds(0); + } const formattedToday = this.formatDate(today); return formattedToday.split(' '); },