import { Alert, Drawer, TextInput, Text, useMantineTheme, Group, Button, Textarea, Stack, Select, ColorSwatch } from '@mantine/core'; import type { ActionArgs, LoaderArgs, MetaFunction } from '@remix-run/node'; import { json, redirect } from '@remix-run/node'; import { Form, useActionData, useCatch, useLoaderData, useNavigate } from '@remix-run/react'; import * as React from 'react'; import { AlertTriangle, Play } from 'react-feather'; import { getProjects } from '~/models/project.server'; import { createTimeEntry, stopAllTimeEntries } from '~/models/timeEntry.server'; import { requireUserId } from '~/session.server'; import { DatePicker, TimeInput } from '@mantine/dates'; import { forwardRef } from 'react'; import 'dayjs/locale/it'; export const meta: MetaFunction = () => { return { title: 'New Time Entry | WorkTimer', description: 'Create a new time entry. You must be logged in to do this.' }; }; export async function loader({ request }: LoaderArgs) { const userId = await requireUserId(request); return json({ ...(await getProjects({ userId })) }); } 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'); if (typeof description !== 'string' || description.length === 0) { return json( { errors: { projectId: null, description: 'Description is required', startTime: null, endTime: null } }, { status: 400 } ); } if (typeof projectId !== 'string' || projectId.length === 0) { return json( { errors: { projectId: 'projectId is required', description: null, startTime: null, endTime: null } }, { status: 400 } ); } if (typeof startTime !== 'string' || startTime.length === 0) { return json( { errors: { projectId: null, description: null, startTime: 'startTime is required', endTime: null } }, { status: 400 } ); } if ( startTime && typeof startTime === 'string' && Number.isNaN(Date.parse(startTime)) ) { return json( { errors: { projectId: null, description: null, startTime: 'startTime is invalid', endTime: null } }, { status: 422 } ); } if ( endTime && typeof endTime === 'string' && Number.isNaN(Date.parse(endTime)) ) { return json( { errors: { projectId: null, description: null, startTime: null, endTime: 'endTime is invalid' } }, { status: 422 } ); } if ( startTime && endTime && typeof startTime === 'string' && typeof endTime === 'string' && new Date(startTime) > new Date(endTime) ) { return json( { errors: { projectId: null, description: null, startTime: 'startTime must be before endTime', endTime: 'startTime must be before endTime' } }, { status: 422 } ); } await stopAllTimeEntries(userId); const timeEntry = await createTimeEntry({ description, startTime: new Date(startTime), endTime: typeof endTime === 'string' ? new Date(endTime) : null, userId, projectId }); return redirect(`/time-entries`); } interface ItemProps extends React.ComponentPropsWithoutRef<'div'> { id: string; label: string; color: string; } const SelectItem = forwardRef( ({ label, color, id, ...others }: ItemProps, ref) => (
{label}
) ); const LayoutWrapper = ({ children }: React.PropsWithChildren<{}>) => { const theme = useMantineTheme(); const navigate = useNavigate(); return ( { navigate('/time-entries'); }} > {children} ); }; export default function NewTimeEntryPage() { const actionData = useActionData(); const data = useLoaderData(); const theme = useMantineTheme(); const descriptionRef = React.useRef(null); const startDateRef = React.useRef(null); const endDateRef = React.useRef(null); const projectRef = React.useRef(null); const [start, setStart] = React.useState(new Date(Date.now())); const [end, setEnd] = React.useState(); React.useEffect(() => { if (actionData?.errors?.description) { descriptionRef.current?.focus(); } else if (actionData?.errors?.startTime) { startDateRef.current?.focus(); } else if (actionData?.errors?.endTime) { endDateRef.current?.focus(); } else if (actionData?.errors?.projectId) { projectRef.current?.focus(); } }, [actionData]); return (