Merge branch 'main' of git.targo.ca:Targo/targo_frontend into dev/matthieu/timesheet-form
This commit is contained in:
commit
7bc9b45ef0
|
|
@ -24,7 +24,7 @@ $dark: #000;
|
||||||
$dark-page: #323232;
|
$dark-page: #323232;
|
||||||
|
|
||||||
$positive: #21ba45;
|
$positive: #21ba45;
|
||||||
$negative: #ff576ba9;
|
$negative: #e6364b;
|
||||||
$info: #54bbdd;
|
$info: #6bb9e7;
|
||||||
$warning: #eec964;
|
$warning: #e4a944;
|
||||||
$white: white;
|
$white: white;
|
||||||
|
|
|
||||||
|
|
@ -247,7 +247,7 @@ export default {
|
||||||
newUsers: 'New user',
|
newUsers: 'New user',
|
||||||
updateUsers: 'Update user',
|
updateUsers: 'Update user',
|
||||||
timeSheets: 'Time sheet',
|
timeSheets: 'Time sheet',
|
||||||
timeSheetValidations: 'Time sheet',
|
timeSheetValidations: 'Time sheet approvals',
|
||||||
},
|
},
|
||||||
timesheet: {
|
timesheet: {
|
||||||
//employee's timesheet page
|
//employee's timesheet page
|
||||||
|
|
@ -289,13 +289,13 @@ export default {
|
||||||
shiftComment: 'Comment',
|
shiftComment: 'Comment',
|
||||||
overTimeTitle: 'Overtime regular hours: ',
|
overTimeTitle: 'Overtime regular hours: ',
|
||||||
totalPayedHours: 'Total hours worked: ',
|
totalPayedHours: 'Total hours worked: ',
|
||||||
//shiftOptions
|
// shift options
|
||||||
regularShift: 'Regular',
|
shiftRegular: 'regular',
|
||||||
eveningShift: 'Evening',
|
shiftEvening: 'evening',
|
||||||
emergencyShift: 'Emergency',
|
shiftEmergency: 'emergency',
|
||||||
sickDay: 'Sick working day',
|
shiftSick: 'sick',
|
||||||
vacancyDay: 'vacation',
|
shiftVacation: 'vacation',
|
||||||
holiday: 'Holiday',
|
shiftHoliday: 'holiday',
|
||||||
dateRangesFrom: 'from',
|
dateRangesFrom: 'from',
|
||||||
dateRangesTo: 'to',
|
dateRangesTo: 'to',
|
||||||
shiftBankedHours: 'Total hours to bank',
|
shiftBankedHours: 'Total hours to bank',
|
||||||
|
|
@ -371,13 +371,13 @@ export default {
|
||||||
reportFilterVacation: 'Vacation',
|
reportFilterVacation: 'Vacation',
|
||||||
},
|
},
|
||||||
shiftColumns: {
|
shiftColumns: {
|
||||||
title: 'Shifts',
|
title: 'shifts',
|
||||||
column_1: 'Type',
|
labelType: 'type',
|
||||||
column_2: 'Start time',
|
labelIn: 'start',
|
||||||
column_3: 'End time',
|
labelOut: 'end',
|
||||||
column_4: 'Comment',
|
labelComment: 'comment',
|
||||||
column_5: 'Status',
|
labelState: 'state',
|
||||||
column_6: 'Supervisor’s report',
|
labelSupervisorReport: 'supervisor report',
|
||||||
},
|
},
|
||||||
expenseColumns: {
|
expenseColumns: {
|
||||||
title: 'Expenses',
|
title: 'Expenses',
|
||||||
|
|
@ -398,7 +398,7 @@ export default {
|
||||||
message_start: 'Attention: You will be automatically logged out in',
|
message_start: 'Attention: You will be automatically logged out in',
|
||||||
message_end: 'seconds if you do not interact with the screen.',
|
message_end: 'seconds if you do not interact with the screen.',
|
||||||
},
|
},
|
||||||
daysOfWeek: {
|
weekdays: {
|
||||||
Sunday: ' Sunday',
|
Sunday: ' Sunday',
|
||||||
Monday: 'Monday',
|
Monday: 'Monday',
|
||||||
Tuesday: 'Tuesday',
|
Tuesday: 'Tuesday',
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ export default {
|
||||||
message_start: 'Attention : vous serez automatiquement déconnecté dans',
|
message_start: 'Attention : vous serez automatiquement déconnecté dans',
|
||||||
message_end: 'secondes si vous n’interagissez pas avec l’écran.',
|
message_end: 'secondes si vous n’interagissez pas avec l’écran.',
|
||||||
},
|
},
|
||||||
daysOfWeek: {
|
weekdays: {
|
||||||
Sunday: 'dimanche',
|
Sunday: 'dimanche',
|
||||||
Monday: 'lundi',
|
Monday: 'lundi',
|
||||||
Tuesday: 'mardi',
|
Tuesday: 'mardi',
|
||||||
|
|
@ -237,12 +237,12 @@ export default {
|
||||||
},
|
},
|
||||||
shiftColumns: {
|
shiftColumns: {
|
||||||
title: 'Quarts de travail',
|
title: 'Quarts de travail',
|
||||||
column_1: 'Type',
|
labelType: 'type',
|
||||||
column_2: 'Entrée',
|
labelIn: 'entrée',
|
||||||
column_3: 'Sortie',
|
labelOut: 'sortie',
|
||||||
column_4: 'Commentaire',
|
labelComment: 'commentaire',
|
||||||
column_5: 'État',
|
labelState: 'état',
|
||||||
column_6: 'Rapport du superviseur',
|
labelSupervisorReport: 'rapport du superviseur',
|
||||||
},
|
},
|
||||||
shiftsTemplate: {
|
shiftsTemplate: {
|
||||||
tabTitle1: 'Quarts de travail',
|
tabTitle1: 'Quarts de travail',
|
||||||
|
|
@ -340,13 +340,13 @@ export default {
|
||||||
shiftComment: 'Commentaire',
|
shiftComment: 'Commentaire',
|
||||||
overTimeTitle: 'Heures régulières supplémentaires: ',
|
overTimeTitle: 'Heures régulières supplémentaires: ',
|
||||||
totalPayedHours: 'Total des heures travaillées: ',
|
totalPayedHours: 'Total des heures travaillées: ',
|
||||||
//shiftOptions
|
// shift options
|
||||||
regularShift: 'Régulier',
|
shiftRegular: 'régulier',
|
||||||
eveningShift: 'Soir',
|
shiftEvening: 'soir',
|
||||||
emergencyShift: 'Urgence',
|
shiftEmergency: 'urgence',
|
||||||
sickDay: 'Maladie',
|
shiftSick: 'maladie',
|
||||||
vacancyDay: 'Vacances',
|
shiftVacation: 'vacances',
|
||||||
holiday: 'Férié',
|
shiftHoliday: 'férié',
|
||||||
dateRangesFrom: 'du',
|
dateRangesFrom: 'du',
|
||||||
dateRangesTo: 'au',
|
dateRangesTo: 'au',
|
||||||
shiftBankedHours: 'Totale d’heures à banquer',
|
shiftBankedHours: 'Totale d’heures à banquer',
|
||||||
|
|
|
||||||
|
|
@ -68,24 +68,26 @@
|
||||||
<template v-slot:top>
|
<template v-slot:top>
|
||||||
<div class="row full-width q-mb-sm">
|
<div class="row full-width q-mb-sm">
|
||||||
<q-btn push icon="person_add" color="primary" :label="$t('usersListPage.addButton')"/>
|
<q-btn push icon="person_add" color="primary" :label="$t('usersListPage.addButton')"/>
|
||||||
|
|
||||||
<q-space />
|
<q-space />
|
||||||
<q-btn-toggle push class="q-mr-md" color="white" text-color="primary" toggle-color="primary" v-model="isGridMode"
|
|
||||||
:options="[
|
<q-btn-toggle push class="q-mr-md" color="white" text-color="primary" toggle-color="primary" v-model="isGridMode"
|
||||||
{icon: 'grid_view', value: true},
|
:options="[
|
||||||
{icon: 'view_list', value: false},
|
{icon: 'grid_view', value: true},
|
||||||
]"/>
|
{icon: 'view_list', value: false},
|
||||||
<q-input
|
]"/>
|
||||||
outlined
|
<q-input
|
||||||
dense
|
outlined
|
||||||
rounded
|
dense
|
||||||
v-model="filter"
|
rounded
|
||||||
:label="$t('shared.searchBar')"
|
v-model="filter"
|
||||||
label-color="primary" bg-color="white" color="primary"
|
:label="$t('shared.searchBar')"
|
||||||
>
|
label-color="primary" bg-color="white" color="primary"
|
||||||
<template v-slot:append>
|
>
|
||||||
<q-icon name="search" color="primary"/>
|
<template v-slot:append>
|
||||||
</template>
|
<q-icon name="search" color="primary"/>
|
||||||
</q-input>
|
</template>
|
||||||
|
</q-input>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
<q-item-section :side="$q.screen.gt.sm">
|
<q-item-section :side="$q.screen.gt.sm">
|
||||||
<q-avatar rounded >
|
<q-avatar rounded >
|
||||||
<q-img src="src/assets/targo-default-avatar.png" />
|
<q-img src="src/assets/targo-default-avatar.png" />
|
||||||
<q-badge floating color="red" v-if="notifAmount > 0" >{{ notifAmount }}</q-badge>
|
<q-badge floating color="negative" v-if="notifAmount > 0" >{{ notifAmount }}</q-badge>
|
||||||
</q-avatar>
|
</q-avatar>
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
|
import { colors } from 'quasar';
|
||||||
import { Bar } from 'vue-chartjs';
|
import { Bar } from 'vue-chartjs';
|
||||||
import { useI18n } from 'vue-i18n';
|
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 { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale, type ChartData, type ChartOptions, type Plugin, type ChartDataset } from 'chart.js';
|
||||||
|
|
@ -7,55 +8,54 @@
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
|
||||||
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale);
|
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale);
|
||||||
ChartJS.defaults.font.family = '"Roboto", sans-serif';
|
ChartJS.defaults.font.family = '"Roboto", sans-serif';
|
||||||
ChartJS.defaults.maintainAspectRatio = false;
|
ChartJS.defaults.maintainAspectRatio = false;
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = defineProps<{
|
||||||
rawData: PayPeriodEmployeeDetails | undefined;
|
rawData: PayPeriodEmployeeDetails | undefined;
|
||||||
options?: ChartOptions<"bar"> | undefined;
|
options?: ChartOptions<"bar"> | undefined;
|
||||||
plugins?: Plugin<"bar">[] | undefined;
|
plugins?: Plugin<"bar">[] | undefined;
|
||||||
}>(), {
|
}>();
|
||||||
options: () => ({}),
|
|
||||||
plugins: () => [],
|
|
||||||
});
|
|
||||||
|
|
||||||
const hours_worked_labels = ref<string[]>([]);
|
const hours_worked_labels = ref<string[]>([]);
|
||||||
const hours_worked_dataset = ref<ChartDataset<'bar'>[]>([]);
|
const hours_worked_dataset = ref<ChartDataset<'bar'>[]>([]);
|
||||||
|
|
||||||
|
|
||||||
const getHoursWorkedData = (): ChartData<'bar'> => {
|
const getHoursWorkedData = (): ChartData<'bar'> => {
|
||||||
if (props.rawData) {
|
if (props.rawData) {
|
||||||
const all_weeks = [props.rawData.week1, props.rawData.week2];
|
const all_weeks = [props.rawData.week1, props.rawData.week2];
|
||||||
const all_days = all_weeks.flatMap( week => Object.values(week.shifts));
|
const all_days = all_weeks.flatMap( week => Object.values(week.shifts));
|
||||||
const regular_hours = all_days.map( day => day.regular_hours);
|
const datasetConfig = [
|
||||||
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 = [
|
|
||||||
{
|
{
|
||||||
|
key: 'regular_hours',
|
||||||
label: t('timeSheetValidations.hoursWorkedRegular'),
|
label: t('timeSheetValidations.hoursWorkedRegular'),
|
||||||
data: regular_hours,
|
color: colors.getPaletteColor('green-5'),
|
||||||
backgroundColor: getComputedStyle(document.body).getPropertyValue('--q-primary').trim(),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
key: 'evening_hours',
|
||||||
label: t('timeSheetValidations.hoursWorkedEvening'),
|
label: t('timeSheetValidations.hoursWorkedEvening'),
|
||||||
data: evening_hours,
|
color: colors.getPaletteColor('green-9'),
|
||||||
backgroundColor: getComputedStyle(document.body).getPropertyValue('--q-info').trim(),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
key: 'emergency_hours',
|
||||||
label: t('timeSheetValidations.hoursWorkedEmergency'),
|
label: t('timeSheetValidations.hoursWorkedEmergency'),
|
||||||
data: emergency_hours,
|
color: getComputedStyle(document.body).getPropertyValue('--q-warning').trim(),
|
||||||
backgroundColor: getComputedStyle(document.body).getPropertyValue('--q-warning').trim(),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
key: 'overtime_hours',
|
||||||
label: t('timeSheetValidations.hoursWorkedOvertime'),
|
label: t('timeSheetValidations.hoursWorkedOvertime'),
|
||||||
data: overtime_hours,
|
color: getComputedStyle(document.body).getPropertyValue('--q-negative').trim(),
|
||||||
backgroundColor: getComputedStyle(document.body).getPropertyValue('--q-negative').trim(),
|
|
||||||
},
|
},
|
||||||
]
|
] as const;
|
||||||
hours_worked_labels.value = all_days.map( day => day.short_date);
|
|
||||||
|
hours_worked_dataset.value = datasetConfig.map(cfg => ({
|
||||||
|
label: cfg.label,
|
||||||
|
data: all_days.map(day => day[ cfg.key ]),
|
||||||
|
backgroundColor: cfg.color,
|
||||||
|
}));
|
||||||
|
|
||||||
|
hours_worked_labels.value = all_days.map(day => day.short_date);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
@ -64,29 +64,36 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Bar
|
<Bar
|
||||||
:data="getHoursWorkedData()"
|
:data="getHoursWorkedData()"
|
||||||
:options="({
|
:options="({
|
||||||
indexAxis: $q.screen.lt.md? 'y' : 'x',
|
indexAxis: $q.screen.lt.md? 'y' : 'x',
|
||||||
plugins: {
|
plugins: {
|
||||||
title: {
|
legend: {
|
||||||
display: true,
|
labels: {
|
||||||
text: t('timeSheetValidations.hoursWorkedChartTitle'),
|
boxWidth: 15,
|
||||||
color: '#616161'
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
scales: {
|
},
|
||||||
x: {
|
title: {
|
||||||
stacked: true,
|
display: true,
|
||||||
},
|
text: t('timeSheetValidations.hoursWorkedChartTitle'),
|
||||||
y: {
|
color: '#616161'
|
||||||
stacked: true,
|
}
|
||||||
}
|
},
|
||||||
}
|
scales: {
|
||||||
})"
|
x: {
|
||||||
|
stacked: true,
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
stacked: true,
|
||||||
|
suggestedMin: 0,
|
||||||
|
suggestedMax: 10,
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
/* eslint-disable */
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { colors } from 'quasar';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { Doughnut } from 'vue-chartjs';
|
||||||
|
import { Chart as ChartJS, Title, Tooltip, Legend, ArcElement, CategoryScale, LinearScale, type ChartData, type ChartOptions, type Plugin, type ChartDataset } from 'chart.js';
|
||||||
|
import type { PayPeriodOverviewEmployee } from 'src/modules/timesheet-approval/types/timesheet-approval-pay-period-overview-employee-interface';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
ChartJS.register(Title, Tooltip, Legend, ArcElement, CategoryScale, LinearScale);
|
||||||
|
ChartJS.defaults.font.family = '"Roboto", sans-serif';
|
||||||
|
ChartJS.defaults.maintainAspectRatio = false;
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
rawData: PayPeriodOverviewEmployee | undefined;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const shift_type_labels = ref<string[]>([]);
|
||||||
|
const shift_type_totals = ref<ChartDataset<'doughnut'>[]>([{ data: [40, 0, 2, 5], }]);
|
||||||
|
|
||||||
|
if (props.rawData){
|
||||||
|
shift_type_totals.value = [{
|
||||||
|
data: [
|
||||||
|
props.rawData.regular_hours,
|
||||||
|
props.rawData.evening_hours,
|
||||||
|
props.rawData.emergency_hours,
|
||||||
|
props.rawData.overtime_hours,
|
||||||
|
],
|
||||||
|
backgroundColor: [
|
||||||
|
colors.getPaletteColor('green-5'), // Regular
|
||||||
|
colors.getPaletteColor('green-9'), // Evening
|
||||||
|
getComputedStyle(document.body).getPropertyValue('--q-warning').trim(), // Emergency
|
||||||
|
getComputedStyle(document.body).getPropertyValue('--q-negative').trim(), // Overtime
|
||||||
|
]
|
||||||
|
}];
|
||||||
|
|
||||||
|
shift_type_labels.value = [
|
||||||
|
props.rawData.regular_hours.toString() + 'h',
|
||||||
|
props.rawData.evening_hours.toString() + 'h',
|
||||||
|
props.rawData.emergency_hours.toString() + 'h',
|
||||||
|
props.rawData.overtime_hours.toString() + 'h',
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
labels: shift_type_labels.value,
|
||||||
|
datasets: shift_type_totals.value,
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Doughnut
|
||||||
|
:data="data"
|
||||||
|
:options="({
|
||||||
|
plugins:{
|
||||||
|
legend:{
|
||||||
|
labels:{
|
||||||
|
boxWidth: 15,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
/*eslint-disable*/
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { Bar } from 'vue-chartjs';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import { Chart as ChartJS, Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale, TimeScale, 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';
|
||||||
|
import type { Expense } from 'src/modules/timesheets/types/timesheet-details-interface';
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale, TimeScale);
|
||||||
|
ChartJS.defaults.font.family = '"Roboto", sans-serif';
|
||||||
|
ChartJS.defaults.maintainAspectRatio = false;
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
rawData: PayPeriodEmployeeDetails | undefined;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const expenses_dataset = ref<ChartDataset<'bar'>[]>([]);
|
||||||
|
const expenses_labels = ref<string[]>([]);
|
||||||
|
|
||||||
|
const getExpensesData = (): ChartData<'bar'> => {
|
||||||
|
if (props.rawData) {
|
||||||
|
const all_weeks = [props.rawData.week1, props.rawData.week2];
|
||||||
|
const all_days = all_weeks.flatMap( week => Object.values(week.expenses));
|
||||||
|
const all_days_dates = all_weeks.flatMap( week => Object.values(week.shifts))
|
||||||
|
|
||||||
|
const all_costs = all_days.map( day => getTotalAmounts(day.cash));
|
||||||
|
const all_mileage = all_days.map( day => getTotalAmounts(day.km));
|
||||||
|
|
||||||
|
|
||||||
|
expenses_dataset.value = [
|
||||||
|
{
|
||||||
|
label: t('timeSheet.refund'),
|
||||||
|
data: all_costs,
|
||||||
|
backgroundColor: getComputedStyle(document.body).getPropertyValue('--q-primary').trim(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('timeSheet.mileage'),
|
||||||
|
data: all_mileage,
|
||||||
|
backgroundColor: getComputedStyle(document.body).getPropertyValue('--q-info').trim(),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
expenses_labels.value = all_days_dates.map( day => day.short_date);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
datasets: expenses_dataset.value,
|
||||||
|
labels: expenses_labels.value
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTotalAmounts = (expenses: Expense[]): number => {
|
||||||
|
let total_amount = 0;
|
||||||
|
|
||||||
|
for (const expense of expenses) {
|
||||||
|
total_amount += expense.amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return total_amount;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Bar
|
||||||
|
:data="getExpensesData()"
|
||||||
|
:options="({
|
||||||
|
indexAxis: $q.screen.lt.md? 'y' : 'x',
|
||||||
|
plugins: {
|
||||||
|
title: {
|
||||||
|
display: true,
|
||||||
|
text: t('timeSheetValidations.reportFilterExpenses'),
|
||||||
|
color: '#616161'
|
||||||
|
},
|
||||||
|
legend:{
|
||||||
|
labels:{
|
||||||
|
boxWidth: 15,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
stacked: true
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
suggestedMin: 0,
|
||||||
|
suggestedMax: 100,
|
||||||
|
stacked: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})"
|
||||||
|
:style="$q.screen.lt.md ? 'min-height: 300px;': '' "
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
<template>
|
||||||
|
<q-card-section
|
||||||
|
horizontal
|
||||||
|
class="text-uppercase text-center items-center q-pa-none"
|
||||||
|
>
|
||||||
|
<!-- shift row itself -->
|
||||||
|
<q-card-section class="col q-pa-none">
|
||||||
|
<q-card-section horizontal class="col q-pa-none">
|
||||||
|
<!-- punch-in timestamps -->
|
||||||
|
<q-card-section class="col q-pa-none">
|
||||||
|
<q-item-label class="text-weight-bolder text-primary" style="font-size: 0.7em;">
|
||||||
|
{{ $t('shiftColumns.labelIn') }}
|
||||||
|
</q-item-label>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<!-- arrows pointing to punch-out timestamps -->
|
||||||
|
<q-card-section class="col q-py-none q-px-sm">
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<!-- punch-out timestamps -->
|
||||||
|
<q-card-section class="col q-pa-none">
|
||||||
|
<q-item-label class="text-weight-bolder text-primary" style="font-size: 0.7em;">
|
||||||
|
{{ $t('shiftColumns.labelOut') }}
|
||||||
|
</q-item-label>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<!-- comment button -->
|
||||||
|
<q-card-section class="col column q-pa-none">
|
||||||
|
</q-card-section>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card-section>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { Shift } from 'src/modules/timesheets/types/timesheet-shift-interface';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
shift: Shift;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const getShiftColor = (type: string): string => {
|
||||||
|
switch(type) {
|
||||||
|
case 'REGULAR': return 'secondary';
|
||||||
|
case 'EVENING': return 'warning';
|
||||||
|
case 'EMERGENCY': return 'amber-10';
|
||||||
|
case 'OVERTIME': return 'negative';
|
||||||
|
case 'VACATION': return 'purple-10';
|
||||||
|
case 'HOLIDAY': return 'purple-10';
|
||||||
|
case 'SICK': return 'grey-8';
|
||||||
|
default : return 'transparent';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTextColor = (type: string): string => {
|
||||||
|
switch(type) {
|
||||||
|
case 'REGULAR': return 'grey-8';
|
||||||
|
case '': return 'transparent';
|
||||||
|
default: return 'white';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<q-card-section
|
||||||
|
horizontal
|
||||||
|
class="q-pa-none text-uppercase text-center items-center cursor-pointer rounded-10"
|
||||||
|
style="line-height: 1;"
|
||||||
|
>
|
||||||
|
<!-- punch-in timestamps -->
|
||||||
|
<q-card-section class="q-pa-none col">
|
||||||
|
<q-item-label
|
||||||
|
class="text-weight-bolder q-pa-xs rounded-5"
|
||||||
|
:class="'bg-' + getShiftColor(props.shift.type) + ' text-' + getTextColor(props.shift.type)"
|
||||||
|
style="font-size: 1.5em; line-height: 80% !important;"
|
||||||
|
>
|
||||||
|
{{ props.shift.start_time }}
|
||||||
|
</q-item-label>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<!-- arrows pointing to punch-out timestamps -->
|
||||||
|
<q-card-section
|
||||||
|
horizontal
|
||||||
|
class="items-center justify-center q-mx-sm col"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="icon_data, index in [
|
||||||
|
{ transform: 'transform: translateX(5px);', color: 'accent' },
|
||||||
|
{ transform: 'transform: translateX(-5px);', color: 'primary' }]"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<q-icon
|
||||||
|
v-if="props.shift.type !== ''"
|
||||||
|
name="double_arrow"
|
||||||
|
:color="icon_data.color"
|
||||||
|
size="24px"
|
||||||
|
:style="icon_data.transform"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<!-- punch-out timestamps -->
|
||||||
|
<q-card-section class="q-pa-none col">
|
||||||
|
<q-item-label
|
||||||
|
class="text-weight-bolder text-white q-pa-xs rounded-5"
|
||||||
|
:class="'bg-' + getShiftColor(props.shift.type) + ' text-' + getTextColor(props.shift.type)"
|
||||||
|
style="font-size: 1.5em; line-height: 80% !important;"
|
||||||
|
>
|
||||||
|
{{ props.shift.end_time }}
|
||||||
|
</q-item-label>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<!-- comment and expenses buttons -->
|
||||||
|
<q-card-section
|
||||||
|
class="col q-pa-none text-right"
|
||||||
|
>
|
||||||
|
<!-- chat_bubble_outline or announcement -->
|
||||||
|
<q-btn
|
||||||
|
v-if="props.shift.type !== ''"
|
||||||
|
flat
|
||||||
|
dense
|
||||||
|
color='grey-8'
|
||||||
|
icon="chat_bubble_outline"
|
||||||
|
class="q-pa-none"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- insert_drive_file or request_quote -->
|
||||||
|
<q-btn
|
||||||
|
v-if="props.shift.type !== ''"
|
||||||
|
flat
|
||||||
|
dense
|
||||||
|
color='grey-8'
|
||||||
|
icon="attach_money"
|
||||||
|
class="q-pa-none q-mx-xs"
|
||||||
|
/>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card-section>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import TimesheetApprovalEmployeeDetailsShiftsRow from 'src/modules/timesheet-approval/components/timesheet-approval-employee-details-shifts-row.vue';
|
||||||
|
import TimesheetApprovalEmployeeDetailsShiftsRowHeader from 'src/modules/timesheet-approval/components/timesheet-approval-employee-details-shifts-row-header.vue';
|
||||||
|
import type { PayPeriod } from 'src/modules/shared/types/pay-period-interface';
|
||||||
|
import { default_shift, type Shift } from 'src/modules/timesheets/types/timesheet-shift-interface';
|
||||||
|
import type { PayPeriodEmployeeDetails } from 'src/modules/timesheet-approval/types/timesheet-approval-pay-period-employee-details-interface';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
rawData: PayPeriodEmployeeDetails;
|
||||||
|
currentPayPeriod: PayPeriod;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const shifts_or_placeholder = (shifts: Shift[]): Shift[] => {
|
||||||
|
return shifts.length > 0 ? shifts : [default_shift];
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDate = (shift_date: string): Date => {
|
||||||
|
return new Date(props.currentPayPeriod.pay_year.toString() + '/' + shift_date);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
v-for="week, index in props.rawData"
|
||||||
|
:key="index"
|
||||||
|
class="q-px-xs q-pt-xs rounded-5 col"
|
||||||
|
>
|
||||||
|
<q-card
|
||||||
|
v-for="day, day_index in week.shifts"
|
||||||
|
:key="day_index"
|
||||||
|
flat
|
||||||
|
bordered
|
||||||
|
class="row items-center rounded-10 q-mb-xs"
|
||||||
|
>
|
||||||
|
<q-card-section class="col-auto q-pa-xs text-white">
|
||||||
|
<div
|
||||||
|
class="bg-primary rounded-10 q-pa-xs text-center"
|
||||||
|
:style="$q.screen.lt.md ? '' : 'width: 75px;'"
|
||||||
|
>
|
||||||
|
<q-item-label
|
||||||
|
style="font-size: 0.7em;"
|
||||||
|
class="text-uppercase"
|
||||||
|
>{{ $d(getDate(day.short_date), {weekday: $q.screen.lt.md ? 'short' : 'long'}) }}</q-item-label>
|
||||||
|
<q-item-label
|
||||||
|
class="text-weight-bolder"
|
||||||
|
style="font-size: 2.5em; line-height: 90% !important;"
|
||||||
|
>{{ day.short_date.split('/')[1] }}</q-item-label>
|
||||||
|
<q-item-label
|
||||||
|
style="font-size: 0.7em;"
|
||||||
|
class="text-uppercase"
|
||||||
|
>{{ $d(getDate(day.short_date), {month: $q.screen.lt.md ? 'short' : 'long'}) }}</q-item-label>
|
||||||
|
</div>
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-section class="col q-pa-none">
|
||||||
|
<TimesheetApprovalEmployeeDetailsShiftsRowHeader />
|
||||||
|
<TimesheetApprovalEmployeeDetailsShiftsRow
|
||||||
|
v-for="shift, shift_index in shifts_or_placeholder(day.shifts)"
|
||||||
|
:key="shift_index"
|
||||||
|
:shift="shift"
|
||||||
|
/>
|
||||||
|
</q-card-section>
|
||||||
|
<q-card-section class="q-pr-xs col-auto">
|
||||||
|
<q-btn
|
||||||
|
push
|
||||||
|
color="primary"
|
||||||
|
icon="more_time"
|
||||||
|
class="q-pa-sm"
|
||||||
|
/>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
<script setup lang="ts">
|
|
||||||
import type { PayPeriodEmployeeDetails } from '../types/timesheet-approval-pay-period-employee-details-interface';
|
|
||||||
import TimesheetApprovalEmployeeDetailsHoursWorkedChart from 'src/modules/timesheet-approval/components/graphs/timesheet-approval-employee-details-hours-worked-chart.vue';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
isLoading: boolean;
|
|
||||||
employeeName: string;
|
|
||||||
employeeDetails: PayPeriodEmployeeDetails | undefined;
|
|
||||||
updateKey: number;
|
|
||||||
}>();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<q-card class="q-pa-md bg-white shadow-12">
|
|
||||||
<!-- loader -->
|
|
||||||
<q-card-section
|
|
||||||
v-if="props.isLoading"
|
|
||||||
class="text-center"
|
|
||||||
>
|
|
||||||
<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 name -->
|
|
||||||
<q-card-section v-if="!props.isLoading" class="text-h5 text-weight-bolder text-center full-width text-primary q-pt-none">
|
|
||||||
{{ props.employeeName }}
|
|
||||||
</q-card-section>
|
|
||||||
|
|
||||||
<!-- employee timesheet details -->
|
|
||||||
<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>
|
|
||||||
|
|
@ -52,7 +52,7 @@
|
||||||
dense
|
dense
|
||||||
v-for="(button, index) in card_buttons"
|
v-for="(button, index) in card_buttons"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="q-py-none bg-white q-my-xs"
|
class="q-py-none q-my-xs"
|
||||||
color="primary"
|
color="primary"
|
||||||
:icon="button.icon"
|
:icon="button.icon"
|
||||||
@click="button.onClick"
|
@click="button.onClick"
|
||||||
|
|
@ -60,7 +60,7 @@
|
||||||
<q-tooltip
|
<q-tooltip
|
||||||
anchor="top middle"
|
anchor="top middle"
|
||||||
self="center middle"
|
self="center middle"
|
||||||
class="bg-primary uppercase text-weight-bold"
|
class="bg-primary text-uppercase text-weight-bold"
|
||||||
>
|
>
|
||||||
{{$t(button.label)}}
|
{{$t(button.label)}}
|
||||||
</q-tooltip>
|
</q-tooltip>
|
||||||
|
|
|
||||||
|
|
@ -2,32 +2,27 @@
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
import { computed, onMounted, ref } from 'vue';
|
import { computed, onMounted, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
||||||
import { useTimesheetApprovalApi } from '../composables/use-timesheet-approval-api';
|
import { useTimesheetApprovalApi } from '../composables/use-timesheet-approval-api';
|
||||||
|
|
||||||
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 TimesheetApprovalEmployeeDetails from 'src/modules/timesheet-approval/pages/timesheet-approval-employee-details.vue';
|
||||||
|
|
||||||
import { date, type QTableColumn } from 'quasar';
|
import { date, type QTableColumn } from 'quasar';
|
||||||
import type { PayPeriodOverviewEmployee } from '../types/timesheet-approval-pay-period-overview-employee-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();
|
||||||
const timesheet_approval_api = useTimesheetApprovalApi();
|
const timesheet_approval_api = useTimesheetApprovalApi();
|
||||||
|
|
||||||
const FORWARD = 1
|
const FORWARD = 1
|
||||||
const BACKWARD = -1
|
const BACKWARD = -1
|
||||||
|
|
||||||
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 is_showing_details = ref<boolean>(false);
|
||||||
const report_filter_company = ref<boolean[]>([true, true]);
|
const report_filter_company = ref<boolean[]>([true, true]);
|
||||||
const report_filter_type = ref<boolean[]>([true, true, true, true]);
|
const report_filter_type = ref<boolean[]>([true, true, true, true]);
|
||||||
const clicked_employee_name = ref<string>('');
|
const clicked_employee_name = ref<string>('');
|
||||||
|
const clicked_employee_email = ref<string>('');
|
||||||
const update_key = ref<number>(0);
|
const update_key = ref<number>(0);
|
||||||
|
|
||||||
const columns = computed((): QTableColumn<PayPeriodOverviewEmployee>[] => [
|
const columns = computed((): QTableColumn<PayPeriodOverviewEmployee>[] => [
|
||||||
{
|
{
|
||||||
name: 'employee_name',
|
name: 'employee_name',
|
||||||
|
|
@ -75,25 +70,21 @@
|
||||||
sortable: true
|
sortable: true
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const has_changes = computed(() => {
|
const has_changes = computed(() => {
|
||||||
return timesheet_store.pay_period_overview_employees.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];
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const is_not_enough_filters = computed(() => {
|
const is_not_enough_filters = computed(() => {
|
||||||
return report_filter_company.value.filter(val => val === true).length < 1 ||
|
return report_filter_company.value.filter(val => val === true).length < 1 ||
|
||||||
report_filter_type.value.filter(val => val === true).length < 1;
|
report_filter_type.value.filter(val => val === true).length < 1;
|
||||||
})
|
})
|
||||||
|
|
||||||
const filter_types_labels = [
|
const filter_types_labels = [
|
||||||
t('timeSheetValidations.reportFilterShifts'),
|
t('timeSheetValidations.reportFilterShifts'),
|
||||||
t('timeSheetValidations.reportFilterExpenses'),
|
t('timeSheetValidations.reportFilterExpenses'),
|
||||||
t('timeSheetValidations.reportFilterHoliday'),
|
t('timeSheetValidations.reportFilterHoliday'),
|
||||||
t('timeSheetValidations.reportFilterVacation'),
|
t('timeSheetValidations.reportFilterVacation'),
|
||||||
]
|
]
|
||||||
|
|
||||||
const is_calendar_limit = computed( () => {
|
const is_calendar_limit = computed( () => {
|
||||||
return timesheet_store.current_pay_period.pay_year === 2024 &&
|
return timesheet_store.current_pay_period.pay_year === 2024 &&
|
||||||
timesheet_store.current_pay_period.pay_period_no <= 1;
|
timesheet_store.current_pay_period.pay_period_no <= 1;
|
||||||
|
|
@ -114,13 +105,19 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getEmployeeOverview = (email: string): PayPeriodOverviewEmployee => {
|
||||||
|
return timesheet_approval_api.getPayPeriodOverviewByEmployeeEmail(email);
|
||||||
|
}
|
||||||
|
|
||||||
const onDateSelected = async (date_string: string) => {
|
const onDateSelected = async (date_string: string) => {
|
||||||
await timesheet_approval_api.getPayPeriodOverviewByDate(date_string);
|
await timesheet_approval_api.getPayPeriodOverviewByDate(date_string);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onClickedDetails = async (email: string, name: string) => {
|
const onClickedDetails = async (email: string, name: string) => {
|
||||||
clicked_employee_name.value = name;
|
clicked_employee_name.value = name;
|
||||||
|
clicked_employee_email.value = email;
|
||||||
is_showing_details.value = true;
|
is_showing_details.value = true;
|
||||||
|
|
||||||
await timesheet_approval_api.getTimesheetsByPayPeriodAndEmail(email);
|
await timesheet_approval_api.getTimesheetsByPayPeriodAndEmail(email);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -143,13 +140,16 @@
|
||||||
transition-show="jump-down"
|
transition-show="jump-down"
|
||||||
transition-hide="jump-down"
|
transition-hide="jump-down"
|
||||||
@before-show="() => update_key += 1"
|
@before-show="() => update_key += 1"
|
||||||
|
full-width
|
||||||
|
:full-height="$q.screen.gt.sm"
|
||||||
>
|
>
|
||||||
<TimesheetApprovalEmployeeDetails
|
<TimesheetApprovalEmployeeDetails
|
||||||
:is-loading="timesheet_store.is_loading"
|
:is-loading="timesheet_store.is_loading"
|
||||||
:employee-name="clicked_employee_name"
|
:employee-name="clicked_employee_name"
|
||||||
|
:employee-overview="getEmployeeOverview(clicked_employee_email)"
|
||||||
:employee-details="timesheet_store.pay_period_employee_details"
|
:employee-details="timesheet_store.pay_period_employee_details"
|
||||||
|
:current-pay-period="timesheet_store.current_pay_period"
|
||||||
:update-key="update_key"
|
:update-key="update_key"
|
||||||
class="full-width"
|
|
||||||
/>
|
/>
|
||||||
</q-dialog>
|
</q-dialog>
|
||||||
<div class="q-pa-md">
|
<div class="q-pa-md">
|
||||||
|
|
@ -171,7 +171,7 @@
|
||||||
>
|
>
|
||||||
<!-- Top Bar that contains Search, Title, Filters -->
|
<!-- Top Bar that contains Search, Title, Filters -->
|
||||||
<template v-slot:top>
|
<template v-slot:top>
|
||||||
<div :class="$q.screen.lt.md ? 'column justify-center items-center' : 'full-width row'">
|
<div class="full-width" :class="$q.screen.lt.md ? 'text-center q-gutter-sm' : 'row'">
|
||||||
<!-- Date Picker -->
|
<!-- Date Picker -->
|
||||||
<TimesheetApprovalPeriodPicker
|
<TimesheetApprovalPeriodPicker
|
||||||
:is-disabled="timesheet_store.is_loading"
|
:is-disabled="timesheet_store.is_loading"
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="row">
|
<div class="row justify-center">
|
||||||
<q-btn
|
<q-btn
|
||||||
push rounded
|
push rounded
|
||||||
icon="keyboard_arrow_left"
|
icon="keyboard_arrow_left"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { useTimesheetStore } from "src/stores/timesheet-store";
|
import { useTimesheetStore } from "src/stores/timesheet-store";
|
||||||
import { useAuthStore } from "src/stores/auth-store";
|
import { useAuthStore } from "src/stores/auth-store";
|
||||||
import type { PayPeriodReportFilters } from "../types/timesheet-approval-pay-period-report-interface";
|
import type { PayPeriodReportFilters } from "../types/timesheet-approval-pay-period-report-interface";
|
||||||
|
import { default_pay_period_overview_employee, type PayPeriodOverviewEmployee } from "../types/timesheet-approval-pay-period-overview-employee-interface";
|
||||||
|
|
||||||
export const useTimesheetApprovalApi = () => {
|
export const useTimesheetApprovalApi = () => {
|
||||||
const timesheet_store = useTimesheetStore();
|
const timesheet_store = useTimesheetStore();
|
||||||
|
|
@ -15,6 +16,12 @@ export const useTimesheetApprovalApi = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getPayPeriodOverviewByEmployeeEmail = (email: string): PayPeriodOverviewEmployee => {
|
||||||
|
const employee_overview = timesheet_store.pay_period_overview_employees.find(overview => overview.email === email);
|
||||||
|
if (employee_overview !== undefined) return employee_overview;
|
||||||
|
return default_pay_period_overview_employee;
|
||||||
|
};
|
||||||
|
|
||||||
/* This method attempts to get the next or previous pay period.
|
/* This method attempts to get the next or previous pay period.
|
||||||
It checks if pay period number is within a certain range, adjusts pay period and year accordingly.
|
It checks if pay period number is within a certain range, adjusts pay period and year accordingly.
|
||||||
It then requests the matching pay period object to set as current pay period from server.
|
It then requests the matching pay period object to set as current pay period from server.
|
||||||
|
|
@ -39,11 +46,11 @@ export const useTimesheetApprovalApi = () => {
|
||||||
if (success) {
|
if (success) {
|
||||||
await timesheet_store.getTimesheetApprovalPayPeriodEmployeeOverviews(new_pay_year, new_pay_period_no, auth_store.user.email);
|
await timesheet_store.getTimesheetApprovalPayPeriodEmployeeOverviews(new_pay_year, new_pay_period_no, auth_store.user.email);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const getTimesheetsByPayPeriodAndEmail = async (employee_email: string) => {
|
const getTimesheetsByPayPeriodAndEmail = async (employee_email: string) => {
|
||||||
await timesheet_store.getTimesheetsByPayPeriodAndEmail(employee_email);
|
await timesheet_store.getTimesheetsByPayPeriodAndEmail(employee_email);
|
||||||
}
|
};
|
||||||
|
|
||||||
const getTimesheetApprovalCSVReport = async ( report_filter_company: boolean[], report_filter_type: boolean[] ) => {
|
const getTimesheetApprovalCSVReport = async ( report_filter_company: boolean[], report_filter_type: boolean[] ) => {
|
||||||
const [ targo, solucom ] = report_filter_company;
|
const [ targo, solucom ] = report_filter_company;
|
||||||
|
|
@ -54,11 +61,12 @@ export const useTimesheetApprovalApi = () => {
|
||||||
} as PayPeriodReportFilters;
|
} as PayPeriodReportFilters;
|
||||||
|
|
||||||
await timesheet_store.getTimesheetApprovalCSVReport(options);
|
await timesheet_store.getTimesheetApprovalCSVReport(options);
|
||||||
}
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getPayPeriodOverviewByDate,
|
getPayPeriodOverviewByDate,
|
||||||
getNextPayPeriodOverview,
|
getNextPayPeriodOverview,
|
||||||
|
getPayPeriodOverviewByEmployeeEmail,
|
||||||
getTimesheetsByPayPeriodAndEmail,
|
getTimesheetsByPayPeriodAndEmail,
|
||||||
getTimesheetApprovalCSVReport
|
getTimesheetApprovalCSVReport
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,177 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
/*eslint-disable*/
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import TimesheetApprovalEmployeeDetailsShifts from 'src/modules/timesheet-approval/components/timesheet-approval-employee-details-shifts.vue';
|
||||||
|
import TimesheetApprovalEmployeeDetailsHoursWorkedChart from 'src/modules/timesheet-approval/components/graphs/timesheet-approval-employee-details-hours-worked-chart.vue';
|
||||||
|
import TimesheetApprovalEmployeeDetailsShiftTypesChart from 'src/modules/timesheet-approval/components/graphs/timesheet-approval-employee-details-shift-types-chart.vue';
|
||||||
|
import TimesheetApprovalEmployeeExpensesChart from 'src/modules/timesheet-approval/components/graphs/timesheet-approval-employee-expenses-chart.vue';
|
||||||
|
import type { PayPeriodOverviewEmployee } from 'src/modules/timesheet-approval/types/timesheet-approval-pay-period-overview-employee-interface';
|
||||||
|
import type { PayPeriodEmployeeDetails } from '../types/timesheet-approval-pay-period-employee-details-interface';
|
||||||
|
import { PayPeriod } from 'src/modules/shared/types/pay-period-interface';
|
||||||
|
import { colors } from 'quasar';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
isLoading: boolean;
|
||||||
|
employeeName: string;
|
||||||
|
employeeOverview: PayPeriodOverviewEmployee;
|
||||||
|
employeeDetails: PayPeriodEmployeeDetails;
|
||||||
|
currentPayPeriod: PayPeriod;
|
||||||
|
updateKey: number;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const is_showing_graph = ref<boolean>(true);
|
||||||
|
|
||||||
|
// case 'REGULAR': return 'green-5';
|
||||||
|
// case 'EVENING': return 'green-9';
|
||||||
|
// case 'EMERGENCY': return 'warning';
|
||||||
|
// case 'OVERTIME': return 'negative';
|
||||||
|
// case 'VACATION': return 'purple-10';
|
||||||
|
// case 'HOLIDAY': return 'purple-10';
|
||||||
|
// case 'SICK': return 'grey-9';
|
||||||
|
// default : return 'transparent';
|
||||||
|
|
||||||
|
type shiftColor = {
|
||||||
|
type: string;
|
||||||
|
color: string;
|
||||||
|
text_color?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const shift_type_legend: shiftColor[] = [
|
||||||
|
{
|
||||||
|
type: t('timeSheet.shiftRegular'),
|
||||||
|
color: 'secondary',
|
||||||
|
text_color: 'grey-8',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: t('timeSheet.shiftEvening'),
|
||||||
|
color: 'warning',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: t('timeSheet.shiftEmergency'),
|
||||||
|
color: 'amber-10',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: t('timeSheetValidations.hoursWorkedOvertime'),
|
||||||
|
color: 'negative',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: t('timeSheet.shiftVacation'),
|
||||||
|
color: 'purple-10',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: t('timeSheet.shiftHoliday'),
|
||||||
|
color: 'purple-8',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: t('timeSheet.shiftSick'),
|
||||||
|
color: 'grey-8',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<q-card
|
||||||
|
class="q-pa-sm bg-white shadow-12 rounded-15 column no-wrap relative"
|
||||||
|
:style="$q.screen.gt.sm ? 'width: 70vw !important; height: 90vh !important;' : '' "
|
||||||
|
>
|
||||||
|
<!-- loader -->
|
||||||
|
<q-card-section
|
||||||
|
v-if="props.isLoading"
|
||||||
|
class="absolute-center text-center"
|
||||||
|
>
|
||||||
|
<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 name -->
|
||||||
|
<q-card-section
|
||||||
|
v-if="!props.isLoading"
|
||||||
|
class="text-h5 text-weight-bolder text-center text-primary q-pa-none text-uppercase col-auto"
|
||||||
|
>
|
||||||
|
{{ props.employeeName }}
|
||||||
|
|
||||||
|
<q-separator class="q-mb-sm" color="accent" size="2px" />
|
||||||
|
<q-card-actions align="center" class="q-pa-none">
|
||||||
|
<q-card flat class="bg-secondary rounded-5 q-pa-xs">
|
||||||
|
<q-btn-toggle
|
||||||
|
color="white"
|
||||||
|
text-color="primary"
|
||||||
|
toggle-color="primary"
|
||||||
|
v-model="is_showing_graph"
|
||||||
|
:options="[
|
||||||
|
{icon: 'bar_chart', value: true},
|
||||||
|
{icon: 'edit', value: false},
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
</q-card>
|
||||||
|
</q-card-actions>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<!-- employee timesheet details edit -->
|
||||||
|
<q-card-section
|
||||||
|
v-if="!props.isLoading && !is_showing_graph"
|
||||||
|
class="q-pa-none"
|
||||||
|
>
|
||||||
|
<!-- shift type color legend -->
|
||||||
|
<q-card-section class="q-py-xs q-px-none text-center q-my-s">
|
||||||
|
<q-badge
|
||||||
|
v-for="shift_type in shift_type_legend"
|
||||||
|
:color="shift_type.color"
|
||||||
|
:label="shift_type.type"
|
||||||
|
:text-color="shift_type.text_color || 'white'"
|
||||||
|
class="q-px-md q-py-xs q-mx-xs q-my-none text-uppercase text-weight-bolder justify-center"
|
||||||
|
style="width: 120px; font-size: 0.8em;"
|
||||||
|
/>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<!-- list of shifts, broken down into weekly columns -->
|
||||||
|
<q-card-section
|
||||||
|
:horizontal="$q.screen.gt.sm"
|
||||||
|
class="q-pa-none bg-secondary rounded-10"
|
||||||
|
>
|
||||||
|
<TimesheetApprovalEmployeeDetailsShifts
|
||||||
|
:raw-data="props.employeeDetails"
|
||||||
|
:current-pay-period="props.currentPayPeriod"
|
||||||
|
/>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<!-- employee timesheet details, but look at these graphs -->
|
||||||
|
<q-card-section v-if="!props.isLoading && is_showing_graph" class="q-pa-md col column full-width no-wrap">
|
||||||
|
<q-card-section class="q-pa-none col no-wrap" style="min-height: 300px;">
|
||||||
|
<TimesheetApprovalEmployeeDetailsHoursWorkedChart
|
||||||
|
:raw-data="props.employeeDetails"
|
||||||
|
/>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-separator class="q-ma-sm"/>
|
||||||
|
|
||||||
|
<q-card-section
|
||||||
|
:horizontal="$q.screen.gt.sm"
|
||||||
|
class="justify-center no-wrap col full-width q-pa-none"
|
||||||
|
>
|
||||||
|
<q-card-section class="q-pa-none q-ma-none col-4">
|
||||||
|
<TimesheetApprovalEmployeeDetailsShiftTypesChart
|
||||||
|
:raw-data="props.employeeOverview"
|
||||||
|
/>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-separator :vertical="$q.screen.gt.sm" class="q-ma-md" />
|
||||||
|
|
||||||
|
<q-card-section class="q-pa-none q-ma-none col" :class="$q.screen.lt.md ? 'full-width' : ''">
|
||||||
|
<TimesheetApprovalEmployeeExpensesChart
|
||||||
|
:raw-data="props.employeeDetails"
|
||||||
|
/>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card-section>
|
||||||
|
</q-card>
|
||||||
|
</template>
|
||||||
|
|
@ -34,17 +34,26 @@
|
||||||
padding
|
padding
|
||||||
class="q-pa-md bg-secondary"
|
class="q-pa-md bg-secondary"
|
||||||
>
|
>
|
||||||
<div class="text-h4 row justify-center q-mt-lg text-uppercase text-weight-bolder text-grey-8">
|
<div class="text-h4 row justify-center text-center q-mt-lg text-uppercase text-weight-bolder text-grey-8">
|
||||||
{{ $t('pageTitles.timeSheetValidations') }}
|
{{ $t('pageTitles.timeSheetValidations') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="row items-center justify-center q-py-none q-my-none">
|
<div class="row items-center justify-center q-py-none q-my-none">
|
||||||
<div class="text-primary text-h6 text-uppercase">
|
<div
|
||||||
|
class="text-primary text-uppercase text-weight-bold"
|
||||||
|
:class="$q.screen.lt.md ? '' : 'text-h6'"
|
||||||
|
>
|
||||||
{{ pay_period_label.start_date }}
|
{{ pay_period_label.start_date }}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-grey-8 text-weight-bold text-uppercase q-mx-md">
|
<div
|
||||||
|
class="text-grey-8 text-uppercase q-mx-md"
|
||||||
|
:class="$q.screen.lt.md ? 'text-weight-medium text-caption' : 'text-weight-bold'"
|
||||||
|
>
|
||||||
{{ $t('timeSheet.dateRangesTo') }}
|
{{ $t('timeSheet.dateRangesTo') }}
|
||||||
</div>
|
</div>
|
||||||
<div class="text-primary text-h6 text-uppercase">
|
<div
|
||||||
|
class="text-primary text-uppercase text-center text-weight-bold"
|
||||||
|
:class="$q.screen.lt.md ? '' : 'text-h6'"
|
||||||
|
>
|
||||||
{{ pay_period_label.end_date }}
|
{{ pay_period_label.end_date }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ 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}`);
|
||||||
console.log('all employee data: ', response.data);
|
console.log('pay period data: ', response.data);
|
||||||
return response.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
import type { TimesheetDetailsWeek } from "src/modules/timesheets/types/timesheet-details-interface";
|
import { default_timesheet_details_week, type TimesheetDetailsWeek } from "src/modules/timesheets/types/timesheet-details-interface";
|
||||||
|
|
||||||
export interface PayPeriodEmployeeDetails {
|
export interface PayPeriodEmployeeDetails {
|
||||||
week1: TimesheetDetailsWeek;
|
week1: TimesheetDetailsWeek;
|
||||||
week2: TimesheetDetailsWeek;
|
week2: TimesheetDetailsWeek;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const default_pay_period_employee_details = {
|
||||||
|
week1: default_timesheet_details_week(),
|
||||||
|
week2: default_timesheet_details_week(),
|
||||||
|
}
|
||||||
|
|
@ -9,3 +9,15 @@ export interface PayPeriodOverviewEmployee {
|
||||||
mileage: number;
|
mileage: number;
|
||||||
is_approved: boolean;
|
is_approved: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const default_pay_period_overview_employee: PayPeriodOverviewEmployee = {
|
||||||
|
email: '',
|
||||||
|
employee_name: '',
|
||||||
|
regular_hours: -1,
|
||||||
|
evening_hours: -1,
|
||||||
|
emergency_hours: -1,
|
||||||
|
overtime_hours: -1,
|
||||||
|
expenses: -1,
|
||||||
|
mileage: -1,
|
||||||
|
is_approved: false
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,21 @@ export interface TimesheetDetailsWeek {
|
||||||
expenses: WeekDay<TimesheetDetailsDailyExpenses>;
|
expenses: WeekDay<TimesheetDetailsDailyExpenses>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TimesheetDetailsDailySchedule {
|
||||||
|
shifts: Shift[];
|
||||||
|
regular_hours: number;
|
||||||
|
evening_hours: number;
|
||||||
|
emergency_hours: number;
|
||||||
|
overtime_hours: number;
|
||||||
|
short_date: string; // ex. 08/24
|
||||||
|
break_duration?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Expense {
|
||||||
|
is_approved: boolean;
|
||||||
|
amount: number;
|
||||||
|
};
|
||||||
|
|
||||||
type WeekDay<T> = {
|
type WeekDay<T> = {
|
||||||
sun: T;
|
sun: T;
|
||||||
mon: T;
|
mon: T;
|
||||||
|
|
@ -16,30 +31,47 @@ type WeekDay<T> = {
|
||||||
sat: T;
|
sat: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TimesheetDetailsDailySchedule {
|
|
||||||
shifts: Shift[];
|
|
||||||
regular_hours: number;
|
|
||||||
evening_hours: number;
|
|
||||||
emergency_hours: number;
|
|
||||||
overtime_hours: number;
|
|
||||||
short_date: string; // ex. 08/24
|
|
||||||
break_duration?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TimesheetDetailsDailyExpenses {
|
interface TimesheetDetailsDailyExpenses {
|
||||||
costs: Expense[];
|
cash: Expense[];
|
||||||
mileage: Expense[];
|
km: Expense[];
|
||||||
[otherType: string]: Expense[]; //for possible future types of expenses
|
[otherType: string]: Expense[]; //for possible future types of expenses
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Expense {
|
|
||||||
is_approved: boolean;
|
|
||||||
amount: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
//employee timesheet template
|
//employee timesheet template
|
||||||
export interface EmployeeTimesheetDetailsWeek {
|
export interface EmployeeTimesheetDetailsWeek {
|
||||||
is_approved: boolean;
|
is_approved: boolean;
|
||||||
shifts: WeekDay<TimesheetDetailsDailySchedule>;
|
shifts: WeekDay<TimesheetDetailsDailySchedule>;
|
||||||
expenses: WeekDay<TimesheetDetailsDailyExpenses>;
|
expenses: WeekDay<TimesheetDetailsDailyExpenses>;
|
||||||
}
|
}
|
||||||
|
// empty default builder
|
||||||
|
const makeWeek = <T>(factory: () => T): WeekDay<T> => ({
|
||||||
|
sun: factory(),
|
||||||
|
mon: factory(),
|
||||||
|
tue: factory(),
|
||||||
|
wed: factory(),
|
||||||
|
thu: factory(),
|
||||||
|
fri: factory(),
|
||||||
|
sat: factory(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const emptyDailySchedule = (): TimesheetDetailsDailySchedule => ({
|
||||||
|
shifts: [],
|
||||||
|
regular_hours: 0,
|
||||||
|
evening_hours: 0,
|
||||||
|
emergency_hours: 0,
|
||||||
|
overtime_hours: 0,
|
||||||
|
short_date: "",
|
||||||
|
break_duration: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
const emptyDailyExpenses = (): TimesheetDetailsDailyExpenses => ({
|
||||||
|
cash: [],
|
||||||
|
km: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
export const default_timesheet_details_week = (): TimesheetDetailsWeek => ({
|
||||||
|
is_approved: false,
|
||||||
|
shifts: makeWeek(emptyDailySchedule),
|
||||||
|
expenses: makeWeek(emptyDailyExpenses),
|
||||||
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
export type CreateShiftPayload = {
|
export interface CreateShiftPayload {
|
||||||
date: string;
|
date: string;
|
||||||
type: string;
|
type: string;
|
||||||
start_time: string;
|
start_time: string;
|
||||||
|
|
@ -7,15 +7,26 @@ export type CreateShiftPayload = {
|
||||||
is_remote?: boolean;
|
is_remote?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CreateWeekShiftPayload = {
|
export interface CreateWeekShiftPayload {
|
||||||
shifts: CreateShiftPayload[];
|
shifts: CreateShiftPayload[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Shift = {
|
export interface Shift {
|
||||||
type: string;
|
date : string;
|
||||||
start_time: string;
|
type : string;
|
||||||
end_time: string;
|
start_time : string;
|
||||||
comment: string;
|
end_time : string;
|
||||||
|
comment : string;
|
||||||
is_approved: boolean;
|
is_approved: boolean;
|
||||||
is_remote: boolean;
|
is_remote : boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const default_shift: Shift = {
|
||||||
|
date: '',
|
||||||
|
start_time: '--:--',
|
||||||
|
end_time: '--:--',
|
||||||
|
type: '',
|
||||||
|
comment: '',
|
||||||
|
is_approved: false,
|
||||||
|
is_remote: false,
|
||||||
}
|
}
|
||||||
|
|
@ -4,7 +4,7 @@ import { timesheetApprovalService } from 'src/modules/timesheet-approval/service
|
||||||
import { timesheetTempService } from 'src/modules/timesheets/services/timesheet-services';
|
import { timesheetTempService } from 'src/modules/timesheets/services/timesheet-services';
|
||||||
import type { PayPeriod } from 'src/modules/shared/types/pay-period-interface';
|
import type { PayPeriod } from 'src/modules/shared/types/pay-period-interface';
|
||||||
import type { PayPeriodOverviewEmployee } from "src/modules/timesheet-approval/types/timesheet-approval-pay-period-overview-employee-interface";
|
import type { PayPeriodOverviewEmployee } from "src/modules/timesheet-approval/types/timesheet-approval-pay-period-overview-employee-interface";
|
||||||
import type { PayPeriodEmployeeDetails } from 'src/modules/timesheet-approval/types/timesheet-approval-pay-period-employee-details-interface';
|
import { default_pay_period_employee_details, type PayPeriodEmployeeDetails } from 'src/modules/timesheet-approval/types/timesheet-approval-pay-period-employee-details-interface';
|
||||||
import type { PayPeriodReportFilters } from 'src/modules/timesheet-approval/types/timesheet-approval-pay-period-report-interface';
|
import type { PayPeriodReportFilters } from 'src/modules/timesheet-approval/types/timesheet-approval-pay-period-report-interface';
|
||||||
import type { Timesheet } from 'src/modules/timesheets/types/timesheet-interface';
|
import type { Timesheet } from 'src/modules/timesheets/types/timesheet-interface';
|
||||||
import type { CreateShiftPayload } from 'src/modules/timesheets/types/timesheet-shift-interface';
|
import type { CreateShiftPayload } from 'src/modules/timesheets/types/timesheet-shift-interface';
|
||||||
|
|
@ -33,7 +33,7 @@ export const useTimesheetStore = defineStore('timesheet', () => {
|
||||||
const current_pay_period = ref<PayPeriod>(default_pay_period);
|
const current_pay_period = ref<PayPeriod>(default_pay_period);
|
||||||
const pay_period_overview_employees = ref<PayPeriodOverviewEmployee[]>([]);
|
const pay_period_overview_employees = ref<PayPeriodOverviewEmployee[]>([]);
|
||||||
const pay_period_overview_employee_approval_statuses = ref<{key: string, value: boolean}[] | undefined>();
|
const pay_period_overview_employee_approval_statuses = ref<{key: string, value: boolean}[] | undefined>();
|
||||||
const pay_period_employee_details = ref<PayPeriodEmployeeDetails | undefined>();
|
const pay_period_employee_details = ref<PayPeriodEmployeeDetails>(default_pay_period_employee_details);
|
||||||
const pay_period_report = ref();
|
const pay_period_report = ref();
|
||||||
|
|
||||||
//employee timesheet
|
//employee timesheet
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user