236 lines
8.0 KiB
Vue

<script setup>
import { ref, watch, computed } from 'vue';
import VueDatePicker from '@vuepic/vue-datepicker';
import '@vuepic/vue-datepicker/dist/main.css';
import PrimaryButton from '@Holos/Button/Primary.vue';
import Input from '@Holos/Form/Input.vue';
import Textarea from '@Holos/Form/Textarea.vue';
import GoogleIcon from '@Shared/GoogleIcon.vue';
/** Eventos */
const emit = defineEmits([
'submit'
])
/** Propiedades */
const props = defineProps({
form: Object
})
/** Métodos */
function submit() {
emit('submit')
}
function addPeriod() {
props.form.periods.push({
start_date: '',
end_date: '',
number_of_days: 0,
});
}
function removePeriod(index) {
if (props.form.periods.length > 1) {
props.form.periods.splice(index, 1);
}
}
function calculateDays(startDate, endDate) {
if (!startDate || !endDate) return 0;
const start = new Date(startDate);
const end = new Date(endDate);
// Validar que la fecha de inicio no sea posterior a la de fin
if (start > end) return 0;
// Calcular la diferencia en días (incluyendo ambos días)
const timeDiff = end.getTime() - start.getTime();
const daysDiff = Math.ceil(timeDiff / (1000 * 3600 * 24)) + 1;
return daysDiff;
}
function updatePeriodDays(index) {
const period = props.form.periods[index];
if (period.start_date && period.end_date) {
period.number_of_days = calculateDays(period.start_date, period.end_date);
} else {
period.number_of_days = 0;
}
}
function getMinDate() {
const today = new Date();
let daysToAdd = 15;
let currentDate = new Date(today);
while (daysToAdd > 0) {
currentDate.setDate(currentDate.getDate() + 1);
// Si no es domingo (0), contar el día
if (currentDate.getDay() !== 0) {
daysToAdd--;
}
}
return currentDate.toISOString().split('T')[0];
}
// Función para desactivar domingos
function isDisabled(date) {
return date.getDay() === 0; // 0 = domingo
}
// Función para formatear fecha a Y-m-d
function formatDate(date) {
if (!date) return '';
// Si la fecha ya es un string en formato correcto, devolverla
if (typeof date === 'string' && date.match(/^\d{4}-\d{2}-\d{2}$/)) {
return date;
}
let d;
if (date instanceof Date) {
d = date;
} else {
d = new Date(date);
}
// Verificar que la fecha es válida
if (isNaN(d.getTime())) {
console.warn('Fecha inválida recibida:', date);
return '';
}
const year = d.getFullYear();
const month = String(d.getMonth() + 1).padStart(2, '0');
const day = String(d.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
// Watcher para detectar cambios en las fechas
watch(() => props.form.periods, (newPeriods) => {
newPeriods.forEach((period, index) => {
if (period.start_date && period.end_date) {
updatePeriodDays(index);
}
});
}, { deep: true });
// Calcular total de días seleccionados
const totalSelectedDays = computed(() => {
return props.form.periods.reduce((total, period) => {
return total + (period.number_of_days || 0);
}, 0);
});
// Exponer el total para el componente padre
defineExpose({
totalSelectedDays
});
</script>
<template>
<form @submit.prevent="submit" class="space-y-6">
<!-- Períodos de vacaciones -->
<div class="space-y-4">
<div v-for="(period, index) in form.periods" :key="index" class="space-y-4">
<div class="flex items-center justify-between">
<h4 class="text-sm font-medium text-slate-700 dark:text-slate-300">
Período {{ index + 1 }}
</h4>
<button
v-if="form.periods.length > 1"
type="button"
@click="removePeriod(index)"
class="flex items-center gap-1 px-2 py-1 text-xs font-medium text-red-600 hover:text-red-700 hover:bg-red-50 rounded-md with-transition dark:text-red-400 dark:hover:bg-red-500/10"
>
<GoogleIcon name="delete" class="w-4 h-4" />
Eliminar
</button>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<div class="relative">
<VueDatePicker
v-model="period.start_date"
class="w-full"
placeholder="Fecha de inicio"
format="dd/MM/yyyy"
locale="es"
:min-date="getMinDate()"
:disabled-dates="isDisabled"
:enable-time-picker="false"
:auto-apply="true"
:close-on-auto-apply="true"
@update:model-value="(date) => {
console.log('Fecha seleccionada (inicio):', date);
period.start_date = formatDate(date);
console.log('Fecha formateada (inicio):', period.start_date);
updatePeriodDays(index);
}"
/>
</div>
</div>
<div>
<div class="relative">
<VueDatePicker
v-model="period.end_date"
class="w-full"
placeholder="Fecha de fin"
format="dd/MM/yyyy"
locale="es"
:min-date="getMinDate()"
:disabled-dates="isDisabled"
:enable-time-picker="false"
:auto-apply="true"
:close-on-auto-apply="true"
@update:model-value="(date) => {
console.log('Fecha seleccionada (fin):', date);
period.end_date = formatDate(date);
console.log('Fecha formateada (fin):', period.end_date);
updatePeriodDays(index);
}"
/>
</div>
</div>
</div>
</div>
<!-- Botón añadir período -->
<button
type="button"
@click="addPeriod"
class="flex items-center gap-2 px-4 py-2 text-sm font-medium text-blue-600 hover:text-blue-700 hover:bg-blue-50 rounded-lg with-transition dark:text-blue-400 dark:hover:bg-blue-500/10"
>
<GoogleIcon name="add" />
Añadir período
</button>
</div>
<!-- Comentarios -->
<div>
<Textarea
v-model="form.comments"
id="comments"
rows="4"
class="w-full px-4 py-3 border border-slate-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent resize-none dark:bg-slate-700 dark:border-slate-600 dark:text-slate-100"
placeholder="Agrega cualquier información adicional sobre tu solicitud..."
:onError="form.errors.comments"
/>
</div>
<!-- Botón de envío -->
<div class="col-span-1 md:col-span-2 flex justify-center">
<PrimaryButton
v-text="$t('request')"
:class="{ 'opacity-25': form.processing }"
:disabled="form.processing"
/>
</div>
</form>
</template>