diff --git a/app/models/timeEntry.server.ts b/app/models/timeEntry.server.ts index 7b35bc6..2e530b0 100644 --- a/app/models/timeEntry.server.ts +++ b/app/models/timeEntry.server.ts @@ -145,7 +145,33 @@ export function createTimeEntry({ }); } -export function stopAllTimeEntries(userId: User['id']) { +export async function updateDuration(userId: User['id']) { + const timeEntriesWithoutDuration = await prisma.timeEntry.findMany({ + where: { + userId, + endTime: { not: null }, + duration: null + } + }); + + Promise.all( + timeEntriesWithoutDuration.map( + async (entry) => + await prisma.timeEntry.update({ + where: { id: entry.id }, + data: { + duration: + (entry.endTime || new Date(Date.now())).getTime() - + entry.startTime.getTime() + } + }) + ) + ); +} + +export async function stopAllTimeEntries(userId: User['id']) { + await updateDuration(userId); + return prisma.timeEntry.updateMany({ where: { userId, endTime: null }, data: { endTime: new Date() } diff --git a/app/routes/reports.tsx b/app/routes/reports.tsx index d34cc4d..3378232 100644 --- a/app/routes/reports.tsx +++ b/app/routes/reports.tsx @@ -12,7 +12,10 @@ import { } from '@mantine/core'; import { MetaFunction, LoaderArgs, redirect, json } from '@remix-run/node'; import { Link, useFetcher, useLoaderData, useNavigate } from '@remix-run/react'; -import { getTimeEntriesByDateAndProject } from '~/models/timeEntry.server'; +import { + getTimeEntriesByDateAndProject, + updateDuration +} from '~/models/timeEntry.server'; import { getProjects, Project } from '~/models/project.server'; import { requireUserId } from '~/session.server'; import { DateRangePicker, DateRangePickerValue } from '@mantine/dates'; @@ -43,6 +46,8 @@ export async function loader({ request }: LoaderArgs) { ? dayjs(url.searchParams.get('dateTo')).toDate() : dayjs().endOf('month').toDate(); + await updateDuration(userId); + return json({ timeByProject: await getTimeEntriesByDateAndProject({ userId, diff --git a/app/routes/time-entries.tsx b/app/routes/time-entries.tsx index bf2e242..58b3ca6 100644 --- a/app/routes/time-entries.tsx +++ b/app/routes/time-entries.tsx @@ -387,11 +387,7 @@ export default function TimeEntriesPage() { {timeEntry.endTime ? (
- + - + new Date(endTime) + startDate > endDate ) { return json( { @@ -145,12 +153,10 @@ export async function action({ request, params }: ActionArgs) { timeEntryId: params.timeEntryId, description, projectId, - startTime: startTime ? new Date(startTime) : undefined, - endTime: endTime ? new Date(endTime) : undefined, + startTime: startDate, + endTime: endDate, duration: - endTime && startTime - ? new Date(endTime).getTime() - new Date(startTime).getTime() - : undefined + endDate && startDate ? endDate.getTime() - startDate.getTime() : null }); } diff --git a/app/routes/time-entries/new.tsx b/app/routes/time-entries/new.tsx index d2e079c..8a5939d 100644 --- a/app/routes/time-entries/new.tsx +++ b/app/routes/time-entries/new.tsx @@ -49,10 +49,16 @@ export async function action({ request }: ActionArgs) { const userId = await requireUserId(request); const formData = await request.formData(); - const description = formData.get('description'); - const projectId = formData.get('projectId'); - let startTime = formData.get('startTime'); - let endTime = formData.get('endTime'); + const description = (formData.get('description') || undefined) as + | string + | undefined; + const projectId = (formData.get('projectId') || undefined) as + | string + | undefined; + let startTime = (formData.get('startTime') || undefined) as + | string + | undefined; + let endTime = (formData.get('endTime') || undefined) as string | undefined; if (typeof description !== 'string' || description.length === 0) { return json( @@ -97,7 +103,7 @@ export async function action({ request }: ActionArgs) { if ( startTime && typeof startTime === 'string' && - Number.isNaN(Date.parse(startTime)) + !(startTime === 'now' || !Number.isNaN(Date.parse(startTime))) ) { return json( { @@ -114,7 +120,7 @@ export async function action({ request }: ActionArgs) { if ( endTime && typeof endTime === 'string' && - Number.isNaN(Date.parse(endTime)) + !(endTime === 'now' || !Number.isNaN(Date.parse(endTime))) ) { return json( { @@ -128,12 +134,18 @@ export async function action({ request }: ActionArgs) { { status: 422 } ); } + + let startDate = new Date(startTime === 'now' ? Date.now() : startTime); + let endDate = endTime + ? new Date(endTime === 'now' ? Date.now() : endTime) + : undefined; + if ( - startTime && - endTime && + startDate && + endDate && typeof startTime === 'string' && typeof endTime === 'string' && - new Date(startTime) > new Date(endTime) + startDate > endDate ) { return json( { @@ -152,12 +164,9 @@ export async function action({ request }: ActionArgs) { const timeEntry = await createTimeEntry({ description, - startTime: new Date(startTime), - endTime: typeof endTime === 'string' ? new Date(endTime) : null, - duration: - typeof endTime === 'string' - ? new Date(endTime).getTime() - new Date(startTime).getTime() - : null, + startTime: startDate, + endTime: endDate || null, + duration: endDate ? endDate.getTime() - startDate.getTime() : null, userId, projectId });