A lot of code trying to make the replies work (I can't recursively show all parent replies because Prisma hasn't implemented recursive relation includes after 2 years of the initial request, which sucks)
This commit is contained in:
parent
364d3a1917
commit
1e632c52be
|
@ -3,9 +3,8 @@ import { Button } from "./Button";
|
|||
import { Card } from "./Card";
|
||||
import { FormLabel, TextArea } from "./Form";
|
||||
import { SubTitle, Text } from "./Typography";
|
||||
import type { User } from "@prisma/client";
|
||||
import type { PostWithRelations } from "~/utils/prisma.server";
|
||||
import { ReactNode } from "react";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
export function Poster({
|
||||
username,
|
||||
|
@ -72,11 +71,17 @@ export function Post({
|
|||
userId,
|
||||
post,
|
||||
topTitle,
|
||||
child,
|
||||
reply,
|
||||
enlarge,
|
||||
rootPostId,
|
||||
}: {
|
||||
post: PostWithRelations;
|
||||
userId?: number;
|
||||
topTitle?: ReactNode;
|
||||
child?: boolean;
|
||||
reply?: boolean;
|
||||
enlarge?: boolean;
|
||||
rootPostId?: number;
|
||||
}) {
|
||||
const fetcher = useFetcher();
|
||||
|
@ -86,103 +91,175 @@ export function Post({
|
|||
|
||||
return (
|
||||
<>
|
||||
{post?.parentReply ? (
|
||||
<Post post={post.parentReply} userId={userId} rootPostId={rootPostId} />
|
||||
{post?.parentReply?.text ? (
|
||||
<>
|
||||
<Post
|
||||
post={post.parentReply}
|
||||
userId={userId}
|
||||
child={true}
|
||||
reply={true}
|
||||
rootPostId={rootPostId}
|
||||
topTitle={
|
||||
<>
|
||||
Replying to{" "}
|
||||
{post.parentReply.parentReply ? (
|
||||
<Poster
|
||||
style="compact"
|
||||
username={post.parentReply.parentReply.author.username}
|
||||
name={post.parentReply.parentReply.author.name}
|
||||
pfp={post.parentReply.parentReply.author.pfp}
|
||||
/>
|
||||
) : (
|
||||
<Poster
|
||||
style="compact"
|
||||
username={post.parentReply.post.author.username}
|
||||
name={post.parentReply.post.author.name}
|
||||
pfp={post.parentReply.post.author.pfp}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<div className="h-8 pl-[39px]">
|
||||
<div className="border w-0 h-full"></div>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<div
|
||||
key={post.id}
|
||||
className="flex relative flex-col gap-4 p-6 transition-all bg-ctp-mantle/20 hover:bg-ctp-base first:rounded-t-lg last:rounded-b-lg "
|
||||
className={`flex relative flex-col ${
|
||||
enlarge ? "text-xl" : ""
|
||||
} gap-4 transition-all bg-ctp-mantle/20 hover:bg-ctp-base first:rounded-t-lg last:rounded-b-lg`}
|
||||
>
|
||||
{topTitle ? <Text type="subtitle">{topTitle}</Text> : ""}
|
||||
{post.reposters?.length > 0 ? (
|
||||
<div className="flex gap-2 items-center">
|
||||
{post.reposters.map((user) => (
|
||||
<Poster
|
||||
style="compact"
|
||||
key={user.id}
|
||||
name={user.name}
|
||||
username={user.username}
|
||||
pfp={user.pfp}
|
||||
<div
|
||||
className={` ${!child && reply ? `border-y py-4` : ""} ${
|
||||
!reply ? "!p-4" : ""
|
||||
} px-4`}
|
||||
>
|
||||
<div className="flex gap-4">
|
||||
<div className="flex flex-col justify-center items-center min-h-full">
|
||||
<img
|
||||
className="w-12 h-12 rounded-full"
|
||||
src={`/uploads/${post.author.pfp}`}
|
||||
alt=""
|
||||
/>
|
||||
))}
|
||||
<Text type="subtitle">reposted this</Text>
|
||||
</div>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<div className="flex items-center">
|
||||
<Poster
|
||||
pfp={post.author.pfp}
|
||||
username={post.author.username}
|
||||
name={post.author.name}
|
||||
/>
|
||||
</div>
|
||||
<Link to={`/${rootPostId ? "reply" : "post"}/${post.id}`}>
|
||||
<div>
|
||||
<Text>{post.text}</Text>
|
||||
</div>
|
||||
</Link>
|
||||
<div className="flex gap-2 text-sm">
|
||||
<Text>{new Date(post.createdAt).toLocaleDateString()}</Text>
|
||||
<fetcher.Form action={`/home`} method="POST">
|
||||
<input
|
||||
type="hidden"
|
||||
name="intent"
|
||||
value={liked ? "unlike" : "like"}
|
||||
/>
|
||||
<input type="hidden" name="postId" value={post.id} />
|
||||
<button type="submit">
|
||||
<Text type="link">
|
||||
{liked ? "Unlike" : "Like"} ({post.likes.length})
|
||||
</Text>
|
||||
</button>
|
||||
</fetcher.Form>
|
||||
<fetcher.Form action={`/home`} method="POST">
|
||||
<input
|
||||
type="hidden"
|
||||
name="intent"
|
||||
value={reposted ? "unrepost" : "repost"}
|
||||
/>
|
||||
<input type="hidden" name="postId" value={post.id} />
|
||||
<button type="submit">
|
||||
<Text type="link">
|
||||
{reposted ? "Unrepost" : "Repost"} ({post.reposts.length})
|
||||
</Text>
|
||||
</button>
|
||||
</fetcher.Form>
|
||||
<details className="space-y-2">
|
||||
<summary className="flex cursor-pointer">
|
||||
<Text type="link">
|
||||
Reply ({post._count.replies}
|
||||
{post._count.childReplies})
|
||||
</Text>
|
||||
</summary>
|
||||
<Card className="absolute max-w-xs z-100">
|
||||
<SubTitle>Reply to {post.author.username}</SubTitle>
|
||||
<fetcher.Form
|
||||
action={`/home`}
|
||||
className="flex flex-col gap-3"
|
||||
method="POST"
|
||||
>
|
||||
<input type="hidden" name="intent" value={"reply"} />
|
||||
{rootPostId ? (
|
||||
<>
|
||||
<input type="hidden" name="postId" value={rootPostId} />
|
||||
<input type="hidden" name="replyId" value={post.id} />
|
||||
</>
|
||||
{child ? <div className="w-0 border h-full"></div> : ""}
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<div className="flex flex-col gap-2">
|
||||
{post.reposters?.length > 0 ? (
|
||||
<div className="flex gap-2 items-center">
|
||||
{post.reposters.map((user) => (
|
||||
<Poster
|
||||
style="compact"
|
||||
key={user.id}
|
||||
name={user.name}
|
||||
username={user.username}
|
||||
pfp={user.pfp}
|
||||
/>
|
||||
))}
|
||||
<Text type="subtitle">reposted this</Text>
|
||||
</div>
|
||||
) : (
|
||||
<input type="hidden" name="postId" value={post.id} />
|
||||
""
|
||||
)}
|
||||
<FormLabel>
|
||||
<Text>Reply body</Text>
|
||||
<TextArea name="reply" />
|
||||
</FormLabel>
|
||||
<Button type="submit">Post</Button>
|
||||
</fetcher.Form>
|
||||
</Card>
|
||||
</details>
|
||||
{topTitle ? (
|
||||
<Text className="flex gap-1" type="subtitle">
|
||||
{topTitle}
|
||||
</Text>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<div className="flex gap-2">
|
||||
{post.author.name ? (
|
||||
<>
|
||||
<SubTitle>{post.author.name}</SubTitle>
|
||||
<Link to={`/users/${post.author.username}`}>
|
||||
<Text type="link">@{post.author.username}</Text>
|
||||
</Link>
|
||||
</>
|
||||
) : (
|
||||
<SubTitle>
|
||||
<Link to={`/users/${post.author.username}`}>
|
||||
<Text type="link">@{post.author.username}</Text>
|
||||
</Link>
|
||||
</SubTitle>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<Link to={`/${rootPostId ? "reply" : "post"}/${post.id}`}>
|
||||
<div>
|
||||
<Text>{post.text}</Text>
|
||||
</div>
|
||||
</Link>
|
||||
<div className="flex gap-2 text-sm">
|
||||
<Text>{new Date(post.createdAt).toLocaleDateString()}</Text>
|
||||
<fetcher.Form action={`/home`} method="POST">
|
||||
<input
|
||||
type="hidden"
|
||||
name="intent"
|
||||
value={liked ? "unlike" : "like"}
|
||||
/>
|
||||
<input type="hidden" name="postId" value={post.id} />
|
||||
<button type="submit">
|
||||
<Text type="link">
|
||||
{liked ? "Unlike" : "Like"} ({post.likes.length})
|
||||
</Text>
|
||||
</button>
|
||||
</fetcher.Form>
|
||||
<fetcher.Form action={`/home`} method="POST">
|
||||
<input
|
||||
type="hidden"
|
||||
name="intent"
|
||||
value={reposted ? "unrepost" : "repost"}
|
||||
/>
|
||||
<input type="hidden" name="postId" value={post.id} />
|
||||
<button type="submit">
|
||||
<Text type="link">
|
||||
{reposted ? "Unrepost" : "Repost"} ({post.reposts.length})
|
||||
</Text>
|
||||
</button>
|
||||
</fetcher.Form>
|
||||
<details className="space-y-2">
|
||||
<summary className="flex cursor-pointer">
|
||||
<Text type="link">
|
||||
Reply ({post._count.replies}
|
||||
{post._count.childReplies})
|
||||
</Text>
|
||||
</summary>
|
||||
<Card className="absolute max-w-xs z-100">
|
||||
<SubTitle>Reply to {post.author.username}</SubTitle>
|
||||
<fetcher.Form
|
||||
action={`/home`}
|
||||
className="flex flex-col gap-3"
|
||||
method="POST"
|
||||
>
|
||||
<input type="hidden" name="intent" value={"reply"} />
|
||||
{rootPostId ? (
|
||||
<>
|
||||
<input
|
||||
type="hidden"
|
||||
name="postId"
|
||||
value={rootPostId}
|
||||
/>
|
||||
<input type="hidden" name="replyId" value={post.id} />
|
||||
</>
|
||||
) : (
|
||||
<input type="hidden" name="postId" value={post.id} />
|
||||
)}
|
||||
<FormLabel>
|
||||
<Text>Reply body</Text>
|
||||
<TextArea name="reply" />
|
||||
</FormLabel>
|
||||
<Button type="submit">Post</Button>
|
||||
</fetcher.Form>
|
||||
</Card>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
@ -14,7 +14,7 @@ import { Card } from "~/components/Card";
|
|||
import { SubTitle, Text, Title } from "~/components/Typography";
|
||||
import type { PostWithRelations } from "~/utils/prisma.server";
|
||||
import { prisma } from "~/utils/prisma.server";
|
||||
import { Post } from "~/components/Post";
|
||||
import { Post, Poster } from "~/components/Post";
|
||||
import type { RootLoaderTypes } from "~/root";
|
||||
import { Button } from "~/components/Button";
|
||||
import { FormLabel, TextArea } from "~/components/Form";
|
||||
|
@ -166,9 +166,14 @@ export default function PostRoute() {
|
|||
return (
|
||||
<div className="flex flex-col gap-5">
|
||||
<Title>Post</Title>
|
||||
<Card className="!p-0 !gap-0 divide-y">
|
||||
<div className="bg-ctp-pink/5">
|
||||
<Post key={data.id} post={data} userId={rootData?.id} />
|
||||
<Card className="!p-0 !gap-0">
|
||||
<div className="border-b">
|
||||
<Post
|
||||
key={data.id}
|
||||
post={data}
|
||||
enlarge={true}
|
||||
userId={rootData?.id}
|
||||
/>
|
||||
</div>
|
||||
{rootData?.id ? (
|
||||
<div className="p-6 !bg-ctp-sky/5">
|
||||
|
@ -192,7 +197,23 @@ export default function PostRoute() {
|
|||
)}
|
||||
{data.replies.map((reply) => (
|
||||
<div key={reply.id}>
|
||||
<Post post={reply} userId={rootData?.id} rootPostId={data.id} />
|
||||
<Post
|
||||
post={reply}
|
||||
userId={rootData?.id}
|
||||
rootPostId={data.id}
|
||||
reply={true}
|
||||
topTitle={
|
||||
<Text className="flex gap-1" type="subtitle">
|
||||
Replying to{" "}
|
||||
<Poster
|
||||
style="compact"
|
||||
username={data.author.username}
|
||||
name={data.author.name}
|
||||
pfp={data.author.pfp}
|
||||
/>
|
||||
</Text>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</Card>
|
||||
|
|
|
@ -14,7 +14,7 @@ import { Card } from "~/components/Card";
|
|||
import { SubTitle, Text, Title } from "~/components/Typography";
|
||||
import type { PostWithRelations } from "~/utils/prisma.server";
|
||||
import { prisma } from "~/utils/prisma.server";
|
||||
import { Post } from "~/components/Post";
|
||||
import { Post, Poster } from "~/components/Post";
|
||||
import type { RootLoaderTypes } from "~/root";
|
||||
import { Button } from "~/components/Button";
|
||||
import { FormLabel, TextArea } from "~/components/Form";
|
||||
|
@ -53,26 +53,6 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
|
|||
id: true,
|
||||
text: true,
|
||||
createdAt: true,
|
||||
author: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
name: true,
|
||||
pfp: true,
|
||||
},
|
||||
},
|
||||
likes: {
|
||||
select: {
|
||||
id: true,
|
||||
userId: true,
|
||||
},
|
||||
},
|
||||
reposts: {
|
||||
select: {
|
||||
id: true,
|
||||
userId: true,
|
||||
},
|
||||
},
|
||||
parentReply: {
|
||||
select: {
|
||||
id: true,
|
||||
|
@ -86,6 +66,42 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
|
|||
pfp: true,
|
||||
},
|
||||
},
|
||||
post: {
|
||||
include: {
|
||||
author: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
name: true,
|
||||
pfp: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
parentReply: {
|
||||
select: {
|
||||
author: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
name: true,
|
||||
pfp: true,
|
||||
},
|
||||
},
|
||||
post: {
|
||||
include: {
|
||||
author: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
name: true,
|
||||
pfp: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
likes: {
|
||||
select: {
|
||||
id: true,
|
||||
|
@ -105,6 +121,74 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
|
|||
},
|
||||
},
|
||||
},
|
||||
author: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
name: true,
|
||||
pfp: true,
|
||||
},
|
||||
},
|
||||
likes: {
|
||||
select: {
|
||||
id: true,
|
||||
userId: true,
|
||||
},
|
||||
},
|
||||
post: {
|
||||
select: {
|
||||
id: true,
|
||||
text: true,
|
||||
createdAt: true,
|
||||
likes: {
|
||||
select: {
|
||||
id: true,
|
||||
userId: true,
|
||||
postId: true,
|
||||
user: {
|
||||
select: {
|
||||
username: true,
|
||||
name: true,
|
||||
pfp: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
reposts: {
|
||||
select: {
|
||||
id: true,
|
||||
userId: true,
|
||||
postId: true,
|
||||
user: {
|
||||
select: {
|
||||
username: true,
|
||||
name: true,
|
||||
pfp: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
author: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
name: true,
|
||||
pfp: true,
|
||||
},
|
||||
},
|
||||
_count: {
|
||||
select: {
|
||||
replies: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
reposts: {
|
||||
select: {
|
||||
id: true,
|
||||
userId: true,
|
||||
},
|
||||
},
|
||||
_count: {
|
||||
select: {
|
||||
childReplies: true,
|
||||
|
@ -257,20 +341,49 @@ export default function ReplyRoute() {
|
|||
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>Post</Title>
|
||||
<Card className="!p-0 !gap-0 divide-y">
|
||||
<div className="text-sm">
|
||||
<Post key={data.id} post={data.post} userId={rootData?.id} />
|
||||
<Card className="!p-0 !pt-6 !gap-0">
|
||||
<Post
|
||||
post={data.post}
|
||||
userId={rootData?.id}
|
||||
child={true}
|
||||
reply={true}
|
||||
/>
|
||||
<div className="h-8 pl-[39px]">
|
||||
<div className="border w-0 h-full"></div>
|
||||
</div>
|
||||
<div className="text-xl bg-ctp-pink/5">
|
||||
<div>
|
||||
<Post
|
||||
key={data.id}
|
||||
post={data}
|
||||
userId={rootData?.id}
|
||||
rootPostId={data.post.id}
|
||||
enlarge={true}
|
||||
reply={true}
|
||||
topTitle={
|
||||
<>
|
||||
Replying to
|
||||
{data.parentReply ? (
|
||||
<Poster
|
||||
style="compact"
|
||||
username={data.parentReply.author.username}
|
||||
name={data.parentReply.author.name}
|
||||
pfp={data.parentReply.author.pfp}
|
||||
/>
|
||||
) : (
|
||||
<Poster
|
||||
style="compact"
|
||||
username={data.post.author.username}
|
||||
name={data.post.author.name}
|
||||
pfp={data.post.author.pfp}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
{rootData?.id ? (
|
||||
|
@ -300,6 +413,7 @@ export default function ReplyRoute() {
|
|||
post={reply}
|
||||
userId={rootData?.id}
|
||||
rootPostId={data.post.id}
|
||||
reply={true}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
|
|
Loading…
Reference in New Issue