269 lines
7.1 KiB
Vue
269 lines
7.1 KiB
Vue
<script setup>
|
|
import { onBeforeMount, ref, watch, computed } from 'vue';
|
|
import { useI18n } from 'vue-i18n';
|
|
import { date } from 'quasar';
|
|
import { useRoute } from 'vue-router';
|
|
|
|
import QCalendarMonthWrapper from 'src/components/ui/QCalendarMonthWrapper.vue';
|
|
import { QCalendarMonth } from '@quasar/quasar-ui-qcalendar/src/index.js';
|
|
import '@quasar/quasar-ui-qcalendar/src/QCalendarVariables.sass';
|
|
|
|
import { useWeekdayStore } from 'src/stores/useWeekdayStore';
|
|
import useNotify from 'src/composables/useNotify.js';
|
|
import axios from 'axios';
|
|
|
|
const props = defineProps({
|
|
year: {
|
|
type: Number,
|
|
required: true,
|
|
},
|
|
month: {
|
|
type: Number,
|
|
required: true,
|
|
},
|
|
absenceType: {
|
|
type: Object,
|
|
default: null,
|
|
},
|
|
businessFk: {
|
|
type: Number,
|
|
default: null,
|
|
},
|
|
events: {
|
|
type: Object,
|
|
default: null,
|
|
},
|
|
});
|
|
|
|
const emit = defineEmits(['refresh', 'onDeletedEvent']);
|
|
|
|
const route = useRoute();
|
|
const { t } = useI18n();
|
|
const { notify } = useNotify();
|
|
const { locale } = useI18n();
|
|
|
|
const calendarRef = ref(null);
|
|
const weekdayStore = useWeekdayStore();
|
|
const selectedDate = ref();
|
|
const calendarEventDates = [];
|
|
const today = ref(date.formatDate(Date.vnNew(), 'YYYY-MM-DD'));
|
|
const todayTimestamp = computed(() => {
|
|
const date = Date.vnNew();
|
|
date.setHours(0, 0, 0, 0);
|
|
return date.getTime();
|
|
});
|
|
const _year = computed(() => props.year);
|
|
|
|
const updateSelectedDate = (year) => {
|
|
const _date = new Date(year, props.month - 1, 1);
|
|
selectedDate.value = date.formatDate(_date, 'YYYY-MM-DD');
|
|
};
|
|
|
|
const createEvent = async (date) => {
|
|
try {
|
|
const params = {
|
|
dated: date,
|
|
absenceTypeId: props.absenceType.id,
|
|
businessFk: props.businessFk,
|
|
};
|
|
|
|
const { data } = await axios.post(
|
|
`Workers/${route.params.id}/createAbsence`,
|
|
params
|
|
);
|
|
|
|
if (data) emit('refresh');
|
|
} catch (error) {
|
|
console.error('error creating event:: ', error);
|
|
}
|
|
};
|
|
|
|
const editEvent = async (event) => {
|
|
try {
|
|
const absenceType = props.absenceType;
|
|
const params = {
|
|
absenceId: event.absenceId,
|
|
absenceTypeId: absenceType.id,
|
|
};
|
|
const { data } = await axios.patch(
|
|
`Workers/${route.params.id}/updateAbsence`,
|
|
params
|
|
);
|
|
|
|
if (data) emit('refresh');
|
|
} catch (error) {
|
|
console.error('error editing event:: ', error);
|
|
}
|
|
};
|
|
|
|
const deleteEvent = async (event, date) => {
|
|
const params = { absenceId: event.absenceId };
|
|
const { data } = await axios.delete(`Workers/${route.params.id}/deleteAbsence`, {
|
|
params,
|
|
});
|
|
|
|
if (data) emit('onDeletedEvent', date.getTime());
|
|
};
|
|
|
|
const handleDateSelected = (date) => {
|
|
if (!props.absenceType) {
|
|
notify(t('Choose an absence type from the right menu'), 'warning');
|
|
return;
|
|
}
|
|
|
|
const { year, month, day } = date.scope.timestamp;
|
|
const _date = new Date(year, month - 1, day);
|
|
const stamp = _date.getTime();
|
|
const event = props.events[stamp];
|
|
|
|
if (!event) createEvent(_date);
|
|
};
|
|
|
|
const handleEventSelected = (event, { year, month, day }) => {
|
|
if (!props.absenceType) {
|
|
notify(t('Choose an absence type from the right menu'), 'warning');
|
|
return;
|
|
}
|
|
|
|
const date = new Date(year, month - 1, day);
|
|
if (!event?.absenceId) createEvent(date);
|
|
else if (event.type == props.absenceType.code) deleteEvent(event, date);
|
|
else editEvent(event);
|
|
};
|
|
|
|
const getEventByTimestamp = ({ year, month, day }) => {
|
|
const stamp = new Date(year, month - 1, day).getTime();
|
|
return props.events[stamp] || null;
|
|
};
|
|
|
|
const isFestive = (timestamp) => {
|
|
const event = getEventByTimestamp(timestamp);
|
|
if (!event) return false;
|
|
|
|
const { isFestive } = event;
|
|
return isFestive;
|
|
};
|
|
const getEventAttrs = (timestamp) => {
|
|
const event = getEventByTimestamp(timestamp);
|
|
if (!event) return {};
|
|
|
|
const { name, color, isFestive, type } = event;
|
|
|
|
// Atributos a asignar a cada slot que representa un evento en el calendario
|
|
|
|
const attrs = {
|
|
title: name,
|
|
style: color ? `background-color: ${color};` : ``,
|
|
label: timestamp.day,
|
|
};
|
|
|
|
if (isFestive) {
|
|
attrs.class = '--festive';
|
|
attrs.label = event.absenceId ?? timestamp.day;
|
|
} else attrs.class = `--${type}`;
|
|
|
|
return attrs;
|
|
};
|
|
|
|
const isToday = (timestamp) => {
|
|
const { year, month, day } = timestamp;
|
|
return todayTimestamp.value === new Date(year, month - 1, day).getTime();
|
|
};
|
|
onBeforeMount(() => {
|
|
updateSelectedDate(_year.value);
|
|
});
|
|
|
|
watch(_year, (newValue) => {
|
|
updateSelectedDate(newValue);
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<QCalendarMonthWrapper
|
|
style="height: 290px; width: 310px"
|
|
class="outline"
|
|
bordered
|
|
transparent-background
|
|
view-customization="workerCalendar"
|
|
>
|
|
<template #header>
|
|
<span class="full-width text-center text-body1 q-py-sm">{{
|
|
weekdayStore.getLocaleMonths[$props.month - 1].locale
|
|
}}</span>
|
|
</template>
|
|
<template #calendar>
|
|
<QCalendarMonth
|
|
ref="calendarRef"
|
|
v-model="selectedDate"
|
|
@click-date="handleDateSelected"
|
|
show-work-weeks
|
|
no-outside-days
|
|
:selected-dates="calendarEventDates"
|
|
no-active-date
|
|
:weekdays="[1, 2, 3, 4, 5, 6, 0]"
|
|
short-weekday-label
|
|
:locale="locale"
|
|
:now="today"
|
|
mini-mode
|
|
>
|
|
<template #day="{ scope: { timestamp } }">
|
|
<!-- Este slot representa cada día del calendario y muestra un botón representando el correspondiente evento -->
|
|
<QBtn
|
|
v-bind="{ ...getEventAttrs(timestamp) }"
|
|
@click="
|
|
handleEventSelected(getEventByTimestamp(timestamp), timestamp)
|
|
"
|
|
rounded
|
|
dense
|
|
flat
|
|
class="calendar-event"
|
|
:class="{
|
|
'--today': isToday(timestamp),
|
|
}"
|
|
/>
|
|
</template>
|
|
</QCalendarMonth>
|
|
</template>
|
|
</QCalendarMonthWrapper>
|
|
</template>
|
|
|
|
<style lang="scss">
|
|
.q-calendar-month__day:has(.q-calendar-month__day--content):has(.q-btn.--festive)
|
|
.q-calendar-month__day--label__wrapper
|
|
button {
|
|
color: transparent;
|
|
}
|
|
.calendar-event {
|
|
display: flex;
|
|
justify-content: center;
|
|
width: 32px;
|
|
height: 32px;
|
|
font-size: 13px;
|
|
line-height: 1.715em;
|
|
cursor: pointer;
|
|
|
|
&.--today {
|
|
border: 2px solid $info;
|
|
}
|
|
|
|
&.--festive {
|
|
color: $negative;
|
|
}
|
|
|
|
&.--holiday {
|
|
& > span:nth-child(2) .block {
|
|
color: white;
|
|
}
|
|
}
|
|
|
|
&:hover {
|
|
opacity: 0.8;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<i18n>
|
|
es:
|
|
Choose an absence type from the right menu: Elige un tipo de ausencia desde el menú de la derecha
|
|
</i18n>
|