add date selector to time entries, fixes ST-134

This commit is contained in:
Gregor Vostrak
2024-06-05 15:41:56 +02:00
parent 2692db2a86
commit b1795392ad
6 changed files with 56 additions and 28 deletions

View File

@@ -183,7 +183,7 @@ test('test that adding a new tag to an existing time entry works', async ({
}); });
// Test that Start / End Time Update Works // Test that Start / End Time Update Works
test('test that updating a the start of an existing time entry in the overview works on blur', async ({ test('test that updating a the start of an existing time entry in the overview works on enter', async ({
page, page,
}) => { }) => {
await goToTimeOverview(page); await goToTimeOverview(page);
@@ -220,7 +220,7 @@ test('test that updating a the start of an existing time entry in the overview w
page page
.getByTestId('time_entry_range_end') .getByTestId('time_entry_range_end')
.getByTestId('time_picker_minute') .getByTestId('time_picker_minute')
.press('Tab'), .press('Enter'),
]); ]);
}); });

View File

@@ -1,7 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { ref } from 'vue';
import { getLocalizedDayJs } from '@/utils/time'; import { getLocalizedDayJs } from '@/utils/time';
import { twMerge } from 'tailwind-merge';
const props = defineProps<{
class?: string;
}>();
const model = defineModel<string | null>({ const model = defineModel<string | null>({
default: null, default: null,
}); });
@@ -19,6 +23,7 @@ function updateDate(event: Event) {
.set('date', newDate.date()) .set('date', newDate.date())
.utc() .utc()
.format(); .format();
emit('changed', model.value);
} }
} }
@@ -28,6 +33,8 @@ function updateTempValue(event: Event) {
const target = event.target as HTMLInputElement; const target = event.target as HTMLInputElement;
tempDate.value = target.value; tempDate.value = target.value;
} }
const emit = defineEmits(['changed']);
</script> </script>
<template> <template>
@@ -36,7 +43,13 @@ function updateTempValue(event: Event) {
ref="datePicker" ref="datePicker"
@change="updateTempValue" @change="updateTempValue"
@blur="updateDate" @blur="updateDate"
class="bg-input-background border text-white border-input-border rounded-md" @keydown.enter="updateDate"
:class="
twMerge(
'bg-input-background border text-white border-input-border rounded-md',
props.class
)
"
type="date" type="date"
id="start" id="start"
name="trip-start" name="trip-start"

View File

@@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, onMounted } from 'vue'; import { computed } from 'vue';
import { getDayJsInstance, getLocalizedDayJs } from '@/utils/time'; import { getLocalizedDayJs } from '@/utils/time';
import { twMerge } from 'tailwind-merge'; import { twMerge } from 'tailwind-merge';
const model = defineModel<string | null>({ const model = defineModel<string | null>({
@@ -47,11 +47,6 @@ function updateHours(event: Event) {
} }
const emit = defineEmits(['changed']); const emit = defineEmits(['changed']);
onMounted(() => {
if (!model.value) {
model.value = getDayJsInstance().utc().format();
}
});
</script> </script>
<template> <template>
@@ -86,7 +81,7 @@ onMounted(() => {
type="text" type="text"
:class=" :class="
twMerge( twMerge(
'border-none bg-transparent px-1 py-0.5 w-[30px] text-center focus:ring-0 focus:bg-card-background-active', 'border-none bg-transparent px-1 py-1 w-[30px] text-center focus:ring-0 focus:bg-card-background-active',
props.size === 'large' ? 'text-base' : 'text-sm' props.size === 'large' ? 'text-base' : 'text-sm'
) )
" /> " />

View File

@@ -2,6 +2,7 @@
import { defineProps, ref, watch } from 'vue'; import { defineProps, ref, watch } from 'vue';
import TimePicker from '@/Components/Common/TimePicker.vue'; import TimePicker from '@/Components/Common/TimePicker.vue';
import { useFocusWithin } from '@vueuse/core'; import { useFocusWithin } from '@vueuse/core';
import DatePicker from '@/Components/Common/DatePicker.vue';
const props = defineProps<{ const props = defineProps<{
start: string; start: string;
@@ -35,21 +36,32 @@ watch(focused, (newValue, oldValue) => {
<template> <template>
<div <div
ref="dropdownContent" ref="dropdownContent"
class="grid grid-cols-2 divide-x divide-card-background-separator text-center py-1"> class="grid grid-cols-2 divide-x divide-card-background-separator text-center py-2">
<div> <div class="px-2">
<div class="font-bold text-white text-sm pb-1">Start</div> <div class="font-bold text-white text-sm pb-2">Start</div>
<TimePicker <div class="space-y-1">
data-testid="time_entry_range_start" <TimePicker
@changed="updateTimeEntry" data-testid="time_entry_range_start"
v-model="tempStart"></TimePicker> @changed="updateTimeEntry"
v-model="tempStart"></TimePicker>
<DatePicker
class="text-sm px-2 py-1"
@changed="updateTimeEntry"
v-model="tempStart"></DatePicker>
</div>
</div> </div>
<div> <div class="px-2">
<div class="font-bold text-white text-sm pb-1">End</div> <div class="font-bold text-white text-sm pb-2">End</div>
<TimePicker <div v-if="tempEnd !== null" class="space-y-1">
v-if="tempEnd !== null" <TimePicker
data-testid="time_entry_range_end" data-testid="time_entry_range_end"
@changed="updateTimeEntry" @changed="updateTimeEntry"
v-model="tempEnd"></TimePicker> v-model="tempEnd"></TimePicker>
<DatePicker
class="text-sm px-2 py-1"
@changed="updateTimeEntry"
v-model="tempEnd"></DatePicker>
</div>
<div class="text-muted" v-else>-- : --</div> <div class="text-muted" v-else>-- : --</div>
</div> </div>
</div> </div>

View File

@@ -6,7 +6,7 @@ import dayjs from 'dayjs';
import parse from 'parse-duration'; import parse from 'parse-duration';
import { useCurrentTimeEntryStore } from '@/utils/useCurrentTimeEntry'; import { useCurrentTimeEntryStore } from '@/utils/useCurrentTimeEntry';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { getDayJsInstance } from '@/utils/time'; import { formatDuration, getDayJsInstance } from '@/utils/time';
const currentTimeEntryStore = useCurrentTimeEntryStore(); const currentTimeEntryStore = useCurrentTimeEntryStore();
const { startLiveTimer, stopLiveTimer, updateTimer, startTimer } = const { startLiveTimer, stopLiveTimer, updateTimer, startTimer } =
currentTimeEntryStore; currentTimeEntryStore;
@@ -34,8 +34,8 @@ const currentTime = computed({
} }
if (now.value && currentTimeEntry.value.start) { if (now.value && currentTimeEntry.value.start) {
const startTime = dayjs(currentTimeEntry.value.start); const startTime = dayjs(currentTimeEntry.value.start);
const diff = now.value.diff(startTime); const diff = now.value.diff(startTime, 'seconds');
return dayjs(diff).utc().format('HH:mm:ss'); return formatDuration(diff);
} }
return null; return null;
}, },

View File

@@ -46,6 +46,14 @@ export function formatHumanReadableDuration(duration: number): string {
return `${hours}h ${minutes.toString().padStart(2, '0')}min`; return `${hours}h ${minutes.toString().padStart(2, '0')}min`;
} }
export function formatDuration(duration: number): string {
const dayJsDuration = dayjs.duration(duration, 's');
const hours = dayJsDuration.hours() + dayJsDuration.days() * 24;
const minutes = dayJsDuration.minutes();
const seconds = dayJsDuration.seconds();
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
}
export function calculateDifference(start: string, end: string | null) { export function calculateDifference(start: string, end: string | null) {
if (end === null) { if (end === null) {
end = dayjs().utc().format(); end = dayjs().utc().format();