diff --git a/app/containers/message/Components/Attachments/Reply.tsx b/app/containers/message/Components/Attachments/Reply.tsx
index 74d47da3ceb..833f60918ad 100644
--- a/app/containers/message/Components/Attachments/Reply.tsx
+++ b/app/containers/message/Components/Attachments/Reply.tsx
@@ -17,6 +17,10 @@ import MessageContext from '../../Context';
import Touchable from '../../Touchable';
import messageStyles from '../../styles';
import dayjs from '../../../../lib/dayjs';
+import { CustomIcon } from '../../../CustomIcon';
+import { getFileIcon } from '../../../../lib/methods/getFileIcon';
+import { formatSize } from '../../../../lib/methods/formatSize';
+import { isDocumentFile } from '../../../../lib/methods/isDocumentFile';
const styles = StyleSheet.create({
button: {
@@ -30,6 +34,8 @@ const styles = StyleSheet.create({
flex: 1,
borderRadius: 4,
flexDirection: 'row',
+ alignItems: 'center',
+ gap: 8,
paddingVertical: 4,
paddingLeft: 8
},
@@ -88,6 +94,15 @@ const styles = StyleSheet.create({
flex: 1,
fontSize: 16,
...sharedStyles.textMedium
+ },
+ fileIconContainer: {
+ borderRadius: 4,
+ padding: 4
+ },
+ fileSizeText: {
+ fontSize: 13,
+ lineHeight: 18,
+ ...sharedStyles.textRegular
}
});
@@ -124,6 +139,7 @@ const Description = React.memo(
const { user } = useContext(MessageContext);
const text = attachment.text || attachment.title;
+ const { colors } = useTheme();
if (!text) {
return null;
@@ -134,6 +150,11 @@ const Description = React.memo(
// For other attachments (message quotes, embeds), the text may contain actual markdown formatting,
// so we use the full Markdown component to preserve styling.
const isFileName = attachment.type === 'file' && !attachment.text;
+ const isDocument = isDocumentFile(attachment);
+
+ if (isFileName && isDocument && attachment.size !== undefined) {
+ return {formatSize(attachment.size, 2)};
+ }
if (isFileName) {
return ;
@@ -151,6 +172,12 @@ const Description = React.memo(
if (prevProps.attachment.type !== nextProps.attachment.type) {
return false;
}
+ if (prevProps.attachment.format !== nextProps.attachment.format) {
+ return false;
+ }
+ if (prevProps.attachment.size !== nextProps.attachment.size) {
+ return false;
+ }
return true;
}
);
@@ -209,7 +236,7 @@ const Reply = React.memo(
'use memo';
const [loading, setLoading] = useState(false);
- const { theme } = useTheme();
+ const { theme, colors } = useTheme();
const { baseUrl, user, id, e2e, isEncrypted } = useContext(MessageContext);
if (!attachment || (isEncrypted && !e2e)) {
@@ -236,6 +263,12 @@ const Reply = React.memo(
strokeLight = attachment.color;
}
+ // in case we dont have format in payload, we can extract extention from title
+ const titleParts = attachment.title?.split('.') ?? [];
+ const attachmentFormat = attachment.format ?? titleParts[titleParts.length - 1];
+
+ const isDocument = attachment.type === 'file' && isDocumentFile(attachment) && attachment.title;
+
return (
+ {isDocument && (
+
+
+
+ )}
+
diff --git a/app/containers/message/__snapshots__/Message.test.tsx.snap b/app/containers/message/__snapshots__/Message.test.tsx.snap
index eb164c03554..cb7ab51fb7f 100644
--- a/app/containers/message/__snapshots__/Message.test.tsx.snap
+++ b/app/containers/message/__snapshots__/Message.test.tsx.snap
@@ -1313,9 +1313,11 @@ exports[`Story Snapshots: AttachmentWithTextAndLink should match snapshot 1`] =
{
+ if (!bytes || bytes === 0) return '0 Bytes';
+
+ const k = 1024;
+ const dm = decimals < 0 ? 0 : decimals;
+ const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
+
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
+
+ return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
+};
diff --git a/app/lib/methods/getFileIcon.ts b/app/lib/methods/getFileIcon.ts
new file mode 100644
index 00000000000..771836b3a2a
--- /dev/null
+++ b/app/lib/methods/getFileIcon.ts
@@ -0,0 +1,25 @@
+import { type TIconsName } from '../../containers/CustomIcon';
+
+export const getFileIcon = (format: string): TIconsName => {
+ const fileFormat = format.toLowerCase();
+
+ switch (fileFormat) {
+ case 'pdf':
+ return 'adobe-reader-monochromatic';
+
+ // sheets
+ case 'xls':
+ case 'xlsx':
+ case 'csv':
+ return 'file-sheet';
+
+ // presentations
+ case 'pptx':
+ case 'ppt':
+ return 'engagement-dashboard';
+
+ // other documents
+ default:
+ return 'file-document';
+ }
+};
diff --git a/app/lib/methods/isDocumentFile.ts b/app/lib/methods/isDocumentFile.ts
new file mode 100644
index 00000000000..d2f6a02ce92
--- /dev/null
+++ b/app/lib/methods/isDocumentFile.ts
@@ -0,0 +1,18 @@
+import { type IAttachment } from '../../definitions';
+
+export const isDocumentFile = (attachment: IAttachment) => {
+ if (attachment.type === 'file') {
+ switch (attachment.format?.toLowerCase()) {
+ case 'pdf':
+ case 'xlsx':
+ case 'xls':
+ case 'csv':
+ case 'pptx':
+ case 'ppt':
+ case 'docx':
+ case 'doc':
+ return true;
+ }
+ }
+ return false;
+};