mirror of
https://github.com/Qortal/Qortal-Hub.git
synced 2025-07-12 16:01:22 +00:00
started
This commit is contained in:
parent
09c5625a07
commit
5d1ef926c8
@ -3219,7 +3219,7 @@ function App() {
|
|||||||
onClick={onOkUnsavedChanges}
|
onClick={onOkUnsavedChanges}
|
||||||
autoFocus
|
autoFocus
|
||||||
>
|
>
|
||||||
{t('core:action.decline', {
|
{t('core:action.continue_logout', {
|
||||||
postProcess: 'capitalize',
|
postProcess: 'capitalize',
|
||||||
})}
|
})}
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -42,7 +42,7 @@ import CloseIcon from '@mui/icons-material/Close';
|
|||||||
import { throttle } from 'lodash';
|
import { throttle } from 'lodash';
|
||||||
|
|
||||||
const uid = new ShortUniqueId({ length: 5 });
|
const uid = new ShortUniqueId({ length: 5 });
|
||||||
|
const uidImages = new ShortUniqueId({ length: 12 });
|
||||||
export const ChatGroup = ({
|
export const ChatGroup = ({
|
||||||
selectedGroup,
|
selectedGroup,
|
||||||
secretKey,
|
secretKey,
|
||||||
@ -74,6 +74,7 @@ export const ChatGroup = ({
|
|||||||
const [isOpenQManager, setIsOpenQManager] = useState(null);
|
const [isOpenQManager, setIsOpenQManager] = useState(null);
|
||||||
|
|
||||||
const [messageSize, setMessageSize] = useState(0);
|
const [messageSize, setMessageSize] = useState(0);
|
||||||
|
const [chatImagesToSave, setChatImagesToSave] = useState([]);
|
||||||
const hasInitializedWebsocket = useRef(false);
|
const hasInitializedWebsocket = useRef(false);
|
||||||
const socketRef = useRef(null); // WebSocket reference
|
const socketRef = useRef(null); // WebSocket reference
|
||||||
const timeoutIdRef = useRef(null); // Timeout ID reference
|
const timeoutIdRef = useRef(null); // Timeout ID reference
|
||||||
@ -778,11 +779,45 @@ export const ChatGroup = ({
|
|||||||
: {
|
: {
|
||||||
isEdited: chatReference ? true : false,
|
isEdited: chatReference ? true : false,
|
||||||
};
|
};
|
||||||
|
const imagesToPublish = [];
|
||||||
|
if (!chatReference && chatImagesToSave?.length > 0) {
|
||||||
|
chatImagesToSave.forEach((base64Img) => {
|
||||||
|
const identifier = `qchat_1_group_${selectedGroup}_${uidImages.rnd()}`;
|
||||||
|
imagesToPublish.push({
|
||||||
|
service: 'IMAGE',
|
||||||
|
identifier,
|
||||||
|
name: myName,
|
||||||
|
base64: base64Img,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const res = await window.sendMessage(
|
||||||
|
'PUBLISH_MULTIPLE_QDN_RESOURCES',
|
||||||
|
|
||||||
|
{
|
||||||
|
resources: imagesToPublish,
|
||||||
|
},
|
||||||
|
240000,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
console.log('res', res);
|
||||||
|
if (res !== true) throw new Error('Unable to publish images');
|
||||||
|
}
|
||||||
|
|
||||||
const otherData = {
|
const otherData = {
|
||||||
repliedTo,
|
repliedTo,
|
||||||
...(onEditMessage?.decryptedData || {}),
|
...(onEditMessage?.decryptedData || {}),
|
||||||
type: chatReference ? 'edit' : '',
|
type: chatReference ? 'edit' : '',
|
||||||
specialId: uid.rnd(),
|
specialId: uid.rnd(),
|
||||||
|
images:
|
||||||
|
onEditMessage?.images ||
|
||||||
|
imagesToPublish.map((item) => {
|
||||||
|
return {
|
||||||
|
name: item.name,
|
||||||
|
identifier: item.identifier,
|
||||||
|
service: item.service,
|
||||||
|
};
|
||||||
|
}),
|
||||||
...publicData,
|
...publicData,
|
||||||
};
|
};
|
||||||
const objectMessage = {
|
const objectMessage = {
|
||||||
@ -824,6 +859,7 @@ export const ChatGroup = ({
|
|||||||
clearEditorContent();
|
clearEditorContent();
|
||||||
setReplyMessage(null);
|
setReplyMessage(null);
|
||||||
setOnEditMessage(null);
|
setOnEditMessage(null);
|
||||||
|
setChatImagesToSave([]);
|
||||||
}
|
}
|
||||||
// send chat message
|
// send chat message
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -986,6 +1022,10 @@ export const ChatGroup = ({
|
|||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const insertImage = useCallback((img) => {
|
||||||
|
setChatImagesToSave((prev) => [...prev, img]);
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@ -1049,6 +1089,29 @@ export const ChatGroup = ({
|
|||||||
width: 'calc(100% - 100px)',
|
width: 'calc(100% - 100px)',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
alignItems: 'flex-start',
|
||||||
|
display: 'flex',
|
||||||
|
width: '100%',
|
||||||
|
gap: '10px',
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{chatImagesToSave?.map((imgBase64) => {
|
||||||
|
return (
|
||||||
|
<img
|
||||||
|
style={{
|
||||||
|
height: '50px',
|
||||||
|
width: '50px',
|
||||||
|
objectFit: 'contain',
|
||||||
|
borderRadius: '3px',
|
||||||
|
}}
|
||||||
|
src={`data:image/webp;base64,${imgBase64}`}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Box>
|
||||||
{replyMessage && (
|
{replyMessage && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
@ -1104,6 +1167,7 @@ export const ChatGroup = ({
|
|||||||
isFocusedParent={isFocusedParent}
|
isFocusedParent={isFocusedParent}
|
||||||
setIsFocusedParent={setIsFocusedParent}
|
setIsFocusedParent={setIsFocusedParent}
|
||||||
membersWithNames={members}
|
membersWithNames={members}
|
||||||
|
insertImage={insertImage}
|
||||||
/>
|
/>
|
||||||
{messageSize > 750 && (
|
{messageSize > 750 && (
|
||||||
<Box
|
<Box
|
||||||
|
@ -30,6 +30,7 @@ import MentionList from './MentionList.jsx';
|
|||||||
import { isDisabledEditorEnterAtom } from '../../atoms/global.js';
|
import { isDisabledEditorEnterAtom } from '../../atoms/global.js';
|
||||||
import { Box, Checkbox, Typography, useTheme } from '@mui/material';
|
import { Box, Checkbox, Typography, useTheme } from '@mui/material';
|
||||||
import { useAtom } from 'jotai';
|
import { useAtom } from 'jotai';
|
||||||
|
import { fileToBase64 } from '../../utils/fileReading/index.js';
|
||||||
|
|
||||||
function textMatcher(doc, from) {
|
function textMatcher(doc, from) {
|
||||||
const textBeforeCursor = doc.textBetween(0, from, ' ', ' ');
|
const textBeforeCursor = doc.textBetween(0, from, ' ', ' ');
|
||||||
@ -114,7 +115,7 @@ const MenuBar = React.memo(
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (editor) {
|
if (editor && !isChat) {
|
||||||
editor.view.dom.addEventListener('paste', handlePaste);
|
editor.view.dom.addEventListener('paste', handlePaste);
|
||||||
return () => {
|
return () => {
|
||||||
editor.view.dom.removeEventListener('paste', handlePaste);
|
editor.view.dom.removeEventListener('paste', handlePaste);
|
||||||
@ -366,12 +367,46 @@ export default ({
|
|||||||
customEditorHeight,
|
customEditorHeight,
|
||||||
membersWithNames,
|
membersWithNames,
|
||||||
enableMentions,
|
enableMentions,
|
||||||
|
insertImage,
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const [isDisabledEditorEnter, setIsDisabledEditorEnter] = useAtom(
|
const [isDisabledEditorEnter, setIsDisabledEditorEnter] = useAtom(
|
||||||
isDisabledEditorEnterAtom
|
isDisabledEditorEnterAtom
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleImageUpload = async (file) => {
|
||||||
|
try {
|
||||||
|
if (!file.type.includes('image')) return;
|
||||||
|
let compressedFile = file;
|
||||||
|
if (file.type !== 'image/gif') {
|
||||||
|
await new Promise<void>((resolve) => {
|
||||||
|
new Compressor(file, {
|
||||||
|
quality: 0.6,
|
||||||
|
maxWidth: 1200,
|
||||||
|
mimeType: 'image/webp',
|
||||||
|
success(result) {
|
||||||
|
compressedFile = new File([result], 'image.webp', {
|
||||||
|
type: 'image/webp',
|
||||||
|
});
|
||||||
|
resolve();
|
||||||
|
},
|
||||||
|
error(err) {
|
||||||
|
console.error('Image compression error:', err);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compressedFile) {
|
||||||
|
const toBase64 = await fileToBase64(compressedFile);
|
||||||
|
insertImage(toBase64);
|
||||||
|
console.log('toBase64', toBase64);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const extensionsFiltered = isChat
|
const extensionsFiltered = isChat
|
||||||
? extensions.filter((item) => item?.name !== 'image')
|
? extensions.filter((item) => item?.name !== 'image')
|
||||||
: extensions;
|
: extensions;
|
||||||
@ -543,6 +578,24 @@ export default ({
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
handlePaste(view, event) {
|
||||||
|
if (!isChat) return;
|
||||||
|
const items = event.clipboardData?.items;
|
||||||
|
if (!items) return false;
|
||||||
|
|
||||||
|
for (const item of items) {
|
||||||
|
if (item.type.startsWith('image/')) {
|
||||||
|
const file = item.getAsFile();
|
||||||
|
if (file) {
|
||||||
|
event.preventDefault(); // Block the default paste
|
||||||
|
handleImageUpload(file); // Custom handler
|
||||||
|
return true; // Let ProseMirror know we handled it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // fallback to default behavior otherwise
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -1218,6 +1218,7 @@ export const publishMultipleQDNResources = async (
|
|||||||
sender,
|
sender,
|
||||||
isFromExtension
|
isFromExtension
|
||||||
) => {
|
) => {
|
||||||
|
console.log('data', data);
|
||||||
const requiredFields = ['resources'];
|
const requiredFields = ['resources'];
|
||||||
const missingFields: string[] = [];
|
const missingFields: string[] = [];
|
||||||
let feeAmount = null;
|
let feeAmount = null;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user