feat(details): add ui elements to shift rows in employee details
This commit is contained in:
parent
5bd19c4a9c
commit
fbf8114666
|
|
@ -342,13 +342,13 @@ export default {
|
|||
reportFilterVacation: 'Vacation',
|
||||
},
|
||||
shiftColumns: {
|
||||
title: 'Shifts',
|
||||
column_1: 'Type',
|
||||
column_2: 'Start time',
|
||||
column_3: 'End time',
|
||||
column_4: 'Comment',
|
||||
column_5: 'Status',
|
||||
column_6: 'Supervisor’s report',
|
||||
title: 'shifts',
|
||||
labelType: 'type',
|
||||
labelIn: 'start',
|
||||
labelOut: 'end',
|
||||
labelComment: 'comment',
|
||||
labelState: 'state',
|
||||
labelSupervisorReport: 'supervisor report',
|
||||
},
|
||||
expenseColumns: {
|
||||
title: 'Expenses',
|
||||
|
|
|
|||
|
|
@ -236,12 +236,12 @@ export default {
|
|||
},
|
||||
shiftColumns: {
|
||||
title: 'Quarts de travail',
|
||||
column_1: 'Type',
|
||||
column_2: 'Entrée',
|
||||
column_3: 'Sortie',
|
||||
column_4: 'Commentaire',
|
||||
column_5: 'État',
|
||||
column_6: 'Rapport du superviseur',
|
||||
labelType: 'type',
|
||||
labelIn: 'entrée',
|
||||
labelOut: 'sortie',
|
||||
labelComment: 'commentaire',
|
||||
labelState: 'état',
|
||||
labelSupervisorReport: 'rapport du superviseur',
|
||||
},
|
||||
shiftsTemplate: {
|
||||
tabTitle1: 'Quarts de travail',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
<template>
|
||||
<!-- This header component is placed in absolute top in order to keep the timestamps
|
||||
below it centered. As such it must imitate the column width of the shift row below it
|
||||
as much as possible, hence the empty q-card-sections. -->
|
||||
<q-card-section
|
||||
horizontal
|
||||
class="text-uppercase text-center items-center q-px-xs"
|
||||
>
|
||||
<!-- Date widget -->
|
||||
<q-card-section class="q-px-xs q-py-none col-auto" style="width: 75px;"></q-card-section>
|
||||
|
||||
<!-- shift row itself -->
|
||||
<q-card-section horizontal class="q-px-xs col">
|
||||
<!-- punch-in timestamps -->
|
||||
<q-card-section class="col q-px-xs q-py-none">
|
||||
<q-item-label class="text-weight-bolder text-primary">
|
||||
{{ $t('shiftColumns.labelIn') }}
|
||||
</q-item-label>
|
||||
</q-card-section>
|
||||
|
||||
<!-- arrows pointing to punch-out timestamps -->
|
||||
<q-card-section class="col-auto q-pa-none q-mx-sm">
|
||||
<q-icon
|
||||
name="double_arrow"
|
||||
color="transparent"
|
||||
size="24px"
|
||||
style="transform: translateX(5px);"
|
||||
/>
|
||||
<q-icon
|
||||
name="double_arrow"
|
||||
color="transparent"
|
||||
size="24px"
|
||||
style="transform: translateX(-5px);"
|
||||
/>
|
||||
</q-card-section>
|
||||
|
||||
<!-- punch-out timestamps -->
|
||||
<q-card-section class="col q-px-xs q-py-none">
|
||||
<q-item-label class="text-weight-bolder text-primary">
|
||||
{{ $t('shiftColumns.labelOut') }}
|
||||
</q-item-label>
|
||||
</q-card-section>
|
||||
|
||||
<!-- shift type badge -->
|
||||
<q-card-section class="col q-pa-none"></q-card-section>
|
||||
|
||||
<!-- comment button -->
|
||||
<q-card-section class="col-auto q-pa-none">
|
||||
<q-btn
|
||||
icon="chat_bubble_outline"
|
||||
color="transparent"
|
||||
flat
|
||||
class="q-pa-sm"
|
||||
/>
|
||||
</q-card-section>
|
||||
</q-card-section>
|
||||
</q-card-section>
|
||||
</template>
|
||||
|
|
@ -1,28 +1,112 @@
|
|||
<script setup lang="ts">
|
||||
import { date } from 'quasar';
|
||||
import { computed } from 'vue';
|
||||
import { default_shift } from 'src/modules/timesheets/types/timesheet-shift-interface';
|
||||
import type { TimesheetDetailsDailySchedule } from 'src/modules/timesheets/types/timesheet-details-interface';
|
||||
|
||||
const props = defineProps<{
|
||||
dayData: TimesheetDetailsDailySchedule;
|
||||
}>();
|
||||
const shifts_or_placeholder = computed(() => {
|
||||
return props.dayData.shifts.length > 0 ? props.dayData.shifts : [default_shift];
|
||||
})
|
||||
|
||||
const getWeekDay = (shift_date: string): string => {
|
||||
const d = date.extractDate(shift_date, 'YYYY/MM/DD');
|
||||
return date.formatDate(d, 'dddd');
|
||||
const getShiftColor = (type: string): string => {
|
||||
switch(type) {
|
||||
case 'REGULAR': return 'primary';
|
||||
case 'EVENING': return 'info';
|
||||
case 'EMERGENCY': return 'teal-14';
|
||||
case 'OVERTIME': return 'negative';
|
||||
case 'VACATION': return 'purple-10';
|
||||
case 'HOLIDAY': return 'indigo-13';
|
||||
case 'SICK': return 'grey-9';
|
||||
default : return 'transparent';
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<q-card>
|
||||
<q-card-section
|
||||
horizontal
|
||||
class="q-pa-xs"
|
||||
>
|
||||
<q-card-section>
|
||||
<div class="bg-primary rounded-10">
|
||||
<span></span>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-card-section
|
||||
horizontal
|
||||
class="q-pa-xs text-uppercase text-center items-center"
|
||||
>
|
||||
<!-- punch-in timestamps -->
|
||||
<q-card-section class="q-pa-none col">
|
||||
<q-item-label
|
||||
v-for="shift, index in props.dayData.shifts"
|
||||
:key="index"
|
||||
class="text-weight-bolder text-grey-8 bg-secondary q-pa-xs rounded-5"
|
||||
style="font-size: 1.75em; line-height: 80% !important;"
|
||||
>
|
||||
{{ shift.start_time }}
|
||||
</q-item-label>
|
||||
<q-item-label v-if="props.dayData.shifts.length === 0"
|
||||
class="text-weight-bolder text-grey-5"
|
||||
style="font-size: 1.75em; line-height: 80% !important;"
|
||||
>
|
||||
---
|
||||
</q-item-label>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
|
||||
<!-- arrows pointing to punch-out timestamps -->
|
||||
<q-card-section
|
||||
horizontal class="items-center justify-center q-ma-sm col-auto">
|
||||
<q-icon
|
||||
name="double_arrow"
|
||||
:color=" props.dayData.shifts.length > 0 ? 'accent' : 'transparent'"
|
||||
size="24px"
|
||||
style="transform: translateX(5px);"
|
||||
/>
|
||||
<q-icon
|
||||
name="double_arrow"
|
||||
:color=" props.dayData.shifts.length > 0 ? 'primary' : 'transparent'"
|
||||
size="24px"
|
||||
style="transform: translateX(-5px);"
|
||||
/>
|
||||
</q-card-section>
|
||||
|
||||
<!-- punch-out timestamps -->
|
||||
<q-card-section class="q-pa-none col">
|
||||
<q-item-label
|
||||
v-for="shift, index in props.dayData.shifts"
|
||||
:key="index"
|
||||
class="text-weight-bolder text-grey-8 bg-secondary q-pa-xs rounded-5"
|
||||
style="font-size: 1.75em; line-height: 80% !important;"
|
||||
>
|
||||
{{ shift.end_time }}
|
||||
</q-item-label>
|
||||
<q-item-label v-if="props.dayData.shifts.length === 0"
|
||||
class="text-weight-bolder text-grey-5"
|
||||
style="font-size: 1.75em; line-height: 80% !important;"
|
||||
>
|
||||
---
|
||||
</q-item-label>
|
||||
</q-card-section>
|
||||
|
||||
<!-- shift type badge -->
|
||||
<q-card-section class="col q-pa-none">
|
||||
<q-badge
|
||||
v-for="shift, index in shifts_or_placeholder"
|
||||
:key="index"
|
||||
:color="shift.type ? getShiftColor(shift.type) : 'transparent'"
|
||||
:label="shift.type || ''"
|
||||
class="text-weight-medium justify-center"
|
||||
style="width: 80px; font-size: 0.8em;"
|
||||
/>
|
||||
</q-card-section>
|
||||
|
||||
<!-- comment button -->
|
||||
<q-card-actions
|
||||
class="col-auto q-pa-none"
|
||||
>
|
||||
<q-btn
|
||||
v-for="(shift, index) in shifts_or_placeholder"
|
||||
:key="index"
|
||||
flat
|
||||
:disable="shift.type === ''"
|
||||
icon="chat_bubble_outline"
|
||||
:color="shift.type === '' ? 'grey-5' : 'grey-8'"
|
||||
class="q-pa-sm"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-card-section>
|
||||
</template>
|
||||
|
|
@ -1,77 +1,57 @@
|
|||
<script setup lang="ts">
|
||||
/*eslint-disable*/
|
||||
import { useI18n } from 'vue-i18n';
|
||||
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 type { PayPeriodEmployeeDetails } from 'src/modules/timesheet-approval/types/timesheet-approval-pay-period-employee-details-interface';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const props = defineProps<{
|
||||
rawData: PayPeriodEmployeeDetails;
|
||||
currentPayPeriod: PayPeriod;
|
||||
}>();
|
||||
|
||||
const weeks = [ props.rawData.week1, props.rawData?.week2 ];
|
||||
const days = weeks.flatMap( week => Object.values(week.shifts) );
|
||||
|
||||
const getShiftColor = (type: string): string => {
|
||||
switch(type) {
|
||||
case 'REGULAR': return 'primary';
|
||||
case 'EVENING': return 'info';
|
||||
case 'EMERGENCY': return 'teal-14';
|
||||
case 'OVERTIME': return 'negative';
|
||||
case 'VACATION': return 'purple-10';
|
||||
case 'HOLIDAY': return 'indigo-13';
|
||||
case 'SICK': return 'grey-9';
|
||||
default : return '';
|
||||
}
|
||||
const getDate = (shift_date: string): Date => {
|
||||
return new Date(props.currentPayPeriod.pay_year.toString() + '/' + shift_date);
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="bg-secondary full-width q-pa-sm rounded-5">
|
||||
<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, index in days"
|
||||
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>
|
||||
<TimesheetApprovalEmployeeDetailsShiftsRowHeader class="absolute-top" />
|
||||
<q-card-section class="col-auto q-pa-xs text-white">
|
||||
<div
|
||||
class="bg-primary rounded-10 q-pa-xs text-center"
|
||||
style="width: 75px;"
|
||||
>
|
||||
<q-item-label
|
||||
style="font-size: 0.8em;"
|
||||
class="text-uppercase"
|
||||
>{{ $d(getDate(day.short_date), {weekday: 'long'}) }}</q-item-label>
|
||||
<q-item-label
|
||||
class="text-weight-bolder"
|
||||
style="font-size: 3em; line-height: 90% !important;"
|
||||
>{{ day.short_date.split('/')[1] }}</q-item-label>
|
||||
<q-item-label
|
||||
style="font-size: 0.8em;"
|
||||
class="text-uppercase"
|
||||
>{{ $d(getDate(day.short_date), {month: 'long'}) }}</q-item-label>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-card-section class="col q-pa-none">
|
||||
<TimesheetApprovalEmployeeDetailsShiftsRow
|
||||
:day-data="day"
|
||||
/>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</div>
|
||||
|
||||
<!-- <q-card-section :horizontal="$q.screen.gt.sm" class="row">
|
||||
<q-card-section v-for="week in props.rawData" class="q-pa-none q-ma-none col">
|
||||
<div v-for="day, index in week.shifts">
|
||||
<div class=" text-primary text-uppercase q-pa-none q-ma-none"> {{ day_labels[index] }} </div>
|
||||
<div v-if="day.shifts.length === 0" class="q-pa-none q-ma-none">---</div>
|
||||
<div v-for="shift in day.shifts">
|
||||
<div class="text-caption row items-center">
|
||||
<div class="col row">
|
||||
{{ shift.start_time }}
|
||||
<q-space />
|
||||
<q-separator vertical :color="getShiftColor(shift.type)"/>
|
||||
</div>
|
||||
<q-separator class="col" :color="getShiftColor(shift.type)"/>
|
||||
<div class="col-auto">
|
||||
<q-badge
|
||||
:color="getShiftColor(shift.type)"
|
||||
class="text-lowercase text-center"
|
||||
style="font-size: 0.8em;"
|
||||
>
|
||||
{{ shift.type }}
|
||||
</q-badge>
|
||||
</div>
|
||||
<q-separator class="col" :color="getShiftColor(shift.type)"/>
|
||||
<div class="col row">
|
||||
<q-separator vertical :color="getShiftColor(shift.type)"/>
|
||||
<q-space />
|
||||
{{ shift.end_time }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</q-card-section>
|
||||
</q-card-section> -->
|
||||
</template>
|
||||
|
|
@ -60,7 +60,7 @@
|
|||
<q-tooltip
|
||||
anchor="top middle"
|
||||
self="center middle"
|
||||
class="bg-primary uppercase text-weight-bold"
|
||||
class="bg-primary text-uppercase text-weight-bold"
|
||||
>
|
||||
{{$t(button.label)}}
|
||||
</q-tooltip>
|
||||
|
|
|
|||
|
|
@ -2,24 +2,19 @@
|
|||
/* eslint-disable */
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import { useTimesheetStore } from 'src/stores/timesheet-store';
|
||||
import { useTimesheetApprovalApi } from '../composables/use-timesheet-approval-api';
|
||||
|
||||
import TimesheetApprovalPeriodPicker from '../components/timesheet-approval-period-picker.vue';
|
||||
import TimesheetApprovalEmployeeOverviewListItem from './timesheet-approval-employee-overview-list-item.vue';
|
||||
import TimesheetApprovalEmployeeDetails from 'src/modules/timesheet-approval/pages/timesheet-approval-employee-details.vue';
|
||||
|
||||
import { date, type QTableColumn } from 'quasar';
|
||||
import type { PayPeriodOverviewEmployee } from '../types/timesheet-approval-pay-period-overview-employee-interface';
|
||||
|
||||
const { t } = useI18n();
|
||||
const timesheet_store = useTimesheetStore();
|
||||
const timesheet_approval_api = useTimesheetApprovalApi();
|
||||
|
||||
const FORWARD = 1
|
||||
const BACKWARD = -1
|
||||
|
||||
const filter = ref<string | number | null>('');
|
||||
const original_approvals = ref<Record<string, boolean>>({});
|
||||
const is_showing_details = ref<boolean>(false);
|
||||
|
|
@ -28,7 +23,6 @@
|
|||
const clicked_employee_name = ref<string>('');
|
||||
const clicked_employee_email = ref<string>('');
|
||||
const update_key = ref<number>(0);
|
||||
|
||||
const columns = computed((): QTableColumn<PayPeriodOverviewEmployee>[] => [
|
||||
{
|
||||
name: 'employee_name',
|
||||
|
|
@ -76,25 +70,21 @@
|
|||
sortable: true
|
||||
}
|
||||
]);
|
||||
|
||||
const has_changes = computed(() => {
|
||||
return timesheet_store.pay_period_overview_employees.some(emp => {
|
||||
return emp.is_approved !== original_approvals.value[emp.email];
|
||||
});
|
||||
});
|
||||
|
||||
const is_not_enough_filters = computed(() => {
|
||||
return report_filter_company.value.filter(val => val === true).length < 1 ||
|
||||
report_filter_type.value.filter(val => val === true).length < 1;
|
||||
})
|
||||
|
||||
const filter_types_labels = [
|
||||
t('timeSheetValidations.reportFilterShifts'),
|
||||
t('timeSheetValidations.reportFilterExpenses'),
|
||||
t('timeSheetValidations.reportFilterHoliday'),
|
||||
t('timeSheetValidations.reportFilterVacation'),
|
||||
]
|
||||
|
||||
const is_calendar_limit = computed( () => {
|
||||
return timesheet_store.current_pay_period.pay_year === 2024 &&
|
||||
timesheet_store.current_pay_period.pay_period_no <= 1;
|
||||
|
|
@ -150,7 +140,7 @@
|
|||
transition-show="jump-down"
|
||||
transition-hide="jump-down"
|
||||
@before-show="() => update_key += 1"
|
||||
:full-width="$q.screen.gt.sm"
|
||||
full-width
|
||||
:full-height="$q.screen.gt.sm"
|
||||
>
|
||||
<TimesheetApprovalEmployeeDetails
|
||||
|
|
@ -158,6 +148,7 @@
|
|||
:employee-name="clicked_employee_name"
|
||||
:employee-overview="getEmployeeOverview(clicked_employee_email)"
|
||||
:employee-details="timesheet_store.pay_period_employee_details"
|
||||
:current-pay-period="timesheet_store.current_pay_period"
|
||||
:update-key="update_key"
|
||||
/>
|
||||
</q-dialog>
|
||||
|
|
|
|||
|
|
@ -8,12 +8,14 @@
|
|||
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';
|
||||
|
||||
const props = defineProps<{
|
||||
isLoading: boolean;
|
||||
employeeName: string;
|
||||
employeeOverview: PayPeriodOverviewEmployee;
|
||||
employeeDetails: PayPeriodEmployeeDetails;
|
||||
currentPayPeriod: PayPeriod;
|
||||
updateKey: number;
|
||||
}>();
|
||||
|
||||
|
|
@ -23,7 +25,7 @@
|
|||
|
||||
<template>
|
||||
<q-card
|
||||
class="q-pa-md bg-white shadow-12 rounded-15 column no-wrap relative"
|
||||
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 -->
|
||||
|
|
@ -58,7 +60,7 @@
|
|||
v-model="is_showing_graph"
|
||||
:options="[
|
||||
{icon: 'bar_chart', value: true},
|
||||
{icon: 'mode_edit_outline', value: false},
|
||||
{icon: 'edit', value: false},
|
||||
]"
|
||||
/>
|
||||
</q-card>
|
||||
|
|
@ -66,9 +68,14 @@
|
|||
</q-card-section>
|
||||
|
||||
<!-- employee timesheet details edit -->
|
||||
<q-card-section v-if="!props.isLoading && !is_showing_graph">
|
||||
<q-card-section
|
||||
v-if="!props.isLoading && !is_showing_graph"
|
||||
: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>
|
||||
|
||||
|
|
|
|||
|
|
@ -5,3 +5,11 @@ export interface Shift {
|
|||
type : string;
|
||||
is_approved : boolean;
|
||||
}
|
||||
|
||||
export const default_shift: Shift = {
|
||||
date: '',
|
||||
start_time: '',
|
||||
end_time: '',
|
||||
type: '',
|
||||
is_approved: false,
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user