Skip to content

Commit fda85a8

Browse files
[FEATURE] Affiche tous les badges du PC (Pix-16352)
#11417
2 parents 34b309e + 2b7304b commit fda85a8

File tree

14 files changed

+162
-72
lines changed

14 files changed

+162
-72
lines changed

Diff for: api/db/seeds/data/common/tooling/campaign-tooling.js

+14-9
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ async function createAssessmentCampaign({
116116
targetProfileId,
117117
});
118118

119-
const badgeIds = await databaseBuilder.knex('badges').pluck('id').where({ targetProfileId });
120119
if (configCampaign) {
121120
if (configCampaign.anonymousParticipation) {
122121
_createAnonymousParticipation(databaseBuilder, realOrganizationId, realCampaignId, realCreatedAt);
@@ -157,7 +156,7 @@ async function createAssessmentCampaign({
157156
validatedSkillsCount,
158157
masteryRate,
159158
pixScore,
160-
buildBadges,
159+
buildBadgeIds,
161160
buildStageAcquisitions,
162161
} = await _getCompletionCampaignParticipationData(
163162
completionDistribution.shift(),
@@ -215,8 +214,8 @@ async function createAssessmentCampaign({
215214
);
216215
}
217216

218-
if (!isStarted && buildBadges) {
219-
for (const badgeId of badgeIds) {
217+
if (!isStarted && buildBadgeIds) {
218+
for (const badgeId of buildBadgeIds) {
220219
databaseBuilder.factory.buildBadgeAcquisition({
221220
badgeId,
222221
userId,
@@ -657,10 +656,17 @@ async function _getCompletionCampaignParticipationData(
657656
computedScore,
658657
validatedSkillsCount = 0,
659658
masteryRate = 0,
660-
buildBadges = false,
659+
buildBadgeIds = [],
661660
pixScore = 0;
662661

663662
const randomValidatedSkill = generic.pickOneRandomAmong(_.range(campaignSkills.length));
663+
const allBadges = await databaseBuilder
664+
.knex('badges')
665+
.select('badges.id')
666+
.max('threshold as threshold')
667+
.join('badge-criteria', 'badgeId', 'badges.id')
668+
.groupBy('badges.id')
669+
.where({ targetProfileId });
664670

665671
const stages = await databaseBuilder.knex('stages').where({ targetProfileId });
666672
const buildStageAcquisitions = stages.length > 0;
@@ -677,12 +683,11 @@ async function _getCompletionCampaignParticipationData(
677683
case 'SHARED':
678684
answersAndKnowledgeElements = await _getKnowledgeElementFromSkills(campaignSkills, randomValidatedSkill);
679685
status = CampaignParticipationStatuses.SHARED;
680-
buildBadges = randomValidatedSkill > campaignSkills.length / 2;
681-
682686
computedScore = _getCampaignParticipationResults(answersAndKnowledgeElements);
683687
validatedSkillsCount = computedScore.validatedSkillsCount;
684688
pixScore = computedScore.pixScore;
685689
masteryRate = computedScore.masteryRate;
690+
buildBadgeIds = allBadges.flatMap(({ id, threshold }) => (masteryRate * 100 >= threshold ? [id] : []));
686691
break;
687692
case 'SHARED_ONE_VALIDATED_SKILL':
688693
answersAndKnowledgeElements = await _getKnowledgeElementFromSkills(campaignSkills, 1);
@@ -696,7 +701,7 @@ async function _getCompletionCampaignParticipationData(
696701
case 'SHARED_PERFECT':
697702
answersAndKnowledgeElements = await _getKnowledgeElementFromSkills(campaignSkills, campaignSkills.length);
698703
status = CampaignParticipationStatuses.SHARED;
699-
buildBadges = true;
704+
buildBadgeIds = allBadges.map(({ id }) => id);
700705

701706
computedScore = _getCampaignParticipationResults(answersAndKnowledgeElements);
702707
validatedSkillsCount = computedScore.validatedSkillsCount;
@@ -711,7 +716,7 @@ async function _getCompletionCampaignParticipationData(
711716
validatedSkillsCount,
712717
masteryRate,
713718
pixScore,
714-
buildBadges,
719+
buildBadgeIds,
715720
buildStageAcquisitions,
716721
};
717722
}

Diff for: api/db/seeds/data/team-prescription/build-target-profiles.js

+49-20
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { SCO_MANAGING_ORGANIZATION_ID } from '../common/constants.js';
22
import { createBadge, createStages, createTargetProfile } from '../common/tooling/target-profile-tooling.js';
33
import {
44
BADGES_CAMP_ID,
5+
BADGES_CAMPAIGN_UNACQUIRED_ID,
56
BADGES_TUBES_CAMP_ID,
67
TARGET_PROFILE_BADGES_STAGES_ID,
78
TARGET_PROFILE_NO_BADGES_NO_STAGES_ID,
@@ -42,18 +43,6 @@ async function _createTargetProfileWithBadgesStages(databaseBuilder) {
4243
],
4344
};
4445

45-
const configBadge = {
46-
criteria: [
47-
{
48-
scope: 'CappedTubes',
49-
threshold: 60,
50-
},
51-
{
52-
scope: 'CampaignParticipation',
53-
threshold: 50,
54-
},
55-
],
56-
};
5746
const { targetProfileId, cappedTubesDTO } = await createTargetProfile({
5847
databaseBuilder,
5948
targetProfileId: TARGET_PROFILE_BADGES_STAGES_ID,
@@ -70,27 +59,67 @@ async function _createTargetProfileWithBadgesStages(databaseBuilder) {
7059
cappedTubesDTO,
7160
badgeId: BADGES_TUBES_CAMP_ID,
7261
altMessage: '1 RT double critère Campaign & Tubes',
73-
imageUrl: 'https://images.pix.fr/badges/abcpix_je_navigue_sur_internet.svg',
74-
message: '1 RT double critère Campaign & Tubes',
75-
title: '1 RT double critère Campaign & Tubes',
62+
imageUrl: 'https://images.pix.fr/badges/Badge_OLYMPIX.svg',
63+
message: '1 RT double critère Campaign & Tubes 60/50',
64+
title: '1 RT double critère Campaign & Tubes 60/50',
7665
key: `SOME_KEY_FOR_RT_${BADGES_TUBES_CAMP_ID}`,
7766
isCertifiable: false,
7867
isAlwaysVisible: true,
79-
configBadge,
68+
configBadge: {
69+
criteria: [
70+
{
71+
scope: 'CappedTubes',
72+
threshold: 60,
73+
},
74+
{
75+
scope: 'CampaignParticipation',
76+
threshold: 50,
77+
},
78+
],
79+
},
8080
});
81+
8182
await createBadge({
8283
databaseBuilder,
8384
targetProfileId,
8485
cappedTubesDTO,
8586
badgeId: BADGES_CAMP_ID,
8687
altMessage: '1 RT simple critère Campaign',
87-
imageUrl: 'https://images.pix.fr/badges/Badge_OLYMPIX.svg',
88-
message: '1 RT simple critère Campaign',
89-
title: '1 RT simple critère Campaign',
88+
imageUrl: 'https://images.pix.fr/badges/Badge_Pixome%CC%80tre-Lune.svg',
89+
message: '1 RT simple critère Campaign 20',
90+
title: '1 RT simple critère Campaign 20',
9091
key: `SOME_KEY_FOR_RT_${BADGES_CAMP_ID}`,
9192
isCertifiable: false,
9293
isAlwaysVisible: true,
93-
configBadge,
94+
configBadge: {
95+
criteria: [
96+
{
97+
scope: 'CampaignParticipation',
98+
threshold: 20,
99+
},
100+
],
101+
},
102+
});
103+
await createBadge({
104+
databaseBuilder,
105+
targetProfileId,
106+
cappedTubesDTO,
107+
badgeId: BADGES_CAMPAIGN_UNACQUIRED_ID,
108+
altMessage: 'Badge DadiCool',
109+
imageUrl: 'https://images.pix.fr/badges/abcpix_je_navigue_sur_internet.svg',
110+
message: '1 RT Campaign 100',
111+
title: '1 RT Campaign 100',
112+
key: `SOME_KEY_FOR_RT_${BADGES_CAMPAIGN_UNACQUIRED_ID}`,
113+
isCertifiable: false,
114+
isAlwaysVisible: true,
115+
configBadge: {
116+
criteria: [
117+
{
118+
scope: 'CampaignParticipation',
119+
threshold: 100,
120+
},
121+
],
122+
},
94123
});
95124
await createStages({
96125
databaseBuilder,

Diff for: api/db/seeds/data/team-prescription/constants.js

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const TARGET_PROFILE_BADGES_STAGES_ID = TEAM_PRESCRIPTION_OFFSET_ID + 1;
99
//BADGES
1010
const BADGES_TUBES_CAMP_ID = TEAM_PRESCRIPTION_OFFSET_ID;
1111
const BADGES_CAMP_ID = TEAM_PRESCRIPTION_OFFSET_ID + 1;
12+
const BADGES_CAMPAIGN_UNACQUIRED_ID = TEAM_PRESCRIPTION_OFFSET_ID + 2;
1213

1314
// CAMPAIGNS
1415

@@ -17,6 +18,7 @@ const CAMPAIGN_PROCOLMUL_ID = TEAM_PRESCRIPTION_OFFSET_ID + 1;
1718

1819
export {
1920
BADGES_CAMP_ID,
21+
BADGES_CAMPAIGN_UNACQUIRED_ID,
2022
BADGES_TUBES_CAMP_ID,
2123
CAMPAIGN_PROASSMUL_ID,
2224
CAMPAIGN_PROCOLMUL_ID,

Diff for: orga/app/components/campaign/badges.gjs

+19-1
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,36 @@
11
import PixTooltip from '@1024pix/pix-ui/components/pix-tooltip';
2+
import { t } from 'ember-intl';
3+
4+
const isAcquired = (badge, acquiredBadges = []) => {
5+
let acquired = false;
6+
acquiredBadges.forEach((acquiredBadge) => {
7+
if (acquiredBadge.id === badge.id) {
8+
acquired = true;
9+
}
10+
});
11+
return acquired;
12+
};
213

314
<template>
415
{{#each @badges as |badge|}}
5-
<PixTooltip @id="badge-tooltip-{{badge.id}}" @position="bottom" @isInline={{true}}>
16+
<PixTooltip @id="badge-tooltip-{{badge.id}}">
617
<:triggerElement>
718
<img
819
src={{badge.imageUrl}}
920
alt={{badge.altMessage}}
1021
tabindex="0"
22+
class={{unless (isAcquired badge @acquiredBadges) "badge--unacquired"}}
1123
aria-describedby="badge-tooltip-{{badge.id}}"
1224
/>
1325
</:triggerElement>
1426
<:tooltip>
1527
{{badge.title}}
28+
-
29+
{{if
30+
(isAcquired badge @acquiredBadges)
31+
(t "pages.campaign-results.table.badge-tooltip.acquired")
32+
(t "pages.campaign-results.table.badge-tooltip.unacquired")
33+
}}
1634
</:tooltip>
1735
</PixTooltip>
1836
{{/each}}

Diff for: orga/app/components/campaign/results/assessment-list.gjs

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { t } from 'ember-intl';
44
import getService from '../../../helpers/get-service.js';
55
import TableHeader from '../../table/header';
66
import CampaignParticipationFilters from '../filter/participation-filters';
7-
import CampaignAssessmentRow from '../results/assessment-row';
7+
import CampaignAssessmentRow from './assessment-row';
88
import EvolutionHeader from './evolution-header';
99

1010
<template>
@@ -74,6 +74,7 @@ import EvolutionHeader from './evolution-header';
7474
@participation={{participation}}
7575
@campaignId={{@campaign.id}}
7676
@stages={{@campaign.stages}}
77+
@badges={{@campaign.badges}}
7778
@onClickParticipant={{@onClickParticipant}}
7879
@displayParticipationCount={{@campaign.multipleSendings}}
7980
/>

Diff for: orga/app/components/campaign/results/assessment-row.gjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ import ParticipationEvolutionIcon from './participation-evolution-icon';
4444
{{/if}}
4545
{{#if @hasBadges}}
4646
<td class="participant-list__badges">
47-
<CampaignBadges @badges={{@participation.badges}} />
47+
<CampaignBadges @badges={{@badges}} @acquiredBadges={{@participation.badges}} />
4848
</td>
4949
{{/if}}
5050
</tr>

Diff for: orga/app/models/badge.js

+1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ export default class Badge extends Model {
44
@attr('string') title;
55
@attr('string') imageUrl;
66
@attr('string') altMessage;
7+
@attr('boolean') acquired;
78
}
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
.assessment-results {
22
&__list {
33
padding: 0;
4+
5+
.badge--unacquired {
6+
opacity: .8;
7+
filter: grayscale(1);
8+
}
49
}
510

611
&__charts {
712
margin-bottom: 24px;
813
}
14+
15+
916
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { render } from '@1024pix/ember-testing-library';
2+
import Badges from 'pix-orga/components/campaign/badges';
3+
import { module, test } from 'qunit';
4+
5+
import setupIntlRenderingTest from '../../../helpers/setup-intl-rendering';
6+
7+
module('Integration | Component | Campaign | Badges', function (hooks) {
8+
setupIntlRenderingTest(hooks);
9+
10+
test('should render badge images for each one', async function (assert) {
11+
// given
12+
const badges = [
13+
{ id: 1, title: 'badge1', imageUrl: 'img1.svg', altMessage: 'alt-img1' },
14+
{ id: 2, title: 'badge2', imageUrl: 'img2.svg', altMessage: 'alt-img2' },
15+
];
16+
const acquiredBadges = [];
17+
// when
18+
const screen = await render(<template><Badges @badges={{badges}} @acquiredBadges={{acquiredBadges}} /></template>);
19+
// then
20+
const badgeImages = screen.getAllByRole('img');
21+
assert.strictEqual(badgeImages.length, 2);
22+
assert.strictEqual(badgeImages[0].getAttribute('src'), 'img1.svg');
23+
assert.strictEqual(badgeImages[0].getAttribute('alt'), 'alt-img1');
24+
25+
assert.strictEqual(badgeImages[1].getAttribute('src'), 'img2.svg');
26+
assert.strictEqual(badgeImages[1].getAttribute('alt'), 'alt-img2');
27+
});
28+
29+
test('should render unacquired in the title', async function (assert) {
30+
// given
31+
const badges = [{ title: 'badge1', imageUrl: 'img1', altMessage: 'alt-img1' }];
32+
const acquiredBadges = [];
33+
34+
// when
35+
const screen = await render(<template><Badges @badges={{badges}} @acquiredBadges={{acquiredBadges}} /></template>);
36+
37+
// then
38+
assert.ok(screen.getByText(/badge1 - Non acquis/i));
39+
});
40+
test('should render acquired in the title', async function (assert) {
41+
// given
42+
const badges = [{ title: 'badge1', imageUrl: 'img1', altMessage: 'alt-img1' }];
43+
const acquiredBadges = [badges[0]];
44+
45+
// when
46+
const screen = await render(<template><Badges @badges={{badges}} @acquiredBadges={{acquiredBadges}} /></template>);
47+
48+
// then
49+
assert.ok(screen.getByText(/badge1 - Acquis/i));
50+
});
51+
});

Diff for: orga/tests/integration/components/campaign/badges-test.js

-37
This file was deleted.

0 commit comments

Comments
 (0)