feat(shift): start to add logic to lock timestamp entry when selecting certain shift types
This commit is contained in:
parent
b09057a6be
commit
6368beb24d
|
|
@ -6,15 +6,29 @@
|
||||||
import { computed, inject, onMounted, ref } from 'vue';
|
import { computed, inject, onMounted, ref } from 'vue';
|
||||||
import { QSelect, QInput, useQuasar, type QSelectProps, QPopupProxy } from 'quasar';
|
import { QSelect, QInput, useQuasar, type QSelectProps, QPopupProxy } from 'quasar';
|
||||||
import { useUiStore } from 'src/stores/ui-store';
|
import { useUiStore } from 'src/stores/ui-store';
|
||||||
import { SHIFT_OPTIONS } from 'src/modules/timesheets/utils/shift.util';
|
|
||||||
import type { Shift } from 'src/modules/timesheets/models/shift.models';
|
|
||||||
import { useAuthStore } from 'src/stores/auth-store';
|
import { useAuthStore } from 'src/stores/auth-store';
|
||||||
|
import { SHIFT_OPTIONS } from 'src/modules/timesheets/utils/shift.util';
|
||||||
|
import type { TotalHours } from 'src/modules/timesheets/models/timesheet.models';
|
||||||
|
import type { Shift, ShiftOption, ShiftType } from 'src/modules/timesheets/models/shift.models';
|
||||||
|
import { getHoursMinutesStringFromHoursFloat } from 'src/utils/date-and-time-utils';
|
||||||
|
|
||||||
// ================== State ==================
|
// ========== Constants ========================================
|
||||||
|
|
||||||
|
const SHIFT_TYPES_WITH_PREDEFINED_TIMES: ShiftType[] = ['HOLIDAY', 'SICK', 'VACATION'];
|
||||||
|
|
||||||
|
// ========== State ========================================
|
||||||
|
|
||||||
const shift = defineModel<Shift>('shift', { required: true });
|
const shift = defineModel<Shift>('shift', { required: true });
|
||||||
|
|
||||||
const { errorMessage = undefined, isTimesheetApproved = false, holiday = false } = defineProps<{
|
const {
|
||||||
|
errorMessage = undefined,
|
||||||
|
isTimesheetApproved = false,
|
||||||
|
holiday = false,
|
||||||
|
expectedDailyHours = 8,
|
||||||
|
dailyHours,
|
||||||
|
} = defineProps<{
|
||||||
|
dailyHours: TotalHours;
|
||||||
|
expectedDailyHours?: number;
|
||||||
isTimesheetApproved?: boolean;
|
isTimesheetApproved?: boolean;
|
||||||
errorMessage?: string | undefined;
|
errorMessage?: string | undefined;
|
||||||
holiday?: boolean | undefined;
|
holiday?: boolean | undefined;
|
||||||
|
|
@ -39,7 +53,10 @@
|
||||||
const selectRef = ref<QSelect | null>(null);
|
const selectRef = ref<QSelect | null>(null);
|
||||||
const shiftErrorMessage = ref<string | undefined>();
|
const shiftErrorMessage = ref<string | undefined>();
|
||||||
const is_showing_delete_confirm = ref(false);
|
const is_showing_delete_confirm = ref(false);
|
||||||
|
const isShowingPredefinedTime = ref(false);
|
||||||
const popupProxyRef = ref<QPopupProxy | null>(null);
|
const popupProxyRef = ref<QPopupProxy | null>(null);
|
||||||
|
const predefinedHours = ref(0);
|
||||||
|
const predefinedHoursBgColor = ref('');
|
||||||
|
|
||||||
// ================== Computed ==================
|
// ================== Computed ==================
|
||||||
|
|
||||||
|
|
@ -128,6 +145,28 @@
|
||||||
popupProxyRef.value.hide();
|
popupProxyRef.value.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onShiftTypeChange = (option: ShiftOption) => {
|
||||||
|
shift.value.type = option.value;
|
||||||
|
|
||||||
|
if (SHIFT_TYPES_WITH_PREDEFINED_TIMES.includes(option.value)) {
|
||||||
|
isShowingPredefinedTime.value = true;
|
||||||
|
predefinedHoursBgColor.value = `bg-${option.icon_color}`;
|
||||||
|
|
||||||
|
if (option.value === 'SICK') {
|
||||||
|
const workedHours =
|
||||||
|
dailyHours.regular +
|
||||||
|
dailyHours.emergency +
|
||||||
|
dailyHours.evening +
|
||||||
|
dailyHours.holiday +
|
||||||
|
dailyHours.sick +
|
||||||
|
dailyHours.vacation;
|
||||||
|
predefinedHours.value = Math.max(expectedDailyHours - workedHours, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
isShowingPredefinedTime.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (ui_store.focus_next_component) {
|
if (ui_store.focus_next_component) {
|
||||||
selectRef.value?.focus();
|
selectRef.value?.focus();
|
||||||
|
|
@ -206,7 +245,7 @@
|
||||||
v-model="shiftTypeSelected"
|
v-model="shiftTypeSelected"
|
||||||
v-bind="shiftTypeSelectProps"
|
v-bind="shiftTypeSelectProps"
|
||||||
@blur="onBlurShiftTypeSelect"
|
@blur="onBlurShiftTypeSelect"
|
||||||
@update:model-value="option => shift.type = option.value"
|
@update:model-value="onShiftTypeChange"
|
||||||
>
|
>
|
||||||
<template #selected-item="scope">
|
<template #selected-item="scope">
|
||||||
<div
|
<div
|
||||||
|
|
@ -291,40 +330,58 @@
|
||||||
</q-select>
|
</q-select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col row items-start text-uppercase rounded-5 q-pa-xs">
|
<div class="col row">
|
||||||
<!-- punch in field -->
|
<!-- If shift type has predefined timestamps -->
|
||||||
<q-input
|
<div
|
||||||
ref="start_time"
|
v-if="isShowingPredefinedTime"
|
||||||
v-model="shift.start_time"
|
class="col row q-px-sm relative-position flex-center"
|
||||||
v-bind="timeInputProps"
|
|
||||||
type="time"
|
|
||||||
@blur="onTimeFieldBlur(shift.start_time)"
|
|
||||||
>
|
>
|
||||||
<template #label>
|
<div
|
||||||
<span
|
class="absolute-full rounded-5 q-mx-sm"
|
||||||
class="text-weight-bolder"
|
:class="predefinedHoursBgColor"
|
||||||
:class="shift.is_approved ? ' q-ml-md' : ''"
|
style="opacity: 0.3;"
|
||||||
style="font-size: 0.95em;"
|
></div>
|
||||||
>{{ $t('shared.misc.in') }}</span>
|
<span class="col text-center text-uppercase text-h6 text-bold">{{ getHoursMinutesStringFromHoursFloat(predefinedHours) }}</span>
|
||||||
</template>
|
</div>
|
||||||
</q-input>
|
|
||||||
|
|
||||||
<!-- punch out field -->
|
<!-- Else show input fields for in-out timestamps -->
|
||||||
<q-input
|
<div
|
||||||
ref="end_time"
|
v-else
|
||||||
v-model="shift.end_time"
|
class="col row items-start text-uppercase rounded-5 q-pa-xs"
|
||||||
v-bind="timeInputProps"
|
|
||||||
type="time"
|
|
||||||
@blur="onTimeFieldBlur(shift.end_time)"
|
|
||||||
>
|
>
|
||||||
<template #label>
|
<q-input
|
||||||
<span
|
ref="start_time"
|
||||||
class="text-weight-bolder"
|
v-model="shift.start_time"
|
||||||
:class="shift.is_approved ? ' q-ml-md' : ''"
|
v-bind="timeInputProps"
|
||||||
style="font-size: 0.95em;"
|
type="time"
|
||||||
>{{ $t('shared.misc.out') }}</span>
|
@blur="onTimeFieldBlur(shift.start_time)"
|
||||||
</template>
|
>
|
||||||
</q-input>
|
<template #label>
|
||||||
|
<span
|
||||||
|
class="text-weight-bolder"
|
||||||
|
:class="shift.is_approved ? ' q-ml-md' : ''"
|
||||||
|
style="font-size: 0.95em;"
|
||||||
|
>{{ $t('shared.misc.in') }}</span>
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
|
||||||
|
<!-- punch out field -->
|
||||||
|
<q-input
|
||||||
|
ref="end_time"
|
||||||
|
v-model="shift.end_time"
|
||||||
|
v-bind="timeInputProps"
|
||||||
|
type="time"
|
||||||
|
@blur="onTimeFieldBlur(shift.end_time)"
|
||||||
|
>
|
||||||
|
<template #label>
|
||||||
|
<span
|
||||||
|
class="text-weight-bolder"
|
||||||
|
:class="shift.is_approved ? ' q-ml-md' : ''"
|
||||||
|
style="font-size: 0.95em;"
|
||||||
|
>{{ $t('shared.misc.out') }}</span>
|
||||||
|
</template>
|
||||||
|
</q-input>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="row full-height"
|
class="row full-height"
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,7 @@
|
||||||
v-else
|
v-else
|
||||||
v-model:shift="day.shifts[shift_index]!"
|
v-model:shift="day.shifts[shift_index]!"
|
||||||
:holiday="holiday"
|
:holiday="holiday"
|
||||||
|
:daily-hours="day.daily_hours"
|
||||||
:is-timesheet-approved="approved"
|
:is-timesheet-approved="approved"
|
||||||
:error-message="shift_error_message"
|
:error-message="shift_error_message"
|
||||||
@request-delete="deleteCurrentShift(shift)"
|
@request-delete="deleteCurrentShift(shift)"
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import type { QSelectOption } from "quasar";
|
||||||
|
|
||||||
export const SHIFT_TYPES: ShiftType[] = [
|
export const SHIFT_TYPES: ShiftType[] = [
|
||||||
'REGULAR',
|
'REGULAR',
|
||||||
'EVENING',
|
'EVENING',
|
||||||
|
|
@ -39,7 +41,7 @@ export class Shift {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ShiftOption {
|
export interface ShiftOption extends QSelectOption {
|
||||||
label: string;
|
label: string;
|
||||||
value: ShiftType;
|
value: ShiftType;
|
||||||
icon: string;
|
icon: string;
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ import { type FederalHoliday, TARGO_HOLIDAY_NAMES_FR } from 'src/modules/timeshe
|
||||||
import type { RouteNames } from 'src/router/router-constants';
|
import type { RouteNames } from 'src/router/router-constants';
|
||||||
import type { RouteRecordNameGeneric } from 'vue-router';
|
import type { RouteRecordNameGeneric } from 'vue-router';
|
||||||
|
|
||||||
|
|
||||||
export const useTimesheetStore = defineStore('timesheet', () => {
|
export const useTimesheetStore = defineStore('timesheet', () => {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const is_loading = ref<boolean>(false);
|
const is_loading = ref<boolean>(false);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user