import { prisma, type PostWithRelations } from "~/utils/prisma.server"; import type { ActionFunction, ActionFunctionArgs, LoaderFunction, LoaderFunctionArgs, MetaFunction, } from "@remix-run/node"; import { json, redirect } from "@remix-run/node"; import { Form, Link, 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 { like, unLike } from "~/models/like.server"; import { createPost } from "~/models/post.server"; import { commitSession, getSession } from "~/utils/session.server"; import type { RootLoaderTypes } from "~/root"; import { repost, unRepost } from "~/models/repost.server"; import { reply } from "~/models/reply.server"; export const meta: MetaFunction = () => { return [{ title: `Home | Twitter Clone` }]; }; 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 like( Number(formData.postId), userId, Number(formData.replyId) ); if (Object.values(likeErrors).some(Boolean)) { return likeErrors; } session.flash("globalMessage", "Post liked!"); break; case "unlike": const unLikeErrors = await unLike( Number(formData.postId), userId, Number(formData.replyId) ); if (Object.values(unLikeErrors).some(Boolean)) { return unLikeErrors; } session.flash("globalMessage", "Post un-liked!"); break; case "repost": const repostErrors = await repost( Number(formData.postId), userId, Number(formData.replyId) ); if (Object.values(repostErrors).some(Boolean)) { return repostErrors; } session.flash("globalMessage", "Post reposted!"); break; case "unrepost": const unrepostErrors = await unRepost( Number(formData.postId), userId, Number(formData.replyId) ); if (Object.values(unrepostErrors).some(Boolean)) { return unrepostErrors; } session.flash("globalMessage", "Post un-reposted!"); break; case "reply": const replyErrors = await reply( String(formData.reply), Number(formData.postId), Number(formData.replyId), userId ); if (Object.values(replyErrors).some(Boolean)) { return replyErrors; } session.flash("globalMessage", "Replied to post!"); 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("/"); } const userId = session.get("userId"); const following = await prisma.user.findFirst({ where: { id: userId }, select: { following: { select: { id: true } } }, }); const followingArr = [...following.following.map((user) => user.id)]; const feed = await prisma.post.findMany({ where: { OR: [ { userId: { in: followingArr, }, }, { reposts: { some: { userId: { in: followingArr, }, }, }, }, ], }, select: { id: true, text: true, createdAt: true, author: { select: { username: true, name: true, pfp: true, }, }, reposts: { select: { userId: true, user: { select: { id: true, username: true, pfp: true, name: true, }, }, }, }, likes: { select: { userId: true, user: { select: { id: true, username: true, pfp: true, name: true, }, }, }, }, _count: { select: { replies: { where: { parentReplyId: null, }, }, }, }, }, orderBy: { createdAt: "desc", }, }); feed.forEach((post) => { const filter = post.reposts.filter((user) => followingArr.includes(user.userId) ); const reposters = filter.map((repost) => repost.user); post.reposters = reposters; }); return feed; } export default function Index() { const rootData = useRouteLoaderData("root"); const data: PostWithRelations[] = useLoaderData(); const errors = useActionData(); return (
Home {rootData?.id ? ( <> New post
Post body