feat(heures) : calendrier des jours validés (vue Jour) + harmonisation Malio UI (#30)
Auto Tag Develop / tag (push) Successful in 10s
Auto Tag Develop / tag (push) Successful in 10s
## Fonctionnel - Calendrier MalioDate en vue Jour (écrans Heures ET Heures Conducteurs) : les jours entièrement validés par un admin sont peints en vert. - Endpoint `GET /work-hours/validation-status?from=&to=[&driver=1]` (scope conducteur inversé via `driver=1`), périmètre complet (ignore le filtre sites). - Chargement à la volée par mois (event `@month-change`), refresh après validation / saisie / absence. ## Harmonisation @malio/layer-ui 1.7.11 - `reserveMessageSpace=false` sur tous les champs (alignement). - Tous les drawers migrés sur `MalioDrawer` (titre via slot `#header`, `AppDrawer` custom supprimé). - Boutons d'action en `MalioButton` ; deux boutons côte à côte partagent l'espace. - Inputs date en `MalioDate`, sélecteur semaine en `MalioDateWeek`. - Boutons d'ajout uniformisés sur « Ajouter » + icône. ## Divers - `.env` : `EXCLUDED_PUBLIC_HOLIDAYS="null"`. - Doc : `doc/hours-validated-days.md`, `documentation-content.ts`, `CLAUDE.md`. - Tests : provider `WorkHourValidationStatus` (suite complète 236/236 OK via pre-commit hook). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: #30 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
This commit was merged in pull request #30.
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
<template>
|
||||
<AppDrawer v-model="drawerOpen" title="Nouvelle absence">
|
||||
<MalioDrawer v-model="drawerOpen">
|
||||
<template #header>
|
||||
<h2 class="text-[32px] font-semibold text-primary-500">Nouvelle absence</h2>
|
||||
</template>
|
||||
<form class="space-y-4" @submit.prevent="handleSubmit">
|
||||
<MalioSelect
|
||||
<MalioSelect :reserve-message-space="false"
|
||||
:model-value="absenceForm.employeeId === '' ? null : absenceForm.employeeId"
|
||||
:options="employeeOptions"
|
||||
label="Employé *"
|
||||
@@ -12,7 +15,7 @@
|
||||
@update:model-value="onEmployeeChange"
|
||||
/>
|
||||
|
||||
<MalioSelect
|
||||
<MalioSelect :reserve-message-space="false"
|
||||
:model-value="absenceForm.typeId === '' ? null : absenceForm.typeId"
|
||||
:options="typeOptions"
|
||||
label="Type d'absence *"
|
||||
@@ -24,16 +27,16 @@
|
||||
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="text-md font-semibold text-neutral-700" for="start-date">Début</label>
|
||||
<div class="mt-2 grid grid-cols-2 gap-2">
|
||||
<input
|
||||
id="start-date"
|
||||
<label class="text-md font-semibold text-neutral-700">Début</label>
|
||||
<div class="mt-2 space-y-2">
|
||||
<MalioDate
|
||||
v-model="absenceForm.startDate"
|
||||
type="date"
|
||||
:class="[dateInputBaseClass, absenceForm.startDate ? 'border-black' : 'border-m-muted']"
|
||||
:clearable="false"
|
||||
:reserve-message-space="false"
|
||||
:disabled="props.lockDates"
|
||||
group-class="w-full"
|
||||
/>
|
||||
<MalioSelect
|
||||
<MalioSelect :reserve-message-space="false"
|
||||
:model-value="absenceForm.startHalf"
|
||||
:options="halfDayOptions"
|
||||
min-width=""
|
||||
@@ -42,16 +45,16 @@
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-md font-semibold text-neutral-700" for="end-date">Fin</label>
|
||||
<div class="mt-2 grid grid-cols-2 gap-2">
|
||||
<input
|
||||
id="end-date"
|
||||
<label class="text-md font-semibold text-neutral-700">Fin</label>
|
||||
<div class="mt-2 space-y-2">
|
||||
<MalioDate
|
||||
v-model="absenceForm.endDate"
|
||||
type="date"
|
||||
:class="[dateInputBaseClass, absenceForm.endDate ? 'border-black' : 'border-m-muted']"
|
||||
:clearable="false"
|
||||
:reserve-message-space="false"
|
||||
:disabled="props.lockDates"
|
||||
group-class="w-full"
|
||||
/>
|
||||
<MalioSelect
|
||||
<MalioSelect :reserve-message-space="false"
|
||||
:model-value="absenceForm.endHalf"
|
||||
:options="halfDayOptions"
|
||||
min-width=""
|
||||
@@ -72,31 +75,30 @@
|
||||
</div>
|
||||
|
||||
<div v-if="editingAbsence" class="grid grid-cols-2 gap-3 pt-2">
|
||||
<button
|
||||
type="button"
|
||||
class="flex items-center justify-center rounded-md bg-red-500 px-4 py-2 text-md font-semibold text-white hover:bg-red-600"
|
||||
<MalioButton
|
||||
label="Supprimer"
|
||||
variant="danger"
|
||||
button-class="w-full"
|
||||
@click="handleDelete"
|
||||
>
|
||||
Supprimer
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="flex items-center justify-center rounded-md bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500"
|
||||
:class="submitButtonClass"
|
||||
>
|
||||
Modifier
|
||||
</button>
|
||||
/>
|
||||
<MalioButton
|
||||
label="Modifier"
|
||||
variant="primary"
|
||||
button-class="w-full"
|
||||
:disabled="props.isSubmitting || !isFormValid"
|
||||
@click="handleSubmit"
|
||||
/>
|
||||
</div>
|
||||
<div v-else class="flex justify-center pt-2">
|
||||
<MalioButton
|
||||
type="submit"
|
||||
label="Valider"
|
||||
button-class="w-[200px]"
|
||||
:disabled="props.isSubmitting || !isFormValid"
|
||||
@click="handleSubmit"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</AppDrawer>
|
||||
</MalioDrawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
@@ -106,7 +108,6 @@ import type { AbsenceType } from '~/services/dto/absence-type'
|
||||
import type { Absence } from '~/services/dto/absence'
|
||||
import type { HalfDay } from '~/services/dto/half-day'
|
||||
import { HALF_DAYS } from '~/services/dto/half-day'
|
||||
import AppDrawer from '~/components/AppDrawer.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: boolean
|
||||
@@ -159,13 +160,6 @@ const showTypeError = computed(
|
||||
() => validationTouched.type && !isTypeValid.value
|
||||
)
|
||||
|
||||
const submitButtonClass = computed(() => {
|
||||
if (props.isSubmitting || !isFormValid.value) {
|
||||
return 'opacity-50 cursor-not-allowed'
|
||||
}
|
||||
return ''
|
||||
})
|
||||
|
||||
const employeeOptions = computed(() =>
|
||||
props.employees.map((e) => ({ label: `${e.firstName} ${e.lastName}`, value: e.id }))
|
||||
)
|
||||
@@ -174,9 +168,6 @@ const typeOptions = computed(() =>
|
||||
)
|
||||
const halfDayOptions = HALF_DAYS.map((h) => ({ label: h.label, value: h.value }))
|
||||
|
||||
const dateInputBaseClass =
|
||||
'h-10 w-full rounded-md border px-3 text-md text-black outline-none focus:border-2 focus:border-m-primary'
|
||||
|
||||
const onEmployeeChange = (value: string | number | null) => {
|
||||
absenceForm.value.employeeId = value === null ? '' : Number(value)
|
||||
}
|
||||
|
||||
@@ -1,36 +1,28 @@
|
||||
<template>
|
||||
<AppDrawer v-model="drawerOpen" title="Imprimer les absences">
|
||||
<MalioDrawer v-model="drawerOpen">
|
||||
<template #header>
|
||||
<h2 class="text-[32px] font-semibold text-primary-500">Imprimer les absences</h2>
|
||||
</template>
|
||||
<form class="space-y-4" @submit.prevent="handleSubmit">
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="text-md font-semibold text-neutral-700" for="print-from">
|
||||
Date de début <span class="text-red-600">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="print-from"
|
||||
v-model="printForm.from"
|
||||
type="date"
|
||||
:class="fromFieldClass"
|
||||
/>
|
||||
<p v-if="showFromError" class="mt-1 text-sm text-red-600">
|
||||
La date de début est obligatoire.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<label class="text-md font-semibold text-neutral-700" for="print-to">
|
||||
Date de fin <span class="text-red-600">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="print-to"
|
||||
v-model="printForm.to"
|
||||
type="date"
|
||||
:class="toFieldClass"
|
||||
/>
|
||||
<p v-if="showToError" class="mt-1 text-sm text-red-600">
|
||||
La date de fin est obligatoire.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<MalioDate
|
||||
v-model="printForm.from"
|
||||
label="Date de début"
|
||||
required
|
||||
:clearable="false"
|
||||
:reserve-message-space="false"
|
||||
:error="showFromError ? 'La date de début est obligatoire.' : ''"
|
||||
group-class="w-full"
|
||||
/>
|
||||
|
||||
<MalioDate
|
||||
v-model="printForm.to"
|
||||
label="Date de fin"
|
||||
required
|
||||
:clearable="false"
|
||||
:reserve-message-space="false"
|
||||
:error="showToError ? 'La date de fin est obligatoire.' : ''"
|
||||
group-class="w-full"
|
||||
/>
|
||||
|
||||
<div class="space-y-2">
|
||||
<p class="text-md font-semibold text-neutral-700">
|
||||
@@ -97,21 +89,19 @@
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center pt-2">
|
||||
<button
|
||||
type="submit"
|
||||
class="flex w-[200px] items-center justify-center gap-2 rounded-md bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500"
|
||||
:class="submitButtonClass"
|
||||
>
|
||||
Imprimer
|
||||
</button>
|
||||
<MalioButton
|
||||
label="Imprimer"
|
||||
variant="primary"
|
||||
:button-class="submitButtonClass"
|
||||
@click="handleSubmit"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</AppDrawer>
|
||||
</MalioDrawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, reactive, toRef, watch } from 'vue'
|
||||
import AppDrawer from '~/components/AppDrawer.vue'
|
||||
|
||||
type SiteOption = {
|
||||
id: number
|
||||
@@ -190,21 +180,6 @@ const showSitesError = computed(() => validationTouched.sites && !isSitesValid.v
|
||||
const showContractNaturesError = computed(() => validationTouched.contractNatures && !isContractNaturesValid.value)
|
||||
const showWorkContractsError = computed(() => validationTouched.workContracts && !isWorkContractsValid.value)
|
||||
|
||||
const baseInputClass =
|
||||
'mt-2 w-full rounded-md border px-3 py-2 text-md text-neutral-900'
|
||||
const fromFieldClass = computed(() => {
|
||||
if (showFromError.value) {
|
||||
return `${baseInputClass} border-red-500`
|
||||
}
|
||||
return `${baseInputClass} border-neutral-300`
|
||||
})
|
||||
const toFieldClass = computed(() => {
|
||||
if (showToError.value) {
|
||||
return `${baseInputClass} border-red-500`
|
||||
}
|
||||
return `${baseInputClass} border-neutral-300`
|
||||
})
|
||||
|
||||
const submitButtonClass = computed(() => {
|
||||
if (!isFormValid.value) {
|
||||
return 'opacity-50 cursor-not-allowed'
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
<template>
|
||||
<div v-if="modelValue" class="fixed inset-0 z-[60]">
|
||||
<Transition name="drawer-backdrop">
|
||||
<div class="absolute inset-0 bg-black/40" @click="close" />
|
||||
</Transition>
|
||||
<Transition name="drawer-panel">
|
||||
<div class="absolute right-0 top-0 h-full w-full max-w-md bg-white shadow-xl flex flex-col">
|
||||
<div class="shrink-0 flex items-center justify-between px-[20px] pt-8 pb-8">
|
||||
<h2 class="text-[32px] font-semibold text-primary-500">
|
||||
{{ title }}
|
||||
</h2>
|
||||
<button
|
||||
type="button"
|
||||
class="rounded-md p-1 text-primary-500 hover:text-secondary-500"
|
||||
@click="close"
|
||||
>
|
||||
<Icon name="mdi:close" size="24"/>
|
||||
</button>
|
||||
</div>
|
||||
<div class="min-h-0 flex-1 overflow-y-auto px-[20px] pb-4 pt-1">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{ modelValue: boolean; title?: string }>()
|
||||
const emit = defineEmits<{ (e: 'update:modelValue', value: boolean): void }>()
|
||||
|
||||
const close = () => emit('update:modelValue', false)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.drawer-backdrop-enter-active,
|
||||
.drawer-backdrop-leave-active {
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.drawer-backdrop-enter-from,
|
||||
.drawer-backdrop-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.drawer-panel-enter-active,
|
||||
.drawer-panel-leave-active {
|
||||
transition: transform 0.2s ease, opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.drawer-panel-enter-from,
|
||||
.drawer-panel-leave-to {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<AppDrawer v-model="drawerOpen" title="Export heures (tous les employés)">
|
||||
<MalioDrawer v-model="drawerOpen">
|
||||
<template #header>
|
||||
<h2 class="text-[32px] font-semibold text-primary-500">Export heures (tous les employés)</h2>
|
||||
</template>
|
||||
<form class="space-y-4" @submit.prevent="handleSubmit">
|
||||
<div>
|
||||
<label class="text-md font-semibold text-neutral-700" for="bulk-yearly-hours-year">
|
||||
@@ -29,26 +32,19 @@
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center pt-2">
|
||||
<button
|
||||
type="submit"
|
||||
class="flex w-[200px] items-center justify-center gap-2 rounded-md bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
<MalioButton
|
||||
:label="isLoading ? 'Génération en cours...' : 'Imprimer'"
|
||||
button-class="w-[200px]"
|
||||
:disabled="isLoading || selectedMonth === ''"
|
||||
>
|
||||
<template v-if="isLoading">
|
||||
Génération en cours...
|
||||
</template>
|
||||
<template v-else>
|
||||
Imprimer
|
||||
</template>
|
||||
</button>
|
||||
@click="handleSubmit"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</AppDrawer>
|
||||
</MalioDrawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import AppDrawer from '~/components/AppDrawer.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: boolean
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<AppDrawer v-model="drawerOpen" title="Export heures">
|
||||
<MalioDrawer v-model="drawerOpen">
|
||||
<template #header>
|
||||
<h2 class="text-[32px] font-semibold text-primary-500">Export heures</h2>
|
||||
</template>
|
||||
<form class="space-y-4" @submit.prevent="handleSubmit">
|
||||
<div>
|
||||
<label class="text-md font-semibold text-neutral-700" for="yearly-hours-year">
|
||||
@@ -29,20 +32,18 @@
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center pt-2">
|
||||
<button
|
||||
type="submit"
|
||||
class="flex w-[200px] items-center justify-center gap-2 rounded-md bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500"
|
||||
>
|
||||
Imprimer
|
||||
</button>
|
||||
<MalioButton
|
||||
label="Imprimer"
|
||||
button-class="w-[200px]"
|
||||
@click="handleSubmit"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</AppDrawer>
|
||||
</MalioDrawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import AppDrawer from '~/components/AppDrawer.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: boolean
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<AppDrawer v-model="drawerOpen" title="Récapitulatif Salaire">
|
||||
<MalioDrawer v-model="drawerOpen">
|
||||
<template #header>
|
||||
<h2 class="text-[32px] font-semibold text-primary-500">Récapitulatif Salaire</h2>
|
||||
</template>
|
||||
<form class="space-y-4" @submit.prevent="handleSubmit">
|
||||
<div>
|
||||
<label class="text-md font-semibold text-neutral-700" for="salary-recap-month">
|
||||
@@ -17,21 +20,18 @@
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center pt-2">
|
||||
<button
|
||||
type="submit"
|
||||
class="flex w-[200px] items-center justify-center gap-2 rounded-md bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500"
|
||||
:class="submitButtonClass"
|
||||
>
|
||||
Imprimer
|
||||
</button>
|
||||
<MalioButton
|
||||
label="Imprimer"
|
||||
button-class="w-[200px]"
|
||||
@click="handleSubmit"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</AppDrawer>
|
||||
</MalioDrawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import AppDrawer from '~/components/AppDrawer.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: boolean
|
||||
@@ -63,13 +63,6 @@ const monthFieldClass = computed(() => {
|
||||
return `${baseInputClass} border-neutral-300`
|
||||
})
|
||||
|
||||
const submitButtonClass = computed(() => {
|
||||
if (!isMonthValid.value) {
|
||||
return 'opacity-50 cursor-not-allowed'
|
||||
}
|
||||
return ''
|
||||
})
|
||||
|
||||
const handleSubmit = () => {
|
||||
validationTouched.value = true
|
||||
if (!isMonthValid.value) return
|
||||
|
||||
@@ -33,7 +33,10 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<AppDrawer v-model="isDrawerOpen" :title="isEditing ? 'Modification prime' : 'Nouvelle prime'">
|
||||
<MalioDrawer v-model="isDrawerOpen">
|
||||
<template #header>
|
||||
<h2 class="text-[32px] font-semibold text-primary-500">{{ isEditing ? 'Modification prime' : 'Nouvelle prime' }}</h2>
|
||||
</template>
|
||||
<form class="space-y-4" @submit.prevent="onSubmit">
|
||||
<div>
|
||||
<label class="text-md font-semibold text-neutral-700" for="bonus-month">
|
||||
@@ -75,38 +78,38 @@
|
||||
</div>
|
||||
|
||||
<div v-if="isEditing" class="grid grid-cols-2 gap-3 pt-2">
|
||||
<button
|
||||
type="button"
|
||||
class="flex items-center justify-center rounded-md bg-red-500 px-4 py-2 text-md font-semibold text-white hover:bg-red-600"
|
||||
<MalioButton
|
||||
label="Supprimer"
|
||||
variant="danger"
|
||||
button-class="w-full"
|
||||
@click="onDelete"
|
||||
>
|
||||
Supprimer
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="flex items-center justify-center rounded-md bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
/>
|
||||
<MalioButton
|
||||
label="Modifier"
|
||||
variant="primary"
|
||||
button-class="w-full"
|
||||
:disabled="!isFormValid"
|
||||
>
|
||||
Modifier
|
||||
</button>
|
||||
@click="onSubmit"
|
||||
/>
|
||||
</div>
|
||||
<div v-else class="flex justify-center pt-2">
|
||||
<button
|
||||
type="submit"
|
||||
class="flex w-[200px] items-center justify-center gap-2 rounded-md bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
<MalioButton
|
||||
label="Ajouter"
|
||||
icon-name="mdi:plus"
|
||||
icon-position="left"
|
||||
variant="primary"
|
||||
button-class="w-[200px]"
|
||||
:disabled="!isFormValid"
|
||||
>
|
||||
+ Ajouter
|
||||
</button>
|
||||
@click="onSubmit"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</AppDrawer>
|
||||
</MalioDrawer>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Bonus } from '~/services/dto/bonus'
|
||||
import AppDrawer from '~/components/AppDrawer.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
bonuses: Bonus[]
|
||||
|
||||
@@ -43,7 +43,10 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<AppDrawer :model-value="isContractDrawerOpen" title="Modifier le contrat" @update:model-value="onUpdateContractDrawerOpen">
|
||||
<MalioDrawer :model-value="isContractDrawerOpen" @update:model-value="onUpdateContractDrawerOpen">
|
||||
<template #header>
|
||||
<h2 class="text-[32px] font-semibold text-primary-500">Modifier le contrat</h2>
|
||||
</template>
|
||||
<div class="mb-4 flex border-b border-neutral-200">
|
||||
<button
|
||||
type="button"
|
||||
@@ -141,13 +144,12 @@
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center pt-2">
|
||||
<button
|
||||
type="submit"
|
||||
class="flex w-[200px] items-center justify-center gap-2 rounded-md bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
<MalioButton
|
||||
label="Modifier"
|
||||
button-class="w-[200px]"
|
||||
:disabled="isContractSubmitting || !isContractEndDateValid"
|
||||
>
|
||||
Modifier
|
||||
</button>
|
||||
@click="onSubmitCloseContract"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -188,27 +190,29 @@
|
||||
class="mt-2 w-full rounded-md border border-neutral-300 bg-white px-3 py-2 text-base text-neutral-900 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-secondary-500/20"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="w-full rounded-md bg-primary-500 px-4 py-2 text-base font-semibold text-white transition hover:bg-secondary-500 disabled:cursor-not-allowed disabled:opacity-60"
|
||||
<MalioButton
|
||||
:label="form.id ? 'Modifier' : 'Ajouter'"
|
||||
button-class="w-full"
|
||||
:disabled="!form.startDate || isSuspensionSubmitting"
|
||||
@click="onSubmitSuspension(index)"
|
||||
>
|
||||
{{ form.id ? 'Modifier' : 'Ajouter' }}
|
||||
</button>
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="w-full rounded-md border-2 border-dashed border-primary-500/50 px-4 py-3 text-base font-semibold text-primary-500/50 transition hover:border-primary-500 hover:text-primary-500"
|
||||
<MalioButton
|
||||
label="Ajouter une suspension"
|
||||
icon-name="mdi:plus"
|
||||
icon-position="left"
|
||||
variant="tertiary"
|
||||
button-class="w-full"
|
||||
@click="onAddSuspensionForm"
|
||||
>
|
||||
+ Ajouter une suspension
|
||||
</button>
|
||||
/>
|
||||
</div>
|
||||
</AppDrawer>
|
||||
</MalioDrawer>
|
||||
|
||||
<AppDrawer :model-value="isCreateContractDrawerOpen" title="Ajouter un contrat" @update:model-value="onUpdateCreateContractDrawerOpen">
|
||||
<MalioDrawer :model-value="isCreateContractDrawerOpen" @update:model-value="onUpdateCreateContractDrawerOpen">
|
||||
<template #header>
|
||||
<h2 class="text-[32px] font-semibold text-primary-500">Ajouter un contrat</h2>
|
||||
</template>
|
||||
<form class="space-y-4" @submit.prevent="onSubmitCreateContract">
|
||||
<div>
|
||||
<label class="text-md font-semibold text-neutral-700" for="create-contract-nature">
|
||||
@@ -282,16 +286,17 @@
|
||||
/>
|
||||
|
||||
<div class="sticky bottom-0 -mx-[20px] bg-white px-[20px] py-3 flex justify-center">
|
||||
<button
|
||||
type="submit"
|
||||
class="flex w-[200px] items-center justify-center gap-2 rounded-md bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
<MalioButton
|
||||
label="Ajouter"
|
||||
icon-name="mdi:plus"
|
||||
icon-position="left"
|
||||
button-class="w-[200px]"
|
||||
:disabled="isCreateContractSubmitting || !isCreateContractFormValid"
|
||||
>
|
||||
+ Ajouter
|
||||
</button>
|
||||
@click="onSubmitCreateContract"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</AppDrawer>
|
||||
</MalioDrawer>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -47,7 +47,10 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<AppDrawer v-model="isDrawerOpen" title="Formation">
|
||||
<MalioDrawer v-model="isDrawerOpen">
|
||||
<template #header>
|
||||
<h2 class="text-[32px] font-semibold text-primary-500">Formation</h2>
|
||||
</template>
|
||||
<form class="space-y-4" @submit.prevent="onSubmit">
|
||||
<div>
|
||||
<label class="text-md font-semibold text-neutral-700" for="formation-start-date">
|
||||
@@ -107,39 +110,39 @@
|
||||
</div>
|
||||
|
||||
<div v-if="isEditing" class="grid grid-cols-2 gap-3 pt-2">
|
||||
<button
|
||||
type="button"
|
||||
class="flex items-center justify-center rounded-md bg-red-500 px-4 py-2 text-md font-semibold text-white hover:bg-red-600"
|
||||
<MalioButton
|
||||
label="Supprimer"
|
||||
variant="danger"
|
||||
button-class="w-full"
|
||||
@click="onDelete"
|
||||
>
|
||||
Supprimer
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="flex items-center justify-center rounded-md bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
/>
|
||||
<MalioButton
|
||||
label="Modifier"
|
||||
variant="primary"
|
||||
button-class="w-full"
|
||||
:disabled="!isFormValid"
|
||||
>
|
||||
Modifier
|
||||
</button>
|
||||
@click="onSubmit"
|
||||
/>
|
||||
</div>
|
||||
<div v-else class="flex justify-center pt-2">
|
||||
<button
|
||||
type="submit"
|
||||
class="flex w-[200px] items-center justify-center gap-2 rounded-md bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
<MalioButton
|
||||
label="Ajouter"
|
||||
icon-name="mdi:plus"
|
||||
icon-position="left"
|
||||
variant="primary"
|
||||
button-class="w-[200px]"
|
||||
:disabled="!isFormValid"
|
||||
>
|
||||
+ Ajouter
|
||||
</button>
|
||||
@click="onSubmit"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</AppDrawer>
|
||||
</MalioDrawer>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type {Formation} from '~/services/dto/formation'
|
||||
import {getFormationJustificatifUrl} from '~/services/formations'
|
||||
import AppDrawer from '~/components/AppDrawer.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
formations: Formation[]
|
||||
|
||||
@@ -111,7 +111,10 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<AppDrawer v-model="isFractionedDrawerOpen" title="Jours fractionnés">
|
||||
<MalioDrawer v-model="isFractionedDrawerOpen">
|
||||
<template #header>
|
||||
<h2 class="text-[32px] font-semibold text-primary-500">Jours fractionnés</h2>
|
||||
</template>
|
||||
<form class="space-y-4" @submit.prevent="handleSubmitFractioned">
|
||||
<div>
|
||||
<label class="text-md font-semibold text-neutral-700" for="fractioned-days">
|
||||
@@ -127,24 +130,25 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end gap-3 pt-2">
|
||||
<button
|
||||
type="button"
|
||||
class="rounded-lg border border-neutral-200 px-4 py-2 text-md font-semibold text-neutral-700 hover:bg-neutral-100"
|
||||
<div class="grid grid-cols-2 gap-3 pt-2">
|
||||
<MalioButton
|
||||
label="Annuler"
|
||||
variant="tertiary"
|
||||
button-class="w-full"
|
||||
@click="isFractionedDrawerOpen = false"
|
||||
>
|
||||
Annuler
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="rounded-lg bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500"
|
||||
>
|
||||
Enregistrer
|
||||
</button>
|
||||
/>
|
||||
<MalioButton
|
||||
label="Enregistrer"
|
||||
button-class="w-full"
|
||||
@click="handleSubmitFractioned"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</AppDrawer>
|
||||
<AppDrawer v-model="isPaidLeaveDrawerOpen" title="Congés N-1 payés">
|
||||
</MalioDrawer>
|
||||
<MalioDrawer v-model="isPaidLeaveDrawerOpen">
|
||||
<template #header>
|
||||
<h2 class="text-[32px] font-semibold text-primary-500">Congés N-1 payés</h2>
|
||||
</template>
|
||||
<form class="space-y-4" @submit.prevent="handleSubmitPaidLeave">
|
||||
<div>
|
||||
<label class="text-md font-semibold text-neutral-700" for="paid-leave-days">
|
||||
@@ -160,23 +164,21 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-end gap-3 pt-2">
|
||||
<button
|
||||
type="button"
|
||||
class="rounded-lg border border-neutral-200 px-4 py-2 text-md font-semibold text-neutral-700 hover:bg-neutral-100"
|
||||
<div class="grid grid-cols-2 gap-3 pt-2">
|
||||
<MalioButton
|
||||
label="Annuler"
|
||||
variant="tertiary"
|
||||
button-class="w-full"
|
||||
@click="isPaidLeaveDrawerOpen = false"
|
||||
>
|
||||
Annuler
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="rounded-lg bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500"
|
||||
>
|
||||
Enregistrer
|
||||
</button>
|
||||
/>
|
||||
<MalioButton
|
||||
label="Enregistrer"
|
||||
button-class="w-full"
|
||||
@click="handleSubmitPaidLeave"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</AppDrawer>
|
||||
</MalioDrawer>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
@@ -184,7 +186,6 @@
|
||||
import type {Absence} from '~/services/dto/absence'
|
||||
import type {EmployeeLeaveSummary} from '~/services/dto/employee-leave-summary'
|
||||
import {normalizeDate, toYmd} from '~/utils/date'
|
||||
import AppDrawer from '~/components/AppDrawer.vue'
|
||||
|
||||
type DayLeaveState = {
|
||||
am: boolean
|
||||
|
||||
@@ -64,7 +64,10 @@
|
||||
</div>
|
||||
|
||||
|
||||
<AppDrawer v-model="isDrawerOpen" title="Frais">
|
||||
<MalioDrawer v-model="isDrawerOpen">
|
||||
<template #header>
|
||||
<h2 class="text-[32px] font-semibold text-primary-500">Frais</h2>
|
||||
</template>
|
||||
<form class="space-y-4" @submit.prevent="onSubmit">
|
||||
<div>
|
||||
<label class="text-md font-semibold text-neutral-700" for="mileage-month">
|
||||
@@ -157,39 +160,39 @@
|
||||
</div>
|
||||
|
||||
<div v-if="isEditing" class="grid grid-cols-2 gap-3 pt-2">
|
||||
<button
|
||||
type="button"
|
||||
class="flex items-center justify-center rounded-md bg-red-500 px-4 py-2 text-md font-semibold text-white hover:bg-red-600"
|
||||
<MalioButton
|
||||
label="Supprimer"
|
||||
variant="danger"
|
||||
button-class="w-full"
|
||||
@click="onDelete"
|
||||
>
|
||||
Supprimer
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="flex items-center justify-center rounded-md bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
/>
|
||||
<MalioButton
|
||||
label="Modifier"
|
||||
variant="primary"
|
||||
button-class="w-full"
|
||||
:disabled="!isFormValid"
|
||||
>
|
||||
Modifier
|
||||
</button>
|
||||
@click="onSubmit"
|
||||
/>
|
||||
</div>
|
||||
<div v-else class="flex justify-center pt-2">
|
||||
<button
|
||||
type="submit"
|
||||
class="flex w-[200px] items-center justify-center gap-2 rounded-md bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
<MalioButton
|
||||
label="Ajouter"
|
||||
icon-name="mdi:plus"
|
||||
icon-position="left"
|
||||
variant="primary"
|
||||
button-class="w-[200px]"
|
||||
:disabled="!isFormValid"
|
||||
>
|
||||
+ Ajouter
|
||||
</button>
|
||||
@click="onSubmit"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</AppDrawer>
|
||||
</MalioDrawer>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type {MileageAllowance} from '~/services/dto/mileage-allowance'
|
||||
import {getKmReceiptUrl, getAmountReceiptUrl} from '~/services/mileage-allowances'
|
||||
import AppDrawer from '~/components/AppDrawer.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
allowances: MileageAllowance[]
|
||||
|
||||
@@ -31,7 +31,10 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<AppDrawer v-model="isDrawerOpen" :title="isEditing ? 'Modification observation' : 'Nouvelle observation'">
|
||||
<MalioDrawer v-model="isDrawerOpen">
|
||||
<template #header>
|
||||
<h2 class="text-[32px] font-semibold text-primary-500">{{ isEditing ? 'Modification observation' : 'Nouvelle observation' }}</h2>
|
||||
</template>
|
||||
<form class="space-y-4" @submit.prevent="onSubmit">
|
||||
<div>
|
||||
<label class="text-md font-semibold text-neutral-700" for="observation-month">
|
||||
@@ -59,38 +62,38 @@
|
||||
</div>
|
||||
|
||||
<div v-if="isEditing" class="grid grid-cols-2 gap-3 pt-2">
|
||||
<button
|
||||
type="button"
|
||||
class="flex items-center justify-center rounded-md bg-red-500 px-4 py-2 text-md font-semibold text-white hover:bg-red-600"
|
||||
<MalioButton
|
||||
label="Supprimer"
|
||||
variant="danger"
|
||||
button-class="w-full"
|
||||
@click="onDelete"
|
||||
>
|
||||
Supprimer
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="flex items-center justify-center rounded-md bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
/>
|
||||
<MalioButton
|
||||
label="Modifier"
|
||||
variant="primary"
|
||||
button-class="w-full"
|
||||
:disabled="!isFormValid"
|
||||
>
|
||||
Modifier
|
||||
</button>
|
||||
@click="onSubmit"
|
||||
/>
|
||||
</div>
|
||||
<div v-else class="flex justify-center pt-2">
|
||||
<button
|
||||
type="submit"
|
||||
class="flex w-[200px] items-center justify-center gap-2 rounded-md bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500 disabled:cursor-not-allowed disabled:opacity-50"
|
||||
<MalioButton
|
||||
label="Ajouter"
|
||||
icon-name="mdi:plus"
|
||||
icon-position="left"
|
||||
variant="primary"
|
||||
button-class="w-[200px]"
|
||||
:disabled="!isFormValid"
|
||||
>
|
||||
+ Ajouter
|
||||
</button>
|
||||
@click="onSubmit"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</AppDrawer>
|
||||
</MalioDrawer>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Observation } from '~/services/dto/observation'
|
||||
import AppDrawer from '~/components/AppDrawer.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
observations: Observation[]
|
||||
|
||||
@@ -203,7 +203,10 @@
|
||||
</div>
|
||||
|
||||
<!-- Payment Drawer -->
|
||||
<AppDrawer v-model="isPaymentDrawerOpen" title="Payer des RTT">
|
||||
<MalioDrawer v-model="isPaymentDrawerOpen">
|
||||
<template #header>
|
||||
<h2 class="text-[32px] font-semibold text-primary-500">Payer des RTT</h2>
|
||||
</template>
|
||||
<form @submit.prevent="onSubmitPayment">
|
||||
<div class="mb-4">
|
||||
<label class="block text-sm font-medium text-neutral-700">Mois</label>
|
||||
@@ -254,30 +257,27 @@
|
||||
class="mt-2 w-full rounded-md border border-neutral-300 px-3 py-2 text-base text-neutral-900 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-secondary-500/20"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex justify-end gap-3">
|
||||
<button
|
||||
type="button"
|
||||
class="rounded-md border border-neutral-300 px-4 py-2 text-sm font-medium text-neutral-700 hover:bg-neutral-50"
|
||||
<div class="grid grid-cols-2 gap-3 pt-2">
|
||||
<MalioButton
|
||||
label="Annuler"
|
||||
variant="tertiary"
|
||||
button-class="w-full"
|
||||
@click="isPaymentDrawerOpen = false"
|
||||
>
|
||||
Annuler
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="rounded-md bg-primary-500 px-4 py-2 text-sm font-medium text-white hover:bg-primary-600"
|
||||
>
|
||||
Enregistrer
|
||||
</button>
|
||||
/>
|
||||
<MalioButton
|
||||
label="Enregistrer"
|
||||
button-class="w-full"
|
||||
@click="onSubmitPayment"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</AppDrawer>
|
||||
</MalioDrawer>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { EmployeeRttSummary, EmployeeRttWeekSummary } from '~/services/dto/employee-rtt-summary'
|
||||
import type { ContractPhase } from '~/services/dto/contract-phase'
|
||||
import AppDrawer from '~/components/AppDrawer.vue'
|
||||
|
||||
type RttYearOption = {
|
||||
value: number
|
||||
|
||||
@@ -1,49 +1,43 @@
|
||||
<template>
|
||||
<AppDrawer v-model="drawerOpen" title="Export des heures">
|
||||
<MalioDrawer v-model="drawerOpen">
|
||||
<template #header>
|
||||
<h2 class="text-[32px] font-semibold text-primary-500">Export des heures</h2>
|
||||
</template>
|
||||
<form class="space-y-4" @submit.prevent="handleSubmit">
|
||||
<div>
|
||||
<label class="text-md font-semibold text-neutral-700" for="hours-export-date">
|
||||
Date <span class="text-red-600">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="hours-export-date"
|
||||
v-model="selectedDate"
|
||||
type="date"
|
||||
class="mt-2 w-full rounded-md border border-black px-3 py-2 text-md text-neutral-900"
|
||||
>
|
||||
</div>
|
||||
<MalioDate
|
||||
v-model="selectedDate"
|
||||
label="Date"
|
||||
required
|
||||
:clearable="false"
|
||||
:reserve-message-space="false"
|
||||
group-class="w-full"
|
||||
/>
|
||||
|
||||
<div>
|
||||
<label class="text-md font-semibold text-neutral-700">
|
||||
Sites <span class="text-red-600">*</span>
|
||||
</label>
|
||||
<MalioSelectCheckbox
|
||||
v-model="selectedSites"
|
||||
:options="siteOptions"
|
||||
groupClass="w-full mt-2"
|
||||
label="Sites"
|
||||
display-select-all
|
||||
display-tag
|
||||
/>
|
||||
</div>
|
||||
<MalioSelectCheckbox
|
||||
v-model="selectedSites"
|
||||
:options="siteOptions"
|
||||
label="Sites"
|
||||
required
|
||||
:reserve-message-space="false"
|
||||
groupClass="w-full"
|
||||
display-select-all
|
||||
display-tag
|
||||
/>
|
||||
|
||||
<div class="flex justify-center pt-2">
|
||||
<button
|
||||
type="submit"
|
||||
class="flex w-[200px] items-center justify-center gap-2 rounded-md bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
<MalioButton
|
||||
:label="isLoading ? 'Génération en cours...' : 'Exporter'"
|
||||
button-class="w-[200px]"
|
||||
:disabled="isLoading || !selectedDate || selectedSites.length === 0"
|
||||
>
|
||||
<template v-if="isLoading">Génération en cours...</template>
|
||||
<template v-else>Exporter</template>
|
||||
</button>
|
||||
@click="handleSubmit"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</AppDrawer>
|
||||
</MalioDrawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import AppDrawer from '~/components/AppDrawer.vue'
|
||||
import type { Site } from '~/services/dto/site'
|
||||
|
||||
const props = defineProps<{
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<!-- Desktop: filters row -->
|
||||
<div class="hidden lg:flex lg:items-center lg:gap-4">
|
||||
<div v-if="sites.length > 0 && isAdmin" class="relative z-50 w-80">
|
||||
<MalioSelectCheckbox
|
||||
<MalioSelectCheckbox :reserve-message-space="false"
|
||||
v-model="selectedSiteIds"
|
||||
:options="siteOptions"
|
||||
groupClass="w-80"
|
||||
@@ -11,8 +11,8 @@
|
||||
display-select-all
|
||||
/>
|
||||
</div>
|
||||
<div v-if="isAdmin" class="w-80">
|
||||
<MalioInputText
|
||||
<div v-if="isAdmin" class="w-96">
|
||||
<MalioInputText :reserve-message-space="false"
|
||||
v-model="employeeFilter"
|
||||
label="Recherche d'un employé"
|
||||
icon-name="mdi:magnify"
|
||||
@@ -23,7 +23,7 @@
|
||||
<!-- Mobile: search + filter button -->
|
||||
<div v-if="isAdmin" class="flex items-center gap-2 lg:hidden">
|
||||
<div class="flex-1 min-w-0">
|
||||
<MalioInputText
|
||||
<MalioInputText :reserve-message-space="false"
|
||||
v-model="employeeFilter"
|
||||
label="Recherche d'un employé"
|
||||
icon-name="mdi:magnify"
|
||||
@@ -39,12 +39,15 @@
|
||||
</div>
|
||||
|
||||
<!-- Mobile filters drawer -->
|
||||
<AppDrawer v-model="filtersDrawerOpen" title="Filtres">
|
||||
<MalioDrawer v-model="filtersDrawerOpen">
|
||||
<template #header>
|
||||
<h2 class="text-[32px] font-semibold text-primary-500">Filtres</h2>
|
||||
</template>
|
||||
<div class="space-y-6">
|
||||
<div v-if="sites.length > 0 && isAdmin">
|
||||
<label class="text-md font-semibold text-neutral-700">Sites</label>
|
||||
<div class="mt-2">
|
||||
<MalioSelectCheckbox
|
||||
<MalioSelectCheckbox :reserve-message-space="false"
|
||||
v-model="selectedSiteIds"
|
||||
:options="siteOptions"
|
||||
groupClass="w-80"
|
||||
@@ -77,11 +80,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AppDrawer>
|
||||
</MalioDrawer>
|
||||
|
||||
<!-- Date navigation -->
|
||||
<div class="flex flex-col gap-3 lg:flex-row lg:justify-between lg:items-center lg:gap-4">
|
||||
<div class="flex flex-col gap-3 lg:flex-row lg:flex-wrap lg:gap-4">
|
||||
<div class="flex flex-col gap-3 lg:flex-row lg:flex-wrap lg:items-center lg:gap-4">
|
||||
<div
|
||||
v-if="viewMode === 'day'"
|
||||
class="inline-flex h-10 w-full overflow-hidden rounded-md border border-primary-500 bg-white lg:w-[320px]"
|
||||
@@ -142,10 +145,33 @@
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Vue Jour (opt-in) : calendrier Malio avec jours validés en vert (markedDates). -->
|
||||
<MalioDate
|
||||
v-if="viewMode === 'day' && showValidationCalendar"
|
||||
:model-value="selectedDate"
|
||||
:clearable="false"
|
||||
:reserve-message-space="false"
|
||||
:marked-dates="markedDates"
|
||||
group-class="w-full lg:w-96"
|
||||
label="Date"
|
||||
@update:model-value="onDatePicked"
|
||||
@month-change="(payload) => emit('month-change', payload)"
|
||||
/>
|
||||
<!-- Vue Semaine : sélecteur de semaine Malio. -->
|
||||
<MalioDateWeek
|
||||
v-else-if="viewMode === 'week'"
|
||||
:model-value="pickerValue"
|
||||
:clearable="false"
|
||||
:reserve-message-space="false"
|
||||
group-class="w-full lg:w-96"
|
||||
label="Semaine"
|
||||
@update:model-value="onWeekPicked"
|
||||
/>
|
||||
<PeriodStepperPicker
|
||||
v-else
|
||||
width-class="w-full lg:w-[320px]"
|
||||
:label="formattedSelectedDate"
|
||||
:picker-type="viewMode === 'week' ? 'week' : 'date'"
|
||||
picker-type="date"
|
||||
:picker-value="pickerValue"
|
||||
prev-aria-label="Période précédente"
|
||||
next-aria-label="Période suivante"
|
||||
@@ -195,7 +221,6 @@
|
||||
import type { Site } from '~/services/dto/site'
|
||||
import type { AbsenceType } from '~/services/dto/absence-type'
|
||||
import PeriodStepperPicker from '~/components/PeriodStepperPicker.vue'
|
||||
import AppDrawer from '~/components/AppDrawer.vue'
|
||||
import { weekInputValueToYmd, ymdToWeekInputValue } from '~/utils/date'
|
||||
|
||||
const selectedDate = defineModel<string>('selectedDate', { required: true })
|
||||
@@ -208,6 +233,10 @@ const props = defineProps<{
|
||||
sites: Site[]
|
||||
absenceTypes: AbsenceType[]
|
||||
formattedSelectedDate: string
|
||||
// Calendrier des jours validés (vert) : opt-in, réservé à l'écran Heures.
|
||||
// L'écran Heures Conducteurs ne le passe pas → garde le PeriodStepperPicker.
|
||||
showValidationCalendar?: boolean
|
||||
markedDates?: Record<string, 'success' | 'danger'>
|
||||
shortcutButtonClass: (target: 'yesterday' | 'today' | 'tomorrow') => string
|
||||
weekShortcutButtonClass: (target: 'previousWeek' | 'thisWeek' | 'nextWeek') => string
|
||||
getWeekShortcutLabel: (target: 'previousWeek' | 'thisWeek' | 'nextWeek') => string
|
||||
@@ -223,6 +252,7 @@ const emit = defineEmits<{
|
||||
(e: 'set-this-week'): void
|
||||
(e: 'set-next-week'): void
|
||||
(e: 'shift-date', value: number): void
|
||||
(e: 'month-change', value: { month: number; year: number }): void
|
||||
}>()
|
||||
|
||||
const filtersDrawerOpen = ref(false)
|
||||
@@ -252,4 +282,20 @@ const onPickerValue = (value: string) => {
|
||||
|
||||
selectedDate.value = value
|
||||
}
|
||||
|
||||
// Sélection d'un jour dans le calendrier MalioDate (vue Jour). `clearable=false`
|
||||
// → pas de null en pratique, mais on garde la garde par sécurité.
|
||||
const onDatePicked = (value: string | null) => {
|
||||
if (!value) return
|
||||
selectedDate.value = value
|
||||
}
|
||||
|
||||
// Sélection d'une semaine dans MalioDateWeek (vue Semaine) : v-model au format ISO
|
||||
// week (YYYY-Www) → on repositionne selectedDate sur le lundi de cette semaine.
|
||||
const onWeekPicked = (value: string | null) => {
|
||||
if (!value) return
|
||||
const ymd = weekInputValueToYmd(value)
|
||||
if (!ymd) return
|
||||
selectedDate.value = ymd
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
<template>
|
||||
<MalioDrawer v-model="drawerOpen" title="Commentaire">
|
||||
<MalioDrawer v-model="drawerOpen">
|
||||
<template #header>
|
||||
<h2 class="text-[32px] font-semibold text-primary-500">Commentaire</h2>
|
||||
</template>
|
||||
<form class="space-y-4" @submit.prevent="onSave">
|
||||
<div v-if="employeeLabel" class="text-md font-semibold text-neutral-700">{{ employeeLabel }}</div>
|
||||
<div class="text-md font-semibold text-neutral-700">{{ formatWeekRange }}</div>
|
||||
<MalioInputTextArea
|
||||
<MalioInputTextArea :reserve-message-space="false"
|
||||
v-model="content"
|
||||
label="Commentaire"
|
||||
:size="8"
|
||||
@@ -11,17 +14,18 @@
|
||||
:show-counter="true"
|
||||
resize="vertical"
|
||||
/>
|
||||
<div class="sticky bottom-0 -mx-[20px] bg-white px-[20px] py-3 flex justify-between gap-3">
|
||||
<div class="sticky bottom-0 -mx-[20px] bg-white px-[20px] py-3 flex gap-3">
|
||||
<MalioButton
|
||||
v-if="commentId"
|
||||
label="Supprimer"
|
||||
variant="danger"
|
||||
button-class="flex-1"
|
||||
:disabled="isSubmitting"
|
||||
@click="onDelete"
|
||||
/>
|
||||
<MalioButton
|
||||
label="Enregistrer"
|
||||
button-class="ml-auto"
|
||||
button-class="flex-1"
|
||||
:disabled="isSubmitting || !canSubmit"
|
||||
@click="onSave"
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user