Files
cozsweet-frontend-nextjs/src/app/chat/components/chat-media-image.tsx
T

108 lines
2.4 KiB
TypeScript

"use client";
/* eslint-disable @next/next/no-img-element */
import Image from "next/image";
import type { MouseEventHandler, ReactNode } from "react";
import { useState } from "react";
import {
isBrowserLocalChatImageSource,
normalizeChatImageSource,
} from "@/lib/chat/chat_media_url";
import { useCachedChatMediaUrl } from "@/lib/chat/use_cached_chat_media_url";
export interface ChatMediaImageProps {
characterId: string;
remoteMessageId?: string;
remoteUrl: string;
alt?: string;
className?: string;
nativeClassName?: string;
errorClassName?: string;
width?: number;
height?: number;
fill?: boolean;
sizes?: string;
showErrorFallback?: boolean;
onClick?: MouseEventHandler<HTMLImageElement>;
children?: ReactNode;
}
export function ChatMediaImage({
characterId,
remoteMessageId,
remoteUrl,
alt = "",
className,
nativeClassName,
errorClassName,
width = 240,
height = 240,
fill = false,
sizes,
showErrorFallback = true,
onClick,
children,
}: ChatMediaImageProps) {
const [errorSrc, setErrorSrc] = useState<string | null>(null);
const { mediaUrl, isUsingCachedMedia, reportMediaError } =
useCachedChatMediaUrl({
characterId,
messageId: remoteMessageId,
remoteUrl,
kind: "image",
});
const src = normalizeChatImageSource(mediaUrl || remoteUrl);
const shouldUseNativeImage = isBrowserLocalChatImageSource(src);
const hasError = errorSrc === src;
const handleImageError = () => {
if (isUsingCachedMedia) {
reportMediaError();
return;
}
setErrorSrc(src);
};
if (hasError && showErrorFallback) {
return <div className={errorClassName}>🖼</div>;
}
return (
<>
{shouldUseNativeImage ? (
<img
className={nativeClassName ?? className}
src={src}
alt={alt}
onError={handleImageError}
onClick={onClick}
/>
) : fill ? (
<Image
className={className}
src={src}
alt={alt}
fill
sizes={sizes}
onError={handleImageError}
onClick={onClick}
/>
) : (
<Image
className={className}
src={src}
alt={alt}
width={width}
height={height}
sizes={sizes}
onError={handleImageError}
onClick={onClick}
/>
)}
{hasError ? null : children}
</>
);
}