Merge branch 'main' of git.targo.ca:Targo/targo_frontend into dev/matthieu/timesheet-form

This commit is contained in:
Matthieu Haineault 2025-09-08 16:25:41 -04:00
commit 7bc9b45ef0
25 changed files with 784 additions and 197 deletions

View File

@ -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;

View File

@ -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: 'Supervisors 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',

View File

@ -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 ninteragissez pas avec lécran.', message_end: 'secondes si vous ninteragissez 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 dheures à banquer', shiftBankedHours: 'Totale dheures à banquer',

View File

@ -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>

View File

@ -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>

View File

@ -1,61 +1,61 @@
<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';
import type { 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 { 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 {
@ -63,30 +63,37 @@
datasets: hours_worked_dataset.value, datasets: hours_worked_dataset.value,
}; };
}; };
</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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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"

View File

@ -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"

View File

@ -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
} }

View File

@ -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>

View File

@ -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>

View File

@ -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;
}, },

View File

@ -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(),
}

View File

@ -8,4 +8,16 @@ export interface PayPeriodOverviewEmployee {
expenses: number; expenses: number;
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
}

View File

@ -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),
});

View File

@ -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,
}

View File

@ -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

View File

@ -13,4 +13,4 @@ export const getCurrentPayPeriod = (today = new Date()): number => {
console.log(current_period); console.log(current_period);
return current_period; return current_period;
} }