feat(posts): Add user replies tab and improve reply management

- Add "replies" tab to user profile page to display posts where user replied to others
- Implement replies fetching via new `type=replies` query parameter in posts API
- Add reply deletion permissions for parent post owners on their own posts
- Add swarm reply deletion notification to origin nodes when replies are deleted
- Pass `parentPostAuthorId` prop to PostCard for improved reply context tracking
- Update profile tab navigation to include replies tab for non-bot users
- Add loading and empty states for replies tab display
- Improve authorization logic to allow parent post owners to delete replies on their posts
This commit is contained in:
Christomatt
2026-01-26 14:22:32 +01:00
parent 141b99747a
commit a2ec470354
7 changed files with 232 additions and 27 deletions
+50 -3
View File
@@ -255,6 +255,8 @@ export async function DELETE(
const user = await requireAuth();
const { id } = await params;
const nodeDomain = process.env.NEXT_PUBLIC_NODE_DOMAIN || 'localhost:3000';
const post = await db.query.posts.findFirst({
where: eq(posts.id, id),
with: {
@@ -267,10 +269,22 @@ export async function DELETE(
}
// Allow deletion if user owns the post OR if user owns the bot that made the post
// OR if user owns the parent post (can delete replies on their posts)
const isPostOwner = post.userId === user.id;
const isBotOwner = post.bot && post.bot.ownerId === user.id;
if (!isPostOwner && !isBotOwner) {
// Check if user owns the parent post (for deleting replies on their posts)
let isParentPostOwner = false;
if (post.replyToId) {
const parentPost = await db.query.posts.findFirst({
where: eq(posts.id, post.replyToId),
});
if (parentPost && parentPost.userId === user.id) {
isParentPostOwner = true;
}
}
if (!isPostOwner && !isBotOwner && !isParentPostOwner) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 403 });
}
@@ -286,10 +300,43 @@ export async function DELETE(
}
}
// 2. Delete the post (cascades to media, likes, notifications)
// 2. If this is a reply to a swarm post, notify the origin node to delete it
if (post.swarmReplyToId) {
const parts = post.swarmReplyToId.split(':');
if (parts.length >= 3) {
const originDomain = parts[1];
// Fire and forget - don't block on this
(async () => {
try {
const protocol = originDomain.includes('localhost') ? 'http' : 'https';
const res = await fetch(`${protocol}://${originDomain}/api/swarm/replies`, {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
replyId: post.id,
nodeDomain,
authorHandle: user.handle,
}),
signal: AbortSignal.timeout(5000),
});
if (res.ok) {
console.log(`[Swarm] Deletion propagated to ${originDomain}`);
} else {
console.error(`[Swarm] Failed to propagate deletion: ${res.status}`);
}
} catch (err) {
console.error('[Swarm] Error propagating deletion:', err);
}
})();
}
}
// 3. Delete the post (cascades to media, likes, notifications)
await db.delete(posts).where(eq(posts.id, id));
// 3. Decrement the post author's postsCount
// 4. Decrement the post author's postsCount
const postAuthor = await db.query.users.findFirst({
where: eq(users.id, post.userId),
});