diff --git a/app/src/plugins/tm@modal/task/_components/employees/a-employee-timeblock-header.vue b/app/src/plugins/tm@modal/task/_components/employees/a-employee-timeblock-header.vue index 2a08bcb..2eccda9 100644 --- a/app/src/plugins/tm@modal/task/_components/employees/a-employee-timeblock-header.vue +++ b/app/src/plugins/tm@modal/task/_components/employees/a-employee-timeblock-header.vue @@ -117,7 +117,9 @@ class="timeblock__time-overview__label timeblock__time-overview__label--mobile" >Vol. čas: - {{ freeTime }}h + {{ freeTime }}h

diff --git a/app/src/plugins/tm@modal/task/_components/employees/a-employee-timeblock-timeline.vue b/app/src/plugins/tm@modal/task/_components/employees/a-employee-timeblock-timeline.vue index 7eea973..43aa3fb 100644 --- a/app/src/plugins/tm@modal/task/_components/employees/a-employee-timeblock-timeline.vue +++ b/app/src/plugins/tm@modal/task/_components/employees/a-employee-timeblock-timeline.vue @@ -398,16 +398,32 @@ const handleMouseMove = (event: MouseEvent) => { // Convert to time and snap const rawTime = positionToTime(x); const snappedStart = snapToInterval(rawTime); - const snappedEnd = moment(snappedStart).add(1, 'hour').toDate(); - // Only show preview within work hours + // Calculate default end time (1 hour later) + let snappedEnd = moment(snappedStart).add(1, 'hour').toDate(); + + // Only show preview if start is within work hours const startHour = snappedStart.getHours() + snappedStart.getMinutes() / 60; - const endHour = snappedEnd.getHours() + snappedEnd.getMinutes() / 60; if ( startHour >= props.employee.work_start && - endHour <= props.employee.work_end + startHour < props.employee.work_end ) { + // If the end would exceed work hours, cap it at work_end + const endHour = snappedEnd.getHours() + snappedEnd.getMinutes() / 60; + + if (endHour > props.employee.work_end) { + // Create end time at exactly work_end + snappedEnd = moment(snappedStart) + .set({ + hour: Math.floor(props.employee.work_end), + minute: (props.employee.work_end % 1) * 60, + second: 0, + millisecond: 0, + }) + .toDate(); + } + showPreview.value = true; previewBlock.value = { start: snappedStart, @@ -451,19 +467,47 @@ const handleStretchMove = (event: MouseEvent) => { const x = event.clientX - rect.left + timelineScroll.value.scrollLeft; const currentTime = positionToTime(x); - const snappedTime = snapToInterval(currentTime); + let snappedTime = snapToInterval(currentTime); const initialStartTime = dragState.value.initialStart.getTime(); const snappedTimeValue = snappedTime.getTime(); if (snappedTimeValue > initialStartTime) { // Stretching right (extending end) + // Cap at work_end + const snappedEndHour = + snappedTime.getHours() + snappedTime.getMinutes() / 60; + if (snappedEndHour > props.employee.work_end) { + snappedTime = moment(snappedTime) + .set({ + hour: Math.floor(props.employee.work_end), + minute: (props.employee.work_end % 1) * 60, + second: 0, + millisecond: 0, + }) + .toDate(); + } + previewBlock.value = { start: dragState.value.initialStart, end: snappedTime, }; } else { // Stretching left (extending start) + // Cap at work_start + const snappedStartHour = + snappedTime.getHours() + snappedTime.getMinutes() / 60; + if (snappedStartHour < props.employee.work_start) { + snappedTime = moment(snappedTime) + .set({ + hour: Math.floor(props.employee.work_start), + minute: (props.employee.work_start % 1) * 60, + second: 0, + millisecond: 0, + }) + .toDate(); + } + previewBlock.value = { start: snappedTime, end: dragState.value.initialStart, @@ -519,10 +563,24 @@ const handleResizeCurrentMove = (event: MouseEvent) => { const x = event.clientX - rect.left + timelineScroll.value.scrollLeft; const currentTime = positionToTime(x); - const snappedTime = snapToInterval(currentTime); + let snappedTime = snapToInterval(currentTime); if (dragState.value.resizeEdge === 'left') { // Resizing left edge (changing start time) + // Cap at work_start + const snappedStartHour = + snappedTime.getHours() + snappedTime.getMinutes() / 60; + if (snappedStartHour < props.employee.work_start) { + snappedTime = moment(snappedTime) + .set({ + hour: Math.floor(props.employee.work_start), + minute: (props.employee.work_start % 1) * 60, + second: 0, + millisecond: 0, + }) + .toDate(); + } + // Make sure new start is before end if (snappedTime < dragState.value.initialEnd) { resizedCurrentBlock.value = { @@ -532,6 +590,20 @@ const handleResizeCurrentMove = (event: MouseEvent) => { } } else if (dragState.value.resizeEdge === 'right') { // Resizing right edge (changing end time) + // Cap at work_end + const snappedEndHour = + snappedTime.getHours() + snappedTime.getMinutes() / 60; + if (snappedEndHour > props.employee.work_end) { + snappedTime = moment(snappedTime) + .set({ + hour: Math.floor(props.employee.work_end), + minute: (props.employee.work_end % 1) * 60, + second: 0, + millisecond: 0, + }) + .toDate(); + } + // Make sure new end is after start if (snappedTime > dragState.value.initialStart) { resizedCurrentBlock.value = { diff --git a/app/src/plugins/tm@modal/task/_components/employees/a-employee-timeblock.vue b/app/src/plugins/tm@modal/task/_components/employees/a-employee-timeblock.vue index 191f4a4..182b5d9 100644 --- a/app/src/plugins/tm@modal/task/_components/employees/a-employee-timeblock.vue +++ b/app/src/plugins/tm@modal/task/_components/employees/a-employee-timeblock.vue @@ -426,6 +426,34 @@ const validate = async () => { defineExpose({ validate, }); + +watch( + () => props.modelValue.ends_at_time, + () => { + if (v$.value.ends_at_time.$model !== props.modelValue.ends_at_time) { + v$.value.ends_at_time.$model = props.modelValue.ends_at_time; + } + }, +); + +watch( + () => props.modelValue.starts_at_time, + () => { + if (v$.value.starts_at_time.$model !== props.modelValue.starts_at_time) { + v$.value.starts_at_time.$model = props.modelValue.starts_at_time; + console.log('starts_at_time changed', v$.value.starts_at_time.$model); + } + }, +); + +watch( + () => props.modelValue.date, + () => { + if (v$.value.date.$model !== props.modelValue.date) { + v$.value.date.$model = props.modelValue.date; + } + }, +);