fix: calc durations on save, trigger duration calc on reports, update/create te with now value on server

This commit is contained in:
Nicola Zambello 2023-03-01 00:40:22 +01:00
parent c6215912e6
commit 6d8d487e28
Signed by: nzambello
GPG key ID: 56E4A92C2C1E50BA
5 changed files with 75 additions and 37 deletions

View file

@ -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({ return prisma.timeEntry.updateMany({
where: { userId, endTime: null }, where: { userId, endTime: null },
data: { endTime: new Date() } data: { endTime: new Date() }

View file

@ -12,7 +12,10 @@ import {
} from '@mantine/core'; } from '@mantine/core';
import { MetaFunction, LoaderArgs, redirect, json } from '@remix-run/node'; import { MetaFunction, LoaderArgs, redirect, json } from '@remix-run/node';
import { Link, useFetcher, useLoaderData, useNavigate } from '@remix-run/react'; 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 { getProjects, Project } from '~/models/project.server';
import { requireUserId } from '~/session.server'; import { requireUserId } from '~/session.server';
import { DateRangePicker, DateRangePickerValue } from '@mantine/dates'; import { DateRangePicker, DateRangePickerValue } from '@mantine/dates';
@ -43,6 +46,8 @@ export async function loader({ request }: LoaderArgs) {
? dayjs(url.searchParams.get('dateTo')).toDate() ? dayjs(url.searchParams.get('dateTo')).toDate()
: dayjs().endOf('month').toDate(); : dayjs().endOf('month').toDate();
await updateDuration(userId);
return json({ return json({
timeByProject: await getTimeEntriesByDateAndProject({ timeByProject: await getTimeEntriesByDateAndProject({
userId, userId,

View file

@ -387,11 +387,7 @@ export default function TimeEntriesPage() {
</Menu> </Menu>
{timeEntry.endTime ? ( {timeEntry.endTime ? (
<Form method="post" action="/time-entries/new"> <Form method="post" action="/time-entries/new">
<input <input type="hidden" name="startTime" value="now" />
type="hidden"
name="startTime"
value={new Date(Date.now()).toISOString()}
/>
<input <input
type="hidden" type="hidden"
name="description" name="description"
@ -421,11 +417,7 @@ export default function TimeEntriesPage() {
method="patch" method="patch"
action={`/time-entries/${timeEntry.id}`} action={`/time-entries/${timeEntry.id}`}
> >
<input <input type="hidden" name="endTime" value="now" />
type="hidden"
name="endTime"
value={new Date().toISOString()}
/>
<ActionIcon <ActionIcon
type="submit" type="submit"
variant="filled" variant="filled"

View file

@ -90,7 +90,7 @@ export async function action({ request, params }: ActionArgs) {
if ( if (
startTime && startTime &&
typeof startTime === 'string' && typeof startTime === 'string' &&
Number.isNaN(Date.parse(startTime)) !(startTime === 'now' || !Number.isNaN(Date.parse(startTime)))
) { ) {
return json( return json(
{ {
@ -107,7 +107,7 @@ export async function action({ request, params }: ActionArgs) {
if ( if (
endTime && endTime &&
typeof endTime === 'string' && typeof endTime === 'string' &&
Number.isNaN(Date.parse(endTime)) !(endTime === 'now' || !Number.isNaN(Date.parse(endTime)))
) { ) {
return json( return json(
{ {
@ -121,12 +121,20 @@ export async function action({ request, params }: ActionArgs) {
{ status: 422 } { status: 422 }
); );
} }
let startDate = startTime
? new Date(startTime === 'now' ? Date.now() : startTime)
: undefined;
let endDate = endTime
? new Date(endTime === 'now' ? Date.now() : endTime)
: undefined;
if ( if (
startTime && startDate &&
endTime && endDate &&
typeof startTime === 'string' && typeof startTime === 'string' &&
typeof endTime === 'string' && typeof endTime === 'string' &&
new Date(startTime) > new Date(endTime) startDate > endDate
) { ) {
return json( return json(
{ {
@ -145,12 +153,10 @@ export async function action({ request, params }: ActionArgs) {
timeEntryId: params.timeEntryId, timeEntryId: params.timeEntryId,
description, description,
projectId, projectId,
startTime: startTime ? new Date(startTime) : undefined, startTime: startDate,
endTime: endTime ? new Date(endTime) : undefined, endTime: endDate,
duration: duration:
endTime && startTime endDate && startDate ? endDate.getTime() - startDate.getTime() : null
? new Date(endTime).getTime() - new Date(startTime).getTime()
: undefined
}); });
} }

View file

@ -49,10 +49,16 @@ export async function action({ request }: ActionArgs) {
const userId = await requireUserId(request); const userId = await requireUserId(request);
const formData = await request.formData(); const formData = await request.formData();
const description = formData.get('description'); const description = (formData.get('description') || undefined) as
const projectId = formData.get('projectId'); | string
let startTime = formData.get('startTime'); | undefined;
let endTime = formData.get('endTime'); 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) { if (typeof description !== 'string' || description.length === 0) {
return json( return json(
@ -97,7 +103,7 @@ export async function action({ request }: ActionArgs) {
if ( if (
startTime && startTime &&
typeof startTime === 'string' && typeof startTime === 'string' &&
Number.isNaN(Date.parse(startTime)) !(startTime === 'now' || !Number.isNaN(Date.parse(startTime)))
) { ) {
return json( return json(
{ {
@ -114,7 +120,7 @@ export async function action({ request }: ActionArgs) {
if ( if (
endTime && endTime &&
typeof endTime === 'string' && typeof endTime === 'string' &&
Number.isNaN(Date.parse(endTime)) !(endTime === 'now' || !Number.isNaN(Date.parse(endTime)))
) { ) {
return json( return json(
{ {
@ -128,12 +134,18 @@ export async function action({ request }: ActionArgs) {
{ status: 422 } { status: 422 }
); );
} }
let startDate = new Date(startTime === 'now' ? Date.now() : startTime);
let endDate = endTime
? new Date(endTime === 'now' ? Date.now() : endTime)
: undefined;
if ( if (
startTime && startDate &&
endTime && endDate &&
typeof startTime === 'string' && typeof startTime === 'string' &&
typeof endTime === 'string' && typeof endTime === 'string' &&
new Date(startTime) > new Date(endTime) startDate > endDate
) { ) {
return json( return json(
{ {
@ -152,12 +164,9 @@ export async function action({ request }: ActionArgs) {
const timeEntry = await createTimeEntry({ const timeEntry = await createTimeEntry({
description, description,
startTime: new Date(startTime), startTime: startDate,
endTime: typeof endTime === 'string' ? new Date(endTime) : null, endTime: endDate || null,
duration: duration: endDate ? endDate.getTime() - startDate.getTime() : null,
typeof endTime === 'string'
? new Date(endTime).getTime() - new Date(startTime).getTime()
: null,
userId, userId,
projectId projectId
}); });