import {
Drawer,
TextInput,
useMantineTheme,
Group,
Button,
Textarea,
ColorInput,
Alert,
ActionIcon
} 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, RefreshCcw, Save } from 'react-feather';
import { createProject, Project } from '~/models/project.server';
import { requireUserId } from '~/session.server';
export const meta: MetaFunction = () => {
return {
title: 'New Project | WorkTimer',
description: 'Create a new project. You must be logged in to do this.'
};
};
export async function loader({ request }: LoaderArgs) {
const userId = await requireUserId(request);
if (!userId) return redirect('/projects');
return json({});
}
export async function action({ request }: ActionArgs) {
const userId = await requireUserId(request);
const formData = await request.formData();
const name = formData.get('name');
const description = formData.get('description');
const color = formData.get('color');
if (typeof name !== 'string' || name.length === 0) {
return json(
{
errors: {
name: 'name is required',
description: null,
color: null
}
},
{ status: 400 }
);
}
if (description && typeof description !== 'string') {
return json(
{
errors: {
name: null,
description: 'Description is invalid',
color: null
}
},
{ status: 422 }
);
}
if (typeof color !== 'string' || color.length === 0) {
return json(
{
errors: {
name: null,
description: null,
color: 'color is required'
}
},
{ status: 400 }
);
}
const project = await createProject({
name,
description,
color,
userId
});
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 NewProjectPage() {
const data = useLoaderData();
const actionData = useActionData();
const theme = useMantineTheme();
const nameRef = React.useRef(null);
const descriptionRef = React.useRef(null);
const colorRef = React.useRef(null);
const [color, setColor] = React.useState(randomColor());
React.useEffect(() => {
if (actionData?.errors?.name) {
nameRef.current?.focus();
} else if (actionData?.errors?.description) {
descriptionRef.current?.focus();
} else if (actionData?.errors?.color) {
colorRef.current?.focus();
}
}, [actionData]);
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}`);
}