diff --git a/src/app/[handle]/page.tsx b/src/app/[handle]/page.tsx
index 7099bda..be7f4c6 100644
--- a/src/app/[handle]/page.tsx
+++ b/src/app/[handle]/page.tsx
@@ -110,6 +110,16 @@ export default function ProfilePage() {
router.push(`/${post.author.handle}/posts/${post.id}`);
};
+ const handleDelete = (postId: string) => {
+ setPosts(prev => prev.filter(p => p.id !== postId));
+ if (user && isOwnProfile) {
+ setUser({
+ ...user,
+ postsCount: (user.postsCount || 0) - 1
+ });
+ }
+ };
+
useEffect(() => {
if (user && currentUser?.handle === user.handle) {
setProfileForm({
@@ -582,6 +592,7 @@ export default function ProfilePage() {
onLike={handleLike}
onRepost={handleRepost}
onComment={handleComment}
+ onDelete={handleDelete}
/>
))
)
diff --git a/src/app/[handle]/posts/[id]/page.tsx b/src/app/[handle]/posts/[id]/page.tsx
index e0a30ea..3991aa7 100644
--- a/src/app/[handle]/posts/[id]/page.tsx
+++ b/src/app/[handle]/posts/[id]/page.tsx
@@ -68,6 +68,17 @@ export default function PostDetailPage() {
await fetch(`/api/posts/${postId}/repost`, { method });
};
+ const handleDelete = (postId: string) => {
+ if (postId === id) {
+ router.push(`/${handle}`);
+ } else {
+ setReplies(prev => prev.filter(r => r.id !== postId));
+ if (post) {
+ setPost({ ...post, repliesCount: Math.max(0, post.repliesCount - 1) });
+ }
+ }
+ };
+
if (loading) {
return (
@@ -113,6 +124,7 @@ export default function PostDetailPage() {
isDetail
onLike={handleLike}
onRepost={handleRepost}
+ onDelete={handleDelete}
onComment={() => {
const composer = document.querySelector('.compose-input') as HTMLTextAreaElement;
composer?.focus();
@@ -137,6 +149,7 @@ export default function PostDetailPage() {
post={reply}
onLike={handleLike}
onRepost={handleRepost}
+ onDelete={handleDelete}
onComment={(p) => {
// In detail view, commenting on a reply should probably just focus the main composer
// but we could also implement nested replies later.
diff --git a/src/app/explore/page.tsx b/src/app/explore/page.tsx
index 84dc8eb..0e2dba2 100644
--- a/src/app/explore/page.tsx
+++ b/src/app/explore/page.tsx
@@ -113,6 +113,14 @@ export default function ExplorePage() {
await fetch(`/api/posts/${postId}/repost`, { method });
};
+ const handleDelete = (postId: string) => {
+ setTrendingPosts(prev => prev.filter(p => p.id !== postId));
+ setSearchResults(prev => ({
+ ...prev,
+ posts: prev.posts.filter(p => p.id !== postId)
+ }));
+ };
+
return (
diff --git a/src/app/page.tsx b/src/app/page.tsx
index a55e837..e2f4d17 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -83,6 +83,10 @@ export default function Home() {
await fetch(`/api/posts/${postId}/repost`, { method });
};
+ const handleDelete = (postId: string) => {
+ setPosts(prev => prev.filter(p => p.id !== postId));
+ };
+
return (
<>
{
setReplyingTo(p);
window.scrollTo({ top: 0, behavior: 'smooth' });
diff --git a/src/app/search/page.tsx b/src/app/search/page.tsx
index 803dc89..f02ed02 100644
--- a/src/app/search/page.tsx
+++ b/src/app/search/page.tsx
@@ -4,6 +4,8 @@ import { useState, useEffect, useCallback } from 'react';
import Link from 'next/link';
import { useSearchParams, useRouter } from 'next/navigation';
import { formatFullHandle } from '@/lib/utils/handle';
+import { PostCard } from '@/components/PostCard';
+import { Post } from '@/lib/types';
interface User {
id: string;
@@ -15,22 +17,7 @@ interface User {
isRemote?: boolean;
}
-interface MediaItem {
- id: string;
- url: string;
- altText?: string | null;
-}
-interface Post {
- id: string;
- content: string;
- createdAt: string;
- likesCount: number;
- repostsCount: number;
- repliesCount: number;
- author: User;
- media?: MediaItem[];
-}
// Icons
const SearchIcon = () => (
@@ -116,98 +103,7 @@ function UserCard({ user }: { user: User }) {
);
}
-function PostCard({ post }: { post: Post }) {
- const [liked, setLiked] = useState(false);
- const [reporting, setReporting] = useState(false);
- const formatTime = (dateStr: string) => {
- const date = new Date(dateStr);
- const now = new Date();
- const diff = now.getTime() - date.getTime();
- const minutes = Math.floor(diff / 60000);
- const hours = Math.floor(minutes / 60);
- const days = Math.floor(hours / 24);
-
- if (minutes < 1) return 'now';
- if (minutes < 60) return `${minutes}m`;
- if (hours < 24) return `${hours}h`;
- if (days < 7) return `${days}d`;
- return date.toLocaleDateString();
- };
-
- return (
-
-
-
- {post.author?.avatarUrl ? (
-

- ) : (
- (post.author?.displayName || post.author?.handle || '?').charAt(0).toUpperCase()
- )}
-
-
-
- {post.author?.displayName || post.author?.handle}
-
- {formatFullHandle(post.author?.handle || '')} ยท {formatTime(post.createdAt)}
-
-
- {post.content}
- {post.media && post.media.length > 0 && (
-
- {post.media.map((item) => (
-
-

-
- ))}
-
- )}
-
-
-
-
-
-
-
- );
-}
export default function SearchPage() {
const router = useRouter();
@@ -261,6 +157,20 @@ export default function SearchPage() {
}
};
+ const handleLike = async (postId: string, currentLiked: boolean) => {
+ const method = currentLiked ? 'DELETE' : 'POST';
+ await fetch(`/api/posts/${postId}/like`, { method });
+ };
+
+ const handleRepost = async (postId: string, currentReposted: boolean) => {
+ const method = currentReposted ? 'DELETE' : 'POST';
+ await fetch(`/api/posts/${postId}/repost`, { method });
+ };
+
+ const handleDelete = (postId: string) => {
+ setPosts(prev => prev.filter(p => p.id !== postId));
+ };
+
return (
{/* Header */}
@@ -368,7 +278,15 @@ export default function SearchPage() {
Posts
)}
- {posts.map(post => )}
+ {posts.map(post => (
+
+ ))}
)}
>
diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx
index e33b83f..ce4d090 100644
--- a/src/components/Sidebar.tsx
+++ b/src/components/Sidebar.tsx
@@ -62,17 +62,17 @@ export function Sidebar() {
{user && (
-
-
+
+
{user.avatarUrl ? (

) : (
(user.displayName?.charAt(0) || user.handle.charAt(0)).toUpperCase()
)}
-
-
{user.displayName}
-
{formatFullHandle(user.handle)}
+
+
{user.displayName}
+
{formatFullHandle(user.handle)}