From 89148343b610fa81733123eadcb447cc5a53a699 Mon Sep 17 00:00:00 2001 From: Nicolas Drolet Date: Tue, 2 Sep 2025 16:56:04 -0400 Subject: [PATCH] feat(approvals): add chart to track total hours for each type, chart to track expenses, begin work on widget to display detailed shift info. --- src/i18n/en-ca/index.ts | 2 +- ...al-employee-details-hours-worked-chart.vue | 26 +---- ...val-employee-details-shift-types-chart.vue | 63 ++++++++++++ ...sheet-approval-employee-expenses-chart.vue | 81 ++++++++++++++++ ...sheet-approval-employee-details-shifts.vue | 14 +++ .../timesheet-approval-employee-details.vue | 95 +++++++++++++++++-- ...esheet-approval-employee-overview-list.vue | 12 ++- .../composables/use-timesheet-approval-api.ts | 12 ++- .../services/services-timesheet-approval.ts | 3 +- .../types/timesheet-details-interface.ts | 25 ++--- 10 files changed, 282 insertions(+), 51 deletions(-) create mode 100644 src/modules/timesheet-approval/components/graphs/timesheet-approval-employee-details-shift-types-chart.vue create mode 100644 src/modules/timesheet-approval/components/graphs/timesheet-approval-employee-expenses-chart.vue create mode 100644 src/modules/timesheet-approval/components/timesheet-approval-employee-details-shifts.vue diff --git a/src/i18n/en-ca/index.ts b/src/i18n/en-ca/index.ts index 71b4552..c7ac6d0 100644 --- a/src/i18n/en-ca/index.ts +++ b/src/i18n/en-ca/index.ts @@ -246,7 +246,7 @@ export default { newUsers: 'New user', updateUsers: 'Update user', timeSheets: 'Time sheet', - timeSheetValidations: 'Time sheet', + timeSheetValidations: 'Time sheet approvals', }, timeSheet: { timeSheetTab_1: 'Shifts', diff --git a/src/modules/timesheet-approval/components/graphs/timesheet-approval-employee-details-hours-worked-chart.vue b/src/modules/timesheet-approval/components/graphs/timesheet-approval-employee-details-hours-worked-chart.vue index 95bcbfc..0b57ee6 100644 --- a/src/modules/timesheet-approval/components/graphs/timesheet-approval-employee-details-hours-worked-chart.vue +++ b/src/modules/timesheet-approval/components/graphs/timesheet-approval-employee-details-hours-worked-chart.vue @@ -6,6 +6,7 @@ import type { PayPeriodEmployeeDetails } from 'src/modules/timesheet-approval/types/timesheet-approval-pay-period-employee-details-interface'; const { t } = useI18n(); + ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale); ChartJS.defaults.font.family = '"Roboto", sans-serif'; @@ -21,8 +22,7 @@ }); const hours_worked_labels = ref([]); - const hours_worked_dataset = ref[]>([]); - + const hours_worked_dataset = ref[]>([]); const getHoursWorkedData = (): ChartData<'bar'> => { if (props.rawData) { @@ -63,30 +63,12 @@ datasets: hours_worked_dataset.value, }; }; - \ No newline at end of file diff --git a/src/modules/timesheet-approval/components/graphs/timesheet-approval-employee-details-shift-types-chart.vue b/src/modules/timesheet-approval/components/graphs/timesheet-approval-employee-details-shift-types-chart.vue new file mode 100644 index 0000000..a736325 --- /dev/null +++ b/src/modules/timesheet-approval/components/graphs/timesheet-approval-employee-details-shift-types-chart.vue @@ -0,0 +1,63 @@ + + + \ No newline at end of file diff --git a/src/modules/timesheet-approval/components/graphs/timesheet-approval-employee-expenses-chart.vue b/src/modules/timesheet-approval/components/graphs/timesheet-approval-employee-expenses-chart.vue new file mode 100644 index 0000000..1817716 --- /dev/null +++ b/src/modules/timesheet-approval/components/graphs/timesheet-approval-employee-expenses-chart.vue @@ -0,0 +1,81 @@ + + + \ No newline at end of file diff --git a/src/modules/timesheet-approval/components/timesheet-approval-employee-details-shifts.vue b/src/modules/timesheet-approval/components/timesheet-approval-employee-details-shifts.vue new file mode 100644 index 0000000..6806242 --- /dev/null +++ b/src/modules/timesheet-approval/components/timesheet-approval-employee-details-shifts.vue @@ -0,0 +1,14 @@ + + + \ No newline at end of file diff --git a/src/modules/timesheet-approval/components/timesheet-approval-employee-details.vue b/src/modules/timesheet-approval/components/timesheet-approval-employee-details.vue index cf235b1..9c7c955 100644 --- a/src/modules/timesheet-approval/components/timesheet-approval-employee-details.vue +++ b/src/modules/timesheet-approval/components/timesheet-approval-employee-details.vue @@ -1,17 +1,25 @@ \ No newline at end of file diff --git a/src/modules/timesheet-approval/components/timesheet-approval-employee-overview-list.vue b/src/modules/timesheet-approval/components/timesheet-approval-employee-overview-list.vue index 3f361fb..e97cd0c 100644 --- a/src/modules/timesheet-approval/components/timesheet-approval-employee-overview-list.vue +++ b/src/modules/timesheet-approval/components/timesheet-approval-employee-overview-list.vue @@ -26,6 +26,7 @@ const report_filter_company = ref([true, true]); const report_filter_type = ref([true, true, true, true]); const clicked_employee_name = ref(''); + const clicked_employee_email = ref(''); const update_key = ref(0); const columns = computed((): QTableColumn[] => [ @@ -114,13 +115,19 @@ } } + const getEmployeeOverview = (email: string): PayPeriodOverviewEmployee | undefined => { + return timesheet_approval_api.getPayPeriodOverviewByEmployeeEmail(email); + } + const onDateSelected = async (date_string: string) => { await timesheet_approval_api.getPayPeriodOverviewByDate(date_string); }; const onClickedDetails = async (email: string, name: string) => { - clicked_employee_name.value = name; + clicked_employee_name.value = name; + clicked_employee_email.value = email; is_showing_details.value = true; + await timesheet_approval_api.getTimesheetsByPayPeriodAndEmail(email); }; @@ -143,13 +150,14 @@ transition-show="jump-down" transition-hide="jump-down" @before-show="() => update_key += 1" + class="full-width" >
diff --git a/src/modules/timesheet-approval/composables/use-timesheet-approval-api.ts b/src/modules/timesheet-approval/composables/use-timesheet-approval-api.ts index 4f424d5..3b7018d 100644 --- a/src/modules/timesheet-approval/composables/use-timesheet-approval-api.ts +++ b/src/modules/timesheet-approval/composables/use-timesheet-approval-api.ts @@ -1,6 +1,7 @@ import { useTimesheetStore } from "src/stores/timesheet-store"; import { useAuthStore } from "src/stores/auth-store"; import type { PayPeriodReportFilters } from "../types/timesheet-approval-pay-period-report-interface"; +import type { PayPeriodOverviewEmployee } from "../types/timesheet-approval-pay-period-overview-employee-interface"; export const useTimesheetApprovalApi = () => { const timesheet_store = useTimesheetStore(); @@ -15,6 +16,10 @@ export const useTimesheetApprovalApi = () => { } } + const getPayPeriodOverviewByEmployeeEmail = (email: string): PayPeriodOverviewEmployee | undefined => { + return timesheet_store.pay_period_overview_employees.find(overview => overview.email === email); + }; + /* This method attempts to get the next or previous pay period. It checks if pay period number is within a certain range, adjusts pay period and year accordingly. It then requests the matching pay period object to set as current pay period from server. @@ -39,11 +44,11 @@ export const useTimesheetApprovalApi = () => { if (success) { await timesheet_store.getTimesheetApprovalPayPeriodEmployeeOverviews(new_pay_year, new_pay_period_no, auth_store.user.email); } - } + }; const getTimesheetsByPayPeriodAndEmail = async (employee_email: string) => { await timesheet_store.getTimesheetsByPayPeriodAndEmail(employee_email); - } + }; const getTimesheetApprovalCSVReport = async ( report_filter_company: boolean[], report_filter_type: boolean[] ) => { const [ targo, solucom ] = report_filter_company; @@ -54,11 +59,12 @@ export const useTimesheetApprovalApi = () => { } as PayPeriodReportFilters; await timesheet_store.getTimesheetApprovalCSVReport(options); - } + }; return { getPayPeriodOverviewByDate, getNextPayPeriodOverview, + getPayPeriodOverviewByEmployeeEmail, getTimesheetsByPayPeriodAndEmail, getTimesheetApprovalCSVReport } diff --git a/src/modules/timesheet-approval/services/services-timesheet-approval.ts b/src/modules/timesheet-approval/services/services-timesheet-approval.ts index 43f509d..814e7f1 100644 --- a/src/modules/timesheet-approval/services/services-timesheet-approval.ts +++ b/src/modules/timesheet-approval/services/services-timesheet-approval.ts @@ -19,13 +19,12 @@ export const timesheetApprovalService = { getPayPeriodEmployeeOverviews: async (year: number, period_number: number, supervisor_email: string): Promise => { // TODO: REMOVE MOCK DATA PEFORE PUSHING TO PROD const response = await api.get(`pay-periods/${year}/${period_number}/${supervisor_email}`); - console.log('all employee data: ', response.data); + console.log('pay period data: ', response.data); return response.data; }, getTimesheetsByPayPeriodAndEmail: async (year: number, period_no: number, email: string): Promise => { const response = await api.get('timesheets', { params: { year, period_no, email, }}); - console.log('employee details: ', response.data); return response.data; }, diff --git a/src/modules/timesheets/types/timesheet-details-interface.ts b/src/modules/timesheets/types/timesheet-details-interface.ts index b9d940d..13a2817 100644 --- a/src/modules/timesheets/types/timesheet-details-interface.ts +++ b/src/modules/timesheets/types/timesheet-details-interface.ts @@ -6,6 +6,16 @@ export interface TimesheetDetailsWeek { expenses: WeekDay; } +export interface TimesheetDetailsDailySchedule { + shifts: Shift[]; + regular_hours: number; + evening_hours: number; + emergency_hours: number; + overtime_hours: number; + short_date: string; // ex. 08/24 + break_duration?: number; +} + type WeekDay = { sun: T; mon: T; @@ -16,23 +26,14 @@ type WeekDay = { sat: T; } -interface TimesheetDetailsDailySchedule { - shifts: Shift[]; - regular_hours: number; - evening_hours: number; - emergency_hours: number; - overtime_hours: number; - short_date: string; // ex. 08/24 - break_duration?: number; -} interface TimesheetDetailsDailyExpenses { - costs: Expense[]; - mileage: Expense[]; + cash: Expense[]; + km: Expense[]; [otherType: string]: Expense[]; //for possible future types of expenses } -interface Expense { +export interface Expense { is_approved: boolean; amount: number; }; \ No newline at end of file