diff --git a/src/modules/employee-list/components/supervisor/supervisor-crew-table-item.vue b/src/modules/employee-list/components/supervisor/supervisor-crew-table-item.vue index 9aae542..70a0874 100644 --- a/src/modules/employee-list/components/supervisor/supervisor-crew-table-item.vue +++ b/src/modules/employee-list/components/supervisor/supervisor-crew-table-item.vue @@ -1,25 +1,18 @@ @@ -27,7 +20,7 @@ import { useEmployeeListApi } from 'src/modules/employee-list/composables/use-em v-ripple class="rounded-15 bg-white col-xs-6 col-sm-4 col-md-3 col-lg-2 column no-wrap cursor-pointer q-ma-sm" style="max-width: 230px;" - @click="onProfileCardClick(props.row.email)" + @click="emit('onProfileClick', props.row.email)" > diff --git a/src/modules/shared/components/utils/table-filters.vue b/src/modules/shared/components/utils/table-filters.vue new file mode 100644 index 0000000..5295a2a --- /dev/null +++ b/src/modules/shared/components/utils/table-filters.vue @@ -0,0 +1,42 @@ + + + + + + + + emit('onSearchValueUpdated', value)" + > + + + + + \ No newline at end of file diff --git a/src/modules/shared/types/pay-period-bundle-interface.ts b/src/modules/shared/types/pay-period-bundle-interface.ts deleted file mode 100644 index 6ea23bf..0000000 --- a/src/modules/shared/types/pay-period-bundle-interface.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { PayPeriod } from "./pay-period-interface"; - -export interface PayPeriodBundle { - current: PayPeriod; - periods: PayPeriod[]; -} \ No newline at end of file diff --git a/src/modules/shared/types/q-date-details.ts b/src/modules/shared/types/q-date-details.ts new file mode 100644 index 0000000..980ca72 --- /dev/null +++ b/src/modules/shared/types/q-date-details.ts @@ -0,0 +1,15 @@ +export interface QDateDetails { + year: number; + month: number; + day: number; + from?: { + year: number; + month: number; + day: number; + }; + to?: { + year: number; + month: number; + day: number; + }; +} \ No newline at end of file diff --git a/src/modules/timesheet-approval/components/timesheet-approval-employee-overview-list-item.vue b/src/modules/timesheet-approval/components/timesheet-approval-employee-overview-list-item.vue index 8ac6054..003716a 100644 --- a/src/modules/timesheet-approval/components/timesheet-approval-employee-overview-list-item.vue +++ b/src/modules/timesheet-approval/components/timesheet-approval-employee-overview-list-item.vue @@ -18,19 +18,34 @@ - - {{ props.row.employee_name }} + + + {{ props.row.employee_name }} + - + - + - + {{ props.cols.find(c => c.name === 'regular_hours')?.label }} @@ -39,12 +54,23 @@ - + - - + + {{ col.label }} @@ -54,12 +80,24 @@ - + - - + + {{ col.label }} @@ -70,13 +108,16 @@ - + $emit('update:modelValue', val)" :label="props.modelValue ? $t('timeSheetValidations.timeSheetStatusVerified') : $t('timeSheetValidations.timeSheetStatusUnverified')" class="text-uppercase" - /> + /> 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 79f1b41..244df57 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 @@ -2,54 +2,96 @@ /* eslint-disable */ import { computed, onMounted, ref } from 'vue'; import { useI18n } from 'vue-i18n'; - import type { PayPeriodEmployeeOverview } from '../types/timesheet-approval-pay-period-employee-overview-interface'; - import type { QTableColumn } from 'quasar'; - import TimesheetApprovalEmployeeOverviewListItem from './timesheet-approval-employee-overview-list-item.vue'; - import { useTimesheetApprovalApi } from '../composables/use-timesheet-approval-api'; - import { getCurrentPayPeriod } from 'src/utils/pay-period-calculator'; - import { useAuthStore } from 'src/stores/auth-store'; + import { useTimesheetStore } from 'src/stores/timesheet-store'; + import { useTimesheetApprovalApi } from '../composables/use-timesheet-approval-api'; + import TimesheetApprovalPeriodPicker from '../components/timesheet-approval-period-picker.vue'; + import TimesheetApprovalEmployeeOverviewListItem from './timesheet-approval-employee-overview-list-item.vue'; + + import { date, type QTableColumn } from 'quasar'; + import type { PayPeriodEmployeeOverview } from '../types/timesheet-approval-pay-period-employee-overview-interface'; const { t } = useI18n(); + const timesheet_store = useTimesheetStore(); + const timesheet_approval_api = useTimesheetApprovalApi(); + + const FORWARD = 1 + const BACKWARD = -1 - const currentPayPeriod = getCurrentPayPeriod(); - const currentYear = (new Date()).getFullYear(); + const filter = ref(''); + const original_approvals = ref>({}); + + const columns = computed((): QTableColumn[] => [ + { + name: 'employee_name', + label: t('timeSheetValidations.tableColumnLabelFullname'), + field: 'employee_name', + sortable: true + }, + { + name: 'regular_hours', + label: t('timeSheetValidations.tableColumnLabelRegularHours'), + field: 'regular_hours', + sortable: true + }, + { + name: 'evening_hours', + label: t('timeSheetValidations.tableColumnLabelEveningHours'), + field: 'evening_hours' + }, + { + name: 'emergency_hours', + label: t('timeSheetValidations.tableColumnLabelEmergencyHours'), + field: 'emergency_hours' + }, + { + name: 'overtime_hours', + label: t('timeSheetValidations.tableColumnLabelOvertime'), + field: 'overtime_hours' + }, + { + name: 'expenses', + label: t('timeSheetValidations.tableColumnLabelExpenses'), + field: 'expenses', + sortable: true + }, + { + name: 'mileage', + label: t('timeSheetValidations.tableColumnLabelMileage'), + field: 'mileage', + sortable: true + } + ]); - const originalApprovals = ref>({}); - const hasChanges = computed(() => { - return timesheetStore.payPeriodEmployeeOverviews.some(emp => { - return emp.is_approved !== originalApprovals.value[emp.email]; + const has_changes = computed(() => { + return timesheet_store.pay_period_employee_overviews.some(emp => { + return emp.is_approved !== original_approvals.value[emp.email]; }); }); - const authStore = useAuthStore(); - const timesheetStore = useTimesheetStore(); - const timesheetApprovalApi = useTimesheetApprovalApi(); + const is_calendar_limit = computed( () => { + return timesheet_store.current_pay_period.pay_year === 2024 && + timesheet_store.current_pay_period.pay_period_no <= 1; + }); - const columns = computed((): QTableColumn[] => [ - { name: 'employee_name', label: t('timeSheetValidations.tableColumnLabelFullname'), field: 'employee_name', sortable: true }, - { name: 'regular_hours', label: t('timeSheetValidations.tableColumnLabelRegularHours'), field: 'regular_hours', sortable: true }, - { name: 'evening_hours', label: t('timeSheetValidations.tableColumnLabelEveningHours'), field: 'evening_hours' }, - { name: 'emergency_hours', label: t('timeSheetValidations.tableColumnLabelEmergencyHours'), field: 'emergency_hours' }, - { name: 'overtime_hours', label: t('timeSheetValidations.tableColumnLabelOvertime'), field: 'overtime_hours' }, - { name: 'expenses', label: t('timeSheetValidations.tableColumnLabelExpenses'), field: 'expenses', sortable: true }, - { name: 'mileage', label: t('timeSheetValidations.tableColumnLabelMileage'), field: 'mileage', sortable: true } - ]); - - const filter = ref(''); + const onDateSelected = async (date_string: string) => { + await timesheet_approval_api.getPayPeriodOverviewByDate(date_string); + } onMounted( async () => { - await timesheetApprovalApi.getPayPeriodOverviewByDate(new Date()); - originalApprovals.value = Object.fromEntries( timesheetStore.payPeriodEmployeeOverviews.map(emp => [emp.email, emp.is_approved])); + const today = date.formatDate(new Date(), 'YYYY-MM-DD'); + await timesheet_approval_api.getPayPeriodOverviewByDate(today); + + const approvals = timesheet_store.pay_period_employee_overviews.map(emp => [emp.email, emp.is_approved]); + original_approvals.value = Object.fromEntries(approvals); }) - - + - - - - - - - - - + - + {{ message }} - + diff --git a/src/modules/timesheet-approval/components/timesheet-approval-period-picker.vue b/src/modules/timesheet-approval/components/timesheet-approval-period-picker.vue index be131d7..98a03c8 100644 --- a/src/modules/timesheet-approval/components/timesheet-approval-period-picker.vue +++ b/src/modules/timesheet-approval/components/timesheet-approval-period-picker.vue @@ -1,18 +1,28 @@ @@ -21,8 +31,8 @@ push rounded icon="keyboard_arrow_left" color="primary" - @click="timesheet_approval_api.getNextPayPeriodOverview(-1)" - :disable="is_calendar_limit || timesheet_store.isLoading" + @click="$emit('pressed-previous-button')" + :disable="props.isPreviousLimit || props.isDisabled" class="q-mr-sm q-px-sm" /> - + \ 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 498d70f..16b8b6d 100644 --- a/src/modules/timesheet-approval/composables/use-timesheet-approval-api.ts +++ b/src/modules/timesheet-approval/composables/use-timesheet-approval-api.ts @@ -5,11 +5,11 @@ export const useTimesheetApprovalApi = () => { const timesheet_store = useTimesheetStore(); const auth_store = useAuthStore(); - const getPayPeriodOverviewByDate = async (date: Date) => { - const success = await timesheet_store.getPayPeriodByDate(date); + const getPayPeriodOverviewByDate = async (date_string: string) => { + const success = await timesheet_store.getPayPeriodByDate(date_string); if (success) { - const current_pay_period = timesheet_store.currentPayPeriod; + const current_pay_period = timesheet_store.current_pay_period; await timesheet_store.getTimesheetApprovalPayPeriodEmployeeOverviews(current_pay_period.pay_year, current_pay_period.pay_period_no, auth_store.user.email); } } @@ -19,7 +19,7 @@ export const useTimesheetApprovalApi = () => { It then requests the matching pay period object to set as current pay period from server. If successful, it then requests pay period overviews from that new pay period. */ const getNextPayPeriodOverview = async (direction: number) => { - const current_pay_period = timesheet_store.currentPayPeriod; + const current_pay_period = timesheet_store.current_pay_period; let new_pay_period_no = current_pay_period.pay_period_no + direction; let new_pay_year = current_pay_period.pay_year; diff --git a/src/modules/timesheet-approval/pages/timesheet-approval.vue b/src/modules/timesheet-approval/pages/timesheet-approval.vue index d6b0447..72bd89d 100644 --- a/src/modules/timesheet-approval/pages/timesheet-approval.vue +++ b/src/modules/timesheet-approval/pages/timesheet-approval.vue @@ -1,5 +1,6 @@ - - {{ $t('pageTitles.timeSheetValidations') }} + + + {{ $t('pageTitles.timeSheetValidations') }} + - {{ pay_period_label.start_date }} - {{ $t('timeSheet.dateRangesTo') }} - {{ pay_period_label.end_date }} + + {{ pay_period_label.start_date }} + + + {{ $t('timeSheet.dateRangesTo') }} + + + {{ pay_period_label.end_date }} + diff --git a/src/modules/timesheet-approval/services/services-timesheet-approval.ts b/src/modules/timesheet-approval/services/services-timesheet-approval.ts index a7f4c2d..88d78ee 100644 --- a/src/modules/timesheet-approval/services/services-timesheet-approval.ts +++ b/src/modules/timesheet-approval/services/services-timesheet-approval.ts @@ -3,8 +3,8 @@ import type { PayPeriodOverview } from "../types/timesheet-approval-pay-period-o import type { PayPeriod } from "src/modules/shared/types/pay-period-interface"; export const timesheetApprovalService = { - getPayPeriodByDate: async (date: Date): Promise => { - const response = await api.get(`pay-periods/date/${date.toISOString()}`); + getPayPeriodByDate: async (date_string: string): Promise => { + const response = await api.get(`pay-periods/date/${date_string}`); return response.data; }, diff --git a/src/stores/timesheet-store.ts b/src/stores/timesheet-store.ts index 6b202b1..300efa8 100644 --- a/src/stores/timesheet-store.ts +++ b/src/stores/timesheet-store.ts @@ -14,17 +14,17 @@ const default_pay_period: PayPeriod = { }; export const useTimesheetStore = defineStore('timesheet', () => { - const currentPayPeriod = ref(default_pay_period); - const payPeriodEmployeeOverviews = ref([]); - const isLoading = ref(false); + const current_pay_period = ref(default_pay_period); + const pay_period_employee_overviews = ref([]); + const is_loading = ref(false); - const getPayPeriodByDate = async (date: Date): Promise => { - isLoading.value = true; + const getPayPeriodByDate = async (date_string: string): Promise => { + is_loading.value = true; try { - const response = await timesheetApprovalService.getPayPeriodByDate(date); - currentPayPeriod.value = response; - isLoading.value = false; + const response = await timesheetApprovalService.getPayPeriodByDate(date_string); + current_pay_period.value = response; + is_loading.value = false; return true; } catch(error){ @@ -32,18 +32,18 @@ export const useTimesheetStore = defineStore('timesheet', () => { //TODO: More in-depth error-handling here } - isLoading.value = false; + is_loading.value = false; return false; }; const getPayPeriodByYearAndPeriodNumber = async (year: number, period_number: number): Promise => { - isLoading.value = true; + is_loading.value = true; try { const response = await timesheetApprovalService.getPayPeriodByYearAndPeriodNumber(year, period_number); - currentPayPeriod.value = response; - isLoading.value = false; + current_pay_period.value = response; + is_loading.value = false; return true; } catch(error){ @@ -51,30 +51,30 @@ export const useTimesheetStore = defineStore('timesheet', () => { //TODO: More in-depth error-handling here } - isLoading.value = false; + is_loading.value = false; return false; }; const getTimesheetApprovalPayPeriodEmployeeOverviews = async (pay_year: number, period_number: number, supervisor_email: string) => { - isLoading.value = true; + is_loading.value = true; try { const response = await timesheetApprovalService.getPayPeriodEmployeeOverviews(pay_year, period_number, supervisor_email); - payPeriodEmployeeOverviews.value = response.employees_overview; + pay_period_employee_overviews.value = response.employees_overview; } catch (error) { console.error('There was an error retrieving Employee Pay Period overviews: ', error); - payPeriodEmployeeOverviews.value = []; + pay_period_employee_overviews.value = []; // TODO: trigger an alert window with an error message here! } - isLoading.value = false; + is_loading.value = false; }; return { - currentPayPeriod, - payPeriodEmployeeOverviews, - isLoading, + current_pay_period, + pay_period_employee_overviews, + is_loading, getPayPeriodByDate, getPayPeriodByYearAndPeriodNumber, getTimesheetApprovalPayPeriodEmployeeOverviews,