diff --git a/frontend/components/TimeEntryDrawer.vue b/frontend/components/TimeEntryDrawer.vue
index 2e13ce7..a3b2a17 100644
--- a/frontend/components/TimeEntryDrawer.vue
+++ b/frontend/components/TimeEntryDrawer.vue
@@ -20,25 +20,43 @@
/>
+
+
+
+
+
+
+ {{ durationLabel }}
+
+
-
+
+
+
+
@@ -114,52 +142,89 @@ const authStore = useAuthStore()
const form = reactive({
title: '',
description: '',
- startedAt: '',
- stoppedAt: '',
+ date: '',
+ startTime: '',
+ endTime: '',
userId: authStore.user?.id ?? null as number | null,
projectId: null as number | null,
typeId: null as number | null,
})
-watch(() => props.entry, (entry) => {
+const durationLabel = computed(() => {
+ if (!form.startTime || !form.endTime) return ''
+ const [sh, sm] = form.startTime.split(':').map(Number) as [number, number]
+ const [eh, em] = form.endTime.split(':').map(Number) as [number, number]
+ const diff = (eh * 60 + em) - (sh * 60 + sm)
+ if (diff <= 0) return ''
+ const h = Math.floor(diff / 60)
+ const m = diff % 60
+ return m > 0 ? `${h}h${String(m).padStart(2, '0')}` : `${h}h`
+})
+
+function toLocalDate(iso: string): string {
+ const d = new Date(iso)
+ const offset = d.getTimezoneOffset()
+ const local = new Date(d.getTime() - offset * 60000)
+ return local.toISOString().slice(0, 10)
+}
+
+function toLocalTime(iso: string): string {
+ const d = new Date(iso)
+ const offset = d.getTimezoneOffset()
+ const local = new Date(d.getTime() - offset * 60000)
+ return local.toISOString().slice(11, 16)
+}
+
+function toISO(date: string, time: string): string {
+ return new Date(`${date}T${time}`).toISOString()
+}
+
+function populateForm(entry: TimeEntry | null | undefined) {
if (entry) {
form.title = entry.title ?? ''
form.description = entry.description ?? ''
- form.startedAt = toLocalDatetimeInput(entry.startedAt)
- form.stoppedAt = entry.stoppedAt ? toLocalDatetimeInput(entry.stoppedAt) : ''
+ form.date = toLocalDate(entry.startedAt)
+ form.startTime = toLocalTime(entry.startedAt)
+ form.endTime = entry.stoppedAt ? toLocalTime(entry.stoppedAt) : ''
form.userId = entry.user?.id ?? authStore.user?.id ?? null
form.projectId = entry.project?.id ?? null
form.typeId = entry.types?.[0]?.id ?? null
} else {
form.title = ''
form.description = ''
- form.startedAt = props.prefillStartedAt ? toLocalDatetimeInput(props.prefillStartedAt) : ''
- form.stoppedAt = ''
+ form.date = props.prefillStartedAt ? toLocalDate(props.prefillStartedAt) : new Date().toISOString().slice(0, 10)
+ form.startTime = props.prefillStartedAt ? toLocalTime(props.prefillStartedAt) : ''
+ form.endTime = ''
form.userId = authStore.user?.id ?? null
form.projectId = null
form.typeId = null
}
-}, { immediate: true })
-
-function toLocalDatetimeInput(iso: string): string {
- const d = new Date(iso)
- const offset = d.getTimezoneOffset()
- const local = new Date(d.getTime() - offset * 60000)
- return local.toISOString().slice(0, 16)
}
-function toISOFromLocal(localStr: string): string {
- return new Date(localStr).toISOString()
+watch([() => props.modelValue, () => props.entry] as const, ([open, entry]) => {
+ if (open) {
+ populateForm(entry)
+ }
+})
+
+async function onDelete() {
+ if (!props.entry) return
+ const { remove } = useTimeEntryService()
+ await remove(props.entry.id)
+ emit('saved')
+ isOpen.value = false
}
async function onSubmit() {
+ if (!form.date || !form.startTime || !form.endTime) return
+
const { create, update } = useTimeEntryService()
const payload: Record = {
title: form.title || null,
description: form.description || null,
- startedAt: toISOFromLocal(form.startedAt),
- stoppedAt: form.stoppedAt ? toISOFromLocal(form.stoppedAt) : null,
+ startedAt: toISO(form.date, form.startTime),
+ stoppedAt: form.endTime ? toISO(form.date, form.endTime) : null,
user: `/api/users/${form.userId}`,
project: form.projectId ? `/api/projects/${form.projectId}` : null,
types: form.typeId ? [`/api/task_types/${form.typeId}`] : [],