Files
chatwoot/app/javascript/dashboard/composables/useFileUpload.js
Sivin Varghese f801c1928d chore: Default file limits for private notes and reset attachment on mode switch (#12310)
# Pull Request Template

## Description

This PR fixes the handling of attachments and file limits in reply
modes:

* Applies **default file size and type limits** for private notes
* **Resets attachments** automatically when switching reply modes


## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## How Has This Been Tested?

### Loom video

https://www.loom.com/share/abad3e6a0383405ea5f31314c1494f2f?sid=38715fd0-e305-4a9b-8f4d-fc6a6e5c0833


## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2025-08-27 11:56:07 +05:30

102 lines
2.8 KiB
JavaScript

import { useMapGetter } from 'dashboard/composables/store';
import { useAlert } from 'dashboard/composables';
import { useI18n } from 'vue-i18n';
import { DirectUpload } from 'activestorage';
import { checkFileSizeLimit } from 'shared/helpers/FileHelper';
import { getMaxUploadSizeByChannel } from '@chatwoot/utils';
import { MAXIMUM_FILE_UPLOAD_SIZE } from 'shared/constants/messages';
/**
* Composable for handling file uploads in conversations
* @param {Object} options
* @param {Object} options.inbox - Current inbox object (has channel_type, medium, etc.)
* @param {Function} options.attachFile - Callback to handle file attachment
* @param {boolean} options.isPrivateNote - Whether the upload is for a private note
*/
export const useFileUpload = ({ inbox, attachFile, isPrivateNote = false }) => {
const { t } = useI18n();
const accountId = useMapGetter('getCurrentAccountId');
const currentUser = useMapGetter('getCurrentUser');
const currentChat = useMapGetter('getSelectedChat');
const globalConfig = useMapGetter('globalConfig/get');
// helper: compute max upload size for a given file's mime
const maxSizeFor = mime => {
// Use default file size limit for private notes
if (isPrivateNote) {
return MAXIMUM_FILE_UPLOAD_SIZE;
}
return getMaxUploadSizeByChannel({
channelType: inbox?.channel_type,
medium: inbox?.medium, // e.g. 'sms' | 'whatsapp' | etc.
mime, // e.g. 'image/png'
});
};
const alertOverLimit = maxSizeMB =>
useAlert(
t('CONVERSATION.FILE_SIZE_LIMIT', {
MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE: maxSizeMB,
})
);
const handleDirectFileUpload = file => {
if (!file) return;
const mime = file.file?.type || file.type;
const maxSizeMB = maxSizeFor(mime);
if (!checkFileSizeLimit(file, maxSizeMB)) {
alertOverLimit(maxSizeMB);
return;
}
const upload = new DirectUpload(
file.file,
`/api/v1/accounts/${accountId.value}/conversations/${currentChat.value.id}/direct_uploads`,
{
directUploadWillCreateBlobWithXHR: xhr => {
xhr.setRequestHeader(
'api_access_token',
currentUser.value.access_token
);
},
}
);
upload.create((error, blob) => {
if (error) {
useAlert(error);
} else {
attachFile({ file, blob });
}
});
};
const handleIndirectFileUpload = file => {
if (!file) return;
const mime = file.file?.type || file.type;
const maxSizeMB = maxSizeFor(mime);
if (!checkFileSizeLimit(file, maxSizeMB)) {
alertOverLimit(maxSizeMB);
return;
}
attachFile({ file });
};
const onFileUpload = file => {
if (globalConfig.value.directUploadsEnabled) {
handleDirectFileUpload(file);
} else {
handleIndirectFileUpload(file);
}
};
return { onFileUpload };
};