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(false); const pay_period = ref(); const timesheets = ref([]); const all_current_shifts = computed(() => timesheets.value.flatMap(week => week.days.flatMap(day => day.shifts)) ?? []); const initial_timesheets = ref([]); const pay_period_overviews = ref([]); const pay_period_infos = ref(); const is_report_dialog_open = ref(false); const is_details_dialog_open = ref(false); const selected_employee_name = ref(); const has_timesheet_preset = ref(false); const current_pay_period_overview = ref(); const pay_period_report = ref(); const pay_period_observer = ref(); const federal_holidays = ref([]); const getCurrentFederalHolidays = async (): Promise => { 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 => { 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 => { 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 => { 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 => { 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) => { // 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, }; });