Skip to content

Commit

Permalink
Merge pull request #2088 from sophiemoustard/COM-3845
Browse files Browse the repository at this point in the history
Com 3845
  • Loading branch information
ulysseferreira authored Dec 3, 2024
2 parents 6064d1a + 8423e0c commit 38a013c
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 5 deletions.
3 changes: 3 additions & 0 deletions src/core/api/AttendanceSheets.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ export default {
formData.append('origin', WEBAPP);
await alenviAxios.post(`${process.env.API_HOSTNAME}/attendancesheets`, formData);
},
async update (attendanceSheetId, payload) {
await alenviAxios.put(`${process.env.API_HOSTNAME}/attendancesheets/${attendanceSheetId}`, payload);
},
async delete (attendanceSheetId) {
await alenviAxios.delete(`${process.env.API_HOSTNAME}/attendancesheets/${attendanceSheetId}`);
},
Expand Down
72 changes: 72 additions & 0 deletions src/core/components/courses/AttendanceSheetEditionModal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<template>
<ni-modal :model-value="modelValue" @hide="hide" @update:model-value="input">
<template #title>
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"
caption="Sélectionner les créneaux auxquels a été présent·e le/la participant·e"
:error="validations.slots.$error" />
<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" />
</template>
</ni-modal>
</template>

