mirror of
https://github.com/Qortal/Qortal-Hub.git
synced 2025-06-06 16:36:58 +00:00
Format code, rmove unused
This commit is contained in:
parent
4f9b8fe6cc
commit
2a41667ef8
@ -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',
|
||||
|
@ -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"
|
||||
|
@ -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,
|
||||
}}
|
||||
>
|
||||
|
@ -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,
|
||||
|
@ -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>
|
||||
|
@ -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
@ -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>
|
||||
|
@ -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,
|
||||
|
@ -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
@ -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>
|
||||
|
@ -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>
|
||||
</>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
29
src/components/Theme/ThemeContext.tsx
Normal file
29
src/components/Theme/ThemeContext.tsx
Normal 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);
|
77
src/components/Theme/ThemeSelector.tsx
Normal file
77
src/components/Theme/ThemeSelector.tsx
Normal 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;
|
Loading…
x
Reference in New Issue
Block a user