Skip to content

Commit

Permalink
feat(mon-pix): prevent live-alert trigger when the challenge is alrea…
Browse files Browse the repository at this point in the history
…dy answered

refactor(mon-pix): use PixButton for the challenge live-alert trigger
  • Loading branch information
Jeyffrey committed Mar 7, 2025
1 parent 3da3487 commit 6de09f4
Show file tree
Hide file tree
Showing 10 changed files with 236 additions and 98 deletions.
70 changes: 70 additions & 0 deletions mon-pix/app/components/challenge/content.gjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { fn } from '@ember/helper';
import { on } from '@ember/modifier';
import { action } from '@ember/object';
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { t } from 'ember-intl';
import { eq } from 'ember-truth-helpers';

import AssessmentsLiveAlert from '../assessments/live-alert';
import FeedbackPanel from '../feedback-panel';
import FeedbackPanelV3 from '../feedback-panel-v3';
import ChallengeItem from './item';

export default class ChallengeContent extends Component {
@tracked isLiveAlertButtonEnabled = true;

@action
handleChallengeSubmit() {
this.isLiveAlertButtonEnabled = false;
}

<template>
<div
class="focus-zone-warning
{{if @isFocusedChallengeAndUserHasFocusedOutOfChallenge 'focus-zone-warning--triggered'}}"
data-challenge-id="{{@challenge.id}}"
{{on "mouseenter" @hideOutOfFocusBorder}}
{{on "mouseleave" @showOutOfFocusBorder}}
>

<ChallengeItem
@challenge={{@challenge}}
@assessment={{@assessment}}
@answer={{@answer}}
@timeoutChallenge={{@timeoutChallenge}}
@resetAllChallengeInfo={{@resetAllChallengeInfo}}
@resetChallengeInfoOnResume={{@resetChallengeInfoOnResume}}
@onFocusIntoChallenge={{fn @setFocusedOutOfChallenge false}}
@onFocusOutOfChallenge={{fn @setFocusedOutOfChallenge true}}
@onFocusOutOfWindow={{@focusedOutOfWindow}}
@hasFocusedOutOfWindow={{@hasFocusedOutOfWindow}}
@isFocusedChallengeAndUserHasFocusedOutOfChallenge={{@isFocusedChallengeAndUserHasFocusedOutOfChallenge}}
@isTextToSpeechActivated={{@isTextToSpeechActivated}}
@onChallengeSubmit={{this.handleChallengeSubmit}}
/>

{{#unless @assessment.hasOngoingCompanionLiveAlert}}
<div class="challenge__feedback" role="complementary">
{{#if (eq @assessment.certificationCourse.version 3)}}
<FeedbackPanelV3
@submitLiveAlert={{@submitLiveAlert}}
@assessment={{@assessment}}
@isEnabled={{this.isLiveAlertButtonEnabled}}
/>
{{else}}
<FeedbackPanel @assessment={{@assessment}} @challenge={{@challenge}} />
{{/if}}
</div>
{{/unless}}

{{#if @assessment.hasOngoingCompanionLiveAlert}}
<AssessmentsLiveAlert @message={{t "pages.challenge.live-alerts.companion.message"}} />
{{/if}}
</div>

{{#if @isFocusedChallengeAndUserHasFocusedOutOfChallenge}}
<div class="focus-zone-warning__overlay" />
{{/if}}
</template>
}
2 changes: 2 additions & 0 deletions mon-pix/app/components/challenge/item.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ export default class Item extends Component {
return;
}

this.args.onChallengeSubmit();

const answer = await this._findOrCreateAnswer(challenge, assessment);
answer.setProperties({
value: answerValue.trim(),
Expand Down
22 changes: 12 additions & 10 deletions mon-pix/app/components/feedback-panel-v3.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,18 @@
{{else}}
<div class="feedback-panel-v3">
<h2 class="screen-reader-only">{{t "pages.challenge.parts.feedback-v3"}}</h2>
<button
class="feedback-panel-v3__open-button
{{if this.isToggleFeedbackFormHidden 'feedback-panel-v3__open-button--hidden'}}"
{{on "click" this.toggleFeedbackForm}}
aria-expanded={{this.isAriaExpanded}}
type="button"
>
<PixIcon @name="flag" @plainIcon={{true}} @ariaHidden={{true}} />
{{t "pages.challenge.feedback-panel-v3.actions.open-close"}}
</button>

{{#unless this.isToggleFeedbackFormHidden}}
<PixButton
@variant="tertiary"
@triggerAction={{this.toggleFeedbackForm}}
@isDisabled={{not @isEnabled}}
aria-expanded={{this.isAriaExpanded}}
@iconBefore="flag"
>
{{t "pages.challenge.feedback-panel-v3.actions.open-close"}}
</PixButton>
{{/unless}}

{{#if this.shouldBeExpanded}}
<div class="feedback-panel-v3__view">
Expand Down
2 changes: 1 addition & 1 deletion mon-pix/app/components/feedback-panel-v3.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default class FeedbackPanelV3 extends Component {
}

get shouldBeExpanded() {
return this.isAssessmentPaused || this.isExpanded;
return this.args.isEnabled && (this.isAssessmentPaused || this.isExpanded);
}

get isToggleFeedbackFormHidden() {
Expand Down
33 changes: 0 additions & 33 deletions mon-pix/app/styles/components/_feedback-panel-v3.scss
Original file line number Diff line number Diff line change
Expand Up @@ -30,39 +30,6 @@

/* "Link" view
–––––––––––––––––––––––––––––––––––––––––––––––––– */

.feedback-panel-v3__open-button {
display: flex;
gap: var(--pix-spacing-1x);
align-items: center;
width: 100%;
margin-top: var(--pix-spacing-4x);
padding: 0.75rem 0;
line-height: 20px;
text-align: left;
text-decoration: underline;

svg {
width: 1rem;
height: 1rem;
}

&[aria-expanded='true'] {
color: var(--pix-neutral-900);
}

&--hidden {
padding: 0;
visibility: hidden;
}

&:hover,
&:focus-visible,
&:active {
color: var(--pix-primary-500);
}
}

.feedback-panel-v3__view {
display: flex;
gap: 24px;
Expand Down
57 changes: 16 additions & 41 deletions mon-pix/app/templates/assessments/challenge.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -60,47 +60,22 @@
{{/if}}

{{#if this.displayChallenge}}
<div
class="focus-zone-warning
{{if this.isFocusedChallengeAndUserHasFocusedOutOfChallenge 'focus-zone-warning--triggered'}}"
data-challenge-id="{{@challenge.id}}"
{{on "mouseenter" this.hideOutOfFocusBorder}}
{{on "mouseleave" this.showOutOfFocusBorder}}
>

<Challenge::Item
@challenge={{@model.challenge}}
@assessment={{@model.assessment}}
@answer={{@model.answer}}
@timeoutChallenge={{this.timeoutChallenge}}
@resetAllChallengeInfo={{this.resetAllChallengeInfo}}
@resetChallengeInfoOnResume={{this.resetChallengeInfoOnResume}}
@onFocusIntoChallenge={{fn this.setFocusedOutOfChallenge false}}
@onFocusOutOfChallenge={{fn this.setFocusedOutOfChallenge true}}
@onFocusOutOfWindow={{this.focusedOutOfWindow}}
@hasFocusedOutOfWindow={{this.hasFocusedOutOfWindow}}
@isFocusedChallengeAndUserHasFocusedOutOfChallenge={{this.isFocusedChallengeAndUserHasFocusedOutOfChallenge}}
@isTextToSpeechActivated={{this.isTextToSpeechActivated}}
/>

{{#unless @model.assessment.hasOngoingCompanionLiveAlert}}
<div class="challenge__feedback" role="complementary">
{{#if (eq @model.assessment.certificationCourse.version 3)}}
<FeedbackPanelV3 @submitLiveAlert={{this.submitLiveAlert}} @assessment={{@model.assessment}} />
{{else}}
<FeedbackPanel @assessment={{@model.assessment}} @challenge={{@model.challenge}} />
{{/if}}
</div>
{{/unless}}

{{#if @model.assessment.hasOngoingCompanionLiveAlert}}
<Assessments::LiveAlert @message={{t "pages.challenge.live-alerts.companion.message"}} />
{{/if}}
</div>

{{#if this.isFocusedChallengeAndUserHasFocusedOutOfChallenge}}
<div class="focus-zone-warning__overlay" />
{{/if}}
<Challenge::Content
@answer={{@model.answer}}
@assessment={{@model.assessment}}
@challenge={{@model.challenge}}
@focusedOutOfWindow={{this.focusedOutOfWindow}}
@hasFocusedOutOfWindow={{this.hasFocusedOutOfWindow}}
@hideOutOfFocusBorder={{this.hideOutOfFocusBorder}}
@isFocusedChallengeAndUserHasFocusedOutOfChallenge={{this.isFocusedChallengeAndUserHasFocusedOutOfChallenge}}
@isTextToSpeechActivated={{this.isTextToSpeechActivated}}
@resetAllChallengeInfo={{this.resetAllChallengeInfo}}
@resetChallengeInfoOnResume={{this.resetChallengeInfoOnResume}}
@setFocusedOutOfChallenge={{this.setFocusedOutOfChallenge}}
@showOutOfFocusBorder={{this.showOutOfFocusBorder}}
@submitLiveAlert={{this.submitLiveAlert}}
@timeoutChallenge={{this.timeoutChallenge}}
/>
{{/if}}
</main>

Expand Down
Empty file.
87 changes: 87 additions & 0 deletions mon-pix/tests/integration/components/challenge/content-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { render } from '@1024pix/ember-testing-library';
import { click, fillIn } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
import { module, test } from 'qunit';
import sinon from 'sinon';

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

module('Integration | Component | Challenge | Content', function (hooks) {
setupIntlRenderingTest(hooks);

let screen;

hooks.before(function () {
sinon.stub(window, 'fetch');
});

hooks.beforeEach(async function () {
// given
const router = this.owner.lookup('service:router');
router.transitionTo = sinon.stub();

const store = this.owner.lookup('service:store');
this.set(
'challenge',
store.createRecord('challenge', {
type: 'QROC',
timer: false,
format: 'phrase',
proposals: '${myInput}',
}),
);
this.set('answer', null);
this.set(
'assessment',
store.createRecord('assessment', {
certificationCourse: store.createRecord('certification-course', {
version: 3,
}),
answers: [],
}),
);
this.set('fakeFunction', () => {});

// when
screen = await render(
hbs`<Challenge::Content
@challenge={{this.challenge}}
@answer={{this.answer}}
@assessment={{this.assessment}}
@hideOutOfFocusBorder={{this.fakeFunction}}
@showOutOfFocusBorder={{this.fakeFunction}}
@resetAllChallengeInfo={{this.fakeFunction}}
/>`,
);
});

module('on challenge skip', function () {
test('should disable the live alert button', async function (assert) {
// then
await click(screen.getByRole('button', { name: /Signaler un problème avec la question/ }));
assert.dom(screen.getByRole('button', { name: /Oui, je suis/ })).exists();

await click(screen.getByRole('button', { name: /Je passe/ }));
assert
.dom(screen.getByRole('button', { name: /Signaler un problème avec la question/ }))
.hasAttribute('disabled');
assert.dom(screen.queryByRole('button', { name: /Oui, je suis/ })).doesNotExist();
});
});

module('on challenge answering', function () {
test('should disable the live alert button', async function (assert) {
// then
await click(screen.getByRole('button', { name: /Signaler un problème avec la question/ }));
assert.dom(screen.getByRole('button', { name: /Oui, je suis/ })).exists();

await fillIn(screen.getByRole('textbox'), 'answer');
await click(screen.getByRole('button', { name: /Je valide/ }));

assert
.dom(screen.getByRole('button', { name: /Signaler un problème avec la question/ }))
.hasAttribute('disabled');
assert.dom(screen.queryByRole('button', { name: /Oui, je suis/ })).doesNotExist();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ module('Integration | Component | feedback-panel-v3', function (hooks) {
this.set('assessment', mockAssessment);
this.set('submitLiveAlert', submitLiveAlert);
const screen = await render(
hbs`<FeedbackPanelV3 @submitLiveAlert={{this.submitLiveAlert}} @assessment={{this.assessment}} />`,
hbs`<FeedbackPanelV3 @submitLiveAlert={{this.submitLiveAlert}} @assessment={{this.assessment}} @isEnabled={{true}} />`,
);

// when
Expand Down
Loading

0 comments on commit 6de09f4

Please sign in to comment.