112 lines
4.0 KiB
JavaScript
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>
|
|
);
|
|
};
|