102 lines
3.0 KiB
TypeScript
102 lines
3.0 KiB
TypeScript
"use client";
|
|
import { ImageBubble } from "./image-bubble";
|
|
import { PrivateMessageCard } from "./private-message-card";
|
|
import { TextBubble } from "./text-bubble";
|
|
import { VoiceBubble } from "./voice-bubble";
|
|
import styles from "./chat-area.module.css";
|
|
|
|
export interface MessageContentProps {
|
|
content: string;
|
|
imageUrl?: string | null;
|
|
imagePaywalled?: boolean;
|
|
audioUrl?: string | null;
|
|
messageId?: string;
|
|
isFromAI: boolean;
|
|
locked?: boolean | null;
|
|
lockReason?: string | null;
|
|
lockedPrivate?: boolean | null;
|
|
privateMessageHint?: string | null;
|
|
isUnlockingMessage?: boolean;
|
|
onUnlockPrivateMessage?: (messageId: string) => void;
|
|
onUnlockVoiceMessage?: (messageId: string) => void;
|
|
onOpenImage?: (messageId: string) => void;
|
|
}
|
|
|
|
const IMAGE_PLACEHOLDER = "[图片]";
|
|
|
|
export function MessageContent({
|
|
content,
|
|
imageUrl,
|
|
imagePaywalled,
|
|
audioUrl,
|
|
messageId,
|
|
isFromAI,
|
|
locked,
|
|
lockReason,
|
|
lockedPrivate,
|
|
privateMessageHint,
|
|
isUnlockingMessage,
|
|
onUnlockPrivateMessage,
|
|
onUnlockVoiceMessage,
|
|
onOpenImage,
|
|
}: MessageContentProps) {
|
|
const hasImage = imageUrl != null && imageUrl.length > 0;
|
|
const hasAudio = audioUrl != null && audioUrl.length > 0;
|
|
const hasText = content.length > 0 && content !== IMAGE_PLACEHOLDER;
|
|
const isLockedPrivateMessage =
|
|
lockedPrivate === true ||
|
|
(locked === true && lockReason === "private_message");
|
|
const isLockedVoiceMessage = locked === true && lockReason === "voice_message";
|
|
const shouldRenderVoiceMessage = hasAudio || isLockedVoiceMessage;
|
|
const handleUnlockPrivateMessage =
|
|
messageId && onUnlockPrivateMessage
|
|
? () => onUnlockPrivateMessage(messageId)
|
|
: undefined;
|
|
const handleUnlockVoiceMessage =
|
|
isLockedVoiceMessage && messageId && onUnlockVoiceMessage
|
|
? () => onUnlockVoiceMessage(messageId)
|
|
: undefined;
|
|
|
|
return (
|
|
<div
|
|
className={[
|
|
styles.messageContent,
|
|
isFromAI ? styles.messageContentAi : styles.messageContentUser,
|
|
].join(" ")}
|
|
>
|
|
{isLockedPrivateMessage ? (
|
|
<PrivateMessageCard
|
|
hint={privateMessageHint}
|
|
isUnlocking={isUnlockingMessage}
|
|
onUnlock={handleUnlockPrivateMessage}
|
|
/>
|
|
) : (
|
|
<>
|
|
{hasImage && imageUrl && (
|
|
<ImageBubble
|
|
messageId={messageId}
|
|
imageUrl={imageUrl}
|
|
imagePaywalled={imagePaywalled}
|
|
onOpenImage={onOpenImage}
|
|
/>
|
|
)}
|
|
{shouldRenderVoiceMessage ? (
|
|
<VoiceBubble
|
|
messageId={messageId}
|
|
audioUrl={audioUrl}
|
|
isFromAI={isFromAI}
|
|
locked={isLockedVoiceMessage}
|
|
hint={privateMessageHint}
|
|
isUnlocking={isUnlockingMessage}
|
|
onUnlock={handleUnlockVoiceMessage}
|
|
/>
|
|
) : null}
|
|
{hasText && !shouldRenderVoiceMessage ? (
|
|
<TextBubble content={content} isFromAI={isFromAI} />
|
|
) : null}
|
|
</>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|