popover for payment and message - users avatar

This commit is contained in:
PhilReact 2024-09-14 11:42:05 +03:00
parent 93fba38de3
commit bf27a4f566
17 changed files with 1145 additions and 681 deletions

View File

@ -82,7 +82,7 @@ import {
groupApiSocket, groupApiSocket,
groupApiSocketLocal, groupApiSocketLocal,
} from "./background"; } from "./background";
import { executeEvent } from "./utils/events"; import { executeEvent, subscribeToEvent, unsubscribeFromEvent } from "./utils/events";
import { requestQueueCommentCount, requestQueuePublishedAccouncements } from "./components/Chat/GroupAnnouncements"; import { requestQueueCommentCount, requestQueuePublishedAccouncements } from "./components/Chat/GroupAnnouncements";
import { requestQueueGroupJoinRequests } from "./components/Group/GroupJoinRequests"; import { requestQueueGroupJoinRequests } from "./components/Group/GroupJoinRequests";
import { DrawerComponent } from "./components/Drawer/Drawer"; import { DrawerComponent } from "./components/Drawer/Drawer";
@ -293,7 +293,8 @@ function App() {
const [confirmUseOfLocal, setConfirmUseOfLocal] = useState(false); const [confirmUseOfLocal, setConfirmUseOfLocal] = useState(false);
const [isOpenDrawerProfile, setIsOpenDrawerProfile] = useState(false); const [isOpenDrawerProfile, setIsOpenDrawerProfile] = useState(false);
const [apiKey, setApiKey] = useState(""); const [apiKey, setApiKey] = useState("");
const [isOpenSendQort, setIsOpenSendQort] = useState(false)
const [isOpenSendQortSuccess, setIsOpenSendQortSuccess] = useState(false)
useEffect(() => { useEffect(() => {
if(!isMobile) return if(!isMobile) return
// Function to set the height of the app to the viewport height // Function to set the height of the app to the viewport height
@ -519,7 +520,9 @@ function App() {
if (response?.error) { if (response?.error) {
setSendPaymentError(response.error); setSendPaymentError(response.error);
} else { } else {
setExtstate("transfer-success-regular"); setIsOpenSendQort(false)
setIsOpenSendQortSuccess(true)
// setExtstate("transfer-success-regular");
// setSendPaymentSuccess("Payment successfully sent"); // setSendPaymentSuccess("Payment successfully sent");
} }
setIsLoading(false); setIsLoading(false);
@ -901,6 +904,8 @@ function App() {
setWalletToBeDownloaded(null); setWalletToBeDownloaded(null);
setWalletToBeDownloadedPassword(""); setWalletToBeDownloadedPassword("");
setExtstate("authenticated"); setExtstate("authenticated");
setIsOpenSendQort(false)
setIsOpenSendQortSuccess(false)
}; };
const resetAllStates = () => { const resetAllStates = () => {
@ -1026,6 +1031,17 @@ function App() {
// Handler for when the window gains focus // Handler for when the window gains focus
const handleFocus = () => { const handleFocus = () => {
setIsFocused(true); setIsFocused(true);
if(isMobile){
chrome?.runtime?.sendMessage(
{
action: "clearAllNotifications",
payload: {
},
}
);
}
console.log("Webview is focused"); console.log("Webview is focused");
}; };
@ -1043,6 +1059,16 @@ function App() {
const handleVisibilityChange = () => { const handleVisibilityChange = () => {
if (document.visibilityState === "visible") { if (document.visibilityState === "visible") {
setIsFocused(true); setIsFocused(true);
if(isMobile){
chrome?.runtime?.sendMessage(
{
action: "clearAllNotifications",
payload: {
},
}
);
}
console.log("Webview is visible"); console.log("Webview is visible");
} else { } else {
setIsFocused(false); setIsFocused(false);
@ -1060,6 +1086,22 @@ function App() {
}; };
}, []); }, []);
const openPaymentInternal = (e) => {
const directAddress = e.detail?.address;
const name = e.detail?.name
setIsOpenSendQort(true)
setPaymentTo(name || directAddress)
};
useEffect(() => {
subscribeToEvent("openPaymentInternal", openPaymentInternal);
return () => {
unsubscribeFromEvent("openPaymentInternal", openPaymentInternal);
};
}, []);
const registerName = async () => { const registerName = async () => {
try { try {
if (!userInfo?.address) throw new Error("Your address was not found"); if (!userInfo?.address) throw new Error("Your address was not found");
@ -1262,7 +1304,8 @@ function App() {
<Spacer height="20px" /> <Spacer height="20px" />
<CustomButton <CustomButton
onClick={() => { onClick={() => {
setExtstate("send-qort"); setIsOpenSendQort(true)
// setExtstate("send-qort");
setIsOpenDrawerProfile(false) setIsOpenDrawerProfile(false)
}} }}
> >
@ -1584,8 +1627,17 @@ function App() {
</MyContext.Provider> </MyContext.Provider>
)} )}
{extState === "send-qort" && isMainWindow && ( {isOpenSendQort && isMainWindow && (
<> <Box sx={{
width: '100%',
height: '100%',
position: 'fixed',
background: '#27282c',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
zIndex: 6
}}>
<Spacer height="22px" /> <Spacer height="22px" />
<Box <Box
sx={{ sx={{
@ -1691,7 +1743,7 @@ function App() {
> >
Send Send
</CustomButton> </CustomButton>
</> </Box>
)} )}
{extState === "web-app-request-buy-order" && !isMainWindow && ( {extState === "web-app-request-buy-order" && !isMainWindow && (
<> <>
@ -2225,8 +2277,17 @@ function App() {
)} )}
</> </>
)} )}
{extState === "transfer-success-regular" && ( {isOpenSendQortSuccess && (
<> <Box sx={{
width: '100%',
height: '100%',
position: 'fixed',
background: '#27282c',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
zIndex: 6
}}>
<Spacer height="48px" /> <Spacer height="48px" />
<img src={Success} /> <img src={Success} />
<Spacer height="45px" /> <Spacer height="45px" />
@ -2246,7 +2307,7 @@ function App() {
> >
Continue Continue
</CustomButton> </CustomButton>
</> </Box>
)} )}
{extState === "transfer-success-request" && ( {extState === "transfer-success-request" && (
<> <>

View File

@ -202,7 +202,7 @@ export function isExtMsg(data){
} catch (error) { } catch (error) {
isMsgFromExtensionGroup = false isMsgFromExtensionGroup = false
} }
console.log('isMsgFromExtensionGroup', isMsgFromExtensionGroup)
return isMsgFromExtensionGroup return isMsgFromExtensionGroup
} }
@ -264,7 +264,7 @@ if (!oldestLatestTimestamp || oldChat?.timestamp > oldestLatestTimestamp?.timest
} }
}); });
console.log('newestLatestTimestamp', newestLatestTimestamp)
if(checkDifference(newestLatestTimestamp.timestamp) && !oldestLatestTimestamp || (newestLatestTimestamp && newestLatestTimestamp?.timestamp > oldestLatestTimestamp?.timestamp)){ if(checkDifference(newestLatestTimestamp.timestamp) && !oldestLatestTimestamp || (newestLatestTimestamp && newestLatestTimestamp?.timestamp > oldestLatestTimestamp?.timestamp)){
const notificationId = 'chat_notification_' + Date.now() + '_type=direct' + `_from=${newestLatestTimestamp.address}`; const notificationId = 'chat_notification_' + Date.now() + '_type=direct' + `_from=${newestLatestTimestamp.address}`;
chrome.notifications.create(notificationId, { chrome.notifications.create(notificationId, {
@ -460,7 +460,7 @@ const handleNotification = async (groups)=> {
if(checkDifference(newestLatestTimestamp.timestamp) && !oldestLatestTimestamp || (newestLatestTimestamp && newestLatestTimestamp?.timestamp > oldestLatestTimestamp?.timestamp)){ if(checkDifference(newestLatestTimestamp.timestamp) && !oldestLatestTimestamp || (newestLatestTimestamp && newestLatestTimestamp?.timestamp > oldestLatestTimestamp?.timestamp)){
if (!lastGroupNotification || ((Date.now() - lastGroupNotification) >= 120000)) { if (!lastGroupNotification || ((Date.now() - lastGroupNotification) >= 120000)) {
if(!newestLatestTimestamp?.data || !isExtMsg(newestLatestTimestamp?.data)) return if(!newestLatestTimestamp?.data || !isExtMsg(newestLatestTimestamp?.data)) return
console.log('newestLatestTimestamp', newestLatestTimestamp)
const notificationId = 'chat_notification_' + Date.now() + '_type=group' + `_from=${newestLatestTimestamp.groupId}`; const notificationId = 'chat_notification_' + Date.now() + '_type=group' + `_from=${newestLatestTimestamp.groupId}`;
chrome.notifications.create(notificationId, { chrome.notifications.create(notificationId, {
@ -859,6 +859,13 @@ async function getSaveWallet() {
} }
} }
async function clearAllNotifications(){
const notifications = await chrome.notifications.getAll();
for (const notificationId of Object.keys(notifications)) {
await chrome.notifications.clear(notificationId);
}
}
async function getUserInfo() { async function getUserInfo() {
const wallet = await getSaveWallet(); const wallet = await getSaveWallet();
const address = wallet.address0; const address = wallet.address0;
@ -1502,7 +1509,7 @@ async function decryptDirectFunc({ messages, involvingAddress }) {
publicKey: uint8PublicKey, publicKey: uint8PublicKey,
}; };
for (const message of messages) { for (const message of messages) {
console.log('messagedep', message)
try { try {
const decodedMessage = decryptChatMessage( const decodedMessage = decryptChatMessage(
message.data, message.data,
@ -2905,6 +2912,18 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
}); });
break; break;
} }
case "clearAllNotifications": {
;
clearAllNotifications()
.then((res) => {
})
.catch((error) => {
});
break;
}
case "setGroupData": { case "setGroupData": {
const { groupId, const { groupId,

View File

@ -283,6 +283,7 @@ export const AnnouncementDiscussion = ({
disableComment disableComment
showLoadMore={comments.length > 0 && comments.length % 20 === 0} showLoadMore={comments.length > 0 && comments.length % 20 === 0}
loadMore={loadMore} loadMore={loadMore}
myName={myName}
/> />
<div <div
@ -331,6 +332,29 @@ export const AnnouncementDiscussion = ({
flexShrink: 0, flexShrink: 0,
position: 'relative', position: 'relative',
}}> }}>
{isFocusedParent && (
<CustomButton
onClick={()=> {
if(isSending) return
setIsFocusedParent(false)
clearEditorContent()
// Unfocus the editor
}}
style={{
marginTop: 'auto',
alignSelf: 'center',
cursor: isSending ? 'default' : 'pointer',
flexShrink: 0,
padding: isMobile && '5px',
fontSize: isMobile && '14px',
background: 'red',
}}
>
{` Close`}
</CustomButton>
)}
<CustomButton <CustomButton
onClick={() => { onClick={() => {
if (isSending) return; if (isSending) return;
@ -361,29 +385,7 @@ export const AnnouncementDiscussion = ({
)} )}
{` Publish Comment`} {` Publish Comment`}
</CustomButton> </CustomButton>
{isFocusedParent && (
<CustomButton
onClick={()=> {
if(isSending) return
setIsFocusedParent(false)
clearEditorContent()
// Unfocus the editor
}}
style={{
marginTop: 'auto',
alignSelf: 'center',
cursor: isSending ? 'default' : 'pointer',
background: isSending && 'rgba(0, 0, 0, 0.8)',
flexShrink: 0,
padding: isMobile && '5px',
fontSize: isMobile && '14px',
}}
>
{` Close`}
</CustomButton>
)}
</Box> </Box>
</div> </div>

View File

@ -10,7 +10,8 @@ import { getBaseApi } from "../../background";
import { requestQueueCommentCount } from "./GroupAnnouncements"; import { requestQueueCommentCount } from "./GroupAnnouncements";
import { CustomLoader } from "../../common/CustomLoader"; import { CustomLoader } from "../../common/CustomLoader";
import { getBaseApiReact } from "../../App"; import { getBaseApiReact } from "../../App";
export const AnnouncementItem = ({ message, messageData, setSelectedAnnouncement, disableComment }) => { import { WrapperUserAction } from "../WrapperUserAction";
export const AnnouncementItem = ({ message, messageData, setSelectedAnnouncement, disableComment, myName }) => {
const [commentLength, setCommentLength] = useState(0) const [commentLength, setCommentLength] = useState(0)
const getNumberOfComments = React.useCallback( const getNumberOfComments = React.useCallback(
@ -63,6 +64,7 @@ export const AnnouncementItem = ({ message, messageData, setSelectedAnnouncement
width: '100%', width: '100%',
wordBreak: 'break-word' wordBreak: 'break-word'
}}> }}>
<WrapperUserAction disabled={myName === message?.name} address={undefined} name={message?.name}>
<Avatar <Avatar
sx={{ sx={{
backgroundColor: '#27282c', backgroundColor: '#27282c',
@ -73,6 +75,7 @@ export const AnnouncementItem = ({ message, messageData, setSelectedAnnouncement
> >
{message?.name?.charAt(0)} {message?.name?.charAt(0)}
</Avatar> </Avatar>
</WrapperUserAction>
<Box <Box
sx={{ sx={{
display: "flex", display: "flex",
@ -81,6 +84,7 @@ export const AnnouncementItem = ({ message, messageData, setSelectedAnnouncement
width: '100%' width: '100%'
}} }}
> >
<WrapperUserAction disabled={myName === message?.name} address={undefined} name={message?.name}>
<Typography <Typography
sx={{ sx={{
fontWight: 600, fontWight: 600,
@ -90,6 +94,7 @@ export const AnnouncementItem = ({ message, messageData, setSelectedAnnouncement
> >
{message?.name} {message?.name}
</Typography> </Typography>
</WrapperUserAction>
{!messageData?.decryptedData && ( {!messageData?.decryptedData && (
<Box sx={{ <Box sx={{
width: '100%', width: '100%',

View File

@ -20,7 +20,8 @@ export const AnnouncementList = ({
setSelectedAnnouncement, setSelectedAnnouncement,
disableComment, disableComment,
showLoadMore, showLoadMore,
loadMore loadMore,
myName
}) => { }) => {
const listRef = useRef(); const listRef = useRef();
@ -63,7 +64,7 @@ export const AnnouncementList = ({
alignItems: "center", alignItems: "center",
}} }}
> >
<AnnouncementItem disableComment={disableComment} setSelectedAnnouncement={setSelectedAnnouncement} message={message} messageData={messageData} /> <AnnouncementItem myName={myName} disableComment={disableComment} setSelectedAnnouncement={setSelectedAnnouncement} message={message} messageData={messageData} />
</div> </div>
); );

View File

@ -6,7 +6,7 @@ import "@chatscope/chat-ui-kit-styles/dist/default/styles.min.css";
import Tiptap from './TipTap' import Tiptap from './TipTap'
import { CustomButton } from '../../App-styles' import { CustomButton } from '../../App-styles'
import CircularProgress from '@mui/material/CircularProgress'; import CircularProgress from '@mui/material/CircularProgress';
import { Box, Input } from '@mui/material'; import { Box, Input, Typography } from '@mui/material';
import { LoadingSnackbar } from '../Snackbar/LoadingSnackbar'; import { LoadingSnackbar } from '../Snackbar/LoadingSnackbar';
import { getNameInfo } from '../Group/Group'; import { getNameInfo } from '../Group/Group';
import { Spacer } from '../../common/Spacer'; import { Spacer } from '../../common/Spacer';
@ -14,14 +14,13 @@ import { CustomizedSnackbars } from '../Snackbar/Snackbar';
import { getBaseApiReactSocket, isMobile, pauseAllQueues, resumeAllQueues } from '../../App'; import { getBaseApiReactSocket, isMobile, pauseAllQueues, resumeAllQueues } from '../../App';
import { getPublicKey } from '../../background'; import { getPublicKey } from '../../background';
import { useMessageQueue } from '../../MessageQueueContext'; import { useMessageQueue } from '../../MessageQueueContext';
import { executeEvent } from '../../utils/events'; import { executeEvent, subscribeToEvent, unsubscribeFromEvent } from '../../utils/events';
import zIndex from '@mui/material/styles/zIndex'; import ArrowBackIcon from '@mui/icons-material/ArrowBack';
export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDirect, setNewChat, getTimestampEnterChat, myName, balance, close}) => {
export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDirect, setNewChat, getTimestampEnterChat, myName, balance}) => {
const { queueChats, addToQueue, } = useMessageQueue(); const { queueChats, addToQueue, } = useMessageQueue();
const [isFocusedParent, setIsFocusedParent] = useState(false); const [isFocusedParent, setIsFocusedParent] = useState(false);
@ -187,7 +186,16 @@ export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDi
}; };
}; };
const setDirectChatValueFunc = async (e)=> {
setDirectToValue(e.detail.directToValue)
}
useEffect(() => {
subscribeToEvent("setDirectToValueNewChat", setDirectChatValueFunc);
return () => {
unsubscribeFromEvent("setDirectToValueNewChat", setDirectChatValueFunc);
};
}, []);
useEffect(() => { useEffect(() => {
if (hasInitializedWebsocket.current || isNewChat) return; if (hasInitializedWebsocket.current || isNewChat) return;
@ -327,6 +335,27 @@ console.log('isFocusedParent', isFocusedParent)
flexDirection: 'column', flexDirection: 'column',
width: '100%' width: '100%'
}}> }}>
<Box onClick={close} sx={{
display: 'flex',
alignItems: 'center',
gap: '5px',
cursor: 'pointer',
padding: '4px 6px',
width: 'fit-content',
borderRadius: '3px',
background: 'rgb(35, 36, 40)',
margin: '10px 0px',
alignSelf: 'center'
}}>
<ArrowBackIcon sx={{
color: 'white',
fontSize: isMobile ? '20px' : '20px'
}}/>
<Typography sx={{
color: 'white',
fontSize: isMobile ? '14px' : '14px'
}}>Close Direct Chat</Typography>
</Box>
{isNewChat && ( {isNewChat && (
<> <>
<Spacer height="30px" /> <Spacer height="30px" />
@ -375,6 +404,28 @@ console.log('isFocusedParent', isFocusedParent)
flexShrink: 0, flexShrink: 0,
position: 'relative', position: 'relative',
}}> }}>
{isFocusedParent && (
<CustomButton
onClick={()=> {
if(isSending) return
setIsFocusedParent(false)
clearEditorContent()
// Unfocus the editor
}}
style={{
marginTop: 'auto',
alignSelf: 'center',
cursor: isSending ? 'default' : 'pointer',
background: 'red',
flexShrink: 0,
padding: isMobile && '5px'
}}
>
{` Close`}
</CustomButton>
)}
<CustomButton <CustomButton
onClick={()=> { onClick={()=> {
if(isSending) return if(isSending) return
@ -404,28 +455,7 @@ console.log('isFocusedParent', isFocusedParent)
)} )}
{` Send`} {` Send`}
</CustomButton> </CustomButton>
{isFocusedParent && (
<CustomButton
onClick={()=> {
if(isSending) return
setIsFocusedParent(false)
clearEditorContent()
// Unfocus the editor
}}
style={{
marginTop: 'auto',
alignSelf: 'center',
cursor: isSending ? 'default' : 'pointer',
background: isSending && 'rgba(0, 0, 0, 0.8)',
flexShrink: 0,
padding: isMobile && '5px'
}}
>
{` Close`}
</CustomButton>
)}
</Box> </Box>
</div> </div>
<LoadingSnackbar open={isLoading} info={{ <LoadingSnackbar open={isLoading} info={{

View File

@ -395,6 +395,28 @@ const clearEditorContent = () => {
flexShrink: 0, flexShrink: 0,
position: 'relative', position: 'relative',
}}> }}>
{isFocusedParent && (
<CustomButton
onClick={()=> {
if(isSending) return
setIsFocusedParent(false)
clearEditorContent()
// Unfocus the editor
}}
style={{
marginTop: 'auto',
alignSelf: 'center',
cursor: isSending ? 'default' : 'pointer',
background: 'red',
flexShrink: 0,
padding: isMobile && '5px'
}}
>
{` Close`}
</CustomButton>
)}
<CustomButton <CustomButton
onClick={()=> { onClick={()=> {
if(isSending) return if(isSending) return
@ -425,28 +447,7 @@ const clearEditorContent = () => {
)} )}
{` Send`} {` Send`}
</CustomButton> </CustomButton>
{isFocusedParent && (
<CustomButton
onClick={()=> {
if(isSending) return
setIsFocusedParent(false)
clearEditorContent()
// Unfocus the editor
}}
style={{
marginTop: 'auto',
alignSelf: 'center',
cursor: isSending ? 'default' : 'pointer',
background: isSending && 'rgba(0, 0, 0, 0.8)',
flexShrink: 0,
padding: isMobile && '5px'
}}
>
{` Close`}
</CustomButton>
)}
</Box> </Box>
{/* <button onClick={sendMessage}>send</button> */} {/* <button onClick={sendMessage}>send</button> */}
</div> </div>

View File

@ -126,6 +126,7 @@ export const ChatList = ({ initialMessages, myAddress, tempMessages }) => {
message={message} message={message}
onSeen={handleMessageSeen} onSeen={handleMessageSeen}
isTemp={!!message?.isTemp} isTemp={!!message?.isTemp}
myAddress={myAddress}
/> />
</div> </div>
</div> </div>

View File

@ -301,6 +301,7 @@ export const GroupAnnouncements = ({
} }
// send chat message // send chat message
} catch (error) { } catch (error) {
if(!error) return
setInfoSnack({ setInfoSnack({
type: "error", type: "error",
message: error, message: error,
@ -542,6 +543,7 @@ export const GroupAnnouncements = ({
disableComment={false} disableComment={false}
showLoadMore={announcements.length > 0 && announcements.length % 20 === 0} showLoadMore={announcements.length > 0 && announcements.length % 20 === 0}
loadMore={loadMore} loadMore={loadMore}
myName={myName}
/> />
@ -591,6 +593,29 @@ export const GroupAnnouncements = ({
flexShrink: 0, flexShrink: 0,
position: 'relative', position: 'relative',
}}> }}>
{isFocusedParent && (
<CustomButton
onClick={()=> {
if(isSending) return
setIsFocusedParent(false)
clearEditorContent()
// Unfocus the editor
}}
style={{
marginTop: 'auto',
alignSelf: 'center',
cursor: isSending ? 'default' : 'pointer',
background: 'red',
flexShrink: 0,
padding: isMobile && '5px',
fontSize: isMobile && '14px',
}}
>
{` Close`}
</CustomButton>
)}
<CustomButton <CustomButton
onClick={() => { onClick={() => {
if (isSending) return; if (isSending) return;
@ -622,29 +647,7 @@ export const GroupAnnouncements = ({
)} )}
{` Publish Announcement`} {` Publish Announcement`}
</CustomButton> </CustomButton>
{isFocusedParent && (
<CustomButton
onClick={()=> {
if(isSending) return
setIsFocusedParent(false)
clearEditorContent()
// Unfocus the editor
}}
style={{
marginTop: 'auto',
alignSelf: 'center',
cursor: isSending ? 'default' : 'pointer',
background: isSending && 'rgba(0, 0, 0, 0.8)',
flexShrink: 0,
padding: isMobile && '5px',
fontSize: isMobile && '14px',
}}
>
{` Close`}
</CustomButton>
)}
</Box> </Box>
</div> </div>
)} )}

View File

@ -10,7 +10,9 @@ import { generateHTML } from "@tiptap/react";
import Highlight from '@tiptap/extension-highlight' import Highlight from '@tiptap/extension-highlight'
import StarterKit from '@tiptap/starter-kit' import StarterKit from '@tiptap/starter-kit'
import Underline from '@tiptap/extension-underline' import Underline from '@tiptap/extension-underline'
export const MessageItem = ({ message, onSeen, isLast, isTemp }) => { import { executeEvent } from "../../utils/events";
import { WrapperUserAction } from "../WrapperUserAction";
export const MessageItem = ({ message, onSeen, isLast, isTemp, myAddress }) => {
const { ref, inView } = useInView({ const { ref, inView } = useInView({
threshold: 0.7, // Fully visible threshold: 0.7, // Fully visible
@ -36,6 +38,7 @@ export const MessageItem = ({ message, onSeen, isLast, isTemp }) => {
opacity: isTemp ? 0.5 : 1 opacity: isTemp ? 0.5 : 1
}} }}
> >
<WrapperUserAction disabled={myAddress === message?.sender} address={message?.sender} name={message?.senderName}>
<Avatar <Avatar
sx={{ sx={{
backgroundColor: '#27282c', backgroundColor: '#27282c',
@ -46,6 +49,7 @@ export const MessageItem = ({ message, onSeen, isLast, isTemp }) => {
> >
{message?.senderName?.charAt(0)} {message?.senderName?.charAt(0)}
</Avatar> </Avatar>
</WrapperUserAction>
<Box <Box
sx={{ sx={{
display: "flex", display: "flex",
@ -54,15 +58,18 @@ export const MessageItem = ({ message, onSeen, isLast, isTemp }) => {
width: '100%' width: '100%'
}} }}
> >
<WrapperUserAction disabled={myAddress === message?.sender} address={message?.sender} name={message?.senderName}>
<Typography <Typography
sx={{ sx={{
fontWight: 600, fontWight: 600,
fontFamily: "Inter", fontFamily: "Inter",
color: "cadetBlue", color: "cadetBlue",
}} }}
> >
{message?.senderName || message?.sender} {message?.senderName || message?.sender}
</Typography> </Typography>
</WrapperUserAction>
{message?.messageText && ( {message?.messageText && (
<MessageDisplay htmlContent={generateHTML(message?.messageText, [StarterKit, Underline, Highlight])} /> <MessageDisplay htmlContent={generateHTML(message?.messageText, [StarterKit, Underline, Highlight])} />
)} )}

View File

@ -54,6 +54,7 @@ import { LoadingSnackbar } from "../../Snackbar/LoadingSnackbar";
import { executeEvent, subscribeToEvent, unsubscribeFromEvent } from "../../../utils/events"; import { executeEvent, subscribeToEvent, unsubscribeFromEvent } from "../../../utils/events";
import RefreshIcon from '@mui/icons-material/Refresh'; import RefreshIcon from '@mui/icons-material/Refresh';
import { getBaseApiReact } from "../../../App"; import { getBaseApiReact } from "../../../App";
import { WrapperUserAction } from "../../WrapperUserAction";
const filterOptions = ["Recently active", "Newest", "Oldest"]; const filterOptions = ["Recently active", "Newest", "Oldest"];
export const threadIdentifier = "DOCUMENT"; export const threadIdentifier = "DOCUMENT";
@ -672,6 +673,7 @@ export const GroupMail = ({
} }
}} }}
> >
<Avatar <Avatar
sx={{ sx={{
height: "50px", height: "50px",
@ -682,11 +684,14 @@ export const GroupMail = ({
> >
{thread?.threadData?.name?.charAt(0)} {thread?.threadData?.name?.charAt(0)}
</Avatar> </Avatar>
<ThreadInfoColumn> <ThreadInfoColumn>
<ThreadInfoColumnNameP> <ThreadInfoColumnNameP>
<ThreadInfoColumnbyP>by </ThreadInfoColumnbyP> <ThreadInfoColumnbyP>by </ThreadInfoColumnbyP>
{thread?.threadData?.name} {thread?.threadData?.name}
</ThreadInfoColumnNameP> </ThreadInfoColumnNameP>
<ThreadInfoColumnTime> <ThreadInfoColumnTime>
{formatTimestamp(thread?.threadData?.createdAt)} {formatTimestamp(thread?.threadData?.createdAt)}
</ThreadInfoColumnTime> </ThreadInfoColumnTime>

View File

@ -19,8 +19,9 @@ import ReadOnlySlate from "./ReadOnlySlate";
import { MessageDisplay } from "../../Chat/MessageDisplay"; import { MessageDisplay } from "../../Chat/MessageDisplay";
import { getBaseApi } from "../../../background"; import { getBaseApi } from "../../../background";
import { getBaseApiReact } from "../../../App"; import { getBaseApiReact } from "../../../App";
import { WrapperUserAction } from "../../WrapperUserAction";
export const ShowMessage = ({ message, openNewPostWithQuote }: any) => { export const ShowMessage = ({ message, openNewPostWithQuote, myName }: any) => {
const [expandAttachments, setExpandAttachments] = useState<boolean>(false); const [expandAttachments, setExpandAttachments] = useState<boolean>(false);
let cleanHTML = ""; let cleanHTML = "";
@ -53,13 +54,17 @@ export const ShowMessage = ({ message, openNewPostWithQuote }: any) => {
}} }}
> >
<WrapperUserAction disabled={myName === message?.name} address={undefined} name={message?.name}>
<Avatar sx={{ <Avatar sx={{
height: '50px', height: '50px',
width: '50px' width: '50px'
}} src={`${getBaseApiReact()}/arbitrary/THUMBNAIL/${message?.name}/qortal_avatar?async=true`} alt={message?.name}>{message?.name?.charAt(0)}</Avatar> }} src={`${getBaseApiReact()}/arbitrary/THUMBNAIL/${message?.name}/qortal_avatar?async=true`} alt={message?.name}>{message?.name?.charAt(0)}</Avatar>
</WrapperUserAction>
<ThreadInfoColumn> <ThreadInfoColumn>
<WrapperUserAction disabled={myName === message?.name} address={undefined} name={message?.name}>
<ThreadInfoColumnNameP>{message?.name}</ThreadInfoColumnNameP> <ThreadInfoColumnNameP>{message?.name}</ThreadInfoColumnNameP>
</WrapperUserAction>
<ThreadInfoColumnTime> <ThreadInfoColumnTime>
{formatTimestampForum(message?.created)} {formatTimestampForum(message?.created)}
</ThreadInfoColumnTime> </ThreadInfoColumnTime>

View File

@ -531,6 +531,7 @@ export const Thread = ({
key={message?.identifier} key={message?.identifier}
message={fullMessage} message={fullMessage}
openNewPostWithQuote={openNewPostWithQuote} openNewPostWithQuote={openNewPostWithQuote}
myName={userInfo?.name}
/> />
); );
} else if(message?.tempData){ } else if(message?.tempData){
@ -539,6 +540,7 @@ export const Thread = ({
key={message?.identifier} key={message?.identifier}
message={message?.tempData} message={message?.tempData}
openNewPostWithQuote={openNewPostWithQuote} openNewPostWithQuote={openNewPostWithQuote}
myName={userInfo?.name}
/> />
); );
} }

View File

@ -30,9 +30,9 @@ import MarkUnreadChatAltIcon from "@mui/icons-material/MarkUnreadChatAlt";
import AddCircleOutlineIcon from "@mui/icons-material/AddCircleOutline"; import AddCircleOutlineIcon from "@mui/icons-material/AddCircleOutline";
import CreateIcon from "@mui/icons-material/Create"; import CreateIcon from "@mui/icons-material/Create";
import RefreshIcon from "@mui/icons-material/Refresh"; import RefreshIcon from "@mui/icons-material/Refresh";
import AnnouncementsIcon from '@mui/icons-material/Notifications'; import AnnouncementsIcon from "@mui/icons-material/Notifications";
import GroupIcon from '@mui/icons-material/Group'; import GroupIcon from "@mui/icons-material/Group";
import PersonIcon from '@mui/icons-material/Person'; import PersonIcon from "@mui/icons-material/Person";
import { import {
AuthenticatedContainerInnerRight, AuthenticatedContainerInnerRight,
CustomButton, CustomButton,
@ -56,7 +56,7 @@ import { LoadingButton } from "@mui/lab";
import { LoadingSnackbar } from "../Snackbar/LoadingSnackbar"; import { LoadingSnackbar } from "../Snackbar/LoadingSnackbar";
import { GroupAnnouncements } from "../Chat/GroupAnnouncements"; import { GroupAnnouncements } from "../Chat/GroupAnnouncements";
import HomeIcon from "@mui/icons-material/Home"; import HomeIcon from "@mui/icons-material/Home";
import CloseIcon from '@mui/icons-material/Close'; import CloseIcon from "@mui/icons-material/Close";
import { ThingsToDoInitial } from "./ThingsToDoInitial"; import { ThingsToDoInitial } from "./ThingsToDoInitial";
import { GroupJoinRequests } from "./GroupJoinRequests"; import { GroupJoinRequests } from "./GroupJoinRequests";
@ -96,7 +96,6 @@ import { isExtMsg } from "../../background";
// } // }
// }); // });
interface GroupProps { interface GroupProps {
myAddress: string; myAddress: string;
isFocused: boolean; isFocused: boolean;
@ -223,8 +222,8 @@ export const getGroupAdimns = async (groupNumber: number) => {
); );
const groupData = await response.json(); const groupData = await response.json();
let members: any = []; let members: any = [];
let membersAddresses = [] let membersAddresses = [];
let both = [] let both = [];
// if (groupData && Array.isArray(groupData?.members)) { // if (groupData && Array.isArray(groupData?.members)) {
// for (const member of groupData.members) { // for (const member of groupData.members) {
// if (member.member) { // if (member.member) {
@ -243,16 +242,16 @@ export const getGroupAdimns = async (groupNumber: number) => {
}); });
if (name) { if (name) {
members.push(name); members.push(name);
both.push({name, address: member.member}) both.push({ name, address: member.member });
} }
membersAddresses.push(member.member) membersAddresses.push(member.member);
} }
return true; return true;
}); });
await Promise.all(getMemNames); await Promise.all(getMemNames);
return {names: members, addresses: membersAddresses, both}; return { names: members, addresses: membersAddresses, both };
}; };
export const getNames = async (listOfMembers) => { export const getNames = async (listOfMembers) => {
@ -314,7 +313,8 @@ export const Group = ({
isMain, isMain,
userInfo, userInfo,
balance, balance,
isOpenDrawerProfile, setIsOpenDrawerProfile isOpenDrawerProfile,
setIsOpenDrawerProfile,
}: GroupProps) => { }: GroupProps) => {
const [secretKey, setSecretKey] = useState(null); const [secretKey, setSecretKey] = useState(null);
const [secretKeyPublishDate, setSecretKeyPublishDate] = useState(null); const [secretKeyPublishDate, setSecretKeyPublishDate] = useState(null);
@ -355,7 +355,7 @@ export const Group = ({
const [defaultThread, setDefaultThread] = React.useState(null); const [defaultThread, setDefaultThread] = React.useState(null);
const [isOpenDrawer, setIsOpenDrawer] = React.useState(false); const [isOpenDrawer, setIsOpenDrawer] = React.useState(false);
const [drawerMode, setDrawerMode] = React.useState('groups'); const [drawerMode, setDrawerMode] = React.useState("groups");
const isFocusedRef = useRef(true); const isFocusedRef = useRef(true);
const selectedGroupRef = useRef(null); const selectedGroupRef = useRef(null);
const selectedDirectRef = useRef(null); const selectedDirectRef = useRef(null);
@ -410,21 +410,20 @@ export const Group = ({
{ {
action: "getGroupDataSingle", action: "getGroupDataSingle",
payload: { payload: {
groupId groupId,
} },
}, },
(response) => { (response) => {
if (!response?.error) { if (!response?.error) {
res(response); res(response);
return return;
} }
rej(response.error); rej(response.error);
} }
); );
}); });
} catch (error) { } catch (error) {
return {} return {};
} }
}; };
const refreshHomeDataFunc = () => { const refreshHomeDataFunc = () => {
@ -526,11 +525,12 @@ export const Group = ({
let hasUnread = false; let hasUnread = false;
groups.forEach((group) => { groups.forEach((group) => {
if ( if (
group?.data && isExtMsg(group?.data) && group?.sender !== myAddress && group?.data &&
isExtMsg(group?.data) &&
group?.sender !== myAddress &&
group?.timestamp && group?.timestamp &&
((!timestampEnterData[group?.groupId] && ((!timestampEnterData[group?.groupId] &&
Date.now() - group?.timestamp < Date.now() - group?.timestamp < timeDifferenceForNotificationChats) ||
timeDifferenceForNotificationChats) ||
timestampEnterData[group?.groupId] < group?.timestamp) timestampEnterData[group?.groupId] < group?.timestamp)
) { ) {
hasUnread = true; hasUnread = true;
@ -599,15 +599,17 @@ export const Group = ({
try { try {
// setGroupDataLastSet(null) // setGroupDataLastSet(null)
pauseAllQueues(); pauseAllQueues();
let dataFromStorage let dataFromStorage;
let publishFromStorage let publishFromStorage;
let adminsFromStorage let adminsFromStorage;
const groupData = await getGroupDataSingle(selectedGroup?.groupId) const groupData = await getGroupDataSingle(selectedGroup?.groupId);
if(groupData?.secretKeyData && Date.now() - groupData?.timestampLastSet < 3600000 ){ if (
groupData?.secretKeyData &&
dataFromStorage = groupData.secretKeyData Date.now() - groupData?.timestampLastSet < 3600000
publishFromStorage = groupData.secretKeyResource ) {
adminsFromStorage = groupData.admins dataFromStorage = groupData.secretKeyData;
publishFromStorage = groupData.secretKeyResource;
adminsFromStorage = groupData.admins;
// setGroupDataLastSet(groupData.timestampLastSet) // setGroupDataLastSet(groupData.timestampLastSet)
} }
@ -629,13 +631,15 @@ export const Group = ({
} }
const prevGroupId = selectedGroupRef.current.groupId; const prevGroupId = selectedGroupRef.current.groupId;
// const validApi = await findUsableApi(); // const validApi = await findUsableApi();
const {names, addresses, both} = adminsFromStorage || await getGroupAdimns(selectedGroup?.groupId); const { names, addresses, both } =
adminsFromStorage || (await getGroupAdimns(selectedGroup?.groupId));
setAdmins(addresses); setAdmins(addresses);
setAdminsWithNames(both) setAdminsWithNames(both);
if (!names.length) { if (!names.length) {
throw new Error("Network error"); throw new Error("Network error");
} }
const publish = publishFromStorage || await getPublishesFromAdmins(names); const publish =
publishFromStorage || (await getPublishesFromAdmins(names));
if (prevGroupId !== selectedGroupRef.current.groupId) { if (prevGroupId !== selectedGroupRef.current.groupId) {
if (settimeoutForRefetchSecretKey.current) { if (settimeoutForRefetchSecretKey.current) {
@ -651,9 +655,9 @@ export const Group = ({
return false; return false;
} }
setSecretKeyPublishDate(publish?.updated || publish?.created); setSecretKeyPublishDate(publish?.updated || publish?.created);
let data let data;
if(dataFromStorage){ if (dataFromStorage) {
data = dataFromStorage data = dataFromStorage;
} else { } else {
const res = await fetch( const res = await fetch(
`${getBaseApiReact()}/arbitrary/DOCUMENT_PRIVATE/${publish.name}/${ `${getBaseApiReact()}/arbitrary/DOCUMENT_PRIVATE/${publish.name}/${
@ -663,7 +667,6 @@ export const Group = ({
data = await res.text(); data = await res.text();
} }
const decryptedKey: any = await decryptResource(data); const decryptedKey: any = await decryptResource(data);
const dataint8Array = base64ToUint8Array(decryptedKey.data); const dataint8Array = base64ToUint8Array(decryptedKey.data);
@ -675,17 +678,15 @@ export const Group = ({
setSecretKey(decryptedKeyToObject); setSecretKey(decryptedKeyToObject);
lastFetchedSecretKey.current = Date.now(); lastFetchedSecretKey.current = Date.now();
setMemberCountFromSecretKeyData(decryptedKey.count); setMemberCountFromSecretKeyData(decryptedKey.count);
chrome?.runtime?.sendMessage( chrome?.runtime?.sendMessage({
{
action: "setGroupData", action: "setGroupData",
payload: { payload: {
groupId: selectedGroup?.groupId, groupId: selectedGroup?.groupId,
secretKeyData: data, secretKeyData: data,
secretKeyResource: publish, secretKeyResource: publish,
admins: {names, addresses, both} admins: { names, addresses, both },
}, },
} });
);
if (decryptedKeyToObject) { if (decryptedKeyToObject) {
setTriedToFetchSecretKey(true); setTriedToFetchSecretKey(true);
setFirstSecretKeyInCreation(false); setFirstSecretKeyInCreation(false);
@ -915,12 +916,16 @@ export const Group = ({
} catch (error) {} } catch (error) {}
}; };
useEffect(() => { useEffect(() => {
if (!initiatedGetMembers.current && selectedGroup?.groupId && secretKey && admins.includes(myAddress)) { if (
!initiatedGetMembers.current &&
console.log('goung through', admins) selectedGroup?.groupId &&
secretKey &&
admins.includes(myAddress)
) {
console.log("goung through", admins);
// getAdmins(selectedGroup?.groupId); // getAdmins(selectedGroup?.groupId);
getMembers(selectedGroup?.groupId); getMembers(selectedGroup?.groupId);
initiatedGetMembers.current = true initiatedGetMembers.current = true;
} }
}, [selectedGroup?.groupId, secretKey, myAddress, admins]); }, [selectedGroup?.groupId, secretKey, myAddress, admins]);
@ -998,7 +1003,7 @@ export const Group = ({
.filter((group) => group?.sender !== myAddress) .filter((group) => group?.sender !== myAddress)
.find((gr) => gr?.groupId === selectedGroup?.groupId); .find((gr) => gr?.groupId === selectedGroup?.groupId);
if (!findGroup) return false; if (!findGroup) return false;
if(!findGroup?.data || !isExtMsg(findGroup?.data)) return false if (!findGroup?.data || !isExtMsg(findGroup?.data)) return false;
return ( return (
findGroup?.timestamp && findGroup?.timestamp &&
((!timestampEnterData[selectedGroup?.groupId] && ((!timestampEnterData[selectedGroup?.groupId] &&
@ -1030,7 +1035,7 @@ export const Group = ({
if (findDirect) { if (findDirect) {
setChatMode("directs"); setChatMode("directs");
setSelectedDirect(null); setSelectedDirect(null);
setSelectedGroup(null); // setSelectedGroup(null);
setNewChat(false); setNewChat(false);
@ -1052,6 +1057,52 @@ export const Group = ({
} }
}; };
const openDirectChatFromInternal = (e) => {
const directAddress = e.detail?.address;
const name = e.detail?.name
const findDirect = directs?.find(
(direct) => direct?.address === directAddress || direct?.name === name
);
if (findDirect) {
setChatMode("directs");
setSelectedDirect(null);
// setSelectedGroup(null);
setNewChat(false);
chrome?.runtime?.sendMessage({
action: "addTimestampEnterChat",
payload: {
timestamp: Date.now(),
groupId: findDirect.address,
},
});
setTimeout(() => {
setSelectedDirect(findDirect);
getTimestampEnterChat();
}, 200);
} else {
setChatMode('directs')
setNewChat(true);
setTimeout(() => {
executeEvent("setDirectToValueNewChat", {
directToValue: name || directAddress
});
}, 500);
}
};
useEffect(() => {
subscribeToEvent("openDirectMessageInternal", openDirectChatFromInternal);
return () => {
unsubscribeFromEvent("openDirectMessageInternal", openDirectChatFromInternal);
};
}, [directs, selectedDirect]);
useEffect(() => { useEffect(() => {
subscribeToEvent("openDirectMessage", openDirectChatFromNotification); subscribeToEvent("openDirectMessage", openDirectChatFromNotification);
@ -1106,7 +1157,7 @@ export const Group = ({
isLoadingOpenSectionFromNotification.current = false; isLoadingOpenSectionFromNotification.current = false;
setupGroupWebsocketInterval.current = null; setupGroupWebsocketInterval.current = null;
settimeoutForRefetchSecretKey.current = null; settimeoutForRefetchSecretKey.current = null;
initiatedGetMembers.current = false initiatedGetMembers.current = false;
}; };
const logoutEventFunc = () => { const logoutEventFunc = () => {
@ -1275,7 +1326,7 @@ export const Group = ({
setFirstSecretKeyInCreation(true); setFirstSecretKeyInCreation(true);
}; };
const goToHome = async ()=> { const goToHome = async () => {
setGroupSection("default"); setGroupSection("default");
clearAllQueues(); clearAllQueues();
await new Promise((res) => { await new Promise((res) => {
@ -1297,9 +1348,9 @@ export const Group = ({
setMemberCountFromSecretKeyData(null); setMemberCountFromSecretKeyData(null);
setTriedToFetchSecretKey(false); setTriedToFetchSecretKey(false);
setFirstSecretKeyInCreation(false); setFirstSecretKeyInCreation(false);
} };
const goToAnnouncements = async ()=> { const goToAnnouncements = async () => {
setGroupSection("default"); setGroupSection("default");
await new Promise((res) => { await new Promise((res) => {
setTimeout(() => { setTimeout(() => {
@ -1317,9 +1368,9 @@ export const Group = ({
setTimeout(() => { setTimeout(() => {
getGroupAnnouncements(); getGroupAnnouncements();
}, 200); }, 200);
} };
const goToChat = async ()=> { const goToChat = async () => {
setGroupSection("default"); setGroupSection("default");
await new Promise((res) => { await new Promise((res) => {
setTimeout(() => { setTimeout(() => {
@ -1340,9 +1391,9 @@ export const Group = ({
getTimestampEnterChat(); getTimestampEnterChat();
}, 200); }, 200);
} }
} };
const renderGroups = ()=> { const renderGroups = () => {
return ( return (
<div <div
style={{ style={{
@ -1360,30 +1411,37 @@ export const Group = ({
justifyContent: "center", justifyContent: "center",
gap: "20px", gap: "20px",
padding: "10px", padding: "10px",
flexDirection: 'column' flexDirection: "column",
}} }}
> >
{isMobile && ( {isMobile && (
<Box sx={{ <Box
width: '100%', sx={{
display: 'flex', width: "100%",
justifyContent: 'flex-end' display: "flex",
}}><CloseIcon onClick={()=> { justifyContent: "flex-end",
setIsOpenDrawer(false) }}
}} sx={{ >
cursor: 'pointer', <CloseIcon
color: 'white' onClick={() => {
}} /></Box> setIsOpenDrawer(false);
}}
sx={{
cursor: "pointer",
color: "white",
}}
/>
</Box>
)} )}
<CustomButton <CustomButton
onClick={() => { onClick={() => {
setChatMode((prev) => setChatMode((prev) =>
prev === "directs" ? "groups" : "directs" prev === "directs" ? "groups" : "directs"
); );
setNewChat(false); // setNewChat(false);
setSelectedDirect(null); // setSelectedDirect(null);
setSelectedGroup(null); // setSelectedGroup(null);
setGroupSection("default"); // setGroupSection("default");
}} }}
> >
{chatMode === "groups" && ( {chatMode === "groups" && (
@ -1422,8 +1480,8 @@ export const Group = ({
onClick={() => { onClick={() => {
setSelectedDirect(null); setSelectedDirect(null);
setNewChat(false); setNewChat(false);
setSelectedGroup(null); // setSelectedGroup(null);
setIsOpenDrawer(false) setIsOpenDrawer(false);
chrome?.runtime?.sendMessage({ chrome?.runtime?.sendMessage({
action: "addTimestampEnterChat", action: "addTimestampEnterChat",
payload: { payload: {
@ -1548,14 +1606,13 @@ export const Group = ({
setFirstSecretKeyInCreation(false); setFirstSecretKeyInCreation(false);
// setGroupSection("announcement"); // setGroupSection("announcement");
setGroupSection("chat"); setGroupSection("chat");
setIsOpenDrawer(false) setIsOpenDrawer(false);
setTimeout(() => { setTimeout(() => {
setSelectedGroup(group); setSelectedGroup(group);
// getTimestampEnterChat(); // getTimestampEnterChat();
}, 200); }, 200);
chrome?.runtime?.sendMessage({ chrome?.runtime?.sendMessage({
action: "addTimestampEnterChat", action: "addTimestampEnterChat",
payload: { payload: {
@ -1568,7 +1625,6 @@ export const Group = ({
getTimestampEnterChat(); getTimestampEnterChat();
}, 200); }, 200);
// if (groupSectionRef.current === "announcement") { // if (groupSectionRef.current === "announcement") {
// chrome?.runtime?.sendMessage({ // chrome?.runtime?.sendMessage({
// action: "addGroupNotificationTimestamp", // action: "addGroupNotificationTimestamp",
@ -1618,15 +1674,13 @@ export const Group = ({
primaryTypographyProps={{ primaryTypographyProps={{
style: { style: {
color: color:
group?.groupId === selectedGroup?.groupId && group?.groupId === selectedGroup?.groupId && "black",
"black",
}, },
}} // Change the color of the primary text }} // Change the color of the primary text
secondaryTypographyProps={{ secondaryTypographyProps={{
style: { style: {
color: color:
group?.groupId === selectedGroup?.groupId && group?.groupId === selectedGroup?.groupId && "black",
"black",
}, },
}} }}
sx={{ sx={{
@ -1644,7 +1698,9 @@ export const Group = ({
}} }}
/> />
)} )}
{group?.data && isExtMsg(group?.data) && group?.sender !== myAddress && {group?.data &&
isExtMsg(group?.data) &&
group?.sender !== myAddress &&
group?.timestamp && group?.timestamp &&
((!timestampEnterData[group?.groupId] && ((!timestampEnterData[group?.groupId] &&
Date.now() - group?.timestamp < Date.now() - group?.timestamp <
@ -1689,8 +1745,8 @@ export const Group = ({
onClick={() => { onClick={() => {
setNewChat(true); setNewChat(true);
setSelectedDirect(null); setSelectedDirect(null);
setSelectedGroup(null); // setSelectedGroup(null);
setIsOpenDrawer(false) setIsOpenDrawer(false);
}} }}
> >
<CreateIcon <CreateIcon
@ -1703,8 +1759,8 @@ export const Group = ({
)} )}
</div> </div>
</div> </div>
) );
} };
return ( return (
<> <>
@ -1729,6 +1785,11 @@ export const Group = ({
}} }}
> >
{!isMobile && renderGroups()} {!isMobile && renderGroups()}
<Box sx={{
width: '100%',
height: '100%',
position: 'relative'
}}>
<AddGroup <AddGroup
address={myAddress} address={myAddress}
open={openAddGroup} open={openAddGroup}
@ -1736,6 +1797,17 @@ export const Group = ({
/> />
{newChat && ( {newChat && (
<> <>
<Box
sx={{
position: "absolute",
left: '0px',
right: '0px',
bottom: '0px',
top: '0px',
background: '#27282c',
zIndex: 5
}}
>
<ChatDirect <ChatDirect
myAddress={myAddress} myAddress={myAddress}
myName={userInfo?.name} myName={userInfo?.name}
@ -1745,10 +1817,16 @@ export const Group = ({
setNewChat={setNewChat} setNewChat={setNewChat}
getTimestampEnterChat={getTimestampEnterChat} getTimestampEnterChat={getTimestampEnterChat}
balance={balance} balance={balance}
close={()=> {
setSelectedDirect(null);
setNewChat(false);
}}
/> />
</Box>
</> </>
)} )}
{selectedGroup && !newChat && ( {selectedGroup && (
<> <>
<Box <Box
sx={{ sx={{
@ -1923,14 +2001,30 @@ export const Group = ({
{selectedDirect && !newChat && ( {selectedDirect && !newChat && (
<> <>
<Box
sx={{
position: "absolute",
left: '0px',
right: '0px',
bottom: '0px',
top: '0px',
background: '#27282c',
zIndex: 5
}}
>
<Box <Box
sx={{ sx={{
position: "relative", position: "relative",
flexGrow: 1, flexGrow: 1,
display: "flex", display: "flex",
height: '100%' height: "100%",
}} }}
> >
<ChatDirect <ChatDirect
myAddress={myAddress} myAddress={myAddress}
isNewChat={newChat} isNewChat={newChat}
@ -1939,13 +2033,18 @@ export const Group = ({
setNewChat={setNewChat} setNewChat={setNewChat}
getTimestampEnterChat={getTimestampEnterChat} getTimestampEnterChat={getTimestampEnterChat}
myName={userInfo?.name} myName={userInfo?.name}
close={()=> {
setSelectedDirect(null);
setNewChat(false);
}}
/> />
</Box> </Box>
</Box>
</> </>
)} )}
{!selectedDirect && {
!selectedGroup && !selectedGroup &&
!newChat &&
groupSection === "home" && ( groupSection === "home" && (
<Box <Box
sx={{ sx={{
@ -1953,8 +2052,8 @@ export const Group = ({
width: "100%", width: "100%",
flexDirection: "column", flexDirection: "column",
gap: "20px", gap: "20px",
height: '100%', height: "100%",
overflow: 'auto' overflow: "auto",
}} }}
> >
<Box <Box
@ -1981,9 +2080,11 @@ export const Group = ({
display: "flex", display: "flex",
gap: "40px", gap: "40px",
flexWrap: "wrap", flexWrap: "wrap",
justifyContent: 'center' justifyContent: "center",
}} }}
> >
<ListOfThreadPostsWatched />
<ThingsToDoInitial <ThingsToDoInitial
balance={balance} balance={balance}
myAddress={myAddress} myAddress={myAddress}
@ -2003,19 +2104,18 @@ export const Group = ({
myAddress={myAddress} myAddress={myAddress}
groups={groups} groups={groups}
/> />
<ListOfThreadPostsWatched />
</Box> </Box>
)} )}
</Box> </Box>
)} )}
</Box>
<AuthenticatedContainerInnerRight <AuthenticatedContainerInnerRight
sx={{ sx={{
marginLeft: "auto", marginLeft: "auto",
width: "135px", width: "135px",
minWidth: "135px", minWidth: "135px",
padding: "5px", padding: "5px",
display: isMobile ? 'none' : 'flex' display: isMobile ? "none" : "flex",
}} }}
> >
<Spacer height="20px" /> <Spacer height="20px" />
@ -2209,10 +2309,11 @@ export const Group = ({
message: "Setting up groups... please wait.", message: "Setting up groups... please wait.",
}} }}
/> />
</div> </div>
<DrawerComponent open={isOpenDrawer} setOpen={setIsOpenDrawer} >{renderGroups()}</DrawerComponent> <DrawerComponent open={isOpenDrawer} setOpen={setIsOpenDrawer}>
{renderGroups()}
</DrawerComponent>
{isMobile && ( {isMobile && (
<Box <Box
@ -2226,8 +2327,12 @@ export const Group = ({
background: "rgba(0, 0, 0, 0.1)", background: "rgba(0, 0, 0, 0.1)",
padding: "0px", // Remove unnecessary padding padding: "0px", // Remove unnecessary padding
}} }}
> >
<Grid container spacing={0.5} sx={{ width: "100%", justifyContent: "space-around" }}> <Grid
container
spacing={0.5}
sx={{ width: "100%", justifyContent: "space-around" }}
>
{selectedGroup && ( {selectedGroup && (
<> <>
<Grid item xs={4}> <Grid item xs={4}>
@ -2236,10 +2341,36 @@ export const Group = ({
size="small" size="small"
variant="contained" variant="contained"
startIcon={<AnnouncementsIcon />} startIcon={<AnnouncementsIcon />}
sx={{ padding: '4px 6px', sx={{
color: groupSection === 'announcement' ? 'black' : 'white', padding: "4px 6px",
color:
groupSection === "announcement" ? "black" : "white",
backgroundColor: isUnread backgroundColor: isUnread
? "red" : groupSection === 'announcement' ? 'white' : 'black', ? "red"
: groupSection === "announcement"
? "white"
: "black",
"&:hover": {
backgroundColor: isUnread
? "red"
: groupSection === "announcement"
? "white"
: "black",
},
"&:active": {
backgroundColor: isUnread
? "red"
: groupSection === "announcement"
? "white"
: "black",
},
"&:focus": {
backgroundColor: isUnread
? "red"
: groupSection === "announcement"
? "white"
: "black",
},
}} }}
onClick={goToAnnouncements} onClick={goToAnnouncements}
> >
@ -2252,10 +2383,36 @@ export const Group = ({
size="small" size="small"
variant="contained" variant="contained"
startIcon={<ChatIcon />} startIcon={<ChatIcon />}
sx={{ padding: '4px 6px', color: groupSection === 'chat' ? 'black' : 'white', sx={{
padding: "4px 6px",
color: groupSection === "chat" ? "black" : "white",
backgroundColor: isUnreadChat backgroundColor: isUnreadChat
? "red" ? "red"
: groupSection === 'chat' ? 'white' : 'black', }} : groupSection === "chat"
? "white"
: "black",
"&:hover": {
backgroundColor: isUnreadChat
? "red"
: groupSection === "chat"
? "white"
: "black", // Same logic for hover
},
"&:active": {
backgroundColor: isUnreadChat
? "red"
: groupSection === "chat"
? "white"
: "black", // Same logic for active
},
"&:focus": {
backgroundColor: isUnreadChat
? "red"
: groupSection === "chat"
? "white"
: "black", // Same logic for focus
},
}}
onClick={goToChat} onClick={goToChat}
> >
Chat Chat
@ -2267,8 +2424,21 @@ export const Group = ({
size="small" size="small"
variant="contained" variant="contained"
startIcon={<ForumIcon />} startIcon={<ForumIcon />}
sx={{ padding: '4px 6px', color: groupSection === 'forum' ? 'black' : 'white', sx={{
backgroundColor: groupSection === 'forum' ? 'white' : 'black', }} padding: "4px 6px",
color: groupSection === "forum" ? "black" : "white",
backgroundColor:
groupSection === "forum" ? "white" : "black",
"&:hover": {
backgroundColor: groupSection === "forum" ? "white" : "black", // Hover state
},
"&:active": {
backgroundColor: groupSection === "forum" ? "white" : "black", // Active state
},
"&:focus": {
backgroundColor: groupSection === "forum" ? "white" : "black", // Focus state
},
}}
onClick={() => setGroupSection("forum")} onClick={() => setGroupSection("forum")}
> >
Forum Forum
@ -2280,7 +2450,15 @@ export const Group = ({
size="small" size="small"
variant="contained" variant="contained"
startIcon={<GroupIcon />} startIcon={<GroupIcon />}
sx={{ padding: '4px 6px', backgroundColor: 'black' }} sx={{ padding: "4px 6px", backgroundColor: "black", "&:hover": {
backgroundColor: "black", // Hover state
},
"&:active": {
backgroundColor: "black", // Active state
},
"&:focus": {
backgroundColor: "black", // Focus state
}, }}
onClick={() => setOpenManageMembers(true)} onClick={() => setOpenManageMembers(true)}
> >
Members Members
@ -2296,7 +2474,33 @@ export const Group = ({
size="small" size="small"
variant="contained" variant="contained"
startIcon={<GroupIcon />} startIcon={<GroupIcon />}
sx={{ padding: '2px 4px', backgroundColor: groupChatHasUnread || groupsAnnHasUnread || directChatHasUnread ? "red" : 'black' }} sx={{
padding: "2px 4px",
backgroundColor:
groupChatHasUnread ||
groupsAnnHasUnread ||
directChatHasUnread
? "red"
: "black",
"&:hover": {
backgroundColor:
groupChatHasUnread || groupsAnnHasUnread || directChatHasUnread
? "red"
: "black", // Hover state follows the same logic
},
"&:active": {
backgroundColor:
groupChatHasUnread || groupsAnnHasUnread || directChatHasUnread
? "red"
: "black", // Active state follows the same logic
},
"&:focus": {
backgroundColor:
groupChatHasUnread || groupsAnnHasUnread || directChatHasUnread
? "red"
: "black", // Focus state follows the same logic
},
}}
onClick={() => { onClick={() => {
setIsOpenDrawer(true); setIsOpenDrawer(true);
setDrawerMode("groups"); setDrawerMode("groups");
@ -2307,7 +2511,7 @@ export const Group = ({
</Grid> </Grid>
<Grid item xs={2}> <Grid item xs={2}>
<IconButton <IconButton
sx={{ padding: '0', color: 'white' }} // Reduce padding for icons sx={{ padding: "0", color: "white" }} // Reduce padding for icons
onClick={goToHome} onClick={goToHome}
> >
<HomeIcon /> <HomeIcon />
@ -2315,18 +2519,15 @@ export const Group = ({
</Grid> </Grid>
<Grid item xs={2}> <Grid item xs={2}>
<IconButton <IconButton
sx={{ padding: '0', color: 'white' }} // Reduce padding for icons sx={{ padding: "0", color: "white" }} // Reduce padding for icons
onClick={() => setIsOpenDrawerProfile(true)} onClick={() => setIsOpenDrawerProfile(true)}
> >
<PersonIcon /> <PersonIcon />
</IconButton> </IconButton>
</Grid> </Grid>
</Grid> </Grid>
</Box> </Box>
)}
)}
</> </>
); );
}; };

View File

@ -14,7 +14,7 @@ export const Loader = () => {
left:'0px', left:'0px',
right: '0px', right: '0px',
bottom: '0px', bottom: '0px',
zIndex: 2, zIndex: 10,
background: 'rgba(0, 0, 0, 0.4)' background: 'rgba(0, 0, 0, 0.4)'
}}> }}>
<CircularProgress color="success" size={25} /> <CircularProgress color="success" size={25} />

View File

@ -0,0 +1,108 @@
import React, { useState } from 'react';
import { Popover, Button, Box } from '@mui/material';
import { executeEvent } from '../utils/events';
export const WrapperUserAction = ({ children, address, name, disabled }) => {
const [anchorEl, setAnchorEl] = useState(null);
// Handle child element click to open Popover
const handleChildClick = (event) => {
event.stopPropagation(); // Prevent parent onClick from firing
setAnchorEl(event.currentTarget);
};
// Handle closing the Popover
const handleClose = () => {
setAnchorEl(null);
};
// Determine if the popover is open
const open = Boolean(anchorEl);
const id = open ? address || name : undefined;
if(disabled){
return children
}
return (
<>
<Box
onClick={handleChildClick} // Open popover on click
sx={{
display: 'inline-flex', // Keep inline behavior
alignItems: 'center',
justifyContent: 'center',
cursor: 'pointer',
padding: 0,
width: 'fit-content', // Limit width to content size
height: 'fit-content', // Limit height to content size
alignSelf: 'flex-start', // Prevent stretching to parent height
maxWidth: '100%', // Optional: Limit the width to avoid overflow
maxHeight: '100%', // Prevent flex shrink behavior in a flex container
}}
>
{/* Render the child without altering dimensions */}
{children}
</Box>
{/* Popover */}
<Popover
id={id}
open={open}
anchorEl={anchorEl}
onClose={handleClose} // Close popover on click outside
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'center',
}}
componentsProps={{
paper: {
onClick: (event) => event.stopPropagation(), // Stop propagation inside popover
},
}}
>
<Box sx={{ p: 2, display: 'flex', flexDirection: 'column', gap: 1 }}>
{/* Option 1: Message */}
<Button
variant="text"
onClick={() => {
executeEvent('openDirectMessageInternal', {
address,
name,
});
handleClose();
console.log('Message clicked');
}}
sx={{
color: 'white'
}}
>
Message
</Button>
{/* Option 2: Send QORT */}
<Button
variant="text"
onClick={() => {
executeEvent('openPaymentInternal', {
address,
name,
});
handleClose();
console.log('Send QORT clicked');
}}
sx={{
color: 'white'
}}
>
Send QORT
</Button>
</Box>
</Popover>
</>
);
};

View File

@ -78,6 +78,19 @@ body {
border: 4px solid transparent; border: 4px solid transparent;
} }
/* Mobile-specific scrollbar styles */
@media only screen and (max-width: 600px) {
::-webkit-scrollbar {
width: 8px; /* Narrower scrollbar width on mobile */
height: 6px; /* Narrower scrollbar height on mobile */
}
::-webkit-scrollbar-thumb {
border-radius: 4px; /* Adjust the radius for a narrower thumb */
border: 2px solid transparent; /* Narrower thumb border */
}
}
.group-list::-webkit-scrollbar-thumb:hover { .group-list::-webkit-scrollbar-thumb:hover {
background-color: whitesmoke; background-color: whitesmoke;
} }