137 lines
3.7 KiB
TypeScript
137 lines
3.7 KiB
TypeScript
import type { PostWithRelations } from "~/utils/prisma.server";
|
|
import type {
|
|
ActionFunction,
|
|
ActionFunctionArgs,
|
|
LoaderFunction,
|
|
LoaderFunctionArgs,
|
|
} from "@remix-run/node";
|
|
import { json, redirect } from "@remix-run/node";
|
|
import {
|
|
Form,
|
|
useActionData,
|
|
useLoaderData,
|
|
useRouteLoaderData,
|
|
} from "@remix-run/react";
|
|
import { Button } from "~/components/Button";
|
|
import { Card } from "~/components/Card";
|
|
import { FormLabel, TextArea } from "~/components/Form";
|
|
import { Post } from "~/components/Post";
|
|
import { SubTitle, Text, Title } from "~/components/Typography";
|
|
import { likePost, unLikePost } from "~/models/like.server";
|
|
import { createPost, getAllPosts, getFeed } from "~/models/post.server";
|
|
import { commitSession, getSession } from "~/utils/session.server";
|
|
import type { RootLoaderTypes } from "~/root";
|
|
|
|
export async function action({ request }: ActionFunctionArgs) {
|
|
const session = await getSession(request.headers.get("Cookie"));
|
|
if (!session.has("userId")) {
|
|
return redirect("/");
|
|
}
|
|
|
|
const userId = session.get("userId");
|
|
|
|
const formData = await request
|
|
.formData()
|
|
.then((data) => Object.fromEntries(data));
|
|
|
|
switch (formData.intent) {
|
|
case "newpost":
|
|
const postErrors = await createPost(String(formData.post), userId);
|
|
|
|
if (Object.values(postErrors).some(Boolean)) {
|
|
return postErrors;
|
|
}
|
|
|
|
session.flash("globalMessage", "Post created!");
|
|
|
|
break;
|
|
case "like":
|
|
const likeErrors = await likePost(Number(formData.postId), userId);
|
|
|
|
if (Object.values(likeErrors).some(Boolean)) {
|
|
return likeErrors;
|
|
}
|
|
|
|
session.flash("globalMessage", "Post liked!");
|
|
|
|
break;
|
|
case "unlike":
|
|
const unLikeErrors = await unLikePost(Number(formData.postId), userId);
|
|
|
|
if (Object.values(unLikeErrors).some(Boolean)) {
|
|
return unLikeErrors;
|
|
}
|
|
|
|
session.flash("globalMessage", "Post unliked!");
|
|
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
return json(
|
|
{},
|
|
{
|
|
headers: {
|
|
"Set-Cookie": await commitSession(session),
|
|
},
|
|
}
|
|
);
|
|
}
|
|
|
|
export async function loader({ request }: LoaderFunctionArgs) {
|
|
const session = await getSession(request.headers.get("Cookie"));
|
|
if (!session.has("userId")) {
|
|
return redirect("/");
|
|
}
|
|
|
|
return await getFeed(session.get("userId"));
|
|
}
|
|
|
|
export default function Index() {
|
|
const rootData = useRouteLoaderData<RootLoaderTypes>("root");
|
|
const data: PostWithRelations[] = useLoaderData<LoaderFunction>();
|
|
const errors = useActionData<ActionFunction>();
|
|
|
|
console.log(data);
|
|
|
|
return (
|
|
<div className="flex flex-col gap-5">
|
|
<Title>Home</Title>
|
|
<Card>
|
|
{rootData?.id ? (
|
|
<>
|
|
<Title>New post</Title>
|
|
<Form className="flex flex-col gap-3" method="POST">
|
|
<input type="hidden" name="intent" value={"newpost"} />
|
|
<FormLabel>
|
|
<Text>Post body</Text>
|
|
<TextArea name="post" />
|
|
<Text type="error">{errors?.body ? errors.body : ""}</Text>
|
|
</FormLabel>
|
|
<Button type="submit">Post</Button>
|
|
</Form>
|
|
</>
|
|
) : (
|
|
<>
|
|
<Title>Twitter clone</Title>
|
|
<SubTitle>Made with Remix</SubTitle>
|
|
</>
|
|
)}
|
|
</Card>
|
|
<SubTitle>Feed</SubTitle>
|
|
{data.length > 0 ? (
|
|
<Card className="!p-0 !gap-0 divide-y">
|
|
{data.map((post: PostWithRelations) => (
|
|
<Post userId={rootData?.id} key={post.id} post={post} />
|
|
))}
|
|
</Card>
|
|
) : (
|
|
<Text type="error">
|
|
Feed is empty, follow someone so their recent posts will show up here!
|
|
</Text>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|