Skip to content

Commit

Permalink
Merge pull request #2090 from sophiemoustard/COM-3857
Browse files Browse the repository at this point in the history
Com 3857
  • Loading branch information
ulysseferreira authored Dec 4, 2024
2 parents 38a013c + 1e1e182 commit 2018fe2
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 41 deletions.
42 changes: 29 additions & 13 deletions src/core/components/courses/AttendanceSheetAdditionModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
<ni-input in-modal caption="Feuille d'émargement" type="file" @blur="validations.file.$touch" last required-field
:model-value="newAttendanceSheet.file" @update:model-value="update($event, 'file')"
:extensions="[DOC_EXTENSIONS, IMAGE_EXTENSIONS]" :error="validations.file.$error" />
<ni-option-group v-if="slotOptions.length" :model-value="newAttendanceSheet.slots" in-modal required-field
:options="slotOptions" :error="validations.slots.$error" type="checkbox" inline
@update:model-value="update($event, 'slots')"
<ni-multiple-option-group v-if="slotOptions.length" :model-value="newAttendanceSheet.slots" in-modal required-field
:options-groups="slotOptions" :error="validations.slots.$error" type="checkbox" inline
@update:model-value="update($event, 'slots')" :group-titles="stepsName"
caption="Sélectionner les créneaux auxquels a été présent·e le/la participant·e" />
<template #footer>
<ni-button class="full-width modal-btn bg-primary" label="Ajouter la feuille d'émargement" :loading="loading"
Expand All @@ -25,11 +25,12 @@

