Format code, rmove unused

This commit is contained in:
Nicola Benaglia 2025-04-12 16:40:32 +02:00
parent 4f9b8fe6cc
commit 2a41667ef8
16 changed files with 3969 additions and 3295 deletions

View File

@ -6,7 +6,7 @@ import React, {
useState,
} from 'react';
import { Spacer } from '../common/Spacer';
import { CustomButton, TextP, TextSpan } from '../App-styles';
import { CustomButton, TextP, TextSpan } from '../styles/App-styles';
import {
Box,
Button,
@ -29,7 +29,7 @@ import { CustomizedSnackbars } from '../components/Snackbar/Snackbar';
import { cleanUrl, gateways } from '../background';
import { GlobalContext } from '../App';
import Tooltip, { TooltipProps, tooltipClasses } from '@mui/material/Tooltip';
import ThemeSelector from '../styles/ThemeSelector';
import ThemeSelector from '../components/Theme/ThemeSelector';
const manifestData = {
version: '0.5.3',

View File

@ -3,15 +3,15 @@ import {
InputAdornment,
TextField,
TextFieldProps,
} from "@mui/material";
import React, { useRef, useState } from "react";
import AddIcon from "@mui/icons-material/Add";
import RemoveIcon from "@mui/icons-material/Remove";
} from '@mui/material';
import React, { useRef, useState } from 'react';
import AddIcon from '@mui/icons-material/Add';
import RemoveIcon from '@mui/icons-material/Remove';
import {
removeTrailingZeros,
setNumberWithinBounds,
} from "./numberFunctions.ts";
import { CustomInput } from "../App-styles.ts";
} from './numberFunctions.ts';
import { CustomInput } from '../styles/App-styles.ts';
type eventType = React.ChangeEvent<HTMLInputElement>;
type BoundedNumericTextFieldProps = {
@ -37,18 +37,18 @@ export const BoundedNumericTextField = ({
...props
}: BoundedNumericTextFieldProps) => {
const [textFieldValue, setTextFieldValue] = useState<string>(
initialValue || ""
initialValue || ''
);
const ref = useRef<HTMLInputElement | null>(null);
const stringIsEmpty = (value: string) => {
return value === "";
return value === '';
};
const isAllZerosNum = /^0*\.?0*$/;
const isFloatNum = /^-?[0-9]*\.?[0-9]*$/;
const isIntegerNum = /^-?[0-9]+$/;
const skipMinMaxCheck = (value: string) => {
const lastIndexIsDecimal = value.charAt(value.length - 1) === ".";
const lastIndexIsDecimal = value.charAt(value.length - 1) === '.';
const isEmpty = stringIsEmpty(value);
const isAllZeros = isAllZerosNum.test(value);
const isInteger = isIntegerNum.test(value);
@ -69,7 +69,7 @@ export const BoundedNumericTextField = ({
const getSigDigits = (number: string) => {
if (isIntegerNum.test(number)) return 0;
const decimalSplit = number.split(".");
const decimalSplit = number.split('.');
return decimalSplit[decimalSplit.length - 1].length;
};
@ -78,15 +78,15 @@ export const BoundedNumericTextField = ({
};
const filterTypes = (value: string) => {
if (allowDecimals === false) value = value.replace(".", "");
if (allowNegatives === false) value = value.replace("-", "");
if (allowDecimals === false) value = value.replace('.', '');
if (allowNegatives === false) value = value.replace('-', '');
if (sigDigitsExceeded(value, maxSigDigits)) {
value = value.substring(0, value.length - 1);
}
return value;
};
const filterValue = (value: string) => {
if (stringIsEmpty(value)) return "";
if (stringIsEmpty(value)) return '';
value = filterTypes(value);
if (isFloatNum.test(value)) {
return setMinMaxValue(value);
@ -109,8 +109,8 @@ export const BoundedNumericTextField = ({
const formatValueOnBlur = (e: eventType) => {
let value = e.target.value;
if (stringIsEmpty(value) || value === ".") {
setTextFieldValue("");
if (stringIsEmpty(value) || value === '.') {
setTextFieldValue('');
return;
}
@ -129,23 +129,33 @@ export const BoundedNumericTextField = ({
...props?.InputProps,
endAdornment: addIconButtons ? (
<InputAdornment position="end">
<IconButton size="small" onClick={() => changeValueWithIncDecButton(1)}>
<AddIcon sx={{
color: 'white'
}} />{" "}
<IconButton
size="small"
onClick={() => changeValueWithIncDecButton(1)}
>
<AddIcon
sx={{
color: 'white',
}}
/>{' '}
</IconButton>
<IconButton size="small" onClick={() => changeValueWithIncDecButton(-1)}>
<RemoveIcon sx={{
color: 'white'
}} />{" "}
<IconButton
size="small"
onClick={() => changeValueWithIncDecButton(-1)}
>
<RemoveIcon
sx={{
color: 'white',
}}
/>{' '}
</IconButton>
</InputAdornment>
) : (
<></>
),
}}
onChange={e => listeners(e as eventType)}
onBlur={e => {
onChange={(e) => listeners(e as eventType)}
onBlur={(e) => {
formatValueOnBlur(e as eventType);
}}
autoComplete="off"

View File

@ -1,57 +1,57 @@
import React, { useState } from "react";
import QRCode from "react-qr-code";
import { TextP } from "../App-styles";
import { Box, Typography } from "@mui/material";
import React, { useState } from 'react';
import QRCode from 'react-qr-code';
import { TextP } from '../styles/App-styles';
import { Box, Typography } from '@mui/material';
export const AddressQRCode = ({ targetAddress }) => {
const [open, setOpen] = useState(false);
return (
<Box
sx={{
display: "flex",
gap: "10px",
alignItems: "center",
flexDirection: "column",
marginTop: '10px'
display: 'flex',
gap: '10px',
alignItems: 'center',
flexDirection: 'column',
marginTop: '10px',
}}
>
<Typography
sx={{
cursor: "pointer",
fontSize: "14px",
cursor: 'pointer',
fontSize: '14px',
}}
onClick={() => {
setOpen((prev)=> !prev);
setOpen((prev) => !prev);
}}
>
{open ? 'Hide QR code' :'See QR code'}
{open ? 'Hide QR code' : 'See QR code'}
</Typography>
{open && (
<Box
sx={{
display: "flex",
gap: "10px",
alignItems: "center",
justifyContent: "center",
width: "100%",
display: 'flex',
gap: '10px',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
}}
>
<Box
sx={{
display: "flex",
gap: "10px",
width: "100%",
alignItems: "center",
flexDirection: "column",
marginTop: "20px",
display: 'flex',
gap: '10px',
width: '100%',
alignItems: 'center',
flexDirection: 'column',
marginTop: '20px',
}}
>
<TextP
sx={{
textAlign: "center",
textAlign: 'center',
lineHeight: 1.2,
fontSize: "16px",
fontSize: '16px',
fontWeight: 500,
}}
>

View File

@ -15,7 +15,8 @@ import { SortablePinnedApps } from './SortablePinnedApps';
import { extractComponents } from '../Chat/MessageDisplay';
import ArrowOutwardIcon from '@mui/icons-material/ArrowOutward';
import { AppsPrivate } from './AppsPrivate';
import ThemeSelector from '../../styles/ThemeSelector';
import ThemeSelector from '../Theme/ThemeSelector';
export const AppsHomeDesktop = ({
setMode,
myApp,

View File

@ -1,18 +1,32 @@
import React, { useMemo, useRef, useState } from "react";
import TipTap from "./TipTap";
import { AuthenticatedContainerInnerTop, CustomButton } from "../../App-styles";
import { Box, CircularProgress } from "@mui/material";
import { objectToBase64 } from "../../qdn/encryption/group-encryption";
import ShortUniqueId from "short-unique-id";
import { LoadingSnackbar } from "../Snackbar/LoadingSnackbar";
import { getBaseApi, getFee } from "../../background";
import { decryptPublishes, getTempPublish, handleUnencryptedPublishes, saveTempPublish } from "./GroupAnnouncements";
import { AnnouncementList } from "./AnnouncementList";
import { Spacer } from "../../common/Spacer";
import React, { useMemo, useRef, useState } from 'react';
import TipTap from './TipTap';
import {
AuthenticatedContainerInnerTop,
CustomButton,
} from '../../styles/App-styles';
import { Box, CircularProgress } from '@mui/material';
import { objectToBase64 } from '../../qdn/encryption/group-encryption';
import ShortUniqueId from 'short-unique-id';
import { LoadingSnackbar } from '../Snackbar/LoadingSnackbar';
import { getBaseApi, getFee } from '../../background';
import {
decryptPublishes,
getTempPublish,
handleUnencryptedPublishes,
saveTempPublish,
} from './GroupAnnouncements';
import { AnnouncementList } from './AnnouncementList';
import { Spacer } from '../../common/Spacer';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import { getArbitraryEndpointReact, getBaseApiReact, isMobile, pauseAllQueues, resumeAllQueues } from "../../App";
import {
getArbitraryEndpointReact,
getBaseApiReact,
isMobile,
pauseAllQueues,
resumeAllQueues,
} from '../../App';
const tempKey = 'accouncement-comment'
const tempKey = 'accouncement-comment';
const uid = new ShortUniqueId({ length: 8 });
export const AnnouncementDiscussion = ({
@ -23,28 +37,28 @@ export const AnnouncementDiscussion = ({
setSelectedAnnouncement,
show,
myName,
isPrivate
isPrivate,
}) => {
const [isSending, setIsSending] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [isFocusedParent, setIsFocusedParent] = useState(false);
const [comments, setComments] = useState([])
const [tempPublishedList, setTempPublishedList] = useState([])
const firstMountRef = useRef(false)
const [data, setData] = useState({})
const [comments, setComments] = useState([]);
const [tempPublishedList, setTempPublishedList] = useState([]);
const firstMountRef = useRef(false);
const [data, setData] = useState({});
const editorRef = useRef(null);
const setEditorRef = (editorInstance) => {
editorRef.current = editorInstance;
};
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);
}, 200);
}
}
@ -52,14 +66,16 @@ export const AnnouncementDiscussion = ({
const getData = async ({ identifier, name }, isPrivate) => {
try {
const res = await fetch(
`${getBaseApiReact()}/arbitrary/DOCUMENT/${name}/${identifier}?encoding=base64`
);
if(!res?.ok) return
if (!res?.ok) return;
const data = await res.text();
const response = isPrivate === false ? handleUnencryptedPublishes([data]) : await decryptPublishes([{ data }], secretKey);
const response =
isPrivate === false
? handleUnencryptedPublishes([data])
: await decryptPublishes([{ data }], secretKey);
const messageData = response[0];
setData((prev) => {
return {
@ -67,19 +83,19 @@ export const AnnouncementDiscussion = ({
[`${identifier}-${name}`]: messageData,
};
});
} catch (error) {}
};
const publishAnc = async ({ encryptedData, identifier }: any) => {
try {
if (!selectedAnnouncement) return;
return new Promise((res, rej) => {
window.sendMessage("publishGroupEncryptedResource", {
encryptedData,
identifier,
})
window
.sendMessage('publishGroupEncryptedResource', {
encryptedData,
identifier,
})
.then((response) => {
if (!response?.error) {
res(response);
@ -88,63 +104,60 @@ export const AnnouncementDiscussion = ({
rej(response.error);
})
.catch((error) => {
rej(error.message || "An error occurred");
rej(error.message || 'An error occurred');
});
});
} catch (error) {}
};
const setTempData = async ()=> {
const setTempData = async () => {
try {
const getTempAnnouncements = await getTempPublish()
if(getTempAnnouncements[tempKey]){
let tempData = []
Object.keys(getTempAnnouncements[tempKey] || {}).map((key)=> {
const value = getTempAnnouncements[tempKey][key]
if(value.data?.announcementId === selectedAnnouncement.identifier){
tempData.push(value.data)
const getTempAnnouncements = await getTempPublish();
if (getTempAnnouncements[tempKey]) {
let tempData = [];
Object.keys(getTempAnnouncements[tempKey] || {}).map((key) => {
const value = getTempAnnouncements[tempKey][key];
if (value.data?.announcementId === selectedAnnouncement.identifier) {
tempData.push(value.data);
}
});
setTempPublishedList(tempData);
}
})
setTempPublishedList(tempData)
}
} catch (error) {
}
}
} catch (error) {}
};
const publishComment = 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();
if (!htmlContent?.trim() || htmlContent?.trim() === "<p></p>") return;
if (!htmlContent?.trim() || htmlContent?.trim() === '<p></p>') return;
setIsSending(true);
const message = {
version: 1,
extra: {},
message: htmlContent,
};
const secretKeyObject = isPrivate === false ? null : await getSecretKey(false, true);
const message64: any = await objectToBase64(message);
const encryptSingle = isPrivate === false ? message64 : await encryptChatMessage(
message64,
secretKeyObject
);
const secretKeyObject =
isPrivate === false ? null : await getSecretKey(false, true);
const message64: any = await objectToBase64(message);
const encryptSingle =
isPrivate === false
? message64
: await encryptChatMessage(message64, secretKeyObject);
const randomUid = uid.rnd();
const identifier = `cm-${selectedAnnouncement.identifier}-${randomUid}`;
const res = await publishAnc({
encryptedData: encryptSingle,
identifier
identifier,
});
const dataToSaveToStorage = {
@ -153,18 +166,18 @@ export const AnnouncementDiscussion = ({
service: 'DOCUMENT',
tempData: message,
created: Date.now(),
announcementId: selectedAnnouncement.identifier
}
await saveTempPublish({data: dataToSaveToStorage, key: tempKey})
setTempData()
announcementId: selectedAnnouncement.identifier,
};
await saveTempPublish({ data: dataToSaveToStorage, key: tempKey });
setTempData();
clearEditorContent();
}
// send chat message
} catch (error) {
console.error(error);
} finally {
resumeAllQueues()
resumeAllQueues();
setIsSending(false);
}
};
@ -172,7 +185,6 @@ export const AnnouncementDiscussion = ({
const getComments = React.useCallback(
async (selectedAnnouncement, isPrivate) => {
try {
setIsLoading(true);
const offset = 0;
@ -181,13 +193,13 @@ export const AnnouncementDiscussion = ({
const identifier = `cm-${selectedAnnouncement.identifier}`;
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",
method: 'GET',
headers: {
"Content-Type": "application/json",
'Content-Type': 'application/json',
},
});
const responseData = await response.json();
setTempData()
setTempData();
setComments(responseData);
setIsLoading(false);
for (const data of responseData) {
@ -203,119 +215,122 @@ export const AnnouncementDiscussion = ({
[secretKey]
);
const loadMore = async()=> {
const loadMore = async () => {
try {
setIsLoading(true);
const offset = comments.length
const offset = comments.length;
const identifier = `cm-${selectedAnnouncement.identifier}`;
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 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();
setComments((prev)=> [...prev, ...responseData]);
setIsLoading(false);
for (const data of responseData) {
getData({ name: data.name, identifier: data.identifier }, isPrivate);
}
} catch (error) {
}
}
setComments((prev) => [...prev, ...responseData]);
setIsLoading(false);
for (const data of responseData) {
getData({ name: data.name, identifier: data.identifier }, isPrivate);
}
} catch (error) {}
};
const combinedListTempAndReal = useMemo(() => {
// Combine the two lists
const combined = [...tempPublishedList, ...comments];
// 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, comments]);
React.useEffect(() => {
if(!secretKey && isPrivate) return
if (!secretKey && isPrivate) return;
if (selectedAnnouncement && !firstMountRef.current && isPrivate !== null) {
getComments(selectedAnnouncement, isPrivate);
firstMountRef.current = true
firstMountRef.current = true;
}
}, [selectedAnnouncement, secretKey, isPrivate]);
return (
<div
style={{
height: isMobile ? '100%' : "100%",
display: "flex",
flexDirection: "column",
width: "100%",
height: isMobile ? '100%' : '100%',
display: 'flex',
flexDirection: 'column',
width: '100%',
}}
>
<div style={{
position: "relative",
width: "100%",
display: "flex",
flexDirection: "column",
flexShrink: 0,
}}>
<AuthenticatedContainerInnerTop sx={{
height: '20px'
}}>
<ArrowBackIcon onClick={()=> setSelectedAnnouncement(null)} sx={{
cursor: 'pointer'
}} />
</AuthenticatedContainerInnerTop>
<div
style={{
position: 'relative',
width: '100%',
display: 'flex',
flexDirection: 'column',
flexShrink: 0,
}}
>
<AuthenticatedContainerInnerTop
sx={{
height: '20px',
}}
>
<ArrowBackIcon
onClick={() => setSelectedAnnouncement(null)}
sx={{
cursor: 'pointer',
}}
/>
</AuthenticatedContainerInnerTop>
<Spacer height="20px" />
</div>
<AnnouncementList
announcementData={data}
initialMessages={combinedListTempAndReal}
setSelectedAnnouncement={()=> {}}
setSelectedAnnouncement={() => {}}
disableComment
showLoadMore={comments.length > 0 && comments.length % 20 === 0}
loadMore={loadMore}
myName={myName}
/>
<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",
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,
flexShrink: 0,
}}
>
<div
style={{
display: "flex",
flexDirection: "column",
display: 'flex',
flexDirection: 'column',
// height: '100%',
flexGrow: isMobile && 1,
overflow: "auto",
overflow: 'auto',
}}
>
<TipTap
@ -323,79 +338,78 @@ export const AnnouncementDiscussion = ({
onEnter={publishComment}
disableEnter
maxHeightOffset="60px"
isFocusedParent={isFocusedParent} setIsFocusedParent={setIsFocusedParent}
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',
flexShrink: 0,
padding: isMobile && '5px',
fontSize: isMobile && '14px',
background: 'red',
}}
>
{` Close`}
</CustomButton>
)}
<CustomButton
onClick={() => {
if (isSending) return;
publishComment();
}}
style={{
marginTop: "auto",
alignSelf: "center",
cursor: isSending ? "default" : "pointer",
background: isSending && "rgba(0, 0, 0, 0.8)",
<Box
sx={{
display: 'flex',
width: '100&',
gap: '10px',
justifyContent: 'center',
flexShrink: 0,
padding: isMobile && '5px',
fontSize: isMobile && '14px'
position: 'relative',
}}
>
{isSending && (
<CircularProgress
size={18}
sx={{
position: "absolute",
top: "50%",
left: "50%",
marginTop: "-12px",
marginLeft: "-12px",
color: "white",
{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>
)}
{` Publish Comment`}
</CustomButton>
</Box>
<CustomButton
onClick={() => {
if (isSending) return;
publishComment();
}}
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 Comment`}
</CustomButton>
</Box>
</div>
<LoadingSnackbar
open={isLoading}
info={{
message: "Loading comments... please wait.",
message: 'Loading comments... please wait.',
}}
/>
</div>

View File

@ -1,13 +1,13 @@
import React, { useCallback, useState, useEffect, useRef } from "react";
import React, { useCallback, useState, useEffect, useRef } from 'react';
import {
List,
AutoSizer,
CellMeasurerCache,
CellMeasurer,
} from "react-virtualized";
import { AnnouncementItem } from "./AnnouncementItem";
import { Box } from "@mui/material";
import { CustomButton } from "../../App-styles";
} from 'react-virtualized';
import { AnnouncementItem } from './AnnouncementItem';
import { Box } from '@mui/material';
import { CustomButton } from '../../styles/App-styles';
const cache = new CellMeasurerCache({
fixedWidth: true,
@ -21,9 +21,8 @@ export const AnnouncementList = ({
disableComment,
showLoadMore,
loadMore,
myName
myName,
}) => {
const listRef = useRef();
const [messages, setMessages] = useState(initialMessages);
@ -35,39 +34,44 @@ export const AnnouncementList = ({
setMessages(initialMessages);
}, [initialMessages]);
return (
<div
style={{
position: "relative",
position: 'relative',
flexGrow: 1,
width: "100%",
display: "flex",
flexDirection: "column",
width: '100%',
display: 'flex',
flexDirection: 'column',
flexShrink: 1,
overflow: 'auto'
overflow: 'auto',
}}
>
{messages.map((message) => {
const messageData = message?.tempData ? {
decryptedData: message?.tempData
} : announcementData[`${message.identifier}-${message.name}`];
const messageData = message?.tempData
? {
decryptedData: message?.tempData,
}
: announcementData[`${message.identifier}-${message.name}`];
return (
<div
key={message?.identifier}
style={{
marginBottom: "10px",
width: "100%",
display: "flex",
flexDirection: "column",
alignItems: "center",
}}
>
<AnnouncementItem myName={myName} disableComment={disableComment} setSelectedAnnouncement={setSelectedAnnouncement} message={message} messageData={messageData} />
</div>
<div
key={message?.identifier}
style={{
marginBottom: '10px',
width: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
}}
>
<AnnouncementItem
myName={myName}
disableComment={disableComment}
setSelectedAnnouncement={setSelectedAnnouncement}
message={message}
messageData={messageData}
/>
</div>
);
})}
{/* <AutoSizer>
@ -83,16 +87,20 @@ export const AnnouncementList = ({
/>
)}
</AutoSizer> */}
<Box sx={{
width: '100%',
marginTop: '25px',
display: 'flex',
justifyContent: 'center'
}}>
{showLoadMore && (
<CustomButton onClick={loadMore}>Load older announcements</CustomButton>
)}
</Box>
<Box
sx={{
width: '100%',
marginTop: '25px',
display: 'flex',
justifyContent: 'center',
}}
>
{showLoadMore && (
<CustomButton onClick={loadMore}>
Load older announcements
</CustomButton>
)}
</Box>
</div>
);
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -4,30 +4,33 @@ import React, {
useMemo,
useRef,
useState,
} from "react";
import { CreateCommonSecret } from "./CreateCommonSecret";
import { reusableGet } from "../../qdn/publish/pubish";
import { uint8ArrayToObject } from "../../backgroundFunctions/encryption";
} from 'react';
import { CreateCommonSecret } from './CreateCommonSecret';
import { reusableGet } from '../../qdn/publish/pubish';
import { uint8ArrayToObject } from '../../backgroundFunctions/encryption';
import {
base64ToUint8Array,
objectToBase64,
} from "../../qdn/encryption/group-encryption";
import { ChatContainerComp } from "./ChatContainer";
import { ChatList } from "./ChatList";
import "@chatscope/chat-ui-kit-styles/dist/default/styles.min.css";
import Tiptap from "./TipTap";
import { AuthenticatedContainerInnerTop, CustomButton } from "../../App-styles";
import CircularProgress from "@mui/material/CircularProgress";
import { getBaseApi, getFee } from "../../background";
import { LoadingSnackbar } from "../Snackbar/LoadingSnackbar";
import { Box, Typography } from "@mui/material";
import { Spacer } from "../../common/Spacer";
import ShortUniqueId from "short-unique-id";
import { AnnouncementList } from "./AnnouncementList";
} from '../../qdn/encryption/group-encryption';
import { ChatContainerComp } from './ChatContainer';
import { ChatList } from './ChatList';
import '@chatscope/chat-ui-kit-styles/dist/default/styles.min.css';
import Tiptap from './TipTap';
import {
AuthenticatedContainerInnerTop,
CustomButton,
} from '../../styles/App-styles';
import CircularProgress from '@mui/material/CircularProgress';
import { getBaseApi, getFee } from '../../background';
import { LoadingSnackbar } from '../Snackbar/LoadingSnackbar';
import { Box, Typography } from '@mui/material';
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 { AnnouncementDiscussion } from "./AnnouncementDiscussion";
import CampaignIcon from '@mui/icons-material/Campaign';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import { AnnouncementDiscussion } from './AnnouncementDiscussion';
import {
MyContext,
getArbitraryEndpointReact,
@ -35,11 +38,11 @@ import {
isMobile,
pauseAllQueues,
resumeAllQueues,
} from "../../App";
import { RequestQueueWithPromise } from "../../utils/queue/queue";
import { CustomizedSnackbars } from "../Snackbar/Snackbar";
import { addDataPublishesFunc, getDataPublishesFunc } from "../Group/Group";
import { getRootHeight } from "../../utils/mobile/mobileUtils";
} from '../../App';
import { RequestQueueWithPromise } from '../../utils/queue/queue';
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
import { addDataPublishesFunc, getDataPublishesFunc } from '../Group/Group';
import { getRootHeight } from '../../utils/mobile/mobileUtils';
export const requestQueueCommentCount = new RequestQueueWithPromise(3);
export const requestQueuePublishedAccouncements = new RequestQueueWithPromise(
@ -48,10 +51,11 @@ export const requestQueuePublishedAccouncements = new RequestQueueWithPromise(
export const saveTempPublish = async ({ data, key }: any) => {
return new Promise((res, rej) => {
window.sendMessage("saveTempPublish", {
data,
key,
})
window
.sendMessage('saveTempPublish', {
data,
key,
})
.then((response) => {
if (!response?.error) {
res(response);
@ -60,37 +64,37 @@ export const saveTempPublish = async ({ data, key }: any) => {
rej(response.error);
})
.catch((error) => {
rej(error.message || "An error occurred");
rej(error.message || 'An error occurred');
});
});
};
export const getTempPublish = async () => {
return new Promise((res, rej) => {
window.sendMessage("getTempPublish", {})
.then((response) => {
if (!response?.error) {
res(response);
return;
}
rej(response.error);
})
.catch((error) => {
rej(error.message || "An error occurred");
});
window
.sendMessage('getTempPublish', {})
.then((response) => {
if (!response?.error) {
res(response);
return;
}
rej(response.error);
})
.catch((error) => {
rej(error.message || 'An error occurred');
});
});
};
export const decryptPublishes = async (encryptedMessages: any[], secretKey) => {
try {
return await new Promise((res, rej) => {
window.sendMessage("decryptSingleForPublishes", {
data: encryptedMessages,
secretKeyObject: secretKey,
skipDecodeBase64: true,
})
window
.sendMessage('decryptSingleForPublishes', {
data: encryptedMessages,
secretKeyObject: secretKey,
skipDecodeBase64: true,
})
.then((response) => {
if (!response?.error) {
res(response);
@ -99,26 +103,23 @@ export const decryptPublishes = async (encryptedMessages: any[], secretKey) => {
rej(response.error);
})
.catch((error) => {
rej(error.message || "An error occurred");
rej(error.message || 'An error occurred');
});
});
} catch (error) {}
};
export const handleUnencryptedPublishes = (publishes) => {
let publishesData = []
publishes.forEach((pub)=> {
export const handleUnencryptedPublishes = (publishes) => {
let publishesData = [];
publishes.forEach((pub) => {
try {
const decryptToUnit8Array = base64ToUint8Array(pub);
const decodedData = uint8ArrayToObject(decryptToUnit8Array);
if(decodedData){
publishesData.push({decryptedData: decodedData})
if (decodedData) {
publishesData.push({ decryptedData: decodedData });
}
} catch (error) {
}
})
return publishesData
} catch (error) {}
});
return publishesData;
};
export const GroupAnnouncements = ({
selectedGroup,
@ -130,7 +131,7 @@ export const GroupAnnouncements = ({
isAdmin,
hide,
myName,
isPrivate
isPrivate,
}) => {
const [messages, setMessages] = useState([]);
const [isSending, setIsSending] = useState(false);
@ -159,12 +160,15 @@ export const GroupAnnouncements = ({
useEffect(() => {
if (!selectedGroup) return;
(async () => {
const res = await getDataPublishesFunc(selectedGroup, "anc");
const res = await getDataPublishesFunc(selectedGroup, 'anc');
dataPublishes.current = res || {};
})();
}, [selectedGroup]);
const getAnnouncementData = async ({ identifier, name, resource }, isPrivate) => {
const getAnnouncementData = async (
{ identifier, name, resource },
isPrivate
) => {
try {
let data = dataPublishes.current[`${name}-${identifier}`];
if (
@ -179,14 +183,17 @@ export const GroupAnnouncements = ({
});
if (!res?.ok) return;
data = await res.text();
await addDataPublishesFunc({ ...resource, data }, selectedGroup, "anc");
await addDataPublishesFunc({ ...resource, data }, selectedGroup, 'anc');
} else {
data = data.data;
}
const response = isPrivate === false ? handleUnencryptedPublishes([data]) : await decryptPublishes([{ data }], secretKey);
const response =
isPrivate === false
? handleUnencryptedPublishes([data])
: await decryptPublishes([{ data }], secretKey);
const messageData = response[0];
if(!messageData) return
if (!messageData) return;
setAnnouncementData((prev) => {
return {
...prev,
@ -194,12 +201,17 @@ export const GroupAnnouncements = ({
};
});
} catch (error) {
console.error("error", error);
console.error('error', error);
}
};
useEffect(() => {
if ((!secretKey && isPrivate) || hasInitializedWebsocket.current || isPrivate === null) return;
if (
(!secretKey && isPrivate) ||
hasInitializedWebsocket.current ||
isPrivate === null
)
return;
setIsLoading(true);
// initWebsocketMessageGroup()
hasInitializedWebsocket.current = true;
@ -208,10 +220,11 @@ export const GroupAnnouncements = ({
const encryptChatMessage = async (data: string, secretKeyObject: any) => {
try {
return new Promise((res, rej) => {
window.sendMessage("encryptSingle", {
data,
secretKeyObject,
})
window
.sendMessage('encryptSingle', {
data,
secretKeyObject,
})
.then((response) => {
if (!response?.error) {
res(response);
@ -220,19 +233,19 @@ export const GroupAnnouncements = ({
rej(response.error);
})
.catch((error) => {
rej(error.message || "An error occurred");
rej(error.message || 'An error occurred');
});
});
} catch (error) {}
};
const publishAnc = async ({ encryptedData, identifier }: any) => {
return new Promise((res, rej) => {
window.sendMessage("publishGroupEncryptedResource", {
encryptedData,
identifier,
})
window
.sendMessage('publishGroupEncryptedResource', {
encryptedData,
identifier,
})
.then((response) => {
if (!response?.error) {
res(response);
@ -241,9 +254,8 @@ export const GroupAnnouncements = ({
rej(response.error);
})
.catch((error) => {
rej(error.message || "An error occurred");
rej(error.message || 'An error occurred');
});
});
};
const clearEditorContent = () => {
@ -255,7 +267,7 @@ export const GroupAnnouncements = ({
setIsFocusedParent(false);
setTimeout(() => {
triggerRerender();
}, 300);
}, 300);
}, 200);
}
}
@ -266,10 +278,12 @@ export const GroupAnnouncements = ({
const getTempAnnouncements = await getTempPublish();
if (getTempAnnouncements?.announcement) {
let tempData = [];
Object.keys(getTempAnnouncements?.announcement || {}).filter((annKey)=> annKey?.startsWith(`grp-${selectedGroup}-anc`)).map((key) => {
const value = getTempAnnouncements?.announcement[key];
tempData.push(value.data);
});
Object.keys(getTempAnnouncements?.announcement || {})
.filter((annKey) => annKey?.startsWith(`grp-${selectedGroup}-anc`))
.map((key) => {
const value = getTempAnnouncements?.announcement[key];
tempData.push(value.data);
});
setTempPublishedList(tempData);
}
} catch (error) {}
@ -278,27 +292,28 @@ export const GroupAnnouncements = ({
const publishAnnouncement = async () => {
try {
pauseAllQueues();
const fee = await getFee("ARBITRARY");
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();
if (!htmlContent?.trim() || htmlContent?.trim() === "<p></p>") return;
if (!htmlContent?.trim() || htmlContent?.trim() === '<p></p>') return;
setIsSending(true);
const message = {
version: 1,
extra: {},
message: htmlContent,
};
const secretKeyObject = isPrivate === false ? null : await getSecretKey(false, true);
const message64: any = await objectToBase64(message);
const encryptSingle = isPrivate === false ? message64 : await encryptChatMessage(
message64,
secretKeyObject
);
const secretKeyObject =
isPrivate === false ? null : await getSecretKey(false, true);
const message64: any = await objectToBase64(message);
const encryptSingle =
isPrivate === false
? message64
: await encryptChatMessage(message64, secretKeyObject);
const randomUid = uid.rnd();
const identifier = `grp-${selectedGroup}-anc-${randomUid}`;
const res = await publishAnc({
@ -309,13 +324,13 @@ export const GroupAnnouncements = ({
const dataToSaveToStorage = {
name: myName,
identifier,
service: "DOCUMENT",
service: 'DOCUMENT',
tempData: message,
created: Date.now(),
};
await saveTempPublish({
data: dataToSaveToStorage,
key: "announcement",
key: 'announcement',
});
setTempData(selectedGroup);
clearEditorContent();
@ -324,7 +339,7 @@ export const GroupAnnouncements = ({
} catch (error) {
if (!error) return;
setInfoSnack({
type: "error",
type: 'error',
message: error,
});
setOpenSnack(true);
@ -343,9 +358,9 @@ export const GroupAnnouncements = ({
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",
method: 'GET',
headers: {
"Content-Type": "application/json",
'Content-Type': 'application/json',
},
});
const responseData = await response.json();
@ -354,11 +369,14 @@ export const GroupAnnouncements = ({
setAnnouncements(responseData);
setIsLoading(false);
for (const data of responseData) {
getAnnouncementData({
name: data.name,
identifier: data.identifier,
resource: data,
}, isPrivate);
getAnnouncementData(
{
name: data.name,
identifier: data.identifier,
resource: data,
},
isPrivate
);
}
} catch (error) {
} finally {
@ -369,8 +387,13 @@ export const GroupAnnouncements = ({
);
React.useEffect(() => {
if(!secretKey && isPrivate) return
if (selectedGroup && !hasInitialized.current && !hide && isPrivate !== null) {
if (!secretKey && isPrivate) return;
if (
selectedGroup &&
!hasInitialized.current &&
!hide &&
isPrivate !== null
) {
getAnnouncements(selectedGroup, isPrivate);
hasInitialized.current = true;
}
@ -384,9 +407,9 @@ export const GroupAnnouncements = ({
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",
method: 'GET',
headers: {
"Content-Type": "application/json",
'Content-Type': 'application/json',
},
});
const responseData = await response.json();
@ -394,7 +417,10 @@ export const GroupAnnouncements = ({
setAnnouncements((prev) => [...prev, ...responseData]);
setIsLoading(false);
for (const data of responseData) {
getAnnouncementData({ name: data.name, identifier: data.identifier }, isPrivate);
getAnnouncementData(
{ name: data.name, identifier: data.identifier },
isPrivate
);
}
} catch (error) {}
};
@ -406,9 +432,9 @@ export const GroupAnnouncements = ({
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",
method: 'GET',
headers: {
"Content-Type": "application/json",
'Content-Type': 'application/json',
},
});
const responseData = await response.json();
@ -416,10 +442,13 @@ export const GroupAnnouncements = ({
if (!latestMessage) {
for (const data of responseData) {
try {
getAnnouncementData({
name: data.name,
identifier: data.identifier,
}, isPrivate);
getAnnouncementData(
{
name: data.name,
identifier: data.identifier,
},
isPrivate
);
} catch (error) {}
}
setAnnouncements(responseData);
@ -434,7 +463,10 @@ export const GroupAnnouncements = ({
for (const data of newArray) {
try {
getAnnouncementData({ name: data.name, identifier: data.identifier }, isPrivate);
getAnnouncementData(
{ name: data.name, identifier: data.identifier },
isPrivate
);
} catch (error) {}
}
setAnnouncements((prev) => [...newArray, ...prev]);
@ -486,13 +518,15 @@ export const GroupAnnouncements = ({
<div
style={{
// reference to change height
height: isMobile ? `calc(${rootHeight} - 127px` : "calc(100vh - 70px)",
display: "flex",
flexDirection: "column",
width: "100%",
visibility: hide && "hidden",
position: hide && "fixed",
left: hide && "-1000px",
height: isMobile
? `calc(${rootHeight} - 127px`
: 'calc(100vh - 70px)',
display: 'flex',
flexDirection: 'column',
width: '100%',
visibility: hide && 'hidden',
position: hide && 'fixed',
left: hide && '-1000px',
}}
>
<AnnouncementDiscussion
@ -509,63 +543,62 @@ export const GroupAnnouncements = ({
);
}
return (
<div
style={{
// reference to change height
height: isMobile ? `calc(${rootHeight} - 127px` : "calc(100vh - 70px)",
display: "flex",
flexDirection: "column",
width: "100%",
visibility: hide && "hidden",
position: hide && "fixed",
left: hide && "-1000px",
// reference to change height
height: isMobile ? `calc(${rootHeight} - 127px` : 'calc(100vh - 70px)',
display: 'flex',
flexDirection: 'column',
width: '100%',
visibility: hide && 'hidden',
position: hide && 'fixed',
left: hide && '-1000px',
}}
>
<div
style={{
position: "relative",
width: "100%",
display: "flex",
flexDirection: "column",
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",
width: '100%',
display: 'flex',
justifyContent: 'center',
padding: isMobile ? '8px' : '25px',
fontSize: isMobile ? '16px' : '20px',
gap: '20px',
alignItems: 'center',
}}
>
<CampaignIcon
sx={{
fontSize: isMobile ? "16px" : "30px",
fontSize: isMobile ? '16px' : '30px',
}}
/>
Group Announcements
</Box>
)}
<Spacer height={isMobile ? "0px" : "25px"} />
<Spacer height={isMobile ? '0px' : '25px'} />
</div>
{!isLoading && combinedListTempAndReal?.length === 0 && (
<Box
sx={{
width: "100%",
display: "flex",
justifyContent: "center",
width: '100%',
display: 'flex',
justifyContent: 'center',
}}
>
<Typography
sx={{
fontSize: "16px",
fontSize: '16px',
}}
>
No announcements
@ -589,28 +622,28 @@ export const GroupAnnouncements = ({
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",
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",
display: 'flex',
flexDirection: 'column',
flexGrow: isMobile && 1,
overflow: "auto",
overflow: 'auto',
// height: '100%',
}}
>
@ -625,12 +658,12 @@ export const GroupAnnouncements = ({
</div>
<Box
sx={{
display: "flex",
width: "100&",
gap: "10px",
justifyContent: "center",
display: 'flex',
width: '100&',
gap: '10px',
justifyContent: 'center',
flexShrink: 0,
position: "relative",
position: 'relative',
}}
>
{isFocusedParent && (
@ -639,19 +672,19 @@ export const GroupAnnouncements = ({
if (isSending) return;
setIsFocusedParent(false);
clearEditorContent();
setTimeout(() => {
triggerRerender();
}, 300);
setTimeout(() => {
triggerRerender();
}, 300);
// Unfocus the editor
}}
style={{
marginTop: "auto",
alignSelf: "center",
cursor: isSending ? "default" : "pointer",
background: "var(--danger)",
marginTop: 'auto',
alignSelf: 'center',
cursor: isSending ? 'default' : 'pointer',
background: 'var(--danger)',
flexShrink: 0,
padding: isMobile && "5px",
fontSize: isMobile && "14px",
padding: isMobile && '5px',
fontSize: isMobile && '14px',
}}
>
{` Close`}
@ -663,25 +696,25 @@ export const GroupAnnouncements = ({
publishAnnouncement();
}}
style={{
marginTop: "auto",
alignSelf: "center",
cursor: isSending ? "default" : "pointer",
background: isSending && "rgba(0, 0, 0, 0.8)",
marginTop: 'auto',
alignSelf: 'center',
cursor: isSending ? 'default' : 'pointer',
background: isSending && 'rgba(0, 0, 0, 0.8)',
flexShrink: 0,
padding: isMobile && "5px",
fontSize: isMobile && "14px",
padding: isMobile && '5px',
fontSize: isMobile && '14px',
}}
>
{isSending && (
<CircularProgress
size={18}
sx={{
position: "absolute",
top: "50%",
left: "50%",
marginTop: "-12px",
marginLeft: "-12px",
color: "white",
position: 'absolute',
top: '50%',
left: '50%',
marginTop: '-12px',
marginLeft: '-12px',
color: 'white',
}}
/>
)}
@ -701,7 +734,7 @@ export const GroupAnnouncements = ({
<LoadingSnackbar
open={isLoading}
info={{
message: "Loading announcements... please wait.",
message: 'Loading announcements... please wait.',
}}
/>
</div>

View File

@ -6,7 +6,7 @@ import { IconWrapper } from './Desktop/DesktopFooter';
import { useRecoilState } from 'recoil';
import { enabledDevModeAtom } from '../atoms/global';
import { AppsIcon } from '../assets/Icons/AppsIcon';
import ThemeSelector from '../styles/ThemeSelector';
import ThemeSelector from './Theme/ThemeSelector';
export const DesktopSideBar = ({
goToHome,

View File

@ -1,5 +1,5 @@
import React, { useContext, useEffect, useMemo, useState } from "react";
import { subscribeToEvent, unsubscribeFromEvent } from "../../utils/events";
import React, { useContext, useEffect, useMemo, useState } from 'react';
import { subscribeToEvent, unsubscribeFromEvent } from '../../utils/events';
import {
Box,
Button,
@ -9,12 +9,12 @@ import {
DialogActions,
DialogContent,
Typography,
} from "@mui/material";
import { CustomButton, CustomButtonAccept } from "../../App-styles";
import { getBaseApiReact, MyContext } from "../../App";
import { getFee } from "../../background";
import { CustomizedSnackbars } from "../Snackbar/Snackbar";
import { FidgetSpinner } from "react-loader-spinner";
} from '@mui/material';
import { CustomButton, CustomButtonAccept } from '../../styles/App-styles';
import { getBaseApiReact, MyContext } from '../../App';
import { getFee } from '../../background';
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
import { FidgetSpinner } from 'react-loader-spinner';
export const JoinGroup = ({ memberGroups }) => {
const { show, setTxList } = useContext(MyContext);
@ -42,43 +42,45 @@ export const JoinGroup = ({ memberGroups }) => {
};
useEffect(() => {
subscribeToEvent("globalActionJoinGroup", handleJoinGroup);
subscribeToEvent('globalActionJoinGroup', handleJoinGroup);
return () => {
unsubscribeFromEvent("globalActionJoinGroup", handleJoinGroup);
unsubscribeFromEvent('globalActionJoinGroup', handleJoinGroup);
};
}, []);
const isInGroup = useMemo(()=> {
return !!memberGroups.find((item)=> +item?.groupId === +groupInfo?.groupId)
}, [memberGroups, groupInfo])
const isInGroup = useMemo(() => {
return !!memberGroups.find(
(item) => +item?.groupId === +groupInfo?.groupId
);
}, [memberGroups, groupInfo]);
const joinGroup = async (group, isOpen) => {
try {
const groupId = group.groupId;
const fee = await getFee("JOIN_GROUP");
const fee = await getFee('JOIN_GROUP');
await show({
message: "Would you like to perform an JOIN_GROUP transaction?",
publishFee: fee.fee + " QORT",
message: 'Would you like to perform an JOIN_GROUP transaction?',
publishFee: fee.fee + ' QORT',
});
setIsLoadingJoinGroup(true);
await new Promise((res, rej) => {
window
.sendMessage("joinGroup", {
.sendMessage('joinGroup', {
groupId,
})
.then((response) => {
if (!response?.error) {
setInfoSnack({
type: "success",
type: 'success',
message:
"Successfully requested to join group. It may take a couple of minutes for the changes to propagate",
'Successfully requested to join group. It may take a couple of minutes for the changes to propagate',
});
if (isOpen) {
setTxList((prev) => [
{
...response,
type: "joined-group",
type: 'joined-group',
label: `Joined Group ${group?.groupName}: awaiting confirmation`,
labelDone: `Joined Group ${group?.groupName}: success!`,
done: false,
@ -90,7 +92,7 @@ export const JoinGroup = ({ memberGroups }) => {
setTxList((prev) => [
{
...response,
type: "joined-group-request",
type: 'joined-group-request',
label: `Requested to join Group ${group?.groupName}: awaiting confirmation`,
labelDone: `Requested to join Group ${group?.groupName}: success!`,
done: false,
@ -105,7 +107,7 @@ export const JoinGroup = ({ memberGroups }) => {
return;
} else {
setInfoSnack({
type: "error",
type: 'error',
message: response?.error,
});
setOpenSnack(true);
@ -114,8 +116,8 @@ export const JoinGroup = ({ memberGroups }) => {
})
.catch((error) => {
setInfoSnack({
type: "error",
message: error.message || "An error occurred",
type: 'error',
message: error.message || 'An error occurred',
});
setOpenSnack(true);
rej(error);
@ -138,37 +140,37 @@ export const JoinGroup = ({ memberGroups }) => {
{!groupInfo && (
<Box
sx={{
width: "325px",
height: "150px",
display: "flex",
alignItems: "center",
justifyContent: "center",
width: '325px',
height: '150px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
{" "}
{' '}
<CircularProgress
size={25}
sx={{
color: "white",
color: 'white',
}}
/>{" "}
/>{' '}
</Box>
)}
<Box
sx={{
width: "325px",
height: "auto",
maxHeight: "400px",
display: !groupInfo ? "none" : "flex",
flexDirection: "column",
alignItems: "center",
gap: "10px",
padding: "10px",
width: '325px',
height: 'auto',
maxHeight: '400px',
display: !groupInfo ? 'none' : 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: '10px',
padding: '10px',
}}
>
<Typography
sx={{
fontSize: "15px",
fontSize: '15px',
fontWeight: 600,
}}
>
@ -176,7 +178,7 @@ export const JoinGroup = ({ memberGroups }) => {
</Typography>
<Typography
sx={{
fontSize: "15px",
fontSize: '15px',
fontWeight: 600,
}}
>
@ -185,7 +187,7 @@ export const JoinGroup = ({ memberGroups }) => {
{groupInfo?.description && (
<Typography
sx={{
fontSize: "15px",
fontSize: '15px',
fontWeight: 600,
}}
>
@ -193,19 +195,19 @@ export const JoinGroup = ({ memberGroups }) => {
</Typography>
)}
{isInGroup && (
<Typography
sx={{
fontSize: "14px",
fontWeight: 600,
}}
>
*You are already in this group!
</Typography>
<Typography
sx={{
fontSize: '14px',
fontWeight: 600,
}}
>
*You are already in this group!
</Typography>
)}
{!isInGroup && groupInfo?.isOpen === false && (
<Typography
sx={{
fontSize: "14px",
fontSize: '14px',
fontWeight: 600,
}}
>
@ -216,32 +218,34 @@ export const JoinGroup = ({ memberGroups }) => {
</Box>
</DialogContent>
<DialogActions>
<ButtonBase onClick={() => {
<ButtonBase
onClick={() => {
joinGroup(groupInfo, groupInfo?.isOpen);
setIsOpen(false);
}} disabled={isInGroup}>
<CustomButtonAccept
color="black"
bgColor="var(--green)"
sx={{
minWidth: "102px",
height: "45px",
fontSize: '16px',
opacity: isInGroup ? 0.1 : 1
}}
disabled={isInGroup}
>
Join
</CustomButtonAccept>
<CustomButtonAccept
color="black"
bgColor="var(--green)"
sx={{
minWidth: '102px',
height: '45px',
fontSize: '16px',
opacity: isInGroup ? 0.1 : 1,
}}
>
Join
</CustomButtonAccept>
</ButtonBase>
<CustomButtonAccept
color="black"
bgColor="var(--danger)"
sx={{
minWidth: "102px",
height: "45px",
minWidth: '102px',
height: '45px',
}}
onClick={() => setIsOpen(false)}
>
@ -259,14 +263,14 @@ export const JoinGroup = ({ memberGroups }) => {
{isLoadingJoinGroup && (
<Box
sx={{
position: "absolute",
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
display: "flex",
justifyContent: "center",
alignItems: "center",
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<FidgetSpinner

File diff suppressed because it is too large Load Diff

View File

@ -13,29 +13,29 @@ import {
InputLabel,
Snackbar,
Typography,
} from "@mui/material";
} from '@mui/material';
import React, {
useCallback,
useContext,
useEffect,
useMemo,
useState,
} from "react";
import CloseIcon from "@mui/icons-material/Close";
import { MyContext, getBaseApiReact } from "../../App";
} from 'react';
import CloseIcon from '@mui/icons-material/Close';
import { MyContext, getBaseApiReact } from '../../App';
import {
executeEvent,
subscribeToEvent,
unsubscribeFromEvent,
} from "../../utils/events";
import { getFee, getNameOrAddress } from "../../background";
import CopyToClipboard from "react-copy-to-clipboard";
import { AddressBox } from "../../App-styles";
import { Spacer } from "../../common/Spacer";
import Copy from "../../assets/svgs/Copy.svg";
import { Loader } from "../Loader";
import { FidgetSpinner } from "react-loader-spinner";
import { useModal } from "../../common/useModal";
} from '../../utils/events';
import { getFee, getNameOrAddress } from '../../background';
import CopyToClipboard from 'react-copy-to-clipboard';
import { AddressBox } from '../../styles/App-styles';
import { Spacer } from '../../common/Spacer';
import Copy from '../../assets/svgs/Copy.svg';
import { Loader } from '../Loader';
import { FidgetSpinner } from 'react-loader-spinner';
import { useModal } from '../../common/useModal';
export const Minting = ({
setIsOpenMinting,
@ -47,30 +47,30 @@ export const Minting = ({
}) => {
const [mintingAccounts, setMintingAccounts] = useState([]);
const [accountInfo, setAccountInfo] = useState(null);
const [rewardSharePublicKey, setRewardSharePublicKey] = useState("");
const [mintingKey, setMintingKey] = useState("");
const [rewardsharekey, setRewardsharekey] = useState("");
const [rewardSharePublicKey, setRewardSharePublicKey] = useState('');
const [mintingKey, setMintingKey] = useState('');
const [rewardsharekey, setRewardsharekey] = useState('');
const [rewardShares, setRewardShares] = useState([]);
const [nodeInfos, setNodeInfos] = useState({});
const [openSnack, setOpenSnack] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const { show: showKey, message } = useModal();
const { isShow: isShowNext, onOk, show: showNext } = useModal();
const { show: showKey, message } = useModal();
const { isShow: isShowNext, onOk, show: showNext } = useModal();
const [info, setInfo] = useState(null);
const [names, setNames] = useState({});
const [accountInfos, setAccountInfos] = useState({});
const [showWaitDialog, setShowWaitDialog] = useState(false)
const [showWaitDialog, setShowWaitDialog] = useState(false);
const isPartOfMintingGroup = useMemo(() => {
if (groups?.length === 0) return false;
return !!groups?.find((item) => item?.groupId?.toString() === "694");
return !!groups?.find((item) => item?.groupId?.toString() === '694');
}, [groups]);
const getMintingAccounts = useCallback(async () => {
try {
const url = `${getBaseApiReact()}/admin/mintingaccounts`;
const response = await fetch(url);
if (!response.ok) {
throw new Error("network error");
throw new Error('network error');
}
const data = await response.json();
setMintingAccounts(data);
@ -117,7 +117,7 @@ export const Minting = ({
const url = `${getBaseApiReact()}/addresses/${address}`;
const response = await fetch(url);
if (!response.ok) {
throw new Error("network error");
throw new Error('network error');
}
const data = await response.json();
if (others) {
@ -144,10 +144,10 @@ export const Minting = ({
};
useEffect(() => {
subscribeToEvent("refresh-rewardshare-list", refreshRewardShare);
subscribeToEvent('refresh-rewardshare-list', refreshRewardShare);
return () => {
unsubscribeFromEvent("refresh-rewardshare-list", refreshRewardShare);
unsubscribeFromEvent('refresh-rewardshare-list', refreshRewardShare);
};
}, [myAddress]);
@ -177,15 +177,15 @@ export const Minting = ({
try {
const url = `${getBaseApiReact()}/admin/status`;
const response = await fetch(url, {
method: "GET",
method: 'GET',
headers: {
"Content-Type": "application/json",
'Content-Type': 'application/json',
},
});
const data = await response.json();
setNodeInfos(data);
} catch (error) {
console.error("Request failed", error);
console.error('Request failed', error);
}
};
@ -194,11 +194,11 @@ export const Minting = ({
const url = `${getBaseApiReact()}/addresses/rewardshares?involving=${address}`;
const response = await fetch(url);
if (!response.ok) {
throw new Error("network error");
throw new Error('network error');
}
const data = await response.json();
setRewardShares(data);
return data
return data;
} catch (error) {}
}, []);
@ -208,10 +208,10 @@ export const Minting = ({
return await new Promise((res, rej) => {
window
.sendMessage(
"ADMIN_ACTION",
'ADMIN_ACTION',
{
type: "addmintingaccount",
type: 'addmintingaccount',
value: val,
},
180000,
@ -220,7 +220,7 @@ export const Minting = ({
.then((response) => {
if (!response?.error) {
res(response);
setMintingKey("");
setMintingKey('');
setTimeout(() => {
getMintingAccounts();
}, 300);
@ -229,13 +229,13 @@ export const Minting = ({
rej({ message: response.error });
})
.catch((error) => {
rej({ message: error.message || "An error occurred" });
rej({ message: error.message || 'An error occurred' });
});
});
} catch (error) {
setInfo({
type: "error",
message: error?.message || "Unable to add minting account",
type: 'error',
message: error?.message || 'Unable to add minting account',
});
setOpenSnack(true);
} finally {
@ -249,10 +249,10 @@ export const Minting = ({
return await new Promise((res, rej) => {
window
.sendMessage(
"ADMIN_ACTION",
'ADMIN_ACTION',
{
type: "removemintingaccount",
type: 'removemintingaccount',
value: val,
},
180000,
@ -270,13 +270,13 @@ export const Minting = ({
rej({ message: response.error });
})
.catch((error) => {
rej({ message: error.message || "An error occurred" });
rej({ message: error.message || 'An error occurred' });
});
});
} catch (error) {
setInfo({
type: "error",
message: error?.message || "Unable to remove minting account",
type: 'error',
message: error?.message || 'Unable to remove minting account',
});
setOpenSnack(true);
} finally {
@ -285,14 +285,14 @@ export const Minting = ({
}, []);
const createRewardShare = useCallback(async (publicKey, recipient) => {
const fee = await getFee("REWARD_SHARE");
const fee = await getFee('REWARD_SHARE');
await show({
message: "Would you like to perform an REWARD_SHARE transaction?",
publishFee: fee.fee + " QORT",
message: 'Would you like to perform an REWARD_SHARE transaction?',
publishFee: fee.fee + ' QORT',
});
return await new Promise((res, rej) => {
window
.sendMessage("createRewardShare", {
.sendMessage('createRewardShare', {
recipientPublicKey: publicKey,
})
.then((response) => {
@ -301,7 +301,7 @@ export const Minting = ({
{
recipient,
...response,
type: "add-rewardShare",
type: 'add-rewardShare',
label: `Add rewardshare: awaiting confirmation`,
labelDone: `Add rewardshare: success!`,
done: false,
@ -314,7 +314,7 @@ export const Minting = ({
rej({ message: response.error });
})
.catch((error) => {
rej({ message: error.message || "An error occurred" });
rej({ message: error.message || 'An error occurred' });
});
});
}, []);
@ -322,7 +322,7 @@ export const Minting = ({
const getRewardSharePrivateKey = useCallback(async (publicKey) => {
return await new Promise((res, rej) => {
window
.sendMessage("getRewardSharePrivateKey", {
.sendMessage('getRewardSharePrivateKey', {
recipientPublicKey: publicKey,
})
.then((response) => {
@ -333,7 +333,7 @@ export const Minting = ({
rej({ message: response.error });
})
.catch((error) => {
rej({ message: error.message || "An error occurred" });
rej({ message: error.message || 'An error occurred' });
});
});
}, []);
@ -341,26 +341,24 @@ export const Minting = ({
const waitUntilRewardShareIsConfirmed = async (timeoutMs = 600000) => {
const pollingInterval = 30000;
const startTime = Date.now();
const sleep = (ms) => new Promise((res) => setTimeout(res, ms));
while (Date.now() - startTime < timeoutMs) {
const rewardShares = await getRewardShares(myAddress);
const findRewardShare = rewardShares?.find(
(item) =>
item?.recipient === myAddress && item?.mintingAccount === myAddress
);
if (findRewardShare) {
return true; // Exit early if found
}
const rewardShares = await getRewardShares(myAddress);
const findRewardShare = rewardShares?.find(
(item) =>
item?.recipient === myAddress && item?.mintingAccount === myAddress
);
if (findRewardShare) {
return true; // Exit early if found
}
await sleep(pollingInterval); // Wait before the next poll
}
throw new Error("Timeout waiting for reward share confirmation");
throw new Error('Timeout waiting for reward share confirmation');
};
const startMinting = async () => {
@ -377,23 +375,22 @@ export const Minting = ({
addMintingAccount(privateRewardShare);
} else {
await createRewardShare(accountInfo?.publicKey, myAddress);
setShowWaitDialog(true)
await waitUntilRewardShareIsConfirmed()
setShowWaitDialog(true);
await waitUntilRewardShareIsConfirmed();
await showNext({
message: ''
})
message: '',
});
const privateRewardShare = await getRewardSharePrivateKey(
accountInfo?.publicKey
);
setShowWaitDialog(false)
setShowWaitDialog(false);
addMintingAccount(privateRewardShare);
}
} catch (error) {
setShowWaitDialog(false)
setShowWaitDialog(false);
setInfo({
type: "error",
message: error?.message || "Unable to start minting",
type: 'error',
message: error?.message || 'Unable to start minting',
});
setOpenSnack(true);
} finally {
@ -412,13 +409,13 @@ export const Minting = ({
const url = `${getBaseApiReact()}/groups/member/${address}`;
const response = await fetch(url);
const data = await response.json();
return !!data?.find((grp) => grp?.groupId?.toString() === "694");
return !!data?.find((grp) => grp?.groupId?.toString() === '694');
};
const removeRewardShare = useCallback(async (rewardShare) => {
return await new Promise((res, rej) => {
window
.sendMessage("removeRewardShare", {
.sendMessage('removeRewardShare', {
rewardShareKeyPairPublicKey: rewardShare.rewardSharePublicKey,
recipient: rewardShare.recipient,
percentageShare: -1,
@ -430,7 +427,7 @@ export const Minting = ({
{
...rewardShare,
...response,
type: "remove-rewardShare",
type: 'remove-rewardShare',
label: `Remove rewardshare: awaiting confirmation`,
labelDone: `Remove rewardshare: success!`,
done: false,
@ -442,7 +439,7 @@ export const Minting = ({
rej({ message: response.error });
})
.catch((error) => {
rej({ message: error.message || "An error occurred" });
rej({ message: error.message || 'An error occurred' });
});
});
}, []);
@ -454,8 +451,8 @@ export const Minting = ({
const privateRewardShare = await removeRewardShare(rewardShare);
} catch (error) {
setInfo({
type: "error",
message: error?.message || "Unable to remove reward share",
type: 'error',
message: error?.message || 'Unable to remove reward share',
});
setOpenSnack(true);
} finally {
@ -468,9 +465,9 @@ export const Minting = ({
setIsLoading(true);
const confirmReceiver = await getNameOrAddress(receiver);
if (confirmReceiver.error)
throw new Error("Invalid receiver address or name");
throw new Error('Invalid receiver address or name');
const isInMinterGroup = await checkIfMinterGroup(confirmReceiver);
if (!isInMinterGroup) throw new Error("Account not in Minter Group");
if (!isInMinterGroup) throw new Error('Account not in Minter Group');
const publicKey = await getPublicKeyFromAddress(confirmReceiver);
const findRewardShare = rewardShares?.find(
(item) =>
@ -487,8 +484,8 @@ export const Minting = ({
}
} catch (error) {
setInfo({
type: "error",
message: error?.message || "Unable to create reward share",
type: 'error',
message: error?.message || 'Unable to create reward share',
});
setOpenSnack(true);
} finally {
@ -550,11 +547,9 @@ export const Minting = ({
(accountInfo?.blocksMinted + accountInfo?.blocksMintedAdjustment);
let countBlocksString = countBlocks.toString();
return "" + countBlocksString;
return '' + countBlocksString;
};
return (
<Dialog
open={true}
@ -562,19 +557,19 @@ export const Minting = ({
fullWidth
fullScreen
sx={{
"& .MuiDialog-paper": {
'& .MuiDialog-paper': {
margin: 0,
maxWidth: "100%",
width: "100%",
height: "100vh",
overflow: "hidden", // Prevent scrollbars
maxWidth: '100%',
width: '100%',
height: '100vh',
overflow: 'hidden', // Prevent scrollbars
},
}}
>
<DialogTitle id="alert-dialog-title">{"Manage your minting"}</DialogTitle>
<DialogTitle id="alert-dialog-title">{'Manage your minting'}</DialogTitle>
<IconButton
sx={{
position: "absolute",
position: 'absolute',
right: 8,
top: 8,
}}
@ -586,20 +581,20 @@ export const Minting = ({
</IconButton>
<DialogContent
sx={{
position: "relative",
position: 'relative',
}}
>
{isLoading && (
<Box
sx={{
position: "absolute",
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
display: "flex",
justifyContent: "center",
alignItems: "center",
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<FidgetSpinner
@ -614,8 +609,8 @@ export const Minting = ({
)}
<Card
sx={{
backgroundColor: "var(--bg-2)",
padding: "10px",
backgroundColor: 'var(--bg-2)',
padding: '10px',
}}
>
<Typography>Account: {handleNames(accountInfo?.address)}</Typography>
@ -631,11 +626,11 @@ export const Minting = ({
{isPartOfMintingGroup && !accountIsMinting && (
<Box
sx={{
display: "flex",
gap: "5px",
flexDirection: "column",
width: "100%",
alignItems: "center",
display: 'flex',
gap: '5px',
flexDirection: 'column',
width: '100%',
alignItems: 'center',
}}
>
<Button
@ -645,15 +640,15 @@ export const Minting = ({
}}
disabled={mintingAccounts?.length > 1}
sx={{
backgroundColor: "var(--green)",
color: "black",
fontWeight: "bold",
backgroundColor: 'var(--green)',
color: 'black',
fontWeight: 'bold',
opacity: 0.7,
maxWidth: "90%",
width: "200px",
"&:hover": {
backgroundColor: "var(--green)",
color: "black",
maxWidth: '90%',
width: '200px',
'&:hover': {
backgroundColor: 'var(--green)',
color: 'black',
opacity: 1,
},
}}
@ -675,16 +670,16 @@ export const Minting = ({
)}
<Card
sx={{
backgroundColor: "var(--bg-2)",
padding: "10px",
backgroundColor: 'var(--bg-2)',
padding: '10px',
}}
>
{accountIsMinting && (
<Box
sx={{
display: "flex",
gap: "5px",
flexDirection: "column",
display: 'flex',
gap: '5px',
flexDirection: 'column',
}}
>
<Typography>
@ -698,9 +693,9 @@ export const Minting = ({
<Box
key={acct?.mintingAccount}
sx={{
display: "flex",
gap: "10px",
flexDirection: "column",
display: 'flex',
gap: '10px',
flexDirection: 'column',
}}
>
<Typography>
@ -709,15 +704,15 @@ export const Minting = ({
<Button
size="small"
sx={{
backgroundColor: "var(--danger)",
color: "black",
fontWeight: "bold",
backgroundColor: 'var(--danger)',
color: 'black',
fontWeight: 'bold',
opacity: 0.7,
maxWidth: "90%",
width: "200px",
"&:hover": {
backgroundColor: "var(--danger)",
color: "black",
maxWidth: '90%',
width: '200px',
'&:hover': {
backgroundColor: 'var(--danger)',
color: 'black',
opacity: 1,
},
}}
@ -745,17 +740,17 @@ export const Minting = ({
{!isPartOfMintingGroup && (
<Card
sx={{
backgroundColor: "var(--bg-2)",
padding: "10px",
backgroundColor: 'var(--bg-2)',
padding: '10px',
}}
>
<Box
sx={{
display: "flex",
gap: "5px",
flexDirection: "column",
width: "100%",
alignItems: "center",
display: 'flex',
gap: '5px',
flexDirection: 'column',
width: '100%',
alignItems: 'center',
}}
>
<Typography>
@ -768,22 +763,22 @@ export const Minting = ({
<Button
size="small"
sx={{
backgroundColor: "var(--green)",
color: "black",
fontWeight: "bold",
backgroundColor: 'var(--green)',
color: 'black',
fontWeight: 'bold',
opacity: 0.7,
"&:hover": {
backgroundColor: "var(--green)",
color: "black",
'&:hover': {
backgroundColor: 'var(--green)',
color: 'black',
opacity: 1,
},
}}
onClick={() => {
executeEvent("addTab", {
data: { service: "APP", name: "q-mintership" },
executeEvent('addTab', {
data: { service: 'APP', name: 'q-mintership' },
});
executeEvent("open-apps-mode", {});
executeEvent('open-apps-mode', {});
setIsOpenMinting(false);
}}
variant="contained"
@ -801,29 +796,32 @@ export const Minting = ({
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">
{isShowNext ? "Confirmed" : "Please Wait"}
{isShowNext ? 'Confirmed' : 'Please Wait'}
</DialogTitle>
<DialogContent>
{!isShowNext && (
<Typography>
Confirming creation of rewardshare on chain. Please be patient, this could take up to 90 seconds.
</Typography>
Confirming creation of rewardshare on chain. Please be
patient, this could take up to 90 seconds.
</Typography>
)}
{isShowNext && (
<Typography>
Rewardshare confirmed. Please click Next.
</Typography>
Rewardshare confirmed. Please click Next.
</Typography>
)}
</DialogContent>
<DialogActions>
<Button disabled={!isShowNext} variant="contained" onClick={onOk} autoFocus>
<DialogActions>
<Button
disabled={!isShowNext}
variant="contained"
onClick={onOk}
autoFocus
>
Next
</Button>
</DialogActions>
</Dialog>
)}
</DialogContent>
@ -837,7 +835,7 @@ export const Minting = ({
</Button>
</DialogActions>
<Snackbar
anchorOrigin={{ vertical: "bottom", horizontal: "center" }}
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
open={openSnack}
autoHideDuration={6000}
onClose={handleClose}
@ -846,7 +844,7 @@ export const Minting = ({
onClose={handleClose}
severity={info?.type}
variant="filled"
sx={{ width: "100%" }}
sx={{ width: '100%' }}
>
{info?.message}
</Alert>

View File

@ -1,167 +1,170 @@
import { Box, CircularProgress } from '@mui/material';
import React, { useEffect, useState } from 'react'
import { CustomButton, CustomInput, CustomLabel, TextP } from '../App-styles';
import React, { useEffect, useState } from 'react';
import {
CustomButton,
CustomInput,
CustomLabel,
TextP,
} from '../styles/App-styles';
import { Spacer } from '../common/Spacer';
import BoundedNumericTextField from '../common/BoundedNumericTextField';
import { PasswordField } from './PasswordField/PasswordField';
import { ErrorText } from './ErrorText/ErrorText';
import { getFee } from '../background';
export const QortPayment = ({balance, show, onSuccess, defaultPaymentTo}) => {
const [paymentTo, setPaymentTo] = useState<string>(defaultPaymentTo);
const [paymentAmount, setPaymentAmount] = useState<number>(0);
const [paymentPassword, setPaymentPassword] = useState<string>("");
const [sendPaymentError, setSendPaymentError] = useState<string>("");
const [sendPaymentSuccess, setSendPaymentSuccess] = useState<string>("");
const [isLoadingSendCoin, setIsLoadingSendCoin] = useState<boolean>(false);
export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => {
const [paymentTo, setPaymentTo] = useState<string>(defaultPaymentTo);
const [paymentAmount, setPaymentAmount] = useState<number>(0);
const [paymentPassword, setPaymentPassword] = useState<string>('');
const [sendPaymentError, setSendPaymentError] = useState<string>('');
const [sendPaymentSuccess, setSendPaymentSuccess] = useState<string>('');
const [isLoadingSendCoin, setIsLoadingSendCoin] = useState<boolean>(false);
const sendCoinFunc = async () => {
try {
setSendPaymentError('');
setSendPaymentSuccess('');
if (!paymentTo) {
setSendPaymentError('Please enter a recipient');
return;
}
if (!paymentAmount) {
setSendPaymentError('Please enter an amount greater than 0');
return;
}
if (!paymentPassword) {
setSendPaymentError('Please enter your wallet password');
return;
}
const fee = await getFee('PAYMENT');
const sendCoinFunc = async() => {
try {
setSendPaymentError("");
setSendPaymentSuccess("");
if (!paymentTo) {
setSendPaymentError("Please enter a recipient");
return;
await show({
message: `Would you like to transfer ${Number(paymentAmount)} QORT?`,
paymentFee: fee.fee + ' QORT',
});
setIsLoadingSendCoin(true);
window
.sendMessage('sendCoin', {
amount: Number(paymentAmount),
receiver: paymentTo.trim(),
password: paymentPassword,
})
.then((response) => {
if (response?.error) {
setSendPaymentError(response.error);
} else {
onSuccess();
}
if (!paymentAmount) {
setSendPaymentError("Please enter an amount greater than 0");
return;
}
if (!paymentPassword) {
setSendPaymentError("Please enter your wallet password");
return;
}
const fee = await getFee('PAYMENT')
await show({
message: `Would you like to transfer ${Number(paymentAmount)} QORT?` ,
paymentFee: fee.fee + ' QORT'
})
setIsLoadingSendCoin(true);
window
.sendMessage("sendCoin", {
amount: Number(paymentAmount),
receiver: paymentTo.trim(),
password: paymentPassword,
})
.then((response) => {
if (response?.error) {
setSendPaymentError(response.error);
} else {
onSuccess()
}
setIsLoadingSendCoin(false);
})
.catch((error) => {
console.error("Failed to send coin:", error);
setIsLoadingSendCoin(false);
});
} catch (error) {
// error
}
};
setIsLoadingSendCoin(false);
})
.catch((error) => {
console.error('Failed to send coin:', error);
setIsLoadingSendCoin(false);
});
} catch (error) {
// error
}
};
return (
<>
<Box
sx={{
display: "flex",
flexDirection: "column",
alignItems: "flex-start",
}}
>
<TextP
sx={{
textAlign: "start",
lineHeight: "24px",
fontSize: "20px",
fontWeight: 600,
}}
>
Transfer QORT
</TextP>
<Spacer height="35px" />
<TextP
sx={{
textAlign: "start",
lineHeight: "16px",
fontSize: "20px",
fontWeight: 600,
color: "rgba(255, 255, 255, 0.5)",
}}
>
Balance:
</TextP>
<TextP
sx={{
textAlign: "start",
lineHeight: "24px",
fontSize: "20px",
fontWeight: 700,
}}
>
{balance?.toFixed(2)} QORT
</TextP>
</Box>
<Spacer height="35px" />
sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-start',
}}
>
<TextP
sx={{
textAlign: 'start',
lineHeight: '24px',
fontSize: '20px',
fontWeight: 600,
}}
>
Transfer QORT
</TextP>
<Spacer height="35px" />
<TextP
sx={{
textAlign: 'start',
lineHeight: '16px',
fontSize: '20px',
fontWeight: 600,
color: 'rgba(255, 255, 255, 0.5)',
}}
>
Balance:
</TextP>
<TextP
sx={{
textAlign: 'start',
lineHeight: '24px',
fontSize: '20px',
fontWeight: 700,
}}
>
{balance?.toFixed(2)} QORT
</TextP>
</Box>
<Spacer height="35px" />
<Box>
<CustomLabel htmlFor="standard-adornment-name">To</CustomLabel>
<Spacer height="5px" />
<CustomInput
id="standard-adornment-name"
value={paymentTo}
onChange={(e) => setPaymentTo(e.target.value)}
autoComplete="off"
/>
<Spacer height="6px" />
<CustomLabel htmlFor="standard-adornment-amount">
Amount
</CustomLabel>
<Spacer height="5px" />
<BoundedNumericTextField
value={paymentAmount}
minValue={0}
maxValue={+balance}
allowDecimals={true}
initialValue={'0'}
allowNegatives={false}
afterChange={(e: string) => setPaymentAmount(+e)}
/>
<Spacer height="6px" />
<CustomLabel htmlFor="standard-adornment-password">
Confirm Wallet Password
</CustomLabel>
<Spacer height="5px" />
<PasswordField
id="standard-adornment-password"
value={paymentPassword}
onChange={(e) => setPaymentPassword(e.target.value)}
autoComplete="off"
/>
</Box>
<Spacer height="10px" />
<ErrorText>{sendPaymentError}</ErrorText>
{/* <Typography>{sendPaymentSuccess}</Typography> */}
<Spacer height="25px" />
<CustomButton
<Box>
<CustomLabel htmlFor="standard-adornment-name">To</CustomLabel>
<Spacer height="5px" />
<CustomInput
id="standard-adornment-name"
value={paymentTo}
onChange={(e) => setPaymentTo(e.target.value)}
autoComplete="off"
/>
<Spacer height="6px" />
<CustomLabel htmlFor="standard-adornment-amount">Amount</CustomLabel>
<Spacer height="5px" />
<BoundedNumericTextField
value={paymentAmount}
minValue={0}
maxValue={+balance}
allowDecimals={true}
initialValue={'0'}
allowNegatives={false}
afterChange={(e: string) => setPaymentAmount(+e)}
/>
<Spacer height="6px" />
<CustomLabel htmlFor="standard-adornment-password">
Confirm Wallet Password
</CustomLabel>
<Spacer height="5px" />
<PasswordField
id="standard-adornment-password"
value={paymentPassword}
onChange={(e) => setPaymentPassword(e.target.value)}
autoComplete="off"
/>
</Box>
<Spacer height="10px" />
<ErrorText>{sendPaymentError}</ErrorText>
{/* <Typography>{sendPaymentSuccess}</Typography> */}
<Spacer height="25px" />
<CustomButton
sx={{
cursor: isLoadingSendCoin ? 'default' : 'pointer',
}}
onClick={() => {
if (isLoadingSendCoin) return;
sendCoinFunc();
}}
>
{isLoadingSendCoin && (
<CircularProgress
size={16}
sx={{
cursor: isLoadingSendCoin ? 'default' : 'pointer'
color: 'white',
}}
onClick={() => {
if(isLoadingSendCoin) return
sendCoinFunc();
}}
>
{isLoadingSendCoin && (
<CircularProgress size={16} sx={{
color: 'white'
}} />
)}
Send
</CustomButton>
/>
)}
Send
</CustomButton>
</>
)
}
);
};

View File

@ -0,0 +1,29 @@
import { createContext, useContext, useState, useMemo } from 'react';
import { ThemeProvider as MuiThemeProvider } from '@mui/material/styles';
import { darkTheme, lightTheme } from '../../styles/theme';
const ThemeContext = createContext({
themeMode: 'light',
toggleTheme: () => {},
});
export const ThemeProvider = ({ children }: { children: React.ReactNode }) => {
const [themeMode, setThemeMode] = useState('light');
const theme = useMemo(
() => (themeMode === 'light' ? lightTheme : darkTheme),
[themeMode]
);
const toggleTheme = () => {
setThemeMode((prevMode) => (prevMode === 'light' ? 'dark' : 'light'));
};
return (
<ThemeContext.Provider value={{ themeMode, toggleTheme }}>
<MuiThemeProvider theme={theme}>{children}</MuiThemeProvider>
</ThemeContext.Provider>
);
};
export const useThemeContext = () => useContext(ThemeContext);

View File

@ -0,0 +1,77 @@
import { useThemeContext } from "./ThemeContext";
import { styled, Switch } from "@mui/material";
const ThemeSwitch = styled(Switch)(({ theme }) => ({
width: 62,
height: 34,
padding: 7,
"& .MuiSwitch-switchBase": {
margin: 1,
padding: 0,
transform: "translateX(6px)",
"&.Mui-checked": {
color: "#fff",
transform: "translateX(22px)",
"& .MuiSwitch-thumb:before": {
backgroundImage: `url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="20" width="20" viewBox="0 0 20 20"><path fill="${encodeURIComponent(
"#fff"
)}" d="M4.2 2.5l-.7 1.8-1.8.7 1.8.7.7 1.8.6-1.8L6.7 5l-1.9-.7-.6-1.8zm15 8.3a6.7 6.7 0 11-6.6-6.6 5.8 5.8 0 006.6 6.6z"/></svg>')`,
},
"& + .MuiSwitch-track": {
opacity: 1,
backgroundColor: "#aab4be",
...theme.applyStyles("dark", {
backgroundColor: "#8796A5",
}),
},
},
},
"& .MuiSwitch-thumb": {
backgroundColor: "#001e3c",
width: 32,
height: 32,
"&::before": {
content: "''",
position: "absolute",
width: "100%",
height: "100%",
left: 0,
top: 0,
backgroundRepeat: "no-repeat",
backgroundPosition: "center",
backgroundImage: `url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="20" width="20" viewBox="0 0 20 20"><path fill="${encodeURIComponent(
"#fff"
)}" d="M9.305 1.667V3.75h1.389V1.667h-1.39zm-4.707 1.95l-.982.982L5.09 6.072l.982-.982-1.473-1.473zm10.802 0L13.927 5.09l.982.982 1.473-1.473-.982-.982zM10 5.139a4.872 4.872 0 00-4.862 4.86A4.872 4.872 0 0010 14.862 4.872 4.872 0 0014.86 10 4.872 4.872 0 0010 5.139zm0 1.389A3.462 3.462 0 0113.471 10a3.462 3.462 0 01-3.473 3.472A3.462 3.462 0 016.527 10 3.462 3.462 0 0110 6.528zM1.665 9.305v1.39h2.083v-1.39H1.666zm14.583 0v1.39h2.084v-1.39h-2.084zM5.09 13.928L3.616 15.4l.982.982 1.473-1.473-.982-.982zm9.82 0l-.982.982 1.473 1.473.982-.982-1.473-1.473zM9.305 16.25v2.083h1.389V16.25h-1.39z"/></svg>')`,
},
...theme.applyStyles("dark", {
backgroundColor: "#003892",
}),
},
"& .MuiSwitch-track": {
opacity: 1,
backgroundColor: "#aab4be",
borderRadius: 20 / 2,
...theme.applyStyles("dark", {
backgroundColor: "#8796A5",
}),
},
}));
const ThemeSelector = ({ style }) => {
const { themeMode, toggleTheme } = useThemeContext();
return (
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "center",
gap: "1px",
...style,
}}
>
<ThemeSwitch checked={themeMode === "dark"} onChange={toggleTheme} />
</div>
);
};
export default ThemeSelector;