Skip to content

Commit d6c4e33

Browse files
authored
[FEATURE] affiche une alerte d'expiration des lots de places (PIX-14008) (#10106)
1 parent 0044849 commit d6c4e33

File tree

8 files changed

+176
-0
lines changed

8 files changed

+176
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import PixBanner from '@1024pix/pix-ui/components/pix-banner';
2+
import dayjs from 'dayjs';
3+
import { t } from 'ember-intl';
4+
import { STATUSES } from 'pix-orga/models/organization-places-lot.js';
5+
6+
function getLastActivePlacesLot(placesLots) {
7+
return placesLots
8+
.filter((placesLot) => placesLot.status === STATUSES.ACTIVE)
9+
.sort((placesLotA, placesLotB) => placesLotB.expirationDate - placesLotA.expirationDate);
10+
}
11+
12+
function getCountdDownDays(placesLots) {
13+
const [lastActiveLot] = getLastActivePlacesLot(placesLots);
14+
if (!lastActiveLot) return;
15+
return dayjs(lastActiveLot.expirationDate).diff(dayjs(), 'day');
16+
}
17+
18+
function isAlertVisible(placesLots) {
19+
if (!Array.isArray(placesLots)) return false;
20+
21+
const hasPendingLots = placesLots.some((placesLot) => placesLot.status === STATUSES.PENDING);
22+
23+
if (hasPendingLots) return false;
24+
25+
const [lastActiveLot] = getLastActivePlacesLot(placesLots);
26+
if (!lastActiveLot) return false;
27+
return dayjs(lastActiveLot.expirationDate).isBefore(dayjs().add(30, 'days'));
28+
}
29+
30+
<template>
31+
{{#if (isAlertVisible @placesLots)}}
32+
<PixBanner class="places-lots-alert" @type="warning" @withIcon="true">
33+
{{t "banners.last-places-lot-available.message" days=(getCountdDownDays @placesLots)}}
34+
</PixBanner>
35+
{{/if}}
36+
</template>

orga/app/styles/components/places/index.scss

+2
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@
33
@import 'place-info';
44
@import 'capacity-alert';
55
@import 'places-lots';
6+
@import 'places-lots-alert';
7+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.places-lots-alert {
2+
margin-top: var(--pix-spacing-8x);
3+
}

orga/app/templates/authenticated/places.hbs

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
<Places::Title />
44

5+
<Places::PlacesLotAlert @placesLots={{@model.placesLots}} />
56
<Places::CapacityAlert @occupied={{@model.statistics.occupied}} @total={{@model.statistics.total}} />
67
<Places::Statistics @model={{@model.statistics}} />
78
<Places::PlaceInfo @hasAnonymousSeat={{@model.statistics.hasAnonymousSeat}} />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import { render } from '@1024pix/ember-testing-library';
2+
import { t } from 'ember-intl/test-support';
3+
import PlacesLotsAlert from 'pix-orga/components/places/places-lot-alert';
4+
import { STATUSES } from 'pix-orga/models/organization-places-lot';
5+
import { module, test } from 'qunit';
6+
import sinon from 'sinon';
7+
8+
import setupIntlRenderingTest from '../../../helpers/setup-intl-rendering';
9+
10+
module('Integration | Component | Places | PlacesLotsAlert', function (hooks) {
11+
setupIntlRenderingTest(hooks);
12+
let store, clock;
13+
const now = new Date('2021-11-03');
14+
15+
hooks.beforeEach(function () {
16+
store = this.owner.lookup('service:store');
17+
clock = sinon.useFakeTimers({ now });
18+
});
19+
20+
hooks.afterEach(function () {
21+
clock.restore();
22+
});
23+
24+
test('it should show an alert with remaining days before places lot expires', async function (assert) {
25+
// given
26+
const placesLots = [
27+
store.createRecord('organization-places-lot', {
28+
count: 123,
29+
activationDate: new Date('2021-11-01'),
30+
expirationDate: new Date('2021-11-30'),
31+
status: STATUSES.ACTIVE,
32+
}),
33+
];
34+
// when
35+
const screen = await render(<template><PlacesLotsAlert @placesLots={{placesLots}} /></template>);
36+
const banner = screen.getByRole('alert', { value: t('banners.last-places-lot-available.message') });
37+
// then
38+
assert.strictEqual(banner.outerText, t('banners.last-places-lot-available.message', { days: 27 }));
39+
});
40+
test('it should not show an alert if there is one active lot that has an expiration date in more than 1 month', async function (assert) {
41+
// given
42+
const placesLots = [
43+
store.createRecord('organization-places-lot', {
44+
count: 123,
45+
activationDate: new Date('2021-11-01'),
46+
expirationDate: new Date('2021-11-07'),
47+
status: STATUSES.ACTIVE,
48+
}),
49+
store.createRecord('organization-places-lot', {
50+
count: 123,
51+
activationDate: new Date('2021-11-01'),
52+
expirationDate: new Date('2021-12-03'),
53+
status: STATUSES.ACTIVE,
54+
}),
55+
];
56+
// when
57+
const screen = await render(<template><PlacesLotsAlert @placesLots={{placesLots}} /></template>);
58+
59+
// then
60+
assert.notOk(screen.queryByRole('alert', { value: t('banners.last-places-lot-available.message') }));
61+
});
62+
test('it should not show an alert if remaining days before places lot expires in more than 30 days', async function (assert) {
63+
// given
64+
const placesLots = [
65+
store.createRecord('organization-places-lot', {
66+
count: 123,
67+
activationDate: new Date('2021-11-01'),
68+
expirationDate: new Date('2021-12-03'),
69+
status: STATUSES.ACTIVE,
70+
}),
71+
];
72+
// when
73+
const screen = await render(<template><PlacesLotsAlert @placesLots={{placesLots}} /></template>);
74+
75+
// then
76+
assert.notOk(screen.queryByRole('alert', { value: t('banners.last-places-lot-available.message') }));
77+
});
78+
test('it should not show alert if there is `PENDING` placesLots', async function (assert) {
79+
// given
80+
const placesLots = [
81+
store.createRecord('organization-places-lot', {
82+
count: 123,
83+
activationDate: new Date('2021-11-01'),
84+
expirationDate: new Date('2021-11-30'),
85+
status: STATUSES.ACTIVE,
86+
}),
87+
store.createRecord('organization-places-lot', {
88+
count: 123,
89+
activationDate: new Date('2021-12-01'),
90+
expirationDate: new Date('2021-12-30'),
91+
status: STATUSES.PENDING,
92+
}),
93+
];
94+
// when
95+
const screen = await render(<template><PlacesLotsAlert @placesLots={{placesLots}} /></template>);
96+
97+
// then
98+
assert.notOk(screen.queryByRole('alert', { value: t('banners.last-places-lot-available.message') }));
99+
});
100+
test('it should not show alert if there is no ACTIVE placesLots', async function (assert) {
101+
// given
102+
const placesLots = [
103+
store.createRecord('organization-places-lot', {
104+
count: 123,
105+
activationDate: new Date('2020-12-01'),
106+
expirationDate: new Date('2020-12-30'),
107+
status: STATUSES.EXPIRED,
108+
}),
109+
];
110+
// when
111+
const screen = await render(<template><PlacesLotsAlert @placesLots={{placesLots}} /></template>);
112+
113+
// then
114+
assert.notOk(screen.queryByRole('alert', { value: t('banners.last-places-lot-available.message') }));
115+
});
116+
test('it should not show alert if there is no placesLots', async function (assert) {
117+
// given
118+
const placesLots = [];
119+
// when
120+
const screen = await render(<template><PlacesLotsAlert @placesLots={{placesLots}} /></template>);
121+
122+
// then
123+
assert.notOk(screen.queryByRole('alert', { value: t('banners.last-places-lot-available.message') }));
124+
});
125+
});

orga/translations/en.json

+3
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@
7171
"language-availability": {
7272
"message": "Your language is not yet available on Pix Orga. For your convenience, the application will be presented in English. The entire Pix team is working to add your language."
7373
},
74+
"last-places-lot-available": {
75+
"message": "Please note that your seats will expire in {days, number} days."
76+
},
7477
"over-capacity": {
7578
"message": "Please note that you are using more seats than your total capacity."
7679
}

orga/translations/fr.json

+3
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@
7171
"language-availability": {
7272
"message": "Votre langue n'est pas encore disponible sur Pix Orga. Pour votre confort, l'application sera présentée en anglais. Toute l'équipe de Pix travaille à l'ajout de votre langue."
7373
},
74+
"last-places-lot-available": {
75+
"message": "Attention, vos places arrivent à échéance dans {days, number} jours."
76+
},
7477
"over-capacity": {
7578
"message": "Attention, vous consommez plus de places que votre capacité totale."
7679
},

orga/translations/nl.json

+3
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@
7171
"language-availability": {
7272
"message": "Jouw taal is nog niet beschikbaar op Pix Orga. Voor jouw gemak wordt de applicatie in het Engels weergegeven. Het Pix-team werkt eraan om jouw taal toe te voegen."
7373
},
74+
"last-places-lot-available": {
75+
"message": "Houd er rekening mee dat je seats over {days, number} dagen verlopen."
76+
},
7477
"over-capacity": {
7578
"message": "Houd er rekening mee dat je meer plaats inneemt dan je totale capaciteit."
7679
},

0 commit comments

Comments
 (0)