<script>
import { toRefs, computed } from 'vue';
import groupBy from 'lodash/groupBy';
import Modal from '@components/modal/Modal';
import Select from '@components/form/Select';
import Input from '@components/form/Input';
import Button from '@components/Button';
import OptionGroup from '@components/form/OptionGroup';
import MultipleOptionGroup from '@components/form/MultipleOptionGroup';
import { INTER_B2B, DOC_EXTENSIONS, IMAGE_EXTENSIONS, DD_MM_YYYY, HH_MM } from '@data/constants';
import { formatAndSortIdentityOptions } from '@helpers/utils';
import { ascendingSortBy } from '@helpers/dates/utils';
Expand All @@ -42,7 +43,7 @@ export default {
'ni-modal': Modal,
'ni-input': Input,
'ni-button': Button,
'ni-option-group': OptionGroup,
'ni-multiple-option-group': MultipleOptionGroup,
},
props: {
modelValue: { type: Boolean, default: false },
Expand All @@ -51,10 +52,11 @@ export default {
validations: { type: Object, default: () => ({}) },
loading: { type: Boolean, default: false },
slots: { type: Array, default: () => [] },
stepsById: { type: Object, default: () => ({}) },
},
emits: ['hide', 'update:model-value', 'update:new-attendance-sheet', 'submit'],
setup (props, { emit }) {
const { newAttendanceSheet, course, slots } = toRefs(props);
const { newAttendanceSheet, course, slots, stepsById } = toRefs(props);
const traineeOptions = computed(() => formatAndSortIdentityOptions(course.value.trainees));
Expand All @@ -66,16 +68,29 @@ export default {
return [...dateOptionsSet].map(date => ({ value: date, label: CompaniDate(date).format(DD_MM_YYYY) }));
});
const slotsGroupedByStep = computed(() => {
const groupedSlots = groupBy(slots.value, 'step');
return Object.keys(stepsById.value).reduce((acc, step) => {
if (groupedSlots[step]) acc[step] = groupedSlots[step];
return acc;
}, {});
});
const slotOptions = computed(() => (
[...slots.value]
.sort(ascendingSortBy('startDate'))
.map(s => ({
label: `${CompaniDate(s.startDate).format(`${DD_MM_YYYY} ${HH_MM}`)}
- ${CompaniDate(s.endDate).format(HH_MM)}`,
value: s._id,
}))
Object.values(slotsGroupedByStep.value)
.map(slotGroup => slotGroup.sort(ascendingSortBy('startDate'))
.map(s => ({
label: `${CompaniDate(s.startDate).format(`${DD_MM_YYYY} ${HH_MM}`)}
- ${CompaniDate(s.endDate).format(HH_MM)}`,
value: s._id,
})))
));
const stepsName = computed(() => Object.keys(slotsGroupedByStep.value)
.map(stepId => ({ label: stepsById.value[stepId].name })));
const hide = () => emit('hide');
const input = event => emit('update:model-value', event);
Expand All @@ -93,6 +108,7 @@ export default {
traineeOptions,
dateOptions,
slotOptions,
stepsName,
// Methods
hide,
input,
Expand Down
33 changes: 26 additions & 7 deletions src/core/components/courses/AttendanceSheetEditionModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
Modifier la <span class="text-weight-bold">feuille d'émargement</span>
</template>
<ni-select :model-value="editedAttendanceSheet.trainee" :options="traineeIdentity" disable />
<ni-option-group :model-value="editedAttendanceSheet.slots" in-modal required-field
@update:model-value="update($event, 'slots')" type="checkbox" inline :options="editionSlotOptions"
<ni-multiple-option-group :model-value="editedAttendanceSheet.slots" in-modal required-field
@update:model-value="update($event, 'slots')" type="checkbox" inline :options-groups="slotOptions"
caption="Sélectionner les créneaux auxquels a été présent·e le/la participant·e"
:error="validations.slots.$error" />
:error="validations.slots.$error" :group-titles="stepsName" />
<template #footer>
<ni-button class="full-width modal-btn bg-primary" label="Modifier la feuille d'émargement" :loading="loading"
icon-right="add" @click="submit" color="white" />
Expand All @@ -19,34 +19,51 @@
import { toRefs, computed } from 'vue';
import Modal from '@components/modal/Modal';
import Select from '@components/form/Select';
import OptionGroup from '@components/form/OptionGroup';
import MultipleOptionGroup from '@components/form/MultipleOptionGroup';
import Button from '@components/Button';
import { DD_MM_YYYY, HH_MM } from '@data/constants';
import { formatIdentity } from '@helpers/utils';
import { ascendingSortBy } from '@helpers/dates/utils';
import CompaniDate from '@helpers/dates/companiDates';
export default {
name: 'AttendanceSheetEditionModal',
components: {
'ni-modal': Modal,
'ni-select': Select,
'ni-option-group': OptionGroup,
'ni-multiple-option-group': MultipleOptionGroup,
'ni-button': Button,
},
props: {
modelValue: { type: Boolean, default: false },
editedAttendanceSheet: { type: Object, default: () => ({}) },
validations: { type: Object, default: () => ({}) },
loading: { type: Boolean, default: false },
editionSlotOptions: { type: Array, default: () => [] },
editionSlotsGroupedByStep: { type: Object, default: () => ({}) },
stepsById: { type: Object, default: () => ({}) },
},
emits: ['hide', 'update:model-value', 'submit', 'update:edited-attendance-sheet'],
setup (props, { emit }) {
const { editedAttendanceSheet } = toRefs(props);
const { editedAttendanceSheet, editionSlotsGroupedByStep, stepsById } = toRefs(props);
const traineeIdentity = computed(() => [{
label: formatIdentity(editedAttendanceSheet.value.trainee.identity, 'FL'),
value: editedAttendanceSheet.value.trainee,
}]);
const slotOptions = computed(() => (
Object.values(editionSlotsGroupedByStep.value)
.map(slotGroup => slotGroup.sort(ascendingSortBy('startDate'))
.map(s => ({
label: `${CompaniDate(s.startDate).format(`${DD_MM_YYYY} ${HH_MM}`)}
- ${CompaniDate(s.endDate).format(HH_MM)}`,
value: s._id,
})))
));
const stepsName = computed(() => Object.keys(editionSlotsGroupedByStep.value)
.map(stepId => ({ label: stepsById.value[stepId].name })));
const hide = () => emit('hide');
const input = event => emit('update:model-value', event);
Expand All @@ -61,6 +78,8 @@ export default {
return {
// Computed
traineeIdentity,
slotOptions,
stepsName,
// Methods
hide,
input,
Expand Down
10 changes: 5 additions & 5 deletions src/core/components/form/MultipleOptionGroup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
</div>
<div v-for="(options, index) in optionsGroups" :key="index">
<div class="group-title">
<q-icon :name="groupTitles[index].icon" size="sm" color="copper-grey-500" class="q-mr-xs" />
<q-icon v-if="groupTitles[index].icon" :name="groupTitles[index].icon" size="sm" color="copper-grey-500"
class="q-mr-xs" />
<div class="text-weight-bold">{{ groupTitles[index].label }}</div>
</div>
<q-field dense borderless class="col-12">
<q-option-group :model-value="modelValue" :options="options" type="radio" inline dense
<q-option-group :model-value="modelValue" :options="options" :type="type" inline :dense="type ==='radio'"
@update:model-value="update" />
</q-field>
</div>
Expand All @@ -29,9 +30,10 @@ export default {
caption: { type: String, default: '' },
error: { type: Boolean, default: false },
errorMessage: { type: String, default: REQUIRED_LABEL },
modelValue: { type: String, default: '' },
modelValue: { type: [String, Array, Boolean], default: '' },
optionsGroups: { type: Array, default: () => [] },
groupTitles: { type: Array, default: () => [] },
type: { type: String, default: 'radio' },
},
emits: ['update:model-value'],
methods: {
Expand All @@ -52,8 +54,6 @@ export default {
.required::after
content: ' *'
:deep(.q-option-group)
display: flex
flex-direction: column
color: $copper-grey-700 !important
.q-radio
padding: 10px 6px !important
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { ref, computed } from 'vue';
import { useQuasar } from 'quasar';
import get from 'lodash/get';
import keyBy from 'lodash/keyBy';
import groupBy from 'lodash/groupBy';
import useVuelidate from '@vuelidate/core';
import { required, requiredIf } from '@vuelidate/validators';
import AttendanceSheets from '@api/AttendanceSheets';
import { INTER_B2B, DD_MM_YYYY, HH_MM } from '@data/constants';
import { INTER_B2B, DD_MM_YYYY } from '@data/constants';
import { formatIdentity, sortStrings } from '@helpers/utils';
import CompaniDate from '@helpers/dates/companiDates';
import { ascendingSortBy } from '@helpers/dates/utils';
import { NotifyPositive, NotifyNegative, NotifyWarning } from '@components/popup/notify';

const SINGLE_COURSES_SUBPROGRAM_IDS = process.env.SINGLE_COURSES_SUBPROGRAM_IDS.split(';');
Expand All @@ -26,7 +27,7 @@ export const useAttendanceSheets = (
const attendanceSheets = ref([]);
const newAttendanceSheet = ref({ course: course.value._id });
const editedAttendanceSheet = ref({ _id: '', slots: [], trainee: {} });
const editionSlotOptions = ref([]);
const editionSlotsGroupedByStep = ref({});
const attendanceSheetColumns = ref([
{
name: 'date',
Expand All @@ -43,6 +44,7 @@ export const useAttendanceSheets = (
},
{ name: 'actions', label: '', align: 'left' },
]);
const stepsById = ref(keyBy(course.value.subProgram.steps, '_id'));

const isSingleCourse = computed(() => SINGLE_COURSES_SUBPROGRAM_IDS.includes(course.value.subProgram._id));

Expand Down Expand Up @@ -214,13 +216,13 @@ export const useAttendanceSheets = (
slots: linkedSlots.map(slot => slot._id),
trainee: attendanceSheet.trainee,
};
editionSlotOptions.value = [...linkedSlots, ...notLinkedSlotOptions.value]
.sort(ascendingSortBy('startDate'))
.map(s => ({
label: `${CompaniDate(s.startDate).format(`${DD_MM_YYYY} ${HH_MM}`)}
- ${CompaniDate(s.endDate).format(HH_MM)}`,
value: s._id,
}));

const groupedSlots = groupBy([...linkedSlots, ...notLinkedSlotOptions.value], 'step');
editionSlotsGroupedByStep.value = Object.keys(stepsById.value).reduce((acc, step) => {
if (groupedSlots[step]) acc[step] = groupedSlots[step];
return acc;
}, {});

attendanceSheetEditionModal.value = true;
};

Expand Down Expand Up @@ -248,7 +250,7 @@ export const useAttendanceSheets = (
const resetAttendanceSheetEditionModal = () => {
v$.value.editedAttendanceSheet.$reset();
editedAttendanceSheet.value = { _id: '', slots: [], trainee: {} };
editionSlotOptions.value = [];
editionSlotsGroupedByStep.value = {};
};

return {
Expand All @@ -260,11 +262,12 @@ export const useAttendanceSheets = (
attendanceSheetColumns,
attendanceSheetEditionModal,
editedAttendanceSheet,
stepsById,
// Computed
attendanceSheetVisibleColumns,
formattedAttendanceSheets,
notLinkedSlotOptions,
editionSlotOptions,
editionSlotsGroupedByStep,
isSingleCourse,
// Methods
disableSheetDeletion,
Expand Down
12 changes: 8 additions & 4 deletions src/core/components/table/AttendanceTable/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,12 @@

<attendance-sheet-addition-modal v-model="attendanceSheetAdditionModal" @hide="resetAttendanceSheetAdditionModal"
@submit="addAttendanceSheet" v-model:new-attendance-sheet="newAttendanceSheet" :loading="modalLoading"
:validations="attendanceSheetValidations.newAttendanceSheet" :course="course" :slots="notLinkedSlotOptions" />
:steps-by-id="stepsById" :validations="attendanceSheetValidations.newAttendanceSheet" :course="course"
:slots="notLinkedSlotOptions" />
<attendance-sheet-edition-modal v-model="attendanceSheetEditionModal" @hide="resetAttendanceSheetEditionModal"
@submit="updateAttendanceSheet" v-model:edited-attendance-sheet="editedAttendanceSheet" :loading="modalLoading"
:validations="attendanceSheetValidations.editedAttendanceSheet" :edition-slot-options="editionSlotOptions" />
:validations="attendanceSheetValidations.editedAttendanceSheet" :steps-by-id="stepsById"
:edition-slots-grouped-by-step="editionSlotsGroupedByStep" />
</div>
</template>

Expand Down Expand Up @@ -270,11 +272,12 @@ export default {
attendanceSheetColumns,
attendanceSheetEditionModal,
editedAttendanceSheet,
stepsById,
// Computed
attendanceSheetVisibleColumns,
formattedAttendanceSheets,
notLinkedSlotOptions,
editionSlotOptions,
editionSlotsGroupedByStep,
isSingleCourse,
// Methods
disableSheetDeletion,
Expand Down Expand Up @@ -321,6 +324,7 @@ export default {
attendancePagination,
attendanceSheetEditionModal,
editedAttendanceSheet,
stepsById,
// Computed
canAccessLearnerProfile,
attendanceColumns,
Expand All @@ -339,7 +343,7 @@ export default {
absenceRate,
realAbsenceRate,
notLinkedSlotOptions,
editionSlotOptions,
editionSlotsGroupedByStep,
isSingleCourse,
// Methods
get,
Expand Down
6 changes: 6 additions & 0 deletions src/modules/vendor/components/programs/StepAdditionModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -175,3 +175,9 @@ export default {
},
};
</script>

<style lang="sass" scoped>
:deep(.q-option-group)
display: flex
flex-direction: column
</style>

0 comments on commit 2018fe2

Please sign in to comment.