feat(approvals): add timeline compact viewer. Forego slider/range implementation for custom vue/typescript method
This commit is contained in:
parent
911a959567
commit
6248cb3354
|
|
@ -297,6 +297,7 @@ export default {
|
||||||
},
|
},
|
||||||
timeSheetValidations: {
|
timeSheetValidations: {
|
||||||
tableColumnLabelFullname: 'Full name',
|
tableColumnLabelFullname: 'Full name',
|
||||||
|
tableColumnLabelEmail: 'email address',
|
||||||
tableColumnLabelRegularHours: 'regular hours',
|
tableColumnLabelRegularHours: 'regular hours',
|
||||||
tableColumnLabelEveningHours: 'evening',
|
tableColumnLabelEveningHours: 'evening',
|
||||||
tableColumnLabelEmergencyHours: 'emergency',
|
tableColumnLabelEmergencyHours: 'emergency',
|
||||||
|
|
|
||||||
|
|
@ -347,6 +347,7 @@ export default {
|
||||||
},
|
},
|
||||||
timeSheetValidations: {
|
timeSheetValidations: {
|
||||||
tableColumnLabelFullname: 'nom complet',
|
tableColumnLabelFullname: 'nom complet',
|
||||||
|
tableColumnLabelEmail: 'courriel',
|
||||||
tableColumnLabelRegularHours: 'heures régulières',
|
tableColumnLabelRegularHours: 'heures régulières',
|
||||||
tableColumnLabelEveningHours: 'soir',
|
tableColumnLabelEveningHours: 'soir',
|
||||||
tableColumnLabelEmergencyHours: 'urgence',
|
tableColumnLabelEmergencyHours: 'urgence',
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,121 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from "vue";
|
||||||
|
import type { Shift } from "src/modules/timesheets/types/timesheet-shift-interface";
|
||||||
|
import { date } from 'quasar';
|
||||||
|
|
||||||
|
const totalMinutes = 24 * 60;
|
||||||
|
const props = defineProps<{
|
||||||
|
weekdayShifts: (Shift | null)[];
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const toMinutes = (time: string): number => {
|
||||||
|
const parsed_time = date.extractDate(time, 'HH:mm');
|
||||||
|
return parsed_time.getHours() * 60 + parsed_time.getMinutes();
|
||||||
|
};
|
||||||
|
|
||||||
|
const bars = computed(() => {
|
||||||
|
return props.weekdayShifts
|
||||||
|
.filter((s): s is Shift => s !== null) // skip null shifts
|
||||||
|
.map((s) => {
|
||||||
|
const start = toMinutes(s.start_time);
|
||||||
|
const end = toMinutes(s.end_time);
|
||||||
|
const start_percent = (start / totalMinutes) * 100;
|
||||||
|
const width_percent = ((end - start) / totalMinutes) * 100;
|
||||||
|
|
||||||
|
return { start_percent, width_percent };
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="relative full-width bg-grey-4 rounded-10" style="height: 8px; margin: 7px 0;">
|
||||||
|
<div
|
||||||
|
v-for="(bar, i) in bars"
|
||||||
|
:key="i"
|
||||||
|
class="absolute bg-primary"
|
||||||
|
:style="{
|
||||||
|
left: bar.start_percent + '%',
|
||||||
|
width: bar.width_percent + '%',
|
||||||
|
height: '14px',
|
||||||
|
transform: 'translateY(-3px)',
|
||||||
|
}"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- <script setup lang="ts">
|
||||||
|
import type { Shift } from 'src/modules/timesheets/types/timesheet-shift-interface';
|
||||||
|
import { date } from 'quasar';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
weekdayShifts: Shift[];
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const extractTimeValue = (time: string): number => {
|
||||||
|
const parsed_time = date.extractDate(time, 'HH:mm');
|
||||||
|
return parsed_time.getHours() + (parsed_time.getMinutes() / 60);
|
||||||
|
};
|
||||||
|
|
||||||
|
const slider_model = ref<number>(0);
|
||||||
|
const shifts = ref<Shift[]>(props.weekdayShifts);
|
||||||
|
const ranges = ref(
|
||||||
|
shifts.value.map( shift =>
|
||||||
|
shift
|
||||||
|
? {
|
||||||
|
min: extractTimeValue(shift.start_time),
|
||||||
|
max: extractTimeValue(shift.end_time)
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
min: 0,
|
||||||
|
max: 0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="relative-position q-pa-none q-ma-none col">
|
||||||
|
<div class="absolute-full row justify-between">
|
||||||
|
<div></div>
|
||||||
|
<q-separator vertical color="accent" />
|
||||||
|
<q-separator vertical color="accent" />
|
||||||
|
<q-separator vertical color="accent" />
|
||||||
|
<q-separator vertical color="accent" />
|
||||||
|
<q-separator vertical color="accent" />
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
|
<q-slider
|
||||||
|
v-model="slider_model"
|
||||||
|
track-color="grey-6"
|
||||||
|
track-size="8px"
|
||||||
|
thumb-size="0px"
|
||||||
|
:max="24"
|
||||||
|
readonly
|
||||||
|
class="absolute-full q-pt-xs"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-for="(_range, index) in ranges"
|
||||||
|
:key="index"
|
||||||
|
class="absolute-full"
|
||||||
|
>
|
||||||
|
<q-range
|
||||||
|
v-model="ranges[index]"
|
||||||
|
track-color="transparent"
|
||||||
|
inner-track-color="transparent"
|
||||||
|
color="primary"
|
||||||
|
:max="24"
|
||||||
|
thumb-size="0px"
|
||||||
|
track-size="16px"
|
||||||
|
label-color="accent"
|
||||||
|
label-text-color="primary"
|
||||||
|
label
|
||||||
|
:left-label-value="shifts[index]?.start_time"
|
||||||
|
:right-label-value="shifts[index]?.end_time"
|
||||||
|
readonly
|
||||||
|
class="z-top"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template> -->
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { PayPeriodEmployeeDetails } from '../types/timesheet-approval-pay-period-employee-details-interface';
|
||||||
|
import ShiftPreviewBar from 'src/modules/timesheet-approval/components/shifts/shift-preview-bar.vue';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
isLoading: boolean;
|
||||||
|
employeeDetails: PayPeriodEmployeeDetails | undefined;
|
||||||
|
}>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<q-card class="q-pa-sm bg-white shadow-5 full-width">
|
||||||
|
<!-- loader -->
|
||||||
|
<q-card-section v-if="props.isLoading">
|
||||||
|
<q-spinner
|
||||||
|
color="primary"
|
||||||
|
size="5em"
|
||||||
|
:thickness="10"
|
||||||
|
/>
|
||||||
|
<div class="text-primary text-h6 text-weight-bold">
|
||||||
|
{{ $t('shared.loading') }}
|
||||||
|
</div>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<!-- employee timesheet details -->
|
||||||
|
<q-card-section
|
||||||
|
v-if="!props.isLoading"
|
||||||
|
class="column"
|
||||||
|
>
|
||||||
|
<div class="absolute-full row justify-center text-center text-primary text-weight-bolder text-caption q-py-none q-my-none q-px-xl q-mx-sm">
|
||||||
|
<q-space />
|
||||||
|
<div class="col">4</div>
|
||||||
|
<div class="col">8</div>
|
||||||
|
<div class="col">12</div>
|
||||||
|
<div class="col">4</div>
|
||||||
|
<div class="col">8</div>
|
||||||
|
<q-space />
|
||||||
|
</div>
|
||||||
|
<ShiftPreviewBar
|
||||||
|
v-for="(shifts, index) in employeeDetails?.week1.shifts"
|
||||||
|
:key="index"
|
||||||
|
:weekday-shifts="shifts"
|
||||||
|
class="q-mt-xs"
|
||||||
|
/>
|
||||||
|
<!-- {{ employeeDetails }} -->
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</template>
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
<script setup lang="ts">
|
|
||||||
import type { TimesheetDetailsWeek } from 'src/modules/timesheets/types/timesheet-details-interface';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
isLoading: boolean;
|
|
||||||
employeeDetails: TimesheetDetailsWeek;
|
|
||||||
}>();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<q-card class="q-pa-sm bg-white shadow-5">
|
|
||||||
<!-- loader -->
|
|
||||||
<q-card-section v-if="props.isLoading">
|
|
||||||
<q-spinner
|
|
||||||
color="primary"
|
|
||||||
size="5em"
|
|
||||||
:thickness="10"
|
|
||||||
/>
|
|
||||||
<div class="text-primary text-h6 text-weight-bold">
|
|
||||||
{{ $t('shared.loading') }}
|
|
||||||
</div>
|
|
||||||
</q-card-section>
|
|
||||||
|
|
||||||
<!-- employee timesheet details -->
|
|
||||||
<q-card-section v-if="!props.isLoading">
|
|
||||||
{{ employeeDetails }}
|
|
||||||
</q-card-section>
|
|
||||||
</q-card>
|
|
||||||
</template>
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { PayPeriodEmployeeOverview } from '../types/timesheet-approval-pay-period-employee-overview-interface';
|
import type { PayPeriodOverviewEmployee } from 'src/modules/timesheet-approval/types/timesheet-approval-pay-period-overview-employee-interface';
|
||||||
|
|
||||||
interface TableColumn {
|
interface TableColumn {
|
||||||
name: string;
|
name: string;
|
||||||
|
|
@ -9,36 +9,40 @@
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
cols: TableColumn[];
|
cols: TableColumn[];
|
||||||
row: PayPeriodEmployeeOverview;
|
row: PayPeriodOverviewEmployee;
|
||||||
initialState: boolean;
|
initialState: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
isDetailsButtonPressed: []
|
clickDetails: [email: string];
|
||||||
'update:modelValue': [value: string | number | null]
|
'update:modelValue': [value: boolean | null];
|
||||||
}>();
|
}>();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<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">
|
<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">
|
<q-card class="rounded-10">
|
||||||
<!-- Button to get full timesheet details -->
|
<!-- Card header with employee name and details button-->
|
||||||
<q-btn
|
|
||||||
flat
|
|
||||||
unelevated
|
|
||||||
class="q-pa-sm"
|
|
||||||
icon="open_in_full"
|
|
||||||
@click="emit('isDetailsButtonPressed')"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- Card header with employee name -->
|
|
||||||
<q-card-section
|
<q-card-section
|
||||||
horizontal
|
horizontal
|
||||||
class="q-py-none q-px-md"
|
class="q-py-none q-pl-md"
|
||||||
>
|
>
|
||||||
<div class="text-primary text-h5 text-weight-bolder q-pt-xs overflow-hidden">
|
<div class="text-primary text-h5 text-weight-bolder q-pt-xs overflow-hidden">
|
||||||
{{ props.row.employee_name }}
|
{{ props.row.employee_name }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<q-space />
|
||||||
|
|
||||||
|
<!-- Button to get full timesheet details -->
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
unelevated
|
||||||
|
rounded
|
||||||
|
class="q-py-none"
|
||||||
|
color="primary"
|
||||||
|
icon="open_in_full"
|
||||||
|
@click="emit('clickDetails', props.row.email)"
|
||||||
|
/>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
|
|
||||||
<q-separator
|
<q-separator
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,10 @@
|
||||||
|
|
||||||
import TimesheetApprovalPeriodPicker from '../components/timesheet-approval-period-picker.vue';
|
import TimesheetApprovalPeriodPicker from '../components/timesheet-approval-period-picker.vue';
|
||||||
import TimesheetApprovalEmployeeOverviewListItem from './timesheet-approval-employee-overview-list-item.vue';
|
import TimesheetApprovalEmployeeOverviewListItem from './timesheet-approval-employee-overview-list-item.vue';
|
||||||
|
import TimesheetApprovalEmployeeDetails from '../components/timesheet-approval-employee-details.vue';
|
||||||
|
|
||||||
import { date, type QTableColumn } from 'quasar';
|
import { date, type QTableColumn } from 'quasar';
|
||||||
import type { PayPeriodEmployeeOverview } from '../types/timesheet-approval-pay-period-employee-overview-interface';
|
import type { PayPeriodOverviewEmployee } from '../types/timesheet-approval-pay-period-overview-employee-interface';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const timesheet_store = useTimesheetStore();
|
const timesheet_store = useTimesheetStore();
|
||||||
|
|
@ -21,14 +22,21 @@
|
||||||
|
|
||||||
const filter = ref<string | number | null>('');
|
const filter = ref<string | number | null>('');
|
||||||
const original_approvals = ref<Record<string, boolean>>({});
|
const original_approvals = ref<Record<string, boolean>>({});
|
||||||
|
const is_showing_details = ref<boolean>(false);
|
||||||
|
|
||||||
const columns = computed((): QTableColumn<PayPeriodEmployeeOverview>[] => [
|
const columns = computed((): QTableColumn<PayPeriodOverviewEmployee>[] => [
|
||||||
{
|
{
|
||||||
name: 'employee_name',
|
name: 'employee_name',
|
||||||
label: t('timeSheetValidations.tableColumnLabelFullname'),
|
label: t('timeSheetValidations.tableColumnLabelFullname'),
|
||||||
field: 'employee_name',
|
field: 'employee_name',
|
||||||
sortable: true
|
sortable: true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'email',
|
||||||
|
label: t('timeSheetValidations.tableColumnLabelEmail'),
|
||||||
|
field: 'email',
|
||||||
|
sortable: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'regular_hours',
|
name: 'regular_hours',
|
||||||
label: t('timeSheetValidations.tableColumnLabelRegularHours'),
|
label: t('timeSheetValidations.tableColumnLabelRegularHours'),
|
||||||
|
|
@ -65,7 +73,7 @@
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const has_changes = computed(() => {
|
const has_changes = computed(() => {
|
||||||
return timesheet_store.pay_period_employee_overviews.some(emp => {
|
return timesheet_store.pay_period_overview_employees.some(emp => {
|
||||||
return emp.is_approved !== original_approvals.value[emp.email];
|
return emp.is_approved !== original_approvals.value[emp.email];
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -79,19 +87,36 @@
|
||||||
await timesheet_approval_api.getPayPeriodOverviewByDate(date_string);
|
await timesheet_approval_api.getPayPeriodOverviewByDate(date_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onClickedDetails = async (email: string) => {
|
||||||
|
is_showing_details.value = true;
|
||||||
|
console.log('employee email is: ', email);
|
||||||
|
await timesheet_approval_api.getTimesheetsByPayPeriodAndEmail(email);
|
||||||
|
}
|
||||||
|
|
||||||
onMounted( async () => {
|
onMounted( async () => {
|
||||||
const today = date.formatDate(new Date(), 'YYYY-MM-DD');
|
const today = date.formatDate(new Date(), 'YYYY-MM-DD');
|
||||||
await timesheet_approval_api.getPayPeriodOverviewByDate(today);
|
await timesheet_approval_api.getPayPeriodOverviewByDate(today);
|
||||||
|
|
||||||
const approvals = timesheet_store.pay_period_employee_overviews.map(emp => [emp.email, emp.is_approved]);
|
const approvals = timesheet_store.pay_period_overview_employees.map(emp => [emp.email, emp.is_approved]);
|
||||||
original_approvals.value = Object.fromEntries(approvals);
|
original_approvals.value = Object.fromEntries(approvals);
|
||||||
|
console.log(timesheet_store.pay_period_overview_employees);
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<q-dialog
|
||||||
|
v-model="is_showing_details"
|
||||||
|
transition-show="scale"
|
||||||
|
transition-hide="jump-down"
|
||||||
|
>
|
||||||
|
<TimesheetApprovalEmployeeDetails
|
||||||
|
:is-loading="timesheet_store.is_loading"
|
||||||
|
:employee-details="timesheet_store.pay_period_employee_details"
|
||||||
|
/>
|
||||||
|
</q-dialog>
|
||||||
<div class="q-pa-md">
|
<div class="q-pa-md">
|
||||||
<q-table
|
<q-table
|
||||||
:rows="timesheet_store.pay_period_employee_overviews"
|
:rows="timesheet_store.pay_period_overview_employees"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
row-key="email"
|
row-key="email"
|
||||||
:filter="filter"
|
:filter="filter"
|
||||||
|
|
@ -126,13 +151,15 @@
|
||||||
|
|
||||||
<!-- Template for individual employee cards -->
|
<!-- Template for individual employee cards -->
|
||||||
<template v-slot:item="props: {
|
<template v-slot:item="props: {
|
||||||
cols: (QTableColumn<PayPeriodEmployeeOverview> & { value: unknown })[],
|
cols: (QTableColumn<PayPeriodOverviewEmployee> & { value: unknown })[],
|
||||||
row: PayPeriodEmployeeOverview
|
row: PayPeriodOverviewEmployee
|
||||||
}">
|
}">
|
||||||
<TimesheetApprovalEmployeeOverviewListItem
|
<TimesheetApprovalEmployeeOverviewListItem
|
||||||
:cols="props.cols"
|
:cols="props.cols"
|
||||||
:row="props.row"
|
:row="props.row"
|
||||||
:initial-state="props.row.is_approved"/>
|
:initial-state="props.row.is_approved"
|
||||||
|
@click-details="onClickedDetails"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- Template for custome failed-to-load state -->
|
<!-- Template for custome failed-to-load state -->
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,13 @@ export const useTimesheetApprovalApi = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getTimesheetsByPayPeriodAndEmail = async (employee_email: string) => {
|
||||||
|
await timesheet_store.getTimesheetsByPayPeriodAndEmail(employee_email);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getPayPeriodOverviewByDate,
|
getPayPeriodOverviewByDate,
|
||||||
getNextPayPeriodOverview,
|
getNextPayPeriodOverview,
|
||||||
|
getTimesheetsByPayPeriodAndEmail
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -13,7 +13,6 @@
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const pay_period_label = computed(() => {
|
const pay_period_label = computed(() => {
|
||||||
const dates = timesheet_store.current_pay_period.label.split('.');
|
const dates = timesheet_store.current_pay_period.label.split('.');
|
||||||
const start_date = new Intl.DateTimeFormat(locale.value, date_options).format(date.extractDate(dates[0] as string, 'YYYY-MM-DD'));
|
const start_date = new Intl.DateTimeFormat(locale.value, date_options).format(date.extractDate(dates[0] as string, 'YYYY-MM-DD'));
|
||||||
|
|
@ -42,6 +41,7 @@
|
||||||
{{ pay_period_label.end_date }}
|
{{ pay_period_label.end_date }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<TimesheetApprovalEmployeeOverviewList />
|
<TimesheetApprovalEmployeeOverviewList />
|
||||||
</q-page>
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -17,58 +17,12 @@ export const timesheetApprovalService = {
|
||||||
|
|
||||||
getPayPeriodEmployeeOverviews: async (year: number, period_number: number, supervisor_email: string): Promise<PayPeriodOverview> => {
|
getPayPeriodEmployeeOverviews: async (year: number, period_number: number, supervisor_email: string): Promise<PayPeriodOverview> => {
|
||||||
// TODO: REMOVE MOCK DATA PEFORE PUSHING TO PROD
|
// TODO: REMOVE MOCK DATA PEFORE PUSHING TO PROD
|
||||||
const response = await api.get(`/pay-periods/${year}/${period_number}/${supervisor_email}`);
|
const response = await api.get(`pay-periods/${year}/${period_number}/${supervisor_email}`);
|
||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
|
|
||||||
getTimesheetsByPayPeriodAndEmail: async (year: number, period_number: number, employee_email: string): Promise<PayPeriodEmployeeDetails> => {
|
getTimesheetsByPayPeriodAndEmail: async (year: number, period_no: number, email: string): Promise<PayPeriodEmployeeDetails> => {
|
||||||
const response = await api.get(`/timesheets/${year}/${period_number}/${employee_email}`) || { data: MOCK_DATA_TIMESHEET_DETAILS, status: 200, statusText: 'OK'};
|
const response = await api.get('timesheets', { params: { year, period_no, email, }});
|
||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const MOCK_DATA_TIMESHEET_DETAILS = {
|
|
||||||
is_approved: false,
|
|
||||||
week1: {
|
|
||||||
is_approved: true,
|
|
||||||
shifts: {
|
|
||||||
sun: [],
|
|
||||||
mon: [ { is_approved: true, start_time: '08:00', end_time: '12:00' }, { is_approved: true, start_time: '13:00', end_time: '17:00' } ],
|
|
||||||
tue: [ { is_approved: true, start_time: '08:00', end_time: '11:45' }, { is_approved: true, start_time: '12:45', end_time: '17:00' } ],
|
|
||||||
wed: [ { is_approved: true, start_time: '08:00', end_time: '12:00' }, { is_approved: true, start_time: '13:00', end_time: '17:00' } ],
|
|
||||||
thu: [ { is_approved: false, start_time: '13:00', end_time: '17:00' } ],
|
|
||||||
fri: [ { is_approved: true, start_time: '08:00', end_time: '12:00' }, { is_approved: true, start_time: '13:00', end_time: '17:00' } ],
|
|
||||||
sat: []
|
|
||||||
},
|
|
||||||
expenses: {
|
|
||||||
sun: { costs: [], mileage: [] },
|
|
||||||
mon: { costs: [ { is_approved: true, amount: 156.49 } ], mileage: [] },
|
|
||||||
tue: { costs: [], mileage: [] },
|
|
||||||
wed: { costs: [], mileage: [] },
|
|
||||||
thu: { costs: [], mileage: [ { is_approved: false, amount: 16 } ] },
|
|
||||||
fri: { costs: [], mileage: [] },
|
|
||||||
sat: { costs: [], mileage: [] }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
week2: {
|
|
||||||
is_approved: true,
|
|
||||||
shifts: {
|
|
||||||
sun: [],
|
|
||||||
mon: [],
|
|
||||||
tue: [],
|
|
||||||
wed: [],
|
|
||||||
thu: [],
|
|
||||||
fri: [],
|
|
||||||
sat: []
|
|
||||||
},
|
|
||||||
expenses: {
|
|
||||||
sun: { costs: [], mileage: [] },
|
|
||||||
mon: { costs: [], mileage: [] },
|
|
||||||
tue: { costs: [], mileage: [] },
|
|
||||||
wed: { costs: [], mileage: [] },
|
|
||||||
thu: { costs: [], mileage: [] },
|
|
||||||
fri: { costs: [], mileage: [] },
|
|
||||||
sat: { costs: [], mileage: [] }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
} as PayPeriodEmployeeDetails;
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
export interface PayPeriodEmployeeOverview {
|
export interface PayPeriodOverviewEmployee {
|
||||||
email: string;
|
email: string;
|
||||||
employee_name: string;
|
employee_name: string;
|
||||||
regular_hours: number;
|
regular_hours: number;
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import type { PayPeriodEmployeeOverview } from "./timesheet-approval-pay-period-employee-overview-interface";
|
import type { PayPeriodOverviewEmployee } from "./timesheet-approval-pay-period-overview-employee-interface";
|
||||||
|
|
||||||
export interface PayPeriodOverview {
|
export interface PayPeriodOverview {
|
||||||
pay_period_no: number;
|
pay_period_no: number;
|
||||||
|
|
@ -7,5 +7,5 @@ export interface PayPeriodOverview {
|
||||||
period_start: string;
|
period_start: string;
|
||||||
period_end: string;
|
period_end: string;
|
||||||
label: string;
|
label: string;
|
||||||
employees_overview: PayPeriodEmployeeOverview[];
|
employees_overview: PayPeriodOverviewEmployee[];
|
||||||
};
|
};
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import type { Shift } from "./timesheet-shift-interface";
|
||||||
|
|
||||||
export interface TimesheetDetailsWeek {
|
export interface TimesheetDetailsWeek {
|
||||||
is_approved: boolean;
|
is_approved: boolean;
|
||||||
shifts: WeekDay<TimesheetDetailsWeekDayShifts>;
|
shifts: WeekDay<TimesheetDetailsWeekDayShifts>;
|
||||||
|
|
@ -16,12 +18,6 @@ type WeekDay<T> = {
|
||||||
|
|
||||||
type TimesheetDetailsWeekDayShifts = Shift[];
|
type TimesheetDetailsWeekDayShifts = Shift[];
|
||||||
|
|
||||||
interface Shift {
|
|
||||||
is_approved: boolean;
|
|
||||||
start_time: string;
|
|
||||||
end_time: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TimesheetDetailsWeekDayExpenses {
|
interface TimesheetDetailsWeekDayExpenses {
|
||||||
costs: Expense[];
|
costs: Expense[];
|
||||||
mileage: Expense[];
|
mileage: Expense[];
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
export interface Shift {
|
||||||
|
is_approved: boolean;
|
||||||
|
start_time: string;
|
||||||
|
end_time: string;
|
||||||
|
}
|
||||||
|
|
@ -2,8 +2,8 @@ import { defineStore } from 'pinia';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { timesheetApprovalService } from 'src/modules/timesheet-approval/services/services-timesheet-approval';
|
import { timesheetApprovalService } from 'src/modules/timesheet-approval/services/services-timesheet-approval';
|
||||||
import type { PayPeriod } from 'src/modules/shared/types/pay-period-interface';
|
import type { PayPeriod } from 'src/modules/shared/types/pay-period-interface';
|
||||||
import type { PayPeriodEmployeeOverview } from "src/modules/timesheet-approval/types/timesheet-approval-pay-period-employee-overview-interface";
|
import type { PayPeriodOverviewEmployee } from "src/modules/timesheet-approval/types/timesheet-approval-pay-period-overview-employee-interface";
|
||||||
import { PayPeriodEmployeeDetails } from 'src/modules/timesheet-approval/types/timesheet-approval-pay-period-employee-details-interface';
|
import type { PayPeriodEmployeeDetails } from 'src/modules/timesheet-approval/types/timesheet-approval-pay-period-employee-details-interface';
|
||||||
|
|
||||||
const default_pay_period: PayPeriod = {
|
const default_pay_period: PayPeriod = {
|
||||||
pay_period_no: -1,
|
pay_period_no: -1,
|
||||||
|
|
@ -17,8 +17,8 @@ const default_pay_period: PayPeriod = {
|
||||||
export const useTimesheetStore = defineStore('timesheet', () => {
|
export const useTimesheetStore = defineStore('timesheet', () => {
|
||||||
const is_loading = ref<boolean>(false);
|
const is_loading = ref<boolean>(false);
|
||||||
const current_pay_period = ref<PayPeriod>(default_pay_period);
|
const current_pay_period = ref<PayPeriod>(default_pay_period);
|
||||||
const pay_period_employee_overviews = ref<PayPeriodEmployeeOverview[]>([]);
|
const pay_period_overview_employees = ref<PayPeriodOverviewEmployee[]>([]);
|
||||||
const pay_period_employee_details = ref<PayPeriodEmployeeDetails | {}>({});
|
const pay_period_employee_details = ref<PayPeriodEmployeeDetails | undefined>();
|
||||||
|
|
||||||
const getPayPeriodByDate = async (date_string: string): Promise<boolean> => {
|
const getPayPeriodByDate = async (date_string: string): Promise<boolean> => {
|
||||||
is_loading.value = true;
|
is_loading.value = true;
|
||||||
|
|
@ -62,27 +62,35 @@ export const useTimesheetStore = defineStore('timesheet', () => {
|
||||||
is_loading.value = true;
|
is_loading.value = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await timesheetApprovalService.getPayPeriodEmployeeOverviews(pay_year, period_number, supervisor_email);
|
const response = await timesheetApprovalService.getPayPeriodEmployeeOverviews(
|
||||||
pay_period_employee_overviews.value = response.employees_overview;
|
pay_year,
|
||||||
|
period_number,
|
||||||
|
supervisor_email
|
||||||
|
);
|
||||||
|
pay_period_overview_employees.value = response.employees_overview;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('There was an error retrieving Employee Pay Period overviews: ', error);
|
console.error('There was an error retrieving Employee Pay Period overviews: ', error);
|
||||||
pay_period_employee_overviews.value = [];
|
pay_period_overview_employees.value = [];
|
||||||
// TODO: More in-depth error-handling here
|
// TODO: More in-depth error-handling here
|
||||||
}
|
}
|
||||||
|
|
||||||
is_loading.value = false;
|
is_loading.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getTimesheetsByPayPeriodAndEmail = async (year: number, period_number: number, employee_email: string) => {
|
const getTimesheetsByPayPeriodAndEmail = async (employee_email: string) => {
|
||||||
is_loading.value = true;
|
is_loading.value = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await timesheetApprovalService.getTimesheetsByPayPeriodAndEmail(year, period_number, employee_email);
|
const response = await timesheetApprovalService.getTimesheetsByPayPeriodAndEmail(
|
||||||
|
current_pay_period.value.pay_year,
|
||||||
|
current_pay_period.value.pay_period_no,
|
||||||
|
employee_email
|
||||||
|
);
|
||||||
pay_period_employee_details.value = response;
|
pay_period_employee_details.value = response;
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('There was an error retrieving timesheet details for this employee: ', error);
|
console.error('There was an error retrieving timesheet details for this employee: ', error);
|
||||||
pay_period_employee_details.value = {};
|
pay_period_employee_details.value = MOCK_DATA_TIMESHEET_DETAILS;
|
||||||
// TODO: More in-depth error-handling here
|
// TODO: More in-depth error-handling here
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,10 +99,58 @@ export const useTimesheetStore = defineStore('timesheet', () => {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
current_pay_period,
|
current_pay_period,
|
||||||
pay_period_employee_overviews,
|
pay_period_overview_employees,
|
||||||
is_loading,
|
pay_period_employee_details,
|
||||||
|
is_loading,
|
||||||
getPayPeriodByDate,
|
getPayPeriodByDate,
|
||||||
getPayPeriodByYearAndPeriodNumber,
|
getPayPeriodByYearAndPeriodNumber,
|
||||||
getTimesheetApprovalPayPeriodEmployeeOverviews,
|
getTimesheetApprovalPayPeriodEmployeeOverviews,
|
||||||
|
getTimesheetsByPayPeriodAndEmail,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const MOCK_DATA_TIMESHEET_DETAILS = {
|
||||||
|
is_approved: false,
|
||||||
|
week1: {
|
||||||
|
is_approved: true,
|
||||||
|
shifts: {
|
||||||
|
sun: [],
|
||||||
|
mon: [ { is_approved: true, start_time: '08:00', end_time: '12:00' }, { is_approved: true, start_time: '13:00', end_time: '17:00' } ],
|
||||||
|
tue: [ { is_approved: true, start_time: '08:00', end_time: '11:45' }, { is_approved: true, start_time: '12:45', end_time: '17:00' } ],
|
||||||
|
wed: [ { is_approved: true, start_time: '08:00', end_time: '12:00' }, { is_approved: true, start_time: '13:00', end_time: '17:00' } ],
|
||||||
|
thu: [ { is_approved: false, start_time: '13:00', end_time: '17:00' } ],
|
||||||
|
fri: [ { is_approved: true, start_time: '08:00', end_time: '12:00' }, { is_approved: true, start_time: '13:00', end_time: '17:00' } ],
|
||||||
|
sat: []
|
||||||
|
},
|
||||||
|
expenses: {
|
||||||
|
sun: { costs: [], mileage: [] },
|
||||||
|
mon: { costs: [ { is_approved: true, amount: 156.49 } ], mileage: [] },
|
||||||
|
tue: { costs: [], mileage: [] },
|
||||||
|
wed: { costs: [], mileage: [] },
|
||||||
|
thu: { costs: [], mileage: [ { is_approved: false, amount: 16 } ] },
|
||||||
|
fri: { costs: [], mileage: [] },
|
||||||
|
sat: { costs: [], mileage: [] }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
week2: {
|
||||||
|
is_approved: true,
|
||||||
|
shifts: {
|
||||||
|
sun: [],
|
||||||
|
mon: [],
|
||||||
|
tue: [],
|
||||||
|
wed: [],
|
||||||
|
thu: [],
|
||||||
|
fri: [],
|
||||||
|
sat: []
|
||||||
|
},
|
||||||
|
expenses: {
|
||||||
|
sun: { costs: [], mileage: [] },
|
||||||
|
mon: { costs: [], mileage: [] },
|
||||||
|
tue: { costs: [], mileage: [] },
|
||||||
|
wed: { costs: [], mileage: [] },
|
||||||
|
thu: { costs: [], mileage: [] },
|
||||||
|
fri: { costs: [], mileage: [] },
|
||||||
|
sat: { costs: [], mileage: [] }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
} as PayPeriodEmployeeDetails;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user