feat(timesheet): fully implement holiday tracker with web API. Only works for current year, however.
This commit is contained in:
parent
8b0e40dc2a
commit
b8c112f149
|
|
@ -6,18 +6,19 @@
|
||||||
import ShiftListDateWidget from 'src/modules/timesheets/components/shift-list-date-widget.vue';
|
import ShiftListDateWidget from 'src/modules/timesheets/components/shift-list-date-widget.vue';
|
||||||
|
|
||||||
import { date, useQuasar } from 'quasar';
|
import { date, useQuasar } from 'quasar';
|
||||||
import { ref, computed, watch } from 'vue';
|
import { ref, computed, watch, onMounted } from 'vue';
|
||||||
import { useUiStore } from 'src/stores/ui-store';
|
import { useUiStore } from 'src/stores/ui-store';
|
||||||
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
||||||
import { Shift } from 'src/modules/timesheets/models/shift.models';
|
import { Shift } from 'src/modules/timesheets/models/shift.models';
|
||||||
import { useTimesheetApi } from 'src/modules/timesheets/composables/use-timesheet-api';
|
import { useTimesheetApi } from 'src/modules/timesheets/composables/use-timesheet-api';
|
||||||
import type { TimesheetDay } from 'src/modules/timesheets/models/timesheet.models';
|
import type { TimesheetDay } from 'src/modules/timesheets/models/timesheet.models';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
|
|
||||||
const CURRENT_DATE_STRING = new Date().toISOString().slice(0, 10);
|
const CURRENT_DATE_STRING = new Date().toISOString().slice(0, 10);
|
||||||
const HOLIDAYS: string[] = ['2026-01-01', '2025-11-26']
|
|
||||||
|
|
||||||
const { extractDate } = date;
|
const { extractDate } = date;
|
||||||
|
const { locale } = useI18n();
|
||||||
const q = useQuasar();
|
const q = useQuasar();
|
||||||
|
|
||||||
const ui_store = useUiStore();
|
const ui_store = useUiStore();
|
||||||
|
|
@ -59,11 +60,26 @@
|
||||||
return iso_date_string === CURRENT_DATE_STRING ? 'currentDayComponent' : '';
|
return iso_date_string === CURRENT_DATE_STRING ? 'currentDayComponent' : '';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getHolidayName = (date: string) => {
|
||||||
|
const holiday = timesheet_store.federal_holidays.find(holiday => holiday.date === date);
|
||||||
|
if (!holiday) return;
|
||||||
|
|
||||||
|
if (locale.value === 'fr-FR')
|
||||||
|
return holiday.nameFr;
|
||||||
|
|
||||||
|
else if (locale.value === 'en-CA')
|
||||||
|
return holiday.nameEn;
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await timesheet_store.getCurrentFederalHolidays();
|
||||||
|
});
|
||||||
|
|
||||||
watch(currentDayComponentWatcher, () => {
|
watch(currentDayComponentWatcher, () => {
|
||||||
if (currentDayComponent.value && q.platform.is.mobile) {
|
if (currentDayComponent.value && q.platform.is.mobile) {
|
||||||
emit('onCurrentDayComponentFound', currentDayComponent.value[0])
|
emit('onCurrentDayComponentFound', currentDayComponent.value[0])
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
@ -111,11 +127,11 @@
|
||||||
>
|
>
|
||||||
<!-- optional label indicating which holiday if today is a holiday -->
|
<!-- optional label indicating which holiday if today is a holiday -->
|
||||||
<span
|
<span
|
||||||
v-if="HOLIDAYS.includes(day.date)"
|
v-if="timesheet_store.federal_holidays.some(holiday => holiday.date === day.date)"
|
||||||
class="absolute-top-left text-uppercase text-weight-bolder text-purple-5"
|
class="absolute-top-left text-uppercase text-weight-bolder text-purple-5"
|
||||||
style="transform: translate(25px, -7px);"
|
style="transform: translate(25px, -7px);"
|
||||||
>
|
>
|
||||||
New Year's of the nouvelle annee
|
{{ getHolidayName(day.date) }}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<!-- mobile version in portrait mode -->
|
<!-- mobile version in portrait mode -->
|
||||||
|
|
@ -183,11 +199,11 @@
|
||||||
<div
|
<div
|
||||||
v-else
|
v-else
|
||||||
class="col row full-width rounded-10 ellipsis shadow-10"
|
class="col row full-width rounded-10 ellipsis shadow-10"
|
||||||
:style="HOLIDAYS.includes(day.date) ? 'border: 2px solid #ab47bc' : ''"
|
:style="timesheet_store.federal_holidays.some(holiday => holiday.date === day.date) ? 'border: 2px solid #ab47bc' : ''"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="col row"
|
class="col row"
|
||||||
:class="(getDayApproval(day) || timesheet.is_approved) ? (HOLIDAYS.includes(day.date) ? 'bg-purple-5' : 'bg-accent') : 'bg-dark'"
|
:class="(getDayApproval(day) || timesheet.is_approved) ? (timesheet_store.federal_holidays.some(holiday => holiday.date === day.date) ? 'bg-purple-5' : 'bg-accent') : 'bg-dark'"
|
||||||
>
|
>
|
||||||
<!-- Date block -->
|
<!-- Date block -->
|
||||||
<ShiftListDateWidget
|
<ShiftListDateWidget
|
||||||
|
|
@ -200,7 +216,7 @@
|
||||||
:timesheet-id="timesheet.timesheet_id"
|
:timesheet-id="timesheet.timesheet_id"
|
||||||
:week-day-index="day_index"
|
:week-day-index="day_index"
|
||||||
:day="day"
|
:day="day"
|
||||||
:holiday="HOLIDAYS.includes(day.date)"
|
:holiday="timesheet_store.federal_holidays.some(holiday => holiday.date === day.date)"
|
||||||
:approved="getDayApproval(day) || timesheet.is_approved"
|
:approved="getDayApproval(day) || timesheet.is_approved"
|
||||||
class="col"
|
class="col"
|
||||||
@delete-unsaved-shift="deleteUnsavedShift(timesheet_index, day_index)"
|
@delete-unsaved-shift="deleteUnsavedShift(timesheet_index, day_index)"
|
||||||
|
|
@ -215,7 +231,7 @@
|
||||||
color="white"
|
color="white"
|
||||||
size="xl"
|
size="xl"
|
||||||
class="full-height"
|
class="full-height"
|
||||||
:class="(getDayApproval(day) || timesheet.is_approved) ? (HOLIDAYS.includes(day.date) ? 'bg-purple-5' : 'bg-accent') : ''"
|
:class="(getDayApproval(day) || timesheet.is_approved) ? (timesheet_store.federal_holidays.some(holiday => holiday.date === day.date) ? 'bg-purple-5' : 'bg-accent') : ''"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<q-btn
|
<q-btn
|
||||||
|
|
@ -224,7 +240,7 @@
|
||||||
square
|
square
|
||||||
icon="more_time"
|
icon="more_time"
|
||||||
size="lg"
|
size="lg"
|
||||||
:color="HOLIDAYS.includes(day.date) ? 'purple-5' : 'accent'"
|
:color="timesheet_store.federal_holidays.some(holiday => holiday.date === day.date) ? 'purple-5' : 'accent'"
|
||||||
text-color="white"
|
text-color="white"
|
||||||
class="full-height"
|
class="full-height"
|
||||||
:class="$q.platform.is.mobile ? 'q-px-xs' : ''"
|
:class="$q.platform.is.mobile ? 'q-px-xs' : ''"
|
||||||
|
|
|
||||||
31
src/modules/timesheets/models/federal-holidays.models.ts
Normal file
31
src/modules/timesheets/models/federal-holidays.models.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
export interface FederalHoliday {
|
||||||
|
id: number;
|
||||||
|
date: string;
|
||||||
|
nameEn: string;
|
||||||
|
nameFr: string;
|
||||||
|
federal: number;
|
||||||
|
observedDate: string;
|
||||||
|
provinces: FederalHolidayProvince[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FederalHolidayProvince {
|
||||||
|
id: number;
|
||||||
|
nameEn: string;
|
||||||
|
nameFr: string;
|
||||||
|
sourceLink: string;
|
||||||
|
sourceEn: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TARGO_HOLIDAY_NAMES_FR: string[] = [
|
||||||
|
"Jour de l’An",
|
||||||
|
"Vendredi saint",
|
||||||
|
"Lundi de Pâques",
|
||||||
|
"Journée nationale des patriotes",
|
||||||
|
"Saint-Jean-Baptiste / Fête nationale du Québec",
|
||||||
|
"Fête du Canada",
|
||||||
|
"Fête du travail",
|
||||||
|
"Journée nationale de la vérité et de la réconciliation",
|
||||||
|
"Action de grâce",
|
||||||
|
"Noël",
|
||||||
|
"Lendemain de Noël",
|
||||||
|
]
|
||||||
|
|
@ -3,8 +3,14 @@ import type { PayPeriod } from "src/modules/shared/models/pay-period.models";
|
||||||
import type { TimesheetResponse } from "src/modules/timesheets/models/timesheet.models";
|
import type { TimesheetResponse } from "src/modules/timesheets/models/timesheet.models";
|
||||||
import type { TimesheetApprovalOverview } from "src/modules/timesheet-approval/models/timesheet-overview.models";
|
import type { TimesheetApprovalOverview } from "src/modules/timesheet-approval/models/timesheet-overview.models";
|
||||||
import type { BackendResponse } from "src/modules/shared/models/backend-response.models";
|
import type { BackendResponse } from "src/modules/shared/models/backend-response.models";
|
||||||
|
import type { FederalHoliday } from "src/modules/timesheets/models/federal-holidays.models";
|
||||||
|
|
||||||
export const timesheetService = {
|
export const timesheetService = {
|
||||||
|
getAllFederalHolidays: async (): Promise<FederalHoliday[]> => {
|
||||||
|
const response = await api.get<{ holidays: FederalHoliday[] }>('https://canada-holidays.ca/api/v1/holidays', { withCredentials: false });
|
||||||
|
return response.data.holidays;
|
||||||
|
},
|
||||||
|
|
||||||
getPayPeriodByDate: async (date_string: string): Promise<PayPeriod> => {
|
getPayPeriodByDate: async (date_string: string): Promise<PayPeriod> => {
|
||||||
const response = await api.get<{ success: boolean, data: PayPeriod, error?: string }>(`pay-periods/date/${date_string}`);
|
const response = await api.get<{ success: boolean, data: PayPeriod, error?: string }>(`pay-periods/date/${date_string}`);
|
||||||
return response.data.data;
|
return response.data.data;
|
||||||
|
|
|
||||||
|
|
@ -36,16 +36,3 @@ export const SHIFT_OPTIONS: ShiftOption[] = [
|
||||||
{ label: 'timesheet.shift.types.BANKING', value: 'BANKING', icon: 'savings', icon_color: 'pink-3' },
|
{ label: 'timesheet.shift.types.BANKING', value: 'BANKING', icon: 'savings', icon_color: 'pink-3' },
|
||||||
{ label: 'timesheet.shift.types.WITHDRAW_BANKED', value: 'WITHDRAW_BANKED', icon: 'attach_money', icon_color: 'yellow-4' },
|
{ label: 'timesheet.shift.types.WITHDRAW_BANKED', value: 'WITHDRAW_BANKED', icon: 'attach_money', icon_color: 'yellow-4' },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const HOLIDAY_NAMES: string[] = [
|
|
||||||
"Jour de l’An",
|
|
||||||
"Vendredi saint",
|
|
||||||
"Lundi de Pâques",
|
|
||||||
"Journée nationale des patriotes",
|
|
||||||
"Saint-Jean-Baptiste / Fête nationale du Québec",
|
|
||||||
"Fête du Canada",
|
|
||||||
"Fête du travail",
|
|
||||||
"Journée nationale de la vérité et de la réconciliation",
|
|
||||||
"Action de grâce",
|
|
||||||
"Noël",
|
|
||||||
]
|
|
||||||
|
|
@ -7,6 +7,7 @@ import type { PayPeriodOverviewResponse, TimesheetApprovalOverview } from "src/m
|
||||||
import type { PayPeriod } from 'src/modules/shared/models/pay-period.models';
|
import type { PayPeriod } from 'src/modules/shared/models/pay-period.models';
|
||||||
import type { Timesheet } from 'src/modules/timesheets/models/timesheet.models';
|
import type { Timesheet } from 'src/modules/timesheets/models/timesheet.models';
|
||||||
import type { TimesheetApprovalCSVReportFilters } from 'src/modules/timesheet-approval/models/timesheet-approval-csv-report.models';
|
import type { TimesheetApprovalCSVReportFilters } from 'src/modules/timesheet-approval/models/timesheet-approval-csv-report.models';
|
||||||
|
import { type FederalHoliday, TARGO_HOLIDAY_NAMES_FR } from 'src/modules/timesheets/models/federal-holidays.models';
|
||||||
|
|
||||||
|
|
||||||
export const useTimesheetStore = defineStore('timesheet', () => {
|
export const useTimesheetStore = defineStore('timesheet', () => {
|
||||||
|
|
@ -26,6 +27,16 @@ export const useTimesheetStore = defineStore('timesheet', () => {
|
||||||
const current_pay_period_overview = ref<TimesheetApprovalOverview>();
|
const current_pay_period_overview = ref<TimesheetApprovalOverview>();
|
||||||
const pay_period_report = ref();
|
const pay_period_report = ref();
|
||||||
|
|
||||||
|
const federal_holidays = ref<FederalHoliday[]>([]);
|
||||||
|
|
||||||
|
const getCurrentFederalHolidays = async(): Promise<boolean> => {
|
||||||
|
const all_federal_holidays = await timesheetService.getAllFederalHolidays();
|
||||||
|
if (!all_federal_holidays) return false;
|
||||||
|
|
||||||
|
federal_holidays.value = all_federal_holidays.filter(holiday => TARGO_HOLIDAY_NAMES_FR.includes(holiday.nameFr));
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
const getNextOrPreviousPayPeriod = (direction: number) => {
|
const getNextOrPreviousPayPeriod = (direction: number) => {
|
||||||
if (!pay_period.value) return;
|
if (!pay_period.value) return;
|
||||||
|
|
||||||
|
|
@ -178,6 +189,8 @@ export const useTimesheetStore = defineStore('timesheet', () => {
|
||||||
timesheets,
|
timesheets,
|
||||||
all_current_shifts,
|
all_current_shifts,
|
||||||
initial_timesheets,
|
initial_timesheets,
|
||||||
|
federal_holidays,
|
||||||
|
getCurrentFederalHolidays,
|
||||||
getNextOrPreviousPayPeriod,
|
getNextOrPreviousPayPeriod,
|
||||||
getPayPeriodByDateOrYearAndNumber,
|
getPayPeriodByDateOrYearAndNumber,
|
||||||
getTimesheetOverviews,
|
getTimesheetOverviews,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user