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 {
Alert,
Drawer,
TextInput,
Text,
useMantineTheme,
Group,
Button,
Textarea,
Stack,
Select,
ColorSwatch,
ColorInput,
ActionIcon,
Input,
ColorPicker
} from '@mantine/core';
import {
AlertTriangle,
Delete,
Play,
RefreshCcw,
Save,
Square,
Trash
} from 'react-feather';
import invariant from 'tiny-invariant';
import {
deleteTimeEntry,
getTimeEntry,
updateTimeEntry
} from '~/models/timeEntry.server';
import { requireUserId } from '~/session.server';
import {
deleteProject,
getProject,
getProjects,
Project,
updateProject
} from '~/models/project.server';
import { DatePicker, TimeInput } from '@mantine/dates';
export const meta: MetaFunction = () => {
return {
title: 'Edit Project | WorkTimer',
description: 'Edit a project. You must be logged in to do this.'
};
};
export async function loader({ request, params }: LoaderArgs) {
const userId = await requireUserId(request);
invariant(params.projectId, 'projectId not found');
const project = await getProject({ userId, id: params.projectId });
if (!project) {
throw new Response('Not Found', { status: 404 });
}
return json({ project });
}
export async function action({ request, params }: ActionArgs) {
const userId = await requireUserId(request);
invariant(params.projectId, 'projectId not found');
const project = await getProject({ userId, id: params.projectId });
if (!project) {
throw new Response('Not Found', { status: 404 });
}
if (request.method === 'DELETE') {
await deleteProject({ userId, id: params.projectId });
} else if (request.method === 'PATCH') {
const formData = await request.formData();
const name = (formData.get('name') || undefined) as string | undefined;
const description = (formData.get('description') || undefined) as
| string
| undefined;
let color = (formData.get('color') || undefined) as string | undefined;
await updateProject({
projectId: params.projectId,
name,
description,
color
});
}
return redirect('/projects');
}
const LayoutWrapper = ({ children }: React.PropsWithChildren<{}>) => {
const theme = useMantineTheme();
const navigate = useNavigate();
return (
{
navigate('/projects');
}}
>
{children}
);
};
const randomColor = () =>
`#${Math.floor(Math.random() * 16777215).toString(16)}`;
export default function ProjectDetailsPage() {
const actionData = useActionData();
const data = useLoaderData();
const theme = useMantineTheme();
const nameRef = React.useRef(null);
const descriptionRef = React.useRef(null);
const colorRef = React.useRef(null);
const [color, setColor] = React.useState(
data.project.color || randomColor()
);
return (
);
}
export function ErrorBoundary({ error }: { error: Error }) {
console.error(error);
return (
} title="Error" color="red">
An unexpected error occurred: {error.message}
);
}
export function CatchBoundary() {
const caught = useCatch();
if (caught.status === 404) {
return (
} title="Error" color="red">
Not found
);
}
throw new Error(`Unexpected caught response with status: ${caught.status}`);
}