mirror of
https://github.com/Qortal/Qortal-Hub.git
synced 2025-06-24 00:21:22 +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,24 +1,24 @@
|
||||
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);
|
||||
@ -30,28 +30,28 @@ export const AddressQRCode = ({ targetAddress }) => {
|
||||
{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,16 +37,16 @@ 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;
|
||||
@ -44,7 +58,7 @@ export const AnnouncementDiscussion = ({
|
||||
if (isMobile) {
|
||||
setTimeout(() => {
|
||||
editorRef.current?.chain().blur().run();
|
||||
setIsFocusedParent(false)
|
||||
setIsFocusedParent(false);
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
@ -52,13 +66,15 @@ 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) => {
|
||||
@ -67,7 +83,6 @@ export const AnnouncementDiscussion = ({
|
||||
[`${identifier}-${name}`]: messageData,
|
||||
};
|
||||
});
|
||||
|
||||
} catch (error) {}
|
||||
};
|
||||
|
||||
@ -76,7 +91,8 @@ export const AnnouncementDiscussion = ({
|
||||
if (!selectedAnnouncement) return;
|
||||
|
||||
return new Promise((res, rej) => {
|
||||
window.sendMessage("publishGroupEncryptedResource", {
|
||||
window
|
||||
.sendMessage('publishGroupEncryptedResource', {
|
||||
encryptedData,
|
||||
identifier,
|
||||
})
|
||||
@ -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 () => {
|
||||
try {
|
||||
const getTempAnnouncements = await getTempPublish()
|
||||
const getTempAnnouncements = await getTempPublish();
|
||||
if (getTempAnnouncements[tempKey]) {
|
||||
let tempData = []
|
||||
let tempData = [];
|
||||
Object.keys(getTempAnnouncements[tempKey] || {}).map((key) => {
|
||||
const value = getTempAnnouncements[tempKey][key]
|
||||
const value = getTempAnnouncements[tempKey][key];
|
||||
if (value.data?.announcementId === selectedAnnouncement.identifier) {
|
||||
tempData.push(value.data)
|
||||
tempData.push(value.data);
|
||||
}
|
||||
})
|
||||
setTempPublishedList(tempData)
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
setTempPublishedList(tempData);
|
||||
}
|
||||
} 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 secretKeyObject =
|
||||
isPrivate === false ? null : await getSecretKey(false, true);
|
||||
const message64: any = await objectToBase64(message);
|
||||
|
||||
const encryptSingle = isPrivate === false ? message64 : await encryptChatMessage(
|
||||
message64,
|
||||
secretKeyObject
|
||||
);
|
||||
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,10 +166,10 @@ 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();
|
||||
}
|
||||
@ -164,7 +177,7 @@ export const AnnouncementDiscussion = ({
|
||||
} 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) {
|
||||
@ -207,13 +219,13 @@ export const AnnouncementDiscussion = ({
|
||||
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",
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
const responseData = await response.json();
|
||||
@ -223,11 +235,8 @@ export const AnnouncementDiscussion = ({
|
||||
for (const data of responseData) {
|
||||
getData({ name: data.name, identifier: data.identifier }, isPrivate);
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
} catch (error) {}
|
||||
};
|
||||
|
||||
const combinedListTempAndReal = useMemo(() => {
|
||||
// Combine the two lists
|
||||
@ -235,49 +244,56 @@ export const AnnouncementDiscussion = ({
|
||||
|
||||
// Remove duplicates based on the "identifier"
|
||||
const uniqueItems = new Map();
|
||||
combined.forEach(item => {
|
||||
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",
|
||||
<div
|
||||
style={{
|
||||
position: 'relative',
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
flexShrink: 0,
|
||||
}}>
|
||||
|
||||
<AuthenticatedContainerInnerTop sx={{
|
||||
height: '20px'
|
||||
}}>
|
||||
<ArrowBackIcon onClick={()=> setSelectedAnnouncement(null)} sx={{
|
||||
cursor: 'pointer'
|
||||
}} />
|
||||
}}
|
||||
>
|
||||
<AuthenticatedContainerInnerTop
|
||||
sx={{
|
||||
height: '20px',
|
||||
}}
|
||||
>
|
||||
<ArrowBackIcon
|
||||
onClick={() => setSelectedAnnouncement(null)}
|
||||
sx={{
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
/>
|
||||
</AuthenticatedContainerInnerTop>
|
||||
<Spacer height="20px" />
|
||||
|
||||
</div>
|
||||
<AnnouncementList
|
||||
announcementData={data}
|
||||
@ -287,21 +303,20 @@ export const AnnouncementDiscussion = ({
|
||||
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',
|
||||
@ -311,11 +326,11 @@ export const AnnouncementDiscussion = ({
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
// height: '100%',
|
||||
flexGrow: isMobile && 1,
|
||||
overflow: "auto",
|
||||
overflow: 'auto',
|
||||
}}
|
||||
>
|
||||
<TipTap
|
||||
@ -323,24 +338,26 @@ export const AnnouncementDiscussion = ({
|
||||
onEnter={publishComment}
|
||||
disableEnter
|
||||
maxHeightOffset="60px"
|
||||
isFocusedParent={isFocusedParent} setIsFocusedParent={setIsFocusedParent}
|
||||
|
||||
isFocusedParent={isFocusedParent}
|
||||
setIsFocusedParent={setIsFocusedParent}
|
||||
/>
|
||||
</div>
|
||||
<Box sx={{
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
width: '100&',
|
||||
gap: '10px',
|
||||
justifyContent: 'center',
|
||||
flexShrink: 0,
|
||||
position: 'relative',
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
{isFocusedParent && (
|
||||
<CustomButton
|
||||
onClick={() => {
|
||||
if(isSending) return
|
||||
setIsFocusedParent(false)
|
||||
clearEditorContent()
|
||||
if (isSending) return;
|
||||
setIsFocusedParent(false);
|
||||
clearEditorContent();
|
||||
// Unfocus the editor
|
||||
}}
|
||||
style={{
|
||||
@ -353,10 +370,8 @@ export const AnnouncementDiscussion = ({
|
||||
background: 'red',
|
||||
}}
|
||||
>
|
||||
|
||||
{` Close`}
|
||||
</CustomButton>
|
||||
|
||||
)}
|
||||
<CustomButton
|
||||
onClick={() => {
|
||||
@ -364,38 +379,37 @@ export const AnnouncementDiscussion = ({
|
||||
publishComment();
|
||||
}}
|
||||
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'
|
||||
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',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{` 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",
|
||||
marginBottom: '10px',
|
||||
width: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<AnnouncementItem myName={myName} disableComment={disableComment} setSelectedAnnouncement={setSelectedAnnouncement} message={message} messageData={messageData} />
|
||||
<AnnouncementItem
|
||||
myName={myName}
|
||||
disableComment={disableComment}
|
||||
setSelectedAnnouncement={setSelectedAnnouncement}
|
||||
message={message}
|
||||
messageData={messageData}
|
||||
/>
|
||||
</div>
|
||||
|
||||
);
|
||||
})}
|
||||
{/* <AutoSizer>
|
||||
@ -83,14 +87,18 @@ export const AnnouncementList = ({
|
||||
/>
|
||||
)}
|
||||
</AutoSizer> */}
|
||||
<Box sx={{
|
||||
<Box
|
||||
sx={{
|
||||
width: '100%',
|
||||
marginTop: '25px',
|
||||
display: 'flex',
|
||||
justifyContent: 'center'
|
||||
}}>
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
{showLoadMore && (
|
||||
<CustomButton onClick={loadMore}>Load older announcements</CustomButton>
|
||||
<CustomButton onClick={loadMore}>
|
||||
Load older announcements
|
||||
</CustomButton>
|
||||
)}
|
||||
</Box>
|
||||
</div>
|
||||
|
@ -1,52 +1,78 @@
|
||||
import React, { useCallback, useEffect, useMemo, useReducer, useRef, useState } from 'react'
|
||||
import React, {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useReducer,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
import { objectToBase64 } from '../../qdn/encryption/group-encryption'
|
||||
import { ChatList } from './ChatList'
|
||||
import "@chatscope/chat-ui-kit-styles/dist/default/styles.min.css";
|
||||
import Tiptap from './TipTap'
|
||||
import { CustomButton } from '../../App-styles'
|
||||
import { objectToBase64 } from '../../qdn/encryption/group-encryption';
|
||||
import { ChatList } from './ChatList';
|
||||
import '@chatscope/chat-ui-kit-styles/dist/default/styles.min.css';
|
||||
import Tiptap from './TipTap';
|
||||
import { CustomButton } from '../../styles/App-styles';
|
||||
import CircularProgress from '@mui/material/CircularProgress';
|
||||
import { Box, ButtonBase, Input, Typography } from '@mui/material';
|
||||
import { LoadingSnackbar } from '../Snackbar/LoadingSnackbar';
|
||||
import { getNameInfo } from '../Group/Group';
|
||||
import { Spacer } from '../../common/Spacer';
|
||||
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
|
||||
import { getBaseApiReact, getBaseApiReactSocket, isMobile, pauseAllQueues, resumeAllQueues } from '../../App';
|
||||
import {
|
||||
getBaseApiReact,
|
||||
getBaseApiReactSocket,
|
||||
isMobile,
|
||||
pauseAllQueues,
|
||||
resumeAllQueues,
|
||||
} from '../../App';
|
||||
import { getPublicKey } from '../../background';
|
||||
import { useMessageQueue } from '../../MessageQueueContext';
|
||||
import { executeEvent, subscribeToEvent, unsubscribeFromEvent } from '../../utils/events';
|
||||
import {
|
||||
executeEvent,
|
||||
subscribeToEvent,
|
||||
unsubscribeFromEvent,
|
||||
} from '../../utils/events';
|
||||
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
||||
import ShortUniqueId from "short-unique-id";
|
||||
import ShortUniqueId from 'short-unique-id';
|
||||
import { ReturnIcon } from '../../assets/Icons/ReturnIcon';
|
||||
import { ExitIcon } from '../../assets/Icons/ExitIcon';
|
||||
import { MessageItem, ReplyPreview } from './MessageItem';
|
||||
|
||||
|
||||
const uid = new ShortUniqueId({ length: 5 });
|
||||
|
||||
|
||||
export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDirect, setNewChat, getTimestampEnterChat, myName, balance, close, setMobileViewModeKeepOpen}) => {
|
||||
export const ChatDirect = ({
|
||||
myAddress,
|
||||
isNewChat,
|
||||
selectedDirect,
|
||||
setSelectedDirect,
|
||||
setNewChat,
|
||||
getTimestampEnterChat,
|
||||
myName,
|
||||
balance,
|
||||
close,
|
||||
setMobileViewModeKeepOpen,
|
||||
}) => {
|
||||
const { queueChats, addToQueue, processWithNewMessages } = useMessageQueue();
|
||||
const [isFocusedParent, setIsFocusedParent] = useState(false);
|
||||
const [onEditMessage, setOnEditMessage] = useState(null)
|
||||
const [onEditMessage, setOnEditMessage] = useState(null);
|
||||
|
||||
const [messages, setMessages] = useState([])
|
||||
const [isSending, setIsSending] = useState(false)
|
||||
const [directToValue, setDirectToValue] = useState('')
|
||||
const hasInitialized = useRef(false)
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [messages, setMessages] = useState([]);
|
||||
const [isSending, setIsSending] = useState(false);
|
||||
const [directToValue, setDirectToValue] = useState('');
|
||||
const hasInitialized = useRef(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [openSnack, setOpenSnack] = React.useState(false);
|
||||
const [infoSnack, setInfoSnack] = React.useState(null);
|
||||
const [publicKeyOfRecipient, setPublicKeyOfRecipient] = React.useState("")
|
||||
const hasInitializedWebsocket = useRef(false)
|
||||
const [chatReferences, setChatReferences] = useState({})
|
||||
const [publicKeyOfRecipient, setPublicKeyOfRecipient] = React.useState('');
|
||||
const hasInitializedWebsocket = useRef(false);
|
||||
const [chatReferences, setChatReferences] = useState({});
|
||||
|
||||
const editorRef = useRef(null);
|
||||
const socketRef = useRef(null);
|
||||
const timeoutIdRef = useRef(null);
|
||||
const [messageSize, setMessageSize] = useState(0)
|
||||
const [messageSize, setMessageSize] = useState(0);
|
||||
const groupSocketTimeoutRef = useRef(null);
|
||||
const [replyMessage, setReplyMessage] = useState(null)
|
||||
const [replyMessage, setReplyMessage] = useState(null);
|
||||
const setEditorRef = (editorInstance) => {
|
||||
editorRef.current = editorInstance;
|
||||
};
|
||||
@ -55,42 +81,47 @@ export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDi
|
||||
const triggerRerender = () => {
|
||||
forceUpdate(); // Trigger re-render by updating the state
|
||||
};
|
||||
const publicKeyOfRecipientRef = useRef(null)
|
||||
const publicKeyOfRecipientRef = useRef(null);
|
||||
const getPublicKeyFunc = async (address) => {
|
||||
try {
|
||||
const publicKey = await getPublicKey(address)
|
||||
if(publicKeyOfRecipientRef.current !== selectedDirect?.address) return
|
||||
setPublicKeyOfRecipient(publicKey)
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
}
|
||||
const publicKey = await getPublicKey(address);
|
||||
if (publicKeyOfRecipientRef.current !== selectedDirect?.address) return;
|
||||
setPublicKeyOfRecipient(publicKey);
|
||||
} catch (error) {}
|
||||
};
|
||||
|
||||
const tempMessages = useMemo(() => {
|
||||
if(!selectedDirect?.address) return []
|
||||
if (!selectedDirect?.address) return [];
|
||||
if (queueChats[selectedDirect?.address]) {
|
||||
return queueChats[selectedDirect?.address]?.filter((item)=> !item?.chatReference)
|
||||
return queueChats[selectedDirect?.address]?.filter(
|
||||
(item) => !item?.chatReference
|
||||
);
|
||||
}
|
||||
return []
|
||||
}, [selectedDirect?.address, queueChats])
|
||||
return [];
|
||||
}, [selectedDirect?.address, queueChats]);
|
||||
|
||||
const tempChatReferences = useMemo(() => {
|
||||
if(!selectedDirect?.address) return []
|
||||
if (!selectedDirect?.address) return [];
|
||||
if (queueChats[selectedDirect?.address]) {
|
||||
return queueChats[selectedDirect?.address]?.filter((item)=> !!item?.chatReference)
|
||||
return queueChats[selectedDirect?.address]?.filter(
|
||||
(item) => !!item?.chatReference
|
||||
);
|
||||
}
|
||||
return []
|
||||
}, [selectedDirect?.address, queueChats])
|
||||
return [];
|
||||
}, [selectedDirect?.address, queueChats]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedDirect?.address) {
|
||||
publicKeyOfRecipientRef.current = selectedDirect?.address
|
||||
getPublicKeyFunc(publicKeyOfRecipientRef.current)
|
||||
publicKeyOfRecipientRef.current = selectedDirect?.address;
|
||||
getPublicKeyFunc(publicKeyOfRecipientRef.current);
|
||||
}
|
||||
}, [selectedDirect?.address])
|
||||
}, [selectedDirect?.address]);
|
||||
|
||||
|
||||
const middletierFunc = async (data: any, selectedDirectAddress: string, myAddress: string) => {
|
||||
const middletierFunc = async (
|
||||
data: any,
|
||||
selectedDirectAddress: string,
|
||||
myAddress: string
|
||||
) => {
|
||||
try {
|
||||
if (hasInitialized.current) {
|
||||
decryptMessages(data, true);
|
||||
@ -99,9 +130,9 @@ export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDi
|
||||
hasInitialized.current = true;
|
||||
const url = `${getBaseApiReact()}/chat/messages?involving=${selectedDirectAddress}&involving=${myAddress}&encoding=BASE64&limit=0&reverse=false`;
|
||||
const response = await fetch(url, {
|
||||
method: "GET",
|
||||
method: 'GET',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
const responseData = await response.json();
|
||||
@ -109,22 +140,28 @@ export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDi
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const decryptMessages = (encryptedMessages: any[], isInitiated: boolean) => {
|
||||
try {
|
||||
return new Promise((res, rej) => {
|
||||
window.sendMessage("decryptDirect", {
|
||||
window
|
||||
.sendMessage('decryptDirect', {
|
||||
data: encryptedMessages,
|
||||
involvingAddress: selectedDirect?.address,
|
||||
})
|
||||
.then((decryptResponse) => {
|
||||
if (!decryptResponse?.error) {
|
||||
const response = processWithNewMessages(decryptResponse, selectedDirect?.address);
|
||||
const response = processWithNewMessages(
|
||||
decryptResponse,
|
||||
selectedDirect?.address
|
||||
);
|
||||
res(response);
|
||||
|
||||
if (isInitiated) {
|
||||
const formatted = response.filter((rawItem) => !rawItem?.chatReference).map((item) => ({
|
||||
const formatted = response
|
||||
.filter((rawItem) => !rawItem?.chatReference)
|
||||
.map((item) => ({
|
||||
...item,
|
||||
id: item.signature,
|
||||
text: item.message,
|
||||
@ -134,21 +171,26 @@ export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDi
|
||||
setChatReferences((prev) => {
|
||||
const organizedChatReferences = { ...prev };
|
||||
|
||||
response.filter((rawItem) => !!rawItem?.chatReference && rawItem?.type === 'edit').forEach((item) => {
|
||||
response
|
||||
.filter(
|
||||
(rawItem) =>
|
||||
!!rawItem?.chatReference && rawItem?.type === 'edit'
|
||||
)
|
||||
.forEach((item) => {
|
||||
try {
|
||||
organizedChatReferences[item.chatReference] = {
|
||||
...(organizedChatReferences[item.chatReference] || {}),
|
||||
edit: item
|
||||
...(organizedChatReferences[item.chatReference] ||
|
||||
{}),
|
||||
edit: item,
|
||||
};
|
||||
} catch(error){
|
||||
|
||||
}
|
||||
})
|
||||
return organizedChatReferences
|
||||
})
|
||||
} catch (error) {}
|
||||
});
|
||||
return organizedChatReferences;
|
||||
});
|
||||
} else {
|
||||
hasInitialized.current = true;
|
||||
const formatted = response.filter((rawItem) => !rawItem?.chatReference)
|
||||
const formatted = response
|
||||
.filter((rawItem) => !rawItem?.chatReference)
|
||||
.map((item) => ({
|
||||
...item,
|
||||
id: item.signature,
|
||||
@ -160,32 +202,33 @@ export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDi
|
||||
setChatReferences((prev) => {
|
||||
const organizedChatReferences = { ...prev };
|
||||
|
||||
response.filter((rawItem) => !!rawItem?.chatReference && rawItem?.type === 'edit').forEach((item) => {
|
||||
response
|
||||
.filter(
|
||||
(rawItem) =>
|
||||
!!rawItem?.chatReference && rawItem?.type === 'edit'
|
||||
)
|
||||
.forEach((item) => {
|
||||
try {
|
||||
organizedChatReferences[item.chatReference] = {
|
||||
...(organizedChatReferences[item.chatReference] || {}),
|
||||
edit: item
|
||||
...(organizedChatReferences[item.chatReference] ||
|
||||
{}),
|
||||
edit: item,
|
||||
};
|
||||
} catch(error){
|
||||
|
||||
}
|
||||
})
|
||||
return organizedChatReferences
|
||||
})
|
||||
} catch (error) {}
|
||||
});
|
||||
return organizedChatReferences;
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
rej(response.error);
|
||||
})
|
||||
.catch((error) => {
|
||||
rej(error.message || "An error occurred");
|
||||
rej(error.message || 'An error occurred');
|
||||
});
|
||||
|
||||
})
|
||||
} catch (error) {
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (error) {}
|
||||
};
|
||||
|
||||
const forceCloseWebSocket = () => {
|
||||
if (socketRef.current) {
|
||||
@ -212,7 +255,6 @@ export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDi
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const initWebsocketMessageGroup = () => {
|
||||
forceCloseWebSocket(); // Close any existing connection
|
||||
|
||||
@ -231,7 +273,11 @@ export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDi
|
||||
clearTimeout(timeoutIdRef.current);
|
||||
groupSocketTimeoutRef.current = setTimeout(pingWebSocket, 45000); // Ping every 45 seconds
|
||||
} else {
|
||||
middletierFunc(JSON.parse(e.data), selectedDirect?.address, myAddress)
|
||||
middletierFunc(
|
||||
JSON.parse(e.data),
|
||||
selectedDirect?.address,
|
||||
myAddress
|
||||
);
|
||||
|
||||
setIsLoading(false);
|
||||
}
|
||||
@ -260,13 +306,13 @@ export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDi
|
||||
};
|
||||
|
||||
const setDirectChatValueFunc = async (e) => {
|
||||
setDirectToValue(e.detail.directToValue)
|
||||
}
|
||||
setDirectToValue(e.detail.directToValue);
|
||||
};
|
||||
useEffect(() => {
|
||||
subscribeToEvent("setDirectToValueNewChat", setDirectChatValueFunc);
|
||||
subscribeToEvent('setDirectToValueNewChat', setDirectChatValueFunc);
|
||||
|
||||
return () => {
|
||||
unsubscribeFromEvent("setDirectToValueNewChat", setDirectChatValueFunc);
|
||||
unsubscribeFromEvent('setDirectToValueNewChat', setDirectChatValueFunc);
|
||||
};
|
||||
}, []);
|
||||
|
||||
@ -281,22 +327,30 @@ export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDi
|
||||
};
|
||||
}, [selectedDirect?.address, myAddress, isNewChat]);
|
||||
|
||||
|
||||
|
||||
const sendChatDirect = async ({ chatReference = undefined, messageText, otherData}: any, address, publicKeyOfRecipient, isNewChatVar)=> {
|
||||
const sendChatDirect = async (
|
||||
{ chatReference = undefined, messageText, otherData }: any,
|
||||
address,
|
||||
publicKeyOfRecipient,
|
||||
isNewChatVar
|
||||
) => {
|
||||
try {
|
||||
const directTo = isNewChatVar ? directToValue : address
|
||||
const directTo = isNewChatVar ? directToValue : address;
|
||||
|
||||
if(!directTo) return
|
||||
if (!directTo) return;
|
||||
return new Promise((res, rej) => {
|
||||
window.sendMessage("sendChatDirect", {
|
||||
window
|
||||
.sendMessage(
|
||||
'sendChatDirect',
|
||||
{
|
||||
directTo,
|
||||
chatReference,
|
||||
messageText,
|
||||
otherData,
|
||||
publicKeyOfRecipient,
|
||||
address: directTo,
|
||||
}, 120000)
|
||||
},
|
||||
120000
|
||||
)
|
||||
.then(async (response) => {
|
||||
if (!response?.error) {
|
||||
if (isNewChatVar) {
|
||||
@ -304,7 +358,7 @@ const sendChatDirect = async ({ chatReference = undefined, messageText, otherDat
|
||||
try {
|
||||
getRecipientName = await getNameInfo(response.recipient);
|
||||
} catch (error) {
|
||||
console.error("Error fetching recipient name:", error);
|
||||
console.error('Error fetching recipient name:', error);
|
||||
}
|
||||
setSelectedDirect({
|
||||
address: response.recipient,
|
||||
@ -315,11 +369,16 @@ const sendChatDirect = async ({ chatReference = undefined, messageText, otherDat
|
||||
});
|
||||
setNewChat(null);
|
||||
|
||||
window.sendMessage("addTimestampEnterChat", {
|
||||
window
|
||||
.sendMessage('addTimestampEnterChat', {
|
||||
timestamp: Date.now(),
|
||||
groupId: response.recipient,
|
||||
}).catch((error) => {
|
||||
console.error("Failed to add timestamp:", error.message || "An error occurred");
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(
|
||||
'Failed to add timestamp:',
|
||||
error.message || 'An error occurred'
|
||||
);
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
@ -332,24 +391,23 @@ const sendChatDirect = async ({ chatReference = undefined, messageText, otherDat
|
||||
rej(response.error);
|
||||
})
|
||||
.catch((error) => {
|
||||
rej(error.message || "An error occurred");
|
||||
rej(error.message || 'An error occurred');
|
||||
});
|
||||
});
|
||||
|
||||
})
|
||||
} catch (error) {
|
||||
throw new Error(error)
|
||||
throw new Error(error);
|
||||
} finally {
|
||||
}
|
||||
}
|
||||
};
|
||||
const clearEditorContent = () => {
|
||||
if (editorRef.current) {
|
||||
setMessageSize(0)
|
||||
setMessageSize(0);
|
||||
editorRef.current.chain().focus().clearContent().run();
|
||||
if (isMobile) {
|
||||
setTimeout(() => {
|
||||
editorRef.current?.chain().blur().run();
|
||||
setIsFocusedParent(false)
|
||||
executeEvent("sent-new-message-group", {})
|
||||
setIsFocusedParent(false);
|
||||
executeEvent('sent-new-message-group', {});
|
||||
setTimeout(() => {
|
||||
triggerRerender();
|
||||
}, 300);
|
||||
@ -377,42 +435,44 @@ useEffect(() => {
|
||||
|
||||
const sendMessage = async () => {
|
||||
try {
|
||||
if(messageSize > 4000) return
|
||||
if (messageSize > 4000) return;
|
||||
|
||||
|
||||
if(+balance < 4) throw new Error('You need at least 4 QORT to send a message')
|
||||
if(isSending) return
|
||||
if (+balance < 4)
|
||||
throw new Error('You need at least 4 QORT to send a message');
|
||||
if (isSending) return;
|
||||
if (editorRef.current) {
|
||||
const htmlContent = editorRef.current.getHTML();
|
||||
|
||||
if(!htmlContent?.trim() || htmlContent?.trim() === '<p></p>') return
|
||||
setIsSending(true)
|
||||
pauseAllQueues()
|
||||
const message = JSON.stringify(htmlContent)
|
||||
|
||||
if (!htmlContent?.trim() || htmlContent?.trim() === '<p></p>') return;
|
||||
setIsSending(true);
|
||||
pauseAllQueues();
|
||||
const message = JSON.stringify(htmlContent);
|
||||
|
||||
if (isNewChat) {
|
||||
await sendChatDirect({ messageText: htmlContent}, null, null, true)
|
||||
return
|
||||
await sendChatDirect({ messageText: htmlContent }, null, null, true);
|
||||
return;
|
||||
}
|
||||
let repliedTo = replyMessage?.signature
|
||||
let repliedTo = replyMessage?.signature;
|
||||
|
||||
if (replyMessage?.chatReference) {
|
||||
repliedTo = replyMessage?.chatReference
|
||||
repliedTo = replyMessage?.chatReference;
|
||||
}
|
||||
let chatReference = onEditMessage?.signature
|
||||
let chatReference = onEditMessage?.signature;
|
||||
|
||||
const otherData = {
|
||||
...(onEditMessage?.decryptedData || {}),
|
||||
specialId: uid.rnd(),
|
||||
repliedTo: onEditMessage ? onEditMessage?.repliedTo : repliedTo,
|
||||
type: chatReference ? 'edit' : ''
|
||||
}
|
||||
const sendMessageFunc = async () => {
|
||||
return await sendChatDirect({ chatReference, messageText: htmlContent, otherData}, selectedDirect?.address, publicKeyOfRecipient, false)
|
||||
type: chatReference ? 'edit' : '',
|
||||
};
|
||||
const sendMessageFunc = async () => {
|
||||
return await sendChatDirect(
|
||||
{ chatReference, messageText: htmlContent, otherData },
|
||||
selectedDirect?.address,
|
||||
publicKeyOfRecipient,
|
||||
false
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Add the function to the queue
|
||||
const messageObj = {
|
||||
@ -423,60 +483,71 @@ useEffect(() => {
|
||||
...(otherData || {}),
|
||||
text: htmlContent,
|
||||
},
|
||||
chatReference
|
||||
}
|
||||
addToQueue(sendMessageFunc, messageObj, 'chat-direct',
|
||||
selectedDirect?.address );
|
||||
chatReference,
|
||||
};
|
||||
addToQueue(
|
||||
sendMessageFunc,
|
||||
messageObj,
|
||||
'chat-direct',
|
||||
selectedDirect?.address
|
||||
);
|
||||
setTimeout(() => {
|
||||
executeEvent("sent-new-message-group", {})
|
||||
executeEvent('sent-new-message-group', {});
|
||||
}, 150);
|
||||
clearEditorContent()
|
||||
setReplyMessage(null)
|
||||
setOnEditMessage(null)
|
||||
|
||||
clearEditorContent();
|
||||
setReplyMessage(null);
|
||||
setOnEditMessage(null);
|
||||
}
|
||||
// send chat message
|
||||
} catch (error) {
|
||||
const errorMsg = error?.message || error
|
||||
const errorMsg = error?.message || error;
|
||||
setInfoSnack({
|
||||
type: "error",
|
||||
message: errorMsg === 'invalid signature' ? 'You need at least 4 QORT to send a message' : errorMsg,
|
||||
type: 'error',
|
||||
message:
|
||||
errorMsg === 'invalid signature'
|
||||
? 'You need at least 4 QORT to send a message'
|
||||
: errorMsg,
|
||||
});
|
||||
setOpenSnack(true);
|
||||
console.error(error)
|
||||
console.error(error);
|
||||
} finally {
|
||||
setIsSending(false)
|
||||
resumeAllQueues()
|
||||
}
|
||||
setIsSending(false);
|
||||
resumeAllQueues();
|
||||
}
|
||||
};
|
||||
|
||||
const onReply = useCallback((message)=> {
|
||||
const onReply = useCallback(
|
||||
(message) => {
|
||||
if (onEditMessage) {
|
||||
clearEditorContent()
|
||||
clearEditorContent();
|
||||
}
|
||||
setReplyMessage(message)
|
||||
setOnEditMessage(null)
|
||||
editorRef?.current?.chain().focus()
|
||||
}, [onEditMessage])
|
||||
|
||||
setReplyMessage(message);
|
||||
setOnEditMessage(null);
|
||||
editorRef?.current?.chain().focus();
|
||||
},
|
||||
[onEditMessage]
|
||||
);
|
||||
|
||||
const onEdit = useCallback((message) => {
|
||||
setOnEditMessage(message)
|
||||
setReplyMessage(null)
|
||||
setOnEditMessage(message);
|
||||
setReplyMessage(null);
|
||||
editorRef.current.chain().focus().setContent(message?.text).run();
|
||||
|
||||
}, [])
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
<div
|
||||
style={{
|
||||
height: isMobile ? '100%' : '100vh',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
width: '100%',
|
||||
background: !isMobile && 'var(--bg-2)'
|
||||
}}>
|
||||
background: !isMobile && 'var(--bg-2)',
|
||||
}}
|
||||
>
|
||||
{!isMobile && (
|
||||
<Box onClick={close} sx={{
|
||||
<Box
|
||||
onClick={close}
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '5px',
|
||||
@ -486,47 +557,54 @@ useEffect(() => {
|
||||
borderRadius: '3px',
|
||||
background: 'rgb(35, 36, 40)',
|
||||
margin: '10px 0px',
|
||||
alignSelf: 'center'
|
||||
}}>
|
||||
<ArrowBackIcon sx={{
|
||||
alignSelf: 'center',
|
||||
}}
|
||||
>
|
||||
<ArrowBackIcon
|
||||
sx={{
|
||||
color: 'white',
|
||||
fontSize: isMobile ? '20px' : '20px'
|
||||
}}/>
|
||||
<Typography sx={{
|
||||
fontSize: isMobile ? '20px' : '20px',
|
||||
}}
|
||||
/>
|
||||
<Typography
|
||||
sx={{
|
||||
color: 'white',
|
||||
fontSize: isMobile ? '14px' : '14px'
|
||||
}}>Close Direct Chat</Typography>
|
||||
fontSize: isMobile ? '14px' : '14px',
|
||||
}}
|
||||
>
|
||||
Close Direct Chat
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
{isMobile && (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
width: "100%",
|
||||
marginTop: "14px",
|
||||
justifyContent: "center",
|
||||
height: "15px",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
width: '100%',
|
||||
marginTop: '14px',
|
||||
justifyContent: 'center',
|
||||
height: '15px',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
width: "320px",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
width: '320px',
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
width: "50px",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
width: '50px',
|
||||
}}
|
||||
>
|
||||
<ButtonBase
|
||||
onClick={() => {
|
||||
close()
|
||||
close();
|
||||
}}
|
||||
>
|
||||
<ReturnIcon />
|
||||
@ -534,25 +612,28 @@ useEffect(() => {
|
||||
</Box>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "14px",
|
||||
fontSize: '14px',
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
{isNewChat ? '' : selectedDirect?.name || (selectedDirect?.address?.slice(0,10) + '...')}
|
||||
{isNewChat
|
||||
? ''
|
||||
: selectedDirect?.name ||
|
||||
selectedDirect?.address?.slice(0, 10) + '...'}
|
||||
</Typography>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
width: "50px",
|
||||
justifyContent: "flex-end",
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
width: '50px',
|
||||
justifyContent: 'flex-end',
|
||||
}}
|
||||
>
|
||||
<ButtonBase
|
||||
onClick={() => {
|
||||
setSelectedDirect(null)
|
||||
setMobileViewModeKeepOpen('')
|
||||
setNewChat(false)
|
||||
setSelectedDirect(null);
|
||||
setMobileViewModeKeepOpen('');
|
||||
setNewChat(false);
|
||||
}}
|
||||
>
|
||||
<ExitIcon />
|
||||
@ -564,21 +645,34 @@ useEffect(() => {
|
||||
{isNewChat && (
|
||||
<>
|
||||
<Spacer height="30px" />
|
||||
<Input sx={{
|
||||
<Input
|
||||
sx={{
|
||||
fontSize: '18px',
|
||||
padding: '5px'
|
||||
}} placeholder='Name or address' value={directToValue} onChange={(e)=> setDirectToValue(e.target.value)} />
|
||||
|
||||
padding: '5px',
|
||||
}}
|
||||
placeholder="Name or address"
|
||||
value={directToValue}
|
||||
onChange={(e) => setDirectToValue(e.target.value)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
<ChatList chatReferences={chatReferences} onEdit={onEdit} onReply={onReply} chatId={selectedDirect?.address} initialMessages={messages} myAddress={myAddress} tempMessages={tempMessages} tempChatReferences={tempChatReferences}/>
|
||||
<ChatList
|
||||
chatReferences={chatReferences}
|
||||
onEdit={onEdit}
|
||||
onReply={onReply}
|
||||
chatId={selectedDirect?.address}
|
||||
initialMessages={messages}
|
||||
myAddress={myAddress}
|
||||
tempMessages={tempMessages}
|
||||
tempChatReferences={tempChatReferences}
|
||||
/>
|
||||
|
||||
|
||||
<div style={{
|
||||
<div
|
||||
style={{
|
||||
// position: 'fixed',
|
||||
// bottom: '0px',
|
||||
backgroundColor: "#232428",
|
||||
backgroundColor: '#232428',
|
||||
minHeight: isMobile ? '0px' : '150px',
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
@ -590,32 +684,36 @@ useEffect(() => {
|
||||
bottom: isFocusedParent ? '0px' : 'unset',
|
||||
top: isFocusedParent ? '0px' : 'unset',
|
||||
zIndex: isFocusedParent ? 5 : 'unset',
|
||||
flexShrink: 0
|
||||
}}>
|
||||
<div style={{
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
flexGrow: isMobile && 1,
|
||||
overflow: !isMobile && "auto",
|
||||
overflow: !isMobile && 'auto',
|
||||
flexShrink: 0,
|
||||
width: 'calc(100% - 100px)',
|
||||
justifyContent: 'flex-end'
|
||||
}}>
|
||||
justifyContent: 'flex-end',
|
||||
}}
|
||||
>
|
||||
{replyMessage && (
|
||||
<Box sx={{
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
gap: '5px',
|
||||
alignItems: 'flex-start',
|
||||
width: 'calc(100% - 100px)',
|
||||
justifyContent: 'flex-end'
|
||||
}}>
|
||||
justifyContent: 'flex-end',
|
||||
}}
|
||||
>
|
||||
<ReplyPreview message={replyMessage} />
|
||||
|
||||
<ButtonBase
|
||||
onClick={() => {
|
||||
setReplyMessage(null)
|
||||
setOnEditMessage(null)
|
||||
|
||||
setReplyMessage(null);
|
||||
setOnEditMessage(null);
|
||||
}}
|
||||
>
|
||||
<ExitIcon />
|
||||
@ -623,22 +721,22 @@ useEffect(() => {
|
||||
</Box>
|
||||
)}
|
||||
{onEditMessage && (
|
||||
<Box sx={{
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
gap: '5px',
|
||||
alignItems: 'flex-start',
|
||||
width: '100%'
|
||||
}}>
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
<ReplyPreview isEdit message={onEditMessage} />
|
||||
|
||||
<ButtonBase
|
||||
onClick={() => {
|
||||
setReplyMessage(null)
|
||||
setOnEditMessage(null)
|
||||
|
||||
clearEditorContent()
|
||||
|
||||
setReplyMessage(null);
|
||||
setOnEditMessage(null);
|
||||
|
||||
clearEditorContent();
|
||||
}}
|
||||
>
|
||||
<ExitIcon />
|
||||
@ -646,24 +744,35 @@ useEffect(() => {
|
||||
</Box>
|
||||
)}
|
||||
|
||||
<Tiptap isFocusedParent={isFocusedParent} setEditorRef={setEditorRef} onEnter={sendMessage} isChat disableEnter={isMobile ? true : false} setIsFocusedParent={setIsFocusedParent}/>
|
||||
<Tiptap
|
||||
isFocusedParent={isFocusedParent}
|
||||
setEditorRef={setEditorRef}
|
||||
onEnter={sendMessage}
|
||||
isChat
|
||||
disableEnter={isMobile ? true : false}
|
||||
setIsFocusedParent={setIsFocusedParent}
|
||||
/>
|
||||
{messageSize > 750 && (
|
||||
<Box sx={{
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
justifyContent: 'flex-start',
|
||||
position: 'relative',
|
||||
}}>
|
||||
<Typography sx={{
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: '12px',
|
||||
color: messageSize > 4000 ? 'var(--danger)' : 'unset'
|
||||
}}>{`Your message size is of ${messageSize} bytes out of a maximum of 4000`}</Typography>
|
||||
|
||||
color: messageSize > 4000 ? 'var(--danger)' : 'unset',
|
||||
}}
|
||||
>{`Your message size is of ${messageSize} bytes out of a maximum of 4000`}</Typography>
|
||||
</Box>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Box sx={{
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
width: '100px',
|
||||
|
||||
@ -671,13 +780,12 @@ useEffect(() => {
|
||||
justifyContent: 'center',
|
||||
flexShrink: 0,
|
||||
position: 'relative',
|
||||
}}>
|
||||
|
||||
}}
|
||||
>
|
||||
<CustomButton
|
||||
onClick={() => {
|
||||
|
||||
if(isSending) return
|
||||
sendMessage()
|
||||
if (isSending) return;
|
||||
sendMessage();
|
||||
}}
|
||||
style={{
|
||||
marginTop: 'auto',
|
||||
@ -687,7 +795,7 @@ useEffect(() => {
|
||||
flexShrink: 0,
|
||||
padding: '5px',
|
||||
width: '100px',
|
||||
minWidth: 'auto'
|
||||
minWidth: 'auto',
|
||||
}}
|
||||
>
|
||||
{isSending && (
|
||||
@ -699,19 +807,26 @@ useEffect(() => {
|
||||
left: '50%',
|
||||
marginTop: '-12px',
|
||||
marginLeft: '-12px',
|
||||
color: 'white'
|
||||
color: 'white',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{` Send`}
|
||||
</CustomButton>
|
||||
|
||||
</Box>
|
||||
</div>
|
||||
<LoadingSnackbar open={isLoading} info={{
|
||||
message: "Loading chat... please wait."
|
||||
}} />
|
||||
<CustomizedSnackbars open={openSnack} setOpen={setOpenSnack} info={infoSnack} setInfo={setInfoSnack} />
|
||||
<LoadingSnackbar
|
||||
open={isLoading}
|
||||
info={{
|
||||
message: 'Loading chat... please wait.',
|
||||
}}
|
||||
/>
|
||||
<CustomizedSnackbars
|
||||
open={openSnack}
|
||||
setOpen={setOpenSnack}
|
||||
info={infoSnack}
|
||||
setInfo={setInfoSnack}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
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,7 +51,8 @@ export const requestQueuePublishedAccouncements = new RequestQueueWithPromise(
|
||||
|
||||
export const saveTempPublish = async ({ data, key }: any) => {
|
||||
return new Promise((res, rej) => {
|
||||
window.sendMessage("saveTempPublish", {
|
||||
window
|
||||
.sendMessage('saveTempPublish', {
|
||||
data,
|
||||
key,
|
||||
})
|
||||
@ -60,15 +64,15 @@ 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", {})
|
||||
window
|
||||
.sendMessage('getTempPublish', {})
|
||||
.then((response) => {
|
||||
if (!response?.error) {
|
||||
res(response);
|
||||
@ -77,16 +81,16 @@ export const getTempPublish = async () => {
|
||||
rej(response.error);
|
||||
})
|
||||
.catch((error) => {
|
||||
rej(error.message || "An error occurred");
|
||||
rej(error.message || 'An error occurred');
|
||||
});
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
export const decryptPublishes = async (encryptedMessages: any[], secretKey) => {
|
||||
try {
|
||||
return await new Promise((res, rej) => {
|
||||
window.sendMessage("decryptSingleForPublishes", {
|
||||
window
|
||||
.sendMessage('decryptSingleForPublishes', {
|
||||
data: encryptedMessages,
|
||||
secretKeyObject: secretKey,
|
||||
skipDecodeBase64: true,
|
||||
@ -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 = []
|
||||
let publishesData = [];
|
||||
publishes.forEach((pub) => {
|
||||
try {
|
||||
const decryptToUnit8Array = base64ToUint8Array(pub);
|
||||
const decodedData = uint8ArrayToObject(decryptToUnit8Array);
|
||||
if (decodedData) {
|
||||
publishesData.push({decryptedData: 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,7 +220,8 @@ export const GroupAnnouncements = ({
|
||||
const encryptChatMessage = async (data: string, secretKeyObject: any) => {
|
||||
try {
|
||||
return new Promise((res, rej) => {
|
||||
window.sendMessage("encryptSingle", {
|
||||
window
|
||||
.sendMessage('encryptSingle', {
|
||||
data,
|
||||
secretKeyObject,
|
||||
})
|
||||
@ -220,16 +233,16 @@ 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", {
|
||||
window
|
||||
.sendMessage('publishGroupEncryptedResource', {
|
||||
encryptedData,
|
||||
identifier,
|
||||
})
|
||||
@ -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 = () => {
|
||||
@ -266,7 +278,9 @@ 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) => {
|
||||
Object.keys(getTempAnnouncements?.announcement || {})
|
||||
.filter((annKey) => annKey?.startsWith(`grp-${selectedGroup}-anc`))
|
||||
.map((key) => {
|
||||
const value = getTempAnnouncements?.announcement[key];
|
||||
tempData.push(value.data);
|
||||
});
|
||||
@ -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 secretKeyObject =
|
||||
isPrivate === false ? null : await getSecretKey(false, true);
|
||||
const message64: any = await objectToBase64(message);
|
||||
const encryptSingle = isPrivate === false ? message64 : await encryptChatMessage(
|
||||
message64,
|
||||
secretKeyObject
|
||||
);
|
||||
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({
|
||||
getAnnouncementData(
|
||||
{
|
||||
name: data.name,
|
||||
identifier: data.identifier,
|
||||
resource: data,
|
||||
}, isPrivate);
|
||||
},
|
||||
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({
|
||||
getAnnouncementData(
|
||||
{
|
||||
name: data.name,
|
||||
identifier: data.identifier,
|
||||
}, isPrivate);
|
||||
},
|
||||
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",
|
||||
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 && (
|
||||
@ -645,13 +678,13 @@ export const GroupAnnouncements = ({
|
||||
// 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])
|
||||
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,
|
||||
}}
|
||||
>
|
||||
@ -195,7 +197,7 @@ export const JoinGroup = ({ memberGroups }) => {
|
||||
{isInGroup && (
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "14px",
|
||||
fontSize: '14px',
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
@ -205,7 +207,7 @@ export const JoinGroup = ({ memberGroups }) => {
|
||||
{!isInGroup && groupInfo?.isOpen === false && (
|
||||
<Typography
|
||||
sx={{
|
||||
fontSize: "14px",
|
||||
fontSize: '14px',
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
@ -216,21 +218,23 @@ export const JoinGroup = ({ memberGroups }) => {
|
||||
</Box>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<ButtonBase onClick={() => {
|
||||
<ButtonBase
|
||||
onClick={() => {
|
||||
joinGroup(groupInfo, groupInfo?.isOpen);
|
||||
|
||||
setIsOpen(false);
|
||||
}} disabled={isInGroup}>
|
||||
}}
|
||||
disabled={isInGroup}
|
||||
>
|
||||
<CustomButtonAccept
|
||||
color="black"
|
||||
bgColor="var(--green)"
|
||||
sx={{
|
||||
minWidth: "102px",
|
||||
height: "45px",
|
||||
minWidth: '102px',
|
||||
height: '45px',
|
||||
fontSize: '16px',
|
||||
opacity: isInGroup ? 0.1 : 1
|
||||
opacity: isInGroup ? 0.1 : 1,
|
||||
}}
|
||||
|
||||
>
|
||||
Join
|
||||
</CustomButtonAccept>
|
||||
@ -240,8 +244,8 @@ export const JoinGroup = ({ memberGroups }) => {
|
||||
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,9 +47,9 @@ 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);
|
||||
@ -60,17 +60,17 @@ export const Minting = ({
|
||||
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' });
|
||||
});
|
||||
});
|
||||
}, []);
|
||||
@ -345,7 +345,6 @@ export const Minting = ({
|
||||
const sleep = (ms) => new Promise((res) => setTimeout(res, ms));
|
||||
|
||||
while (Date.now() - startTime < timeoutMs) {
|
||||
|
||||
const rewardShares = await getRewardShares(myAddress);
|
||||
const findRewardShare = rewardShares?.find(
|
||||
(item) =>
|
||||
@ -356,11 +355,10 @@ export const Minting = ({
|
||||
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,12 +796,13 @@ 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.
|
||||
Confirming creation of rewardshare on chain. Please be
|
||||
patient, this could take up to 90 seconds.
|
||||
</Typography>
|
||||
)}
|
||||
{isShowNext && (
|
||||
@ -814,16 +810,18 @@ export const Minting = ({
|
||||
Rewardshare confirmed. Please click Next.
|
||||
</Typography>
|
||||
)}
|
||||
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions>
|
||||
<Button disabled={!isShowNext} variant="contained" onClick={onOk} autoFocus>
|
||||
<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,6 +1,11 @@
|
||||
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';
|
||||
@ -10,38 +15,36 @@ 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 [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("");
|
||||
setSendPaymentError('');
|
||||
setSendPaymentSuccess('');
|
||||
if (!paymentTo) {
|
||||
setSendPaymentError("Please enter a recipient");
|
||||
setSendPaymentError('Please enter a recipient');
|
||||
return;
|
||||
}
|
||||
if (!paymentAmount) {
|
||||
setSendPaymentError("Please enter an amount greater than 0");
|
||||
setSendPaymentError('Please enter an amount greater than 0');
|
||||
return;
|
||||
}
|
||||
if (!paymentPassword) {
|
||||
setSendPaymentError("Please enter your wallet password");
|
||||
setSendPaymentError('Please enter your wallet password');
|
||||
return;
|
||||
}
|
||||
const fee = await getFee('PAYMENT')
|
||||
const fee = await getFee('PAYMENT');
|
||||
|
||||
await show({
|
||||
message: `Would you like to transfer ${Number(paymentAmount)} QORT?`,
|
||||
paymentFee: fee.fee + ' QORT'
|
||||
})
|
||||
paymentFee: fee.fee + ' QORT',
|
||||
});
|
||||
setIsLoadingSendCoin(true);
|
||||
window
|
||||
.sendMessage("sendCoin", {
|
||||
.sendMessage('sendCoin', {
|
||||
amount: Number(paymentAmount),
|
||||
receiver: paymentTo.trim(),
|
||||
password: paymentPassword,
|
||||
@ -50,13 +53,12 @@ export const QortPayment = ({balance, show, onSuccess, defaultPaymentTo}) => {
|
||||
if (response?.error) {
|
||||
setSendPaymentError(response.error);
|
||||
} else {
|
||||
onSuccess()
|
||||
|
||||
onSuccess();
|
||||
}
|
||||
setIsLoadingSendCoin(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Failed to send coin:", error);
|
||||
console.error('Failed to send coin:', error);
|
||||
setIsLoadingSendCoin(false);
|
||||
});
|
||||
} catch (error) {
|
||||
@ -67,16 +69,16 @@ export const QortPayment = ({balance, show, onSuccess, defaultPaymentTo}) => {
|
||||
<>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "flex-start",
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start',
|
||||
}}
|
||||
>
|
||||
<TextP
|
||||
sx={{
|
||||
textAlign: "start",
|
||||
lineHeight: "24px",
|
||||
fontSize: "20px",
|
||||
textAlign: 'start',
|
||||
lineHeight: '24px',
|
||||
fontSize: '20px',
|
||||
fontWeight: 600,
|
||||
}}
|
||||
>
|
||||
@ -85,20 +87,20 @@ export const QortPayment = ({balance, show, onSuccess, defaultPaymentTo}) => {
|
||||
<Spacer height="35px" />
|
||||
<TextP
|
||||
sx={{
|
||||
textAlign: "start",
|
||||
lineHeight: "16px",
|
||||
fontSize: "20px",
|
||||
textAlign: 'start',
|
||||
lineHeight: '16px',
|
||||
fontSize: '20px',
|
||||
fontWeight: 600,
|
||||
color: "rgba(255, 255, 255, 0.5)",
|
||||
color: 'rgba(255, 255, 255, 0.5)',
|
||||
}}
|
||||
>
|
||||
Balance:
|
||||
</TextP>
|
||||
<TextP
|
||||
sx={{
|
||||
textAlign: "start",
|
||||
lineHeight: "24px",
|
||||
fontSize: "20px",
|
||||
textAlign: 'start',
|
||||
lineHeight: '24px',
|
||||
fontSize: '20px',
|
||||
fontWeight: 700,
|
||||
}}
|
||||
>
|
||||
@ -117,9 +119,7 @@ export const QortPayment = ({balance, show, onSuccess, defaultPaymentTo}) => {
|
||||
autoComplete="off"
|
||||
/>
|
||||
<Spacer height="6px" />
|
||||
<CustomLabel htmlFor="standard-adornment-amount">
|
||||
Amount
|
||||
</CustomLabel>
|
||||
<CustomLabel htmlFor="standard-adornment-amount">Amount</CustomLabel>
|
||||
<Spacer height="5px" />
|
||||
<BoundedNumericTextField
|
||||
value={paymentAmount}
|
||||
@ -148,20 +148,23 @@ export const QortPayment = ({balance, show, onSuccess, defaultPaymentTo}) => {
|
||||
<Spacer height="25px" />
|
||||
<CustomButton
|
||||
sx={{
|
||||
cursor: isLoadingSendCoin ? 'default' : 'pointer'
|
||||
cursor: isLoadingSendCoin ? 'default' : 'pointer',
|
||||
}}
|
||||
onClick={() => {
|
||||
if(isLoadingSendCoin) return
|
||||
if (isLoadingSendCoin) return;
|
||||
sendCoinFunc();
|
||||
}}
|
||||
>
|
||||
{isLoadingSendCoin && (
|
||||
<CircularProgress size={16} sx={{
|
||||
color: 'white'
|
||||
}} />
|
||||
<CircularProgress
|
||||
size={16}
|
||||
sx={{
|
||||
color: 'white',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
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