mobile new design

This commit is contained in:
PhilReact 2024-09-21 07:48:54 +03:00
parent f9c6f4c5fd
commit 38545e3da5
18 changed files with 1778 additions and 1122 deletions

View File

@ -0,0 +1,13 @@
import React from 'react';
export const ExitIcon= ({ color = 'white', height, width }) => {
return (
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2 0L0 2L4 6L0 10L2 12L6 8L10 12L12 10L8 6L12 2L10 0L6 4L2 0Z" fill={color}/>
</svg>
);
};

View File

@ -1,8 +1,8 @@
import React from 'react';
export const HubsIcon= ({ color, height, width }) => {
export const HubsIcon= ({ color, height = 31, width = 32 }) => {
return (
<svg width="32" height="31" viewBox="0 0 32 31" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg width={width} height={height} viewBox="0 0 32 31" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M24.5333 30H22.4C22.3987 28.1694 20.9667 26.6856 19.2 26.6842H12.8C11.0333 26.6856 9.60133 28.1694 9.6 30H7.46667C7.468 28.5355 8.03065 27.1305 9.03066 26.0943C10.0307 25.0581 11.3866 24.4751 12.8 24.4737H19.2C20.6133 24.4751 21.9693 25.0581 22.9693 26.0943C23.9693 27.1305 24.532 28.5355 24.5333 30ZM11.7333 17.8422C11.7333 16.0545 12.7733 14.4422 14.3667 13.7583C15.9613 13.073 17.7974 13.4516 19.0173 14.7157C20.2373 15.9798 20.6026 17.8822 19.9413 19.5346C19.2813 21.1856 17.7253 22.2632 15.9999 22.2632C13.6439 22.2604 11.7361 20.2834 11.7333 17.8422ZM13.8667 17.8422C13.8667 18.7361 14.3867 19.5429 15.184 19.8842C15.9813 20.2268 16.8987 20.0375 17.508 19.4048C18.1187 18.7734 18.3013 17.8228 17.9707 16.9967C17.6414 16.1705 16.8627 15.6317 16 15.6317C14.8227 15.6331 13.868 16.6223 13.8667 17.8422ZM26.6667 20.0527H22.4V22.2632H26.6667C28.4333 22.2646 29.8653 23.7484 29.8667 25.579H32C31.9987 24.1145 31.436 22.7095 30.436 21.6733C29.436 20.6371 28.08 20.0541 26.6667 20.0527ZM21.3333 13.4212C21.3333 11.6335 22.3733 10.0212 23.9667 9.33727C25.5613 8.65201 27.3974 9.03056 28.6173 10.2947C29.8373 11.5588 30.2026 13.4612 29.5413 15.1136C28.8813 16.7646 27.3253 17.8422 25.5999 17.8422C23.2439 17.8394 21.3361 15.8624 21.3333 13.4212ZM23.4667 13.4212C23.4667 14.3151 23.9867 15.1219 24.784 15.4632C25.5813 15.8058 26.4987 15.6165 27.108 14.9837C27.7187 14.3524 27.9013 13.4018 27.5707 12.5757C27.2414 11.7495 26.4627 11.2107 25.6 11.2107C24.4227 11.2121 23.468 12.2013 23.4667 13.4212ZM9.6 20.0527H5.33333C3.92001 20.0541 2.56399 20.6371 1.56399 21.6733C0.563985 22.7095 0.0013312 24.1145 0 25.579H2.13333C2.13467 23.7484 3.56666 22.2646 5.33333 22.2632H9.6V20.0527ZM2.13333 13.4212C2.13333 11.6335 3.17334 10.0212 4.76665 9.33727C6.36133 8.65201 8.19739 9.03056 9.41732 10.2947C10.6373 11.5588 11.0026 13.4612 10.3413 15.1136C9.6813 16.7646 8.1253 17.8422 6.39993 17.8422C4.04395 17.8394 2.13606 15.8624 2.13333 13.4212ZM4.26667 13.4212C4.26667 14.3151 4.78665 15.1219 5.58401 15.4632C6.38133 15.8058 7.29866 15.6165 7.90801 14.9837C8.51869 14.3524 8.70134 13.4018 8.37069 12.5757C8.04136 11.7495 7.26269 11.2107 6.40003 11.2107C5.22271 11.2121 4.268 12.2013 4.26667 13.4212Z" fill={color}/>
</svg>

View File

@ -0,0 +1,14 @@
import React from 'react';
export const MessagingIcon2= ({ color = '#8F8F91', height = 24, width =24 }) => {
return (
<svg width={width} height={height} viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M22.6636 0.00168233C22.6127 -0.000756257 22.5614 -0.000627677 22.5099 0.00261984C22.3724 0.0112798 22.2331 0.0405753 22.0969 0.093558L1.02096 8.28971C0.362343 8.54585 -0.00366118 9.18408 2.76147e-05 9.79253C0.00371641 10.401 0.377567 11.0341 1.03925 11.2822L9.02065 14.2752C9.34631 14.3974 9.60258 14.6536 9.72471 14.9793L12.7177 22.9607C12.9658 23.6224 13.5989 23.9963 14.2074 24C14.8158 24.0037 15.454 23.6376 15.7102 22.979L23.9063 1.90295C24.1182 1.35797 23.9526 0.768987 23.5917 0.408091C23.3549 0.171254 23.02 0.0187526 22.6636 0.00168233ZM18.4022 4.99812C18.5613 4.99815 18.7139 5.06138 18.8264 5.17391C18.9389 5.28643 19.0021 5.43902 19.0021 5.59813C19.0021 5.75724 18.9389 5.90983 18.8264 6.02235L13.2239 11.6244C13.1114 11.7369 12.9588 11.8001 12.7997 11.8001C12.6406 11.8001 12.488 11.7369 12.3755 11.6244C12.263 11.5119 12.1998 11.3593 12.1998 11.2002C12.1998 11.0411 12.263 10.8885 12.3755 10.776L17.9775 5.17391C18.0333 5.11813 18.0995 5.0739 18.1724 5.04374C18.2452 5.01357 18.3233 4.99807 18.4022 4.99812Z" fill={color}/>
</svg>
);
};

View File

@ -1,11 +1,12 @@
import React from 'react';
export const NotificationIcon= ({ color, height, width }) => {
export const NotificationIcon= ({ color = 'white', height = 16, width = 14 }) => {
return (
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.55681 1.32222C6.55681 0.591749 7.20253 0 7.99963 0C8.79673 0 9.44245 0.591749 9.44245 1.32222V1.35911C12.663 1.9634 15.0849 4.57455 15.0849 7.70462V10.394C15.0849 10.6213 15.13 10.847 15.2169 11.0595L15.8997 12.7234C16.2797 13.6501 15.5326 14.6389 14.4529 14.6389H10.7749C10.6694 15.9589 9.46735 17 7.99955 17C6.53175 17 5.32972 15.9589 5.22418 14.6389H1.54706C0.485079 14.6389 -0.260488 13.6804 0.0857267 12.7603L0.729843 11.0485C0.804721 10.8493 0.842564 10.6398 0.842564 10.4288V7.80284C0.842564 4.63009 3.29495 1.98282 6.55675 1.3644L6.55681 1.32222ZM6.67597 14.6388C6.775 15.2269 7.32975 15.6777 7.99963 15.6777C8.66951 15.6777 9.22426 15.2269 9.3233 14.6388H6.67597ZM8.01734 2.54999C4.85241 2.54999 2.28543 4.90146 2.28543 7.80278V10.4287C2.28543 10.7866 2.22102 11.1415 2.0938 11.4794L1.44969 13.1912C1.42714 13.2524 1.47626 13.3166 1.54711 13.3166H14.4527C14.5252 13.3166 14.5743 13.251 14.5493 13.189L13.8666 11.5251C13.7184 11.1636 13.6419 10.7807 13.6419 10.394V7.70463C13.6419 4.85809 11.1243 2.54999 8.01734 2.54999Z" fill={color}/>
</svg>
<svg width={width} height={height} viewBox="0 0 14 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8.73084 13.401H5.27178C5.11667 13.401 4.96853 13.4672 4.86412 13.5829C4.7647 13.6946 4.71697 13.8439 4.73387 13.9932C4.86611 15.1369 5.84149 15.9999 6.99878 15.9999C8.15709 15.9999 9.13146 15.1369 9.26369 13.9932C9.28159 13.8439 9.23287 13.6946 9.13344 13.5829C9.03103 13.4672 8.88295 13.401 8.73084 13.401Z" fill={color}/>
<path d="M13.0219 10.4077V10.4048C12.5506 10.0983 12.2583 9.51111 12.2583 8.87843V6.75003C12.2583 4.52575 10.8614 2.49816 8.83004 1.72603C8.77934 0.764153 7.97696 0 6.99962 0C6.02525 0 5.22585 0.762179 5.16919 1.71614C3.1071 2.47536 1.74093 4.40908 1.74093 6.6136V8.8784C1.74093 9.51108 1.44863 10.0983 0.977343 10.4067C0.366879 10.8061 0 11.4823 0 12.2089V12.8416C0 13.4367 0.486203 13.9201 1.08473 13.9201H12.9153C13.5138 13.9201 14 13.4367 14 12.8416V12.2089C13.999 11.4833 13.6351 10.8071 13.0216 10.4077L13.0219 10.4077Z" fill={color}/>
</svg>
);

View File

@ -0,0 +1,14 @@
import React from 'react';
export const ReturnIcon= ({ color = 'white', height, width }) => {
return (
<svg width="20" height="13" viewBox="0 0 20 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.0937 3.73451H3.6243L5.84808 1.67047C6.04153 1.48456 6.14857 1.23558 6.14615 0.97713C6.14373 0.718684 6.03205 0.471459 5.83515 0.288703C5.63825 0.105948 5.37189 0.00228309 5.09344 3.72619e-05C4.815 -0.00220856 4.54674 0.0971438 4.34645 0.276696L0.310933 4.02233C0.111843 4.20718 0 4.45785 0 4.71922C0 4.98059 0.111843 5.23126 0.310933 5.41611L4.34645 9.16175C4.54674 9.3413 4.815 9.44065 5.09344 9.43841C5.37189 9.43616 5.63825 9.33249 5.83515 9.14974C6.03205 8.96698 6.14373 8.71976 6.14615 8.46131C6.14857 8.20287 6.04153 7.95388 5.84808 7.76797L3.6243 5.7059H15.0937C15.8316 5.7059 16.5393 5.97799 17.0611 6.4623C17.5829 6.94662 17.876 7.60349 17.876 8.28842C17.876 8.97335 17.5829 9.63022 17.0611 10.1145C16.5393 10.5989 15.8316 10.8709 15.0937 10.8709V12.8423C16.3949 12.8423 17.6429 12.3625 18.563 11.5085C19.4831 10.6545 20 9.49619 20 8.28842C20 7.08065 19.4831 5.92234 18.563 5.06832C17.6429 4.2143 16.3949 3.73451 15.0937 3.73451Z" fill={color}/>
</svg>
);
};

View File

@ -6,7 +6,7 @@ import "@chatscope/chat-ui-kit-styles/dist/default/styles.min.css";
import Tiptap from './TipTap'
import { CustomButton } from '../../App-styles'
import CircularProgress from '@mui/material/CircularProgress';
import { Box, Input, Typography } from '@mui/material';
import { Box, ButtonBase, Input, Typography } from '@mui/material';
import { LoadingSnackbar } from '../Snackbar/LoadingSnackbar';
import { getNameInfo } from '../Group/Group';
import { Spacer } from '../../common/Spacer';
@ -17,12 +17,14 @@ import { useMessageQueue } from '../../MessageQueueContext';
import { executeEvent, subscribeToEvent, unsubscribeFromEvent } from '../../utils/events';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import ShortUniqueId from "short-unique-id";
import { ReturnIcon } from '../../assets/Icons/ReturnIcon';
import { ExitIcon } from '../../assets/Icons/ExitIcon';
const uid = new ShortUniqueId({ length: 5 });
export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDirect, setNewChat, getTimestampEnterChat, myName, balance, close}) => {
export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDirect, setNewChat, getTimestampEnterChat, myName, balance, close, setMobileViewModeKeepOpen}) => {
const { queueChats, addToQueue, processWithNewMessages} = useMessageQueue();
const [isFocusedParent, setIsFocusedParent] = useState(false);
@ -344,27 +346,69 @@ const clearEditorContent = () => {
flexDirection: 'column',
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>
{isMobile && (
<Box
sx={{
display: "flex",
alignItems: "center",
width: "100%",
marginTop: "14px",
justifyContent: "center",
height: "15px",
}}
>
<Box
sx={{
display: "flex",
alignItems: "center",
justifyContent: "space-between",
width: "320px",
}}
>
<Box
sx={{
display: "flex",
alignItems: "center",
width: "50px",
}}
>
<ButtonBase
onClick={() => {
close()
}}
>
<ReturnIcon />
</ButtonBase>
</Box>
<Typography
sx={{
fontSize: "14px",
fontWeight: 600,
}}
>
{isNewChat ? '' : selectedDirect?.name || (selectedDirect?.address?.slice(0,10) + '...')}
</Typography>
<Box
sx={{
display: "flex",
alignItems: "center",
width: "50px",
justifyContent: "flex-end",
}}
>
<ButtonBase
onClick={() => {
setSelectedDirect(null)
setMobileViewModeKeepOpen('')
setNewChat(false)
}}
>
<ExitIcon />
</ButtonBase>
</Box>
</Box>
</Box>
)}
{isNewChat && (
<>
<Spacer height="30px" />
@ -376,7 +420,7 @@ const clearEditorContent = () => {
</>
)}
<ChatList initialMessages={messages} myAddress={myAddress} tempMessages={tempMessages}/>
<ChatList chatId={selectedDirect?.address} initialMessages={messages} myAddress={myAddress} tempMessages={tempMessages}/>
<div style={{

View File

@ -374,7 +374,7 @@ const clearEditorContent = () => {
left: hide && '-100000px',
}}>
<ChatList initialMessages={messages} myAddress={myAddress} tempMessages={tempMessages}/>
<ChatList chatId={selectedGroup} initialMessages={messages} myAddress={myAddress} tempMessages={tempMessages}/>
<div style={{

View File

@ -3,18 +3,21 @@ import { List, AutoSizer, CellMeasurerCache, CellMeasurer } from 'react-virtuali
import { MessageItem } from './MessageItem';
import { subscribeToEvent, unsubscribeFromEvent } from '../../utils/events';
const cache = new CellMeasurerCache({
fixedWidth: true,
defaultHeight: 50,
});
// const cache = new CellMeasurerCache({
// fixedWidth: true,
// defaultHeight: 50,
// });
export const ChatList = ({ initialMessages, myAddress, tempMessages }) => {
export const ChatList = ({ initialMessages, myAddress, tempMessages, chatId }) => {
const hasLoadedInitialRef = useRef(false);
const listRef = useRef();
const [messages, setMessages] = useState(initialMessages);
const [showScrollButton, setShowScrollButton] = useState(false);
const cache = useMemo(() => new CellMeasurerCache({
fixedWidth: true,
defaultHeight: 50,
}), [chatId]); // Recreate cache when chatId changes
useEffect(() => {
cache.clearAll();
@ -175,7 +178,7 @@ let uniqueInitialMessages = Array.from(uniqueInitialMessagesMap.values()).sort((
// }, [messages, myAddress]);
return (
<div style={{ position: 'relative', flexGrow: 1, width: '100%', display: 'flex', flexDirection: 'column', flexShrink: 1 }}>
<div style={{ position: 'relative', marginTop: '14px', flexGrow: 1, width: '100%', display: 'flex', flexDirection: 'column', flexShrink: 1 }}>
<AutoSizer>
{({ height, width }) => (
<List

View File

@ -25,21 +25,28 @@ import { Spacer } from "../../common/Spacer";
import ShortUniqueId from "short-unique-id";
import { AnnouncementList } from "./AnnouncementList";
const uid = new ShortUniqueId({ length: 8 });
import CampaignIcon from '@mui/icons-material/Campaign';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import CampaignIcon from "@mui/icons-material/Campaign";
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
import { AnnouncementDiscussion } from "./AnnouncementDiscussion";
import { MyContext, getArbitraryEndpointReact, getBaseApiReact, isMobile, pauseAllQueues, resumeAllQueues } from "../../App";
import {
MyContext,
getArbitraryEndpointReact,
getBaseApiReact,
isMobile,
pauseAllQueues,
resumeAllQueues,
} from "../../App";
import { RequestQueueWithPromise } from "../../utils/queue/queue";
import { CustomizedSnackbars } from "../Snackbar/Snackbar";
import { addDataPublishesFunc, getDataPublishesFunc } from "../Group/Group";
import { addDataPublishesFunc, getDataPublishesFunc } from "../Group/Group";
import { getRootHeight } from "../../utils/mobile/mobileUtils";
export const requestQueueCommentCount = new RequestQueueWithPromise(3)
export const requestQueuePublishedAccouncements = new RequestQueueWithPromise(3)
export const requestQueueCommentCount = new RequestQueueWithPromise(3);
export const requestQueuePublishedAccouncements = new RequestQueueWithPromise(
3
);
export const saveTempPublish = async ({ data, key }: any) => {
return new Promise((res, rej) => {
chrome?.runtime?.sendMessage(
{
@ -50,10 +57,9 @@ export const saveTempPublish = async ({ data, key }: any) => {
},
},
(response) => {
if (!response?.error) {
res(response);
return
return;
}
rej(response.error);
}
@ -62,19 +68,16 @@ export const saveTempPublish = async ({ data, key }: any) => {
};
export const getTempPublish = async () => {
return new Promise((res, rej) => {
chrome?.runtime?.sendMessage(
{
action: "getTempPublish",
payload: {
},
payload: {},
},
(response) => {
if (!response?.error) {
res(response);
return
return;
}
rej(response.error);
}
@ -95,7 +98,6 @@ export const decryptPublishes = async (encryptedMessages: any[], secretKey) => {
},
},
(response) => {
if (!response?.error) {
res(response);
// if(hasInitialized.current){
@ -130,13 +132,13 @@ export const GroupAnnouncements = ({
handleNewEncryptionNotification,
isAdmin,
hide,
myName
myName,
}) => {
const [messages, setMessages] = useState([]);
const [isSending, setIsSending] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const [announcements, setAnnouncements] = useState([]);
const [tempPublishedList, setTempPublishedList] = useState([])
const [tempPublishedList, setTempPublishedList] = useState([]);
const [announcementData, setAnnouncementData] = useState({});
const [selectedAnnouncement, setSelectedAnnouncement] = useState(null);
const [isFocusedParent, setIsFocusedParent] = useState(false);
@ -147,37 +149,45 @@ export const GroupAnnouncements = ({
const hasInitialized = useRef(false);
const hasInitializedWebsocket = useRef(false);
const editorRef = useRef(null);
const dataPublishes = useRef({})
const dataPublishes = useRef({});
const setEditorRef = (editorInstance) => {
editorRef.current = editorInstance;
};
const [, forceUpdate] = React.useReducer((x) => x + 1, 0);
useEffect(()=> {
if(!selectedGroup) return
(async ()=> {
const res = await getDataPublishesFunc(selectedGroup, 'anc')
dataPublishes.current = res || {}
})()
}, [selectedGroup])
const triggerRerender = () => {
forceUpdate(); // Trigger re-render by updating the state
};
useEffect(() => {
if (!selectedGroup) return;
(async () => {
const res = await getDataPublishesFunc(selectedGroup, "anc");
dataPublishes.current = res || {};
})();
}, [selectedGroup]);
const getAnnouncementData = async ({ identifier, name, resource }) => {
try {
let data = dataPublishes.current[`${name}-${identifier}`]
if(!data || (data?.update || data?.created !== (resource?.updated || resource?.created))){
const res = await requestQueuePublishedAccouncements.enqueue(()=> {
let data = dataPublishes.current[`${name}-${identifier}`];
if (
!data ||
data?.update ||
data?.created !== (resource?.updated || resource?.created)
) {
const res = await requestQueuePublishedAccouncements.enqueue(() => {
return fetch(
`${getBaseApiReact()}/arbitrary/DOCUMENT/${name}/${identifier}?encoding=base64`
);
})
if(!res?.ok) return
data = await res.text();
await addDataPublishesFunc({...resource, data}, selectedGroup, 'anc')
});
if (!res?.ok) return;
data = await res.text();
await addDataPublishesFunc({ ...resource, data }, selectedGroup, "anc");
} else {
data = data.data
data = data.data;
}
const response = await decryptPublishes([{ data }], secretKey);
const messageData = response[0];
setAnnouncementData((prev) => {
return {
@ -185,16 +195,11 @@ export const GroupAnnouncements = ({
[`${identifier}-${name}`]: messageData,
};
});
} catch (error) {
console.log('error', error)
console.log("error", error);
}
};
useEffect(() => {
if (!secretKey || hasInitializedWebsocket.current) return;
setIsLoading(true);
@ -226,64 +231,61 @@ export const GroupAnnouncements = ({
};
const publishAnc = async ({ encryptedData, identifier }: any) => {
return new Promise((res, rej) => {
chrome?.runtime?.sendMessage(
{
action: "publishGroupEncryptedResource",
payload: {
encryptedData,
identifier,
},
return new Promise((res, rej) => {
chrome?.runtime?.sendMessage(
{
action: "publishGroupEncryptedResource",
payload: {
encryptedData,
identifier,
},
(response) => {
if (!response?.error) {
res(response);
}
rej(response.error);
},
(response) => {
if (!response?.error) {
res(response);
}
);
});
rej(response.error);
}
);
});
};
const clearEditorContent = () => {
if (editorRef.current) {
editorRef.current.chain().focus().clearContent().run();
if(isMobile){
if (isMobile) {
setTimeout(() => {
editorRef.current?.chain().blur().run();
setIsFocusedParent(false)
editorRef.current?.chain().blur().run();
setIsFocusedParent(false);
setTimeout(() => {
triggerRerender();
}, 300);
}, 200);
}
}
};
const setTempData = async ()=> {
const setTempData = async () => {
try {
const getTempAnnouncements = await getTempPublish()
if(getTempAnnouncements?.announcement){
let tempData = []
Object.keys(getTempAnnouncements?.announcement || {}).map((key)=> {
const value = getTempAnnouncements?.announcement[key]
tempData.push(value.data)
})
setTempPublishedList(tempData)
}
} catch (error) {
}
}
const getTempAnnouncements = await getTempPublish();
if (getTempAnnouncements?.announcement) {
let tempData = [];
Object.keys(getTempAnnouncements?.announcement || {}).map((key) => {
const value = getTempAnnouncements?.announcement[key];
tempData.push(value.data);
});
setTempPublishedList(tempData);
}
} catch (error) {}
};
const publishAnnouncement = async () => {
try {
pauseAllQueues()
const fee = await getFee('ARBITRARY')
pauseAllQueues();
const fee = await getFee("ARBITRARY");
await show({
message: "Would you like to perform a ARBITRARY transaction?" ,
publishFee: fee.fee + ' QORT'
})
message: "Would you like to perform a ARBITRARY transaction?",
publishFee: fee.fee + " QORT",
});
if (isSending) return;
if (editorRef.current) {
const htmlContent = editorRef.current.getHTML();
@ -292,8 +294,8 @@ export const GroupAnnouncements = ({
const message = {
version: 1,
extra: {},
message: htmlContent
}
message: htmlContent,
};
const secretKeyObject = await getSecretKey(false, true);
const message64: any = await objectToBase64(message);
const encryptSingle = await encryptChatMessage(
@ -304,36 +306,37 @@ export const GroupAnnouncements = ({
const identifier = `grp-${selectedGroup}-anc-${randomUid}`;
const res = await publishAnc({
encryptedData: encryptSingle,
identifier
identifier,
});
const dataToSaveToStorage = {
name: myName,
identifier,
service: 'DOCUMENT',
service: "DOCUMENT",
tempData: message,
created: Date.now()
}
await saveTempPublish({data: dataToSaveToStorage, key: 'announcement'})
setTempData()
created: Date.now(),
};
await saveTempPublish({
data: dataToSaveToStorage,
key: "announcement",
});
setTempData();
clearEditorContent();
}
// send chat message
} catch (error) {
if(!error) return
if (!error) return;
setInfoSnack({
type: "error",
message: error,
});
setOpenSnack(true)
setOpenSnack(true);
} finally {
resumeAllQueues()
resumeAllQueues();
setIsSending(false);
}
};
const getAnnouncements = React.useCallback(
async (selectedGroup) => {
try {
@ -349,12 +352,16 @@ export const GroupAnnouncements = ({
},
});
const responseData = await response.json();
setTempData()
setTempData();
setAnnouncements(responseData);
setIsLoading(false);
for (const data of responseData) {
getAnnouncementData({ name: data.name, identifier: data.identifier, resource: data });
getAnnouncementData({
name: data.name,
identifier: data.identifier,
resource: data,
});
}
} catch (error) {
} finally {
@ -363,199 +370,206 @@ export const GroupAnnouncements = ({
},
[secretKey]
);
React.useEffect(() => {
if (selectedGroup && secretKey && !hasInitialized.current && !hide) {
getAnnouncements(selectedGroup);
hasInitialized.current = true
hasInitialized.current = true;
}
}, [selectedGroup, secretKey, hide]);
const loadMore = async()=> {
const loadMore = async () => {
try {
setIsLoading(true);
const offset = announcements.length
const identifier = `grp-${selectedGroup}-anc-`;
const url = `${getBaseApiReact()}${getArbitraryEndpointReact()}?mode=ALL&service=DOCUMENT&identifier=${identifier}&limit=20&includemetadata=false&offset=${offset}&reverse=true&prefix=true`;
const response = await fetch(url, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
const responseData = await response.json();
const offset = announcements.length;
const identifier = `grp-${selectedGroup}-anc-`;
const url = `${getBaseApiReact()}${getArbitraryEndpointReact()}?mode=ALL&service=DOCUMENT&identifier=${identifier}&limit=20&includemetadata=false&offset=${offset}&reverse=true&prefix=true`;
const response = await fetch(url, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
const responseData = await response.json();
setAnnouncements((prev)=> [...prev, ...responseData]);
setIsLoading(false);
setAnnouncements((prev) => [...prev, ...responseData]);
setIsLoading(false);
for (const data of responseData) {
getAnnouncementData({ name: data.name, identifier: data.identifier });
}
} catch (error) {}
};
const interval = useRef<any>(null);
const checkNewMessages = React.useCallback(async () => {
try {
const identifier = `grp-${selectedGroup}-anc-`;
const url = `${getBaseApiReact()}${getArbitraryEndpointReact()}?mode=ALL&service=DOCUMENT&identifier=${identifier}&limit=20&includemetadata=false&offset=${0}&reverse=true&prefix=true`;
const response = await fetch(url, {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
const responseData = await response.json();
const latestMessage = announcements[0];
if (!latestMessage) {
for (const data of responseData) {
getAnnouncementData({ name: data.name, identifier: data.identifier });
}
} catch (error) {
}
}
const interval = useRef<any>(null)
const checkNewMessages = React.useCallback(
async () => {
try {
const identifier = `grp-${selectedGroup}-anc-`;
const url = `${getBaseApiReact()}${getArbitraryEndpointReact()}?mode=ALL&service=DOCUMENT&identifier=${identifier}&limit=20&includemetadata=false&offset=${0}&reverse=true&prefix=true`;
const response = await fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
})
const responseData = await response.json()
const latestMessage = announcements[0]
if (!latestMessage) {
for (const data of responseData) {
try {
getAnnouncementData({ name: data.name, identifier: data.identifier });
} catch (error) {}
}
setAnnouncements(responseData)
return
}
const findMessage = responseData?.findIndex(
(item: any) => item?.identifier === latestMessage?.identifier
)
if(findMessage === -1) return
const newArray = responseData.slice(0, findMessage)
for (const data of newArray) {
try {
getAnnouncementData({ name: data.name, identifier: data.identifier });
getAnnouncementData({
name: data.name,
identifier: data.identifier,
});
} catch (error) {}
}
setAnnouncements((prev)=> [...newArray, ...prev])
} catch (error) {
} finally {
setAnnouncements(responseData);
return;
}
},
[announcements, secretKey, selectedGroup]
)
const findMessage = responseData?.findIndex(
(item: any) => item?.identifier === latestMessage?.identifier
);
if (findMessage === -1) return;
const newArray = responseData.slice(0, findMessage);
for (const data of newArray) {
try {
getAnnouncementData({ name: data.name, identifier: data.identifier });
} catch (error) {}
}
setAnnouncements((prev) => [...newArray, ...prev]);
} catch (error) {
} finally {
}
}, [announcements, secretKey, selectedGroup]);
const checkNewMessagesFunc = useCallback(() => {
let isCalling = false
let isCalling = false;
interval.current = setInterval(async () => {
if (isCalling) return
isCalling = true
const res = await checkNewMessages()
isCalling = false
}, 20000)
}, [checkNewMessages])
if (isCalling) return;
isCalling = true;
const res = await checkNewMessages();
isCalling = false;
}, 20000);
}, [checkNewMessages]);
useEffect(() => {
if(!secretKey || hide) return
checkNewMessagesFunc()
if (!secretKey || hide) return;
checkNewMessagesFunc();
return () => {
if (interval?.current) {
clearInterval(interval.current)
clearInterval(interval.current);
}
}
}, [checkNewMessagesFunc, hide])
};
}, [checkNewMessagesFunc, hide]);
const combinedListTempAndReal = useMemo(() => {
// Combine the two lists
const combined = [...tempPublishedList, ...announcements];
// Remove duplicates based on the "identifier"
const uniqueItems = new Map();
combined.forEach(item => {
uniqueItems.set(item.identifier, item); // This will overwrite duplicates, keeping the last occurrence
combined.forEach((item) => {
uniqueItems.set(item.identifier, item); // This will overwrite duplicates, keeping the last occurrence
});
// Convert the map back to an array and sort by "created" timestamp in descending order
const sortedList = Array.from(uniqueItems.values()).sort((a, b) => b.created - a.created);
const sortedList = Array.from(uniqueItems.values()).sort(
(a, b) => b.created - a.created
);
return sortedList;
}, [tempPublishedList, announcements]);
if(selectedAnnouncement){
if (selectedAnnouncement) {
return (
<div
style={{
height: isMobile ? `calc(${getRootHeight()} - 83px` : "100vh",
display: "flex",
flexDirection: "column",
width: "100%",
visibility: hide && 'hidden',
position: hide && 'fixed',
left: hide && '-1000px'
}}
>
<AnnouncementDiscussion myName={myName} show={show} secretKey={secretKey} selectedAnnouncement={selectedAnnouncement} setSelectedAnnouncement={setSelectedAnnouncement} encryptChatMessage={encryptChatMessage} getSecretKey={getSecretKey} />
style={{
// reference to change height
height: isMobile ? `calc(${getRootHeight()} - 127px` : "100vh",
display: "flex",
flexDirection: "column",
width: "100%",
visibility: hide && "hidden",
position: hide && "fixed",
left: hide && "-1000px",
}}
>
<AnnouncementDiscussion
myName={myName}
show={show}
secretKey={secretKey}
selectedAnnouncement={selectedAnnouncement}
setSelectedAnnouncement={setSelectedAnnouncement}
encryptChatMessage={encryptChatMessage}
getSecretKey={getSecretKey}
/>
</div>
)
);
}
return (
<div
style={{
height: isMobile ? `calc(${getRootHeight()} - 83px` : "100vh",
// reference to change height
height: isMobile ? `calc(${getRootHeight()} - 127px` : "100vh",
display: "flex",
flexDirection: "column",
width: "100%",
visibility: hide && 'hidden',
position: hide && 'fixed',
left: hide && '-1000px'
visibility: hide && "hidden",
position: hide && "fixed",
left: hide && "-1000px",
}}
>
<div style={{
position: "relative",
width: "100%",
display: "flex",
flexDirection: "column",
flexShrink: 0,
}}>
{!isMobile && (
<Box
sx={{
width: "100%",
display: "flex",
justifyContent: "center",
padding: isMobile ? '8px' : "25px",
fontSize: isMobile ? '16px' : "20px",
gap: '20px',
alignItems: 'center'
}}
>
<CampaignIcon sx={{
fontSize: isMobile ? '16px' : '30px'
}} />
Group Announcements
</Box>
)}
<Spacer height={isMobile ? "0px" : "25px"} />
<div
style={{
position: "relative",
width: "100%",
display: "flex",
flexDirection: "column",
flexShrink: 0,
}}
>
{!isMobile && (
<Box
sx={{
width: "100%",
display: "flex",
justifyContent: "center",
padding: isMobile ? "8px" : "25px",
fontSize: isMobile ? "16px" : "20px",
gap: "20px",
alignItems: "center",
}}
>
<CampaignIcon
sx={{
fontSize: isMobile ? "16px" : "30px",
}}
/>
Group Announcements
</Box>
)}
<Spacer height={isMobile ? "0px" : "25px"} />
</div>
{!isLoading && combinedListTempAndReal?.length === 0 && (
<Box sx={{
width: '100%',
display: 'flex',
justifyContent: 'center'
}}>
<Typography sx={{
fontSize: '16px'
}}>No announcements</Typography>
<Box
sx={{
width: "100%",
display: "flex",
justifyContent: "center",
}}
>
<Typography
sx={{
fontSize: "16px",
}}
>
No announcements
</Typography>
</Box>
)}
<AnnouncementList
@ -563,118 +577,126 @@ export const GroupAnnouncements = ({
initialMessages={combinedListTempAndReal}
setSelectedAnnouncement={setSelectedAnnouncement}
disableComment={false}
showLoadMore={announcements.length > 0 && announcements.length % 20 === 0}
showLoadMore={
announcements.length > 0 && announcements.length % 20 === 0
}
loadMore={loadMore}
myName={myName}
/>
{isAdmin && (
<div
style={{
// position: 'fixed',
// bottom: '0px',
backgroundColor: "#232428",
minHeight: isMobile ? "0px" : "150px",
maxHeight: isMobile ? "auto" : "400px",
display: "flex",
flexDirection: "column",
overflow: "hidden",
width: "100%",
boxSizing: "border-box",
padding: isMobile ? "10px": "20px",
position: isFocusedParent ? 'fixed' : 'relative',
bottom: isFocusedParent ? '0px' : 'unset',
top: isFocusedParent ? '0px' : 'unset',
zIndex: isFocusedParent ? 5 : 'unset',
flexShrink: 0
}}
>
<div
style={{
display: "flex",
flexDirection: "column",
flexGrow: isMobile && 1,
overflow: "auto",
// height: '100%',
}}
>
<Tiptap
setEditorRef={setEditorRef}
onEnter={publishAnnouncement}
disableEnter
maxHeightOffset="40px"
isFocusedParent={isFocusedParent} setIsFocusedParent={setIsFocusedParent}
/>
</div>
<Box sx={{
display: 'flex',
width: '100&',
gap: '10px',
justifyContent: 'center',
flexShrink: 0,
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>
{isAdmin && (
<div
style={{
// position: 'fixed',
// bottom: '0px',
backgroundColor: "#232428",
minHeight: isMobile ? "0px" : "150px",
maxHeight: isMobile ? "auto" : "400px",
display: "flex",
flexDirection: "column",
overflow: "hidden",
width: "100%",
boxSizing: "border-box",
padding: isMobile ? "10px" : "20px",
position: isFocusedParent ? "fixed" : "relative",
bottom: isFocusedParent ? "0px" : "unset",
top: isFocusedParent ? "0px" : "unset",
zIndex: isFocusedParent ? 5 : "unset",
flexShrink: 0,
}}
>
<div
style={{
display: "flex",
flexDirection: "column",
flexGrow: isMobile && 1,
overflow: "auto",
// height: '100%',
}}
>
<Tiptap
setEditorRef={setEditorRef}
onEnter={publishAnnouncement}
disableEnter
maxHeightOffset="40px"
isFocusedParent={isFocusedParent}
setIsFocusedParent={setIsFocusedParent}
/>
</div>
<Box
sx={{
display: "flex",
width: "100&",
gap: "10px",
justifyContent: "center",
flexShrink: 0,
position: "relative",
}}
>
{isFocusedParent && (
<CustomButton
onClick={() => {
if (isSending) return;
setIsFocusedParent(false);
clearEditorContent();
setTimeout(() => {
triggerRerender();
}, 300);
// 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
onClick={() => {
if (isSending) return;
publishAnnouncement();
}}
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',
<CustomButton
onClick={() => {
if (isSending) return;
publishAnnouncement();
}}
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",
}}
>
{isSending && (
<CircularProgress
size={18}
sx={{
position: "absolute",
top: "50%",
left: "50%",
marginTop: "-12px",
marginLeft: "-12px",
color: "white",
}}
/>
)}
{` Publish Announcement`}
</CustomButton>
</Box>
</div>
)}
}}
>
{isSending && (
<CircularProgress
size={18}
sx={{
position: "absolute",
top: "50%",
left: "50%",
marginTop: "-12px",
marginLeft: "-12px",
color: "white",
}}
/>
)}
{` Publish Announcement`}
</CustomButton>
</Box>
</div>
)}
<CustomizedSnackbars open={openSnack} setOpen={setOpenSnack} info={infoSnack} setInfo={setInfoSnack} />
<CustomizedSnackbars
open={openSnack}
setOpen={setOpenSnack}
info={infoSnack}
setInfo={setInfoSnack}
/>
<LoadingSnackbar
open={isLoading}

View File

@ -7,6 +7,7 @@ import React, {
} from "react";
import { GroupMail } from "../Group/Forum/GroupMail";
import { isMobile } from "../../App";
import { getRootHeight } from "../../utils/mobile/mobileUtils";
@ -36,7 +37,8 @@ export const GroupForum = ({
return (
<div
style={{
height: isMobile ? '100%' : "100vh",
// reference to change height
height: isMobile ? `calc(${getRootHeight()} - 127px` : "100vh",
display: "flex",
flexDirection: "column",
width: "100%",

View File

@ -445,7 +445,7 @@ export const NewThread = ({
sx={{
backgroundColor: "#434448",
padding: isMobile ? '5px' : "20px 42px",
height: "calc(100% - 150px)",
height: "calc(100% - 165px)",
flexShrink: 0,
}}
>

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,7 @@ import { ChatIcon } from "../../assets/Icons/ChatIcon";
import { ThreadsIcon } from "../../assets/Icons/ThreadsIcon";
import { MembersIcon } from "../../assets/Icons/MembersIcon";
export const GroupMenu = ({ setGroupSection, groupSection }) => {
export const GroupMenu = ({ setGroupSection, groupSection, setOpenManageMembers }) => {
const [anchorEl, setAnchorEl] = useState(null);
const open = Boolean(anchorEl);
@ -177,7 +177,7 @@ export const GroupMenu = ({ setGroupSection, groupSection }) => {
</MenuItem>
<MenuItem
onClick={() => {
// setGroupSection("")
setOpenManageMembers(true)
handleClose();
}}
>

View File

@ -1,32 +1,58 @@
import { Box, Button, Typography } from '@mui/material'
import React from 'react'
import { Spacer } from '../../common/Spacer'
import { ListOfThreadPostsWatched } from './ListOfThreadPostsWatched'
import { ThingsToDoInitial } from './ThingsToDoInitial'
import { GroupJoinRequests } from './GroupJoinRequests'
import { GroupInvites } from './GroupInvites'
import { Box, Button, Typography } from "@mui/material";
import React from "react";
import { Spacer } from "../../common/Spacer";
import { ListOfThreadPostsWatched } from "./ListOfThreadPostsWatched";
import { ThingsToDoInitial } from "./ThingsToDoInitial";
import { GroupJoinRequests } from "./GroupJoinRequests";
import { GroupInvites } from "./GroupInvites";
import RefreshIcon from "@mui/icons-material/Refresh";
export const Home = ({refreshHomeDataFunc, myAddress, isLoadingGroups, balance, userInfo, groups, setGroupSection, setSelectedGroup, getTimestampEnterChat, setOpenManageMembers, setOpenAddGroup, setMobileViewMode}) => {
export const Home = ({
refreshHomeDataFunc,
myAddress,
isLoadingGroups,
balance,
userInfo,
groups,
setGroupSection,
setSelectedGroup,
getTimestampEnterChat,
setOpenManageMembers,
setOpenAddGroup,
setMobileViewMode,
}) => {
return (
<Box
sx={{
display: "flex",
width: "100%",
flexDirection: "column",
height: "100%",
overflow: "auto",
alignItems: "center"
}}
>
<Spacer height="20px" />
<Typography sx={{ color: 'rgba(255, 255, 255, 1)', fontWeight: 400, fontSize: '24px'}}>
<Spacer height="16px" />
Welcome
</Typography>
<Spacer height="26px" />
sx={{
display: "flex",
width: "100%",
flexDirection: "column",
height: "100%",
overflow: "auto",
alignItems: "center",
}}
>
<Spacer height="20px" />
<Typography
sx={{
color: "rgba(255, 255, 255, 1)",
fontWeight: 400,
fontSize: userInfo?.name?.length > 15 ? "16px" : "20px",
padding: '10px'
}}
>
Welcome{" "}
{userInfo?.name ? (
<span
style={{
fontStyle: "italic",
}}
>{`, ${userInfo?.name}`}</span>
) : null}
</Typography>
<Spacer height="26px" />
{/* <Box
{/* <Box
sx={{
display: "flex",
width: "100%",
@ -44,42 +70,41 @@ export const Home = ({refreshHomeDataFunc, myAddress, isLoadingGroups, balance,
Refresh home data
</Button>
</Box> */}
{!isLoadingGroups && (
<Box
sx={{
display: "flex",
gap: "15px",
flexWrap: "wrap",
justifyContent: "center",
}}
>
{!isLoadingGroups && (
<Box
sx={{
display: "flex",
gap: "15px",
flexWrap: "wrap",
justifyContent: "center",
}}
>
<ThingsToDoInitial
balance={balance}
myAddress={myAddress}
name={userInfo?.name}
hasGroups={groups?.length !== 0}
/>
<ListOfThreadPostsWatched />
<ThingsToDoInitial
balance={balance}
myAddress={myAddress}
name={userInfo?.name}
hasGroups={groups?.length !== 0}
/>
<ListOfThreadPostsWatched />
<GroupJoinRequests
setGroupSection={setGroupSection}
setSelectedGroup={setSelectedGroup}
getTimestampEnterChat={getTimestampEnterChat}
setOpenManageMembers={setOpenManageMembers}
myAddress={myAddress}
groups={groups}
setMobileViewMode={setMobileViewMode}
/>
<GroupInvites
setOpenAddGroup={setOpenAddGroup}
myAddress={myAddress}
groups={groups}
setMobileViewMode={setMobileViewMode}
/>
</Box>
)}
<Spacer height="180px" />
</Box>
)
}
<GroupJoinRequests
setGroupSection={setGroupSection}
setSelectedGroup={setSelectedGroup}
getTimestampEnterChat={getTimestampEnterChat}
setOpenManageMembers={setOpenManageMembers}
myAddress={myAddress}
groups={groups}
setMobileViewMode={setMobileViewMode}
/>
<GroupInvites
setOpenAddGroup={setOpenAddGroup}
myAddress={myAddress}
groups={groups}
setMobileViewMode={setMobileViewMode}
/>
</Box>
)}
<Spacer height="180px" />
</Box>
);
};

View File

@ -253,6 +253,7 @@ export const ManageMembers = ({
sx={{
width: "100%",
padding: "25px",
maxWidth: '750px'
}}
>
<ListOfMembers
@ -271,6 +272,7 @@ export const ManageMembers = ({
sx={{
width: "100%",
padding: "25px",
maxWidth: '750px'
}}
>
<InviteMember show={show} groupId={selectedGroup?.groupId} setOpenSnack={setOpenSnack} setInfoSnack={setInfoSnack} />
@ -281,7 +283,8 @@ export const ManageMembers = ({
<Box
sx={{
width: "100%",
padding: "25px",
padding: "25px",
maxWidth: '750px'
}}
>
<ListOfInvites show={show} groupId={selectedGroup?.groupId} setOpenSnack={setOpenSnack} setInfoSnack={setInfoSnack} />
@ -293,7 +296,8 @@ export const ManageMembers = ({
<Box
sx={{
width: "100%",
padding: "25px",
padding: "25px",
maxWidth: '750px'
}}
>
<ListOfBans show={show} groupId={selectedGroup?.groupId} setOpenSnack={setOpenSnack} setInfoSnack={setInfoSnack} />
@ -304,7 +308,8 @@ export const ManageMembers = ({
<Box
sx={{
width: "100%",
padding: "25px",
padding: "25px",
maxWidth: '750px'
}}
>
<ListOfJoinRequests show={show} setOpenSnack={setOpenSnack} setInfoSnack={setInfoSnack} groupId={selectedGroup?.groupId} />

View File

@ -1,35 +1,46 @@
import * as React from 'react';
import { BottomNavigation, BottomNavigationAction, Typography } from '@mui/material';
import { Home, Groups, Message, ShowChart } from '@mui/icons-material';
import Box from '@mui/material/Box';
import BottomLogo from '../../assets/svgs/BottomLogo5.svg'
import { CustomSvg } from '../../common/CustomSvg';
import { WalletIcon } from '../../assets/Icons/WalletIcon';
import { HubsIcon } from '../../assets/Icons/HubsIcon';
import { TradingIcon } from '../../assets/Icons/TradingIcon';
import { MessagingIcon } from '../../assets/Icons/MessagingIcon';
import * as React from "react";
import {
BottomNavigation,
BottomNavigationAction,
Typography,
} from "@mui/material";
import { Home, Groups, Message, ShowChart } from "@mui/icons-material";
import Box from "@mui/material/Box";
import BottomLogo from "../../assets/svgs/BottomLogo5.svg";
import { CustomSvg } from "../../common/CustomSvg";
import { WalletIcon } from "../../assets/Icons/WalletIcon";
import { HubsIcon } from "../../assets/Icons/HubsIcon";
import { TradingIcon } from "../../assets/Icons/TradingIcon";
import { MessagingIcon } from "../../assets/Icons/MessagingIcon";
const IconWrapper = ({children, label, color})=> {
return <Box sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
gap: '5px',
flexDirection: 'column'
}}>
{children}
<Typography sx={{
fontFamily: "Inter",
fontSize: "12px",
fontWeight: 500,
color: color
}}>{label}</Typography>
const IconWrapper = ({ children, label, color }) => {
return (
<Box
sx={{
display: "flex",
justifyContent: "center",
alignItems: "center",
gap: "5px",
flexDirection: "column",
}}
>
{children}
<Typography
sx={{
fontFamily: "Inter",
fontSize: "12px",
fontWeight: 500,
color: color,
}}
>
{label}
</Typography>
</Box>
}
);
};
export const MobileFooter =({
selectedGroup,
export const MobileFooter = ({
selectedGroup,
groupSection,
isUnread,
goToAnnouncements,
@ -44,84 +55,131 @@ selectedGroup,
openDrawerGroups,
goToHome,
setIsOpenDrawerProfile,
mobileViewMode,
mobileViewMode,
setMobileViewMode,
setMobileViewModeKeepOpen
setMobileViewModeKeepOpen,
hasUnreadGroups,
hasUnreadDirects
}) => {
const [value, setValue] = React.useState(0);
return (
<Box sx={{
width: '100%',
position: 'fixed',
bottom: 0,
backgroundColor: 'var(--bg-primary)',
display: 'flex',
alignItems: 'center',
height: '67px', // Footer height
const [value, setValue] = React.useState(0);
return (
<Box
sx={{
width: "100%",
position: "fixed",
bottom: 0,
backgroundColor: "var(--bg-primary)",
display: "flex",
alignItems: "center",
height: "67px", // Footer height
zIndex: 1,
borderTopRightRadius: '25px',
borderTopLeftRadius: '25px'
}}>
<BottomNavigation
showLabels
value={value}
onChange={(event, newValue) => setValue(newValue)}
sx={{ backgroundColor: 'transparent', flexGrow: 1 }}
>
<BottomNavigationAction onClick={()=> {
borderTopRightRadius: "25px",
borderTopLeftRadius: "25px",
boxShadow: '0px -2px 10px rgba(0, 0, 0, 0.1)',
}}
>
<BottomNavigation
showLabels
value={value}
onChange={(event, newValue) => setValue(newValue)}
sx={{ backgroundColor: "transparent", flexGrow: 1 }}
>
<BottomNavigationAction
onClick={() => {
// setMobileViewMode('wallet')
setIsOpenDrawerProfile(true)
}} icon={<IconWrapper color="rgba(250, 250, 250, 0.5)" label="Wallet"><WalletIcon color="rgba(250, 250, 250, 0.5)" /></IconWrapper>} sx={{ color: value === 0 ? 'white' : 'gray', padding: '0px 10px' }} />
<BottomNavigationAction onClick={()=> {
setMobileViewMode('groups')
}} icon={<IconWrapper color="rgba(250, 250, 250, 0.5)" label="Hubs"><HubsIcon color="rgba(250, 250, 250, 0.5)" /></IconWrapper>} sx={{ color: value === 0 ? 'white' : 'gray', paddingLeft: '10px', paddingRight: '42px' }} />
setIsOpenDrawerProfile(true);
}}
icon={
<IconWrapper color="rgba(250, 250, 250, 0.5)" label="Wallet">
<WalletIcon color="rgba(250, 250, 250, 0.5)" />
</IconWrapper>
}
sx={{ color: value === 0 ? "white" : "gray", padding: "0px 10px" }}
/>
<BottomNavigationAction
onClick={() => {
setMobileViewMode("groups");
}}
icon={
<IconWrapper color="rgba(250, 250, 250, 0.5)" label="Hubs">
<HubsIcon color={hasUnreadGroups ? "var(--unread)" : "rgba(250, 250, 250, 0.5)"} />
</IconWrapper>
}
sx={{
color: value === 0 ? "white" : "gray",
paddingLeft: "10px",
paddingRight: "42px",
}}
/>
</BottomNavigation>
</BottomNavigation>
{/* Floating Center Button */}
<Box sx={{
position: 'absolute',
bottom: '34px', // Adjusted to float properly based on footer height
left: '50%',
transform: 'translateX(-50%)', // Center horizontally
width: '59px',
height: '59px',
backgroundColor: 'var(--bg-primary)',
borderRadius: '50%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
boxShadow: '0 4px 10px rgba(0, 0, 0, 0.3)', // Subtle shadow for the floating effect
zIndex: 3,
}}>
<Box sx={{
width: '49px', // Slightly smaller inner circle
height: '49px',
backgroundColor: 'var(--bg-primary)',
borderRadius: '50%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}>
{/* Custom Center Icon */}
<img src={BottomLogo} alt="center-icon" />
</Box>
</Box>
<BottomNavigation
showLabels
value={value}
onChange={(event, newValue) => setValue(newValue)}
sx={{ backgroundColor: 'transparent', flexGrow: 1 }}
{/* Floating Center Button */}
<Box
sx={{
position: "absolute",
bottom: "34px", // Adjusted to float properly based on footer height
left: "50%",
transform: "translateX(-50%)", // Center horizontally
width: "59px",
height: "59px",
backgroundColor: "var(--bg-primary)",
borderRadius: "50%",
display: "flex",
justifyContent: "center",
alignItems: "center",
boxShadow: "0 4px 10px rgba(0, 0, 0, 0.3)", // Subtle shadow for the floating effect
zIndex: 3,
}}
>
<Box
sx={{
width: "49px", // Slightly smaller inner circle
height: "49px",
backgroundColor: "var(--bg-primary)",
borderRadius: "50%",
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
<BottomNavigationAction onClick={()=> {
setMobileViewModeKeepOpen('messaging')
}} icon={<IconWrapper label="Messaging" color="rgba(250, 250, 250, 0.5)"><MessagingIcon color="rgba(250, 250, 250, 0.5)" /></IconWrapper>} sx={{ color: value === 2 ? 'white' : 'gray', paddingLeft: '55px', paddingRight: '10px' }} />
<BottomNavigationAction onClick={() => {
chrome.tabs.create({ url: "https://www.qort.trade", active: true });
}} icon={<IconWrapper label="Trading" color="rgba(250, 250, 250, 0.5)"><TradingIcon color="rgba(250, 250, 250, 0.5)" /></IconWrapper>} sx={{ color: value === 3 ? 'white' : 'gray' , padding: '0px 10px'}} />
</BottomNavigation>
{/* Custom Center Icon */}
<img src={BottomLogo} alt="center-icon" />
</Box>
</Box>
);
}
<BottomNavigation
showLabels
value={value}
onChange={(event, newValue) => setValue(newValue)}
sx={{ backgroundColor: "transparent", flexGrow: 1 }}
>
<BottomNavigationAction
onClick={() => {
setMobileViewModeKeepOpen("messaging");
}}
icon={
<IconWrapper label="Messaging" color="rgba(250, 250, 250, 0.5)">
<MessagingIcon color={hasUnreadDirects ? "var(--unread)" :"rgba(250, 250, 250, 0.5)"} />
</IconWrapper>
}
sx={{
color: value === 2 ? "white" : "gray",
paddingLeft: "55px",
paddingRight: "10px",
}}
/>
<BottomNavigationAction
onClick={() => {
chrome.tabs.create({ url: "https://www.qort.trade", active: true });
}}
icon={
<IconWrapper label="Trading" color="rgba(250, 250, 250, 0.5)">
<TradingIcon color="rgba(250, 250, 250, 0.5)" />
</IconWrapper>
}
sx={{ color: value === 3 ? "white" : "gray", padding: "0px 10px" }}
/>
</BottomNavigation>
</Box>
);
};

View File

@ -1,17 +1,35 @@
import React from 'react';
import { AppBar, Toolbar, IconButton, Typography, Box, MenuItem, Select, ButtonBase } from '@mui/material';
import { HomeIcon } from '../../assets/Icons/HomeIcon';
import { LogoutIcon } from '../../assets/Icons/LogoutIcon';
import { NotificationIcon } from '../../assets/Icons/NotificationIcon';
import { ArrowDownIcon } from '../../assets/Icons/ArrowDownIcon';
import { MessagingIcon } from '../../assets/Icons/MessagingIcon';
import React, { useState } from "react";
import {
AppBar,
Toolbar,
IconButton,
Typography,
Box,
MenuItem,
Select,
ButtonBase,
Menu,
ListItemIcon,
ListItemText,
} from "@mui/material";
import { HomeIcon } from "../../assets/Icons/HomeIcon";
import { LogoutIcon } from "../../assets/Icons/LogoutIcon";
import { NotificationIcon } from "../../assets/Icons/NotificationIcon";
import { ArrowDownIcon } from "../../assets/Icons/ArrowDownIcon";
import { MessagingIcon } from "../../assets/Icons/MessagingIcon";
import { MessagingIcon2 } from "../../assets/Icons/MessagingIcon2";
import { HubsIcon } from "../../assets/Icons/HubsIcon";
const Header = ({
logoutFunc,
goToHome,
setIsOpenDrawerProfile,
isThin,
setMobileViewModeKeepOpen
setMobileViewModeKeepOpen,
hasUnreadGroups,
hasUnreadDirects,
setMobileViewMode,
// selectedGroup,
// onHomeClick,
// onLogoutClick,
@ -19,94 +37,243 @@ const Header = ({
// onWalletClick,
// onNotificationClick,
}) => {
if(isThin){
const [anchorEl, setAnchorEl] = useState(null);
const open = Boolean(anchorEl);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
if (isThin) {
return (
<AppBar position="static" sx={{ backgroundColor: 'background: rgba(0, 0, 0, 0.2)', boxShadow: 'none' }}>
<Toolbar sx={{ justifyContent: 'space-between', padding: '0 16px', height: '30px', minHeight: '30px' }}>
{/* Left Home Icon */}
<Box sx={{
display: 'flex',
alignItems: 'center',
gap: '18px',
width: '75px'
}}>
<IconButton edge="start" color="inherit" aria-label="home"
onClick={()=> {
setMobileViewModeKeepOpen('')
goToHome()
}}
// onClick={onHomeClick}
<AppBar
position="static"
sx={{
backgroundColor: "background: rgba(0, 0, 0, 0.2)",
boxShadow: "none",
}}
>
<Toolbar
sx={{
justifyContent: "space-between",
padding: "0 16px",
height: "45px",
minHeight: "45px",
}}
>
<HomeIcon height={16} width={18} color="rgba(145, 145, 147, 1)" />
</IconButton>
<IconButton edge="start" color="inherit" aria-label="home"
onClick={()=> {
setMobileViewModeKeepOpen()
goToHome()
}}
// onClick={onHomeClick}
{/* Left Home Icon */}
<Box
sx={{
display: "flex",
alignItems: "center",
gap: "18px",
width: "75px",
}}
>
<IconButton
edge="start"
color="inherit"
aria-label="home"
onClick={() => {
setMobileViewModeKeepOpen("");
goToHome();
}}
// onClick={onHomeClick}
>
<HomeIcon height={20} width={27} color="rgba(145, 145, 147, 1)" />
</IconButton>
<IconButton
edge="start"
color="inherit"
aria-label="home"
onClick={handleClick}
>
<NotificationIcon height={20} width={21} color={hasUnreadDirects || hasUnreadGroups ? "var(--unread)" : "rgba(145, 145, 147, 1)"} />
</IconButton>
</Box>
{/* Center Title */}
<Typography
variant="h6"
sx={{
color: "rgba(255, 255, 255, 1)",
fontWeight: 700,
letterSpacing: "2px",
fontSize: "13px",
}}
>
QORTAL
</Typography>
<Box
sx={{
display: "flex",
alignItems: "center",
gap: "18px",
width: "75px",
justifyContent: "flex-end",
}}
>
{/* Right Logout Icon */}
<IconButton
onClick={() => {
setMobileViewModeKeepOpen("messaging");
}}
edge="end"
color="inherit"
aria-label="logout"
// onClick={onLogoutClick}
>
<MessagingIcon2 height={20} color={hasUnreadDirects ? "var(--unread)" : "rgba(145, 145, 147, 1)"}
/>
</IconButton>
<IconButton
onClick={logoutFunc}
edge="end"
color="inherit"
aria-label="logout"
// onClick={onLogoutClick}
>
<LogoutIcon
height={20}
width={21}
color="rgba(145, 145, 147, 1)"
/>
</IconButton>
</Box>
</Toolbar>
<Menu
id="home-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
MenuListProps={{
"aria-labelledby": "basic-button",
}}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'center',
}}
slotProps={{
paper: {
sx: {
backgroundColor: 'var(--bg-primary)',
color: '#fff',
width: '148px',
borderRadius: '5px'
},
},
}}
sx={{
marginTop: '10px'
}}
>
<MenuItem
onClick={() => {
setMobileViewMode("groups");
setMobileViewModeKeepOpen("")
handleClose();
}}
>
<NotificationIcon color="rgba(145, 145, 147, 1)" />
</IconButton>
</Box>
<ListItemIcon sx={{
minWidth: '24px !important'
}}>
<HubsIcon height={20} color={hasUnreadGroups ? "var(--unread)" :"rgba(250, 250, 250, 0.5)"} />
</ListItemIcon>
<ListItemText sx={{
"& .MuiTypography-root": {
fontSize: "12px",
fontWeight: 600,
color: hasUnreadDirects ? "var(--unread)" :"rgba(250, 250, 250, 0.5)"
},
}} primary="Hubs" />
</MenuItem>
<MenuItem
onClick={() => {
setMobileViewModeKeepOpen("messaging");
{/* Center Title */}
<Typography variant="h6" sx={{ color: 'rgba(255, 255, 255, 1)', fontWeight: 700, letterSpacing: '2px' , fontSize: '13px'}}>
QORTAL
</Typography>
<Box sx={{
display: 'flex',
alignItems: 'center',
gap: '18px',
width: '75px',
justifyContent: 'flex-end'
}}>
{/* Right Logout Icon */}
<IconButton onClick={()=> {
setMobileViewModeKeepOpen('messaging')
}} edge="end" color="inherit" aria-label="logout"
// onClick={onLogoutClick}
>
<MessagingIcon height={16} width={16} color="rgba(145, 145, 147, 1)" />
</IconButton>
<IconButton onClick={logoutFunc} edge="end" color="inherit" aria-label="logout"
// onClick={onLogoutClick}
handleClose();
}}
>
<LogoutIcon height={16} width={14} color="rgba(145, 145, 147, 1)" />
</IconButton>
</Box>
</Toolbar>
</AppBar>
)
<ListItemIcon sx={{
minWidth: '24px !important'
}}>
<MessagingIcon height={20} color={hasUnreadDirects ? "var(--unread)" :"rgba(250, 250, 250, 0.5)"} />
</ListItemIcon>
<ListItemText sx={{
"& .MuiTypography-root": {
fontSize: "12px",
fontWeight: 600,
color: hasUnreadDirects ? "var(--unread)" :"rgba(250, 250, 250, 0.5)"
},
}} primary="Messaging" />
</MenuItem>
</Menu>
</AppBar>
);
}
return (
<>
{/* Main Header */}
<AppBar position="static" sx={{ backgroundColor: 'var(--bg-primary)', boxShadow: 'none' }}>
<Toolbar sx={{ justifyContent: 'space-between', padding: '0 16px', height: '60px' }}>
<AppBar
position="static"
sx={{ backgroundColor: "var(--bg-primary)", boxShadow: "none" }}
>
<Toolbar
sx={{
justifyContent: "space-between",
padding: "0 16px",
height: "60px",
}}
>
{/* Left Home Icon */}
<IconButton edge="start" color="inherit" aria-label="home"
onClick={goToHome}
// onClick={onHomeClick}
<IconButton
edge="start"
color="inherit"
aria-label="home"
onClick={goToHome}
// onClick={onHomeClick}
>
<HomeIcon color="rgba(145, 145, 147, 1)" />
<HomeIcon color="rgba(145, 145, 147, 1)" />
</IconButton>
{/* Center Title */}
<Typography variant="h6" sx={{ color: 'rgba(255, 255, 255, 1)', fontWeight: 700, letterSpacing: '2px' , fontSize: '13px'}}>
<Typography
variant="h6"
sx={{
color: "rgba(255, 255, 255, 1)",
fontWeight: 700,
letterSpacing: "2px",
fontSize: "13px",
}}
>
QORTAL
</Typography>
{/* Right Logout Icon */}
<IconButton onClick={logoutFunc} edge="end" color="inherit" aria-label="logout"
<IconButton
onClick={logoutFunc}
edge="end"
color="inherit"
aria-label="logout"
// onClick={onLogoutClick}
// onClick={onLogoutClick}
>
<LogoutIcon color="rgba(145, 145, 147, 1)" />
</IconButton>
@ -116,69 +283,160 @@ onClick={()=> {
{/* Secondary Section */}
<Box
sx={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
backgroundColor: 'var(--bg-3)',
padding: '8px 16px',
position: 'relative',
height: '27px'
display: "flex",
justifyContent: "space-between",
alignItems: "center",
backgroundColor: "var(--bg-3)",
padding: "8px 16px",
position: "relative",
height: "27px",
}}
>
<Box sx={{
display: 'flex',
gap: '10px',
alignItems: 'center',
userSelect: 'none'
}}>
<Typography sx={{ color: 'rgba(255, 255, 255, 1)', fontWeight: 400, fontSize: '11px'}}>
<Box
sx={{
display: "flex",
gap: "10px",
alignItems: "center",
userSelect: "none",
}}
>
<Typography
sx={{
color: "rgba(255, 255, 255, 1)",
fontWeight: 400,
fontSize: "11px",
}}
>
Palmas
</Typography>
{/*
{/*
<ArrowDownIcon /> */}
</Box>
<Box
sx={{
position: 'absolute',
left: '50%',
transform: 'translate(-50%, 50%)',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
position: "absolute",
left: "50%",
transform: "translate(-50%, 50%)",
display: "flex",
justifyContent: "center",
alignItems: "center",
zIndex: 500,
width: '30px', // Adjust as needed
height: '30px', // Adjust as needed
backgroundColor: '#232428', // Circle background
borderRadius: '50%',
boxShadow: '0px 4px 10px rgba(0, 0, 0, 0.3)', // Optional shadow for the circle
width: "30px", // Adjust as needed
height: "30px", // Adjust as needed
backgroundColor: "#232428", // Circle background
borderRadius: "50%",
boxShadow: "0px 4px 10px rgba(0, 0, 0, 0.3)", // Optional shadow for the circle
}}
>
<IconButton color="inherit">
<NotificationIcon color="rgba(255, 255, 255, 1)" />
<IconButton onClick={handleClick} color="inherit">
<NotificationIcon color={hasUnreadDirects || hasUnreadGroups ? "var(--unread)" : "rgba(255, 255, 255, 1)"} />
</IconButton>
</Box>
{/* Right Dropdown */}
<ButtonBase onClick={()=> {
setIsOpenDrawerProfile(true)
}}>
<Box sx={{
display: 'flex',
gap: '10px',
alignItems: 'center'
}}>
<Typography sx={{ color: 'rgba(255, 255, 255, 1)', fontWeight: 400, fontSize: '11px'}}>
View Wallet
</Typography>
{/* <ButtonBase
onClick={() => {
setIsOpenDrawerProfile(true);
}}
>
<Box
sx={{
display: "flex",
gap: "10px",
alignItems: "center",
}}
>
<Typography
sx={{
color: "rgba(255, 255, 255, 1)",
fontWeight: 400,
fontSize: "11px",
}}
>
View Wallet
</Typography>
<ArrowDownIcon />
</Box>
</ButtonBase>
<ArrowDownIcon />
</Box>
</ButtonBase> */}
</Box>
<Menu
id="home-menu"
anchorEl={anchorEl}
open={open}
onClose={handleClose}
MenuListProps={{
"aria-labelledby": "basic-button",
}}
anchorOrigin={{
vertical: 'bottom',
horizontal: 'center',
}}
transformOrigin={{
vertical: 'top',
horizontal: 'center',
}}
slotProps={{
paper: {
sx: {
backgroundColor: 'var(--bg-primary)',
color: '#fff',
width: '148px',
borderRadius: '5px'
},
},
}}
sx={{
marginTop: '10px'
}}
>
<MenuItem
onClick={() => {
setMobileViewMode("groups");
setMobileViewModeKeepOpen("")
handleClose();
}}
>
<ListItemIcon sx={{
minWidth: '24px !important'
}}>
<HubsIcon height={20} color={hasUnreadGroups ? "var(--unread)" :"rgba(250, 250, 250, 0.5)"} />
</ListItemIcon>
<ListItemText sx={{
"& .MuiTypography-root": {
fontSize: "12px",
fontWeight: 600,
color: hasUnreadDirects ? "var(--unread)" :"rgba(250, 250, 250, 0.5)"
},
}} primary="Hubs" />
</MenuItem>
<MenuItem
onClick={() => {
setMobileViewModeKeepOpen("messaging");
handleClose();
}}
>
<ListItemIcon sx={{
minWidth: '24px !important'
}}>
<MessagingIcon height={20} color={hasUnreadDirects ? "var(--unread)" :"rgba(250, 250, 250, 0.5)"} />
</ListItemIcon>
<ListItemText sx={{
"& .MuiTypography-root": {
fontSize: "12px",
fontWeight: 600,
color: hasUnreadDirects ? "var(--unread)" :"rgba(250, 250, 250, 0.5)"
},
}} primary="Messaging" />
</MenuItem>
</Menu>
</>
);
};

View File

@ -25,6 +25,7 @@
padding: 0px;
margin: 0px;
box-sizing: border-box !important;
word-break: break-word;
--color-instance : #1E1E20;
--color-instance-popover-bg: #222222;
--Mail-Background: rgba(49, 51, 56, 1);
@ -33,6 +34,7 @@
--bg-primary : rgba(31, 32, 35, 1);
--bg-2: #27282c;
--bg-3: rgba(0, 0, 0, 0.1);
--unread: rgba(255, 0, 0, 1);
}
body {