From 859833452fd52601010dfb8c0aacb990b254ed95 Mon Sep 17 00:00:00 2001 From: Gregor Vostrak Date: Fri, 23 Aug 2024 15:34:49 +0200 Subject: [PATCH] add daily duration to header, fix dropdown overflows, add time dropdown to duration select --- .../js/packages/ui/src/DaySectionHeader.vue | 49 +++++++++++-------- .../js/packages/ui/src/Input/Dropdown.vue | 12 ++++- .../src/TimeEntry/TimeEntryAggregateRow.vue | 4 +- .../src/TimeEntry/TimeEntryGroupedTable.vue | 10 +++- .../TimeEntry/TimeEntryRowDurationInput.vue | 36 +++++++++++--- .../ui/src/TimeEntry/TimeEntryRowHeading.vue | 3 +- resources/js/packages/ui/src/utils/time.ts | 4 ++ 7 files changed, 85 insertions(+), 33 deletions(-) diff --git a/resources/js/packages/ui/src/DaySectionHeader.vue b/resources/js/packages/ui/src/DaySectionHeader.vue index d0fbc25a..5e4e52da 100644 --- a/resources/js/packages/ui/src/DaySectionHeader.vue +++ b/resources/js/packages/ui/src/DaySectionHeader.vue @@ -1,34 +1,43 @@ diff --git a/resources/js/packages/ui/src/Input/Dropdown.vue b/resources/js/packages/ui/src/Input/Dropdown.vue index d445dfe3..4404cdf8 100644 --- a/resources/js/packages/ui/src/Input/Dropdown.vue +++ b/resources/js/packages/ui/src/Input/Dropdown.vue @@ -2,8 +2,10 @@ import { onMounted, onUnmounted, ref } from 'vue'; import { flip, + limitShift, type Placement, type ReferenceElement, + shift, useFloating, } from '@floating-ui/vue'; import { offset } from '@floating-ui/vue'; @@ -59,7 +61,15 @@ const floating = ref(null); const { floatingStyles } = useFloating(reference, floating, { placement: props.align, whileElementsMounted: autoUpdate, - middleware: [flip(), offset(10)], + middleware: [ + flip(), + offset(10), + shift({ + limiter: limitShift({ + offset: 5, + }), + }), + ], }); diff --git a/resources/js/packages/ui/src/TimeEntry/TimeEntryAggregateRow.vue b/resources/js/packages/ui/src/TimeEntry/TimeEntryAggregateRow.vue index 6408f288..8f5ecc8a 100644 --- a/resources/js/packages/ui/src/TimeEntry/TimeEntryAggregateRow.vue +++ b/resources/js/packages/ui/src/TimeEntry/TimeEntryAggregateRow.vue @@ -35,6 +35,7 @@ const props = defineProps<{ createClient: (client: CreateClientBody) => Promise; onStartStopClick: (timeEntry: TimeEntry) => void; updateTimeEntries: (ids: string[], changes: Partial) => void; + updateTimeEntry: (timeEntry: TimeEntry) => void; deleteTimeEntries: (timeEntries: TimeEntry[]) => void; currency: string; }>(); @@ -156,8 +157,7 @@ const expanded = ref(false); :tags="tags" indent :updateTimeEntry=" - (timeEntry: TimeEntry) => - updateTimeEntries([timeEntry.id], { ...timeEntry }) + (timeEntry: TimeEntry) => updateTimeEntry(timeEntry) " :onStartStopClick="() => onStartStopClick(subEntry)" :deleteTimeEntry="() => deleteTimeEntries([subEntry])" diff --git a/resources/js/packages/ui/src/TimeEntry/TimeEntryGroupedTable.vue b/resources/js/packages/ui/src/TimeEntry/TimeEntryGroupedTable.vue index 272a99a3..4a0e8db5 100644 --- a/resources/js/packages/ui/src/TimeEntry/TimeEntryGroupedTable.vue +++ b/resources/js/packages/ui/src/TimeEntry/TimeEntryGroupedTable.vue @@ -112,11 +112,16 @@ function startTimeEntryFromExisting(entry: TimeEntry) { description: entry.description, }); } +function sumDuration(timeEntries: TimeEntry[]) { + return timeEntries.reduce((acc, entry) => acc + (entry?.duration ?? 0), 0); +} diff --git a/resources/js/packages/ui/src/TimeEntry/TimeEntryRowDurationInput.vue b/resources/js/packages/ui/src/TimeEntry/TimeEntryRowDurationInput.vue index 0fc63769..c186c221 100644 --- a/resources/js/packages/ui/src/TimeEntry/TimeEntryRowDurationInput.vue +++ b/resources/js/packages/ui/src/TimeEntry/TimeEntryRowDurationInput.vue @@ -6,6 +6,8 @@ import { import { computed, defineProps, ref } from 'vue'; import parse from 'parse-duration'; import dayjs from 'dayjs'; +import Dropdown from '@/packages/ui/src/Input/Dropdown.vue'; +import TimeRangeSelector from '@/packages/ui/src/Input/TimeRangeSelector.vue'; const props = defineProps<{ start: string; @@ -16,6 +18,7 @@ const emit = defineEmits<{ }>(); const temporaryCustomTimerEntry = ref(''); +const open = ref(false); function updateTimerAndStartLiveTimerUpdate() { const time = parse(temporaryCustomTimerEntry.value, 's'); @@ -53,19 +56,38 @@ const currentTime = computed({ }); function selectInput(event: Event) { + open.value = true; const target = event.target as HTMLInputElement; target.select(); } diff --git a/resources/js/packages/ui/src/TimeEntry/TimeEntryRowHeading.vue b/resources/js/packages/ui/src/TimeEntry/TimeEntryRowHeading.vue index ba002f62..e748180a 100644 --- a/resources/js/packages/ui/src/TimeEntry/TimeEntryRowHeading.vue +++ b/resources/js/packages/ui/src/TimeEntry/TimeEntryRowHeading.vue @@ -3,6 +3,7 @@ import DaySectionHeader from '@/packages/ui/src/DaySectionHeader.vue'; import MainContainer from '@/packages/ui/src/MainContainer.vue'; defineProps<{ date: string; + duration: number; }>(); @@ -10,7 +11,7 @@ defineProps<{
- +
diff --git a/resources/js/packages/ui/src/utils/time.ts b/resources/js/packages/ui/src/utils/time.ts index d3039091..fc70dddd 100644 --- a/resources/js/packages/ui/src/utils/time.ts +++ b/resources/js/packages/ui/src/utils/time.ts @@ -102,6 +102,10 @@ export function formatHumanReadableDate(date: string) { return dayjs(date).fromNow(); } +export function formatWeekday(date: string) { + return dayjs(date).format('dddd'); +} + export function formatStartEnd(start: string, end: string | null) { if (end) { return `${formatTime(start)} - ${formatTime(end)}`;