Skip to content

Commit

Permalink
Profile feed added, minor changes to the posts route
Browse files Browse the repository at this point in the history
  • Loading branch information
MantasImb committed Apr 9, 2023
1 parent 1bad4b9 commit 5652daa
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 64 deletions.
11 changes: 11 additions & 0 deletions src/components/Layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { PropsWithChildren } from "react";

export const PageLayout = (props: PropsWithChildren) => {
return (
<main className="flex h-screen justify-center">
<div className="h-full w-full overflow-y-auto border-x border-slate-400 md:max-w-2xl">
{props.children}
</div>
</main>
);
};
35 changes: 35 additions & 0 deletions src/components/PostView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import Image from "next/image";
import type { RouterOutputs } from "~/utils/api";
import Link from "next/link";
import relativeTime from "dayjs/plugin/relativeTime";
import dayjs from "dayjs";
dayjs.extend(relativeTime);

type PostWithAuthor = RouterOutputs["posts"]["getAll"][number];
export function PostView(props: PostWithAuthor) {
const { post, author } = props;
return (
<div className="flex gap-3 border-b border-slate-400 p-4">
<Image
src={author.profileImageUrl}
className="rounded-full"
alt={`${author.id} profile image`}
width={56}
height={56}
/>
<div className="flex flex-col">
<div className="flex gap-1 text-slate-300">
<Link href={`/@${author.username}`}>
<span>{`@${author.username}`}</span>
</Link>
<Link href={`/post/${post.id}`}>
<span className="font-thin">{${dayjs(
post.createdAt
).fromNow()}`}</span>
</Link>
</div>
<span>{post.content}</span>
</div>
</div>
);
}
21 changes: 21 additions & 0 deletions src/pages/[slug].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,26 @@ import Head from "next/head";
import { api } from "~/utils/api";
import Image from "next/image";
import { PageLayout } from "~/components/Layout";
import { LoadingPage } from "~/components/Loading";
import { PostView } from "~/components/PostView";

const ProfileFeed = (props: { userId: string }) => {
const { data, isLoading } = api.posts.getPostsByUserId.useQuery({
userId: props.userId,
});

if (isLoading) return <LoadingPage />;
if (!data) return <div>404</div>;
if (data.length === 0) return <div>No posts yet</div>;

return (
<div className="flex flex-col">
{data.map((fullPost) => (
<PostView key={fullPost.post.id} {...fullPost} />
))}
</div>
);
};

const ProfilePage: NextPage<{ username: string }> = ({ username }) => {
const { data } = api.profile.getUserByUsername.useQuery({
Expand Down Expand Up @@ -31,6 +51,7 @@ const ProfilePage: NextPage<{ username: string }> = ({ username }) => {
data.username ?? ""
}`}</div>
<div className="w-full border-b border-slate-400"></div>
<ProfileFeed userId={data.id} />
</PageLayout>
</>
);
Expand Down
35 changes: 1 addition & 34 deletions src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,12 @@ import { type NextPage } from "next";
import Image from "next/image";

import { api } from "~/utils/api";
import type { RouterOutputs } from "~/utils/api";

import relativeTime from "dayjs/plugin/relativeTime";
import dayjs from "dayjs";
import { LoadingPage, LoadingSpinner } from "~/components/Loading";
import { useState } from "react";
import { toast } from "react-hot-toast";
import Link from "next/link";
import { PageLayout } from "~/components/Layout";
dayjs.extend(relativeTime);
import { PostView } from "~/components/PostView";

function CreatePostWizard() {
const [input, setInput] = useState("");
Expand Down Expand Up @@ -83,35 +79,6 @@ function CreatePostWizard() {
);
}

type PostWithAuthor = RouterOutputs["posts"]["getAll"][number];
function PostView(props: PostWithAuthor) {
const { post, author } = props;
return (
<div className="flex gap-3 border-b border-slate-400 p-4">
<Image
src={author.profileImageUrl}
className="rounded-full"
alt={`${author.id} profile image`}
width={56}
height={56}
/>
<div className="flex flex-col">
<div className="flex gap-1 text-slate-300">
<Link href={`/@${author.username}`}>
<span>{`@${author.username}`}</span>
</Link>
<Link href={`/post/${post.id}`}>
<span className="font-thin">{${dayjs(
post.createdAt
).fromNow()}`}</span>
</Link>
</div>
<span>{post.content}</span>
</div>
</div>
);
}

function Feed() {
const { data, isLoading: postsLoading } = api.posts.getAll.useQuery();

Expand Down
82 changes: 52 additions & 30 deletions src/server/api/routers/posts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,34 @@ import {
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";
import { filterUserForClient } from "~/server/helpers/filterUserForClient";
import type { Post } from "@prisma/client";

// add user data to posts helper
const addUserDataToPosts = async (posts: Post[]) => {
const users = (
await clerkClient.users.getUserList({
userId: posts.map((post) => post.authorId),
limit: 100,
})
).map(filterUserForClient);

return posts.map((post) => {
const author = users.find((user) => user.id === post.authorId);
if (!author || !author.username) {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Could not find author for post",
});
}
return {
post,
author: {
...author,
username: author.username,
},
};
});
};

// ratelimiter, that allows 3 requests per minute
const ratelimit = new Ratelimit({
Expand All @@ -20,38 +48,32 @@ const ratelimit = new Ratelimit({
});

export const postsRouter = createTRPCRouter({
getAll: publicProcedure.query(async ({ ctx }) => {
const posts = await ctx.prisma.post.findMany({
take: 100,
orderBy: {
createdAt: "desc",
},
});

const users = (
await clerkClient.users.getUserList({
userId: posts.map((post) => post.authorId),
limit: 100,
getAll: publicProcedure.query(({ ctx }) =>
ctx.prisma.post
.findMany({
take: 100,
orderBy: {
createdAt: "desc",
},
})
).map(filterUserForClient);
.then(addUserDataToPosts)
),

return posts.map((post) => {
const author = users.find((user) => user.id === post.authorId);
if (!author || !author.username) {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Could not find author for post",
});
}
return {
post,
author: {
...author,
username: author.username,
},
};
});
}),
getPostsByUserId: publicProcedure
.input(z.object({ userId: z.string() }))
.query(({ ctx, input }) =>
ctx.prisma.post
.findMany({
where: {
authorId: input.userId,
},
take: 100,
orderBy: {
createdAt: "desc",
},
})
.then(addUserDataToPosts)
),

create: privateProcedure
.input(
Expand Down
8 changes: 8 additions & 0 deletions src/server/helpers/filterUserForClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { User } from "@clerk/nextjs/dist/api";
export function filterUserForClient(user: User) {
return {
id: user.id,
username: user.username,
profileImageUrl: user.profileImageUrl,
};
}

1 comment on commit 5652daa

@vercel
Copy link

@vercel vercel bot commented on 5652daa Apr 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

chirpt3 – ./

chirpt3-git-main-geeraya.vercel.app
chirpt3-geeraya.vercel.app
chirpt3.vercel.app

Please sign in to comment.