From f8f708a66429834985de906209793550149fe672 Mon Sep 17 00:00:00 2001 From: Gregor Vostrak Date: Tue, 21 Oct 2025 17:10:13 +0200 Subject: [PATCH] add set end time functionality to timetracker component --- .../Dashboard/TeamActivityCardEntry.vue | 3 +- resources/js/Components/TimeTracker.vue | 9 +++- .../ui/src/Input/TimePickerSimple.vue | 1 + .../ui/src/Input/TimeRangeSelector.vue | 45 +++++++++++++++---- .../src/TimeTracker/TimeTrackerControls.vue | 2 + .../TimeTracker/TimeTrackerRangeSelector.vue | 17 ++++++- resources/js/utils/useCurrentTimeEntry.ts | 10 ++++- 7 files changed, 72 insertions(+), 15 deletions(-) diff --git a/resources/js/Components/Dashboard/TeamActivityCardEntry.vue b/resources/js/Components/Dashboard/TeamActivityCardEntry.vue index d3c72374..85fc0acf 100644 --- a/resources/js/Components/Dashboard/TeamActivityCardEntry.vue +++ b/resources/js/Components/Dashboard/TeamActivityCardEntry.vue @@ -10,7 +10,8 @@ defineProps<{
-

+

{{ name }}

diff --git a/resources/js/Components/TimeTracker.vue b/resources/js/Components/TimeTracker.vue index 0aec12df..8acd7573 100644 --- a/resources/js/Components/TimeTracker.vue +++ b/resources/js/Components/TimeTracker.vue @@ -117,6 +117,12 @@ async function createTimeEntry(timeEntry: Omit showManualTimeEntryModal.value = false; } +async function createTimeEntryFromCurrentEntry() { + const { start, end, description, project_id, task_id, billable, tags } = currentTimeEntry.value; + await createTimeEntry({ start, end, description, project_id, task_id, billable, tags }); + currentTimeEntryStore.$reset(); +} + const { handleApiRequestNotifications } = useNotificationsStore(); const queryClient = useQueryClient(); @@ -195,7 +201,8 @@ const { tags } = storeToRefs(useTagsStore()); @stop-live-timer="stopLiveTimer" @start-timer="setActiveState(true)" @stop-timer="setActiveState(false)" - @update-time-entry="updateTimeEntry"> + @update-time-entry="updateTimeEntry" + @create-time-entry="createTimeEntryFromCurrentEntry">
import { defineProps, nextTick, ref, watch } from 'vue'; -import { useFocusWithin } from '@vueuse/core'; import DatePicker from '@/packages/ui/src/Input/DatePicker.vue'; import { getDayJsInstance, getLocalizedDayJs } from '@/packages/ui/src/utils/time'; import dayjs from 'dayjs'; import TimePickerSimple from '@/packages/ui/src/Input/TimePickerSimple.vue'; +import { Button } from '@/Components/ui/button'; const props = defineProps<{ start: string; @@ -17,31 +17,42 @@ const emit = defineEmits(['changed', 'close']); const tempStart = ref(props.start ? getLocalizedDayJs(props.start).format() : dayjs().format()); const tempEnd = ref(props.end ? getLocalizedDayJs(props.end).format() : null); +const showEndTimePicker = ref(false); watch(props, () => { tempStart.value = getLocalizedDayJs(props.start).format(); tempEnd.value = props.end ? getLocalizedDayJs(props.end).format() : null; + showEndTimePicker.value = false; }); + function updateTimeEntry() { const tempStartUtc = getDayJsInstance()(tempStart.value).utc().format(); const tempEndUtc = tempEnd.value ? getDayJsInstance()(tempEnd.value).utc().format() : null; + if (tempStartUtc !== props.start || tempEndUtc !== props.end) { emit( 'changed', getDayJsInstance()(tempStart.value).utc().format(), - getDayJsInstance()(tempEnd.value).utc().format() + tempEnd.value ? getDayJsInstance()(tempEnd.value).utc().format() : null ); } } -const dropdownContent = ref(); -const { focused } = useFocusWithin(dropdownContent); +function setEndTime() { + showEndTimePicker.value = true; + tempEnd.value = getDayJsInstance()().format(); +} -watch(focused, (newValue, oldValue) => { - if (oldValue === true && newValue === false) { +function confirmEndTime() { + // wait for the v-model for the end time to update + nextTick(() => { updateTimeEntry(); - } -}); + showEndTimePicker.value = false; + emit('close'); + }); +} + +const dropdownContent = ref();