diff --git a/docs/DataStructure.md b/docs/DataStructure.md index 52b793110..909706f04 100644 --- a/docs/DataStructure.md +++ b/docs/DataStructure.md @@ -308,6 +308,9 @@ Supported trigger types for conditional questions: | `multiple_unique` | `option_selected` | Radio buttons - the selected option | | `dropdown` | `option_selected` | Dropdown - the selected option | | `multiple` | `options_combination` | Checkboxes - all options of a combination | +| `date` | `date_range` | Date - range including its bounds (`YYYY-MM-DD`) | +| `datetime` | `date_range` | Deprecated date and time (`YYYY-MM-DD HH:mm`) | +| `time` | `date_range` | Time - range including its bounds (`HH:mm`) | A branch is shown when any of its conditions matches. Several branches can be shown at once. @@ -357,6 +360,18 @@ Conditions determine when a branch is activated. The structure depends on the tr All options in `optionIds` must be selected for the condition to match. +#### date_range (for date, datetime, time) + +```json +{ "type": "date_range", "min": "2024-01-01", "max": "2024-12-31" } +``` + +```json +{ "type": "date_range", "min": "09:00", "max": "17:00" } +``` + +`min` and `max` use the answer format of the trigger type and are optional. + ### Conditional Question Example A complete conditional question structure: diff --git a/lib/Constants.php b/lib/Constants.php index bd7ee9c77..e4352a230 100644 --- a/lib/Constants.php +++ b/lib/Constants.php @@ -261,6 +261,7 @@ class Constants { */ public const CONDITION_TYPE_OPTION_SELECTED = 'option_selected'; public const CONDITION_TYPE_OPTIONS_COMBINATION = 'options_combination'; + public const CONDITION_TYPE_DATE_RANGE = 'date_range'; /** * Trigger types allowed for conditional questions @@ -270,6 +271,9 @@ class Constants { self::ANSWER_TYPE_MULTIPLEUNIQUE => [self::CONDITION_TYPE_OPTION_SELECTED], self::ANSWER_TYPE_DROPDOWN => [self::CONDITION_TYPE_OPTION_SELECTED], self::ANSWER_TYPE_MULTIPLE => [self::CONDITION_TYPE_OPTIONS_COMBINATION], + self::ANSWER_TYPE_DATE => [self::CONDITION_TYPE_DATE_RANGE], + self::ANSWER_TYPE_DATETIME => [self::CONDITION_TYPE_DATE_RANGE], + self::ANSWER_TYPE_TIME => [self::CONDITION_TYPE_DATE_RANGE], ]; /** diff --git a/lib/Service/SubmissionService.php b/lib/Service/SubmissionService.php index f4fa13358..56623edfe 100644 --- a/lib/Service/SubmissionService.php +++ b/lib/Service/SubmissionService.php @@ -1159,6 +1159,36 @@ private function evaluateBranchConditions(string $triggerType, array $triggerAns } } return false; + case Constants::ANSWER_TYPE_DATE: + case Constants::ANSWER_TYPE_DATETIME: + case Constants::ANSWER_TYPE_TIME: + // Date range conditions + $dateValue = $triggerAnswer[0] ?? ''; + if (empty($dateValue)) { + return false; + } + $format = Constants::ANSWER_PHPDATETIME_FORMAT[$triggerType] ?? 'Y-m-d'; + $date = \DateTime::createFromFormat('!' . $format, $dateValue); + if (!$date) { + return false; + } + + foreach ($conditions as $condition) { + $min = isset($condition['min']) ? \DateTime::createFromFormat('!' . $format, $condition['min']) : null; + $max = isset($condition['max']) ? \DateTime::createFromFormat('!' . $format, $condition['max']) : null; + + $inRange = true; + if ($min && $date < $min) { + $inRange = false; + } + if ($max && $date > $max) { + $inRange = false; + } + if ($inRange) { + return true; + } + } + return false; default: return false; } diff --git a/src/components/Conditional/BranchConditionEditor.vue b/src/components/Conditional/BranchConditionEditor.vue index eb74f74b0..9b3b938a7 100644 --- a/src/components/Conditional/BranchConditionEditor.vue +++ b/src/components/Conditional/BranchConditionEditor.vue @@ -31,17 +31,39 @@ @update:modelValue="onMultipleOptionsSelect" /> + + +