added conditions for publish limit and fix image chat

This commit is contained in:
PhilReact 2025-06-05 16:25:53 +03:00
parent a58818b042
commit 7a7013de59
7 changed files with 155 additions and 35 deletions

View File

@ -4,6 +4,8 @@ import { executeEvent } from '../../utils/events';
import { useSetRecoilState } from 'recoil'; import { useSetRecoilState } from 'recoil';
import { navigationControllerAtom } from '../../atoms/global'; import { navigationControllerAtom } from '../../atoms/global';
import { extractComponents } from '../Chat/MessageDisplay'; import { extractComponents } from '../Chat/MessageDisplay';
import { isRunningGateway } from '../../qortalRequests';
import { MAX_SIZE_PUBLIC_NODE, MAX_SIZE_PUBLISH } from '../../constants/constants';
@ -718,6 +720,67 @@ isDOMContentLoaded: false
} }
} else if (event?.data?.action === 'PUBLISH_MULTIPLE_QDN_RESOURCES' || event?.data?.action === 'PUBLISH_QDN_RESOURCE' ) { } else if (event?.data?.action === 'PUBLISH_MULTIPLE_QDN_RESOURCES' || event?.data?.action === 'PUBLISH_QDN_RESOURCE' ) {
let data; let data;
if(event?.data?.action === 'PUBLISH_QDN_RESOURCE'){
try {
const file = event?.data?.file
if (file && file.size > MAX_SIZE_PUBLISH) {
throw new Error(
"Maximum file size allowed is 2 GB per file"
);
}
if (file && file.size > MAX_SIZE_PUBLIC_NODE) {
const isPublicNode = await isRunningGateway();
if (isPublicNode) {
throw new Error(
"Maximum file size allowed on the public node is 500 MB. Please use your local node for larger files."
);
}
}
} catch (error) {
event.ports[0].postMessage({
result: null,
error: error?.message,
});
return;
}
}
if(event?.data?.action === 'PUBLISH_MULTIPLE_QDN_RESOURCES'){
try {
const resources = event.data?.resources
const isPublicNode = await isRunningGateway();
if (isPublicNode) {
const hasOversizedFilePublicNode = resources.some((resource) => {
const file = resource?.file;
return file instanceof File && file.size > MAX_SIZE_PUBLIC_NODE;
});
if (hasOversizedFilePublicNode) {
throw new Error(
"Maximum file size allowed on the public node is 500 MB. Please use your local node for larger files."
);
}
}
const hasOversizedFile = resources.some((resource) => {
const file = resource?.file;
return file instanceof File && file.size > MAX_SIZE_PUBLISH;
});
if (hasOversizedFile) {
throw new Error(
"Maximum file size allowed is 2 GB per file"
);
}
} catch (error) {
event.ports[0].postMessage({
result: null,
error: error?.message,
});
return;
}
}
try { try {
data = saveFileReferences(event.data); data = saveFileReferences(event.data);
} catch (error) { } catch (error) {

View File

@ -121,7 +121,7 @@ export const ChatGroup = ({selectedGroup, secretKey, setSecretKey, getSecretKey,
const onEdit = useCallback((message)=> { const onEdit = useCallback((message)=> {
setOnEditMessage(message) setOnEditMessage(message)
setReplyMessage(null) setReplyMessage(null)
editorRef.current.chain().focus().setContent(message?.messageText || message?.text).run(); editorRef?.current?.chain().focus().setContent(message?.messageText || message?.text || '<p></p>').run();
}, []) }, [])
@ -600,13 +600,28 @@ const sendMessage = async ()=> {
if(+balance < 4) throw new Error('You need at least 4 QORT to send a message') if(+balance < 4) throw new Error('You need at least 4 QORT to send a message')
pauseAllQueues() pauseAllQueues()
if (editorRef.current) { if (editorRef.current) {
const htmlContent = editorRef.current.getHTML(); let htmlContent = editorRef.current.getHTML();
const deleteImage =
if(!htmlContent?.trim() || htmlContent?.trim() === '<p></p>') return onEditMessage && isDeleteImage && messageHasImage(onEditMessage);
setIsSending(true) const hasImage =
const message = isPrivate === false ? editorRef.current.getJSON() : htmlContent chatImagesToSave?.length > 0 || onEditMessage?.images?.length > 0;
if (
(!htmlContent?.trim() || htmlContent?.trim() === '<p></p>') &&
!hasImage &&
!deleteImage
)
return;
if (htmlContent?.trim() === '<p></p>') {
htmlContent = null;
}
setIsSending(true);
const message =
isPrivate === false
? !htmlContent
? '<p></p>'
: editorRef.current.getJSON()
: htmlContent;
const secretKeyObject = await getSecretKey(false, true) const secretKeyObject = await getSecretKey(false, true)
let repliedTo = replyMessage?.signature let repliedTo = replyMessage?.signature
@ -620,8 +635,7 @@ const sendMessage = async ()=> {
isEdited : chatReference ? true : false, isEdited : chatReference ? true : false,
} }
const imagesToPublish = []; const imagesToPublish = [];
const deleteImage =
onEditMessage && isDeleteImage && messageHasImage(onEditMessage);
if (deleteImage) { if (deleteImage) {
const fee = await getFee('ARBITRARY'); const fee = await getFee('ARBITRARY');

View File

@ -267,20 +267,17 @@ export const ChatList = ({
if (chatReferences?.[message.signature]) { if (chatReferences?.[message.signature]) {
reactions = chatReferences[message.signature]?.reactions || null; reactions = chatReferences[message.signature]?.reactions || null;
if (chatReferences[message.signature]?.edit?.message && message?.text) { if (chatReferences[message.signature]?.edit) {
message.text = chatReferences[message.signature]?.edit?.message; message.text =
message.isEdit = true chatReferences[message.signature]?.edit?.message;
message.editTimestamp = chatReferences[message.signature]?.edit?.timestamp message.messageText =
} chatReferences[message.signature]?.edit?.messageText;
if (chatReferences[message.signature]?.edit?.messageText && message?.messageText) {
message.messageText = chatReferences[message.signature]?.edit?.messageText;
message.isEdit = true
message.editTimestamp = chatReferences[message.signature]?.edit?.timestamp
}
if (chatReferences[message.signature]?.edit?.images) {
message.images = message.images =
chatReferences[message.signature]?.edit?.images; chatReferences[message.signature]?.edit?.images;
message.isEdit = true; message.isEdit = true;
message.editTimestamp =
chatReferences[message.signature]?.edit?.timestamp;
} }
} }

View File

@ -34,6 +34,7 @@ import level9Img from "../../assets/badges/level-9.png"
import level10Img from "../../assets/badges/level-10.png" import level10Img from "../../assets/badges/level-10.png"
import { Embed } from "../Embeds/Embed"; import { Embed } from "../Embeds/Embed";
import { buildImageEmbedLink, isHtmlString, messageHasImage } from "../../utils/chat"; import { buildImageEmbedLink, isHtmlString, messageHasImage } from "../../utils/chat";
import CommentsDisabledIcon from '@mui/icons-material/CommentsDisabled';
const getBadgeImg = (level)=> { const getBadgeImg = (level)=> {
switch(level?.toString()){ switch(level?.toString()){
@ -71,6 +72,7 @@ export const MessageItem = React.memo(({
isPrivate isPrivate
}) => { }) => {
const {getIndividualUserInfo} = useContext(MyContext) const {getIndividualUserInfo} = useContext(MyContext)
const [anchorEl, setAnchorEl] = useState(null); const [anchorEl, setAnchorEl] = useState(null);
const [selectedReaction, setSelectedReaction] = useState(null); const [selectedReaction, setSelectedReaction] = useState(null);
@ -130,6 +132,13 @@ const onSeenFunc = useCallback(()=> {
onSeen(message.id); onSeen(message.id);
}, [message?.id]) }, [message?.id])
const hasNoMessage =
(!message.decryptedData?.data?.message ||
message.decryptedData?.data?.message === '<p></p>') &&
(message?.images || [])?.length === 0 &&
(!message?.messageText || message?.messageText === '<p></p>') &&
(!message?.text || message?.text === '<p></p>');
return ( return (
<MessageWragger lastMessage={lastSignature === message?.signature} isLast={isLast} onSeen={onSeenFunc}> <MessageWragger lastMessage={lastSignature === message?.signature} isLast={isLast} onSeen={onSeenFunc}>
@ -312,16 +321,36 @@ const onSeenFunc = useCallback(()=> {
</> </>
)} )}
<MessageDisplay {htmlText && !hasNoMessage && (
htmlContent={htmlText} <MessageDisplay htmlContent={htmlText} />
/> )}
{message?.decryptedData?.type === "notification" ? ( {message?.decryptedData?.type === 'notification' ? (
<MessageDisplay htmlContent={message.decryptedData?.data?.message} /> <MessageDisplay
) : ( htmlContent={message.decryptedData?.data?.message}
<MessageDisplay htmlContent={message.text} /> />
)} ) : hasNoMessage ? null : (
{message?.images && messageHasImage(message) && ( <MessageDisplay htmlContent={message.text} />
)}
{hasNoMessage && (
<Box
sx={{
display: 'flex',
alignItems: 'center',
gap: '10px',
}}
>
<CommentsDisabledIcon sx={{
color: 'white'
}} />
<Typography sx={{
color: 'white'
}}>
No message
</Typography>
</Box>
)}
{message?.images && messageHasImage(message) && (
<Embed embedLink={buildImageEmbedLink(message.images[0])} /> <Embed embedLink={buildImageEmbedLink(message.images[0])} />
)} )}
<Box <Box
@ -499,6 +528,7 @@ const onSeenFunc = useCallback(()=> {
export const ReplyPreview = ({message, isEdit})=> { export const ReplyPreview = ({message, isEdit})=> {
const replyMessageText = useMemo(() => { const replyMessageText = useMemo(() => {
if (!message?.messageText) return null;
const isHtml = isHtmlString(message?.messageText); const isHtml = isHtmlString(message?.messageText);
if (isHtml) return message?.messageText; if (isHtml) return message?.messageText;
return generateHTML(message?.messageText, [ return generateHTML(message?.messageText, [
@ -543,7 +573,7 @@ export const ReplyPreview = ({message, isEdit})=> {
}}>Replied to {message?.senderName || message?.senderAddress}</Typography> }}>Replied to {message?.senderName || message?.senderAddress}</Typography>
)} )}
{message?.messageText && ( {replyMessageText && (
<MessageDisplay <MessageDisplay
htmlContent={replyMessageText} htmlContent={replyMessageText}
/> />

View File

@ -50,6 +50,8 @@ export const ImageCard = ({
backgroundColor: "#1F2023", backgroundColor: "#1F2023",
height: height, height: height,
transition: "height 0.6s ease-in-out", transition: "height 0.6s ease-in-out",
display: 'flex',
flexDirection: 'column',
}} }}
> >
<Box <Box
@ -168,8 +170,18 @@ export const ImageCard = ({
)} )}
</Box> </Box>
<Box> <Box
<CardContent> sx={{
maxHeight: '100%',
flexGrow: 1,
overflow: 'hidden',
}}
>
<CardContent
sx={{
height: '100%',
}}
>
<ImageViewer src={image} /> <ImageViewer src={image} />
</CardContent> </CardContent>
</Box> </Box>
@ -192,6 +204,7 @@ export const ImageCard = ({
display: "flex", display: "flex",
justifyContent: "center", justifyContent: "center",
cursor: "pointer", cursor: "pointer",
height: '100%',
}} }}
onClick={handleOpenFullscreen} onClick={handleOpenFullscreen}
> >

View File

@ -55,7 +55,7 @@ export const NewUsersCTA = ({ balance }) => {
}} }}
onClick={() => { onClick={() => {
if (chrome && chrome.tabs) { if (chrome && chrome.tabs) {
chrome.tabs.create({ url: "https://link.qortal.dev/telegram-invite" }, (tab) => { chrome.tabs.create({ url: "https://link.qortal.dev/support" }, (tab) => {
if (chrome.runtime.lastError) { if (chrome.runtime.lastError) {
console.error("Error opening tab:", chrome.runtime.lastError); console.error("Error opening tab:", chrome.runtime.lastError);
} else { } else {
@ -66,7 +66,7 @@ export const NewUsersCTA = ({ balance }) => {
}} }}
> >
Telegram Nextcloud
</ButtonBase> </ButtonBase>
<ButtonBase <ButtonBase
sx={{ sx={{

View File

@ -173,3 +173,6 @@ const STATIC_BCRYPT_SALT = `$${BCRYPT_VERSION}$${BCRYPT_ROUNDS}$IxVE941tXVUD4cW0
const KDF_THREADS = 16 const KDF_THREADS = 16
export { TX_TYPES, ERROR_CODES, QORT_DECIMALS, PROXY_URL, STATIC_SALT, ADDRESS_VERSION, KDF_THREADS, STATIC_BCRYPT_SALT, CHAT_REFERENCE_FEATURE_TRIGGER_TIMESTAMP, DYNAMIC_FEE_TIMESTAMP } export { TX_TYPES, ERROR_CODES, QORT_DECIMALS, PROXY_URL, STATIC_SALT, ADDRESS_VERSION, KDF_THREADS, STATIC_BCRYPT_SALT, CHAT_REFERENCE_FEATURE_TRIGGER_TIMESTAMP, DYNAMIC_FEE_TIMESTAMP }
export const MAX_SIZE_PUBLIC_NODE = 500 * 1024 * 1024; // 500mb
export const MAX_SIZE_PUBLISH = 2000 * 1024 * 1024; // 2GB