import { useCallback, useRef, useState } from 'react';
import type { ConversationDetailResponse } from '../../../../../packages/api-contracts/src/index.js';
import { RedditUsernameLink, redditUsernameLabel } from '../../components/reddit-username-link.js';
import { OriginPostCard } from '../../components/origin-post.js';
import { useConversationDetailQuery, useSendReplyMutation, useSuggestMediaAskMutation, useSuggestReplyMutation } from './conversation-queries.js';
import { SendConfirmationDialog } from './send-confirmation-dialog.js';
import { AccountOwnerBadge } from '../../components/account-owner-badge.js';
interface ConversationDetailProps {
conversationId: string;
onClose(): void;
}
function formatMessageTime(timestamp: number): string {
return new Intl.DateTimeFormat(undefined, { dateStyle: 'medium', timeStyle: 'short' }).format(timestamp);
}
function mediaPath(localPath: string): string {
return `/media/${localPath.split(/[\\/]/).map(encodeURIComponent).join('/')}`;
}
function MessageHistory({ conversation }: { conversation: ConversationDetailResponse }) {
if (!conversation.messages || conversation.messages.length === 0) {
return
No messages have been loaded for this conversation.
;
}
return (
{conversation.messages.map((message) => (
-
{message.isSelf
? `You${conversation.owner ? ` (u/${conversation.owner.redditUsername})` : ''}`
: }
{message.text}
{message.media?.length ? (
{message.media.map((media) => (
))}
) : null}
))}
);
}
function ConversationComposer({ conversation, conversationId }: { conversation: ConversationDetailResponse; conversationId: string }) {
const [draft, setDraft] = useState('');
const [isConfirming, setIsConfirming] = useState(false);
const [wasSent, setWasSent] = useState(false);
const sendButtonRef = useRef(null);
const suggestionMutation = useSuggestReplyMutation(conversationId);
const mediaAskMutation = useSuggestMediaAskMutation(conversationId);
const sendMutation = useSendReplyMutation(conversationId);
const canSend = draft.trim().length > 0 && !sendMutation.isPending;
const closeConfirmation = useCallback(() => {
setIsConfirming(false);
queueMicrotask(() => sendButtonRef.current?.focus());
}, []);
function suggestReply() {
setWasSent(false);
suggestionMutation.mutate(undefined, { onSuccess: (suggestion) => setDraft(suggestion) });
}
function suggestMediaAsk() {
setWasSent(false);
mediaAskMutation.mutate(undefined, { onSuccess: (suggestion) => setDraft(suggestion) });
}
function sendReply() {
if (!canSend) return;
sendMutation.mutate(draft, {
onSuccess() {
setDraft('');
setWasSent(true);
},
onSettled: closeConfirmation,
});
}
return (
Reply
);
}
export function ConversationDetail({ conversationId, onClose }: ConversationDetailProps) {
const detailQuery = useConversationDetailQuery(conversationId);
if (detailQuery.isPending) {
return Loading conversation…
;
}
if (detailQuery.isError) {
return (
Conversation unavailable
{detailQuery.error.message}
);
}
const conversation = detailQuery.data;
return (
Conversation
{conversation.unread ?
Unread : null}
{conversation.syncInProgress ? (
A {conversation.syncInProgress.kind ?? 'chat'} sync is in progress. Messages may be stale.
) : null}
{conversation.triggeringPost ? (
) : null}
);
}