Add like and repost functionality to replies, show them properly in the user pages, sort classnames. Basic functionality pretty much done now
This commit is contained in:
parent
07df91cb5d
commit
486002b0bc
|
@ -135,7 +135,7 @@ export function Post({
|
|||
key={post.id}
|
||||
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`}
|
||||
} gap-4 transition-all hover:bg-ctp-base first:rounded-t-lg last:rounded-b-lg`}
|
||||
>
|
||||
<div
|
||||
className={` ${!child && reply ? `border-y py-4` : ""} ${
|
||||
|
@ -155,7 +155,7 @@ export function Post({
|
|||
</div>
|
||||
<div className="flex relative flex-col gap-2 w-full">
|
||||
<div className="absolute right-0">
|
||||
<Text className="subtitle text-[12px] text-ctp-subtext1/25">
|
||||
<Text className="subtitle text-[12px] text-ctp-subtext1/30">
|
||||
{new Date(post.createdAt).toLocaleDateString("en-fi", {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
|
@ -225,7 +225,11 @@ export function Post({
|
|||
name="intent"
|
||||
value={liked ? "unlike" : "like"}
|
||||
/>
|
||||
<input type="hidden" name="postId" value={post.id} />
|
||||
<input
|
||||
type="hidden"
|
||||
name={rootPostId ? "replyId" : "postId"}
|
||||
value={post.id}
|
||||
/>
|
||||
<button type="submit">
|
||||
<Text type="link">
|
||||
{liked ? "Unlike" : "Like"} ({post.likes.length})
|
||||
|
@ -238,7 +242,11 @@ export function Post({
|
|||
name="intent"
|
||||
value={reposted ? "unrepost" : "repost"}
|
||||
/>
|
||||
<input type="hidden" name="postId" value={post.id} />
|
||||
<input
|
||||
type="hidden"
|
||||
name={rootPostId ? "replyId" : "postId"}
|
||||
value={post.id}
|
||||
/>
|
||||
<button type="submit">
|
||||
<Text type="link">
|
||||
{reposted ? "Unrepost" : "Repost"} ({post.reposts.length})
|
||||
|
|
|
@ -1,86 +1,179 @@
|
|||
import { prisma } from "~/utils/prisma.server";
|
||||
import { getPostById } from "./post.server";
|
||||
import { getReplyById, reply } from "./reply.server";
|
||||
|
||||
interface PostErrors {
|
||||
postId: string | undefined;
|
||||
like: string | undefined;
|
||||
}
|
||||
|
||||
export async function likePost(postId: number, id: number) {
|
||||
const errors: PostErrors = {
|
||||
postId: undefined,
|
||||
like: undefined,
|
||||
};
|
||||
|
||||
const post = await getPostById(postId);
|
||||
if (!post) {
|
||||
errors.postId = "No post with that id";
|
||||
}
|
||||
|
||||
const like = await prisma.like.findFirst({
|
||||
where: {
|
||||
userId: id,
|
||||
postId: postId,
|
||||
},
|
||||
});
|
||||
if (like) {
|
||||
errors.like = "You have already liked that post";
|
||||
}
|
||||
|
||||
if (Object.values(errors).some(Boolean)) {
|
||||
return errors;
|
||||
}
|
||||
|
||||
const likeQ = await prisma.like.create({
|
||||
data: {
|
||||
postId: postId,
|
||||
userId: id,
|
||||
},
|
||||
});
|
||||
|
||||
if (!likeQ) {
|
||||
errors.like = "Something went wrong liking the post";
|
||||
return errors;
|
||||
}
|
||||
|
||||
return errors;
|
||||
interface ReplyErrors {
|
||||
replyId: string | undefined;
|
||||
reply: string | undefined;
|
||||
}
|
||||
|
||||
export async function unLikePost(postId: number, id: number) {
|
||||
const errors: PostErrors = {
|
||||
postId: undefined,
|
||||
like: undefined,
|
||||
};
|
||||
export async function like(
|
||||
postId: number,
|
||||
id: number,
|
||||
replyId: number | undefined
|
||||
) {
|
||||
if (replyId) {
|
||||
const errors: ReplyErrors = {
|
||||
replyId: undefined,
|
||||
reply: undefined,
|
||||
};
|
||||
|
||||
const post = await getPostById(postId);
|
||||
if (!post) {
|
||||
errors.postId = "No post with that id";
|
||||
}
|
||||
const post = await getReplyById(replyId);
|
||||
if (!post) {
|
||||
errors.replyId = "No reply with that id";
|
||||
}
|
||||
|
||||
const like = await prisma.like.findFirst({
|
||||
where: {
|
||||
userId: id,
|
||||
postId: postId,
|
||||
},
|
||||
});
|
||||
if (!like) {
|
||||
errors.like = "Like doesn't exist";
|
||||
}
|
||||
const reply = await prisma.like.findFirst({
|
||||
where: {
|
||||
userId: id,
|
||||
replyId: replyId,
|
||||
},
|
||||
});
|
||||
if (reply) {
|
||||
errors.reply = "You have already liked that reply";
|
||||
}
|
||||
|
||||
if (Object.values(errors).some(Boolean)) {
|
||||
return errors;
|
||||
}
|
||||
|
||||
const replyQ = await prisma.like.create({
|
||||
data: {
|
||||
replyId: replyId,
|
||||
userId: id,
|
||||
},
|
||||
});
|
||||
|
||||
if (!replyQ) {
|
||||
errors.reply = "Something went wrong liking the post";
|
||||
return errors;
|
||||
}
|
||||
|
||||
return errors;
|
||||
} else {
|
||||
const errors: PostErrors = {
|
||||
postId: undefined,
|
||||
like: undefined,
|
||||
};
|
||||
|
||||
const post = await getPostById(postId);
|
||||
if (!post) {
|
||||
errors.postId = "No post with that id";
|
||||
}
|
||||
|
||||
const like = await prisma.like.findFirst({
|
||||
where: {
|
||||
userId: id,
|
||||
postId: postId,
|
||||
},
|
||||
});
|
||||
if (like) {
|
||||
errors.like = "You have already liked that post";
|
||||
}
|
||||
|
||||
if (Object.values(errors).some(Boolean)) {
|
||||
return errors;
|
||||
}
|
||||
|
||||
const likeQ = await prisma.like.create({
|
||||
data: {
|
||||
postId: postId,
|
||||
userId: id,
|
||||
},
|
||||
});
|
||||
|
||||
if (!likeQ) {
|
||||
errors.like = "Something went wrong liking the post";
|
||||
return errors;
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
|
||||
export async function unLike(
|
||||
postId: number,
|
||||
id: number,
|
||||
replyId: number | undefined
|
||||
) {
|
||||
if (replyId) {
|
||||
const errors: ReplyErrors = {
|
||||
replyId: undefined,
|
||||
reply: undefined,
|
||||
};
|
||||
|
||||
const reply = await getReplyById(replyId);
|
||||
if (!reply) {
|
||||
errors.replyId = "No post with that id";
|
||||
}
|
||||
|
||||
const like = await prisma.like.findFirst({
|
||||
where: {
|
||||
userId: id,
|
||||
replyId: replyId,
|
||||
},
|
||||
});
|
||||
if (!like) {
|
||||
errors.reply = "Like doesn't exist";
|
||||
}
|
||||
|
||||
if (Object.values(errors).some(Boolean)) {
|
||||
return errors;
|
||||
}
|
||||
|
||||
const replyQ = await prisma.like.delete({
|
||||
where: {
|
||||
id: like.id,
|
||||
},
|
||||
});
|
||||
|
||||
if (!replyQ) {
|
||||
errors.reply = "Something went wrong unliking the post";
|
||||
return errors;
|
||||
}
|
||||
|
||||
return errors;
|
||||
} else {
|
||||
const errors: PostErrors = {
|
||||
postId: undefined,
|
||||
like: undefined,
|
||||
};
|
||||
|
||||
const post = await getPostById(postId);
|
||||
if (!post) {
|
||||
errors.postId = "No post with that id";
|
||||
}
|
||||
|
||||
const like = await prisma.like.findFirst({
|
||||
where: {
|
||||
userId: id,
|
||||
postId: postId,
|
||||
},
|
||||
});
|
||||
if (!like) {
|
||||
errors.like = "Like doesn't exist";
|
||||
}
|
||||
|
||||
if (Object.values(errors).some(Boolean)) {
|
||||
return errors;
|
||||
}
|
||||
|
||||
const likeQ = await prisma.like.delete({
|
||||
where: {
|
||||
id: like.id,
|
||||
},
|
||||
});
|
||||
|
||||
if (!likeQ) {
|
||||
errors.like = "Something went wrong unliking the post";
|
||||
return errors;
|
||||
}
|
||||
|
||||
if (Object.values(errors).some(Boolean)) {
|
||||
return errors;
|
||||
}
|
||||
|
||||
const likeQ = await prisma.like.delete({
|
||||
where: {
|
||||
id: like.id,
|
||||
},
|
||||
});
|
||||
|
||||
if (!likeQ) {
|
||||
errors.like = "Something went wrong unliking the post";
|
||||
return errors;
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ import { prisma } from "~/utils/prisma.server";
|
|||
import { getPostById, validatePostBody } from "./post.server";
|
||||
import type { Reply } from "@prisma/client";
|
||||
|
||||
async function getReplyById(id: number) {
|
||||
export async function getReplyById(id: number) {
|
||||
const reply = await prisma.reply.findUnique({
|
||||
where: {
|
||||
id: id,
|
||||
|
|
|
@ -1,76 +1,159 @@
|
|||
import { prisma } from "~/utils/prisma.server";
|
||||
import { getPostById } from "./post.server";
|
||||
import { getReplyById } from "./reply.server";
|
||||
|
||||
export async function repost(postId: number, id: number) {
|
||||
const errors = {};
|
||||
export async function repost(
|
||||
postId: number,
|
||||
id: number,
|
||||
replyId: number | undefined
|
||||
) {
|
||||
if (replyId) {
|
||||
const errors = {};
|
||||
|
||||
const post = await getPostById(postId);
|
||||
const reply = await getReplyById(replyId);
|
||||
|
||||
if (!post) {
|
||||
errors.repost = "Post doesn't exist";
|
||||
}
|
||||
if (!reply) {
|
||||
errors.repost = "Post doesn't exist";
|
||||
}
|
||||
|
||||
const repost = await prisma.repost.findFirst({
|
||||
where: {
|
||||
postId: postId,
|
||||
userId: id,
|
||||
},
|
||||
});
|
||||
const repost = await prisma.repost.findFirst({
|
||||
where: {
|
||||
replyId: replyId,
|
||||
userId: id,
|
||||
},
|
||||
});
|
||||
|
||||
if (repost) {
|
||||
errors.repost = "You have already reposted that post";
|
||||
}
|
||||
if (repost) {
|
||||
errors.repost = "You have already reposted that reply";
|
||||
}
|
||||
|
||||
if (Object.values(errors).some(Boolean)) {
|
||||
return errors;
|
||||
}
|
||||
|
||||
const repostQ = await prisma.repost.create({
|
||||
data: {
|
||||
userId: id,
|
||||
replyId: replyId,
|
||||
},
|
||||
});
|
||||
|
||||
if (!repostQ) {
|
||||
errors.repost = "Something went wrong";
|
||||
}
|
||||
|
||||
return errors;
|
||||
} else {
|
||||
const errors = {};
|
||||
|
||||
const post = await getPostById(postId);
|
||||
|
||||
if (!post) {
|
||||
errors.repost = "Post doesn't exist";
|
||||
}
|
||||
|
||||
const repost = await prisma.repost.findFirst({
|
||||
where: {
|
||||
postId: postId,
|
||||
userId: id,
|
||||
},
|
||||
});
|
||||
|
||||
if (repost) {
|
||||
errors.repost = "You have already reposted that post";
|
||||
}
|
||||
|
||||
if (Object.values(errors).some(Boolean)) {
|
||||
return errors;
|
||||
}
|
||||
|
||||
const repostQ = await prisma.repost.create({
|
||||
data: {
|
||||
userId: id,
|
||||
postId: postId,
|
||||
},
|
||||
});
|
||||
|
||||
if (!repostQ) {
|
||||
errors.repost = "Something went wrong";
|
||||
}
|
||||
|
||||
if (Object.values(errors).some(Boolean)) {
|
||||
return errors;
|
||||
}
|
||||
|
||||
const repostQ = await prisma.repost.create({
|
||||
data: {
|
||||
userId: id,
|
||||
postId: postId,
|
||||
},
|
||||
});
|
||||
|
||||
if (!repostQ) {
|
||||
errors.repost = "Something went wrong";
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
export async function unRepost(postId: number, id: number) {
|
||||
const errors = {};
|
||||
export async function unRepost(
|
||||
postId: number,
|
||||
id: number,
|
||||
replyId: number | undefined
|
||||
) {
|
||||
if (replyId) {
|
||||
const errors = {};
|
||||
|
||||
const post = await getPostById(postId);
|
||||
if (!post) {
|
||||
errors.repost = "Post doesn't exist";
|
||||
}
|
||||
const reply = await getReplyById(replyId);
|
||||
if (!reply) {
|
||||
errors.repost = "Reply doesn't exist";
|
||||
}
|
||||
|
||||
const repost = await prisma.repost.findFirst({
|
||||
where: {
|
||||
userId: id,
|
||||
postId: postId,
|
||||
},
|
||||
});
|
||||
const repost = await prisma.repost.findFirst({
|
||||
where: {
|
||||
userId: id,
|
||||
replyId: replyId,
|
||||
},
|
||||
});
|
||||
|
||||
if (!repost) {
|
||||
errors.repost = "Repost doesn't exist";
|
||||
}
|
||||
if (!repost) {
|
||||
errors.repost = "Repost doesn't exist";
|
||||
}
|
||||
|
||||
if (Object.values(errors).some(Boolean)) {
|
||||
return errors;
|
||||
}
|
||||
|
||||
const repostQ = await prisma.repost.delete({
|
||||
where: {
|
||||
id: repost.id,
|
||||
},
|
||||
});
|
||||
|
||||
if (!repostQ) {
|
||||
errors.repost = "Something went wrong";
|
||||
}
|
||||
|
||||
return errors;
|
||||
} else {
|
||||
const errors = {};
|
||||
|
||||
const post = await getPostById(postId);
|
||||
if (!post) {
|
||||
errors.repost = "Post doesn't exist";
|
||||
}
|
||||
|
||||
const repost = await prisma.repost.findFirst({
|
||||
where: {
|
||||
userId: id,
|
||||
postId: postId,
|
||||
},
|
||||
});
|
||||
|
||||
if (!repost) {
|
||||
errors.repost = "Repost doesn't exist";
|
||||
}
|
||||
|
||||
if (Object.values(errors).some(Boolean)) {
|
||||
return errors;
|
||||
}
|
||||
|
||||
const repostQ = await prisma.repost.delete({
|
||||
where: {
|
||||
id: repost.id,
|
||||
},
|
||||
});
|
||||
|
||||
if (!repostQ) {
|
||||
errors.repost = "Something went wrong";
|
||||
}
|
||||
|
||||
if (Object.values(errors).some(Boolean)) {
|
||||
return errors;
|
||||
}
|
||||
|
||||
const repostQ = await prisma.repost.delete({
|
||||
where: {
|
||||
id: repost.id,
|
||||
},
|
||||
});
|
||||
|
||||
if (!repostQ) {
|
||||
errors.repost = "Something went wrong";
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ 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 { like, unLike } from "~/models/like.server";
|
||||
import { createPost } from "~/models/post.server";
|
||||
import { commitSession, getSession } from "~/utils/session.server";
|
||||
import type { RootLoaderTypes } from "~/root";
|
||||
|
@ -54,7 +54,11 @@ export async function action({ request }: ActionFunctionArgs) {
|
|||
|
||||
break;
|
||||
case "like":
|
||||
const likeErrors = await likePost(Number(formData.postId), userId);
|
||||
const likeErrors = await like(
|
||||
Number(formData.postId),
|
||||
userId,
|
||||
Number(formData.replyId)
|
||||
);
|
||||
|
||||
if (Object.values(likeErrors).some(Boolean)) {
|
||||
return likeErrors;
|
||||
|
@ -64,7 +68,11 @@ export async function action({ request }: ActionFunctionArgs) {
|
|||
|
||||
break;
|
||||
case "unlike":
|
||||
const unLikeErrors = await unLikePost(Number(formData.postId), userId);
|
||||
const unLikeErrors = await unLike(
|
||||
Number(formData.postId),
|
||||
userId,
|
||||
Number(formData.replyId)
|
||||
);
|
||||
|
||||
if (Object.values(unLikeErrors).some(Boolean)) {
|
||||
return unLikeErrors;
|
||||
|
@ -74,7 +82,11 @@ export async function action({ request }: ActionFunctionArgs) {
|
|||
|
||||
break;
|
||||
case "repost":
|
||||
const repostErrors = await repost(Number(formData.postId), userId);
|
||||
const repostErrors = await repost(
|
||||
Number(formData.postId),
|
||||
userId,
|
||||
Number(formData.replyId)
|
||||
);
|
||||
|
||||
if (Object.values(repostErrors).some(Boolean)) {
|
||||
return repostErrors;
|
||||
|
@ -84,7 +96,11 @@ export async function action({ request }: ActionFunctionArgs) {
|
|||
|
||||
break;
|
||||
case "unrepost":
|
||||
const unrepostErrors = await unRepost(Number(formData.postId), userId);
|
||||
const unrepostErrors = await unRepost(
|
||||
Number(formData.postId),
|
||||
userId,
|
||||
Number(formData.replyId)
|
||||
);
|
||||
|
||||
if (Object.values(unrepostErrors).some(Boolean)) {
|
||||
return unrepostErrors;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import type { ActionFunction } from "@remix-run/node";
|
||||
import {
|
||||
json,
|
||||
type LoaderFunction,
|
||||
type LoaderFunctionArgs,
|
||||
type ActionFunction,
|
||||
} from "@remix-run/node";
|
||||
import {
|
||||
Form,
|
||||
useActionData,
|
||||
useFetcher,
|
||||
useLoaderData,
|
||||
useRouteLoaderData,
|
||||
} from "@remix-run/react";
|
||||
|
@ -162,6 +162,7 @@ export default function PostRoute() {
|
|||
const rootData = useRouteLoaderData<RootLoaderTypes>("root");
|
||||
const data: PostWithRelations = useLoaderData<LoaderFunction>();
|
||||
const errors = useActionData<ActionFunction>();
|
||||
const fetcher = useFetcher();
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-5">
|
||||
|
@ -178,7 +179,11 @@ export default function PostRoute() {
|
|||
{rootData?.id ? (
|
||||
<div className="p-6 !bg-ctp-sky/5">
|
||||
<SubTitle>New reply</SubTitle>
|
||||
<Form action="/home" className="flex flex-col gap-3" method="POST">
|
||||
<fetcher.Form
|
||||
action="/home"
|
||||
className="flex flex-col gap-3"
|
||||
method="POST"
|
||||
>
|
||||
<input type="hidden" name="intent" value={"reply"} />
|
||||
<input type="hidden" name="postId" value={data.id} />
|
||||
<FormLabel>
|
||||
|
@ -187,7 +192,7 @@ export default function PostRoute() {
|
|||
<Text type="error">{errors?.body ? errors.body : ""}</Text>
|
||||
</FormLabel>
|
||||
<Button type="submit">Post</Button>
|
||||
</Form>
|
||||
</fetcher.Form>
|
||||
</div>
|
||||
) : (
|
||||
""
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
import {
|
||||
Form,
|
||||
useActionData,
|
||||
useFetcher,
|
||||
useLoaderData,
|
||||
useRouteLoaderData,
|
||||
} from "@remix-run/react";
|
||||
|
@ -346,6 +347,7 @@ export default function ReplyRoute() {
|
|||
const rootData = useRouteLoaderData<RootLoaderTypes>("root");
|
||||
const data: PostWithRelations = useLoaderData<LoaderFunction>();
|
||||
const errors = useActionData<ActionFunction>();
|
||||
const fetcher = useFetcher();
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-5">
|
||||
|
@ -397,7 +399,11 @@ export default function ReplyRoute() {
|
|||
{rootData?.id ? (
|
||||
<div className="p-6 !bg-ctp-sky/5">
|
||||
<SubTitle>New reply</SubTitle>
|
||||
<Form action="/home" className="flex flex-col gap-3" method="POST">
|
||||
<fetcher.Form
|
||||
action="/home"
|
||||
className="flex flex-col gap-3"
|
||||
method="POST"
|
||||
>
|
||||
<input type="hidden" name="intent" value={"reply"} />
|
||||
<input type="hidden" name="postId" value={data.post.id} />
|
||||
<input type="hidden" name="replyId" value={data.id} />
|
||||
|
@ -407,13 +413,10 @@ export default function ReplyRoute() {
|
|||
<Text type="error">{errors?.body ? errors.body : ""}</Text>
|
||||
</FormLabel>
|
||||
<Button type="submit">Post</Button>
|
||||
</Form>
|
||||
</fetcher.Form>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<Title>Twitter clone</Title>
|
||||
<SubTitle>Made with Remix</SubTitle>
|
||||
</>
|
||||
""
|
||||
)}
|
||||
{data.childReplies.map((reply) => (
|
||||
<div key={reply.id}>
|
||||
|
@ -425,12 +428,21 @@ export default function ReplyRoute() {
|
|||
topTitle={
|
||||
<>
|
||||
Replying to
|
||||
<Poster
|
||||
style="compact"
|
||||
username={data.parentReply.author.username}
|
||||
name={data.parentReply.author.name}
|
||||
pfp={data.parentReply.author.pfp}
|
||||
/>
|
||||
{data?.parentReply?.author ? (
|
||||
<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}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
|
|
@ -205,6 +205,66 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
|
|||
},
|
||||
},
|
||||
},
|
||||
reply: {
|
||||
select: {
|
||||
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: {
|
||||
author: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
name: true,
|
||||
pfp: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
post: {
|
||||
select: {
|
||||
author: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
name: true,
|
||||
pfp: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
_count: {
|
||||
select: {
|
||||
childReplies: {
|
||||
where: {
|
||||
parentReplyId: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: "desc",
|
||||
|
@ -278,6 +338,66 @@ export async function loader({ request, params }: LoaderFunctionArgs) {
|
|||
},
|
||||
},
|
||||
},
|
||||
reply: {
|
||||
select: {
|
||||
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: {
|
||||
author: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
name: true,
|
||||
pfp: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
post: {
|
||||
select: {
|
||||
author: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
name: true,
|
||||
pfp: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
_count: {
|
||||
select: {
|
||||
childReplies: {
|
||||
where: {
|
||||
parentReplyId: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: "desc",
|
||||
|
@ -311,6 +431,7 @@ export default function UserProfile() {
|
|||
const actionData = useActionData<ActionFunction>();
|
||||
const isFollowing =
|
||||
data.followedBy.filter((follow) => follow.id === rootData?.id).length > 0;
|
||||
console.log(data);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-5">
|
||||
|
@ -395,10 +516,35 @@ export default function UserProfile() {
|
|||
<Post
|
||||
userId={rootData?.id}
|
||||
key={like.id}
|
||||
post={like.post}
|
||||
rootPostId={like?.reply?.post?.id}
|
||||
post={like.reply ? like.reply : like.post}
|
||||
topTitle={
|
||||
<>
|
||||
<strong>{data.username}</strong> liked this
|
||||
{like.reply ? (
|
||||
<>
|
||||
, Replying to{" "}
|
||||
{like.reply.parentReply ? (
|
||||
<Poster
|
||||
style="compact"
|
||||
username={
|
||||
like.reply.parentReply.author.username
|
||||
}
|
||||
name={like.reply.parentReply.author.name}
|
||||
pfp={like.reply.parentReply.author.pfp}
|
||||
/>
|
||||
) : (
|
||||
<Poster
|
||||
style="compact"
|
||||
username={like.reply.post.author.username}
|
||||
name={like.reply.post.author.name}
|
||||
pfp={like.reply.post.author.pfp}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
@ -419,10 +565,35 @@ export default function UserProfile() {
|
|||
<Post
|
||||
userId={rootData?.id}
|
||||
key={repost.id}
|
||||
post={repost.post}
|
||||
rootPostId={repost?.reply?.post?.id}
|
||||
post={repost.reply ? repost.reply : repost.post}
|
||||
topTitle={
|
||||
<>
|
||||
<strong>{data.username}</strong> reposted this
|
||||
{repost.reply ? (
|
||||
<>
|
||||
, Replying to{" "}
|
||||
{repost.reply.parentReply ? (
|
||||
<Poster
|
||||
style="compact"
|
||||
username={
|
||||
repost.reply.parentReply.author.username
|
||||
}
|
||||
name={repost.reply.parentReply.author.name}
|
||||
pfp={repost.reply.parentReply.author.pfp}
|
||||
/>
|
||||
) : (
|
||||
<Poster
|
||||
style="compact"
|
||||
username={repost.reply.post.author.username}
|
||||
name={repost.reply.post.author.name}
|
||||
pfp={repost.reply.post.author.pfp}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
import type { LoaderFunction, LoaderFunctionArgs } from "@remix-run/node";
|
||||
import { useLoaderData, useParams } from "@remix-run/react";
|
||||
import { Card } from "~/components/Card";
|
||||
import { Poster } from "~/components/Post";
|
||||
import { Title } from "~/components/Typography";
|
||||
import { prisma } from "~/utils/prisma.server";
|
||||
|
||||
export async function loader({ params }: LoaderFunctionArgs) {
|
||||
const followers = await prisma.user.findMany({
|
||||
where: {
|
||||
following: {
|
||||
some: {
|
||||
username: params.username,
|
||||
},
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
name: true,
|
||||
pfp: true,
|
||||
},
|
||||
});
|
||||
|
||||
return followers;
|
||||
}
|
||||
|
||||
export default function UserFollowers() {
|
||||
const data = useLoaderData<LoaderFunction>();
|
||||
const params = useParams();
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-5">
|
||||
<Title>
|
||||
User <em>{params.username}</em> followers
|
||||
</Title>
|
||||
<Card>
|
||||
{data.map((follower) => (
|
||||
<Poster
|
||||
key={follower.id}
|
||||
username={follower.username}
|
||||
name={follower.name}
|
||||
pfp={follower.pfp}
|
||||
/>
|
||||
))}
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
import type { LoaderFunction, LoaderFunctionArgs } from "@remix-run/node";
|
||||
import { useLoaderData, useParams } from "@remix-run/react";
|
||||
import { Card } from "~/components/Card";
|
||||
import { Poster } from "~/components/Post";
|
||||
import { Title } from "~/components/Typography";
|
||||
import { prisma } from "~/utils/prisma.server";
|
||||
|
||||
export async function loader({ params }: LoaderFunctionArgs) {
|
||||
const followed = await prisma.user.findMany({
|
||||
where: {
|
||||
followedBy: {
|
||||
some: {
|
||||
username: params.username,
|
||||
},
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
name: true,
|
||||
pfp: true,
|
||||
},
|
||||
});
|
||||
|
||||
console.log(followed);
|
||||
|
||||
if (!followed) {
|
||||
throw Error("Not found");
|
||||
}
|
||||
|
||||
return followed;
|
||||
}
|
||||
|
||||
export default function UserFollowed() {
|
||||
const data = useLoaderData<LoaderFunction>();
|
||||
const params = useParams();
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-5">
|
||||
<Title>
|
||||
User <em>{params.username}</em> follows
|
||||
</Title>
|
||||
<Card>
|
||||
{data.map((follower) => (
|
||||
<Poster
|
||||
key={follower.id}
|
||||
username={follower.username}
|
||||
name={follower.name}
|
||||
pfp={follower.pfp}
|
||||
/>
|
||||
))}
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue