feat(heures) : calendrier des jours validés (vue Jour) + harmonisation Malio UI
- Calendrier MalioDate en vue Jour (Heures + Heures Conducteurs) : jours entièrement validés (admin) peints en vert. Endpoint GET /work-hours/validation-status?from=&to=[&driver=1] (scope conducteur inversé), chargement à la volée par mois, refresh après validation/saisie/absence. - Suite à @malio/layer-ui 1.7.11 : reserveMessageSpace=false sur les champs ; tous les drawers migrés sur MalioDrawer (titre via slot #header, AppDrawer custom supprimé) ; boutons d'action en MalioButton (deux boutons partagent l'espace) ; inputs date en MalioDate ; MalioDateWeek en vue Semaine. - Boutons d'ajout uniformisés sur « Ajouter » + icône. - .env : EXCLUDED_PUBLIC_HOLIDAYS="null". - Doc : doc/hours-validated-days.md, documentation-content.ts, CLAUDE.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
<div class="flex items-center justify-between pb-6">
|
||||
<h1 class="text-4xl font-bold text-primary-500">Types de statut</h1>
|
||||
<MalioButton
|
||||
label="Ajouter un type"
|
||||
label="Ajouter"
|
||||
icon-name="mdi:plus"
|
||||
icon-position="left"
|
||||
@click="openCreate"
|
||||
@@ -55,16 +55,19 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<MalioDrawer v-model="isDrawerOpen" :title="drawerTitle">
|
||||
<MalioDrawer v-model="isDrawerOpen">
|
||||
<template #header>
|
||||
<h2 class="text-[32px] font-semibold text-primary-500">{{ drawerTitle }}</h2>
|
||||
</template>
|
||||
<form class="space-y-4" @submit.prevent="handleSubmit">
|
||||
<MalioInputText
|
||||
<MalioInputText :reserve-message-space="false"
|
||||
v-model="form.code"
|
||||
label="Code *"
|
||||
group-class="mt-2"
|
||||
:max-length="10"
|
||||
:error="showCodeError ? 'Le code est obligatoire.' : ''"
|
||||
/>
|
||||
<MalioInputText
|
||||
<MalioInputText :reserve-message-space="false"
|
||||
v-model="form.label"
|
||||
label="Libellé *"
|
||||
group-class="mt-2"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
</div>
|
||||
<div class="flex flex-col gap-3 py-6">
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<MalioSelectCheckbox
|
||||
<MalioSelectCheckbox :reserve-message-space="false"
|
||||
v-model="selectedSiteIds"
|
||||
:options="siteOptions"
|
||||
label="Sites"
|
||||
@@ -14,7 +14,7 @@
|
||||
/>
|
||||
<div class="flex gap-4">
|
||||
<MalioButton
|
||||
label="Ajouter une absence"
|
||||
label="Ajouter"
|
||||
icon-name="mdi:plus"
|
||||
icon-position="left"
|
||||
@click="openCreateFromToday"
|
||||
@@ -31,7 +31,7 @@
|
||||
<div class="flex justify-between">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="w-80">
|
||||
<MalioInputText
|
||||
<MalioInputText :reserve-message-space="false"
|
||||
v-model="employeeFilter"
|
||||
label="Recherche d'un employé"
|
||||
icon-name="mdi:magnify"
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
:sites="sites"
|
||||
:absence-types="absenceTypes"
|
||||
:formatted-selected-date="formattedSelectedDate"
|
||||
:show-validation-calendar="true"
|
||||
:marked-dates="markedDates"
|
||||
:shortcut-button-class="shortcutButtonClass"
|
||||
:week-shortcut-button-class="weekShortcutButtonClass"
|
||||
:get-week-shortcut-label="getWeekShortcutLabel"
|
||||
@@ -23,6 +25,7 @@
|
||||
@set-this-week="setThisWeek"
|
||||
@set-next-week="setNextWeek"
|
||||
@shift-date="shiftDate"
|
||||
@month-change="onCalendarMonthChange"
|
||||
/>
|
||||
|
||||
<div v-if="isLoading" class="rounded-lg border border-neutral-200 bg-white p-6 text-md text-neutral-600">
|
||||
@@ -193,6 +196,8 @@ const {
|
||||
isSelectedDateHoliday,
|
||||
selectedHolidayLabel,
|
||||
handleSave,
|
||||
markedDates,
|
||||
onCalendarMonthChange,
|
||||
isWeekCommentDrawerOpen,
|
||||
weekCommentContext,
|
||||
openWeekCommentDrawer,
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="showPicker" class="mt-3 flex items-center gap-3">
|
||||
<MalioSelect
|
||||
<MalioSelect :reserve-message-space="false"
|
||||
label="Contrat"
|
||||
:model-value="selectedPhase?.id ?? null"
|
||||
:options="phaseOptions"
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
@click="openExportDrawer"
|
||||
/>
|
||||
<MalioButton
|
||||
label="Ajouter un employé"
|
||||
label="Ajouter"
|
||||
icon-name="mdi:plus"
|
||||
icon-position="left"
|
||||
@click="openCreate"
|
||||
@@ -21,14 +21,14 @@
|
||||
</div>
|
||||
<div class="flex items-center gap-3 py-7">
|
||||
<div class="w-80">
|
||||
<MalioInputText
|
||||
<MalioInputText :reserve-message-space="false"
|
||||
v-model="employeeFilter"
|
||||
label="Recherche d'un employé"
|
||||
icon-name="mdi:magnify"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="sites.length > 0" class="relative z-50 w-80">
|
||||
<MalioSelectCheckbox
|
||||
<MalioSelectCheckbox :reserve-message-space="false"
|
||||
v-model="selectedSiteIds"
|
||||
:options="siteOptions"
|
||||
groupClass="w-80"
|
||||
@@ -37,7 +37,7 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<MalioSelect
|
||||
<MalioSelect :reserve-message-space="false"
|
||||
v-model="contractStatusFilter"
|
||||
label="Statut contrat"
|
||||
:options="contractStatusOptions"
|
||||
@@ -84,21 +84,24 @@
|
||||
</NuxtLink>
|
||||
</div>
|
||||
|
||||
<MalioDrawer v-model="isDrawerOpen" :title="drawerTitle">
|
||||
<MalioDrawer v-model="isDrawerOpen">
|
||||
<template #header>
|
||||
<h2 class="text-[32px] font-semibold text-primary-500">{{ drawerTitle }}</h2>
|
||||
</template>
|
||||
<form class="space-y-4" @submit.prevent="handleSubmit">
|
||||
<MalioInputText
|
||||
<MalioInputText :reserve-message-space="false"
|
||||
v-model="form.firstName"
|
||||
label="Prénom *"
|
||||
group-class="mt-2"
|
||||
:error="showFirstNameError ? 'Le prénom est obligatoire.' : ''"
|
||||
/>
|
||||
<MalioInputText
|
||||
<MalioInputText :reserve-message-space="false"
|
||||
v-model="form.lastName"
|
||||
label="Nom *"
|
||||
group-class="mt-2"
|
||||
:error="showLastNameError ? 'Le nom est obligatoire.' : ''"
|
||||
/>
|
||||
<MalioSelect
|
||||
<MalioSelect :reserve-message-space="false"
|
||||
:model-value="form.siteId === '' ? null : form.siteId"
|
||||
:options="formSiteOptions"
|
||||
label="Site *"
|
||||
@@ -107,7 +110,7 @@
|
||||
@update:model-value="(v) => { form.siteId = v === null ? '' : Number(v) }"
|
||||
/>
|
||||
<template v-if="!editingEmployee">
|
||||
<MalioSelect
|
||||
<MalioSelect :reserve-message-space="false"
|
||||
:model-value="form.contractNature"
|
||||
:options="contractNatureFormOptions"
|
||||
label="Type de contrat *"
|
||||
@@ -115,7 +118,7 @@
|
||||
:error="showContractNatureError ? 'Le type de contrat est obligatoire.' : ''"
|
||||
@update:model-value="(v) => { if (v !== null) form.contractNature = v as 'CDI' | 'CDD' | 'INTERIM' }"
|
||||
/>
|
||||
<MalioSelect
|
||||
<MalioSelect :reserve-message-space="false"
|
||||
v-if="form.contractNature === 'INTERIM'"
|
||||
:model-value="form.interimAgencyId === '' ? null : form.interimAgencyId"
|
||||
:options="interimAgencyOptions"
|
||||
@@ -123,7 +126,7 @@
|
||||
min-width=""
|
||||
@update:model-value="(v) => { form.interimAgencyId = v === null ? '' : Number(v) }"
|
||||
/>
|
||||
<MalioSelect
|
||||
<MalioSelect :reserve-message-space="false"
|
||||
:model-value="form.contractId === '' ? null : form.contractId"
|
||||
:options="contractFormOptions"
|
||||
label="Temps de travail *"
|
||||
@@ -131,37 +134,27 @@
|
||||
:error="showContractError ? 'Le temps de travail est obligatoire.' : ''"
|
||||
@update:model-value="(v) => { form.contractId = v === null ? '' : Number(v) }"
|
||||
/>
|
||||
<div>
|
||||
<label class="text-md font-semibold text-neutral-700" for="contract-start-date">
|
||||
Début contrat <span class="text-red-600">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="contract-start-date"
|
||||
v-model="form.contractStartDate"
|
||||
type="date"
|
||||
:class="[dateInputBaseClass, form.contractStartDate ? 'border-black' : 'border-m-muted', showContractStartDateError ? '!border-m-danger' : '']"
|
||||
/>
|
||||
<p v-if="showContractStartDateError" class="mt-1 text-sm text-red-600">
|
||||
La date de début est obligatoire.
|
||||
</p>
|
||||
</div>
|
||||
<div v-if="showsContractEndDateComputed">
|
||||
<label class="text-md font-semibold text-neutral-700" for="contract-end-date">
|
||||
Fin contrat
|
||||
<span v-if="requiresContractEndDateComputed" class="text-red-600">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="contract-end-date"
|
||||
v-model="form.contractEndDate"
|
||||
type="date"
|
||||
:class="[dateInputBaseClass, form.contractEndDate ? 'border-black' : 'border-m-muted', showContractEndDateError ? '!border-m-danger' : '']"
|
||||
/>
|
||||
<p v-if="showContractEndDateError" class="mt-1 text-sm text-red-600">
|
||||
La date de fin est obligatoire pour un CDD ou un Intérim.
|
||||
</p>
|
||||
</div>
|
||||
<MalioDate
|
||||
:model-value="form.contractStartDate"
|
||||
label="Début contrat"
|
||||
required
|
||||
:reserve-message-space="false"
|
||||
:error="showContractStartDateError ? 'La date de début est obligatoire.' : ''"
|
||||
group-class="w-full"
|
||||
@update:model-value="(v) => form.contractStartDate = v ?? ''"
|
||||
/>
|
||||
<MalioDate
|
||||
v-if="showsContractEndDateComputed"
|
||||
:model-value="form.contractEndDate"
|
||||
label="Fin contrat"
|
||||
:required="requiresContractEndDateComputed"
|
||||
:reserve-message-space="false"
|
||||
:error="showContractEndDateError ? 'La date de fin est obligatoire pour un CDD ou un Intérim.' : ''"
|
||||
group-class="w-full"
|
||||
@update:model-value="(v) => form.contractEndDate = v ?? ''"
|
||||
/>
|
||||
<div class="flex h-10 items-center rounded-md border border-neutral-200 bg-neutral-50 px-3">
|
||||
<MalioCheckbox
|
||||
<MalioCheckbox :reserve-message-space="false"
|
||||
v-model="form.isDriver"
|
||||
label="Chauffeur"
|
||||
group-class="flex items-center"
|
||||
@@ -173,24 +166,29 @@
|
||||
:contract-weekly-hours="selectedContract?.weeklyHours ?? null"
|
||||
/>
|
||||
</template>
|
||||
<div class="flex justify-end gap-3 pt-2">
|
||||
<div class="grid grid-cols-2 gap-3 pt-2">
|
||||
<MalioButton
|
||||
label="Annuler"
|
||||
variant="tertiary"
|
||||
button-class="w-full"
|
||||
@click="isDrawerOpen = false"
|
||||
/>
|
||||
<MalioButton
|
||||
type="submit"
|
||||
label="Enregistrer"
|
||||
button-class="w-full"
|
||||
:disabled="isSubmitting || !isFormValid"
|
||||
@click="handleSubmit"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</MalioDrawer>
|
||||
|
||||
<MalioDrawer v-model="isExportDrawerOpen" title="Export">
|
||||
<MalioDrawer v-model="isExportDrawerOpen">
|
||||
<template #header>
|
||||
<h2 class="text-[32px] font-semibold text-primary-500">Export</h2>
|
||||
</template>
|
||||
<div class="space-y-4">
|
||||
<MalioSelect
|
||||
<MalioSelect :reserve-message-space="false"
|
||||
:model-value="exportChoice === '' ? null : exportChoice"
|
||||
:options="exportTypeOptions"
|
||||
label="Type d'export"
|
||||
@@ -213,14 +211,14 @@
|
||||
</div>
|
||||
|
||||
<template v-else-if="exportChoice === 'yearly-hours'">
|
||||
<MalioSelect
|
||||
<MalioSelect :reserve-message-space="false"
|
||||
:model-value="exportYear"
|
||||
:options="exportYearOptions"
|
||||
label="Année *"
|
||||
min-width=""
|
||||
@update:model-value="(v) => { if (v !== null) exportYear = Number(v) }"
|
||||
/>
|
||||
<MalioSelect
|
||||
<MalioSelect :reserve-message-space="false"
|
||||
:model-value="exportMonth === '' ? null : exportMonth"
|
||||
:options="exportMonthOptions"
|
||||
label="Mois *"
|
||||
@@ -231,7 +229,7 @@
|
||||
</template>
|
||||
|
||||
<div v-else-if="exportChoice === 'night-contingent'">
|
||||
<MalioSelect
|
||||
<MalioSelect :reserve-message-space="false"
|
||||
:model-value="exportYear"
|
||||
:options="exportYearOptions"
|
||||
label="Année *"
|
||||
@@ -241,14 +239,14 @@
|
||||
</div>
|
||||
|
||||
<div v-else-if="exportChoice === 'overtime-contingent'" class="flex flex-col gap-4">
|
||||
<MalioSelect
|
||||
<MalioSelect :reserve-message-space="false"
|
||||
:model-value="exportYear"
|
||||
:options="exportYearOptions"
|
||||
label="Année *"
|
||||
min-width=""
|
||||
@update:model-value="(v) => { if (v !== null) exportYear = Number(v) }"
|
||||
/>
|
||||
<MalioSelectCheckbox
|
||||
<MalioSelectCheckbox :reserve-message-space="false"
|
||||
v-model="exportSiteIds"
|
||||
:options="siteOptions"
|
||||
label="Sites"
|
||||
@@ -467,9 +465,6 @@ const showContractEndDateError = computed(
|
||||
() => !editingEmployee.value && validationTouched.contractEndDate && !isContractEndDateValid.value
|
||||
)
|
||||
|
||||
const dateInputBaseClass =
|
||||
'mt-2 h-10 w-full rounded-md border px-3 text-md text-black outline-none focus:border-2 focus:border-m-primary'
|
||||
|
||||
const formSiteOptions = computed(() =>
|
||||
sites.value.map((site) => ({ label: site.name, value: site.id }))
|
||||
)
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
:sites="sites"
|
||||
:absence-types="absenceTypes"
|
||||
:formatted-selected-date="formattedSelectedDate"
|
||||
:show-validation-calendar="true"
|
||||
:marked-dates="markedDates"
|
||||
:shortcut-button-class="shortcutButtonClass"
|
||||
:week-shortcut-button-class="weekShortcutButtonClass"
|
||||
:get-week-shortcut-label="getWeekShortcutLabel"
|
||||
@@ -39,6 +41,7 @@
|
||||
@set-this-week="setThisWeek"
|
||||
@set-next-week="setNextWeek"
|
||||
@shift-date="shiftDate"
|
||||
@month-change="onCalendarMonthChange"
|
||||
/>
|
||||
|
||||
<div v-if="isLoading" class="rounded-lg border border-neutral-200 bg-white p-6 text-md text-neutral-600">
|
||||
@@ -225,6 +228,8 @@ const {
|
||||
closeAbsenceDrawer,
|
||||
formatMinutes,
|
||||
handleSave,
|
||||
markedDates,
|
||||
onCalendarMonthChange,
|
||||
isWeekCommentDrawerOpen,
|
||||
weekCommentContext,
|
||||
openWeekCommentDrawer,
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
class="mt-8 space-y-6 rounded-lg border border-neutral-200 bg-white p-6 shadow-sm"
|
||||
@submit.prevent="handleSubmit"
|
||||
>
|
||||
<MalioInputText
|
||||
<MalioInputText :reserve-message-space="false"
|
||||
v-model="username"
|
||||
label="Nom d'utilisateur"
|
||||
autocomplete="username"
|
||||
group-class="mt-2"
|
||||
/>
|
||||
|
||||
<MalioInputPassword
|
||||
<MalioInputPassword :reserve-message-space="false"
|
||||
v-model="password"
|
||||
label="Mot de passe"
|
||||
autocomplete="current-password"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="flex items-center justify-between pb-6">
|
||||
<h1 class="text-4xl font-bold text-primary-500">Sites</h1>
|
||||
<MalioButton
|
||||
label="Ajouter un site"
|
||||
label="Ajouter"
|
||||
icon-name="mdi:plus"
|
||||
icon-position="left"
|
||||
@click="openCreate"
|
||||
@@ -51,9 +51,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<MalioDrawer v-model="isDrawerOpen" :title="drawerTitle">
|
||||
<MalioDrawer v-model="isDrawerOpen">
|
||||
<template #header>
|
||||
<h2 class="text-[32px] font-semibold text-primary-500">{{ drawerTitle }}</h2>
|
||||
</template>
|
||||
<form class="space-y-4" @submit.prevent="handleSubmit">
|
||||
<MalioInputText
|
||||
<MalioInputText :reserve-message-space="false"
|
||||
v-model="form.name"
|
||||
label="Nom *"
|
||||
group-class="mt-2"
|
||||
|
||||
@@ -94,10 +94,12 @@
|
||||
|
||||
<MalioDrawer
|
||||
v-model="isDrawerOpen"
|
||||
:title="editingUser ? 'Modifier un utilisateur' : 'Ajouter un utilisateur'"
|
||||
>
|
||||
<template #header>
|
||||
<h2 class="text-[32px] font-semibold text-primary-500">{{ editingUser ? 'Modifier un utilisateur' : 'Ajouter un utilisateur' }}</h2>
|
||||
</template>
|
||||
<form class="space-y-4" @submit.prevent="handleSubmit">
|
||||
<MalioInputText
|
||||
<MalioInputText :reserve-message-space="false"
|
||||
v-model="form.username"
|
||||
:label="editingUser ? `Nom d'utilisateur` : `Nom d'utilisateur *`"
|
||||
group-class="mt-2"
|
||||
@@ -105,7 +107,7 @@
|
||||
/>
|
||||
|
||||
<div>
|
||||
<MalioInputPassword
|
||||
<MalioInputPassword :reserve-message-space="false"
|
||||
v-model="form.password"
|
||||
:label="editingUser ? 'Mot de passe' : 'Mot de passe *'"
|
||||
:hint="editingUser ? 'Laisse vide pour ne pas changer le mot de passe.' : ''"
|
||||
@@ -153,7 +155,7 @@
|
||||
</div>
|
||||
|
||||
<div v-if="form.accessMode === 'self'">
|
||||
<MalioSelect
|
||||
<MalioSelect :reserve-message-space="false"
|
||||
:model-value="form.employeeId === '' ? null : form.employeeId"
|
||||
:options="employeeOptions"
|
||||
label="Employé lié"
|
||||
@@ -172,7 +174,7 @@
|
||||
:key="site.id"
|
||||
class="flex h-10 items-center rounded-md border border-neutral-200 px-3"
|
||||
>
|
||||
<MalioCheckbox
|
||||
<MalioCheckbox :reserve-message-space="false"
|
||||
:model-value="form.siteIds.includes(site.id)"
|
||||
:label="site.name"
|
||||
group-class="flex items-center"
|
||||
@@ -186,7 +188,7 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<MalioCheckbox
|
||||
<MalioCheckbox :reserve-message-space="false"
|
||||
v-model="form.isLocked"
|
||||
label="Verrouiller le compte"
|
||||
hint="Un compte verrouillé ne peut plus se connecter."
|
||||
@@ -194,7 +196,7 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<MalioCheckbox
|
||||
<MalioCheckbox :reserve-message-space="false"
|
||||
v-model="form.hasLeaveRecapAccess"
|
||||
label="Accès à l'écran Récap. congés"
|
||||
hint="Affiche l'onglet dans la sidebar et donne accès au tableau récap."
|
||||
|
||||
Reference in New Issue
Block a user