diff --git a/docs/gherkin/Relative-Scheduler-time-and-participant-starting-time.md b/docs/gherkin/Relative-Scheduler-time-and-participant-starting-time.md
new file mode 100644
index 00000000..2e4669fd
--- /dev/null
+++ b/docs/gherkin/Relative-Scheduler-time-and-participant-starting-time.md
@@ -0,0 +1,11 @@
+# Gherkin Test: Bug fix relative scheduler (UTC time) and participant starting time
+
+### Background:
+- Study was created or exists and has a valid relative observation and 10 participants.
+
+| **Scenario** | **Given** | **Steps** | **Expected Result** | **Result** | **Note** |
+|---------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------|-----------------------------------------------------|
+| Participant list exists and updates | Background, and that a smartphone with the more app is prepared |
- WHEN I click on the participant tab,
- And join the study as one of the participants
| THEN the participants list should show a "started on" coloumn
AND it should update with the correct starting date once the user data has been entered to the smartphone | as expected | After reload the startdate and time has been shown. |
+| Relative scheduer shows the correct start and end times | Background, and the observation tab is open | - WHEN I create a new observation
- AND I add a relative scheduler
- AND enter a valid start and end date
- AND save the relative scheduler
- AND fill in the needed data to save.
- AND save the observation.
| THEN the relative scheduler should show the correct start and end date (I have entered) at any given point during this test. | as expected | |
+| The exported calendar shows the correct dates. | Background, and the study list is open. | - WHEN I click the export study calendar button
- AND I import the data to lokal calendar
| THEN the existing observation(s) should be displayed correctly
AND should not have a one hour offset compared to the observation(s) in the study manager | as expected | |
+| Correct observation display on the smartphone | Background, one observation with a relative calendar exists with an start time of day one at 00:00 and an end time of 12:00
AND it is repeated every day
AND a mobile phone with the MORE app is ready to join the study
AND the participant tab is open | - WHEN I join the study on the mobile phone as one of the participants, which can have a relative observation take place,
| THEN the observaions should be shown at the correct time, at the correct day. | as expected | |
diff --git a/openapi/RelativeEvent.yaml b/openapi/RelativeEvent.yaml
index 2e6833f1..10e910fb 100644
--- a/openapi/RelativeEvent.yaml
+++ b/openapi/RelativeEvent.yaml
@@ -19,6 +19,7 @@ components:
- MINUTE
- HOUR
- DAY
+
RelativeDate:
type: object
description: A date relative to a specific base date (e.g study start)
@@ -29,6 +30,10 @@ components:
type: string
format: time
description: Follows ISO 8601 format for time
+ timezone:
+ type: string
+ description: Time Zone string for relative event
+
RelativeRecurrenceRule:
type: object
description: A recurrence rule relative to dtstart
diff --git a/openapi/StudyManagerAPI.yaml b/openapi/StudyManagerAPI.yaml
index 40fb4c95..1bce37a3 100644
--- a/openapi/StudyManagerAPI.yaml
+++ b/openapi/StudyManagerAPI.yaml
@@ -1397,6 +1397,10 @@ components:
readOnly: true
status:
$ref: '#/components/schemas/ParticipantStatus'
+ start:
+ type: string
+ format: date-time
+ readOnly: true
created:
type: string
format: date-time
diff --git a/src/components/ObservationList.vue b/src/components/ObservationList.vue
index 81f80ed4..f3043dd4 100644
--- a/src/components/ObservationList.vue
+++ b/src/components/ObservationList.vue
@@ -36,7 +36,6 @@ Licensed under the Elastic License 2.0. */
import { useErrorHandling } from '../composable/useErrorHandling';
import DeleteMoreTableRowDialog from './dialog/DeleteMoreTableRowDialog.vue';
import dayjs from 'dayjs';
- import { ZTimeStringToOffsetTimeString } from '../utils/dateUtils';
const loader = useLoader();
const { observationsApi } = useObservationsApi();
@@ -314,15 +313,13 @@ Licensed under the Elastic License 2.0. */
schedule.dtstart.offset?.unit
? `${t(
`scheduler.preview.unit.${schedule.dtstart.offset.unit}`
- )} ${
- schedule.dtstart.offset.value
- }, ${ZTimeStringToOffsetTimeString(schedule.dtstart.time)}`
+ )} ${schedule.dtstart.offset.value}, ${schedule.dtstart.time}`
: undefined;
case 'dtend':
return schedule.dtend.offset?.value && schedule.dtend.offset?.unit
? `${t(`scheduler.preview.unit.${schedule.dtend.offset.unit}`)} ${
schedule.dtend.offset.value
- }, ${ZTimeStringToOffsetTimeString(schedule.dtend.time)} `
+ }, ${schedule.dtend.time} `
: undefined;
default:
return undefined;
diff --git a/src/components/ParticipantList.vue b/src/components/ParticipantList.vue
index 71e42eaf..ebff2ce2 100644
--- a/src/components/ParticipantList.vue
+++ b/src/components/ParticipantList.vue
@@ -98,6 +98,14 @@ Licensed under the Elastic License 2.0. */
placeholder: t('global.placeholder.noGroup'),
columnWidth: '15vw',
},
+ {
+ field: 'start',
+ header: t('participants.props.individualStart'),
+ type: MoreTableFieldType.datetime,
+ sortable: true,
+ placeholder: '-',
+ columnWidth: '10vw',
+ },
];
const rowActions: MoreTableAction[] = [
diff --git a/src/components/shared/MoreTable.vue b/src/components/shared/MoreTable.vue
index bd4eac8b..25caf578 100644
--- a/src/components/shared/MoreTable.vue
+++ b/src/components/shared/MoreTable.vue
@@ -754,7 +754,8 @@ Licensed under the Elastic License 2.0. */
{{ dayjs(data['__internalValue_' + field]).format('DD/MM/YYYY') }}
-
+ -
+
{{ dayjs(data[field]).format('DD/MM/YYYY, HH:mm') }}
diff --git a/src/components/shared/RelativeScheduler.vue b/src/components/shared/RelativeScheduler.vue
index 7c4df5af..bf6ab58e 100644
--- a/src/components/shared/RelativeScheduler.vue
+++ b/src/components/shared/RelativeScheduler.vue
@@ -5,7 +5,6 @@
import InputNumber from 'primevue/inputnumber';
import Dropdown from 'primevue/dropdown';
import Checkbox from 'primevue/checkbox';
- import { ZTimeToOffsetTime } from '../../utils/dateUtils';
import {
RelativeEvent,
RelativeRecurrenceRule,
@@ -28,6 +27,7 @@
unit: schedule.dtstart?.offset?.unit,
},
time: schedule.dtstart?.time,
+ timezone: schedule.dtstart?.timezone,
},
dtend: {
offset: {
@@ -35,6 +35,7 @@
unit: schedule.dtend?.offset?.unit,
},
time: schedule.dtend?.time,
+ timezone: schedule.dtend?.timezone,
},
rrrule: {
frequency: {
@@ -56,7 +57,6 @@
parseInt(schedule.dtstart.time?.substring(0, 2)),
parseInt(schedule.dtstart.time?.substring(3, 5), 0)
);
- startTime.value = ZTimeToOffsetTime(startTime.value);
} else {
startTime.value.setHours(10, 30);
}
@@ -65,14 +65,13 @@
parseInt(schedule.dtend.time?.substring(0, 2)),
parseInt(schedule.dtend.time?.substring(3, 5), 0)
);
- endTime.value = ZTimeToOffsetTime(endTime.value);
} else {
endTime.value.setHours(18, 30);
}
returnSchedule.value.dtstart.time = returnSchedule.value.dtstart.time
? returnSchedule.value.dtstart.time
- : '10:10';
+ : '10:00';
returnSchedule.value.dtend.time = returnSchedule.value.dtend.time
? returnSchedule.value.dtend.time
: '18:00';
@@ -250,15 +249,24 @@
function save() {
returnSchedule.value.dtstart.time = startTime.value
- ?.toISOString()
- .substring(11, 16);
+ ?.toTimeString()
+ .substring(0, 5);
returnSchedule.value.dtend.time = endTime.value
- ?.toISOString()
- .substring(11, 16);
+ ?.toTimeString()
+ .substring(0, 5);
returnSchedule.value.dtstart.offset = rDtstartOffset.value;
returnSchedule.value.dtend.offset = rDtendOffset.value;
+ if (typeof returnSchedule.value.dtstart.time !== 'undefined') {
+ returnSchedule.value.dtstart.timezone =
+ Intl.DateTimeFormat().resolvedOptions().timeZone;
+ }
+ if (typeof returnSchedule.value.dtend.time !== 'undefined') {
+ returnSchedule.value.dtend.timezone =
+ Intl.DateTimeFormat().resolvedOptions().timeZone;
+ }
+
if (repeatChecked.value) {
const rrrule: RelativeRecurrenceRule = {
frequency: rFrequency.value,
@@ -317,6 +325,7 @@
:placeholder="
$t('scheduler.dialog.relativeSchedule.placeholder.dtstartOffset')
"
+ :min="1"
@blur="calculatedRepeat()"
/>
@@ -350,6 +359,7 @@
:placeholder="
$t('scheduler.dialog.relativeSchedule.placeholder.dtendOffset')
"
+ :min="1"
@blur="calculatedRepeat()"
/>
diff --git a/src/components/subComponents/SchedulerInfoBlock.vue b/src/components/subComponents/SchedulerInfoBlock.vue
index aebca34e..35a1e766 100644
--- a/src/components/subComponents/SchedulerInfoBlock.vue
+++ b/src/components/subComponents/SchedulerInfoBlock.vue
@@ -14,7 +14,6 @@ Licensed under the Elastic License 2.0. */
import Button from 'primevue/button';
import { useI18n } from 'vue-i18n';
import dayjs from 'dayjs';
- import { ZTimeStringToOffsetTimeString } from '../../utils/dateUtils';
const { t } = useI18n();
@@ -79,16 +78,14 @@ Licensed under the Elastic License 2.0. */
schedule.dtstart.offset?.unit
? `${t(
`scheduler.preview.unit.${schedule.dtstart.offset.unit}`
- )} ${
- schedule.dtstart.offset.value
- }, ${ZTimeStringToOffsetTimeString(schedule.dtstart.time)}`
+ )} ${schedule.dtstart.offset.value}, ${schedule.dtstart.time}`
: undefined;
}
case 'dtend':
return schedule.dtend.offset?.value && schedule.dtend.offset?.unit
? `${t(`scheduler.preview.unit.${schedule.dtend.offset.unit}`)} ${
schedule.dtend.offset.value
- }, ${ZTimeStringToOffsetTimeString(schedule.dtend.time)} `
+ }, ${schedule.dtend.time} `
: undefined;
default:
return undefined;
diff --git a/src/i18n/de.json b/src/i18n/de.json
index 528483d5..7f5693ce 100644
--- a/src/i18n/de.json
+++ b/src/i18n/de.json
@@ -325,7 +325,8 @@
"participantId": "Teilnehmer ID",
"alias": "Alias",
"token": "Token",
- "registrationToken": "Registrierungstoken"
+ "registrationToken": "Registrierungstoken",
+ "individualStart": "Gestartet am"
},
"dialog": {
"header": {
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 7fb26d9d..704c5f45 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -325,7 +325,8 @@
"participantId": "Participant ID",
"alias": "Alias",
"token": "Token",
- "registrationToken": "Registration token"
+ "registrationToken": "Registration token",
+ "individualStart": "Started on"
},
"dialog": {
"header": {