Skip to content

Commit 849d5bc

Browse files
dianeCdrPixyannbertrandclemlatzer-lim
committed
feat(mon-pix): add evaluation-sent-results modal
Co-authored-by: Yann Bertrand <[email protected]> Co-authored-by: Clément Latzarus <[email protected]> Co-authored-by: Eric Lim <[email protected]>
1 parent b0a0411 commit 849d5bc

File tree

5 files changed

+264
-0
lines changed

5 files changed

+264
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import onEscapeAction from '@1024pix/pix-ui/app/modifiers/on-escape-action';
2+
import trapFocus from '@1024pix/pix-ui/app/modifiers/trap-focus';
3+
import PixButton from '@1024pix/pix-ui/components/pix-button';
4+
import { t } from 'ember-intl';
5+
6+
import TrainingCard from '../../../training/card';
7+
8+
<template>
9+
<div
10+
class="evaluation-sent-results-modal__overlay
11+
{{unless @showModal ' evaluation-sent-results-modal__overlay--hidden'}}"
12+
{{trapFocus @showModal}}
13+
{{onEscapeAction @onCloseButtonClick}}
14+
>
15+
<div
16+
class="evaluation-sent-results-modal"
17+
role="dialog"
18+
aria-labelledby="evaluation-sent-results-modal-title"
19+
aria-describedby="evaluation-sent-results-modal-trainings"
20+
aria-modal="true"
21+
...attributes
22+
>
23+
<div class="evaluation-sent-results-modal__header">
24+
<PixButton @variant="tertiary" @iconAfter="close" @triggerAction={{@onCloseButtonClick}} @size="small">
25+
{{t "common.actions.close"}}
26+
</PixButton>
27+
</div>
28+
<img
29+
src="/images/strike.svg"
30+
role="presentation"
31+
alt=""
32+
width="174"
33+
height="137"
34+
class="evaluation-sent-results-modal__illustration"
35+
/>
36+
<h1 id="evaluation-sent-results-modal-title" class="evaluation-sent-results-modal__title">
37+
{{t "pages.skill-review.tabs.trainings.sent-results-modal.title"}}
38+
</h1>
39+
<p class="evaluation-sent-results-modal__subtitle">
40+
{{t "pages.skill-review.tabs.trainings.sent-results-modal.subtitle"}}
41+
</p>
42+
<ul id="evaluation-sent-results-modal-trainings" class="evaluation-sent-results-modal__trainings">
43+
{{#each @trainings as |training|}}
44+
<li>
45+
<TrainingCard @training={{training}} />
46+
</li>
47+
{{/each}}
48+
</ul>
49+
50+
<div class="evaluation-sent-results-modal__footer">
51+
<PixButton @variant="secondary" @triggerAction={{@onCloseButtonClick}}>
52+
{{t "pages.skill-review.tabs.trainings.sent-results-modal.return-results-action"}}
53+
</PixButton>
54+
</div>
55+
</div>
56+
</div>
57+
</template>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
@use 'pix-design-tokens/breakpoints';
2+
@use 'pix-design-tokens/typography';
3+
@use 'pix-design-tokens/shadows';
4+
5+
.evaluation-sent-results-modal__overlay {
6+
position: fixed;
7+
top: 0;
8+
right: 0;
9+
bottom: 0;
10+
left: 0;
11+
z-index: 1000;
12+
padding: 0;
13+
overflow-y: auto;
14+
text-align: center; // Used to center horizontally the inline-block modal content
15+
// we inline the pix-neutral-800 value
16+
background-color: rgb(37 56 88 / 50%);
17+
transition: all 0.3s ease-in-out;
18+
19+
// This block is used to center vertically the modal
20+
// if the content is less than 100vh
21+
// Inspired by https://mui.com/material-ui/react-dialog/#scrolling-long-content
22+
&::after {
23+
display: inline-block;
24+
width: 0;
25+
height: 100%;
26+
vertical-align: middle;
27+
content: '';
28+
}
29+
30+
&--hidden {
31+
visibility: hidden;
32+
opacity: 0;
33+
}
34+
}
35+
36+
.evaluation-sent-results-modal {
37+
@extend %pix-shadow-sm;
38+
39+
display: inline-block;
40+
width: 100%;
41+
height: 100%;
42+
padding: 6.25vw 5.75vw;
43+
overflow: hidden;
44+
color: var(--pix-neutral-900);
45+
text-align: center;
46+
vertical-align: middle; // Centered vertically with the .evaluation-sent-results-modal__overlay::after which is 100% height
47+
background-color: var(--pix-primary-10);
48+
49+
&__header {
50+
display: flex;
51+
justify-content: end;
52+
margin-bottom: var(--pix-spacing-12x);
53+
}
54+
55+
&__illustration {
56+
margin-bottom: var(--pix-spacing-4x);
57+
}
58+
59+
&__title {
60+
@extend %pix-title-m;
61+
62+
margin-bottom: var(--pix-spacing-8x);
63+
padding-right: var(--pix-spacing-8x) + var(--pix-spacing-2x);
64+
65+
@include breakpoints.device-is('tablet') {
66+
padding-right: var(--pix-spacing-10x) + var(--pix-spacing-2x);
67+
}
68+
}
69+
70+
&__subtitle {
71+
@extend %pix-title-s;
72+
73+
margin-bottom: var(--pix-spacing-6x);
74+
}
75+
76+
&__trainings {
77+
display: grid;
78+
grid-template-columns: repeat(auto-fit, minmax(0, 302px));
79+
gap: var(--pix-spacing-10x);
80+
justify-content: center;
81+
max-width: 1120px;
82+
margin: auto auto var(--pix-spacing-8x);
83+
text-align: start;
84+
}
85+
86+
&__footer {
87+
display: flex;
88+
justify-content: center;
89+
}
90+
}

mon-pix/app/styles/components/campaigns/index.scss

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
@use 'assessment/results/evaluation-sent-results-modal';
12
@use 'assessment/results/quit-results';
23
@use 'assessment/results/evaluation-results-tabs/results-details';
34
@use 'assessment/results/evaluation-results-tabs/rewards';

mon-pix/public/images/strike.svg

+1
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import { render } from '@1024pix/ember-testing-library';
2+
import { click } from '@ember/test-helpers';
3+
import EvaluationSentResultsModal from 'mon-pix/components/campaigns/assessment/results/evaluation-sent-results-modal';
4+
import { module, test } from 'qunit';
5+
import sinon from 'sinon';
6+
7+
import setupIntlRenderingTest from '../../../../../helpers/setup-intl-rendering';
8+
9+
module('Integration | Component | evaluation-sent-results-modal', function (hooks) {
10+
setupIntlRenderingTest(hooks);
11+
12+
module('when showModal is true', function () {
13+
test('should display modal', async function (assert) {
14+
// given
15+
const showModal = true;
16+
const trainings = [
17+
{
18+
title: 'Mon super training 1',
19+
link: 'https://training.net/',
20+
type: 'webinaire',
21+
locale: 'fr-fr',
22+
duration: { hours: 6 },
23+
editorName: "Ministère de l'éducation nationale et de la jeunesse. Liberté égalité fraternité",
24+
editorLogoUrl:
25+
'https://images.pix.fr/contenu-formatif/editeur/logo-ministere-education-nationale-et-jeunesse.svg',
26+
},
27+
{
28+
title: 'Mon super training 2',
29+
link: 'https://training.net/',
30+
type: 'webinaire',
31+
locale: 'fr-fr',
32+
duration: { hours: 8 },
33+
editorName: "Ministère de l'éducation nationale et de la jeunesse. Liberté égalité fraternité",
34+
editorLogoUrl:
35+
'https://images.pix.fr/contenu-formatif/editeur/logo-ministere-education-nationale-et-jeunesse.svg',
36+
},
37+
{
38+
title: 'Mon super training 3',
39+
link: 'https://training.net/',
40+
type: 'webinaire',
41+
locale: 'fr-fr',
42+
duration: { hours: 10 },
43+
editorName: "Ministère de l'éducation nationale et de la jeunesse. Liberté égalité fraternité",
44+
editorLogoUrl:
45+
'https://images.pix.fr/contenu-formatif/editeur/logo-ministere-education-nationale-et-jeunesse.svg',
46+
},
47+
];
48+
49+
// when
50+
const screen = await render(
51+
<template><EvaluationSentResultsModal @showModal={{showModal}} @trainings={{trainings}} /></template>,
52+
);
53+
54+
// then
55+
assert.dom(screen.getByRole('dialog')).exists();
56+
assert.strictEqual(screen.getAllByRole('heading', { level: 3 }).length, 3);
57+
assert.dom(screen.getByRole('heading', { name: trainings[0].title, level: 3 })).exists();
58+
assert.dom(screen.getByRole('heading', { name: trainings[1].title, level: 3 })).exists();
59+
assert.dom(screen.getByRole('heading', { name: trainings[2].title, level: 3 })).exists();
60+
});
61+
62+
module('when click on close button', function () {
63+
test('should call onCloseButtonClick method', async function (assert) {
64+
// given
65+
const showModal = true;
66+
const onCloseButtonClick = sinon.stub();
67+
const screen = await render(
68+
<template>
69+
<EvaluationSentResultsModal @showModal={{showModal}} @onCloseButtonClick={{onCloseButtonClick}} />
70+
</template>,
71+
);
72+
73+
// when
74+
await click(screen.getByRole('button', { name: 'Fermer' }));
75+
76+
// then
77+
sinon.assert.calledOnce(onCloseButtonClick);
78+
assert.ok(true);
79+
});
80+
});
81+
82+
module('when click on close and send results button', function () {
83+
test('should call onCloseButtonClick method', async function (assert) {
84+
// given
85+
const showModal = true;
86+
const onCloseButtonClick = sinon.stub();
87+
const screen = await render(
88+
<template>
89+
<EvaluationSentResultsModal @showModal={{showModal}} @onCloseButtonClick={{onCloseButtonClick}} />
90+
</template>,
91+
);
92+
93+
// when
94+
await click(screen.getByRole('button', { name: 'Fermer et revenir aux résultats' }));
95+
96+
// then
97+
sinon.assert.calledOnce(onCloseButtonClick);
98+
assert.ok(true);
99+
});
100+
});
101+
});
102+
103+
module('when showModal is false', function () {
104+
test('should not display modal', async function (assert) {
105+
// given
106+
const showModal = false;
107+
108+
// when
109+
const screen = await render(<template><EvaluationSentResultsModal @showModal={{showModal}} /></template>);
110+
111+
// then
112+
assert.dom(screen.queryByRole('dialog')).doesNotExist();
113+
});
114+
});
115+
});

0 commit comments

Comments
 (0)