salix-front/src/pages/Worker/Card/WorkerCalendarItem.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>