Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

31 view post #33

Merged
merged 10 commits into from
Mar 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions app/(dashboard)/home/posts/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { getPost } from "@/utils/db";
import PostFullView from "@/components/posts/PostFullView";

interface PostPageProps {
params: Promise<{ slug: string }>;
}

export default async function PostPage({ params }: PostPageProps) {
const { slug } = await params;
const { post, user } = await getPost(slug);

return <PostFullView post={post} user={user} />;
}
14 changes: 0 additions & 14 deletions app/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,14 +0,0 @@
interface User {
name?: string | null;
email?: string | null;
image?: string | null;
}

interface Post {
updatedAt: Date;
id: string;
title: string;
content: string;
createdAt: Date;
slug: string | null;
}
5 changes: 4 additions & 1 deletion components/app-sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
import { Switch } from "@/components/ui/switch";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { type User } from "@prisma/client";

const data = {
navMain: [
Expand Down Expand Up @@ -59,7 +60,9 @@ const data = {
export function AppSidebar({
user,
...props
}: React.ComponentProps<typeof Sidebar> & { user: User }) {
}: React.ComponentProps<typeof Sidebar> & {
user: Pick<User, "id" | "name" | "email" | "image">;
}) {
// TODO: use the url/router to set active item
const router = useRouter();
const [activeItem, setActiveItem] = React.useState(data.navMain[2]);
Expand Down
7 changes: 6 additions & 1 deletion components/nav-user.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,18 @@ import {
} from "@/components/ui/sidebar";

import { logOutUser } from "@/app/actions";
import { type User } from "@prisma/client";

function logUserOut(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault();
logOutUser();
}

export function NavUser({ user }: { user: User }) {
interface NavUserProps {
user: Pick<User, "id" | "name" | "email" | "image">;
}

export function NavUser({ user }: NavUserProps) {
const { isMobile } = useSidebar();

return (
Expand Down
74 changes: 74 additions & 0 deletions components/posts/PostFullView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { formatDate } from "@/utils/posts";
import { generateHTML } from "@tiptap/html";
import StarterKit from "@tiptap/starter-kit";
import { type User, type Post } from "@prisma/client";
import Image from "next/image";
import Link from "next/link";

interface PostFullViewProps {
post: Omit<Post, "ownerId">;
user: Pick<User, "id" | "name" | "email" | "image">;
slug?: string;
}

export default function PostFullView({ post, user, slug }: PostFullViewProps) {
const formattedDate = formatDate(post.updatedAt);
const content = generateHTML(JSON.parse(post.content), [StarterKit]);

function Title({ slug }: { slug: PostFullViewProps["slug"] }) {
return (
<h3 className="mt-3 text-3xl/8 font-semibold text-gray-900">
{slug ? (
<Link
href={`/home/posts/${post.slug}`}
className="hover:text-gray-600"
>
<span className="absolute inset-0" />
{post.title}
</Link>
) : (
post.title
)}
</h3>
);
}

return (
<article
key={post.id}
className="[&:not(:last-child)]:border-b-1 border-gray-200 py-10 px-4 xl:mr-5"
>
<time dateTime={formattedDate} className="text-gray-500 italic text-xs">
{formattedDate}
</time>
<div className="group relative">
<Title slug={slug} />
<div
className="mt-5 line-clamp-3 text-lg/6 text-gray-600"
dangerouslySetInnerHTML={{ __html: content }}
/>
</div>
<div className="relative mt-8 flex items-center gap-x-4">
{user.image && (
<Image
alt=""
src={user.image}
className="size-10 rounded-full bg-gray-50"
width={40}
height={40}
/>
)}
<div className="text-sm/6">
<p className="font-semibold text-gray-900">
<a href="#">
<span className="absolute inset-0" />
{user.name}
</a>
</p>
{/* TODO: update when introduce RBAC */}
{/* <p className="text-gray-600">Admin</p> */}
</div>
</div>
</article>
);
}
79 changes: 17 additions & 62 deletions components/posts/allUserPosts.tsx
Original file line number Diff line number Diff line change
@@ -1,65 +1,20 @@
import { format } from "date-fns";
import Image from "next/image";
import { generateHTML } from "@tiptap/html";
import StarterKit from "@tiptap/starter-kit";
import { sortPostsByDateDesc } from "@/utils/posts";
import PostFullView from "./PostFullView";
import { type User, type Post } from "@prisma/client";

export default function AllUserPosts({
user,
posts,
}: {
posts: Post[];
user: User;
}) {
const sortedPostsDesc = posts.sort((a, b) => {
return new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime();
});
return sortedPostsDesc.map((post) => {
const formattedDate = format(post.updatedAt, "dd MMM, yyyy");

const content = generateHTML(JSON.parse(post.content), [StarterKit]);
interface AllUserPostsProps {
posts: Omit<Post, "ownerId">[];
user: Pick<User, "id" | "name" | "email" | "image">;
}

return (
<article
key={post.id}
className="[&:not(:last-child)]:border-b-1 border-gray-200 py-10 px-4 xl:mr-5"
>
<time dateTime={formattedDate} className="text-gray-500 italic text-xs">
{formattedDate}
</time>
<div className="group relative">
<h3 className="mt-3 text-3xl/8 font-semibold text-gray-900 group-hover:text-gray-600">
<a href={`/home/posts/${post.slug}`}>
<span className="absolute inset-0" />
{post.title}
</a>
</h3>
<div
className="mt-5 line-clamp-3 text-lg/6 text-gray-600"
dangerouslySetInnerHTML={{ __html: content }}
/>
</div>
<div className="relative mt-8 flex items-center gap-x-4">
{user.image && (
<Image
alt=""
src={user.image}
className="size-10 rounded-full bg-gray-50"
width={40}
height={40}
/>
)}
<div className="text-sm/6">
<p className="font-semibold text-gray-900">
<a href="#">
<span className="absolute inset-0" />
{user.name}
</a>
</p>
{/* TODO: update when introduce RBAC */}
{/* <p className="text-gray-600">Admin</p> */}
</div>
</div>
</article>
);
});
export default function AllUserPosts({ user, posts }: AllUserPostsProps) {
// TODO: Update to use PostShortView component
return sortPostsByDateDesc(posts).map((post) => (
<PostFullView
key={post.id}
post={post}
user={user}
slug={post.slug as string}
/>
));
}
11 changes: 7 additions & 4 deletions components/shell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import {
SidebarProvider,
SidebarTrigger,
} from "@/components/ui/sidebar";
import { type User } from "@prisma/client";

export default function Shell({
user,
children,
}: React.PropsWithChildren<{ user: User }>) {
interface ShellProps {
user: Pick<User, "id" | "name" | "email" | "image">;
children: React.ReactNode;
}

export default function Shell({ user, children }: ShellProps) {
return (
<SidebarProvider
style={
Expand Down
2 changes: 2 additions & 0 deletions components/two-column.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { type User } from "@prisma/client";

export default function TwoColumn({
children,
}: React.PropsWithChildren<{ user: User }>) {
Expand Down
Loading