feat: enhance attachment display in inbox

This commit is contained in:
Mohamed Marrouchi
2025-01-17 08:00:45 +01:00
parent f7363563ad
commit 8d1bb47b2a
7 changed files with 134 additions and 50 deletions

View File

@@ -7,20 +7,22 @@
*/
import DownloadIcon from "@mui/icons-material/Download";
import { Button, Dialog, DialogContent } from "@mui/material";
import { Box, Button, Dialog, DialogContent, Typography } from "@mui/material";
import { FC } from "react";
import { DialogTitle } from "@/app-components/dialogs";
import { useDialog } from "@/hooks/useDialog";
import { useGetAttachmentUrl } from "@/hooks/useGetAttachmentUrl";
import { useGetAttachmentMetadata } from "@/hooks/useGetAttachmentMetadata";
import { useTranslate } from "@/hooks/useTranslate";
import {
FileType,
IAttachmentPayload,
StdIncomingAttachmentMessage,
StdOutgoingAttachmentMessage,
} from "@/types/message.types";
interface AttachmentInterface {
name?: string;
url?: string;
}
@@ -70,17 +72,23 @@ const componentMap: { [key in FileType]: FC<AttachmentInterface> } = {
const { t } = useTranslate();
return (
<div>
<span style={{ fontWeight: "bold" }}>{t("label.attachment")}: </span>
<Box>
<Typography
component="span"
className="cs-message__text-content"
mr={2}
>
{props.name}
</Typography>
<Button
href={props.url}
endIcon={<DownloadIcon />}
color="inherit"
variant="text"
variant="contained"
>
{t("button.download")}
</Button>
</div>
</Box>
);
},
[FileType.video]: ({ url }: AttachmentInterface) => (
@@ -91,23 +99,43 @@ const componentMap: { [key in FileType]: FC<AttachmentInterface> } = {
[FileType.unknown]: ({ url }: AttachmentInterface) => <>Unknown Type:{url}</>,
};
export const AttachmentViewer = (props: {
export const MessageAttachmentViewer = ({
attachment,
}: {
attachment: IAttachmentPayload;
}) => {
const metadata = useGetAttachmentMetadata(attachment.payload);
const AttachmentViewerForType = componentMap[attachment.type];
if (!metadata) {
return <>No attachment to display</>;
}
return <AttachmentViewerForType url={metadata.url} name={metadata.name} />;
};
export const MessageAttachmentsViewer = (props: {
message: StdIncomingAttachmentMessage | StdOutgoingAttachmentMessage;
}) => {
const message = props.message;
const getUrl = useGetAttachmentUrl();
// if the attachment is an array show a 4x4 grid with a +{number of remaining attachment} and open a modal to show the list of attachments
// Remark: Messenger doesn't send multiple attachments when user sends multiple at once, it only relays the first one to Hexabot
// TODO: Implenent this
if (!message.attachment) {
return <>No attachment to display</>;
} else if (Array.isArray(message.attachment)) {
return <>Not yet Implemented</>;
}
const AttachmentViewerForType = componentMap[message.attachment.type];
const url = getUrl(message.attachment?.payload);
const attachments = Array.isArray(message.attachment)
? message.attachment
: [message.attachment];
return <AttachmentViewerForType url={url} />;
return attachments.map((attachment, idx) => {
return (
<MessageAttachmentViewer
key={`${attachment.payload.id}-${idx}`}
attachment={attachment}
/>
);
});
};

View File

@@ -21,7 +21,7 @@ import {
} from "@mui/material";
import { forwardRef, useCallback, useEffect, useRef, useState } from "react";
import { useGetAttachmentUrl } from "@/hooks/useGetAttachmentUrl";
import { useGetAttachmentMetadata } from "@/hooks/useGetAttachmentMetadata";
import {
AnyButton as ButtonType,
OutgoingPopulatedListMessage,
@@ -190,7 +190,7 @@ const ListCard = forwardRef<
buttons: ButtonType[];
}
>(function ListCardRef(props, ref) {
const getUrl = useGetAttachmentUrl();
const metadata = useGetAttachmentMetadata(props.content.image_url?.payload);
return (
<Card
@@ -205,9 +205,9 @@ const ListCard = forwardRef<
ref={ref}
id={"A" + props.id}
>
{props.content.image_url ? (
{metadata ? (
<CardMedia
image={getUrl(props.content.image_url.payload)}
image={metadata.url}
sx={{ height: "185px" }}
title={props.content.title}
/>

View File

@@ -1,11 +1,12 @@
/*
* Copyright © 2024 Hexastack. All rights reserved.
* Copyright © 2025 Hexastack. All rights reserved.
*
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
*/
import { Message, MessageModel } from "@chatscope/chat-ui-kit-react";
import MenuRoundedIcon from "@mui/icons-material/MenuRounded";
import ReplyIcon from "@mui/icons-material/Reply";
@@ -17,7 +18,7 @@ import { EntityType } from "@/services/types";
import { IMessage, IMessageFull } from "@/types/message.types";
import { buildURL } from "@/utils/URL";
import { AttachmentViewer } from "../components/AttachmentViewer";
import { MessageAttachmentsViewer } from "../components/AttachmentViewer";
import { Carousel } from "../components/Carousel";
function hasSameSender(
@@ -110,7 +111,7 @@ export function getMessageContent(
if ("attachment" in message) {
content.push(
<Message.CustomContent>
<AttachmentViewer message={message} />
<MessageAttachmentsViewer message={message} />
</Message.CustomContent>,
);
}