first commit
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
"use client";
|
||||
|
||||
import { useThread, useChannel, useSdk, notifyChannelChanged } from "@lynkd/messaging-inbox-sdk";
|
||||
import { useUi } from "@/lib/ui-state";
|
||||
import { MessageItem } from "./MessageItem";
|
||||
import { Composer } from "./Composer";
|
||||
import { X } from "lucide-react";
|
||||
|
||||
export function ThreadPanel() {
|
||||
const { thread, closeThread, toast } = useUi();
|
||||
const { client } = useSdk();
|
||||
const channel = useChannel(thread?.channelId ?? null);
|
||||
const { parent, replies, reply, react, pin, save, edit, remove } = useThread(
|
||||
thread?.channelId ?? null,
|
||||
thread?.parentId ?? null,
|
||||
);
|
||||
|
||||
if (!thread) return null;
|
||||
const channelLabel = channel ? (channel.kind === "channel" ? `#${channel.name}` : channel.name) : "channel";
|
||||
|
||||
return (
|
||||
<aside
|
||||
role="dialog"
|
||||
aria-label="Thread"
|
||||
className="fixed inset-0 z-40 flex w-full flex-col border-l border-border bg-surface md:static md:z-auto md:w-[400px] md:max-w-[400px] md:shrink-0 animate-fade-in"
|
||||
>
|
||||
<div className="flex h-[60px] items-center justify-between border-b border-border px-4">
|
||||
<div>
|
||||
<div className="text-[15px] font-bold">Thread</div>
|
||||
<div className="text-[12px] text-muted">
|
||||
{channel ? (channel.kind === "channel" ? `#${channel.name}` : channel.name) : ""}
|
||||
</div>
|
||||
</div>
|
||||
<button onClick={closeThread} className="focus-ring grid h-8 w-8 place-items-center rounded-control text-muted hover:bg-hover hover:text-ink" aria-label="Close thread">
|
||||
<X size={18} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="min-h-0 flex-1 overflow-y-auto pb-2">
|
||||
{parent && (
|
||||
<MessageItem
|
||||
message={parent}
|
||||
onReact={(e) => react(parent.id, e)}
|
||||
onPin={() => pin(parent.id)}
|
||||
onSave={() => save(parent.id)}
|
||||
onEdit={(b) => edit(parent.id, b)}
|
||||
onDelete={() => { remove(parent.id); closeThread(); }}
|
||||
/>
|
||||
)}
|
||||
<div className="my-1 flex items-center gap-3 px-4">
|
||||
<div className="h-px flex-1 bg-border" />
|
||||
<span className="text-[11px] font-semibold text-muted">
|
||||
{replies.length} {replies.length === 1 ? "reply" : "replies"}
|
||||
</span>
|
||||
<div className="h-px flex-1 bg-border" />
|
||||
</div>
|
||||
{replies.map((m) => (
|
||||
<MessageItem
|
||||
key={m.id}
|
||||
message={m}
|
||||
onReact={(e) => react(m.id, e)}
|
||||
onPin={() => pin(m.id)}
|
||||
onSave={() => save(m.id)}
|
||||
onEdit={(b) => edit(m.id, b)}
|
||||
onDelete={() => remove(m.id)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Composer
|
||||
showAlsoSend
|
||||
channelName={channelLabel}
|
||||
placeholder="Reply…"
|
||||
onSend={async (body, opts) => {
|
||||
await reply(body, { attachments: opts?.attachments });
|
||||
if (opts?.alsoSendToChannel && thread) {
|
||||
await client.sendMessage(thread.channelId, body, { attachments: opts?.attachments, threadRootId: thread.parentId });
|
||||
notifyChannelChanged(thread.channelId);
|
||||
toast(`Also sent to ${channelLabel}`, "success");
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user