fix: chat accepts posts

This commit is contained in:
gosangam
2026-08-29 16:26:53 +05:30
parent 76cd106ef7
commit 3e6a1c6f39
5 changed files with 118 additions and 21 deletions
+4
View File
@@ -18,6 +18,7 @@ import { LinkPreviewCard } from "@/components/chat/link-preview-card";
import { MediaGrid } from "@/components/chat/media-grid";
import { MediaLightbox } from "@/components/chat/media-lightbox";
import { QuoteCard } from "@/components/chat/quote-card";
import { SharedPostCard } from "@/components/chat/shared-post-card";
import { attachmentUrl, type Attachment } from "@/lib/chat";
function humanSize(bytes?: number | null): string {
@@ -58,6 +59,9 @@ export function MessageAttachments({
{rest.map((a) => {
switch (a.kind) {
case "entity":
return <SharedPostCard key={a.id} attachment={a} />;
case "quote":
return <QuoteCard key={a.id} attachment={a} />;
+5 -1
View File
@@ -37,12 +37,16 @@ type SendState = "idle" | "sending" | "sent";
export function ShareToChatDialog({
body = "",
quote,
entity,
onClose,
}: {
/** Plain message text. Empty when sending a quote on its own. */
body?: string;
/** A passage from the library, sent as a tappable quotation. */
quote?: QuotePayload;
/** A post, sent as a card. Only the reference travels — the BFF resolves
* the contents and re-checks visibility for each viewer. */
entity?: { type: "post"; id: string };
onClose: () => void;
}) {
const { user } = useAuth();
@@ -111,7 +115,7 @@ export function ShareToChatDialog({
mark(handle, "sending");
try {
const id = conversationId ?? (await chat.openDM(handle)).id;
await chat.send(id, body, { quote });
await chat.send(id, body, { quote, entity });
mark(handle, "sent");
} catch {
mark(handle, "idle");
+75
View File
@@ -0,0 +1,75 @@
"use client";
/**
* A post shared into a chat, rendered as a card with its author.
*
* The contents are resolved by the BFF on every read, per viewer — never from
* a snapshot frozen at send time. So a post that has since been deleted or
* hidden arrives as `entity_unavailable` and renders as a tombstone rather
* than quietly showing content the reader is no longer allowed to see.
*/
import Link from "next/link";
import { ImageOff } from "lucide-react";
import { UserAvatar } from "@/components/ui/user-avatar";
import type { Attachment } from "@/lib/chat";
export function SharedPostCard({ attachment }: { attachment: Attachment }) {
const post = attachment.entity;
if (!post || attachment.entity_unavailable) {
return (
<div className="mt-1 flex items-center gap-2 rounded-lg border border-border bg-muted/30 px-3 py-2.5">
<ImageOff className="size-4 shrink-0 text-muted-foreground" aria-hidden />
<span className="text-sm text-muted-foreground">
This post is no longer available
</span>
</div>
);
}
return (
<Link
href={`/u/${encodeURIComponent(post.author_handle)}/posts#post-${post.id}`}
className="mt-1 block overflow-hidden rounded-lg border border-border bg-card transition-colors hover:bg-muted/40"
>
<span className="flex items-center gap-2 px-3 py-2">
<UserAvatar
src={post.author_avatar_url ?? null}
name={post.author_name}
className="size-6 shrink-0"
/>
<span className="min-w-0 flex-1">
<span className="block truncate text-xs font-medium text-foreground">
{post.author_name}
</span>
<span className="block truncate text-[11px] text-muted-foreground">
@{post.author_handle}
</span>
</span>
</span>
{post.image_url && (
// eslint-disable-next-line @next/next/no-img-element
<img
src={post.image_url}
alt=""
loading="lazy"
className="aspect-square w-full object-cover"
/>
)}
{post.caption && (
<span className="block px-3 py-2 text-sm leading-relaxed text-foreground line-clamp-3">
{post.caption}
</span>
)}
{post.source_title && (
<span className="block truncate px-3 pb-2 text-xs text-muted-foreground">
{post.source_title}
</span>
)}
</Link>
);
}