From 7f43341629055287bafb5cac7ba5108d38a4e65c Mon Sep 17 00:00:00 2001 From: Nicolas Drolet Date: Fri, 10 Oct 2025 17:04:14 -0400 Subject: [PATCH 001/107] refactor(approvals): so many changes that are difficult to keep track of. Work on more integration between approvals and timesheet, add list view to approvals, etc --- src/css/app.scss | 6 +- src/css/quasar.variables.scss | 10 +- .../components/main-layout-left-drawer.vue | 7 +- .../auth/components/login-dev-bypass.vue | 5 +- src/modules/auth/composables/use-auth-api.ts | 5 +- ...-item.vue => employee-list-table-item.vue} | 4 +- ...crew-table.vue => employee-list-table.vue} | 13 +- .../employee-profile.models.ts} | 0 .../services/employee-list-service.ts | 14 ++ .../services/services-employee-list.ts | 17 -- .../types/employee-list-table-interface.ts | 8 - .../employee/profile-panel-info-employee.vue | 2 +- .../employee/profile-panel-info-personal.vue | 2 +- .../pages/employee/profile-employee.vue | 2 +- src/modules/shared/models/user.models.ts | 24 ++- .../details-crud-dialog-chart-expenses.vue | 1 + ...details-crud-dialog-chart-hours-worked.vue | 4 +- .../details-crud-dialog-chart-shift-types.vue | 12 +- .../components/details-crud-dialog.vue | 139 ++++++------ .../components/overview-list-item.vue | 150 +++++++------ .../components/overview-list.vue | 109 +++++++++- .../composables/use-timesheet-approval-api.ts | 31 ++- .../models/pay-period-overview.models.ts | 71 +++++-- .../components/expense-crud-dialog-form.vue | 6 +- .../components/expense-crud-dialog-header.vue | 30 ++- .../expense-crud-dialog-list-item.vue | 201 ++++++++++++++++++ .../components/expense-crud-dialog-list.vue | 138 ++---------- .../shift-crud-dialog-add-update-shift.vue | 79 +++++++ .../components/shift-crud-dialog.vue | 95 +++------ .../components/shift-list-legend.vue | 8 +- .../timesheets/components/shift-list-row.vue | 154 ++++++++------ .../timesheets/components/shift-list.vue | 30 +-- .../components/timesheet-wrapper.vue | 21 +- .../composables/api/use-shift-api.ts | 76 +++---- .../timesheets/constants/shift.constants.ts | 3 +- .../timesheets/models/expense.models.ts | 13 +- src/modules/timesheets/models/shift.models.ts | 4 +- .../timesheets/services/timesheet-service.ts | 6 +- src/modules/timesheets/utils/expense.util.ts | 10 +- src/pages/employee-list-page.vue | 18 ++ src/pages/profile-page.vue | 2 +- src/pages/supervisor-crew-page.vue | 14 -- src/pages/timesheet-approval-page.vue | 2 +- src/pages/timesheet-page.vue | 8 +- src/router/routes.ts | 2 +- src/stores/auth-store.ts | 69 +++--- src/stores/employee-store.ts | 7 +- src/stores/expense-store.ts | 5 +- src/stores/shift-store.ts | 6 +- 49 files changed, 985 insertions(+), 658 deletions(-) rename src/modules/employee-list/components/{supervisor/supervisor-crew-table-item.vue => employee-list-table-item.vue} (89%) rename src/modules/employee-list/components/{supervisor/supervisor-crew-table.vue => employee-list-table.vue} (91%) rename src/modules/employee-list/{types/employee-profile-interface.ts => models/employee-profile.models.ts} (100%) create mode 100644 src/modules/employee-list/services/employee-list-service.ts delete mode 100644 src/modules/employee-list/services/services-employee-list.ts delete mode 100644 src/modules/employee-list/types/employee-list-table-interface.ts create mode 100644 src/modules/timesheets/components/expense-crud-dialog-list-item.vue create mode 100644 src/modules/timesheets/components/shift-crud-dialog-add-update-shift.vue create mode 100644 src/pages/employee-list-page.vue delete mode 100644 src/pages/supervisor-crew-page.vue diff --git a/src/css/app.scss b/src/css/app.scss index adfa295..9fa20a5 100644 --- a/src/css/app.scss +++ b/src/css/app.scss @@ -25,11 +25,15 @@ } body.body--dark { - --q-secondary: #0f1114; + --q-secondary: #2b2f34; color: $grey-2; } .body--light { --q-dark: #FFF; color: $blue-grey-8; +} + +.shift-highlight { + background: #0195462a; } \ No newline at end of file diff --git a/src/css/quasar.variables.scss b/src/css/quasar.variables.scss index 2131a9e..643d864 100644 --- a/src/css/quasar.variables.scss +++ b/src/css/quasar.variables.scss @@ -16,16 +16,16 @@ $primary : #019547; $secondary : #DAE0E7; $accent : #AAD5C4; -$dark-shadow-color : #019547; +$dark-shadow-color : #00220f; -$elevation-dark-umbra : rgba($dark-shadow-color, 0.4); -$elevation-dark-penumbra : rgba($dark-shadow-color, 0); -$elevation-dark-ambient : rgba($dark-shadow-color, 0); +$elevation-dark-umbra : rgba($dark-shadow-color, 1); +$elevation-dark-penumbra : rgba($dark-shadow-color, 0.2); +$elevation-dark-ambient : rgba($dark-shadow-color, 0.2); $dark-shadow-2 : 0 3px 5px -1px $elevation-dark-umbra, 0 5px 8px $elevation-dark-penumbra, 0 1px 14px $elevation-dark-ambient; $layout-shadow-dark : 0 0 10px 5px rgba($dark-shadow-color, 0.5); -$dark : #333; +$dark : #42444b; $dark-page : #343434; $positive : #21ba45; diff --git a/src/layouts/components/main-layout-left-drawer.vue b/src/layouts/components/main-layout-left-drawer.vue index c34b1eb..acea4f6 100644 --- a/src/layouts/components/main-layout-left-drawer.vue +++ b/src/layouts/components/main-layout-left-drawer.vue @@ -4,6 +4,7 @@ import { useUiStore } from 'src/stores/ui-store'; import { ref } from 'vue'; import { RouteNames } from 'src/router/router-constants'; +import { CAN_APPROVE_PAY_PERIODS } from 'src/modules/shared/models/user.models'; const authStore = useAuthStore(); const uiStore = useUiStore(); @@ -50,7 +51,7 @@ + v-if="CAN_APPROVE_PAY_PERIODS.includes(authStore.user.role)"> @@ -61,7 +62,7 @@ + v-if="CAN_APPROVE_PAY_PERIODS.includes(authStore.user.role)"> @@ -72,7 +73,7 @@ + v-if="CAN_APPROVE_PAY_PERIODS.includes(authStore.user.role)"> diff --git a/src/modules/auth/components/login-dev-bypass.vue b/src/modules/auth/components/login-dev-bypass.vue index 61314da..f4609d2 100644 --- a/src/modules/auth/components/login-dev-bypass.vue +++ b/src/modules/auth/components/login-dev-bypass.vue @@ -1,11 +1,12 @@ + + \ No newline at end of file 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 4f60aeb..765e4c0 100644 --- a/src/modules/timesheet-approval/composables/use-timesheet-approval-api.ts +++ b/src/modules/timesheet-approval/composables/use-timesheet-approval-api.ts @@ -1,13 +1,16 @@ import { useTimesheetStore } from "src/stores/timesheet-store"; import { useAuthStore } from "src/stores/auth-store"; import type { TimesheetApprovalCSVReportFilters } from "src/modules/timesheet-approval/models/timesheet-approval-csv-report.models"; +import { NavigatorConstants } from "src/modules/timesheet-approval/models/pay-period-overview.models"; export const useTimesheetApprovalApi = () => { const timesheet_store = useTimesheetStore(); const auth_store = useAuthStore(); - const getPayPeriodOverviewsByDate = async (date_string: string): Promise => { - const success = await timesheet_store.getPayPeriodByDateOrYearAndNumber(date_string); + const getPayPeriodOverviewsByDateOrYearAndNumber = async (date_or_year: string | number, period_number?: number): Promise => { + let success = false; + if (typeof date_or_year === 'string') success = await timesheet_store.getPayPeriodByDateOrYearAndNumber(date_or_year); + else if (typeof date_or_year === 'number' && period_number) success = await timesheet_store.getPayPeriodByDateOrYearAndNumber(date_or_year, period_number); if (success) { await timesheet_store.getPayPeriodOverviewsBySupervisorEmail( @@ -17,6 +20,26 @@ export const useTimesheetApprovalApi = () => { ); } }; + + const getNextOrPreviousPayPeriodOverview = async (direction: number) => { + let new_period_number = timesheet_store.pay_period.pay_period_no + direction; + let new_year = timesheet_store.pay_period.pay_year; + + if ( new_period_number > 26 || new_period_number < 1) { + new_period_number = 1; + new_year += direction; + } + + await getPayPeriodOverviewsByDateOrYearAndNumber(new_year, new_period_number); + }; + + const getNextPayPeriodOverview = async () => { + await getNextOrPreviousPayPeriodOverview(NavigatorConstants.NEXT_PERIOD); + }; + + const getPreviousPayPeriodOverview = async () => { + await getNextOrPreviousPayPeriodOverview(NavigatorConstants.PREVIOUS_PERIOD); + }; const getTimesheetApprovalCSVReport = async ( report_filter_company: boolean[], report_filter_type: boolean[], year?: number, period_number?: number ) => { const [ targo, solucom ] = report_filter_company; @@ -34,7 +57,9 @@ export const useTimesheetApprovalApi = () => { }; return { - getPayPeriodOverviewsByDate, + getPayPeriodOverviewsByDateOrYearAndNumber, getTimesheetApprovalCSVReport, + getNextPayPeriodOverview, + getPreviousPayPeriodOverview, } }; \ No newline at end of file diff --git a/src/modules/timesheet-approval/models/pay-period-overview.models.ts b/src/modules/timesheet-approval/models/pay-period-overview.models.ts index a83271d..082c1a6 100644 --- a/src/modules/timesheet-approval/models/pay-period-overview.models.ts +++ b/src/modules/timesheet-approval/models/pay-period-overview.models.ts @@ -1,15 +1,28 @@ +import type { QTableColumn } from "quasar"; + +/* eslint-disable */ +export enum NavigatorConstants { + NEXT_PERIOD = 1, + PREVIOUS_PERIOD = -1, +} + export interface PayPeriodOverview { email: string; employee_name: string; regular_hours: number; - evening_hours: number; - emergency_hours: number; - overtime_hours: number; + other_hours: { + evening_hours: number; + emergency_hours: number; + overtime_hours: number; + sick_hours: number; + holiday_hours: number; + vacation_hours: number; + }; total_hours: number; expenses: number; mileage: number; is_approved: boolean; -}; +} export interface PayPeriodOverviewResponse { pay_period_no: number; @@ -25,20 +38,26 @@ export const default_pay_period_overview: PayPeriodOverview = { email: '', employee_name: '', regular_hours: -1, - evening_hours: -1, - emergency_hours: -1, - overtime_hours: -1, + other_hours: { + evening_hours: -1, + emergency_hours: -1, + overtime_hours: -1, + sick_hours: -1, + holiday_hours: -1, + vacation_hours: -1, + }, total_hours: -1, expenses: -1, mileage: -1, is_approved: false } -export const pay_period_overview_columns = [ +export const pay_period_overview_columns: QTableColumn[] = [ { name: 'employee_name', label: 'timesheet_approvals.table.full_name', - field: 'employee_name', + align: 'left', + field: 'employee_name', sortable: true }, { @@ -48,27 +67,45 @@ export const pay_period_overview_columns = [ sortable: true, }, { - name: 'regular_hours', + name: 'REGULAR', label: 'shared.shift_type.regular', field: 'regular_hours', sortable: true, }, { - name: 'evening_hours', + name: 'EVENING', label: 'shared.shift_type.evening', - field: 'evening_hours', + field: row => row.other_hours.evening_hours, sortable: true, }, { - name: 'emergency_hours', + name: 'EMERGENCY', label: 'shared.shift_type.emergency', - field: 'emergency_hours', + field: row => row.other_hours.emergency_hours, + sortable: true, + }, + { + name: 'SICK', + label: 'shared.shift_type.sick', + field: row => row.other_hours.sick_hours, sortable: true, }, { - name: 'overtime_hours', + name: 'HOLIDAY', + label: 'shared.shift_type.holiday', + field: row => row.other_hours.holiday_hours, + sortable: true, + }, + { + name: 'VACATION', + label: 'shared.shift_type.vacation', + field: row => row.other_hours.vacation_hours, + sortable: true, + }, + { + name: 'OVERTIME', label: 'shared.shift_type.overtime', - field: 'overtime_hours', + field: row => row.other_hours.overtime_hours, sortable: true, }, { @@ -89,4 +126,4 @@ export const pay_period_overview_columns = [ field: 'is_approved', sortable: true, } -]; \ No newline at end of file +] \ No newline at end of file diff --git a/src/modules/timesheets/components/expense-crud-dialog-form.vue b/src/modules/timesheets/components/expense-crud-dialog-form.vue index 38773bf..0194592 100644 --- a/src/modules/timesheets/components/expense-crud-dialog-form.vue +++ b/src/modules/timesheets/components/expense-crud-dialog-form.vue @@ -8,9 +8,11 @@ import { default_expense, EXPENSE_TYPE, TYPES_WITH_AMOUNT_ONLY } from 'src/modules/timesheets/models/expense.models'; import { makeExpenseRules } from 'src/modules/timesheets/utils/expense.util'; import { useExpensesApi } from 'src/modules/timesheets/composables/api/use-expense-api'; + import { useTimesheetStore } from 'src/stores/timesheet-store'; const { t } = useI18n(); + const timesheet_store = useTimesheetStore(); const expenses_store = useExpensesStore(); const expenses_api = useExpensesApi(); const files = defineModel('files'); @@ -35,7 +37,7 @@