feat : refacto de la partie calendrier + ajout de validation sur les formulaires + ajout des jours fériés

This commit is contained in:
2026-02-09 14:25:18 +01:00
parent 03f5552dd4
commit c1025d6066
18 changed files with 1303 additions and 427 deletions

View File

@@ -66,35 +66,50 @@
<AppDrawer v-model="isDrawerOpen" :title="drawerTitle">
<form class="space-y-4" @submit.prevent="handleSubmit">
<div>
<label class="text-md font-semibold text-neutral-700" for="code">Code</label>
<label class="text-md font-semibold text-neutral-700" for="code">
Code <span class="text-red-600">*</span>
</label>
<input
id="code"
v-model="form.code"
type="text"
maxlength="10"
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-primary-200"
:class="codeFieldClass"
/>
<p v-if="showCodeError" class="mt-1 text-sm text-red-600">
Le code est obligatoire.
</p>
</div>
<div>
<label class="text-md font-semibold text-neutral-700" for="label">Libellé</label>
<label class="text-md font-semibold text-neutral-700" for="label">
Libellé <span class="text-red-600">*</span>
</label>
<input
id="label"
v-model="form.label"
type="text"
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-primary-200"
:class="labelFieldClass"
/>
<p v-if="showLabelError" class="mt-1 text-sm text-red-600">
Le libellé est obligatoire.
</p>
</div>
<div>
<label class="text-md font-semibold text-neutral-700" for="color">Couleur</label>
<label class="text-md font-semibold text-neutral-700" for="color">
Couleur <span class="text-red-600">*</span>
</label>
<div class="mt-2 flex items-center gap-3">
<input
id="color"
v-model="form.color"
type="color"
class="h-10 w-16 cursor-pointer rounded-md border border-neutral-300 bg-white p-1"
:class="colorFieldClass"
/>
<span class="text-md font-semibold text-neutral-600">{{ form.color }}</span>
</div>
<p v-if="showColorError" class="mt-1 text-sm text-red-600">
La couleur est obligatoire.
</p>
</div>
<div class="flex justify-end gap-3 pt-2">
<button
@@ -107,7 +122,7 @@
<button
type="submit"
class="rounded-lg bg-primary-500 px-4 py-2 text-md font-semibold text-white hover:bg-secondary-500"
:disabled="isSubmitting"
:class="submitButtonClass"
>
Enregistrer
</button>
@@ -135,7 +150,53 @@ const drawerTitle = computed(() =>
const form = reactive({
code: '',
label: '',
color: ''
color: '#222783'
})
const validationTouched = reactive({
code: false,
label: false,
color: false
})
const isCodeValid = computed(() => form.code.trim() !== '')
const isLabelValid = computed(() => form.label.trim() !== '')
const isColorValid = computed(() => form.color.trim() !== '')
const isFormValid = computed(
() => isCodeValid.value && isLabelValid.value && isColorValid.value
)
const showCodeError = computed(() => validationTouched.code && !isCodeValid.value)
const showLabelError = computed(() => validationTouched.label && !isLabelValid.value)
const showColorError = computed(() => validationTouched.color && !isColorValid.value)
const baseInputClass =
'mt-2 w-full rounded-md border px-3 py-2 text-base text-neutral-900 focus:border-primary-500 focus:outline-none focus:ring-2 focus:ring-primary-200'
const codeFieldClass = computed(() => {
if (showCodeError.value) {
return `${baseInputClass} border-red-500`
}
return `${baseInputClass} border-neutral-300`
})
const labelFieldClass = computed(() => {
if (showLabelError.value) {
return `${baseInputClass} border-red-500`
}
return `${baseInputClass} border-neutral-300`
})
const colorFieldClass = computed(() => {
const baseColorClass = 'h-10 w-16 cursor-pointer rounded-md border bg-white p-1'
if (showColorError.value) {
return `${baseColorClass} border-red-500`
}
return `${baseColorClass} border-neutral-300`
})
const submitButtonClass = computed(() => {
if (isSubmitting.value || !isFormValid.value) {
return 'opacity-50 cursor-not-allowed'
}
return ''
})
const loadAbsenceTypes = async () => {
@@ -152,7 +213,7 @@ onMounted(loadAbsenceTypes)
const resetForm = () => {
form.code = ''
form.label = ''
form.color = ''
form.color = '#222783'
}
const openCreate = () => {
@@ -177,6 +238,10 @@ const closeDrawer = () => {
const handleSubmit = async () => {
if (isSubmitting.value) return
validationTouched.code = true
validationTouched.label = true
validationTouched.color = true
if (!isFormValid.value) return
isSubmitting.value = true
try {
@@ -201,6 +266,14 @@ const handleSubmit = async () => {
}
}
watch(isDrawerOpen, (isOpen) => {
if (!isOpen) {
validationTouched.code = false
validationTouched.label = false
validationTouched.color = false
}
})
const confirmDelete = async (type: AbsenceType) => {
const ok = window.confirm(`Supprimer le type ${type.label} ?`)
if (!ok) return