feat(approvals): Add details card basic. Add logic with service, store, api. Create temporary mock data for testing.
This commit is contained in:
parent
8c42235851
commit
911a959567
|
|
@ -0,0 +1,29 @@
|
||||||
|
<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>
|
||||||
|
|
@ -10,13 +10,27 @@
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
cols: TableColumn[];
|
cols: TableColumn[];
|
||||||
row: PayPeriodEmployeeOverview;
|
row: PayPeriodEmployeeOverview;
|
||||||
modelValue: boolean;
|
initialState: boolean;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
isDetailsButtonPressed: []
|
||||||
|
'update:modelValue': [value: string | number | 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 -->
|
||||||
|
<q-btn
|
||||||
|
flat
|
||||||
|
unelevated
|
||||||
|
class="q-pa-sm"
|
||||||
|
icon="open_in_full"
|
||||||
|
@click="emit('isDetailsButtonPressed')"
|
||||||
|
/>
|
||||||
|
|
||||||
<!-- Card header with employee name -->
|
<!-- Card header with employee name -->
|
||||||
<q-card-section
|
<q-card-section
|
||||||
horizontal
|
horizontal
|
||||||
|
|
@ -117,7 +131,7 @@
|
||||||
<q-card-section
|
<q-card-section
|
||||||
horizontal
|
horizontal
|
||||||
class="q-pa-sm text-weight-bold"
|
class="q-pa-sm text-weight-bold"
|
||||||
:class="props.modelValue ? 'text-white bg-primary' : 'text-primary bg-white'"
|
:class="props.initialState ? 'text-white bg-primary' : 'text-primary bg-white'"
|
||||||
>
|
>
|
||||||
<q-space />
|
<q-space />
|
||||||
<q-checkbox
|
<q-checkbox
|
||||||
|
|
@ -126,10 +140,10 @@
|
||||||
size="lg"
|
size="lg"
|
||||||
checked-icon="lock"
|
checked-icon="lock"
|
||||||
unchecked-icon="lock_open"
|
unchecked-icon="lock_open"
|
||||||
:color="props.modelValue ? 'white' : 'primary'" keep-color
|
:color="props.initialState ? 'white' : 'primary'" keep-color
|
||||||
:model-value="props.modelValue"
|
:model-value="props.initialState"
|
||||||
@update:model-value="val => $emit('update:modelValue', val)"
|
@update:model-value="val => emit('update:modelValue', val)"
|
||||||
:label="props.modelValue ? $t('timeSheetValidations.timeSheetStatusVerified') : $t('timeSheetValidations.timeSheetStatusUnverified')"
|
:label="props.initialState ? $t('timeSheetValidations.timeSheetStatusVerified') : $t('timeSheetValidations.timeSheetStatusUnverified')"
|
||||||
class="text-uppercase"
|
class="text-uppercase"
|
||||||
/>
|
/>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@
|
||||||
<TimesheetApprovalEmployeeOverviewListItem
|
<TimesheetApprovalEmployeeOverviewListItem
|
||||||
:cols="props.cols"
|
:cols="props.cols"
|
||||||
:row="props.row"
|
:row="props.row"
|
||||||
v-model="props.row.is_approved"/>
|
:initial-state="props.row.is_approved"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- Template for custome failed-to-load state -->
|
<!-- Template for custome failed-to-load state -->
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
'date-selected': [value: string, reason?: string, details?: QDateDetails]
|
'date-selected': [value: string, reason?: string, details?: QDateDetails]
|
||||||
'pressed-previous-button': void
|
'pressed-previous-button': []
|
||||||
'pressed-next-button': void
|
'pressed-next-button': []
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const onDateSelected = (value: string, reason: string, details: QDateDetails) => {
|
const onDateSelected = (value: string, reason: string, details: QDateDetails) => {
|
||||||
|
|
@ -31,7 +31,7 @@
|
||||||
push rounded
|
push rounded
|
||||||
icon="keyboard_arrow_left"
|
icon="keyboard_arrow_left"
|
||||||
color="primary"
|
color="primary"
|
||||||
@click="$emit('pressed-previous-button')"
|
@click="emit('pressed-previous-button')"
|
||||||
:disable="props.isPreviousLimit || props.isDisabled"
|
:disable="props.isPreviousLimit || props.isDisabled"
|
||||||
class="q-mr-sm q-px-sm"
|
class="q-mr-sm q-px-sm"
|
||||||
/>
|
/>
|
||||||
|
|
@ -47,7 +47,7 @@
|
||||||
push rounded
|
push rounded
|
||||||
icon="keyboard_arrow_right"
|
icon="keyboard_arrow_right"
|
||||||
color="primary"
|
color="primary"
|
||||||
@click="$emit('pressed-next-button')"
|
@click="emit('pressed-next-button')"
|
||||||
:disable="props.isDisabled"
|
:disable="props.isDisabled"
|
||||||
class="q-ml-sm q-px-sm"
|
class="q-ml-sm q-px-sm"
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { api } from "src/boot/axios";
|
import { api } from "src/boot/axios";
|
||||||
import type { PayPeriodOverview } from "../types/timesheet-approval-pay-period-overview-interface";
|
import type { PayPeriodOverview } from "../types/timesheet-approval-pay-period-overview-interface";
|
||||||
import type { PayPeriod } from "src/modules/shared/types/pay-period-interface";
|
import type { PayPeriod } from "src/modules/shared/types/pay-period-interface";
|
||||||
|
import type { PayPeriodEmployeeDetails } from "../types/timesheet-approval-pay-period-employee-details-interface";
|
||||||
|
|
||||||
export const timesheetApprovalService = {
|
export const timesheetApprovalService = {
|
||||||
getPayPeriodByDate: async (date_string: string): Promise<PayPeriod> => {
|
getPayPeriodByDate: async (date_string: string): Promise<PayPeriod> => {
|
||||||
|
|
@ -19,4 +20,55 @@ export const timesheetApprovalService = {
|
||||||
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> => {
|
||||||
|
const response = await api.get(`/timesheets/${year}/${period_number}/${employee_email}`) || { data: MOCK_DATA_TIMESHEET_DETAILS, status: 200, statusText: 'OK'};
|
||||||
|
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;
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
import type { TimesheetDetailsWeek } from "src/modules/timesheets/types/timesheet-details-interface";
|
||||||
|
|
||||||
|
export interface PayPeriodEmployeeDetails {
|
||||||
|
is_approved: boolean;
|
||||||
|
week1: TimesheetDetailsWeek;
|
||||||
|
week2: TimesheetDetailsWeek;
|
||||||
|
};
|
||||||
34
src/modules/timesheets/types/timesheet-details-interface.ts
Normal file
34
src/modules/timesheets/types/timesheet-details-interface.ts
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
export interface TimesheetDetailsWeek {
|
||||||
|
is_approved: boolean;
|
||||||
|
shifts: WeekDay<TimesheetDetailsWeekDayShifts>;
|
||||||
|
expenses: WeekDay<TimesheetDetailsWeekDayExpenses>;
|
||||||
|
}
|
||||||
|
|
||||||
|
type WeekDay<T> = {
|
||||||
|
sun: T;
|
||||||
|
mon: T;
|
||||||
|
tue: T;
|
||||||
|
wed: T;
|
||||||
|
thu: T;
|
||||||
|
fri: T;
|
||||||
|
sat: T;
|
||||||
|
}
|
||||||
|
|
||||||
|
type TimesheetDetailsWeekDayShifts = Shift[];
|
||||||
|
|
||||||
|
interface Shift {
|
||||||
|
is_approved: boolean;
|
||||||
|
start_time: string;
|
||||||
|
end_time: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TimesheetDetailsWeekDayExpenses {
|
||||||
|
costs: Expense[];
|
||||||
|
mileage: Expense[];
|
||||||
|
[otherType: string]: Expense[]; //for possible future types of expenses
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Expense {
|
||||||
|
is_approved: boolean;
|
||||||
|
amount: number;
|
||||||
|
};
|
||||||
|
|
@ -3,6 +3,7 @@ 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 { PayPeriodEmployeeOverview } from "src/modules/timesheet-approval/types/timesheet-approval-pay-period-employee-overview-interface";
|
||||||
|
import { 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,
|
||||||
|
|
@ -14,9 +15,10 @@ const default_pay_period: PayPeriod = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useTimesheetStore = defineStore('timesheet', () => {
|
export const useTimesheetStore = defineStore('timesheet', () => {
|
||||||
|
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_employee_overviews = ref<PayPeriodEmployeeOverview[]>([]);
|
||||||
const is_loading = ref<boolean>(false);
|
const pay_period_employee_details = ref<PayPeriodEmployeeDetails | {}>({});
|
||||||
|
|
||||||
const getPayPeriodByDate = async (date_string: string): Promise<boolean> => {
|
const getPayPeriodByDate = async (date_string: string): Promise<boolean> => {
|
||||||
is_loading.value = true;
|
is_loading.value = true;
|
||||||
|
|
@ -65,12 +67,28 @@ export const useTimesheetStore = defineStore('timesheet', () => {
|
||||||
} 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_employee_overviews.value = [];
|
||||||
// TODO: trigger an alert window with an error message 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) => {
|
||||||
|
is_loading.value = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await timesheetApprovalService.getTimesheetsByPayPeriodAndEmail(year, period_number, employee_email);
|
||||||
|
pay_period_employee_details.value = response;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('There was an error retrieving timesheet details for this employee: ', error);
|
||||||
|
pay_period_employee_details.value = {};
|
||||||
|
// TODO: More in-depth error-handling here
|
||||||
|
}
|
||||||
|
|
||||||
|
is_loading.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
current_pay_period,
|
current_pay_period,
|
||||||
pay_period_employee_overviews,
|
pay_period_employee_overviews,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user