diff --git a/quasar.extensions.json b/quasar.extensions.json
index e5c5cbfaa..867769090 100644
--- a/quasar.extensions.json
+++ b/quasar.extensions.json
@@ -1,7 +1,6 @@
{
- "@quasar/testing-unit-vitest": {
- "options": [
- "scripts"
- ]
- }
-}
\ No newline at end of file
+ "@quasar/testing-unit-vitest": {
+ "options": ["scripts"]
+ },
+ "@quasar/qcalendar": {}
+}
diff --git a/src/components/ui/QCalendarMonthWrapper.vue b/src/components/ui/QCalendarMonthWrapper.vue
new file mode 100644
index 000000000..49acd0e7d
--- /dev/null
+++ b/src/components/ui/QCalendarMonthWrapper.vue
@@ -0,0 +1,23 @@
+
+
+
+
+
diff --git a/src/css/app.scss b/src/css/app.scss
index 8e2853ab2..0e9ae66e2 100644
--- a/src/css/app.scss
+++ b/src/css/app.scss
@@ -1,5 +1,6 @@
// app global css in SCSS form
@import './icons.scss';
+@import '@quasar/quasar-ui-qcalendar/src/QCalendarMonth.sass';
body.body--light {
--fount-color: black;
@@ -120,3 +121,14 @@ input::-webkit-inner-spin-button {
-webkit-appearance: none;
-moz-appearance: none;
}
+
+// Clases para modificar el color de fecha seleccionada en componente QCalendarMonth
+.q-dark div .q-calendar-mini .q-calendar-month__day.q-selected .q-calendar__button {
+ background-color: $primary !important;
+ color: white !important;
+}
+
+.q-calendar-mini .q-calendar-month__day.q-selected .q-calendar__button {
+ background-color: $primary !important;
+ color: white !important;
+}
diff --git a/src/i18n/en/index.js b/src/i18n/en/index.js
index 34ce16aa7..5ca92df0a 100644
--- a/src/i18n/en/index.js
+++ b/src/i18n/en/index.js
@@ -1225,4 +1225,27 @@ export default {
},
iban_tooltip: 'IBAN: ES21 1234 5678 90 0123456789',
},
+ weekdays: {
+ sun: 'Sunday',
+ mon: 'Monday',
+ tue: 'Tuesday',
+ wed: 'Wednesday',
+ thu: 'Thursday',
+ fri: 'Friday',
+ sat: 'Saturday',
+ },
+ months: {
+ jan: 'January',
+ feb: 'February',
+ mar: 'March',
+ apr: 'April',
+ may: 'May',
+ jun: 'June',
+ jul: 'July',
+ aug: 'August',
+ sep: 'September',
+ oct: 'October',
+ nov: 'November',
+ dec: 'December',
+ },
};
diff --git a/src/i18n/es/index.js b/src/i18n/es/index.js
index fee08322c..0b63f3de5 100644
--- a/src/i18n/es/index.js
+++ b/src/i18n/es/index.js
@@ -1225,4 +1225,27 @@ export default {
},
iban_tooltip: 'IBAN: ES21 1234 5678 90 0123456789',
},
+ weekdays: {
+ sun: 'Domingo',
+ mon: 'Lunes',
+ tue: 'Martes',
+ wed: 'Miércoles',
+ thu: 'Jueves',
+ fri: 'Viernes',
+ sat: 'Sábado',
+ },
+ months: {
+ jan: 'Enero',
+ feb: 'Febrero',
+ mar: 'Marzo',
+ apr: 'Abril',
+ may: 'Mayo',
+ jun: 'Junio',
+ jul: 'Julio',
+ aug: 'Agosto',
+ sep: 'Septiembre',
+ oct: 'Octubre',
+ nov: 'Noviembre',
+ dec: 'Diciembre',
+ },
};
diff --git a/src/pages/Worker/Card/WorkerCalendar.vue b/src/pages/Worker/Card/WorkerCalendar.vue
index 73111cafa..859dedb57 100644
--- a/src/pages/Worker/Card/WorkerCalendar.vue
+++ b/src/pages/Worker/Card/WorkerCalendar.vue
@@ -1,26 +1,35 @@
@@ -35,7 +44,7 @@ const onFetchActiveContract = (data) => {
auto-load
/>
-
+
@@ -66,15 +77,39 @@ const onFetchActiveContract = (data) => {
{{ t('Autonomous worker') }}
-
-
-
-
-
-
+
+
+
+ {{
+ t(
+ 'To start adding absences, click an absence type from the right menu and then on the day you want to add an absence'
+ )
+ }}
+
+
+
+
+
+
es:
Search worker: Buscar trabajador
You can search by worker id or name: Puedes buscar por id o nombre del trabajador
+ To start adding absences, click an absence type from the right menu and then on the day you want to add an absence: Para empezar a añadir ausencias, haz clic en un tipo de ausencia desde el menu de la derecha y después en el día que quieres añadir la ausencia
diff --git a/src/pages/Worker/Card/WorkerCalendarFilter.vue b/src/pages/Worker/Card/WorkerCalendarFilter.vue
index d73305085..f8c1b2167 100644
--- a/src/pages/Worker/Card/WorkerCalendarFilter.vue
+++ b/src/pages/Worker/Card/WorkerCalendarFilter.vue
@@ -4,7 +4,7 @@ import FetchData from 'components/FetchData.vue';
import { useI18n } from 'vue-i18n';
import VnSelectFilter from 'components/common/VnSelectFilter.vue';
import { useRoute } from 'vue-router';
-import { computed, ref, watch } from 'vue';
+import { computed, ref, watch, reactive } from 'vue';
import { toDateFormat } from '../../../filters/date';
import axios from 'axios';
@@ -26,7 +26,12 @@ const props = defineProps({
},
});
-const emit = defineEmits(['update:businessFk', 'update:year', 'update:absenceType']);
+const emit = defineEmits([
+ 'update:businessFk',
+ 'update:year',
+ 'update:absenceType',
+ 'updateEvents',
+]);
const selectedBusinessFk = computed({
get: () => props.businessFk,
@@ -35,13 +40,18 @@ const selectedBusinessFk = computed({
emit('update:businessFk', value);
},
});
+
const selectedYear = computed({
get: () => props.year,
set: (value) => emit('update:year', value),
});
+
const selectedAbsenceType = computed({
get: () => props.absenceType,
- set: (value) => emit('update:absenceType', value),
+ set: (value) => {
+ if (value === props.absenceType) value = null;
+ emit('update:absenceType', value);
+ },
});
const generateYears = () => {
@@ -57,11 +67,19 @@ const yearList = ref(generateYears());
const contractHolidays = ref(null);
const yearHolidays = ref(null);
+const events = reactive({});
+const calendar = ref(null);
const getHolidays = async (params) => {
- return axios
- .get(`Workers/${route.params.id}/holidays`, { params })
- .then((res) => res.data);
+ try {
+ const { data } = await axios.get(`Workers/${route.params.id}/holidays`, {
+ params,
+ });
+ return data;
+ } catch (error) {
+ console.error('Error fetching holidays:', error);
+ return null;
+ }
};
const updateContractHolidays = async () => {
@@ -75,14 +93,80 @@ const updateYearHolidays = async () => {
yearHolidays.value = await getHolidays({ year: selectedYear.value });
};
-watch(selectedYear, () => {
+const getAbsences = async () => {
+ try {
+ const params = {
+ workerFk: route.params.id,
+ businessFk: props.businessFk,
+ year: props.year,
+ };
+ const { data } = await axios.get('Calendars/absences', { params });
+ if (data) onAbsencesFetched(data);
+ return data;
+ } catch (error) {
+ console.error('Error fetching absences:', error);
+ return null;
+ }
+};
+
+const refreshData = () => {
updateYearHolidays();
updateContractHolidays();
+ getAbsences();
+};
+
+const onAbsencesFetched = (data) => {
+ calendar.value = data.calendar;
+
+ let addEvent = (day, newEvent) => {
+ const timestamp = new Date(day).getTime();
+ let event = events[timestamp];
+
+ if (event) {
+ const oldName = event.name;
+ Object.assign(event, newEvent);
+ event.name = `${oldName}, ${event.name}`;
+ } else events[timestamp] = newEvent;
+ };
+
+ if (data.holidays) {
+ data.holidays.forEach((holiday) => {
+ const holidayDetail = holiday.detail && holiday.detail.name;
+ const holidayType = holiday.type && holiday.type.name;
+ const holidayName = holidayDetail || holidayType;
+
+ addEvent(holiday.dated, {
+ name: holidayName,
+ className: 'festive',
+ });
+ });
+ }
+ if (data.absences) {
+ data.absences.forEach((absence) => {
+ let type = absence.absenceType;
+ addEvent(absence.dated, {
+ name: type.name,
+ color: type.rgb,
+ type: type.code,
+ absenceId: absence.id,
+ });
+ });
+ }
+
+ emit('updateEvents', events);
+ console.log('events:: ', events);
+};
+
+watch(selectedYear, () => {
+ refreshData();
});
watch(selectedBusinessFk, () => {
- updateYearHolidays();
- updateContractHolidays();
+ refreshData();
+});
+
+defineExpose({
+ refreshData,
});
diff --git a/src/pages/Worker/Card/WorkerCalendarItem.vue b/src/pages/Worker/Card/WorkerCalendarItem.vue
index b06d8f028..79c47063c 100644
--- a/src/pages/Worker/Card/WorkerCalendarItem.vue
+++ b/src/pages/Worker/Card/WorkerCalendarItem.vue
@@ -1,11 +1,17 @@
+
-
+
+
+ {{
+ weekdayStore.getLocaleMonths[$props.month - 1].locale
+ }}
+
+
+
+
+
+ {{ timestamp.day }}
+
+
+
+
+
+
+
+
+
+es:
+ Choose an absence type from the right menu: Elige un tipo de ausencia desde el menú de la derecha
+
diff --git a/src/stores/useWeekdayStore.js b/src/stores/useWeekdayStore.js
new file mode 100644
index 000000000..ad898c9a7
--- /dev/null
+++ b/src/stores/useWeekdayStore.js
@@ -0,0 +1,95 @@
+import { reactive, ref, computed } from 'vue';
+import { useI18n } from 'vue-i18n';
+import { defineStore } from 'pinia';
+
+export const useWeekdayStore = defineStore('weekdayStore', () => {
+ const { t } = useI18n();
+
+ const weekdays = [
+ { code: 'sun', name: 'Sunday' },
+ { code: 'mon', name: 'Monday' },
+ { code: 'tue', name: 'Tuesday' },
+ { code: 'wed', name: 'Wednesday' },
+ { code: 'thu', name: 'Thursday' },
+ { code: 'fri', name: 'Friday' },
+ { code: 'sat', name: 'Saturday' },
+ ];
+
+ const monthCodes = [
+ 'jan',
+ 'feb',
+ 'mar',
+ 'apr',
+ 'may',
+ 'jun',
+ 'jul',
+ 'aug',
+ 'sep',
+ 'oct',
+ 'nov',
+ 'dec',
+ ];
+
+ const localeOrder = {
+ es: ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'],
+ en: ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'],
+ };
+
+ const weekdaysMap = reactive({});
+ const localeWeekdays = ref([]);
+
+ const initStore = () => {
+ getWeekdaysMap();
+ };
+
+ const getWeekdaysMap = () => {
+ if (Object.keys(weekdaysMap).length > 0) return weekdaysMap;
+
+ weekdays.forEach((day, i) => {
+ const obj = {
+ ...day,
+ index: i,
+ char: day.name.substr(0, 1),
+ abr: day.name.substr(0, 3),
+ };
+ weekdaysMap[day.code] = obj;
+ });
+ };
+
+ const getLocales = computed(() => {
+ // El día de mañana esto permitirá ordenar los weekdays en base a el locale si se lo desea reemplazando localeOrder.es por localeOrder[locale]
+ const locales = [];
+ for (let code of localeOrder.es) {
+ const obj = {
+ ...weekdaysMap[code],
+ locale: t(`weekdays.${weekdaysMap[code].code}`),
+ localeChar: t(`weekdays.${weekdaysMap[code].code}`).substr(0, 1),
+ localeAbr: t(`weekdays.${weekdaysMap[code].code}`).substr(0, 3),
+ };
+ locales.push(obj);
+ }
+ return locales;
+ });
+
+ const getLocaleMonths = computed(() => {
+ const locales = [];
+ for (let code of monthCodes) {
+ const obj = {
+ code: code,
+ locale: t(`months.${code}`),
+ };
+ locales.push(obj);
+ }
+ return locales;
+ });
+
+ return {
+ initStore,
+ weekdaysMap,
+ localeWeekdays,
+ getLocales,
+ weekdays,
+ monthCodes,
+ getLocaleMonths,
+ };
+});