Skip to content

Commit 5c1782c

Browse files
[FEATURE] Enregistrer l'auto-évaluation de l'utilisateur dans Matomo (PIX-14313)
#10354
2 parents 030b9e7 + 54a11bd commit 5c1782c

File tree

6 files changed

+118
-16
lines changed

6 files changed

+118
-16
lines changed

mon-pix/app/components/module/element.gjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export default class ModulixElement extends Component {
3232
{{else if (eq @element.type "separator")}}
3333
<SeparatorElement />
3434
{{else if (eq @element.type "flashcards")}}
35-
<FlashcardsElement @flashcards={{@element}} />
35+
<FlashcardsElement @flashcards={{@element}} @onSelfAssessment={{@onSelfAssessment}} />
3636
{{else if (eq @element.type "qcu")}}
3737
<QcuElement
3838
@element={{@element}}

mon-pix/app/components/module/element/flashcards/flashcards.gjs

+14-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { fn } from '@ember/helper';
12
import { on } from '@ember/modifier';
23
import { action } from '@ember/object';
34
import Component from '@glimmer/component';
@@ -55,12 +56,21 @@ export default class ModulixFlashcards extends Component {
5556
this.displayedSideName = this.displayedSideName === 'recto' ? 'verso' : 'recto';
5657
}
5758

58-
@action
5959
goToNextCard() {
6060
this.currentCardIndex++;
6161
this.displayedSideName = 'recto';
6262
}
6363

64+
@action
65+
onSelfAssessment(userAssessment) {
66+
const selfAssessmentData = {
67+
userAssessment,
68+
cardId: this.currentCard.id,
69+
};
70+
this.args.onSelfAssessment(selfAssessmentData);
71+
this.goToNextCard();
72+
}
73+
6474
<template>
6575
<div class="element-flashcards">
6676

@@ -96,21 +106,21 @@ export default class ModulixFlashcards extends Component {
96106
<button
97107
class="element-flashcards__footer__answer__button element-flashcards__footer__answer__button--no"
98108
type="button"
99-
{{on "click" this.goToNextCard}}
109+
{{on "click" (fn this.onSelfAssessment "no")}}
100110
>
101111
{{t "pages.modulix.buttons.flashcards.answers.notAtAll"}}
102112
</button>
103113
<button
104114
class="element-flashcards__footer__answer__button element-flashcards__footer__answer__button--almost"
105115
type="button"
106-
{{on "click" this.goToNextCard}}
116+
{{on "click" (fn this.onSelfAssessment "almost")}}
107117
>
108118
{{t "pages.modulix.buttons.flashcards.answers.almost"}}
109119
</button>
110120
<button
111121
class="element-flashcards__footer__answer__button element-flashcards__footer__answer__button--yes"
112122
type="button"
113-
{{on "click" this.goToNextCard}}
123+
{{on "click" (fn this.onSelfAssessment "yes")}}
114124
>
115125
{{t "pages.modulix.buttons.flashcards.answers.yes"}}
116126
</button>

mon-pix/app/components/module/grain.gjs

+1
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ export default class ModuleGrain extends Component {
187187
@onVideoTranscriptionOpen={{@onVideoTranscriptionOpen}}
188188
@onElementAnswer={{@onElementAnswer}}
189189
@onElementRetry={{@onElementRetry}}
190+
@onSelfAssessment={{@onSelfAssessment}}
190191
@onVideoPlay={{@onVideoPlay}}
191192
@getLastCorrectionForElement={{this.getLastCorrectionForElement}}
192193
@onFileDownload={{@onFileDownload}}

mon-pix/app/components/module/passage.gjs

+11
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,16 @@ export default class ModulePassage extends Component {
131131
});
132132
}
133133

134+
@action
135+
async onSelfAssessment({ userAssessment, cardId }) {
136+
this.metrics.add({
137+
event: 'custom-event',
138+
'pix-event-category': 'Modulix',
139+
'pix-event-action': `Passage du module : ${this.args.module.id}`,
140+
'pix-event-name': `Click sur le bouton '${userAssessment}' de la flashcard : ${cardId}`,
141+
});
142+
}
143+
134144
@action
135145
async onElementRetry(answerData) {
136146
this.metrics.add({
@@ -204,6 +214,7 @@ export default class ModulePassage extends Component {
204214
@onImageAlternativeTextOpen={{this.onImageAlternativeTextOpen}}
205215
@onVideoTranscriptionOpen={{this.onVideoTranscriptionOpen}}
206216
@onElementAnswer={{this.onElementAnswer}}
217+
@onSelfAssessment={{this.onSelfAssessment}}
207218
@onStepperNextStep={{this.onStepperNextStep}}
208219
@canMoveToNextGrain={{this.grainCanMoveToNextGrain index}}
209220
@onGrainContinue={{this.onGrainContinue}}

mon-pix/tests/integration/components/module/flashcards_test.gjs

+11-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { t } from 'ember-intl/test-support';
33
import ModulixFlashcards from 'mon-pix/components/module/element/flashcards/flashcards';
44
// eslint-disable-next-line no-restricted-imports
55
import { module, test } from 'qunit';
6+
import sinon from 'sinon';
67

78
import setupIntlRenderingTest from '../../../helpers/setup-intl-rendering';
89

@@ -173,8 +174,8 @@ module('Integration | Component | Module | Flashcards', function (hooks) {
173174
assert.ok(screen.getByText(t('pages.modulix.buttons.flashcards.answers.notAtAll')));
174175
});
175176

176-
module('then user gives an answer', function () {
177-
test('should display the next card', async function (assert) {
177+
module('when the user self-assesses their response', function () {
178+
test('should display the next card and send self-assessment', async function (assert) {
178179
// given
179180
const firstCard = {
180181
id: 'e1de6394-ff88-4de3-8834-a40057a50ff4',
@@ -214,15 +215,22 @@ module('Integration | Component | Module | Flashcards', function (hooks) {
214215
cards: [firstCard, secondCard],
215216
};
216217

218+
const onSelfAssessmentStub = sinon.stub();
219+
217220
// when
218-
const screen = await render(<template><ModulixFlashcards @flashcards={{flashcards}} /></template>);
221+
const screen = await render(
222+
<template>
223+
<ModulixFlashcards @flashcards={{flashcards}} @onSelfAssessment={{onSelfAssessmentStub}} />
224+
</template>,
225+
);
219226
await clickByName(t('pages.modulix.buttons.flashcards.start'));
220227
await clickByName(t('pages.modulix.buttons.flashcards.seeAnswer'));
221228
await clickByName(t('pages.modulix.buttons.flashcards.answers.notAtAll'));
222229

223230
// then
224231
assert.ok(screen.getByText('Qui a écrit le Dormeur du Val ?'));
225232
assert.ok(screen.getByText(t('pages.modulix.flashcards.position', { currentCardPosition: 2, totalCards: 2 })));
233+
assert.true(onSelfAssessmentStub.calledOnce);
226234
});
227235
});
228236
});

mon-pix/tests/integration/components/module/passage_test.gjs

+80-8
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ module('Integration | Component | Module | Passage', function (hooks) {
4949
assert.dom(screen.queryByRole('button', { name: 'Continuer' })).doesNotExist();
5050
});
5151

52-
module('When a grain contains non existing elements', function () {
52+
module('when a grain contains non existing elements', function () {
5353
test('should not display the grain if it contains only non existing elements', async function (assert) {
5454
// given
5555
const store = this.owner.lookup('service:store');
@@ -160,7 +160,7 @@ module('Integration | Component | Module | Passage', function (hooks) {
160160
assert.dom(screen.queryByRole('button', { name: 'Continuer' })).exists({ count: 1 });
161161
});
162162

163-
module('when user click on skip button', function () {
163+
module('when user clicks on skip button', function () {
164164
test('should display next grain', async function (assert) {
165165
// given
166166
const store = this.owner.lookup('service:store');
@@ -223,7 +223,7 @@ module('Integration | Component | Module | Passage', function (hooks) {
223223
});
224224
});
225225

226-
module('when user click on continue button', function (hooks) {
226+
module('when user clicks on continue button', function (hooks) {
227227
let continueButtonName;
228228
hooks.beforeEach(function () {
229229
continueButtonName = t('pages.modulix.buttons.grain.continue');
@@ -321,7 +321,7 @@ module('Integration | Component | Module | Passage', function (hooks) {
321321
});
322322
});
323323

324-
module('when user click on an answerable element verify button', function () {
324+
module('when user clicks on an answerable element verify button', function () {
325325
test('should save the element answer', async function (assert) {
326326
// given
327327
const metrics = this.owner.lookup('service:metrics');
@@ -401,7 +401,7 @@ module('Integration | Component | Module | Passage', function (hooks) {
401401
});
402402
});
403403

404-
module('when user click on an answerable element retry button', function () {
404+
module('when user clicks on an answerable element retry button', function () {
405405
test('should push metrics event', async function (assert) {
406406
// given
407407
const metrics = this.owner.lookup('service:metrics');
@@ -432,6 +432,78 @@ module('Integration | Component | Module | Passage', function (hooks) {
432432
});
433433
});
434434

435+
module('when user clicks on a flashcards element self-assessment button', function () {
436+
test('should push metrics event', async function (assert) {
437+
// given
438+
const metrics = this.owner.lookup('service:metrics');
439+
metrics.add = sinon.stub();
440+
441+
const store = this.owner.lookup('service:store');
442+
const firstCard = {
443+
id: 'e1de6394-ff88-4de3-8834-a40057a50ff4',
444+
recto: {
445+
image: {
446+
url: 'https://images.pix.fr/modulix/bien-ecrire-son-adresse-mail-explication-les-parties-dune-adresse-mail.svg',
447+
},
448+
text: "A quoi sert l'arobase dans mon adresse email ?",
449+
},
450+
verso: {
451+
image: { url: 'https://images.pix.fr/modulix/didacticiel/ordi-spatial.svg' },
452+
text: "Parce que c'est joli",
453+
},
454+
};
455+
const secondCard = {
456+
id: 'e1de6394-ff88-4de3-8834-a40057a50ff4',
457+
recto: {
458+
image: {
459+
url: 'https://images.pix.fr/modulix/didacticiel/icon.svg',
460+
},
461+
text: 'Qui a écrit le Dormeur du Val ?',
462+
},
463+
verso: {
464+
image: {
465+
url: 'https://images.pix.fr/modulix/didacticiel/chaton.jpg',
466+
},
467+
text: '<p>Arthur Rimbaud</p>',
468+
},
469+
};
470+
471+
const flashcardsElement = {
472+
id: '71de6394-ff88-4de3-8834-a40057a50ff4',
473+
type: 'flashcards',
474+
title: "Introduction à l'adresse e-mail",
475+
instruction: '<p>...</p>',
476+
introImage: { url: 'https://images.pix.fr/modulix/placeholder-details.svg' },
477+
cards: [firstCard, secondCard],
478+
};
479+
480+
const grain1 = store.createRecord('grain', { components: [{ type: 'element', element: flashcardsElement }] });
481+
482+
const module = store.createRecord('module', { id: 'module-id', title: 'Module title', grains: [grain1] });
483+
const passage = store.createRecord('passage');
484+
485+
const createRecordMock = sinon.mock();
486+
createRecordMock.returns({ save: function () {} });
487+
store.createRecord = createRecordMock;
488+
489+
await render(<template><ModulePassage @module={{module}} @passage={{passage}} /></template>);
490+
491+
// when
492+
await clickByName(t('pages.modulix.buttons.flashcards.start'));
493+
await clickByName(t('pages.modulix.buttons.flashcards.seeAnswer'));
494+
await clickByName(t('pages.modulix.buttons.flashcards.answers.notAtAll'));
495+
496+
// then
497+
sinon.assert.calledOnceWithExactly(metrics.add, {
498+
event: 'custom-event',
499+
'pix-event-category': 'Modulix',
500+
'pix-event-action': `Passage du module : ${module.id}`,
501+
'pix-event-name': `Click sur le bouton 'no' de la flashcard : ${firstCard.id}`,
502+
});
503+
assert.ok(true);
504+
});
505+
});
506+
435507
module('when user opens an image alternative text modal', function () {
436508
test('should push metrics event', async function (assert) {
437509
// given
@@ -504,7 +576,7 @@ module('Integration | Component | Module | Passage', function (hooks) {
504576
});
505577
});
506578

507-
module('when user opens an video transcription modal', function () {
579+
module('when user opens a video transcription modal', function () {
508580
test('should push metrics event', async function (assert) {
509581
// given
510582
const metrics = this.owner.lookup('service:metrics');
@@ -578,7 +650,7 @@ module('Integration | Component | Module | Passage', function (hooks) {
578650
});
579651
});
580652

581-
module('when user click on next step button', function () {
653+
module('when user clicks on next step button', function () {
582654
test('should push event', async function (assert) {
583655
// given
584656
const store = this.owner.lookup('service:store');
@@ -903,7 +975,7 @@ module('Integration | Component | Module | Passage', function (hooks) {
903975
});
904976
});
905977

906-
module('When click on terminate button', function () {
978+
module('when user clicks on terminate button', function () {
907979
test('should push an event', async function (assert) {
908980
// given
909981
class PassageAdapterStub extends ApplicationAdapter {

0 commit comments

Comments
 (0)