refactor(many): change some components to respect 'props down, events up' convention for modularity and reusability. Keep branch open for future possible refactors.
This commit is contained in:
parent
b0dcfdc73c
commit
7dbb30259c
|
|
@ -1,25 +1,18 @@
|
|||
<script setup lang="ts">
|
||||
/* eslint-disable */
|
||||
import { useEmployeeStore } from 'src/stores/employee-store';
|
||||
import type { EmployeeListTableItem } from 'src/modules/employee-list/types/employee-list-table-interface';
|
||||
import { useEmployeeListApi } from 'src/modules/employee-list/composables/use-employee-api';
|
||||
|
||||
const employeeStore = useEmployeeStore();
|
||||
const employeeListApi = useEmployeeListApi();
|
||||
import type { EmployeeListTableItem } from 'src/modules/employee-list/types/employee-list-table-interface';
|
||||
|
||||
const getEmployeeAvatar = (first_name: string, last_name: string) => {
|
||||
// add logic here to see if user has an avatar image and return that instead of initials
|
||||
return first_name.charAt(0) + last_name.charAt(0);
|
||||
};
|
||||
const onProfileCardClick = (email: string) => {
|
||||
employeeStore.isShowingEmployeeAddModifyWindow = true;
|
||||
console.log("clicked profile!");
|
||||
employeeListApi.getEmployeeDetails(email);
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
row: EmployeeListTableItem
|
||||
}>()
|
||||
const emit = defineEmits<{
|
||||
onProfileClick: [email: string]
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -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)"
|
||||
>
|
||||
<q-card-section class="text-center col-5">
|
||||
<q-avatar color="primary" size="8em">
|
||||
|
|
|
|||
42
src/modules/shared/components/utils/table-filters.vue
Normal file
42
src/modules/shared/components/utils/table-filters.vue
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<script setup lang="ts">
|
||||
|
||||
const props = defineProps<{
|
||||
searchModel: string | number | null
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
onSearchValueUpdated: [value: string | number | null]
|
||||
}>();
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- Filters toggle -->
|
||||
<q-btn-dropdown
|
||||
rounded
|
||||
push
|
||||
class="q-mr-md bg-white text-primary"
|
||||
label="filters"
|
||||
icon="filter_alt"
|
||||
/>
|
||||
|
||||
<!-- Search bar -->
|
||||
<q-input
|
||||
outlined
|
||||
dense
|
||||
rounded
|
||||
debounce="300"
|
||||
v-model="props.searchModel"
|
||||
:label="$t('shared.searchBar')"
|
||||
label-color="primary"
|
||||
bg-color="white"
|
||||
color="primary"
|
||||
@update:model-value="value => emit('onSearchValueUpdated', value)"
|
||||
>
|
||||
<template v-slot:append>
|
||||
<q-icon
|
||||
name="search"
|
||||
color="primary"
|
||||
/>
|
||||
</template>
|
||||
</q-input>
|
||||
</template>
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
import type { PayPeriod } from "./pay-period-interface";
|
||||
|
||||
export interface PayPeriodBundle {
|
||||
current: PayPeriod;
|
||||
periods: PayPeriod[];
|
||||
}
|
||||
15
src/modules/shared/types/q-date-details.ts
Normal file
15
src/modules/shared/types/q-date-details.ts
Normal file
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
|
@ -18,19 +18,34 @@
|
|||
<div class="q-px-sm q-pb-sm col-xs-12 col-sm-6 col-md-4 col-lg-4 col-xl-3 grid-style-transition">
|
||||
<q-card class="rounded-10">
|
||||
<!-- Card header with employee name -->
|
||||
<q-card-section horizontal class="q-py-none q-px-md">
|
||||
<div class="text-primary text-h5 text-weight-bolder q-pt-xs overflow-hidden">{{ props.row.employee_name }}</div>
|
||||
<q-card-section
|
||||
horizontal
|
||||
class="q-py-none q-px-md"
|
||||
>
|
||||
<div class="text-primary text-h5 text-weight-bolder q-pt-xs overflow-hidden">
|
||||
{{ props.row.employee_name }}
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
<q-separator color="accent" style="height: 2px;"/>
|
||||
<q-separator
|
||||
color="accent"
|
||||
style="height: 2px;"
|
||||
/>
|
||||
|
||||
<!-- Main body of pay period card -->
|
||||
<q-card-section class="q-pa-none q-mt-xs q-mb-sm">
|
||||
<div class="row no-wrap">
|
||||
<!-- left portion of pay period card -->
|
||||
<div class="column no-wrap" :class="$q.screen.lt.md ? 'col' : 'col-8'">
|
||||
<div
|
||||
class="column no-wrap"
|
||||
:class="$q.screen.lt.md ? 'col' : 'col-8'"
|
||||
>
|
||||
<!-- Regular hours segment -->
|
||||
<q-item dense class="column" :class="$q.screen.lt.md ? 'col' : 'col-8'">
|
||||
<q-item
|
||||
dense
|
||||
class="column"
|
||||
:class="$q.screen.lt.md ? 'col' : 'col-8'"
|
||||
>
|
||||
<q-item-label class="text-weight-bold text-primary q-pa-none text-uppercase text-caption">
|
||||
{{ props.cols.find(c => c.name === 'regular_hours')?.label }}
|
||||
</q-item-label>
|
||||
|
|
@ -39,12 +54,23 @@
|
|||
</q-item-label>
|
||||
</q-item>
|
||||
|
||||
<q-separator color="accent" class="q-mx-sm"/>
|
||||
<q-separator
|
||||
color="accent"
|
||||
class="q-mx-sm"
|
||||
/>
|
||||
|
||||
<!-- Other hour types segment -->
|
||||
<div :class="$q.screen.lt.md ? 'column' : 'row no-wrap'">
|
||||
<q-item dense class="column ellipsis " v-for="col in props.cols.slice(2, 5)" :key="col.label">
|
||||
<q-item-label class="text-weight-bold text-primary q-pa-none text-uppercase text-caption" style="font-size: 0.65em;">
|
||||
<q-item
|
||||
dense
|
||||
class="column ellipsis "
|
||||
v-for="col in props.cols.slice(2, 5)"
|
||||
:key="col.label"
|
||||
>
|
||||
<q-item-label
|
||||
class="text-weight-bold text-primary q-pa-none text-uppercase text-caption"
|
||||
style="font-size: 0.65em;"
|
||||
>
|
||||
{{ col.label }}
|
||||
</q-item-label>
|
||||
<q-item-label class="text-weight-bolder q-pa-none text-h6 text-grey-8">
|
||||
|
|
@ -54,12 +80,24 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<q-separator vertical color="accent" class="q-mt-xs q-mb-none"/>
|
||||
<q-separator
|
||||
vertical
|
||||
color="accent"
|
||||
class="q-mt-xs q-mb-none"
|
||||
/>
|
||||
|
||||
<!-- Right portion of pay period card -->
|
||||
<div class="no-wrap ellipsis col">
|
||||
<q-item dense class="column" v-for="col in props.cols.slice(5, )" :key="col.label">
|
||||
<q-item-label class="text-weight-bold text-primary q-pa-none text-uppercase text-caption ellipsis" style="font-size: 0.8em;">
|
||||
<q-item
|
||||
dense
|
||||
class="column"
|
||||
v-for="col in props.cols.slice(5, )"
|
||||
:key="col.label"
|
||||
>
|
||||
<q-item-label
|
||||
class="text-weight-bold text-primary q-pa-none text-uppercase text-caption ellipsis"
|
||||
style="font-size: 0.8em;"
|
||||
>
|
||||
{{ col.label }}
|
||||
</q-item-label>
|
||||
<q-item-label class="text-weight-bolder q-pa-none text-h6 text-grey-8">
|
||||
|
|
@ -70,13 +108,16 @@
|
|||
</div>
|
||||
</q-card-section>
|
||||
|
||||
<q-separator color="primary" style="height: 2px;" />
|
||||
<q-separator
|
||||
color="primary"
|
||||
style="height: 2px;"
|
||||
/>
|
||||
|
||||
<!-- Validate entire Pay Period section -->
|
||||
<q-card-section
|
||||
horizontal
|
||||
class="q-pa-sm text-weight-bold"
|
||||
:class="props.modelValue ? 'text-white bg-primary' : 'text-primary bg-white'"
|
||||
horizontal
|
||||
class="q-pa-sm text-weight-bold"
|
||||
:class="props.modelValue ? 'text-white bg-primary' : 'text-primary bg-white'"
|
||||
>
|
||||
<q-space />
|
||||
<q-checkbox
|
||||
|
|
@ -90,7 +131,7 @@
|
|||
@update:model-value="val => $emit('update:modelValue', val)"
|
||||
:label="props.modelValue ? $t('timeSheetValidations.timeSheetStatusVerified') : $t('timeSheetValidations.timeSheetStatusUnverified')"
|
||||
class="text-uppercase"
|
||||
/>
|
||||
/>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -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 currentPayPeriod = getCurrentPayPeriod();
|
||||
const currentYear = (new Date()).getFullYear();
|
||||
const FORWARD = 1
|
||||
const BACKWARD = -1
|
||||
|
||||
const originalApprovals = ref<Record<string, boolean>>({});
|
||||
const hasChanges = computed(() => {
|
||||
return timesheetStore.payPeriodEmployeeOverviews.some(emp => {
|
||||
return emp.is_approved !== originalApprovals.value[emp.email];
|
||||
const filter = ref<string | number | null>('');
|
||||
const original_approvals = ref<Record<string, boolean>>({});
|
||||
|
||||
const columns = computed((): QTableColumn<PayPeriodEmployeeOverview>[] => [
|
||||
{
|
||||
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 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<PayPeriodEmployeeOverview>[] => [
|
||||
{ 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);
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
<template>
|
||||
<div class="q-pa-md">
|
||||
<q-table
|
||||
:rows="timesheetStore.payPeriodEmployeeOverviews"
|
||||
:rows="timesheet_store.pay_period_employee_overviews"
|
||||
:columns="columns"
|
||||
row-key="email"
|
||||
:filter="filter"
|
||||
|
|
@ -59,7 +101,7 @@
|
|||
color="primary"
|
||||
:rows-per-page-options="[0]"
|
||||
card-container-class="justify-center"
|
||||
:loading="timesheetStore.isLoading"
|
||||
:loading="timesheet_store.is_loading"
|
||||
:no-data-label="$t('shared.failedToLoad')"
|
||||
:no-results-label="$t('shared.failedToSearch')"
|
||||
:loading-label="$t('shared.loading')"
|
||||
|
|
@ -68,37 +110,25 @@
|
|||
<template v-slot:top>
|
||||
<div :class="$q.screen.lt.md ? 'column justify-center items-center' : 'full-width row'">
|
||||
<!-- Date Picker -->
|
||||
<TimesheetApprovalPeriodPicker />
|
||||
<TimesheetApprovalPeriodPicker
|
||||
:is-disabled="timesheet_store.is_loading"
|
||||
:is-previous-limit="is_calendar_limit"
|
||||
@date-selected="onDateSelected"
|
||||
@pressed-previous-button="timesheet_approval_api.getNextPayPeriodOverview(BACKWARD)"
|
||||
@pressed-next-button="timesheet_approval_api.getNextPayPeriodOverview(FORWARD)"
|
||||
/>
|
||||
|
||||
<q-space />
|
||||
|
||||
<!-- Filters toggle -->
|
||||
<q-btn-dropdown
|
||||
rounded
|
||||
push
|
||||
class="q-mr-md bg-white text-primary"
|
||||
label="filters"
|
||||
icon="filter_alt"
|
||||
/>
|
||||
|
||||
<!-- Search bar -->
|
||||
<q-input
|
||||
outlined
|
||||
dense
|
||||
rounded
|
||||
v-model="filter"
|
||||
:label="$t('shared.searchBar')"
|
||||
label-color="primary" bg-color="white" color="primary"
|
||||
>
|
||||
<template v-slot:append>
|
||||
<q-icon name="search" color="primary"/>
|
||||
</template>
|
||||
</q-input>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Template for individual employee cards -->
|
||||
<template v-slot:item="props: { cols: (QTableColumn<PayPeriodEmployeeOverview> & { value: unknown })[], row: PayPeriodEmployeeOverview }">
|
||||
<template v-slot:item="props: {
|
||||
cols: (QTableColumn<PayPeriodEmployeeOverview> & { value: unknown })[],
|
||||
row: PayPeriodEmployeeOverview
|
||||
}">
|
||||
<TimesheetApprovalEmployeeOverviewListItem
|
||||
:cols="props.cols"
|
||||
:row="props.row"
|
||||
|
|
@ -111,7 +141,10 @@
|
|||
<span class="text-h6 q-mt-xl">
|
||||
{{ message }}
|
||||
</span>
|
||||
<q-icon size="4em" :name="filter ? 'filter_alt_off' : 'error_outline'" />
|
||||
<q-icon
|
||||
size="4em"
|
||||
:name="filter ? 'filter_alt_off' : 'error_outline'"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</q-table>
|
||||
|
|
|
|||
|
|
@ -1,18 +1,28 @@
|
|||
<script setup lang="ts">
|
||||
/* eslint-disable */
|
||||
import { ref, computed } from 'vue';
|
||||
import { useTimesheetApprovalApi } from '../composables/use-timesheet-approval-api';
|
||||
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
||||
import { ref } from 'vue';
|
||||
import { date } from 'quasar';
|
||||
import type { QDateDetails } from 'src/modules/shared/types/q-date-details';
|
||||
|
||||
const timesheet_approval_api = useTimesheetApprovalApi();
|
||||
const timesheet_store = useTimesheetStore();
|
||||
const is_showing_calendar_picker = ref(false);
|
||||
const calendar_date = ref(date.formatDate( Date.now(), 'YYYY/MM/DD' ));
|
||||
const is_calendar_limit = computed( () => {
|
||||
return timesheet_store.currentPayPeriod.pay_year === 2024 && timesheet_store.currentPayPeriod.pay_period_no <= 1;
|
||||
});
|
||||
|
||||
const props = defineProps<{
|
||||
isDisabled: boolean,
|
||||
isPreviousLimit: boolean,
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
'date-selected': [value: string, reason?: string, details?: QDateDetails]
|
||||
'pressed-previous-button': void
|
||||
'pressed-next-button': void
|
||||
}>();
|
||||
|
||||
const onDateSelected = (value: string, reason: string, details: QDateDetails) => {
|
||||
calendar_date.value = value;
|
||||
is_showing_calendar_picker.value = false;
|
||||
emit('date-selected', value, reason, details);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -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"
|
||||
/>
|
||||
<q-btn
|
||||
|
|
@ -30,26 +40,28 @@
|
|||
icon="date_range"
|
||||
color="primary"
|
||||
@click="is_showing_calendar_picker = true"
|
||||
:disable="timesheet_store.isLoading"
|
||||
:disable="props.isDisabled"
|
||||
class="q-px-lg"
|
||||
/>
|
||||
<q-btn
|
||||
push rounded
|
||||
icon="keyboard_arrow_right"
|
||||
color="primary"
|
||||
@click="timesheet_approval_api.getNextPayPeriodOverview(1)"
|
||||
:disable="timesheet_store.isLoading"
|
||||
@click="$emit('pressed-next-button')"
|
||||
:disable="props.isDisabled"
|
||||
class="q-ml-sm q-px-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<q-dialog v-model="is_showing_calendar_picker" transition-show="slide-down" transition-hide="slide-up" position="top">
|
||||
<q-dialog v-model="is_showing_calendar_picker" transition-show="jump-down" transition-hide="jump-up" position="top">
|
||||
<q-date
|
||||
v-model="calendar_date"
|
||||
color="primary"
|
||||
class="q-mt-xl"
|
||||
today-btn
|
||||
:options="date => date > '2023/12/16'"
|
||||
mask="YYYY-MM-DD"
|
||||
:options="date => date > '2023-12-16'"
|
||||
@update:model-value="onDateSelected"
|
||||
/>
|
||||
</q-dialog>
|
||||
</template>
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import TimesheetApprovalEmployeeOverviewList from '../components/timesheet-approval-employee-overview-list.vue';
|
||||
import TimesheetApprovalEmployeeOverviewList from '/src/modules/timesheet-approval/\
|
||||
components/timesheet-approval-employee-overview-list.vue';
|
||||
import { computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
||||
|
|
@ -15,9 +16,12 @@
|
|||
|
||||
|
||||
const pay_period_label = computed(() => {
|
||||
const dates = timesheet_store.currentPayPeriod.label.split('.');
|
||||
const start_date = new Intl.DateTimeFormat(locale.value, date_options).format(date.extractDate(dates[0] as string, 'YYYY-MM-DD'));
|
||||
const end_date = new Intl.DateTimeFormat(locale.value, date_options).format(date.extractDate(dates[1] as string, 'YYYY-MM-DD'));
|
||||
const dates = timesheet_store.current_pay_period.label.split('.');
|
||||
const start_date = new Intl.DateTimeFormat(locale.value, date_options);
|
||||
const end_date = new Intl.DateTimeFormat(locale.value, date_options);
|
||||
|
||||
start_date.format(date.extractDate(dates[0] as string, 'YYYY-MM-DD'));
|
||||
end_date.format(date.extractDate(dates[1] as string, 'YYYY-MM-DD'));
|
||||
|
||||
return {
|
||||
start_date: start_date,
|
||||
|
|
@ -27,12 +31,23 @@
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<q-page padding class="q-pa-md bg-secondary">
|
||||
<div class="text-h4 row justify-center q-mt-lg text-uppercase text-weight-bolder text-grey-8">{{ $t('pageTitles.timeSheetValidations') }}</div>
|
||||
<q-page
|
||||
padding
|
||||
class="q-pa-md bg-secondary"
|
||||
>
|
||||
<div class="text-h4 row justify-center q-mt-lg text-uppercase text-weight-bolder text-grey-8">
|
||||
{{ $t('pageTitles.timeSheetValidations') }}
|
||||
</div>
|
||||
<div class="row items-center justify-center q-py-none q-my-none">
|
||||
<div class="text-primary text-h6 text-uppercase">{{ pay_period_label.start_date }}</div>
|
||||
<div class="text-grey-8 text-weight-bold text-uppercase q-mx-md">{{ $t('timeSheet.dateRangesTo') }}</div>
|
||||
<div class="text-primary text-h6 text-uppercase">{{ pay_period_label.end_date }}</div>
|
||||
<div class="text-primary text-h6 text-uppercase">
|
||||
{{ pay_period_label.start_date }}
|
||||
</div>
|
||||
<div class="text-grey-8 text-weight-bold text-uppercase q-mx-md">
|
||||
{{ $t('timeSheet.dateRangesTo') }}
|
||||
</div>
|
||||
<div class="text-primary text-h6 text-uppercase">
|
||||
{{ pay_period_label.end_date }}
|
||||
</div>
|
||||
</div>
|
||||
<TimesheetApprovalEmployeeOverviewList />
|
||||
</q-page>
|
||||
|
|
|
|||
|
|
@ -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<PayPeriod> => {
|
||||
const response = await api.get(`pay-periods/date/${date.toISOString()}`);
|
||||
getPayPeriodByDate: async (date_string: string): Promise<PayPeriod> => {
|
||||
const response = await api.get(`pay-periods/date/${date_string}`);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -14,17 +14,17 @@ const default_pay_period: PayPeriod = {
|
|||
};
|
||||
|
||||
export const useTimesheetStore = defineStore('timesheet', () => {
|
||||
const currentPayPeriod = ref<PayPeriod>(default_pay_period);
|
||||
const payPeriodEmployeeOverviews = ref<PayPeriodEmployeeOverview[]>([]);
|
||||
const isLoading = ref<boolean>(false);
|
||||
const current_pay_period = ref<PayPeriod>(default_pay_period);
|
||||
const pay_period_employee_overviews = ref<PayPeriodEmployeeOverview[]>([]);
|
||||
const is_loading = ref<boolean>(false);
|
||||
|
||||
const getPayPeriodByDate = async (date: Date): Promise<boolean> => {
|
||||
isLoading.value = true;
|
||||
const getPayPeriodByDate = async (date_string: string): Promise<boolean> => {
|
||||
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<boolean> => {
|
||||
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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user