Skip to content

Commit 8189bc7

Browse files
committed
Merge branch 'master' into develop
2 parents b6ff2b1 + 8929349 commit 8189bc7

File tree

13 files changed

+83
-39
lines changed

13 files changed

+83
-39
lines changed

src/features/dashboard/components/NextSession.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ const goto = (url) => {
168168
router.push(url)
169169
}
170170
171+
//TODO: Remove debug logs
171172
watch(closestSession, (val) => {
172173
console.log("Closest future session chosen:", val)
173174
}, { immediate: true })

src/features/ux_creation/ChooseStudyMethods.vue

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,19 @@ const methodsByCategory = {
6161
description: 'Real-time sessions with facilitator guidance and immediate feedback',
6262
icon: 'mdi-account-voice',
6363
color: 'success',
64-
available: true
64+
available: false,
65+
comingSoon: true
66+
6567
},
6668
{
6769
id: METHOD_DEFINITIONS.CARD_SORTING.id,
6870
name: 'Card Sorting (Unmoderated)',
6971
description: 'Participants organize cards independently, without the presence of a moderator, allowing data to be collected on how they group and categorize information according to their own logic.',
7072
icon: 'mdi-card-multiple',
7173
color: 'error',
72-
available: true
74+
available: false,
75+
comingSoon: true
76+
7377
},
7478
{
7579
id: 'ab-testing',

src/shared/utils/managerDefault.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ export const getNavigatorDefault = (test, accessLevel, route, type) => {
2222
if (accessLevel === ACCESS_LEVEL.GUEST) {
2323
items.push(
2424
{ title: 'Answer Test', icon: ICONS.DOCUMENT, path: `/testview/${test.id}` },
25-
{ title: 'Reports', icon: ICONS.BOOK, path: `/${type}/report/${test.id}` },
2625
{ title: 'Answers', icon: ICONS.ORDER, path: `/${type}/answer/${test.id}` }
2726
)
2827
}

src/ux/UserTest/components/AudioRecorder.vue

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ const recordedChunks = ref([])
8181
const mediaRecorder = ref(null)
8282
const audioStream = ref(null)
8383
const recordedAudio = ref('')
84+
const recordingTaskIndex = ref(null) // Store the task index when recording starts
8485
8586
// Computed properties
8687
const currentUserTestAnswer = computed(() => store.getters.currentUserTestAnswer)
@@ -101,6 +102,7 @@ const startAudioRecording = async () => {
101102
const audioAvailable = await hasAudio();
102103
if (!audioAvailable) return;
103104
105+
recordingTaskIndex.value = props.taskIndex; // Store the current task index when recording starts
104106
recordingAudio.value = true
105107
emit('recordingStarted', true)
106108
@@ -127,16 +129,17 @@ const startAudioRecording = async () => {
127129
emit('showLoading')
128130
const audioBlob = new Blob(recordedChunks.value.local, { type: 'audio/webm' })
129131
const storage = getStorage()
132+
const correctTaskIndex = recordingTaskIndex.value;
130133
const storageReference = storageRef(
131134
storage,
132-
`tests/${props.testId}/${currentUserTestAnswer.value.userDocId}/task_${props.taskIndex}_evaluator/${Date.now()}.webm`
135+
`tests/${props.testId}/${currentUserTestAnswer.value.userDocId}/task_${correctTaskIndex}_evaluator/${Date.now()}.webm`
133136
)
134137
await uploadBytes(storageReference, audioBlob)
135138
136139
recordedAudio.value = await getDownloadURL(storageReference)
137140
138141
await store.dispatch('updateTaskMediaUrl', {
139-
taskIndex: props.taskIndex,
142+
taskIndex: correctTaskIndex,
140143
mediaType: MEDIA_FIELD_MAP.audio,
141144
url: recordedAudio.value
142145
});
@@ -166,16 +169,17 @@ const startAudioRecording = async () => {
166169
mediaRecorder.value.remote.onstop = async () => {
167170
const blob = new Blob(recordedChunks.value.remote, { type: 'audio/webm' })
168171
const storage = getStorage()
172+
const correctTaskIndex = recordingTaskIndex.value;
169173
const storageReference = storageRef(
170174
storage,
171-
`tests/${props.testId}/${currentUserTestAnswer.value.userDocId}/task_${props.taskIndex}_moderator/${Date.now()}.webm`
175+
`tests/${props.testId}/${currentUserTestAnswer.value.userDocId}/task_${correctTaskIndex}_moderator/${Date.now()}.webm`
172176
)
173177
await uploadBytes(storageReference, blob)
174178
const downloadURL = await getDownloadURL(storageReference)
175179
176180
console.log('moderator audio =>', downloadURL)
177181
await store.dispatch('updateTaskMediaUrl', {
178-
taskIndex: props.taskIndex,
182+
taskIndex: correctTaskIndex,
179183
mediaType: MEDIA_FIELD_MAP.moderator,
180184
url: downloadURL
181185
});

src/ux/UserTest/components/ScreenRecorder.vue

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,12 @@ const videoUrl = ref('');
6969
const videoStream = ref(null);
7070
const mediaRecorder = ref(null);
7171
const chunks = ref([]);
72+
const recordingTaskIndex = ref(null); // Store the task index when recording starts
7273
7374
const captureScreen = async () => {
7475
try {
76+
recordingTaskIndex.value = props.taskIndex; // Store the current task index when recording starts
77+
console.log('ScreenRecorder: Recording started for task index:', props.taskIndex);
7578
videoStream.value = await navigator.mediaDevices.getDisplayMedia({
7679
cursor: true,
7780
});
@@ -96,18 +99,30 @@ const recordScreen = async () => {
9699
emit('showLoading');
97100
const videoBlob = new Blob(chunks.value, { type: 'video/webm' });
98101
const storage = getStorage();
99-
const storagePath = `tests/${props.testId}/${currentUserTestAnswer.value.userDocId}/task_${props.taskIndex}/screen_record/${videoUrl.value}`;
102+
const storagePath = `tests/${props.testId}/${currentUserTestAnswer.value.userDocId}/task_${recordingTaskIndex.value}/screen_record/${videoUrl.value}`;
100103
const storageReference = storageRef(storage, storagePath);
101104
102105
await uploadBytes(storageReference, videoBlob);
103106
videoUrl.value = await getDownloadURL(storageReference);
104107
108+
// Use the task index from when recording started, not the current one
109+
const correctTaskIndex = recordingTaskIndex.value;
110+
console.log('screen record =>', correctTaskIndex, videoUrl.value);
111+
console.log('Tasks array:', currentUserTestAnswer.value.tasks);
112+
console.log('Tasks length:', currentUserTestAnswer.value.tasks?.length);
113+
105114
await store.dispatch('updateTaskMediaUrl', {
106-
taskIndex: props.taskIndex,
115+
taskIndex: correctTaskIndex,
107116
mediaType: MEDIA_FIELD_MAP.screen,
108117
url: videoUrl.value
109118
});
110-
currentUserTestAnswer.value.tasks[props.taskIndex].screenRecordURL = videoUrl.value;
119+
120+
// Add safety check before setting the property
121+
if (currentUserTestAnswer.value.tasks && currentUserTestAnswer.value.tasks[correctTaskIndex]) {
122+
currentUserTestAnswer.value.tasks[correctTaskIndex].screenRecordURL = videoUrl.value;
123+
} else {
124+
console.error('Task not found at index:', correctTaskIndex, 'Available tasks:', currentUserTestAnswer.value.tasks?.length);
125+
}
111126
112127
// Stop all tracks
113128
videoStream.value.getTracks().forEach((track) => track.stop());

src/ux/UserTest/components/VideoRecorder.vue

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ const videoStream = ref(null)
7373
const recordedChunks = ref([])
7474
const mediaRecorder = ref(null)
7575
const recordedVideo = ref('')
76+
const recordingTaskIndex = ref(null) // Store the task index when recording starts
7677
7778
async function hasCamera() {
7879
try {
@@ -90,6 +91,8 @@ const startRecording = async () => {
9091
if (!cameraAvailable) return;
9192
9293
recording.value = true
94+
recordingTaskIndex.value = props.taskIndex // Store the current task index when recording starts
95+
console.log('VideoRecorder: Recording started for task index:', props.taskIndex);
9396
videoStream.value = await navigator.mediaDevices.getUserMedia({
9497
video: true,
9598
})
@@ -115,21 +118,31 @@ const startRecording = async () => {
115118
type: 'video/webm',
116119
})
117120
const storage = getStorage()
121+
const correctTaskIndex = recordingTaskIndex.value;
118122
const storageReference = storageRef(
119123
storage,
120-
`tests/${props.testId}/${currentUserTestAnswer.value.userDocId}/task_${props.taskIndex}/video/${recordedVideo.value}`,
124+
`tests/${props.testId}/${currentUserTestAnswer.value.userDocId}/task_${correctTaskIndex}/video/${recordedVideo.value}`,
121125
)
122126
await uploadBytes(storageReference, videoBlob)
123127
124128
recordedVideo.value = await getDownloadURL(storageReference)
125-
129+
console.log('webcam url =>', correctTaskIndex, recordedVideo.value);
130+
console.log('Tasks array:', currentUserTestAnswer.value.tasks);
131+
console.log('Tasks length:', currentUserTestAnswer.value.tasks?.length);
132+
console.log('Task at index:', currentUserTestAnswer.value.tasks?.[correctTaskIndex]);
133+
126134
await store.dispatch('updateTaskMediaUrl', {
127-
taskIndex: props.taskIndex,
135+
taskIndex: correctTaskIndex,
128136
mediaType: MEDIA_FIELD_MAP.webcam,
129137
url: recordedVideo.value
130138
});
131139
132-
currentUserTestAnswer.value.tasks[props.taskIndex].webcamRecordURL = recordedVideo.value
140+
// Add safety check before setting the property
141+
if (currentUserTestAnswer.value.tasks && currentUserTestAnswer.value.tasks[correctTaskIndex]) {
142+
currentUserTestAnswer.value.tasks[correctTaskIndex].webcamRecordURL = recordedVideo.value;
143+
} else {
144+
console.error('Task not found at index:', correctTaskIndex, 'Available tasks:', currentUserTestAnswer.value.tasks?.length);
145+
}
133146
134147
videoStream.value.getTracks().forEach((track) => track.stop())
135148
recording.value = false

src/ux/UserTest/components/steps/TaskStep.vue

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@
355355
</div>
356356

357357
<AudioRecorder
358+
v-if="task?.hasAudioRecord"
358359
ref="audioRecorder"
359360
:test-id="testId"
360361
:task-index="taskIndex"
@@ -366,6 +367,7 @@
366367
/>
367368

368369
<ScreenRecorder
370+
v-if="task?.hasScreenRecord"
369371
ref="screenRecorder"
370372
:test-id="testId"
371373
:task-index="taskIndex"
@@ -374,6 +376,7 @@
374376
/>
375377

376378
<VideoRecorder
379+
v-if="task?.hasCamRecord"
377380
ref="videoRecorder"
378381
:test-id="testId"
379382
:task-index="taskIndex"
@@ -511,15 +514,27 @@ function reopenTool() {
511514
const showPostForm = ref({ userCompleted: undefined });
512515
513516
function stopMediaRecorders() {
514-
audioRecorder.value?.stopAudioRecording();
515-
videoRecorder.value?.stopRecording();
516-
screenRecorder.value?.stopRecording();
517+
if (props.task?.hasAudioRecord && audioRecorder.value) {
518+
audioRecorder.value.stopAudioRecording();
519+
}
520+
if (props.task?.hasCamRecord && videoRecorder.value) {
521+
videoRecorder.value.stopRecording();
522+
}
523+
if (props.task?.hasScreenRecord && screenRecorder.value) {
524+
screenRecorder.value.stopRecording();
525+
}
517526
}
518527
519528
async function startMediaRecorders() {
520-
if (props.task?.hasAudioRecord) await audioRecorder.value?.startAudioRecording();
521-
if (props.task?.hasCamRecord) await videoRecorder.value?.startRecording();
522-
if (props.task?.hasScreenRecord) await screenRecorder.value?.captureScreen();
529+
if (props.task?.hasAudioRecord && audioRecorder.value) {
530+
await audioRecorder.value.startAudioRecording();
531+
}
532+
if (props.task?.hasCamRecord && videoRecorder.value) {
533+
await videoRecorder.value.startRecording();
534+
}
535+
if (props.task?.hasScreenRecord && screenRecorder.value) {
536+
await screenRecorder.value.captureScreen();
537+
}
523538
}
524539
525540
function handleShowPostForm(userCompleted) {

src/ux/UserTest/components/steps/WelcomeStep.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
<h2 class="text-h5 font-weight-bold mb-4 text-primary">
66
{{ $t('UserTestView.WelcomeStep.welcome') }}
77
</h2>
8-
<p class="text-body-1 mb-4 text-grey-darken-3">
8+
<div v-if="welcomeMessage" v-html="welcomeMessage" class="text-body-1 mb-4 text-grey-darken-3"></div>
9+
<p v-else class="text-body-1 mb-4 text-grey-darken-3">
910
{{ $t('UserTestView.WelcomeStep.description') }}
1011
</p>
1112
<h2 class="text-h5 font-weight-bold mb-4 text-primary">
@@ -85,6 +86,7 @@ import { VStepperVertical } from 'vuetify/labs/VStepperVertical';
8586
import { useDisplay } from 'vuetify';
8687
const props = defineProps({
8788
stepperValue: { type: Number, required: true },
89+
welcomeMessage: { type: String, default: '' },
8890
});
8991
const emit = defineEmits(['start']);
9092
const { smAndDown } = useDisplay();

src/ux/UserTest/router.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export default [
1919
path: '/userTest/unmoderated/report/:id/:token?',
2020
name: 'UserUnmoderatedReportView',
2121
props: true,
22-
meta: { authorize: [0, 1] },
22+
meta: { authorize: [0] },
2323
component: ReportView,
2424
},
2525
{

src/ux/UserTest/views/ModeratedTestView.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
<WelcomeStep
106106
v-else-if="globalIndex === 0 && !isUserTestAdmin"
107107
:stepper-value="stepperValue"
108+
:welcome-message="test?.testStructure?.welcomeMessage"
108109
@start="displayVideoCallComponent = true; globalIndex = 1"
109110
/>
110111

0 commit comments

Comments
 (0)