<script>
import { toRefs, computed } from 'vue';
import Modal from '@components/modal/Modal';
import Select from '@components/form/Select';
import OptionGroup from '@components/form/OptionGroup';
import Button from '@components/Button';
import { formatIdentity } from '@helpers/utils';
export default {
name: 'AttendanceSheetEditionModal',
components: {
'ni-modal': Modal,
'ni-select': Select,
'ni-option-group': OptionGroup,
'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: () => [] },
},
emits: ['hide', 'update:model-value', 'submit', 'update:edited-attendance-sheet'],
setup (props, { emit }) {
const { editedAttendanceSheet } = toRefs(props);
const traineeIdentity = computed(() => [{
label: formatIdentity(editedAttendanceSheet.value.trainee.identity, 'FL'),
value: editedAttendanceSheet.value.trainee,
}]);
const hide = () => emit('hide');
const input = event => emit('update:model-value', event);
const submit = () => emit('submit');
const update = (slotsValue, prop) => emit(
'update:edited-attendance-sheet',
{ ...editedAttendanceSheet.value, [prop]: slotsValue }
);
return {
// Computed
traineeIdentity,
// Methods
hide,
input,
submit,
update,
};
},
};
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import get from 'lodash/get';
import useVuelidate from '@vuelidate/core';
import { required, requiredIf } from '@vuelidate/validators';
import AttendanceSheets from '@api/AttendanceSheets';
import { INTER_B2B, DD_MM_YYYY } from '@data/constants';
import { INTER_B2B, DD_MM_YYYY, HH_MM } 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 @@ -21,8 +22,11 @@ export const useAttendanceSheets = (
const $q = useQuasar();
const attendanceSheetTableLoading = ref(false);
const attendanceSheetAdditionModal = ref(false);
const attendanceSheetEditionModal = ref(false);
const attendanceSheets = ref([]);
const newAttendanceSheet = ref({ course: course.value._id });
const editedAttendanceSheet = ref({ _id: '', slots: [], trainee: {} });
const editionSlotOptions = ref([]);
const attendanceSheetColumns = ref([
{
name: 'date',
Expand All @@ -49,9 +53,10 @@ export const useAttendanceSheets = (
date: { required: requiredIf(course.value.type !== INTER_B2B) },
slots: { required: requiredIf(isSingleCourse.value) },
},
editedAttendanceSheet: { slots: { required: requiredIf(isSingleCourse.value) } },
}));

const v$ = useVuelidate(attendanceSheetRules, { newAttendanceSheet });
const v$ = useVuelidate(attendanceSheetRules, { newAttendanceSheet, editedAttendanceSheet });

const attendanceSheetVisibleColumns = computed(() => (course.value.type === INTER_B2B
? ['trainee', 'actions']
Expand Down Expand Up @@ -86,11 +91,14 @@ export const useAttendanceSheets = (
const notLinkedSlotOptions = computed(() => {
if (!isSingleCourse.value) return [];

return course.value.slots.filter(s => attendanceSheets.value.every(as => !get(as, 'slots', []).includes(s._id)));
return course.value.slots
.filter(s => attendanceSheets.value.every(as => !get(as, 'slots', []).map(slot => slot._id).includes(s._id)));
});

const disableSheetDeletion = attendanceSheet => !attendanceSheet.file.link || !!course.value.archivedAt;

const disableSheetEdition = () => !!course.value.archivedAt;

const refreshAttendanceSheets = async () => {
try {
attendanceSheetTableLoading.value = true;
Expand Down Expand Up @@ -195,25 +203,81 @@ export const useAttendanceSheets = (
}
};

const openAttendanceSheetEditionModal = (attendanceSheet) => {
const linkedSlots = attendanceSheet.slots || [];
if (![...linkedSlots, ...notLinkedSlotOptions.value].length) {
return NotifyWarning('Tous les créneaux sont déjà rattachés à une feuille d\'émargement.');
}

editedAttendanceSheet.value = {
_id: attendanceSheet._id,
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,
}));
attendanceSheetEditionModal.value = true;
};

const updateAttendanceSheet = async () => {
try {
if (!canUpdate.value) return NotifyNegative('Impossible d\'éditer la feuille d\'émargement.');

v$.value.editedAttendanceSheet.$touch();
if (v$.value.editedAttendanceSheet.$error) return NotifyWarning('Champs(s) invalide(s)');
modalLoading.value = true;

await AttendanceSheets.update(editedAttendanceSheet.value._id, { slots: editedAttendanceSheet.value.slots });

attendanceSheetEditionModal.value = false;
NotifyPositive('Feuille d\'émargement modifiée.');
await refreshAttendanceSheets();
} catch (e) {
console.error(e);
NotifyNegative('Erreur lors de l\'édition de la feuille d\'émargement.');
} finally {
modalLoading.value = false;
}
};

const resetAttendanceSheetEditionModal = () => {
v$.value.editedAttendanceSheet.$reset();
editedAttendanceSheet.value = { _id: '', slots: [], trainee: {} };
editionSlotOptions.value = [];
};

return {
// Data
attendanceSheetTableLoading,
attendanceSheetAdditionModal,
attendanceSheets,
newAttendanceSheet,
attendanceSheetColumns,
attendanceSheetEditionModal,
editedAttendanceSheet,
// Computed
attendanceSheetVisibleColumns,
formattedAttendanceSheets,
notLinkedSlotOptions,
editionSlotOptions,
isSingleCourse,
// Methods
disableSheetDeletion,
disableSheetEdition,
refreshAttendanceSheets,
openAttendanceSheetAdditionModal,
resetAttendanceSheetAdditionModal,
addAttendanceSheet,
validateAttendanceSheetDeletion,
deleteAttendanceSheet,
openAttendanceSheetEditionModal,
updateAttendanceSheet,
resetAttendanceSheetEditionModal,
// Validations
attendanceSheetValidations: v$,
};
Expand Down
27 changes: 25 additions & 2 deletions src/core/components/table/AttendanceTable/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@
:style="col.style">
<template v-if="col.name === 'actions'">
<div class="row no-wrap table-actions justify-end">
<ni-button v-if="canUpdate && isSingleCourse" icon="edit" color="primary"
@click="openAttendanceSheetEditionModal(props.row)" :disable="disableSheetEdition(props.row)" />
<ni-button icon="file_download" color="primary" type="a" :href="props.row.file.link"
:disable="!props.row.file.link" />
<ni-button v-if="canUpdate" icon="delete" color="primary"
Expand All @@ -125,8 +127,11 @@
:trainees="traineesWithAttendance" @submit="addTrainee" />

<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" />
@submit="addAttendanceSheet" v-model:new-attendance-sheet="newAttendanceSheet" :loading="modalLoading"
: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" />
</div>
</template>

Expand All @@ -147,6 +152,7 @@ import SimpleTable from '@components/table/SimpleTable';
import AttendanceSheetAdditionModal from '@components/courses/AttendanceSheetAdditionModal';
import Indicator from '@components/courses/Indicator';
import TraineeAttendanceCreationModal from '../TraineeAttendanceCreationModal';
import AttendanceSheetEditionModal from '../../courses/AttendanceSheetEditionModal.vue';
import { useAttendances } from './Composables/Attendances';
import { useAttendanceSheets } from './Composables/AttendanceSheets';
Expand All @@ -160,6 +166,7 @@ export default {
'ni-simple-table': SimpleTable,
'trainee-attendance-creation-modal': TraineeAttendanceCreationModal,
'attendance-sheet-addition-modal': AttendanceSheetAdditionModal,
'attendance-sheet-edition-modal': AttendanceSheetEditionModal,
'ni-indicator': Indicator,
},
setup (props) {
Expand Down Expand Up @@ -261,17 +268,25 @@ export default {
attendanceSheetAdditionModal,
newAttendanceSheet,
attendanceSheetColumns,
attendanceSheetEditionModal,
editedAttendanceSheet,
// Computed
attendanceSheetVisibleColumns,
formattedAttendanceSheets,
notLinkedSlotOptions,
editionSlotOptions,
isSingleCourse,
// Methods
disableSheetDeletion,
disableSheetEdition,
refreshAttendanceSheets,
openAttendanceSheetAdditionModal,
resetAttendanceSheetAdditionModal,
addAttendanceSheet,
validateAttendanceSheetDeletion,
resetAttendanceSheetEditionModal,
updateAttendanceSheet,
openAttendanceSheetEditionModal,
// Validations
attendanceSheetValidations,
} = useAttendanceSheets(course, isClientInterface, canUpdate, loggedUser, modalLoading);
Expand Down Expand Up @@ -304,6 +319,8 @@ export default {
attendanceSheetColumns,
attendanceSheetPagination,
attendancePagination,
attendanceSheetEditionModal,
editedAttendanceSheet,
// Computed
canAccessLearnerProfile,
attendanceColumns,
Expand All @@ -322,10 +339,13 @@ export default {
absenceRate,
realAbsenceRate,
notLinkedSlotOptions,
editionSlotOptions,
isSingleCourse,
// Methods
get,
attendanceCheckboxValue,
disableSheetDeletion,
disableSheetEdition,
traineesCount,
openAttendanceSheetAdditionModal,
resetAttendanceSheetAdditionModal,
Expand All @@ -339,7 +359,10 @@ export default {
updateSlotCheckbox,
getDelimiterClass,
goToLearnerProfile,
resetAttendanceSheetEditionModal,
updateAttendanceSheet,
formatQuantity,
openAttendanceSheetEditionModal,
// Validations
attendanceSheetValidations,
attendanceValidations,
Expand Down

0 comments on commit 38a013c

Please sign in to comment.