imageboard/app/routes/index.jsx

112 lines
4.0 KiB
JavaScript

import { useLoaderData, useActionData, Form } from "@remix-run/react";
import { unstable_createFileUploadHandler, unstable_parseMultipartFormData } from "@remix-run/node";
import prisma from "~/utils/db.server";
import { redirect } from "@remix-run/node";
import { Link } from "@remix-run/react";
import Overlay from "~/components/Overlay";
import { json } from "@remix-run/node";
export async function action({ request }) {
const clonedData = request.clone();
const formData = await clonedData.formData();
const title = formData.get("title");
const post = formData.get("post");
const fileUploadHandler = unstable_createFileUploadHandler({
directory: './public/uploads/',
maxPartSize: 500000,
file: ({ filename }) => filename,
});
const errors = {};
let multiPartformdata;
let imageName;
try {
multiPartformdata = await unstable_parseMultipartFormData(request, fileUploadHandler);
imageName = multiPartformdata.get("image").name;
} catch (err) {
errors.image = "Image size too big";
}
if (typeof title !== "string" || title.length > 50 || title.length < 3) {
errors.title = "Title too long or short";
};
if (typeof post !== "string" || post.length > 50 || post.length < 3) {
errors.post = "Post too long or short";
};
if (Object.keys(errors).length) {
return json(errors, { status: 422 });
}
const newThread = await prisma.thread.create({
data: {
title: title,
post: post,
imageName: imageName,
},
});
return redirect(`threads/${newThread.id}`);
}
export async function loader() {
const data = await prisma.thread.findMany({
include: {
posts: true,
},
});
return data;
}
export default function Index() {
const data = useLoaderData();
const errors = useActionData();
return (
<Overlay>
<div className="bg-slate-100 border p-4 space-y-4">
<h1 className="text-center font-semibold text-2xl text-gray-800">Create a thread</h1>
<Form className="rounded flex flex-col text-center space-y-1 justify-center items-center " method="post" encType="multipart/form-data">
<label htmlFor="title-input">Title:
<textarea required minLength={3} type="text" name="title" placeholder="Lain" />
<p>{errors ? errors.title : ''}</p>
</label>
<br />
<label htmlFor="post-input">Post:
<textarea required minLength={3} type="text" name="post" placeholder="Iwakura" />
<p>{errors ? errors.post : ''}</p>
</label>
<br />
<label htmlFor="image-upload">Image: (500kb max) <br />
<input required accept="image/*" type="file" id="image-upload" name="image" />
<p>{errors ? errors.image : ''}</p>
</label>
<br />
<button className="bg-white py-2 px-4 rounded-full" type="submit">Submit</button>
</Form>
</div>
{data.length > 0 ?
<ul className="flex flex-wrap justify-around items-center p-8">
{data.map(thread =>
<li className="border shadow rounded-xl p-4 m-4 hover:shadow-xl scale-100 hover:scale-110 duration-500" key={thread.id}>
<Link className="space-y-4 flex flex-col" to={`threads/${thread.id}`}>
<div className="flex items-center justify-center">
<img className="w-48 rounded " src={`/uploads/${thread.imageName}`} alt="" />
</div>
<div>
<h2 className="text-2xl text-center tracking-tighter text-gray-700">{thread.title}</h2>
<p className="text-gray-400 text-center">{thread.post}</p>
<p className=" text-xs text-center text-gray-300">Posts: {thread.posts.length}</p>
</div>
</Link>
</li>
)}
</ul>
:
<h3 className="flex p-20 justify-center items-center text-center text-2xl">no threads yet</h3>
}
</Overlay>
);
};