fix(details): complete chart implementation for worked hours, stacking bars, proper mobile scaling
This commit is contained in:
parent
58f6e808d0
commit
24a700d6f6
|
|
@ -24,7 +24,7 @@ $dark: #000;
|
|||
$dark-page: #323232;
|
||||
|
||||
$positive: #21ba45;
|
||||
$negative: #df6674;
|
||||
$negative: #ff576ba9;
|
||||
$info: #54bbdd;
|
||||
$warning: #eec964;
|
||||
$white: white;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,18 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { Bar } from 'vue-chartjs';
|
||||
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale, type ChartData, type ChartOptions, type Plugin } from 'chart.js';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale, type ChartData, type ChartOptions, type Plugin, type ChartDataset } from 'chart.js';
|
||||
import type { PayPeriodEmployeeDetails } from 'src/modules/timesheet-approval/types/timesheet-approval-pay-period-employee-details-interface';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale);
|
||||
ChartJS.defaults.font.family = '"Roboto", sans-serif';
|
||||
ChartJS.defaults.maintainAspectRatio = false;
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
data: ChartData<"bar">;
|
||||
rawData: PayPeriodEmployeeDetails | undefined;
|
||||
options?: ChartOptions<"bar"> | undefined;
|
||||
plugins?: Plugin<"bar">[] | undefined;
|
||||
}>(), {
|
||||
|
|
@ -13,11 +20,73 @@
|
|||
plugins: () => [],
|
||||
});
|
||||
|
||||
const hours_worked_labels = ref<string[]>([]);
|
||||
const hours_worked_dataset = ref<ChartDataset<'bar'>[]>([]);
|
||||
|
||||
|
||||
const getHoursWorkedData = (): ChartData<'bar'> => {
|
||||
if (props.rawData) {
|
||||
const all_weeks = [props.rawData.week1, props.rawData.week2];
|
||||
const all_days = all_weeks.flatMap( week => Object.values(week.shifts));
|
||||
const regular_hours = all_days.map( day => day.regular_hours);
|
||||
const evening_hours = all_days.map( day => day.evening_hours);
|
||||
const emergency_hours = all_days.map( day => day.emergency_hours);
|
||||
const overtime_hours = all_days.map( day => day.overtime_hours);
|
||||
|
||||
hours_worked_dataset.value = [
|
||||
{
|
||||
label: t('timeSheetValidations.hoursWorkedRegular'),
|
||||
data: regular_hours,
|
||||
backgroundColor: getComputedStyle(document.body).getPropertyValue('--q-primary').trim(),
|
||||
},
|
||||
{
|
||||
label: t('timeSheetValidations.hoursWorkedEvening'),
|
||||
data: evening_hours,
|
||||
backgroundColor: getComputedStyle(document.body).getPropertyValue('--q-info').trim(),
|
||||
},
|
||||
{
|
||||
label: t('timeSheetValidations.hoursWorkedEmergency'),
|
||||
data: emergency_hours,
|
||||
backgroundColor: getComputedStyle(document.body).getPropertyValue('--q-warning').trim(),
|
||||
},
|
||||
{
|
||||
label: t('timeSheetValidations.hoursWorkedOvertime'),
|
||||
data: overtime_hours,
|
||||
backgroundColor: getComputedStyle(document.body).getPropertyValue('--q-negative').trim(),
|
||||
},
|
||||
]
|
||||
hours_worked_labels.value = all_days.map( day => day.short_date);
|
||||
}
|
||||
|
||||
return {
|
||||
labels: hours_worked_labels.value,
|
||||
datasets: hours_worked_dataset.value,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Bar
|
||||
:data="props.data"
|
||||
:data="getHoursWorkedData()"
|
||||
:options="({
|
||||
indexAxis: $q.screen.lt.md? 'y' : 'x',
|
||||
plugins: {
|
||||
title: {
|
||||
display: true,
|
||||
text: t('timeSheetValidations.hoursWorkedChartTitle'),
|
||||
color: '#616161'
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
stacked: true,
|
||||
},
|
||||
y: {
|
||||
stacked: true,
|
||||
}
|
||||
}
|
||||
})"
|
||||
/>
|
||||
</template>
|
||||
|
|
@ -1,11 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import type { PayPeriodEmployeeDetails } from '../types/timesheet-approval-pay-period-employee-details-interface';
|
||||
import type { ChartData, ChartDataset } from 'chart.js';
|
||||
import TimesheetApprovalEmployeeDetailsHoursWorkedChart from 'src/modules/timesheet-approval/components/graphs/timesheet-approval-employee-details-hours-worked-chart.vue';
|
||||
import { ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps<{
|
||||
isLoading: boolean;
|
||||
|
|
@ -13,50 +8,6 @@
|
|||
employeeDetails: PayPeriodEmployeeDetails | undefined;
|
||||
updateKey: number;
|
||||
}>();
|
||||
|
||||
const hours_worked_labels = ref<string[]>([]);
|
||||
const hours_worked_dataset = ref<ChartDataset<'bar'>[]>([]);
|
||||
|
||||
|
||||
const getHoursWorkedData = (): ChartData<'bar'> => {
|
||||
if (props.employeeDetails) {
|
||||
const all_weeks = [props.employeeDetails.week1, props.employeeDetails.week2];
|
||||
const all_days = all_weeks.flatMap( week => Object.values(week.shifts));
|
||||
const regular_hours = all_days.map( day => day.regular_hours);
|
||||
const evening_hours = all_days.map( day => day.evening_hours);
|
||||
const emergency_hours = all_days.map( day => day.emergency_hours);
|
||||
const overtime_hours = all_days.map( day => day.overtime_hours);
|
||||
|
||||
hours_worked_dataset.value = [
|
||||
{
|
||||
label: t('timeSheetValidations.hoursWorkedRegular'),
|
||||
data: regular_hours,
|
||||
backgroundColor: getComputedStyle(document.body).getPropertyValue('--q-primary').trim(),
|
||||
},
|
||||
{
|
||||
label: t('timeSheetValidations.hoursWorkedEvening'),
|
||||
data: evening_hours,
|
||||
backgroundColor: getComputedStyle(document.body).getPropertyValue('--q-info').trim(),
|
||||
},
|
||||
{
|
||||
label: t('timeSheetValidations.hoursWorkedEmergency'),
|
||||
data: emergency_hours,
|
||||
backgroundColor: getComputedStyle(document.body).getPropertyValue('--q-warning').trim(),
|
||||
},
|
||||
{
|
||||
label: t('timeSheetValidations.hoursWorkedOvertime'),
|
||||
data: overtime_hours,
|
||||
backgroundColor: getComputedStyle(document.body).getPropertyValue('--q-negative').trim(),
|
||||
},
|
||||
]
|
||||
hours_worked_labels.value = all_days.map( day => day.short_date);
|
||||
}
|
||||
|
||||
return {
|
||||
labels: hours_worked_labels.value,
|
||||
datasets: hours_worked_dataset.value,
|
||||
};
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
@ -82,8 +33,16 @@
|
|||
</q-card-section>
|
||||
|
||||
<!-- employee timesheet details -->
|
||||
<q-card-section class="q-pa-none justify-center" :class="$q.screen.lt.lg? 'column': 'row'">
|
||||
<TimesheetApprovalEmployeeDetailsHoursWorkedChart :key="props.updateKey" :data="getHoursWorkedData()" />
|
||||
<q-card-section
|
||||
v-if="!props.isLoading"
|
||||
class="q-pa-none justify-center"
|
||||
:class="$q.screen.lt.lg? 'column': 'row'"
|
||||
>
|
||||
<TimesheetApprovalEmployeeDetailsHoursWorkedChart
|
||||
:key="props.updateKey"
|
||||
:raw-data="props.employeeDetails"
|
||||
style="min-height: 300px;"
|
||||
/>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</template>
|
||||
|
|
@ -122,12 +122,10 @@
|
|||
clicked_employee_name.value = name;
|
||||
is_showing_details.value = true;
|
||||
await timesheet_approval_api.getTimesheetsByPayPeriodAndEmail(email);
|
||||
console.log('current employee details: ', timesheet_store.pay_period_employee_details);
|
||||
};
|
||||
|
||||
const onClickPrintReport = async () => {
|
||||
await timesheet_approval_api.getTimesheetApprovalCSVReport(report_filter_company.value, report_filter_type.value);
|
||||
console.log('current filter selections: [', report_filter_company.value.toLocaleString(),'], [', report_filter_type.value.toLocaleString(), ']');
|
||||
};
|
||||
|
||||
onMounted( async () => {
|
||||
|
|
@ -144,7 +142,7 @@
|
|||
v-model="is_showing_details"
|
||||
transition-show="jump-down"
|
||||
transition-hide="jump-down"
|
||||
@show="() => update_key += 1"
|
||||
@before-show="() => update_key += 1"
|
||||
>
|
||||
<TimesheetApprovalEmployeeDetails
|
||||
:is-loading="timesheet_store.is_loading"
|
||||
|
|
|
|||
|
|
@ -19,11 +19,13 @@ export const timesheetApprovalService = {
|
|||
getPayPeriodEmployeeOverviews: async (year: number, period_number: number, supervisor_email: string): Promise<PayPeriodOverview> => {
|
||||
// TODO: REMOVE MOCK DATA PEFORE PUSHING TO PROD
|
||||
const response = await api.get(`pay-periods/${year}/${period_number}/${supervisor_email}`);
|
||||
console.log('all employee data: ', response.data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
getTimesheetsByPayPeriodAndEmail: async (year: number, period_no: number, email: string): Promise<PayPeriodEmployeeDetails> => {
|
||||
const response = await api.get('timesheets', { params: { year, period_no, email, }});
|
||||
console.log('employee details: ', response.data);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user