feat(shift): start to add logic to lock timestamp entry when selecting certain shift types

This commit is contained in:
Nic D 2026-02-18 16:12:51 -05:00
parent b09057a6be
commit 6368beb24d
4 changed files with 97 additions and 38 deletions

View File

@ -6,15 +6,29 @@
import { computed, inject, onMounted, ref } from 'vue';
import { QSelect, QInput, useQuasar, type QSelectProps, QPopupProxy } from 'quasar';
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 { 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 { errorMessage = undefined, isTimesheetApproved = false, holiday = false } = defineProps<{
const {
errorMessage = undefined,
isTimesheetApproved = false,
holiday = false,
expectedDailyHours = 8,
dailyHours,
} = defineProps<{
dailyHours: TotalHours;
expectedDailyHours?: number;
isTimesheetApproved?: boolean;
errorMessage?: string | undefined;
holiday?: boolean | undefined;
@ -39,7 +53,10 @@
const selectRef = ref<QSelect | null>(null);
const shiftErrorMessage = ref<string | undefined>();
const is_showing_delete_confirm = ref(false);
const isShowingPredefinedTime = ref(false);
const popupProxyRef = ref<QPopupProxy | null>(null);
const predefinedHours = ref(0);
const predefinedHoursBgColor = ref('');
// ================== Computed ==================
@ -128,6 +145,28 @@
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(() => {
if (ui_store.focus_next_component) {
selectRef.value?.focus();
@ -206,7 +245,7 @@
v-model="shiftTypeSelected"
v-bind="shiftTypeSelectProps"
@blur="onBlurShiftTypeSelect"
@update:model-value="option => shift.type = option.value"
@update:model-value="onShiftTypeChange"
>
<template #selected-item="scope">
<div
@ -291,8 +330,25 @@
</q-select>
</div>
<div class="col row items-start text-uppercase rounded-5 q-pa-xs">
<!-- punch in field -->
<div class="col row">
<!-- If shift type has predefined timestamps -->
<div
v-if="isShowingPredefinedTime"
class="col row q-px-sm relative-position flex-center"
>
<div
class="absolute-full rounded-5 q-mx-sm"
:class="predefinedHoursBgColor"
style="opacity: 0.3;"
></div>
<span class="col text-center text-uppercase text-h6 text-bold">{{ getHoursMinutesStringFromHoursFloat(predefinedHours) }}</span>
</div>
<!-- Else show input fields for in-out timestamps -->
<div
v-else
class="col row items-start text-uppercase rounded-5 q-pa-xs"
>
<q-input
ref="start_time"
v-model="shift.start_time"
@ -325,6 +381,7 @@
>{{ $t('shared.misc.out') }}</span>
</template>
</q-input>
</div>
<div
class="row full-height"

View File

@ -116,6 +116,7 @@
v-else
v-model:shift="day.shifts[shift_index]!"
:holiday="holiday"
:daily-hours="day.daily_hours"
:is-timesheet-approved="approved"
:error-message="shift_error_message"
@request-delete="deleteCurrentShift(shift)"

View File

@ -1,3 +1,5 @@
import type { QSelectOption } from "quasar";
export const SHIFT_TYPES: ShiftType[] = [
'REGULAR',
'EVENING',
@ -39,7 +41,7 @@ export class Shift {
}
}
export interface ShiftOption {
export interface ShiftOption extends QSelectOption {
label: string;
value: ShiftType;
icon: string;

View File

@ -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 { RouteRecordNameGeneric } from 'vue-router';
export const useTimesheetStore = defineStore('timesheet', () => {
const { t } = useI18n();
const is_loading = ref<boolean>(false);