mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-16 04:02:15 +01:00
add break time entries and simplified time tracker ui
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { ref, type Ref, type ComputedRef } from 'vue';
|
||||
import type { Dayjs } from 'dayjs';
|
||||
import type { TimeEntry } from '@/packages/api/src';
|
||||
import { getDayJsInstance, getLocalizedDayJsFromMinutes } from '../utils/time';
|
||||
import { getDayJsInstance, getLocalizedDayJs, getLocalizedDayJsFromMinutes } from '../utils/time';
|
||||
|
||||
import type { CalendarSettings } from './calendarSettings';
|
||||
import type { CalendarEvent } from './calendarTypes';
|
||||
@@ -19,6 +19,7 @@ export function useContextMenu(params: {
|
||||
deleteTimeEntry: (id: string) => Promise<void>;
|
||||
onEditEvent: (entry: TimeEntry) => void;
|
||||
onCreateEvent: (start: Dayjs, end: Dayjs) => void;
|
||||
onCreateBreak: (start: Dayjs, end: Dayjs) => void;
|
||||
emitRefresh: () => void;
|
||||
}) {
|
||||
const contextMenuTimeEntry = ref<TimeEntry | null>(null);
|
||||
@@ -73,6 +74,7 @@ export function useContextMenu(params: {
|
||||
start: entry.start,
|
||||
end: entry.end,
|
||||
billable: entry.billable,
|
||||
type: entry.type,
|
||||
description: entry.description,
|
||||
project_id: entry.project_id,
|
||||
task_id: entry.task_id,
|
||||
@@ -108,6 +110,7 @@ export function useContextMenu(params: {
|
||||
start: midpoint.utc().format(),
|
||||
end: entry.end,
|
||||
billable: entry.billable,
|
||||
type: entry.type,
|
||||
description: entry.description,
|
||||
project_id: entry.project_id,
|
||||
task_id: entry.task_id,
|
||||
@@ -154,6 +157,47 @@ export function useContextMenu(params: {
|
||||
}
|
||||
}
|
||||
|
||||
function handleContextCreateBreak() {
|
||||
const dayjs = getDayJsInstance();
|
||||
if (!contextMenuCreateTime.value) {
|
||||
params.onCreateBreak(dayjs().utc().subtract(30, 'minute'), dayjs().utc());
|
||||
return;
|
||||
}
|
||||
const clickTime = contextMenuCreateTime.value.start;
|
||||
// Day matching must use the user's configured timezone (the calendar renders
|
||||
// its day columns in that timezone), not the browser's local timezone
|
||||
const clickDate = getLocalizedDayJs(clickTime.format()).format('YYYY-MM-DD');
|
||||
|
||||
// When the click lands in a gap between two entries of the same day,
|
||||
// the break is prefilled to exactly fill that gap
|
||||
let previousEnd: Dayjs | null = null;
|
||||
let nextStart: Dayjs | null = null;
|
||||
for (const calendarEvent of params.calendarEvents.value) {
|
||||
const entry = calendarEvent.timeEntry;
|
||||
const entryStart = dayjs.utc(entry.start);
|
||||
if (getLocalizedDayJs(entry.start).format('YYYY-MM-DD') !== clickDate) {
|
||||
continue;
|
||||
}
|
||||
const entryEnd = entry.end === null ? null : dayjs.utc(entry.end);
|
||||
if (entryEnd !== null && !entryEnd.isAfter(clickTime)) {
|
||||
if (previousEnd === null || entryEnd.isAfter(previousEnd)) {
|
||||
previousEnd = entryEnd;
|
||||
}
|
||||
}
|
||||
if (!entryStart.isBefore(clickTime)) {
|
||||
if (nextStart === null || entryStart.isBefore(nextStart)) {
|
||||
nextStart = entryStart;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (previousEnd !== null && nextStart !== null && previousEnd.isBefore(nextStart)) {
|
||||
params.onCreateBreak(previousEnd, nextStart);
|
||||
return;
|
||||
}
|
||||
params.onCreateBreak(contextMenuCreateTime.value.start, contextMenuCreateTime.value.end);
|
||||
}
|
||||
|
||||
return {
|
||||
contextMenuTimeEntry,
|
||||
contextMenuCreateTime,
|
||||
@@ -165,5 +209,6 @@ export function useContextMenu(params: {
|
||||
handleContextStop,
|
||||
handleContextDiscard,
|
||||
handleContextCreate,
|
||||
handleContextCreateBreak,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user