import { LoaderCircle, Play } from "lucide-react";
import { useState } from "react";
import { Link } from "react-router-dom";
import { FavoriteButton } from "../favorites/FavoriteButton";
import { useI18n } from "../i18n";
import { useLocalizedPath } from "../useLocalizedPath";
import type { Attachment, Post } from "../types/post";
import { DownloadCloudIcon } from "./icons/DownloadCloudIcon";
import {
mediaSaveKindFromAttachment,
useSaveToAlbumGuide,
} from "./SaveToAlbumGuide";
import { useToast } from "./Toast";
import { downloadAttachment } from "./messageStream/utils/downloadFile";
import { fileIcon } from "./messageStream/utils/fileIcon";
import {
filenameWithExtension,
splitFilename,
} from "./messageStream/utils/filenameDisplay";
import { formatBytes } from "./messageStream/utils/formatBytes";
import { formatDateTime } from "./messageStream/utils/formatTime";
import { postDisplayText } from "./messageStream/utils/postText";
import { autolink } from "./messageStream/utils/autolink";
function LatestActions({
post,
attachment,
}: {
post: Post;
attachment?: Attachment;
}) {
const { t } = useI18n();
const { showToast } = useToast();
const { showSaveToAlbumGuide } = useSaveToAlbumGuide();
const [isDownloading, setIsDownloading] = useState(false);
const handleDownload = async () => {
if (!attachment || isDownloading) return;
setIsDownloading(true);
try {
await downloadAttachment(post.id, attachment.id, attachment.filename);
const mediaKind = mediaSaveKindFromAttachment(attachment);
if (mediaKind) showSaveToAlbumGuide(mediaKind);
} catch {
showToast(t("downloadFail"), "error");
} finally {
setIsDownloading(false);
}
};
return (
{attachment ? (
) : null}
);
}
function Footer({ post, attachment }: { post: Post; attachment?: Attachment }) {
return (
);
}
function attachmentPreview(att: Attachment | undefined): string {
if (!att) return "";
return att.thumbnailUrl ?? att.posterUrl ?? att.thumbUrl ?? att.url ?? "";
}
function FileCard({ post, att }: { post: Post; att: Attachment }) {
const { lang } = useI18n();
const { Icon, color } = fileIcon({ mime: att.mime, filename: att.filename });
const displayFilename = filenameWithExtension(att.filename, att.mime);
const text = postDisplayText(post, lang);
return (
{(() => {
const { base, ext } = splitFilename(displayFilename);
const tailChars = Math.min(8, base.length);
const head = base.slice(0, base.length - tailChars);
const tail = base.slice(base.length - tailChars) + ext;
return (
<>
{head}
{tail}
>
);
})()}
{formatBytes(att.sizeBytes)}
{text || post.title || displayFilename}
);
}
function MediaGrid({ attachments }: { attachments: Attachment[] }) {
const visible = attachments.slice(0, 4);
const extra = Math.max(0, attachments.length - visible.length);
if (visible.length <= 1) {
const src = attachmentPreview(visible[0]);
return src ? (
) : (
);
}
return (
{visible.map((att, index) => (
})
{extra > 0 && index === visible.length - 1 ? (
+{extra}
) : null}
))}
);
}
function MediaBadge({ att }: { att?: Attachment }) {
if (!att) return null;
return (
{formatBytes(att.sizeBytes)}
);
}
function VisualCard({ post }: { post: Post }) {
const { lang } = useI18n();
const att = post.attachments[0];
const isVideo = att?.kind === "video" || att?.mime.startsWith("video/");
const text = postDisplayText(post, lang);
return (
{text || post.title ? (
{autolink(text || post.title || "")}
) : null}
);
}
function CardLink({ postId }: { postId: string }) {
const lp = useLocalizedPath();
return (
);
}
export function LatestUpdateCard({ post }: { post: Post }) {
const first = post.attachments[0];
const isFile =
!!first &&
!(
first.kind === "image" ||
first.kind === "video" ||
first.mime.startsWith("image/") ||
first.mime.startsWith("video/")
);
if (isFile) return ;
return ;
}