249 lines
11 KiB
TypeScript
249 lines
11 KiB
TypeScript
import { computed, ref } from 'vue';
|
|
import { defineStore } from 'pinia';
|
|
import { unwrapAndClone } from 'src/utils/unwrap-and-clone';
|
|
import { timesheetApprovalService } from 'src/modules/timesheet-approval/services/timesheet-approval-service';
|
|
import { timesheetService } from 'src/modules/timesheets/services/timesheet-service';
|
|
import type { PayPeriodOverviewResponse, TimesheetApprovalOverview } from "src/modules/timesheet-approval/models/timesheet-overview.models";
|
|
import type { PayPeriod } from 'src/modules/shared/models/pay-period.models';
|
|
import type { Timesheet } from 'src/modules/timesheets/models/timesheet.models';
|
|
import type { PayPeriodEvent } from 'src/modules/timesheet-approval/models/pay-period-event.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';
|
|
import { Notify } from 'quasar';
|
|
import { useI18n } from 'vue-i18n';
|
|
|
|
|
|
export const useTimesheetStore = defineStore('timesheet', () => {
|
|
const { t } = useI18n();
|
|
const is_loading = ref<boolean>(false);
|
|
const pay_period = ref<PayPeriod>();
|
|
const timesheets = ref<Timesheet[]>([]);
|
|
const all_current_shifts = computed(() => timesheets.value.flatMap(week => week.days.flatMap(day => day.shifts)) ?? []);
|
|
const initial_timesheets = ref<Timesheet[]>([]);
|
|
|
|
const pay_period_overviews = ref<TimesheetApprovalOverview[]>([]);
|
|
const pay_period_infos = ref<PayPeriodOverviewResponse>();
|
|
const is_report_dialog_open = ref(false);
|
|
|
|
const is_details_dialog_open = ref(false);
|
|
const selected_employee_name = ref<string>();
|
|
const has_timesheet_preset = ref(false);
|
|
const current_pay_period_overview = ref<TimesheetApprovalOverview>();
|
|
const pay_period_report = ref();
|
|
const pay_period_observer = ref<EventSource | undefined>();
|
|
|
|
const federal_holidays = ref<FederalHoliday[]>([]);
|
|
|
|
const getCurrentFederalHolidays = async (): Promise<boolean> => {
|
|
const all_federal_holidays = await timesheetService.getAllFederalHolidays();
|
|
const all_federal_holidays_2025 = await timesheetService.getAllFederalHolidays(2025);
|
|
if (!all_federal_holidays || !all_federal_holidays_2025) return false;
|
|
|
|
federal_holidays.value = all_federal_holidays.filter(holiday => TARGO_HOLIDAY_NAMES_FR.includes(holiday.nameFr));
|
|
const targo_fed_holidays_2025 = all_federal_holidays_2025.filter(holiday => TARGO_HOLIDAY_NAMES_FR.includes(holiday.nameFr));
|
|
targo_fed_holidays_2025.forEach(holiday => federal_holidays.value.push(holiday));
|
|
|
|
return true;
|
|
};
|
|
|
|
const getNextOrPreviousPayPeriod = (direction: number) => {
|
|
if (!pay_period.value) return;
|
|
|
|
pay_period.value.pay_period_no += direction;
|
|
|
|
if (pay_period.value.pay_period_no > 26) {
|
|
pay_period.value.pay_period_no = 1;
|
|
pay_period.value.pay_year += direction;
|
|
}
|
|
|
|
if (pay_period.value.pay_period_no < 1) {
|
|
pay_period.value.pay_period_no = 26;
|
|
pay_period.value.pay_year += direction;
|
|
}
|
|
};
|
|
|
|
const getPayPeriodByDateOrYearAndNumber = async (date?: string): Promise<boolean> => {
|
|
try {
|
|
if (date !== undefined) {
|
|
pay_period.value = await timesheetService.getPayPeriodByDate(date);
|
|
} else if (pay_period.value !== undefined) {
|
|
pay_period.value = await timesheetService.getPayPeriodByYearAndPeriodNumber(pay_period.value.pay_year, pay_period.value.pay_period_no);
|
|
} else return false;
|
|
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Could not get current pay period: ', error);
|
|
pay_period.value = undefined;
|
|
pay_period_overviews.value = [];
|
|
//TODO: More in-depth error-handling here
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
const getTimesheetOverviews = async (): Promise<boolean> => {
|
|
is_loading.value = true;
|
|
|
|
try {
|
|
if (pay_period.value === undefined) {
|
|
is_loading.value = false;
|
|
return false;
|
|
}
|
|
|
|
const response = await timesheetApprovalService.getPayPeriodOverviews(pay_period.value.pay_year, pay_period.value.pay_period_no);
|
|
pay_period_overviews.value = response.employees_overview;
|
|
is_loading.value = false;
|
|
|
|
return true;
|
|
} catch (error) {
|
|
console.error('There was an error retrieving Employee Pay Period overviews: ', error);
|
|
pay_period_overviews.value = [];
|
|
// TODO: More in-depth error-handling here
|
|
is_loading.value = false;
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
const getTimesheetsByOptionalEmployeeEmail = async (employee_email?: string): Promise<boolean> => {
|
|
if (pay_period.value === undefined) return false;
|
|
is_loading.value = true;
|
|
let response;
|
|
|
|
try {
|
|
if (employee_email) {
|
|
response = await timesheetService.getTimesheetsByPayPeriodAndOptionalEmail(pay_period.value.pay_year, pay_period.value.pay_period_no, employee_email);
|
|
} else {
|
|
response = await timesheetService.getTimesheetsByPayPeriodAndOptionalEmail(pay_period.value.pay_year, pay_period.value.pay_period_no);
|
|
}
|
|
|
|
if (response.success && response.data) {
|
|
has_timesheet_preset.value = response.data.has_preset_schedule;
|
|
selected_employee_name.value = response.data.employee_fullname;
|
|
timesheets.value = response.data.timesheets;
|
|
initial_timesheets.value = unwrapAndClone(timesheets.value);
|
|
} else {
|
|
selected_employee_name.value = '';
|
|
timesheets.value = [];
|
|
initial_timesheets.value = [];
|
|
}
|
|
|
|
is_loading.value = false;
|
|
return response.success;
|
|
} catch (error) {
|
|
console.error('There was an error retrieving timesheet details for this employee: ', error);
|
|
// TODO: More in-depth error-handling here
|
|
timesheets.value = [];
|
|
is_loading.value = false;
|
|
return false;
|
|
}
|
|
};
|
|
|
|
const toggleTimesheetsApprovalByEmployeeEmail = async (email: string, approval_status: boolean): Promise<boolean> => {
|
|
try {
|
|
const timesheet_ids = timesheets.value.map(timesheet => timesheet.timesheet_id);
|
|
|
|
// Backend returns the amount of shifts and expenses successfully updated, could be useful for error handling???
|
|
// const shift_expense_count = timesheets.value.reduce((timesheets_sum, timesheet) => {
|
|
// return timesheets_sum + timesheet.days.reduce((day_sum, day) => {
|
|
// return day_sum + day.shifts.length + day.expenses.length
|
|
// }, 0);
|
|
// }, 0);
|
|
|
|
const response = await timesheetApprovalService.updateTimesheetsApprovalStatus(email, timesheet_ids, approval_status);
|
|
return response.success;
|
|
} catch (error) {
|
|
console.error("couldn't approve timesheets for employee: ", error);
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
const getPayPeriodReport = async (report_filters: TimesheetApprovalCSVReportFilters) => {
|
|
try {
|
|
if (!pay_period.value) return false;
|
|
const response = await timesheetApprovalService.getPayPeriodReportByYearAndPeriodNumber(pay_period.value.pay_year, pay_period.value.pay_period_no, report_filters);
|
|
pay_period_report.value = response;
|
|
return response.data;
|
|
} catch (error) {
|
|
console.error('There was an error retrieving the report CSV: ', error);
|
|
// TODO: More in-depth error-handling here
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
const openReportDialog = () => {
|
|
is_report_dialog_open.value = true;
|
|
is_loading.value = true;
|
|
|
|
|
|
is_loading.value = false;
|
|
};
|
|
|
|
const closeReportDialog = () => {
|
|
is_report_dialog_open.value = false;
|
|
};
|
|
|
|
const subscribeToPayPeriodObservable = () => {
|
|
if (pay_period_observer.value === undefined) {
|
|
pay_period_observer.value = timesheetApprovalService.subscribeToPayPeriodObservable();
|
|
pay_period_observer.value.onmessage = async (event: MessageEvent<string>) => {
|
|
// find employee that modified their timesheets
|
|
const pay_period_event: PayPeriodEvent = JSON.parse(event.data);
|
|
const overview = pay_period_overviews.value.find(overview => overview.email === pay_period_event.employee_email);
|
|
const employee_name = overview?.employee_first_name + ' ' + overview?.employee_last_name;
|
|
|
|
// update overviews
|
|
await getTimesheetOverviews();
|
|
|
|
// if user is looking at details of employee that generated event, update
|
|
if (selected_employee_name.value === employee_name)
|
|
await getTimesheetsByOptionalEmployeeEmail(pay_period_event.employee_email);
|
|
|
|
// create visual feedback of notification and update
|
|
Notify.create({
|
|
message: `${employee_name} ${t('timesheet_approvals.event.' + pay_period_event.action)} ${t('timesheet_approvals.event.' + pay_period_event.event_type)}`,
|
|
color: 'warning',
|
|
textColor: 'primary',
|
|
classes: 'text-weight-bolder',
|
|
caption: t('timesheet_approvals.event.update_notification'),
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
const unsubscribeToPayPeriodObservable = () => {
|
|
if (pay_period_observer.value) {
|
|
pay_period_observer.value.close();
|
|
pay_period_observer.value = undefined;
|
|
}
|
|
}
|
|
|
|
return {
|
|
is_loading,
|
|
is_report_dialog_open,
|
|
is_details_dialog_open,
|
|
pay_period,
|
|
pay_period_overviews,
|
|
current_pay_period_overview,
|
|
pay_period_infos,
|
|
selected_employee_name,
|
|
has_timesheet_preset,
|
|
timesheets,
|
|
all_current_shifts,
|
|
initial_timesheets,
|
|
federal_holidays,
|
|
getCurrentFederalHolidays,
|
|
getNextOrPreviousPayPeriod,
|
|
getPayPeriodByDateOrYearAndNumber,
|
|
getTimesheetOverviews,
|
|
getTimesheetsByOptionalEmployeeEmail,
|
|
toggleTimesheetsApprovalByEmployeeEmail,
|
|
getPayPeriodReport,
|
|
openReportDialog,
|
|
closeReportDialog,
|
|
subscribeToPayPeriodObservable,
|
|
unsubscribeToPayPeriodObservable,
|
|
};
|
|
}); |