Skip to content

Commit c635e58

Browse files
authored
Améliore l'affichage de la progression de l 'audit (#1115)
* update save indicator icons and spacing * update last saving relative time in save indicator tooltip * rework audit progress bar layout and add tooltip slot * fix typos * fix typos * update progress bar left padding * update changelog * fix common e2e tests (non breaking space)
1 parent 2868c24 commit c635e58

10 files changed

Lines changed: 175 additions & 100 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#### <span aria-hidden="true">🐛</span> Corrections
1515

16+
- Corrige l’accessibilité de la barre de progression de l’audit et de l’indicateur d’enregistrement ([#1115](https://github.com/DISIC/Ara/pull/1115))
1617
- Corrige l’affichage de l’éditeur lorsque les CSS sont désactivées ([#1120](https://github.com/DISIC/Ara/pull/1120))
1718

1819
### 22/05/2025
Lines changed: 4 additions & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 1 addition & 0 deletions
Loading

confiture-web-app/src/components/account/dashboard/AuditRow.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ function copyStatementLink(uniqueId: string) {
213213
{{
214214
isInProgress || isNotStarted
215215
? "Audit en cours"
216-
: `${audit.complianceLevel}%`
216+
: `${audit.complianceLevel} %`
217217
}}
218218
</p>
219219
<p

confiture-web-app/src/components/audit/AuditGenerationHeader.vue

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -266,9 +266,24 @@ onMounted(() => {
266266
v-if="showAuditProgressBar"
267267
:value="resultStore.auditProgress"
268268
label="Progression de l’audit"
269-
:size="4"
269+
tooltip-label="Informations sur la progression de l’audit"
270+
:size="8"
270271
class="progress-bar"
271-
/>
272+
>
273+
<template #tooltip-content>
274+
<p class="fr-text--sm">
275+
La progression de l'audit se base sur les critères évalués de chaque
276+
<strong>page de votre échantillon</strong>. Évaluez les critères de
277+
toutes les pages pour terminer votre audit.
278+
</p>
279+
<p class="fr-text--xs fr-mb-0">
280+
À noter : les critères des
281+
<strong>éléments transverses</strong> sont optionnels. Ils sont pris
282+
en compte dans le calcul du taux mais pas dans la progression de
283+
l’audit.
284+
</p>
285+
</template>
286+
</AuditProgressBar>
272287

273288
<div
274289
v-else-if="auditStore.currentAudit?.publicationDate"
@@ -507,7 +522,7 @@ onMounted(() => {
507522
}
508523
509524
.audit-main-indicator {
510-
margin-left: 2rem;
525+
margin-left: 0.75rem;
511526
}
512527
513528
@media (width < 36rem) {
Lines changed: 55 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
<script setup lang="ts">
22
import { computed } from "vue";
33
4+
import { useUniqueId } from "../../composables/useUniqueId";
5+
46
const props = defineProps<{
57
value: number;
68
label: string;
79
size: number; // value in px
810
inline?: boolean;
11+
tooltipLabel?: string;
912
}>();
1013
14+
const uniqueId = useUniqueId();
15+
1116
const progressPercentage = computed(() => {
1217
const percentage = props.value * 100;
1318
const rounded = Math.round(percentage);
@@ -24,13 +29,39 @@ const progressBarSize = computed(() => `${props.size / 16}rem`);
2429
</script>
2530

2631
<template>
27-
<div :class="['audit-progress', { 'audit-progress--inline': inline }]">
32+
<div
33+
:class="[
34+
'audit-progress',
35+
{
36+
'audit-progress--inline': inline,
37+
'audit-progress--with-tooltip':
38+
tooltipLabel && $slots['tooltip-content']
39+
}
40+
]"
41+
>
2842
<span :class="['audit-progress-label', { 'fr-sr-only': inline }]">
2943
{{ label }}
3044
</span>
45+
<template v-if="tooltipLabel && $slots['tooltip-content']">
46+
<button
47+
class="fr-btn--tooltip fr-btn"
48+
type="button"
49+
:aria-describedby="`progress-bar-tooltip-${uniqueId}`"
50+
>
51+
{{ tooltipLabel }}
52+
</button>
53+
<span
54+
:id="`progress-bar-tooltip-${uniqueId}`"
55+
class="fr-tooltip fr-placement fr-text--sm"
56+
role="tooltip"
57+
aria-hidden="true"
58+
>
59+
<slot name="tooltip-content" />
60+
</span>
61+
</template>
3162
<span
3263
:class="[
33-
' fr-text--action-high-grey fr-m-0 audit-progress-percentage',
64+
' fr-text--action-high-grey fr-mb-0 audit-progress-percentage',
3465
{
3566
'fr-text--xs': !inline
3667
}
@@ -43,34 +74,38 @@ const progressBarSize = computed(() => `${props.size / 16}rem`);
4374
</template>
4475

4576
<style scoped>
46-
.audit-progress-bar {
47-
background-color: var(--background-contrast-grey);
48-
position: relative;
49-
grid-column: 1 / -1;
50-
}
51-
5277
.audit-progress {
5378
background: none;
54-
display: grid;
55-
gap: v-bind(progressBarSize) 1rem;
56-
grid-template-columns: 1fr 4ch;
57-
grid-template-rows: auto v-bind(progressBarSize);
79+
display: flex;
80+
flex-wrap: wrap;
81+
align-items: center;
82+
justify-content: start;
83+
gap: v-bind(progressBarSize) 0.125rem;
5884
}
5985
6086
.audit-progress--inline {
61-
grid-template-rows: v-bind(progressBarSize);
62-
gap: 0 0.5rem;
87+
gap: 0.5rem;
88+
flex-direction: row-reverse;
89+
flex-wrap: nowrap;
6390
6491
.audit-progress-bar {
6592
height: v-bind(progressBarSize);
66-
grid-column: 1 / span 1;
6793
}
94+
}
95+
.audit-progress-label {
96+
font-weight: 500;
97+
}
6898
69-
.audit-progress-percentage {
70-
grid-column: 2;
71-
grid-row: 1;
72-
align-self: center;
73-
}
99+
.audit-progress-percentage {
100+
color: var(--text-mention-grey);
101+
margin-inline-start: auto;
102+
}
103+
104+
.audit-progress-bar {
105+
background-color: var(--background-contrast-grey);
106+
position: relative;
107+
height: v-bind(progressBarSize);
108+
flex-basis: 100%;
74109
}
75110
76111
.audit-progress-bar::after {
@@ -83,14 +118,4 @@ const progressBarSize = computed(() => `${props.size / 16}rem`);
83118
transition: width 1s ease;
84119
width: v-bind(progressBarValue);
85120
}
86-
87-
.audit-progress-label {
88-
font-weight: 500;
89-
}
90-
91-
.audit-progress-percentage {
92-
color: var(--text-mention-grey);
93-
align-self: end;
94-
text-align: end;
95-
}
96121
</style>

confiture-web-app/src/components/audit/SaveIndicator.vue

Lines changed: 86 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
import { debounce } from "lodash-es";
33
import { computed, ref, watch } from "vue";
44
5+
import { useUniqueId } from "../../composables/useUniqueId";
56
import { useAuditStore, useResultsStore, useSystemStore } from "../../store";
67
import { StoreName } from "../../types";
7-
import Dropdown from "../ui/Dropdown.vue";
8+
import { formatDate, pluralize } from "../../utils";
89
9-
/* Change the saving status in a way that it wont "flicker" */
10+
const uniqueId = useUniqueId();
1011
12+
/* Change the saving status in a way that it wont "flicker" */
1113
export interface Props {
1214
storeName?: StoreName;
1315
}
@@ -41,59 +43,56 @@ watch(
4143
}
4244
);
4345
44-
/* Show an alert when the app is offline */
45-
46+
/* Update tooltip content conditionally */
4647
const systemStore = useSystemStore();
4748
48-
const dropdownTitle = computed(() => {
49+
const saveContent = computed(() => {
4950
if (isLoading.value) {
50-
return "Enregistrement…";
51-
}
52-
if (!systemStore.isOnline) {
53-
return "Enregistrement impossible";
51+
return {
52+
status: "Enregistrement…",
53+
description: "Modifications en cours d’enregistrement…",
54+
class: "save-indicator-icon--loading"
55+
};
5456
}
5557
56-
return "Enregistré";
57-
});
58-
59-
const dropdownMainText = computed(() => {
60-
if (isLoading.value) {
61-
return "Modifications en cours d’enregistrement…";
62-
}
6358
if (!systemStore.isOnline) {
64-
return "L’enregistrement de vos modifications est impossible hors connexion. Veuillez vérifier votre connexion internet.";
65-
}
66-
return "Ara enregistre automatiquement votre travail";
67-
});
68-
69-
const dropdownIcon = computed(() => {
70-
if (isLoading.value) {
71-
return "fr-icon-refresh-line";
72-
}
73-
if (!systemStore.isOnline) {
74-
return "fr-icon-warning-line";
59+
return {
60+
status: "Enregistrement impossible",
61+
description:
62+
"L’enregistrement de vos modifications est impossible hors connexion. Veuillez vérifier votre connexion internet.",
63+
class: "save-indicator-icon--error"
64+
};
7565
}
7666
77-
return "fr-icon-success-line";
67+
return {
68+
status: "Enregistré",
69+
description: "Ara enregistre automatiquement votre travail.",
70+
class: "save-indicator-icon--default"
71+
};
7872
});
7973
8074
/* Display the time since last successful save */
81-
8275
const relativeLastSaveDate = ref<string>();
8376
84-
/**
85-
*
86-
* @param seconds
87-
*/
8877
function formatInterval(seconds: number) {
8978
if (seconds < 60) {
90-
return `il y a ${seconds} secondes`;
79+
return `il y a quelques secondes`;
9180
} else if (seconds < 60 * 60) {
9281
return `il y a ${Math.floor(seconds / 60)} min`;
93-
} else {
82+
} else if (seconds < 60 * 60 * 24) {
9483
const hours = Math.floor(seconds / (60 * 60));
9584
const minutes = Math.floor((seconds - hours * 60 * 60) / 60);
96-
return `il y a ${hours} h ${minutes} m`;
85+
return minutes > 0
86+
? `il y a ${hours} h ${minutes} min`
87+
: `il y a ${hours} h`;
88+
} else if (seconds < 60 * 60 * 24 * 7) {
89+
const days = Math.floor(seconds / (60 * 60 * 24));
90+
return `il y a ${days} ${pluralize("jour", "jours", days)}`;
91+
} else if (store.value.lastRequestSuccessEnd) {
92+
const date = new Date(store.value.lastRequestSuccessEnd);
93+
return `le ${formatDate(date.toString())}`;
94+
} else {
95+
return "il y a plusieurs jours";
9796
}
9897
}
9998
@@ -127,26 +126,26 @@ watch(
127126
</script>
128127

129128
<template>
130-
<div class="dropdown-container">
131-
<Dropdown
132-
:title="dropdownTitle"
133-
align-left
134-
icon-left
135-
:button-props="{
136-
class: `fr-btn--tertiary-no-outline ${dropdownIcon}`,
137-
style: !systemStore.isOnline
138-
? 'color: var(--text-default-error);'
139-
: undefined
140-
}"
129+
<div class="save-indicator">
130+
<button
131+
:class="[`fr-btn--tooltip fr-btn fr-btn--sm ${saveContent.class}`]"
132+
type="button"
133+
:aria-describedby="`save-indicator-${uniqueId}`"
141134
>
142-
<p class="fr-text--sm fr-mb-1v">
143-
{{ dropdownMainText }}
144-
</p>
145-
146-
<p v-if="relativeLastSaveDate" class="fr-text--xs fr-m-0">
147-
Dernier enregistrement {{ relativeLastSaveDate }}
148-
</p>
149-
</Dropdown>
135+
Informations sur l’enregistrement
136+
</button>
137+
<span
138+
:id="`save-indicator-${uniqueId}`"
139+
class="fr-tooltip fr-placement fr-text--sm"
140+
role="tooltip"
141+
aria-hidden="true"
142+
>
143+
{{ saveContent.description }}
144+
<small class="fr-text--xs fr-m-0 save-indicator-relative-time">
145+
Dernier enregistrement {{ relativeLastSaveDate }}.
146+
</small>
147+
</span>
148+
<p class="fr-m-0 save-indicator-label">{{ saveContent.status }}</p>
150149

151150
<p class="fr-sr-only" aria-live="polite" role="alert">
152151
{{ saveText }}
@@ -155,10 +154,38 @@ watch(
155154
</template>
156155

157156
<style scoped>
158-
.dropdown-container {
159-
min-width: 10rem;
157+
.save-indicator {
158+
align-items: center;
159+
display: flex;
160+
gap: 0.125rem;
161+
}
162+
163+
.save-indicator-icon--default::before {
164+
mask-image: url("../../assets/images/cloud-check.svg");
165+
}
166+
167+
.save-indicator-icon--loading::before {
168+
mask-image: url("../../assets/images/upload-cloud-2-line.svg");
169+
}
170+
171+
.save-indicator-icon--error::before {
172+
mask-image: url("../../assets/images/cloud-off-line.svg");
173+
}
174+
175+
.save-indicator-icon--error {
176+
color: var(--text-default-error);
177+
178+
& ~ .save-indicator-label {
179+
color: var(--text-default-error);
180+
}
181+
}
182+
183+
.save-indicator-label {
184+
color: var(--text-mention-grey);
160185
}
161-
:deep(.fr-btn--tertiary-no-outline) {
162-
padding: 0;
186+
187+
.save-indicator-relative-time {
188+
display: block;
189+
color: var(--text-mention-grey);
163190
}
164191
</style>

0 commit comments

Comments
 (0)