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,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { Spacer } from '../common/Spacer';
|
import { Spacer } from '../common/Spacer';
|
||||||
import { CustomButton, TextP, TextSpan } from '../App-styles';
|
import { CustomButton, TextP, TextSpan } from '../styles/App-styles';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
@ -29,7 +29,7 @@ import { CustomizedSnackbars } from '../components/Snackbar/Snackbar';
|
|||||||
import { cleanUrl, gateways } from '../background';
|
import { cleanUrl, gateways } from '../background';
|
||||||
import { GlobalContext } from '../App';
|
import { GlobalContext } from '../App';
|
||||||
import Tooltip, { TooltipProps, tooltipClasses } from '@mui/material/Tooltip';
|
import Tooltip, { TooltipProps, tooltipClasses } from '@mui/material/Tooltip';
|
||||||
import ThemeSelector from '../styles/ThemeSelector';
|
import ThemeSelector from '../components/Theme/ThemeSelector';
|
||||||
|
|
||||||
const manifestData = {
|
const manifestData = {
|
||||||
version: '0.5.3',
|
version: '0.5.3',
|
||||||
|
@ -3,15 +3,15 @@ import {
|
|||||||
InputAdornment,
|
InputAdornment,
|
||||||
TextField,
|
TextField,
|
||||||
TextFieldProps,
|
TextFieldProps,
|
||||||
} from "@mui/material";
|
} from '@mui/material';
|
||||||
import React, { useRef, useState } from "react";
|
import React, { useRef, useState } from 'react';
|
||||||
import AddIcon from "@mui/icons-material/Add";
|
import AddIcon from '@mui/icons-material/Add';
|
||||||
import RemoveIcon from "@mui/icons-material/Remove";
|
import RemoveIcon from '@mui/icons-material/Remove';
|
||||||
import {
|
import {
|
||||||
removeTrailingZeros,
|
removeTrailingZeros,
|
||||||
setNumberWithinBounds,
|
setNumberWithinBounds,
|
||||||
} from "./numberFunctions.ts";
|
} from './numberFunctions.ts';
|
||||||
import { CustomInput } from "../App-styles.ts";
|
import { CustomInput } from '../styles/App-styles.ts';
|
||||||
|
|
||||||
type eventType = React.ChangeEvent<HTMLInputElement>;
|
type eventType = React.ChangeEvent<HTMLInputElement>;
|
||||||
type BoundedNumericTextFieldProps = {
|
type BoundedNumericTextFieldProps = {
|
||||||
@ -37,18 +37,18 @@ export const BoundedNumericTextField = ({
|
|||||||
...props
|
...props
|
||||||
}: BoundedNumericTextFieldProps) => {
|
}: BoundedNumericTextFieldProps) => {
|
||||||
const [textFieldValue, setTextFieldValue] = useState<string>(
|
const [textFieldValue, setTextFieldValue] = useState<string>(
|
||||||
initialValue || ""
|
initialValue || ''
|
||||||
);
|
);
|
||||||
const ref = useRef<HTMLInputElement | null>(null);
|
const ref = useRef<HTMLInputElement | null>(null);
|
||||||
|
|
||||||
const stringIsEmpty = (value: string) => {
|
const stringIsEmpty = (value: string) => {
|
||||||
return value === "";
|
return value === '';
|
||||||
};
|
};
|
||||||
const isAllZerosNum = /^0*\.?0*$/;
|
const isAllZerosNum = /^0*\.?0*$/;
|
||||||
const isFloatNum = /^-?[0-9]*\.?[0-9]*$/;
|
const isFloatNum = /^-?[0-9]*\.?[0-9]*$/;
|
||||||
const isIntegerNum = /^-?[0-9]+$/;
|
const isIntegerNum = /^-?[0-9]+$/;
|
||||||
const skipMinMaxCheck = (value: string) => {
|
const skipMinMaxCheck = (value: string) => {
|
||||||
const lastIndexIsDecimal = value.charAt(value.length - 1) === ".";
|
const lastIndexIsDecimal = value.charAt(value.length - 1) === '.';
|
||||||
const isEmpty = stringIsEmpty(value);
|
const isEmpty = stringIsEmpty(value);
|
||||||
const isAllZeros = isAllZerosNum.test(value);
|
const isAllZeros = isAllZerosNum.test(value);
|
||||||
const isInteger = isIntegerNum.test(value);
|
const isInteger = isIntegerNum.test(value);
|
||||||
@ -69,7 +69,7 @@ export const BoundedNumericTextField = ({
|
|||||||
|
|
||||||
const getSigDigits = (number: string) => {
|
const getSigDigits = (number: string) => {
|
||||||
if (isIntegerNum.test(number)) return 0;
|
if (isIntegerNum.test(number)) return 0;
|
||||||
const decimalSplit = number.split(".");
|
const decimalSplit = number.split('.');
|
||||||
return decimalSplit[decimalSplit.length - 1].length;
|
return decimalSplit[decimalSplit.length - 1].length;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -78,15 +78,15 @@ export const BoundedNumericTextField = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const filterTypes = (value: string) => {
|
const filterTypes = (value: string) => {
|
||||||
if (allowDecimals === false) value = value.replace(".", "");
|
if (allowDecimals === false) value = value.replace('.', '');
|
||||||
if (allowNegatives === false) value = value.replace("-", "");
|
if (allowNegatives === false) value = value.replace('-', '');
|
||||||
if (sigDigitsExceeded(value, maxSigDigits)) {
|
if (sigDigitsExceeded(value, maxSigDigits)) {
|
||||||
value = value.substring(0, value.length - 1);
|
value = value.substring(0, value.length - 1);
|
||||||
}
|
}
|
||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
const filterValue = (value: string) => {
|
const filterValue = (value: string) => {
|
||||||
if (stringIsEmpty(value)) return "";
|
if (stringIsEmpty(value)) return '';
|
||||||
value = filterTypes(value);
|
value = filterTypes(value);
|
||||||
if (isFloatNum.test(value)) {
|
if (isFloatNum.test(value)) {
|
||||||
return setMinMaxValue(value);
|
return setMinMaxValue(value);
|
||||||
@ -109,8 +109,8 @@ export const BoundedNumericTextField = ({
|
|||||||
|
|
||||||
const formatValueOnBlur = (e: eventType) => {
|
const formatValueOnBlur = (e: eventType) => {
|
||||||
let value = e.target.value;
|
let value = e.target.value;
|
||||||
if (stringIsEmpty(value) || value === ".") {
|
if (stringIsEmpty(value) || value === '.') {
|
||||||
setTextFieldValue("");
|
setTextFieldValue('');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,23 +129,33 @@ export const BoundedNumericTextField = ({
|
|||||||
...props?.InputProps,
|
...props?.InputProps,
|
||||||
endAdornment: addIconButtons ? (
|
endAdornment: addIconButtons ? (
|
||||||
<InputAdornment position="end">
|
<InputAdornment position="end">
|
||||||
<IconButton size="small" onClick={() => changeValueWithIncDecButton(1)}>
|
<IconButton
|
||||||
<AddIcon sx={{
|
size="small"
|
||||||
color: 'white'
|
onClick={() => changeValueWithIncDecButton(1)}
|
||||||
}} />{" "}
|
>
|
||||||
|
<AddIcon
|
||||||
|
sx={{
|
||||||
|
color: 'white',
|
||||||
|
}}
|
||||||
|
/>{' '}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton size="small" onClick={() => changeValueWithIncDecButton(-1)}>
|
<IconButton
|
||||||
<RemoveIcon sx={{
|
size="small"
|
||||||
color: 'white'
|
onClick={() => changeValueWithIncDecButton(-1)}
|
||||||
}} />{" "}
|
>
|
||||||
|
<RemoveIcon
|
||||||
|
sx={{
|
||||||
|
color: 'white',
|
||||||
|
}}
|
||||||
|
/>{' '}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</InputAdornment>
|
</InputAdornment>
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<></>
|
||||||
),
|
),
|
||||||
}}
|
}}
|
||||||
onChange={e => listeners(e as eventType)}
|
onChange={(e) => listeners(e as eventType)}
|
||||||
onBlur={e => {
|
onBlur={(e) => {
|
||||||
formatValueOnBlur(e as eventType);
|
formatValueOnBlur(e as eventType);
|
||||||
}}
|
}}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
|
@ -1,57 +1,57 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from 'react';
|
||||||
import QRCode from "react-qr-code";
|
import QRCode from 'react-qr-code';
|
||||||
import { TextP } from "../App-styles";
|
import { TextP } from '../styles/App-styles';
|
||||||
import { Box, Typography } from "@mui/material";
|
import { Box, Typography } from '@mui/material';
|
||||||
|
|
||||||
export const AddressQRCode = ({ targetAddress }) => {
|
export const AddressQRCode = ({ targetAddress }) => {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
gap: "10px",
|
gap: '10px',
|
||||||
alignItems: "center",
|
alignItems: 'center',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
marginTop: '10px'
|
marginTop: '10px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
cursor: "pointer",
|
cursor: 'pointer',
|
||||||
fontSize: "14px",
|
fontSize: '14px',
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setOpen((prev)=> !prev);
|
setOpen((prev) => !prev);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{open ? 'Hide QR code' :'See QR code'}
|
{open ? 'Hide QR code' : 'See QR code'}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
{open && (
|
{open && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
gap: "10px",
|
gap: '10px',
|
||||||
alignItems: "center",
|
alignItems: 'center',
|
||||||
justifyContent: "center",
|
justifyContent: 'center',
|
||||||
width: "100%",
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
gap: "10px",
|
gap: '10px',
|
||||||
width: "100%",
|
width: '100%',
|
||||||
alignItems: "center",
|
alignItems: 'center',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
marginTop: "20px",
|
marginTop: '20px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TextP
|
<TextP
|
||||||
sx={{
|
sx={{
|
||||||
textAlign: "center",
|
textAlign: 'center',
|
||||||
lineHeight: 1.2,
|
lineHeight: 1.2,
|
||||||
fontSize: "16px",
|
fontSize: '16px',
|
||||||
fontWeight: 500,
|
fontWeight: 500,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -15,7 +15,8 @@ import { SortablePinnedApps } from './SortablePinnedApps';
|
|||||||
import { extractComponents } from '../Chat/MessageDisplay';
|
import { extractComponents } from '../Chat/MessageDisplay';
|
||||||
import ArrowOutwardIcon from '@mui/icons-material/ArrowOutward';
|
import ArrowOutwardIcon from '@mui/icons-material/ArrowOutward';
|
||||||
import { AppsPrivate } from './AppsPrivate';
|
import { AppsPrivate } from './AppsPrivate';
|
||||||
import ThemeSelector from '../../styles/ThemeSelector';
|
import ThemeSelector from '../Theme/ThemeSelector';
|
||||||
|
|
||||||
export const AppsHomeDesktop = ({
|
export const AppsHomeDesktop = ({
|
||||||
setMode,
|
setMode,
|
||||||
myApp,
|
myApp,
|
||||||
|
@ -1,18 +1,32 @@
|
|||||||
import React, { useMemo, useRef, useState } from "react";
|
import React, { useMemo, useRef, useState } from 'react';
|
||||||
import TipTap from "./TipTap";
|
import TipTap from './TipTap';
|
||||||
import { AuthenticatedContainerInnerTop, CustomButton } from "../../App-styles";
|
import {
|
||||||
import { Box, CircularProgress } from "@mui/material";
|
AuthenticatedContainerInnerTop,
|
||||||
import { objectToBase64 } from "../../qdn/encryption/group-encryption";
|
CustomButton,
|
||||||
import ShortUniqueId from "short-unique-id";
|
} from '../../styles/App-styles';
|
||||||
import { LoadingSnackbar } from "../Snackbar/LoadingSnackbar";
|
import { Box, CircularProgress } from '@mui/material';
|
||||||
import { getBaseApi, getFee } from "../../background";
|
import { objectToBase64 } from '../../qdn/encryption/group-encryption';
|
||||||
import { decryptPublishes, getTempPublish, handleUnencryptedPublishes, saveTempPublish } from "./GroupAnnouncements";
|
import ShortUniqueId from 'short-unique-id';
|
||||||
import { AnnouncementList } from "./AnnouncementList";
|
import { LoadingSnackbar } from '../Snackbar/LoadingSnackbar';
|
||||||
import { Spacer } from "../../common/Spacer";
|
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 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 });
|
const uid = new ShortUniqueId({ length: 8 });
|
||||||
export const AnnouncementDiscussion = ({
|
export const AnnouncementDiscussion = ({
|
||||||
@ -23,28 +37,28 @@ export const AnnouncementDiscussion = ({
|
|||||||
setSelectedAnnouncement,
|
setSelectedAnnouncement,
|
||||||
show,
|
show,
|
||||||
myName,
|
myName,
|
||||||
isPrivate
|
isPrivate,
|
||||||
}) => {
|
}) => {
|
||||||
const [isSending, setIsSending] = useState(false);
|
const [isSending, setIsSending] = useState(false);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [isFocusedParent, setIsFocusedParent] = useState(false);
|
const [isFocusedParent, setIsFocusedParent] = useState(false);
|
||||||
|
|
||||||
const [comments, setComments] = useState([])
|
const [comments, setComments] = useState([]);
|
||||||
const [tempPublishedList, setTempPublishedList] = useState([])
|
const [tempPublishedList, setTempPublishedList] = useState([]);
|
||||||
const firstMountRef = useRef(false)
|
const firstMountRef = useRef(false);
|
||||||
const [data, setData] = useState({})
|
const [data, setData] = useState({});
|
||||||
const editorRef = useRef(null);
|
const editorRef = useRef(null);
|
||||||
const setEditorRef = (editorInstance) => {
|
const setEditorRef = (editorInstance) => {
|
||||||
editorRef.current = editorInstance;
|
editorRef.current = editorInstance;
|
||||||
};
|
};
|
||||||
|
|
||||||
const clearEditorContent = () => {
|
const clearEditorContent = () => {
|
||||||
if (editorRef.current) {
|
if (editorRef.current) {
|
||||||
editorRef.current.chain().focus().clearContent().run();
|
editorRef.current.chain().focus().clearContent().run();
|
||||||
if(isMobile){
|
if (isMobile) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
editorRef.current?.chain().blur().run();
|
editorRef.current?.chain().blur().run();
|
||||||
setIsFocusedParent(false)
|
setIsFocusedParent(false);
|
||||||
}, 200);
|
}, 200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -52,14 +66,16 @@ export const AnnouncementDiscussion = ({
|
|||||||
|
|
||||||
const getData = async ({ identifier, name }, isPrivate) => {
|
const getData = async ({ identifier, name }, isPrivate) => {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const res = await fetch(
|
const res = await fetch(
|
||||||
`${getBaseApiReact()}/arbitrary/DOCUMENT/${name}/${identifier}?encoding=base64`
|
`${getBaseApiReact()}/arbitrary/DOCUMENT/${name}/${identifier}?encoding=base64`
|
||||||
);
|
);
|
||||||
if(!res?.ok) return
|
if (!res?.ok) return;
|
||||||
const data = await res.text();
|
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];
|
const messageData = response[0];
|
||||||
setData((prev) => {
|
setData((prev) => {
|
||||||
return {
|
return {
|
||||||
@ -67,19 +83,19 @@ export const AnnouncementDiscussion = ({
|
|||||||
[`${identifier}-${name}`]: messageData,
|
[`${identifier}-${name}`]: messageData,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
const publishAnc = async ({ encryptedData, identifier }: any) => {
|
const publishAnc = async ({ encryptedData, identifier }: any) => {
|
||||||
try {
|
try {
|
||||||
if (!selectedAnnouncement) return;
|
if (!selectedAnnouncement) return;
|
||||||
|
|
||||||
return new Promise((res, rej) => {
|
return new Promise((res, rej) => {
|
||||||
window.sendMessage("publishGroupEncryptedResource", {
|
window
|
||||||
encryptedData,
|
.sendMessage('publishGroupEncryptedResource', {
|
||||||
identifier,
|
encryptedData,
|
||||||
})
|
identifier,
|
||||||
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (!response?.error) {
|
if (!response?.error) {
|
||||||
res(response);
|
res(response);
|
||||||
@ -88,63 +104,60 @@ export const AnnouncementDiscussion = ({
|
|||||||
rej(response.error);
|
rej(response.error);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
rej(error.message || "An error occurred");
|
rej(error.message || 'An error occurred');
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
const setTempData = async ()=> {
|
const setTempData = async () => {
|
||||||
try {
|
try {
|
||||||
const getTempAnnouncements = await getTempPublish()
|
const getTempAnnouncements = await getTempPublish();
|
||||||
if(getTempAnnouncements[tempKey]){
|
if (getTempAnnouncements[tempKey]) {
|
||||||
let tempData = []
|
let tempData = [];
|
||||||
Object.keys(getTempAnnouncements[tempKey] || {}).map((key)=> {
|
Object.keys(getTempAnnouncements[tempKey] || {}).map((key) => {
|
||||||
const value = getTempAnnouncements[tempKey][key]
|
const value = getTempAnnouncements[tempKey][key];
|
||||||
if(value.data?.announcementId === selectedAnnouncement.identifier){
|
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 () => {
|
const publishComment = async () => {
|
||||||
try {
|
try {
|
||||||
pauseAllQueues()
|
pauseAllQueues();
|
||||||
const fee = await getFee('ARBITRARY')
|
const fee = await getFee('ARBITRARY');
|
||||||
await show({
|
await show({
|
||||||
message: "Would you like to perform a ARBITRARY transaction?" ,
|
message: 'Would you like to perform a ARBITRARY transaction?',
|
||||||
publishFee: fee.fee + ' QORT'
|
publishFee: fee.fee + ' QORT',
|
||||||
})
|
});
|
||||||
if (isSending) return;
|
if (isSending) return;
|
||||||
if (editorRef.current) {
|
if (editorRef.current) {
|
||||||
const htmlContent = editorRef.current.getHTML();
|
const htmlContent = editorRef.current.getHTML();
|
||||||
|
|
||||||
if (!htmlContent?.trim() || htmlContent?.trim() === "<p></p>") return;
|
if (!htmlContent?.trim() || htmlContent?.trim() === '<p></p>') return;
|
||||||
setIsSending(true);
|
setIsSending(true);
|
||||||
const message = {
|
const message = {
|
||||||
version: 1,
|
version: 1,
|
||||||
extra: {},
|
extra: {},
|
||||||
message: htmlContent,
|
message: htmlContent,
|
||||||
};
|
};
|
||||||
const secretKeyObject = isPrivate === false ? null : await getSecretKey(false, true);
|
const secretKeyObject =
|
||||||
const message64: any = await objectToBase64(message);
|
isPrivate === false ? null : await getSecretKey(false, true);
|
||||||
|
const message64: any = await objectToBase64(message);
|
||||||
const encryptSingle = isPrivate === false ? message64 : await encryptChatMessage(
|
|
||||||
message64,
|
const encryptSingle =
|
||||||
secretKeyObject
|
isPrivate === false
|
||||||
);
|
? message64
|
||||||
|
: await encryptChatMessage(message64, secretKeyObject);
|
||||||
const randomUid = uid.rnd();
|
const randomUid = uid.rnd();
|
||||||
const identifier = `cm-${selectedAnnouncement.identifier}-${randomUid}`;
|
const identifier = `cm-${selectedAnnouncement.identifier}-${randomUid}`;
|
||||||
const res = await publishAnc({
|
const res = await publishAnc({
|
||||||
encryptedData: encryptSingle,
|
encryptedData: encryptSingle,
|
||||||
identifier
|
identifier,
|
||||||
});
|
});
|
||||||
|
|
||||||
const dataToSaveToStorage = {
|
const dataToSaveToStorage = {
|
||||||
@ -153,18 +166,18 @@ export const AnnouncementDiscussion = ({
|
|||||||
service: 'DOCUMENT',
|
service: 'DOCUMENT',
|
||||||
tempData: message,
|
tempData: message,
|
||||||
created: Date.now(),
|
created: Date.now(),
|
||||||
announcementId: selectedAnnouncement.identifier
|
announcementId: selectedAnnouncement.identifier,
|
||||||
}
|
};
|
||||||
await saveTempPublish({data: dataToSaveToStorage, key: tempKey})
|
await saveTempPublish({ data: dataToSaveToStorage, key: tempKey });
|
||||||
setTempData()
|
setTempData();
|
||||||
|
|
||||||
clearEditorContent();
|
clearEditorContent();
|
||||||
}
|
}
|
||||||
// send chat message
|
// send chat message
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
} finally {
|
} finally {
|
||||||
resumeAllQueues()
|
resumeAllQueues();
|
||||||
setIsSending(false);
|
setIsSending(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -172,7 +185,6 @@ export const AnnouncementDiscussion = ({
|
|||||||
const getComments = React.useCallback(
|
const getComments = React.useCallback(
|
||||||
async (selectedAnnouncement, isPrivate) => {
|
async (selectedAnnouncement, isPrivate) => {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
|
||||||
const offset = 0;
|
const offset = 0;
|
||||||
@ -181,13 +193,13 @@ export const AnnouncementDiscussion = ({
|
|||||||
const identifier = `cm-${selectedAnnouncement.identifier}`;
|
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 url = `${getBaseApiReact()}${getArbitraryEndpointReact()}?mode=ALL&service=DOCUMENT&identifier=${identifier}&limit=20&includemetadata=false&offset=${offset}&reverse=true&prefix=true`;
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
method: "GET",
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const responseData = await response.json();
|
const responseData = await response.json();
|
||||||
setTempData()
|
setTempData();
|
||||||
setComments(responseData);
|
setComments(responseData);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
for (const data of responseData) {
|
for (const data of responseData) {
|
||||||
@ -203,119 +215,122 @@ export const AnnouncementDiscussion = ({
|
|||||||
[secretKey]
|
[secretKey]
|
||||||
);
|
);
|
||||||
|
|
||||||
const loadMore = async()=> {
|
const loadMore = async () => {
|
||||||
try {
|
try {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
|
||||||
const offset = comments.length
|
const offset = comments.length;
|
||||||
const identifier = `cm-${selectedAnnouncement.identifier}`;
|
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 url = `${getBaseApiReact()}${getArbitraryEndpointReact()}?mode=ALL&service=DOCUMENT&identifier=${identifier}&limit=20&includemetadata=false&offset=${offset}&reverse=true&prefix=true`;
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
method: "GET",
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const responseData = await response.json();
|
const responseData = await response.json();
|
||||||
|
|
||||||
setComments((prev)=> [...prev, ...responseData]);
|
setComments((prev) => [...prev, ...responseData]);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
for (const data of responseData) {
|
for (const data of responseData) {
|
||||||
getData({ name: data.name, identifier: data.identifier }, isPrivate);
|
getData({ name: data.name, identifier: data.identifier }, isPrivate);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {}
|
||||||
|
};
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const combinedListTempAndReal = useMemo(() => {
|
const combinedListTempAndReal = useMemo(() => {
|
||||||
// Combine the two lists
|
// Combine the two lists
|
||||||
const combined = [...tempPublishedList, ...comments];
|
const combined = [...tempPublishedList, ...comments];
|
||||||
|
|
||||||
// Remove duplicates based on the "identifier"
|
// Remove duplicates based on the "identifier"
|
||||||
const uniqueItems = new Map();
|
const uniqueItems = new Map();
|
||||||
combined.forEach(item => {
|
combined.forEach((item) => {
|
||||||
uniqueItems.set(item.identifier, item); // This will overwrite duplicates, keeping the last occurrence
|
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
|
// 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;
|
return sortedList;
|
||||||
}, [tempPublishedList, comments]);
|
}, [tempPublishedList, comments]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if(!secretKey && isPrivate) return
|
if (!secretKey && isPrivate) return;
|
||||||
if (selectedAnnouncement && !firstMountRef.current && isPrivate !== null) {
|
if (selectedAnnouncement && !firstMountRef.current && isPrivate !== null) {
|
||||||
getComments(selectedAnnouncement, isPrivate);
|
getComments(selectedAnnouncement, isPrivate);
|
||||||
firstMountRef.current = true
|
firstMountRef.current = true;
|
||||||
}
|
}
|
||||||
}, [selectedAnnouncement, secretKey, isPrivate]);
|
}, [selectedAnnouncement, secretKey, isPrivate]);
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
height: isMobile ? '100%' : "100%",
|
height: isMobile ? '100%' : '100%',
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
width: "100%",
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{
|
<div
|
||||||
position: "relative",
|
style={{
|
||||||
width: "100%",
|
position: 'relative',
|
||||||
display: "flex",
|
width: '100%',
|
||||||
flexDirection: "column",
|
display: 'flex',
|
||||||
flexShrink: 0,
|
flexDirection: 'column',
|
||||||
}}>
|
flexShrink: 0,
|
||||||
|
}}
|
||||||
<AuthenticatedContainerInnerTop sx={{
|
>
|
||||||
height: '20px'
|
<AuthenticatedContainerInnerTop
|
||||||
}}>
|
sx={{
|
||||||
<ArrowBackIcon onClick={()=> setSelectedAnnouncement(null)} sx={{
|
height: '20px',
|
||||||
cursor: 'pointer'
|
}}
|
||||||
}} />
|
>
|
||||||
</AuthenticatedContainerInnerTop>
|
<ArrowBackIcon
|
||||||
|
onClick={() => setSelectedAnnouncement(null)}
|
||||||
|
sx={{
|
||||||
|
cursor: 'pointer',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</AuthenticatedContainerInnerTop>
|
||||||
<Spacer height="20px" />
|
<Spacer height="20px" />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<AnnouncementList
|
<AnnouncementList
|
||||||
announcementData={data}
|
announcementData={data}
|
||||||
initialMessages={combinedListTempAndReal}
|
initialMessages={combinedListTempAndReal}
|
||||||
setSelectedAnnouncement={()=> {}}
|
setSelectedAnnouncement={() => {}}
|
||||||
disableComment
|
disableComment
|
||||||
showLoadMore={comments.length > 0 && comments.length % 20 === 0}
|
showLoadMore={comments.length > 0 && comments.length % 20 === 0}
|
||||||
loadMore={loadMore}
|
loadMore={loadMore}
|
||||||
myName={myName}
|
myName={myName}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
// position: 'fixed',
|
// position: 'fixed',
|
||||||
// bottom: '0px',
|
// bottom: '0px',
|
||||||
backgroundColor: "#232428",
|
backgroundColor: '#232428',
|
||||||
minHeight: isMobile ? "0px" : "150px",
|
minHeight: isMobile ? '0px' : '150px',
|
||||||
maxHeight: isMobile ? "auto" : "400px",
|
maxHeight: isMobile ? 'auto' : '400px',
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
overflow: "hidden",
|
overflow: 'hidden',
|
||||||
width: "100%",
|
width: '100%',
|
||||||
boxSizing: "border-box",
|
boxSizing: 'border-box',
|
||||||
padding: isMobile ? "10px": "20px",
|
padding: isMobile ? '10px' : '20px',
|
||||||
position: isFocusedParent ? 'fixed' : 'relative',
|
position: isFocusedParent ? 'fixed' : 'relative',
|
||||||
bottom: isFocusedParent ? '0px' : 'unset',
|
bottom: isFocusedParent ? '0px' : 'unset',
|
||||||
top: isFocusedParent ? '0px' : 'unset',
|
top: isFocusedParent ? '0px' : 'unset',
|
||||||
zIndex: isFocusedParent ? 5 : 'unset',
|
zIndex: isFocusedParent ? 5 : 'unset',
|
||||||
flexShrink:0,
|
flexShrink: 0,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
// height: '100%',
|
// height: '100%',
|
||||||
flexGrow: isMobile && 1,
|
flexGrow: isMobile && 1,
|
||||||
overflow: "auto",
|
overflow: 'auto',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TipTap
|
<TipTap
|
||||||
@ -323,79 +338,78 @@ export const AnnouncementDiscussion = ({
|
|||||||
onEnter={publishComment}
|
onEnter={publishComment}
|
||||||
disableEnter
|
disableEnter
|
||||||
maxHeightOffset="60px"
|
maxHeightOffset="60px"
|
||||||
isFocusedParent={isFocusedParent} setIsFocusedParent={setIsFocusedParent}
|
isFocusedParent={isFocusedParent}
|
||||||
|
setIsFocusedParent={setIsFocusedParent}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Box sx={{
|
<Box
|
||||||
display: 'flex',
|
sx={{
|
||||||
width: '100&',
|
display: 'flex',
|
||||||
gap: '10px',
|
width: '100&',
|
||||||
justifyContent: 'center',
|
gap: '10px',
|
||||||
flexShrink: 0,
|
justifyContent: 'center',
|
||||||
position: 'relative',
|
|
||||||
}}>
|
|
||||||
{isFocusedParent && (
|
|
||||||
<CustomButton
|
|
||||||
onClick={()=> {
|
|
||||||
if(isSending) return
|
|
||||||
setIsFocusedParent(false)
|
|
||||||
clearEditorContent()
|
|
||||||
// Unfocus the editor
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
marginTop: 'auto',
|
|
||||||
alignSelf: 'center',
|
|
||||||
cursor: isSending ? 'default' : 'pointer',
|
|
||||||
flexShrink: 0,
|
|
||||||
padding: isMobile && '5px',
|
|
||||||
fontSize: isMobile && '14px',
|
|
||||||
background: 'red',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
|
|
||||||
{` Close`}
|
|
||||||
</CustomButton>
|
|
||||||
|
|
||||||
)}
|
|
||||||
<CustomButton
|
|
||||||
onClick={() => {
|
|
||||||
if (isSending) return;
|
|
||||||
publishComment();
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
marginTop: "auto",
|
|
||||||
alignSelf: "center",
|
|
||||||
cursor: isSending ? "default" : "pointer",
|
|
||||||
background: isSending && "rgba(0, 0, 0, 0.8)",
|
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
padding: isMobile && '5px',
|
position: 'relative',
|
||||||
fontSize: isMobile && '14px'
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isSending && (
|
{isFocusedParent && (
|
||||||
<CircularProgress
|
<CustomButton
|
||||||
size={18}
|
onClick={() => {
|
||||||
sx={{
|
if (isSending) return;
|
||||||
position: "absolute",
|
setIsFocusedParent(false);
|
||||||
top: "50%",
|
clearEditorContent();
|
||||||
left: "50%",
|
// Unfocus the editor
|
||||||
marginTop: "-12px",
|
|
||||||
marginLeft: "-12px",
|
|
||||||
color: "white",
|
|
||||||
}}
|
}}
|
||||||
/>
|
style={{
|
||||||
|
marginTop: 'auto',
|
||||||
|
alignSelf: 'center',
|
||||||
|
cursor: isSending ? 'default' : 'pointer',
|
||||||
|
flexShrink: 0,
|
||||||
|
padding: isMobile && '5px',
|
||||||
|
fontSize: isMobile && '14px',
|
||||||
|
background: 'red',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{` Close`}
|
||||||
|
</CustomButton>
|
||||||
)}
|
)}
|
||||||
{` Publish Comment`}
|
<CustomButton
|
||||||
</CustomButton>
|
onClick={() => {
|
||||||
|
if (isSending) return;
|
||||||
</Box>
|
publishComment();
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
marginTop: 'auto',
|
||||||
|
alignSelf: 'center',
|
||||||
|
cursor: isSending ? 'default' : 'pointer',
|
||||||
|
background: isSending && 'rgba(0, 0, 0, 0.8)',
|
||||||
|
flexShrink: 0,
|
||||||
|
padding: isMobile && '5px',
|
||||||
|
fontSize: isMobile && '14px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{isSending && (
|
||||||
|
<CircularProgress
|
||||||
|
size={18}
|
||||||
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
marginTop: '-12px',
|
||||||
|
marginLeft: '-12px',
|
||||||
|
color: 'white',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{` Publish Comment`}
|
||||||
|
</CustomButton>
|
||||||
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<LoadingSnackbar
|
<LoadingSnackbar
|
||||||
open={isLoading}
|
open={isLoading}
|
||||||
info={{
|
info={{
|
||||||
message: "Loading comments... please wait.",
|
message: 'Loading comments... please wait.',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import React, { useCallback, useState, useEffect, useRef } from "react";
|
import React, { useCallback, useState, useEffect, useRef } from 'react';
|
||||||
import {
|
import {
|
||||||
List,
|
List,
|
||||||
AutoSizer,
|
AutoSizer,
|
||||||
CellMeasurerCache,
|
CellMeasurerCache,
|
||||||
CellMeasurer,
|
CellMeasurer,
|
||||||
} from "react-virtualized";
|
} from 'react-virtualized';
|
||||||
import { AnnouncementItem } from "./AnnouncementItem";
|
import { AnnouncementItem } from './AnnouncementItem';
|
||||||
import { Box } from "@mui/material";
|
import { Box } from '@mui/material';
|
||||||
import { CustomButton } from "../../App-styles";
|
import { CustomButton } from '../../styles/App-styles';
|
||||||
|
|
||||||
const cache = new CellMeasurerCache({
|
const cache = new CellMeasurerCache({
|
||||||
fixedWidth: true,
|
fixedWidth: true,
|
||||||
@ -21,9 +21,8 @@ export const AnnouncementList = ({
|
|||||||
disableComment,
|
disableComment,
|
||||||
showLoadMore,
|
showLoadMore,
|
||||||
loadMore,
|
loadMore,
|
||||||
myName
|
myName,
|
||||||
}) => {
|
}) => {
|
||||||
|
|
||||||
const listRef = useRef();
|
const listRef = useRef();
|
||||||
const [messages, setMessages] = useState(initialMessages);
|
const [messages, setMessages] = useState(initialMessages);
|
||||||
|
|
||||||
@ -35,39 +34,44 @@ export const AnnouncementList = ({
|
|||||||
setMessages(initialMessages);
|
setMessages(initialMessages);
|
||||||
}, [initialMessages]);
|
}, [initialMessages]);
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: "relative",
|
position: 'relative',
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
width: "100%",
|
width: '100%',
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
flexShrink: 1,
|
flexShrink: 1,
|
||||||
overflow: 'auto'
|
overflow: 'auto',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{messages.map((message) => {
|
{messages.map((message) => {
|
||||||
const messageData = message?.tempData ? {
|
const messageData = message?.tempData
|
||||||
decryptedData: message?.tempData
|
? {
|
||||||
} : announcementData[`${message.identifier}-${message.name}`];
|
decryptedData: message?.tempData,
|
||||||
|
}
|
||||||
|
: announcementData[`${message.identifier}-${message.name}`];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<div
|
||||||
<div
|
key={message?.identifier}
|
||||||
key={message?.identifier}
|
style={{
|
||||||
style={{
|
marginBottom: '10px',
|
||||||
marginBottom: "10px",
|
width: '100%',
|
||||||
width: "100%",
|
display: 'flex',
|
||||||
display: "flex",
|
flexDirection: 'column',
|
||||||
flexDirection: "column",
|
alignItems: 'center',
|
||||||
alignItems: "center",
|
}}
|
||||||
}}
|
>
|
||||||
>
|
<AnnouncementItem
|
||||||
<AnnouncementItem myName={myName} disableComment={disableComment} setSelectedAnnouncement={setSelectedAnnouncement} message={message} messageData={messageData} />
|
myName={myName}
|
||||||
</div>
|
disableComment={disableComment}
|
||||||
|
setSelectedAnnouncement={setSelectedAnnouncement}
|
||||||
|
message={message}
|
||||||
|
messageData={messageData}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{/* <AutoSizer>
|
{/* <AutoSizer>
|
||||||
@ -83,16 +87,20 @@ export const AnnouncementList = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</AutoSizer> */}
|
</AutoSizer> */}
|
||||||
<Box sx={{
|
<Box
|
||||||
width: '100%',
|
sx={{
|
||||||
marginTop: '25px',
|
width: '100%',
|
||||||
display: 'flex',
|
marginTop: '25px',
|
||||||
justifyContent: 'center'
|
display: 'flex',
|
||||||
}}>
|
justifyContent: 'center',
|
||||||
{showLoadMore && (
|
}}
|
||||||
<CustomButton onClick={loadMore}>Load older announcements</CustomButton>
|
>
|
||||||
)}
|
{showLoadMore && (
|
||||||
</Box>
|
<CustomButton onClick={loadMore}>
|
||||||
|
Load older announcements
|
||||||
|
</CustomButton>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -4,30 +4,33 @@ import React, {
|
|||||||
useMemo,
|
useMemo,
|
||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from 'react';
|
||||||
import { CreateCommonSecret } from "./CreateCommonSecret";
|
import { CreateCommonSecret } from './CreateCommonSecret';
|
||||||
import { reusableGet } from "../../qdn/publish/pubish";
|
import { reusableGet } from '../../qdn/publish/pubish';
|
||||||
import { uint8ArrayToObject } from "../../backgroundFunctions/encryption";
|
import { uint8ArrayToObject } from '../../backgroundFunctions/encryption';
|
||||||
import {
|
import {
|
||||||
base64ToUint8Array,
|
base64ToUint8Array,
|
||||||
objectToBase64,
|
objectToBase64,
|
||||||
} from "../../qdn/encryption/group-encryption";
|
} from '../../qdn/encryption/group-encryption';
|
||||||
import { ChatContainerComp } from "./ChatContainer";
|
import { ChatContainerComp } from './ChatContainer';
|
||||||
import { ChatList } from "./ChatList";
|
import { ChatList } from './ChatList';
|
||||||
import "@chatscope/chat-ui-kit-styles/dist/default/styles.min.css";
|
import '@chatscope/chat-ui-kit-styles/dist/default/styles.min.css';
|
||||||
import Tiptap from "./TipTap";
|
import Tiptap from './TipTap';
|
||||||
import { AuthenticatedContainerInnerTop, CustomButton } from "../../App-styles";
|
import {
|
||||||
import CircularProgress from "@mui/material/CircularProgress";
|
AuthenticatedContainerInnerTop,
|
||||||
import { getBaseApi, getFee } from "../../background";
|
CustomButton,
|
||||||
import { LoadingSnackbar } from "../Snackbar/LoadingSnackbar";
|
} from '../../styles/App-styles';
|
||||||
import { Box, Typography } from "@mui/material";
|
import CircularProgress from '@mui/material/CircularProgress';
|
||||||
import { Spacer } from "../../common/Spacer";
|
import { getBaseApi, getFee } from '../../background';
|
||||||
import ShortUniqueId from "short-unique-id";
|
import { LoadingSnackbar } from '../Snackbar/LoadingSnackbar';
|
||||||
import { AnnouncementList } from "./AnnouncementList";
|
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 });
|
const uid = new ShortUniqueId({ length: 8 });
|
||||||
import CampaignIcon from "@mui/icons-material/Campaign";
|
import CampaignIcon from '@mui/icons-material/Campaign';
|
||||||
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
|
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
|
||||||
import { AnnouncementDiscussion } from "./AnnouncementDiscussion";
|
import { AnnouncementDiscussion } from './AnnouncementDiscussion';
|
||||||
import {
|
import {
|
||||||
MyContext,
|
MyContext,
|
||||||
getArbitraryEndpointReact,
|
getArbitraryEndpointReact,
|
||||||
@ -35,11 +38,11 @@ import {
|
|||||||
isMobile,
|
isMobile,
|
||||||
pauseAllQueues,
|
pauseAllQueues,
|
||||||
resumeAllQueues,
|
resumeAllQueues,
|
||||||
} from "../../App";
|
} from '../../App';
|
||||||
import { RequestQueueWithPromise } from "../../utils/queue/queue";
|
import { RequestQueueWithPromise } from '../../utils/queue/queue';
|
||||||
import { CustomizedSnackbars } from "../Snackbar/Snackbar";
|
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
|
||||||
import { addDataPublishesFunc, getDataPublishesFunc } from "../Group/Group";
|
import { addDataPublishesFunc, getDataPublishesFunc } from '../Group/Group';
|
||||||
import { getRootHeight } from "../../utils/mobile/mobileUtils";
|
import { getRootHeight } from '../../utils/mobile/mobileUtils';
|
||||||
|
|
||||||
export const requestQueueCommentCount = new RequestQueueWithPromise(3);
|
export const requestQueueCommentCount = new RequestQueueWithPromise(3);
|
||||||
export const requestQueuePublishedAccouncements = new RequestQueueWithPromise(
|
export const requestQueuePublishedAccouncements = new RequestQueueWithPromise(
|
||||||
@ -48,10 +51,11 @@ export const requestQueuePublishedAccouncements = new RequestQueueWithPromise(
|
|||||||
|
|
||||||
export const saveTempPublish = async ({ data, key }: any) => {
|
export const saveTempPublish = async ({ data, key }: any) => {
|
||||||
return new Promise((res, rej) => {
|
return new Promise((res, rej) => {
|
||||||
window.sendMessage("saveTempPublish", {
|
window
|
||||||
data,
|
.sendMessage('saveTempPublish', {
|
||||||
key,
|
data,
|
||||||
})
|
key,
|
||||||
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (!response?.error) {
|
if (!response?.error) {
|
||||||
res(response);
|
res(response);
|
||||||
@ -60,37 +64,37 @@ export const saveTempPublish = async ({ data, key }: any) => {
|
|||||||
rej(response.error);
|
rej(response.error);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
rej(error.message || "An error occurred");
|
rej(error.message || 'An error occurred');
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getTempPublish = async () => {
|
export const getTempPublish = async () => {
|
||||||
return new Promise((res, rej) => {
|
return new Promise((res, rej) => {
|
||||||
window.sendMessage("getTempPublish", {})
|
window
|
||||||
.then((response) => {
|
.sendMessage('getTempPublish', {})
|
||||||
if (!response?.error) {
|
.then((response) => {
|
||||||
res(response);
|
if (!response?.error) {
|
||||||
return;
|
res(response);
|
||||||
}
|
return;
|
||||||
rej(response.error);
|
}
|
||||||
})
|
rej(response.error);
|
||||||
.catch((error) => {
|
})
|
||||||
rej(error.message || "An error occurred");
|
.catch((error) => {
|
||||||
});
|
rej(error.message || 'An error occurred');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const decryptPublishes = async (encryptedMessages: any[], secretKey) => {
|
export const decryptPublishes = async (encryptedMessages: any[], secretKey) => {
|
||||||
try {
|
try {
|
||||||
return await new Promise((res, rej) => {
|
return await new Promise((res, rej) => {
|
||||||
window.sendMessage("decryptSingleForPublishes", {
|
window
|
||||||
data: encryptedMessages,
|
.sendMessage('decryptSingleForPublishes', {
|
||||||
secretKeyObject: secretKey,
|
data: encryptedMessages,
|
||||||
skipDecodeBase64: true,
|
secretKeyObject: secretKey,
|
||||||
})
|
skipDecodeBase64: true,
|
||||||
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (!response?.error) {
|
if (!response?.error) {
|
||||||
res(response);
|
res(response);
|
||||||
@ -99,26 +103,23 @@ export const decryptPublishes = async (encryptedMessages: any[], secretKey) => {
|
|||||||
rej(response.error);
|
rej(response.error);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
rej(error.message || "An error occurred");
|
rej(error.message || 'An error occurred');
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
};
|
};
|
||||||
export const handleUnencryptedPublishes = (publishes) => {
|
export const handleUnencryptedPublishes = (publishes) => {
|
||||||
let publishesData = []
|
let publishesData = [];
|
||||||
publishes.forEach((pub)=> {
|
publishes.forEach((pub) => {
|
||||||
try {
|
try {
|
||||||
const decryptToUnit8Array = base64ToUint8Array(pub);
|
const decryptToUnit8Array = base64ToUint8Array(pub);
|
||||||
const decodedData = uint8ArrayToObject(decryptToUnit8Array);
|
const decodedData = uint8ArrayToObject(decryptToUnit8Array);
|
||||||
if(decodedData){
|
if (decodedData) {
|
||||||
publishesData.push({decryptedData: decodedData})
|
publishesData.push({ decryptedData: decodedData });
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {}
|
||||||
|
});
|
||||||
}
|
return publishesData;
|
||||||
})
|
|
||||||
return publishesData
|
|
||||||
};
|
};
|
||||||
export const GroupAnnouncements = ({
|
export const GroupAnnouncements = ({
|
||||||
selectedGroup,
|
selectedGroup,
|
||||||
@ -130,7 +131,7 @@ export const GroupAnnouncements = ({
|
|||||||
isAdmin,
|
isAdmin,
|
||||||
hide,
|
hide,
|
||||||
myName,
|
myName,
|
||||||
isPrivate
|
isPrivate,
|
||||||
}) => {
|
}) => {
|
||||||
const [messages, setMessages] = useState([]);
|
const [messages, setMessages] = useState([]);
|
||||||
const [isSending, setIsSending] = useState(false);
|
const [isSending, setIsSending] = useState(false);
|
||||||
@ -159,12 +160,15 @@ export const GroupAnnouncements = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!selectedGroup) return;
|
if (!selectedGroup) return;
|
||||||
(async () => {
|
(async () => {
|
||||||
const res = await getDataPublishesFunc(selectedGroup, "anc");
|
const res = await getDataPublishesFunc(selectedGroup, 'anc');
|
||||||
dataPublishes.current = res || {};
|
dataPublishes.current = res || {};
|
||||||
})();
|
})();
|
||||||
}, [selectedGroup]);
|
}, [selectedGroup]);
|
||||||
|
|
||||||
const getAnnouncementData = async ({ identifier, name, resource }, isPrivate) => {
|
const getAnnouncementData = async (
|
||||||
|
{ identifier, name, resource },
|
||||||
|
isPrivate
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
let data = dataPublishes.current[`${name}-${identifier}`];
|
let data = dataPublishes.current[`${name}-${identifier}`];
|
||||||
if (
|
if (
|
||||||
@ -179,14 +183,17 @@ export const GroupAnnouncements = ({
|
|||||||
});
|
});
|
||||||
if (!res?.ok) return;
|
if (!res?.ok) return;
|
||||||
data = await res.text();
|
data = await res.text();
|
||||||
await addDataPublishesFunc({ ...resource, data }, selectedGroup, "anc");
|
await addDataPublishesFunc({ ...resource, data }, selectedGroup, 'anc');
|
||||||
} else {
|
} else {
|
||||||
data = data.data;
|
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];
|
const messageData = response[0];
|
||||||
if(!messageData) return
|
if (!messageData) return;
|
||||||
setAnnouncementData((prev) => {
|
setAnnouncementData((prev) => {
|
||||||
return {
|
return {
|
||||||
...prev,
|
...prev,
|
||||||
@ -194,12 +201,17 @@ export const GroupAnnouncements = ({
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("error", error);
|
console.error('error', error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if ((!secretKey && isPrivate) || hasInitializedWebsocket.current || isPrivate === null) return;
|
if (
|
||||||
|
(!secretKey && isPrivate) ||
|
||||||
|
hasInitializedWebsocket.current ||
|
||||||
|
isPrivate === null
|
||||||
|
)
|
||||||
|
return;
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
// initWebsocketMessageGroup()
|
// initWebsocketMessageGroup()
|
||||||
hasInitializedWebsocket.current = true;
|
hasInitializedWebsocket.current = true;
|
||||||
@ -208,10 +220,11 @@ export const GroupAnnouncements = ({
|
|||||||
const encryptChatMessage = async (data: string, secretKeyObject: any) => {
|
const encryptChatMessage = async (data: string, secretKeyObject: any) => {
|
||||||
try {
|
try {
|
||||||
return new Promise((res, rej) => {
|
return new Promise((res, rej) => {
|
||||||
window.sendMessage("encryptSingle", {
|
window
|
||||||
data,
|
.sendMessage('encryptSingle', {
|
||||||
secretKeyObject,
|
data,
|
||||||
})
|
secretKeyObject,
|
||||||
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (!response?.error) {
|
if (!response?.error) {
|
||||||
res(response);
|
res(response);
|
||||||
@ -220,19 +233,19 @@ export const GroupAnnouncements = ({
|
|||||||
rej(response.error);
|
rej(response.error);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
rej(error.message || "An error occurred");
|
rej(error.message || 'An error occurred');
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
const publishAnc = async ({ encryptedData, identifier }: any) => {
|
const publishAnc = async ({ encryptedData, identifier }: any) => {
|
||||||
return new Promise((res, rej) => {
|
return new Promise((res, rej) => {
|
||||||
window.sendMessage("publishGroupEncryptedResource", {
|
window
|
||||||
encryptedData,
|
.sendMessage('publishGroupEncryptedResource', {
|
||||||
identifier,
|
encryptedData,
|
||||||
})
|
identifier,
|
||||||
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (!response?.error) {
|
if (!response?.error) {
|
||||||
res(response);
|
res(response);
|
||||||
@ -241,9 +254,8 @@ export const GroupAnnouncements = ({
|
|||||||
rej(response.error);
|
rej(response.error);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
rej(error.message || "An error occurred");
|
rej(error.message || 'An error occurred');
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const clearEditorContent = () => {
|
const clearEditorContent = () => {
|
||||||
@ -255,7 +267,7 @@ export const GroupAnnouncements = ({
|
|||||||
setIsFocusedParent(false);
|
setIsFocusedParent(false);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
triggerRerender();
|
triggerRerender();
|
||||||
}, 300);
|
}, 300);
|
||||||
}, 200);
|
}, 200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -266,10 +278,12 @@ export const GroupAnnouncements = ({
|
|||||||
const getTempAnnouncements = await getTempPublish();
|
const getTempAnnouncements = await getTempPublish();
|
||||||
if (getTempAnnouncements?.announcement) {
|
if (getTempAnnouncements?.announcement) {
|
||||||
let tempData = [];
|
let tempData = [];
|
||||||
Object.keys(getTempAnnouncements?.announcement || {}).filter((annKey)=> annKey?.startsWith(`grp-${selectedGroup}-anc`)).map((key) => {
|
Object.keys(getTempAnnouncements?.announcement || {})
|
||||||
const value = getTempAnnouncements?.announcement[key];
|
.filter((annKey) => annKey?.startsWith(`grp-${selectedGroup}-anc`))
|
||||||
tempData.push(value.data);
|
.map((key) => {
|
||||||
});
|
const value = getTempAnnouncements?.announcement[key];
|
||||||
|
tempData.push(value.data);
|
||||||
|
});
|
||||||
setTempPublishedList(tempData);
|
setTempPublishedList(tempData);
|
||||||
}
|
}
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
@ -278,27 +292,28 @@ export const GroupAnnouncements = ({
|
|||||||
const publishAnnouncement = async () => {
|
const publishAnnouncement = async () => {
|
||||||
try {
|
try {
|
||||||
pauseAllQueues();
|
pauseAllQueues();
|
||||||
const fee = await getFee("ARBITRARY");
|
const fee = await getFee('ARBITRARY');
|
||||||
await show({
|
await show({
|
||||||
message: "Would you like to perform a ARBITRARY transaction?",
|
message: 'Would you like to perform a ARBITRARY transaction?',
|
||||||
publishFee: fee.fee + " QORT",
|
publishFee: fee.fee + ' QORT',
|
||||||
});
|
});
|
||||||
if (isSending) return;
|
if (isSending) return;
|
||||||
if (editorRef.current) {
|
if (editorRef.current) {
|
||||||
const htmlContent = editorRef.current.getHTML();
|
const htmlContent = editorRef.current.getHTML();
|
||||||
if (!htmlContent?.trim() || htmlContent?.trim() === "<p></p>") return;
|
if (!htmlContent?.trim() || htmlContent?.trim() === '<p></p>') return;
|
||||||
setIsSending(true);
|
setIsSending(true);
|
||||||
const message = {
|
const message = {
|
||||||
version: 1,
|
version: 1,
|
||||||
extra: {},
|
extra: {},
|
||||||
message: htmlContent,
|
message: htmlContent,
|
||||||
};
|
};
|
||||||
const secretKeyObject = isPrivate === false ? null : await getSecretKey(false, true);
|
const secretKeyObject =
|
||||||
const message64: any = await objectToBase64(message);
|
isPrivate === false ? null : await getSecretKey(false, true);
|
||||||
const encryptSingle = isPrivate === false ? message64 : await encryptChatMessage(
|
const message64: any = await objectToBase64(message);
|
||||||
message64,
|
const encryptSingle =
|
||||||
secretKeyObject
|
isPrivate === false
|
||||||
);
|
? message64
|
||||||
|
: await encryptChatMessage(message64, secretKeyObject);
|
||||||
const randomUid = uid.rnd();
|
const randomUid = uid.rnd();
|
||||||
const identifier = `grp-${selectedGroup}-anc-${randomUid}`;
|
const identifier = `grp-${selectedGroup}-anc-${randomUid}`;
|
||||||
const res = await publishAnc({
|
const res = await publishAnc({
|
||||||
@ -309,13 +324,13 @@ export const GroupAnnouncements = ({
|
|||||||
const dataToSaveToStorage = {
|
const dataToSaveToStorage = {
|
||||||
name: myName,
|
name: myName,
|
||||||
identifier,
|
identifier,
|
||||||
service: "DOCUMENT",
|
service: 'DOCUMENT',
|
||||||
tempData: message,
|
tempData: message,
|
||||||
created: Date.now(),
|
created: Date.now(),
|
||||||
};
|
};
|
||||||
await saveTempPublish({
|
await saveTempPublish({
|
||||||
data: dataToSaveToStorage,
|
data: dataToSaveToStorage,
|
||||||
key: "announcement",
|
key: 'announcement',
|
||||||
});
|
});
|
||||||
setTempData(selectedGroup);
|
setTempData(selectedGroup);
|
||||||
clearEditorContent();
|
clearEditorContent();
|
||||||
@ -324,7 +339,7 @@ export const GroupAnnouncements = ({
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (!error) return;
|
if (!error) return;
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: "error",
|
type: 'error',
|
||||||
message: error,
|
message: error,
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
@ -343,9 +358,9 @@ export const GroupAnnouncements = ({
|
|||||||
const identifier = `grp-${selectedGroup}-anc-`;
|
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 url = `${getBaseApiReact()}${getArbitraryEndpointReact()}?mode=ALL&service=DOCUMENT&identifier=${identifier}&limit=20&includemetadata=false&offset=${offset}&reverse=true&prefix=true`;
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
method: "GET",
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const responseData = await response.json();
|
const responseData = await response.json();
|
||||||
@ -354,11 +369,14 @@ export const GroupAnnouncements = ({
|
|||||||
setAnnouncements(responseData);
|
setAnnouncements(responseData);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
for (const data of responseData) {
|
for (const data of responseData) {
|
||||||
getAnnouncementData({
|
getAnnouncementData(
|
||||||
name: data.name,
|
{
|
||||||
identifier: data.identifier,
|
name: data.name,
|
||||||
resource: data,
|
identifier: data.identifier,
|
||||||
}, isPrivate);
|
resource: data,
|
||||||
|
},
|
||||||
|
isPrivate
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
} finally {
|
} finally {
|
||||||
@ -369,8 +387,13 @@ export const GroupAnnouncements = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if(!secretKey && isPrivate) return
|
if (!secretKey && isPrivate) return;
|
||||||
if (selectedGroup && !hasInitialized.current && !hide && isPrivate !== null) {
|
if (
|
||||||
|
selectedGroup &&
|
||||||
|
!hasInitialized.current &&
|
||||||
|
!hide &&
|
||||||
|
isPrivate !== null
|
||||||
|
) {
|
||||||
getAnnouncements(selectedGroup, isPrivate);
|
getAnnouncements(selectedGroup, isPrivate);
|
||||||
hasInitialized.current = true;
|
hasInitialized.current = true;
|
||||||
}
|
}
|
||||||
@ -384,9 +407,9 @@ export const GroupAnnouncements = ({
|
|||||||
const identifier = `grp-${selectedGroup}-anc-`;
|
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 url = `${getBaseApiReact()}${getArbitraryEndpointReact()}?mode=ALL&service=DOCUMENT&identifier=${identifier}&limit=20&includemetadata=false&offset=${offset}&reverse=true&prefix=true`;
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
method: "GET",
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const responseData = await response.json();
|
const responseData = await response.json();
|
||||||
@ -394,7 +417,10 @@ export const GroupAnnouncements = ({
|
|||||||
setAnnouncements((prev) => [...prev, ...responseData]);
|
setAnnouncements((prev) => [...prev, ...responseData]);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
for (const data of responseData) {
|
for (const data of responseData) {
|
||||||
getAnnouncementData({ name: data.name, identifier: data.identifier }, isPrivate);
|
getAnnouncementData(
|
||||||
|
{ name: data.name, identifier: data.identifier },
|
||||||
|
isPrivate
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
};
|
};
|
||||||
@ -406,9 +432,9 @@ export const GroupAnnouncements = ({
|
|||||||
const identifier = `grp-${selectedGroup}-anc-`;
|
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 url = `${getBaseApiReact()}${getArbitraryEndpointReact()}?mode=ALL&service=DOCUMENT&identifier=${identifier}&limit=20&includemetadata=false&offset=${0}&reverse=true&prefix=true`;
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
method: "GET",
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const responseData = await response.json();
|
const responseData = await response.json();
|
||||||
@ -416,10 +442,13 @@ export const GroupAnnouncements = ({
|
|||||||
if (!latestMessage) {
|
if (!latestMessage) {
|
||||||
for (const data of responseData) {
|
for (const data of responseData) {
|
||||||
try {
|
try {
|
||||||
getAnnouncementData({
|
getAnnouncementData(
|
||||||
name: data.name,
|
{
|
||||||
identifier: data.identifier,
|
name: data.name,
|
||||||
}, isPrivate);
|
identifier: data.identifier,
|
||||||
|
},
|
||||||
|
isPrivate
|
||||||
|
);
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
}
|
}
|
||||||
setAnnouncements(responseData);
|
setAnnouncements(responseData);
|
||||||
@ -434,7 +463,10 @@ export const GroupAnnouncements = ({
|
|||||||
|
|
||||||
for (const data of newArray) {
|
for (const data of newArray) {
|
||||||
try {
|
try {
|
||||||
getAnnouncementData({ name: data.name, identifier: data.identifier }, isPrivate);
|
getAnnouncementData(
|
||||||
|
{ name: data.name, identifier: data.identifier },
|
||||||
|
isPrivate
|
||||||
|
);
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
}
|
}
|
||||||
setAnnouncements((prev) => [...newArray, ...prev]);
|
setAnnouncements((prev) => [...newArray, ...prev]);
|
||||||
@ -486,13 +518,15 @@ export const GroupAnnouncements = ({
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
// reference to change height
|
// reference to change height
|
||||||
height: isMobile ? `calc(${rootHeight} - 127px` : "calc(100vh - 70px)",
|
height: isMobile
|
||||||
display: "flex",
|
? `calc(${rootHeight} - 127px`
|
||||||
flexDirection: "column",
|
: 'calc(100vh - 70px)',
|
||||||
width: "100%",
|
display: 'flex',
|
||||||
visibility: hide && "hidden",
|
flexDirection: 'column',
|
||||||
position: hide && "fixed",
|
width: '100%',
|
||||||
left: hide && "-1000px",
|
visibility: hide && 'hidden',
|
||||||
|
position: hide && 'fixed',
|
||||||
|
left: hide && '-1000px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AnnouncementDiscussion
|
<AnnouncementDiscussion
|
||||||
@ -509,63 +543,62 @@ export const GroupAnnouncements = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
// reference to change height
|
// reference to change height
|
||||||
height: isMobile ? `calc(${rootHeight} - 127px` : "calc(100vh - 70px)",
|
height: isMobile ? `calc(${rootHeight} - 127px` : 'calc(100vh - 70px)',
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
width: "100%",
|
width: '100%',
|
||||||
visibility: hide && "hidden",
|
visibility: hide && 'hidden',
|
||||||
position: hide && "fixed",
|
position: hide && 'fixed',
|
||||||
left: hide && "-1000px",
|
left: hide && '-1000px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
position: "relative",
|
position: 'relative',
|
||||||
width: "100%",
|
width: '100%',
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{!isMobile && (
|
{!isMobile && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: "100%",
|
width: '100%',
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
justifyContent: "center",
|
justifyContent: 'center',
|
||||||
padding: isMobile ? "8px" : "25px",
|
padding: isMobile ? '8px' : '25px',
|
||||||
fontSize: isMobile ? "16px" : "20px",
|
fontSize: isMobile ? '16px' : '20px',
|
||||||
gap: "20px",
|
gap: '20px',
|
||||||
alignItems: "center",
|
alignItems: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CampaignIcon
|
<CampaignIcon
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: isMobile ? "16px" : "30px",
|
fontSize: isMobile ? '16px' : '30px',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
Group Announcements
|
Group Announcements
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Spacer height={isMobile ? "0px" : "25px"} />
|
<Spacer height={isMobile ? '0px' : '25px'} />
|
||||||
</div>
|
</div>
|
||||||
{!isLoading && combinedListTempAndReal?.length === 0 && (
|
{!isLoading && combinedListTempAndReal?.length === 0 && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: "100%",
|
width: '100%',
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
justifyContent: "center",
|
justifyContent: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: "16px",
|
fontSize: '16px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
No announcements
|
No announcements
|
||||||
@ -589,28 +622,28 @@ export const GroupAnnouncements = ({
|
|||||||
style={{
|
style={{
|
||||||
// position: 'fixed',
|
// position: 'fixed',
|
||||||
// bottom: '0px',
|
// bottom: '0px',
|
||||||
backgroundColor: "#232428",
|
backgroundColor: '#232428',
|
||||||
minHeight: isMobile ? "0px" : "150px",
|
minHeight: isMobile ? '0px' : '150px',
|
||||||
maxHeight: isMobile ? "auto" : "400px",
|
maxHeight: isMobile ? 'auto' : '400px',
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
overflow: "hidden",
|
overflow: 'hidden',
|
||||||
width: "100%",
|
width: '100%',
|
||||||
boxSizing: "border-box",
|
boxSizing: 'border-box',
|
||||||
padding: isMobile ? "10px" : "20px",
|
padding: isMobile ? '10px' : '20px',
|
||||||
position: isFocusedParent ? "fixed" : "relative",
|
position: isFocusedParent ? 'fixed' : 'relative',
|
||||||
bottom: isFocusedParent ? "0px" : "unset",
|
bottom: isFocusedParent ? '0px' : 'unset',
|
||||||
top: isFocusedParent ? "0px" : "unset",
|
top: isFocusedParent ? '0px' : 'unset',
|
||||||
zIndex: isFocusedParent ? 5 : "unset",
|
zIndex: isFocusedParent ? 5 : 'unset',
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
flexGrow: isMobile && 1,
|
flexGrow: isMobile && 1,
|
||||||
overflow: "auto",
|
overflow: 'auto',
|
||||||
// height: '100%',
|
// height: '100%',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -625,12 +658,12 @@ export const GroupAnnouncements = ({
|
|||||||
</div>
|
</div>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
width: "100&",
|
width: '100&',
|
||||||
gap: "10px",
|
gap: '10px',
|
||||||
justifyContent: "center",
|
justifyContent: 'center',
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
position: "relative",
|
position: 'relative',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isFocusedParent && (
|
{isFocusedParent && (
|
||||||
@ -639,19 +672,19 @@ export const GroupAnnouncements = ({
|
|||||||
if (isSending) return;
|
if (isSending) return;
|
||||||
setIsFocusedParent(false);
|
setIsFocusedParent(false);
|
||||||
clearEditorContent();
|
clearEditorContent();
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
triggerRerender();
|
triggerRerender();
|
||||||
}, 300);
|
}, 300);
|
||||||
// Unfocus the editor
|
// Unfocus the editor
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
marginTop: "auto",
|
marginTop: 'auto',
|
||||||
alignSelf: "center",
|
alignSelf: 'center',
|
||||||
cursor: isSending ? "default" : "pointer",
|
cursor: isSending ? 'default' : 'pointer',
|
||||||
background: "var(--danger)",
|
background: 'var(--danger)',
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
padding: isMobile && "5px",
|
padding: isMobile && '5px',
|
||||||
fontSize: isMobile && "14px",
|
fontSize: isMobile && '14px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{` Close`}
|
{` Close`}
|
||||||
@ -663,25 +696,25 @@ export const GroupAnnouncements = ({
|
|||||||
publishAnnouncement();
|
publishAnnouncement();
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
marginTop: "auto",
|
marginTop: 'auto',
|
||||||
alignSelf: "center",
|
alignSelf: 'center',
|
||||||
cursor: isSending ? "default" : "pointer",
|
cursor: isSending ? 'default' : 'pointer',
|
||||||
background: isSending && "rgba(0, 0, 0, 0.8)",
|
background: isSending && 'rgba(0, 0, 0, 0.8)',
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
padding: isMobile && "5px",
|
padding: isMobile && '5px',
|
||||||
fontSize: isMobile && "14px",
|
fontSize: isMobile && '14px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isSending && (
|
{isSending && (
|
||||||
<CircularProgress
|
<CircularProgress
|
||||||
size={18}
|
size={18}
|
||||||
sx={{
|
sx={{
|
||||||
position: "absolute",
|
position: 'absolute',
|
||||||
top: "50%",
|
top: '50%',
|
||||||
left: "50%",
|
left: '50%',
|
||||||
marginTop: "-12px",
|
marginTop: '-12px',
|
||||||
marginLeft: "-12px",
|
marginLeft: '-12px',
|
||||||
color: "white",
|
color: 'white',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@ -701,7 +734,7 @@ export const GroupAnnouncements = ({
|
|||||||
<LoadingSnackbar
|
<LoadingSnackbar
|
||||||
open={isLoading}
|
open={isLoading}
|
||||||
info={{
|
info={{
|
||||||
message: "Loading announcements... please wait.",
|
message: 'Loading announcements... please wait.',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,7 +6,7 @@ import { IconWrapper } from './Desktop/DesktopFooter';
|
|||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilState } from 'recoil';
|
||||||
import { enabledDevModeAtom } from '../atoms/global';
|
import { enabledDevModeAtom } from '../atoms/global';
|
||||||
import { AppsIcon } from '../assets/Icons/AppsIcon';
|
import { AppsIcon } from '../assets/Icons/AppsIcon';
|
||||||
import ThemeSelector from '../styles/ThemeSelector';
|
import ThemeSelector from './Theme/ThemeSelector';
|
||||||
|
|
||||||
export const DesktopSideBar = ({
|
export const DesktopSideBar = ({
|
||||||
goToHome,
|
goToHome,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import React, { useContext, useEffect, useMemo, useState } from "react";
|
import React, { useContext, useEffect, useMemo, useState } from 'react';
|
||||||
import { subscribeToEvent, unsubscribeFromEvent } from "../../utils/events";
|
import { subscribeToEvent, unsubscribeFromEvent } from '../../utils/events';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
@ -9,12 +9,12 @@ import {
|
|||||||
DialogActions,
|
DialogActions,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
Typography,
|
Typography,
|
||||||
} from "@mui/material";
|
} from '@mui/material';
|
||||||
import { CustomButton, CustomButtonAccept } from "../../App-styles";
|
import { CustomButton, CustomButtonAccept } from '../../styles/App-styles';
|
||||||
import { getBaseApiReact, MyContext } from "../../App";
|
import { getBaseApiReact, MyContext } from '../../App';
|
||||||
import { getFee } from "../../background";
|
import { getFee } from '../../background';
|
||||||
import { CustomizedSnackbars } from "../Snackbar/Snackbar";
|
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
|
||||||
import { FidgetSpinner } from "react-loader-spinner";
|
import { FidgetSpinner } from 'react-loader-spinner';
|
||||||
|
|
||||||
export const JoinGroup = ({ memberGroups }) => {
|
export const JoinGroup = ({ memberGroups }) => {
|
||||||
const { show, setTxList } = useContext(MyContext);
|
const { show, setTxList } = useContext(MyContext);
|
||||||
@ -42,43 +42,45 @@ export const JoinGroup = ({ memberGroups }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
subscribeToEvent("globalActionJoinGroup", handleJoinGroup);
|
subscribeToEvent('globalActionJoinGroup', handleJoinGroup);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
unsubscribeFromEvent("globalActionJoinGroup", handleJoinGroup);
|
unsubscribeFromEvent('globalActionJoinGroup', handleJoinGroup);
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const isInGroup = useMemo(()=> {
|
const isInGroup = useMemo(() => {
|
||||||
return !!memberGroups.find((item)=> +item?.groupId === +groupInfo?.groupId)
|
return !!memberGroups.find(
|
||||||
}, [memberGroups, groupInfo])
|
(item) => +item?.groupId === +groupInfo?.groupId
|
||||||
|
);
|
||||||
|
}, [memberGroups, groupInfo]);
|
||||||
const joinGroup = async (group, isOpen) => {
|
const joinGroup = async (group, isOpen) => {
|
||||||
try {
|
try {
|
||||||
const groupId = group.groupId;
|
const groupId = group.groupId;
|
||||||
const fee = await getFee("JOIN_GROUP");
|
const fee = await getFee('JOIN_GROUP');
|
||||||
await show({
|
await show({
|
||||||
message: "Would you like to perform an JOIN_GROUP transaction?",
|
message: 'Would you like to perform an JOIN_GROUP transaction?',
|
||||||
publishFee: fee.fee + " QORT",
|
publishFee: fee.fee + ' QORT',
|
||||||
});
|
});
|
||||||
setIsLoadingJoinGroup(true);
|
setIsLoadingJoinGroup(true);
|
||||||
await new Promise((res, rej) => {
|
await new Promise((res, rej) => {
|
||||||
window
|
window
|
||||||
.sendMessage("joinGroup", {
|
.sendMessage('joinGroup', {
|
||||||
groupId,
|
groupId,
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (!response?.error) {
|
if (!response?.error) {
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: "success",
|
type: 'success',
|
||||||
message:
|
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) {
|
if (isOpen) {
|
||||||
setTxList((prev) => [
|
setTxList((prev) => [
|
||||||
{
|
{
|
||||||
...response,
|
...response,
|
||||||
type: "joined-group",
|
type: 'joined-group',
|
||||||
label: `Joined Group ${group?.groupName}: awaiting confirmation`,
|
label: `Joined Group ${group?.groupName}: awaiting confirmation`,
|
||||||
labelDone: `Joined Group ${group?.groupName}: success!`,
|
labelDone: `Joined Group ${group?.groupName}: success!`,
|
||||||
done: false,
|
done: false,
|
||||||
@ -90,7 +92,7 @@ export const JoinGroup = ({ memberGroups }) => {
|
|||||||
setTxList((prev) => [
|
setTxList((prev) => [
|
||||||
{
|
{
|
||||||
...response,
|
...response,
|
||||||
type: "joined-group-request",
|
type: 'joined-group-request',
|
||||||
label: `Requested to join Group ${group?.groupName}: awaiting confirmation`,
|
label: `Requested to join Group ${group?.groupName}: awaiting confirmation`,
|
||||||
labelDone: `Requested to join Group ${group?.groupName}: success!`,
|
labelDone: `Requested to join Group ${group?.groupName}: success!`,
|
||||||
done: false,
|
done: false,
|
||||||
@ -105,7 +107,7 @@ export const JoinGroup = ({ memberGroups }) => {
|
|||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: "error",
|
type: 'error',
|
||||||
message: response?.error,
|
message: response?.error,
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
@ -114,8 +116,8 @@ export const JoinGroup = ({ memberGroups }) => {
|
|||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
setInfoSnack({
|
setInfoSnack({
|
||||||
type: "error",
|
type: 'error',
|
||||||
message: error.message || "An error occurred",
|
message: error.message || 'An error occurred',
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
rej(error);
|
rej(error);
|
||||||
@ -138,37 +140,37 @@ export const JoinGroup = ({ memberGroups }) => {
|
|||||||
{!groupInfo && (
|
{!groupInfo && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: "325px",
|
width: '325px',
|
||||||
height: "150px",
|
height: '150px',
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
alignItems: "center",
|
alignItems: 'center',
|
||||||
justifyContent: "center",
|
justifyContent: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{" "}
|
{' '}
|
||||||
<CircularProgress
|
<CircularProgress
|
||||||
size={25}
|
size={25}
|
||||||
sx={{
|
sx={{
|
||||||
color: "white",
|
color: 'white',
|
||||||
}}
|
}}
|
||||||
/>{" "}
|
/>{' '}
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: "325px",
|
width: '325px',
|
||||||
height: "auto",
|
height: 'auto',
|
||||||
maxHeight: "400px",
|
maxHeight: '400px',
|
||||||
display: !groupInfo ? "none" : "flex",
|
display: !groupInfo ? 'none' : 'flex',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
alignItems: "center",
|
alignItems: 'center',
|
||||||
gap: "10px",
|
gap: '10px',
|
||||||
padding: "10px",
|
padding: '10px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: "15px",
|
fontSize: '15px',
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -176,7 +178,7 @@ export const JoinGroup = ({ memberGroups }) => {
|
|||||||
</Typography>
|
</Typography>
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: "15px",
|
fontSize: '15px',
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -185,7 +187,7 @@ export const JoinGroup = ({ memberGroups }) => {
|
|||||||
{groupInfo?.description && (
|
{groupInfo?.description && (
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: "15px",
|
fontSize: '15px',
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -193,19 +195,19 @@ export const JoinGroup = ({ memberGroups }) => {
|
|||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
{isInGroup && (
|
{isInGroup && (
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: "14px",
|
fontSize: '14px',
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
*You are already in this group!
|
*You are already in this group!
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
{!isInGroup && groupInfo?.isOpen === false && (
|
{!isInGroup && groupInfo?.isOpen === false && (
|
||||||
<Typography
|
<Typography
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: "14px",
|
fontSize: '14px',
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@ -216,32 +218,34 @@ export const JoinGroup = ({ memberGroups }) => {
|
|||||||
</Box>
|
</Box>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<ButtonBase onClick={() => {
|
<ButtonBase
|
||||||
|
onClick={() => {
|
||||||
joinGroup(groupInfo, groupInfo?.isOpen);
|
joinGroup(groupInfo, groupInfo?.isOpen);
|
||||||
|
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
}} disabled={isInGroup}>
|
|
||||||
<CustomButtonAccept
|
|
||||||
color="black"
|
|
||||||
bgColor="var(--green)"
|
|
||||||
sx={{
|
|
||||||
minWidth: "102px",
|
|
||||||
height: "45px",
|
|
||||||
fontSize: '16px',
|
|
||||||
opacity: isInGroup ? 0.1 : 1
|
|
||||||
}}
|
}}
|
||||||
|
disabled={isInGroup}
|
||||||
>
|
>
|
||||||
Join
|
<CustomButtonAccept
|
||||||
</CustomButtonAccept>
|
color="black"
|
||||||
|
bgColor="var(--green)"
|
||||||
|
sx={{
|
||||||
|
minWidth: '102px',
|
||||||
|
height: '45px',
|
||||||
|
fontSize: '16px',
|
||||||
|
opacity: isInGroup ? 0.1 : 1,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Join
|
||||||
|
</CustomButtonAccept>
|
||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
|
|
||||||
<CustomButtonAccept
|
<CustomButtonAccept
|
||||||
color="black"
|
color="black"
|
||||||
bgColor="var(--danger)"
|
bgColor="var(--danger)"
|
||||||
sx={{
|
sx={{
|
||||||
minWidth: "102px",
|
minWidth: '102px',
|
||||||
height: "45px",
|
height: '45px',
|
||||||
}}
|
}}
|
||||||
onClick={() => setIsOpen(false)}
|
onClick={() => setIsOpen(false)}
|
||||||
>
|
>
|
||||||
@ -259,14 +263,14 @@ export const JoinGroup = ({ memberGroups }) => {
|
|||||||
{isLoadingJoinGroup && (
|
{isLoadingJoinGroup && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
position: "absolute",
|
position: 'absolute',
|
||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
justifyContent: "center",
|
justifyContent: 'center',
|
||||||
alignItems: "center",
|
alignItems: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FidgetSpinner
|
<FidgetSpinner
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -13,29 +13,29 @@ import {
|
|||||||
InputLabel,
|
InputLabel,
|
||||||
Snackbar,
|
Snackbar,
|
||||||
Typography,
|
Typography,
|
||||||
} from "@mui/material";
|
} from '@mui/material';
|
||||||
import React, {
|
import React, {
|
||||||
useCallback,
|
useCallback,
|
||||||
useContext,
|
useContext,
|
||||||
useEffect,
|
useEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from 'react';
|
||||||
import CloseIcon from "@mui/icons-material/Close";
|
import CloseIcon from '@mui/icons-material/Close';
|
||||||
import { MyContext, getBaseApiReact } from "../../App";
|
import { MyContext, getBaseApiReact } from '../../App';
|
||||||
import {
|
import {
|
||||||
executeEvent,
|
executeEvent,
|
||||||
subscribeToEvent,
|
subscribeToEvent,
|
||||||
unsubscribeFromEvent,
|
unsubscribeFromEvent,
|
||||||
} from "../../utils/events";
|
} from '../../utils/events';
|
||||||
import { getFee, getNameOrAddress } from "../../background";
|
import { getFee, getNameOrAddress } from '../../background';
|
||||||
import CopyToClipboard from "react-copy-to-clipboard";
|
import CopyToClipboard from 'react-copy-to-clipboard';
|
||||||
import { AddressBox } from "../../App-styles";
|
import { AddressBox } from '../../styles/App-styles';
|
||||||
import { Spacer } from "../../common/Spacer";
|
import { Spacer } from '../../common/Spacer';
|
||||||
import Copy from "../../assets/svgs/Copy.svg";
|
import Copy from '../../assets/svgs/Copy.svg';
|
||||||
import { Loader } from "../Loader";
|
import { Loader } from '../Loader';
|
||||||
import { FidgetSpinner } from "react-loader-spinner";
|
import { FidgetSpinner } from 'react-loader-spinner';
|
||||||
import { useModal } from "../../common/useModal";
|
import { useModal } from '../../common/useModal';
|
||||||
|
|
||||||
export const Minting = ({
|
export const Minting = ({
|
||||||
setIsOpenMinting,
|
setIsOpenMinting,
|
||||||
@ -47,30 +47,30 @@ export const Minting = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const [mintingAccounts, setMintingAccounts] = useState([]);
|
const [mintingAccounts, setMintingAccounts] = useState([]);
|
||||||
const [accountInfo, setAccountInfo] = useState(null);
|
const [accountInfo, setAccountInfo] = useState(null);
|
||||||
const [rewardSharePublicKey, setRewardSharePublicKey] = useState("");
|
const [rewardSharePublicKey, setRewardSharePublicKey] = useState('');
|
||||||
const [mintingKey, setMintingKey] = useState("");
|
const [mintingKey, setMintingKey] = useState('');
|
||||||
const [rewardsharekey, setRewardsharekey] = useState("");
|
const [rewardsharekey, setRewardsharekey] = useState('');
|
||||||
const [rewardShares, setRewardShares] = useState([]);
|
const [rewardShares, setRewardShares] = useState([]);
|
||||||
const [nodeInfos, setNodeInfos] = useState({});
|
const [nodeInfos, setNodeInfos] = useState({});
|
||||||
const [openSnack, setOpenSnack] = useState(false);
|
const [openSnack, setOpenSnack] = useState(false);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const { show: showKey, message } = useModal();
|
const { show: showKey, message } = useModal();
|
||||||
const { isShow: isShowNext, onOk, show: showNext } = useModal();
|
const { isShow: isShowNext, onOk, show: showNext } = useModal();
|
||||||
|
|
||||||
const [info, setInfo] = useState(null);
|
const [info, setInfo] = useState(null);
|
||||||
const [names, setNames] = useState({});
|
const [names, setNames] = useState({});
|
||||||
const [accountInfos, setAccountInfos] = useState({});
|
const [accountInfos, setAccountInfos] = useState({});
|
||||||
const [showWaitDialog, setShowWaitDialog] = useState(false)
|
const [showWaitDialog, setShowWaitDialog] = useState(false);
|
||||||
const isPartOfMintingGroup = useMemo(() => {
|
const isPartOfMintingGroup = useMemo(() => {
|
||||||
if (groups?.length === 0) return false;
|
if (groups?.length === 0) return false;
|
||||||
return !!groups?.find((item) => item?.groupId?.toString() === "694");
|
return !!groups?.find((item) => item?.groupId?.toString() === '694');
|
||||||
}, [groups]);
|
}, [groups]);
|
||||||
const getMintingAccounts = useCallback(async () => {
|
const getMintingAccounts = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
const url = `${getBaseApiReact()}/admin/mintingaccounts`;
|
const url = `${getBaseApiReact()}/admin/mintingaccounts`;
|
||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error("network error");
|
throw new Error('network error');
|
||||||
}
|
}
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
setMintingAccounts(data);
|
setMintingAccounts(data);
|
||||||
@ -117,7 +117,7 @@ export const Minting = ({
|
|||||||
const url = `${getBaseApiReact()}/addresses/${address}`;
|
const url = `${getBaseApiReact()}/addresses/${address}`;
|
||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error("network error");
|
throw new Error('network error');
|
||||||
}
|
}
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
if (others) {
|
if (others) {
|
||||||
@ -144,10 +144,10 @@ export const Minting = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
subscribeToEvent("refresh-rewardshare-list", refreshRewardShare);
|
subscribeToEvent('refresh-rewardshare-list', refreshRewardShare);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
unsubscribeFromEvent("refresh-rewardshare-list", refreshRewardShare);
|
unsubscribeFromEvent('refresh-rewardshare-list', refreshRewardShare);
|
||||||
};
|
};
|
||||||
}, [myAddress]);
|
}, [myAddress]);
|
||||||
|
|
||||||
@ -177,15 +177,15 @@ export const Minting = ({
|
|||||||
try {
|
try {
|
||||||
const url = `${getBaseApiReact()}/admin/status`;
|
const url = `${getBaseApiReact()}/admin/status`;
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
method: "GET",
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
setNodeInfos(data);
|
setNodeInfos(data);
|
||||||
} catch (error) {
|
} 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 url = `${getBaseApiReact()}/addresses/rewardshares?involving=${address}`;
|
||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error("network error");
|
throw new Error('network error');
|
||||||
}
|
}
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
setRewardShares(data);
|
setRewardShares(data);
|
||||||
return data
|
return data;
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -208,10 +208,10 @@ export const Minting = ({
|
|||||||
return await new Promise((res, rej) => {
|
return await new Promise((res, rej) => {
|
||||||
window
|
window
|
||||||
.sendMessage(
|
.sendMessage(
|
||||||
"ADMIN_ACTION",
|
'ADMIN_ACTION',
|
||||||
|
|
||||||
{
|
{
|
||||||
type: "addmintingaccount",
|
type: 'addmintingaccount',
|
||||||
value: val,
|
value: val,
|
||||||
},
|
},
|
||||||
180000,
|
180000,
|
||||||
@ -220,7 +220,7 @@ export const Minting = ({
|
|||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (!response?.error) {
|
if (!response?.error) {
|
||||||
res(response);
|
res(response);
|
||||||
setMintingKey("");
|
setMintingKey('');
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
getMintingAccounts();
|
getMintingAccounts();
|
||||||
}, 300);
|
}, 300);
|
||||||
@ -229,13 +229,13 @@ export const Minting = ({
|
|||||||
rej({ message: response.error });
|
rej({ message: response.error });
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
rej({ message: error.message || "An error occurred" });
|
rej({ message: error.message || 'An error occurred' });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setInfo({
|
setInfo({
|
||||||
type: "error",
|
type: 'error',
|
||||||
message: error?.message || "Unable to add minting account",
|
message: error?.message || 'Unable to add minting account',
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
} finally {
|
} finally {
|
||||||
@ -249,10 +249,10 @@ export const Minting = ({
|
|||||||
return await new Promise((res, rej) => {
|
return await new Promise((res, rej) => {
|
||||||
window
|
window
|
||||||
.sendMessage(
|
.sendMessage(
|
||||||
"ADMIN_ACTION",
|
'ADMIN_ACTION',
|
||||||
|
|
||||||
{
|
{
|
||||||
type: "removemintingaccount",
|
type: 'removemintingaccount',
|
||||||
value: val,
|
value: val,
|
||||||
},
|
},
|
||||||
180000,
|
180000,
|
||||||
@ -270,13 +270,13 @@ export const Minting = ({
|
|||||||
rej({ message: response.error });
|
rej({ message: response.error });
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
rej({ message: error.message || "An error occurred" });
|
rej({ message: error.message || 'An error occurred' });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setInfo({
|
setInfo({
|
||||||
type: "error",
|
type: 'error',
|
||||||
message: error?.message || "Unable to remove minting account",
|
message: error?.message || 'Unable to remove minting account',
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
} finally {
|
} finally {
|
||||||
@ -285,14 +285,14 @@ export const Minting = ({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const createRewardShare = useCallback(async (publicKey, recipient) => {
|
const createRewardShare = useCallback(async (publicKey, recipient) => {
|
||||||
const fee = await getFee("REWARD_SHARE");
|
const fee = await getFee('REWARD_SHARE');
|
||||||
await show({
|
await show({
|
||||||
message: "Would you like to perform an REWARD_SHARE transaction?",
|
message: 'Would you like to perform an REWARD_SHARE transaction?',
|
||||||
publishFee: fee.fee + " QORT",
|
publishFee: fee.fee + ' QORT',
|
||||||
});
|
});
|
||||||
return await new Promise((res, rej) => {
|
return await new Promise((res, rej) => {
|
||||||
window
|
window
|
||||||
.sendMessage("createRewardShare", {
|
.sendMessage('createRewardShare', {
|
||||||
recipientPublicKey: publicKey,
|
recipientPublicKey: publicKey,
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
@ -301,7 +301,7 @@ export const Minting = ({
|
|||||||
{
|
{
|
||||||
recipient,
|
recipient,
|
||||||
...response,
|
...response,
|
||||||
type: "add-rewardShare",
|
type: 'add-rewardShare',
|
||||||
label: `Add rewardshare: awaiting confirmation`,
|
label: `Add rewardshare: awaiting confirmation`,
|
||||||
labelDone: `Add rewardshare: success!`,
|
labelDone: `Add rewardshare: success!`,
|
||||||
done: false,
|
done: false,
|
||||||
@ -314,7 +314,7 @@ export const Minting = ({
|
|||||||
rej({ message: response.error });
|
rej({ message: response.error });
|
||||||
})
|
})
|
||||||
.catch((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) => {
|
const getRewardSharePrivateKey = useCallback(async (publicKey) => {
|
||||||
return await new Promise((res, rej) => {
|
return await new Promise((res, rej) => {
|
||||||
window
|
window
|
||||||
.sendMessage("getRewardSharePrivateKey", {
|
.sendMessage('getRewardSharePrivateKey', {
|
||||||
recipientPublicKey: publicKey,
|
recipientPublicKey: publicKey,
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
@ -333,7 +333,7 @@ export const Minting = ({
|
|||||||
rej({ message: response.error });
|
rej({ message: response.error });
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
rej({ message: error.message || "An error occurred" });
|
rej({ message: error.message || 'An error occurred' });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
@ -341,26 +341,24 @@ export const Minting = ({
|
|||||||
const waitUntilRewardShareIsConfirmed = async (timeoutMs = 600000) => {
|
const waitUntilRewardShareIsConfirmed = async (timeoutMs = 600000) => {
|
||||||
const pollingInterval = 30000;
|
const pollingInterval = 30000;
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
|
|
||||||
const sleep = (ms) => new Promise((res) => setTimeout(res, ms));
|
const sleep = (ms) => new Promise((res) => setTimeout(res, ms));
|
||||||
|
|
||||||
while (Date.now() - startTime < timeoutMs) {
|
while (Date.now() - startTime < timeoutMs) {
|
||||||
|
const rewardShares = await getRewardShares(myAddress);
|
||||||
const rewardShares = await getRewardShares(myAddress);
|
const findRewardShare = rewardShares?.find(
|
||||||
const findRewardShare = rewardShares?.find(
|
(item) =>
|
||||||
(item) =>
|
item?.recipient === myAddress && item?.mintingAccount === myAddress
|
||||||
item?.recipient === myAddress && item?.mintingAccount === myAddress
|
);
|
||||||
);
|
|
||||||
|
if (findRewardShare) {
|
||||||
if (findRewardShare) {
|
return true; // Exit early if found
|
||||||
return true; // Exit early if found
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
await sleep(pollingInterval); // Wait before the next poll
|
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 () => {
|
const startMinting = async () => {
|
||||||
@ -377,23 +375,22 @@ export const Minting = ({
|
|||||||
addMintingAccount(privateRewardShare);
|
addMintingAccount(privateRewardShare);
|
||||||
} else {
|
} else {
|
||||||
await createRewardShare(accountInfo?.publicKey, myAddress);
|
await createRewardShare(accountInfo?.publicKey, myAddress);
|
||||||
setShowWaitDialog(true)
|
setShowWaitDialog(true);
|
||||||
await waitUntilRewardShareIsConfirmed()
|
await waitUntilRewardShareIsConfirmed();
|
||||||
await showNext({
|
await showNext({
|
||||||
message: ''
|
message: '',
|
||||||
})
|
});
|
||||||
const privateRewardShare = await getRewardSharePrivateKey(
|
const privateRewardShare = await getRewardSharePrivateKey(
|
||||||
accountInfo?.publicKey
|
accountInfo?.publicKey
|
||||||
);
|
);
|
||||||
setShowWaitDialog(false)
|
setShowWaitDialog(false);
|
||||||
addMintingAccount(privateRewardShare);
|
addMintingAccount(privateRewardShare);
|
||||||
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setShowWaitDialog(false)
|
setShowWaitDialog(false);
|
||||||
setInfo({
|
setInfo({
|
||||||
type: "error",
|
type: 'error',
|
||||||
message: error?.message || "Unable to start minting",
|
message: error?.message || 'Unable to start minting',
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
} finally {
|
} finally {
|
||||||
@ -412,13 +409,13 @@ export const Minting = ({
|
|||||||
const url = `${getBaseApiReact()}/groups/member/${address}`;
|
const url = `${getBaseApiReact()}/groups/member/${address}`;
|
||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
const data = await response.json();
|
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) => {
|
const removeRewardShare = useCallback(async (rewardShare) => {
|
||||||
return await new Promise((res, rej) => {
|
return await new Promise((res, rej) => {
|
||||||
window
|
window
|
||||||
.sendMessage("removeRewardShare", {
|
.sendMessage('removeRewardShare', {
|
||||||
rewardShareKeyPairPublicKey: rewardShare.rewardSharePublicKey,
|
rewardShareKeyPairPublicKey: rewardShare.rewardSharePublicKey,
|
||||||
recipient: rewardShare.recipient,
|
recipient: rewardShare.recipient,
|
||||||
percentageShare: -1,
|
percentageShare: -1,
|
||||||
@ -430,7 +427,7 @@ export const Minting = ({
|
|||||||
{
|
{
|
||||||
...rewardShare,
|
...rewardShare,
|
||||||
...response,
|
...response,
|
||||||
type: "remove-rewardShare",
|
type: 'remove-rewardShare',
|
||||||
label: `Remove rewardshare: awaiting confirmation`,
|
label: `Remove rewardshare: awaiting confirmation`,
|
||||||
labelDone: `Remove rewardshare: success!`,
|
labelDone: `Remove rewardshare: success!`,
|
||||||
done: false,
|
done: false,
|
||||||
@ -442,7 +439,7 @@ export const Minting = ({
|
|||||||
rej({ message: response.error });
|
rej({ message: response.error });
|
||||||
})
|
})
|
||||||
.catch((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);
|
const privateRewardShare = await removeRewardShare(rewardShare);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setInfo({
|
setInfo({
|
||||||
type: "error",
|
type: 'error',
|
||||||
message: error?.message || "Unable to remove reward share",
|
message: error?.message || 'Unable to remove reward share',
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
} finally {
|
} finally {
|
||||||
@ -468,9 +465,9 @@ export const Minting = ({
|
|||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
const confirmReceiver = await getNameOrAddress(receiver);
|
const confirmReceiver = await getNameOrAddress(receiver);
|
||||||
if (confirmReceiver.error)
|
if (confirmReceiver.error)
|
||||||
throw new Error("Invalid receiver address or name");
|
throw new Error('Invalid receiver address or name');
|
||||||
const isInMinterGroup = await checkIfMinterGroup(confirmReceiver);
|
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 publicKey = await getPublicKeyFromAddress(confirmReceiver);
|
||||||
const findRewardShare = rewardShares?.find(
|
const findRewardShare = rewardShares?.find(
|
||||||
(item) =>
|
(item) =>
|
||||||
@ -487,8 +484,8 @@ export const Minting = ({
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setInfo({
|
setInfo({
|
||||||
type: "error",
|
type: 'error',
|
||||||
message: error?.message || "Unable to create reward share",
|
message: error?.message || 'Unable to create reward share',
|
||||||
});
|
});
|
||||||
setOpenSnack(true);
|
setOpenSnack(true);
|
||||||
} finally {
|
} finally {
|
||||||
@ -550,11 +547,9 @@ export const Minting = ({
|
|||||||
(accountInfo?.blocksMinted + accountInfo?.blocksMintedAdjustment);
|
(accountInfo?.blocksMinted + accountInfo?.blocksMintedAdjustment);
|
||||||
|
|
||||||
let countBlocksString = countBlocks.toString();
|
let countBlocksString = countBlocks.toString();
|
||||||
return "" + countBlocksString;
|
return '' + countBlocksString;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
open={true}
|
open={true}
|
||||||
@ -562,19 +557,19 @@ export const Minting = ({
|
|||||||
fullWidth
|
fullWidth
|
||||||
fullScreen
|
fullScreen
|
||||||
sx={{
|
sx={{
|
||||||
"& .MuiDialog-paper": {
|
'& .MuiDialog-paper': {
|
||||||
margin: 0,
|
margin: 0,
|
||||||
maxWidth: "100%",
|
maxWidth: '100%',
|
||||||
width: "100%",
|
width: '100%',
|
||||||
height: "100vh",
|
height: '100vh',
|
||||||
overflow: "hidden", // Prevent scrollbars
|
overflow: 'hidden', // Prevent scrollbars
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogTitle id="alert-dialog-title">{"Manage your minting"}</DialogTitle>
|
<DialogTitle id="alert-dialog-title">{'Manage your minting'}</DialogTitle>
|
||||||
<IconButton
|
<IconButton
|
||||||
sx={{
|
sx={{
|
||||||
position: "absolute",
|
position: 'absolute',
|
||||||
right: 8,
|
right: 8,
|
||||||
top: 8,
|
top: 8,
|
||||||
}}
|
}}
|
||||||
@ -586,20 +581,20 @@ export const Minting = ({
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
<DialogContent
|
<DialogContent
|
||||||
sx={{
|
sx={{
|
||||||
position: "relative",
|
position: 'relative',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
position: "absolute",
|
position: 'absolute',
|
||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
justifyContent: "center",
|
justifyContent: 'center',
|
||||||
alignItems: "center",
|
alignItems: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FidgetSpinner
|
<FidgetSpinner
|
||||||
@ -614,8 +609,8 @@ export const Minting = ({
|
|||||||
)}
|
)}
|
||||||
<Card
|
<Card
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: "var(--bg-2)",
|
backgroundColor: 'var(--bg-2)',
|
||||||
padding: "10px",
|
padding: '10px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography>Account: {handleNames(accountInfo?.address)}</Typography>
|
<Typography>Account: {handleNames(accountInfo?.address)}</Typography>
|
||||||
@ -631,11 +626,11 @@ export const Minting = ({
|
|||||||
{isPartOfMintingGroup && !accountIsMinting && (
|
{isPartOfMintingGroup && !accountIsMinting && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
gap: "5px",
|
gap: '5px',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
width: "100%",
|
width: '100%',
|
||||||
alignItems: "center",
|
alignItems: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
@ -645,15 +640,15 @@ export const Minting = ({
|
|||||||
}}
|
}}
|
||||||
disabled={mintingAccounts?.length > 1}
|
disabled={mintingAccounts?.length > 1}
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: "var(--green)",
|
backgroundColor: 'var(--green)',
|
||||||
color: "black",
|
color: 'black',
|
||||||
fontWeight: "bold",
|
fontWeight: 'bold',
|
||||||
opacity: 0.7,
|
opacity: 0.7,
|
||||||
maxWidth: "90%",
|
maxWidth: '90%',
|
||||||
width: "200px",
|
width: '200px',
|
||||||
"&:hover": {
|
'&:hover': {
|
||||||
backgroundColor: "var(--green)",
|
backgroundColor: 'var(--green)',
|
||||||
color: "black",
|
color: 'black',
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
@ -675,16 +670,16 @@ export const Minting = ({
|
|||||||
)}
|
)}
|
||||||
<Card
|
<Card
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: "var(--bg-2)",
|
backgroundColor: 'var(--bg-2)',
|
||||||
padding: "10px",
|
padding: '10px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{accountIsMinting && (
|
{accountIsMinting && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
gap: "5px",
|
gap: '5px',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography>
|
<Typography>
|
||||||
@ -698,9 +693,9 @@ export const Minting = ({
|
|||||||
<Box
|
<Box
|
||||||
key={acct?.mintingAccount}
|
key={acct?.mintingAccount}
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
gap: "10px",
|
gap: '10px',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography>
|
<Typography>
|
||||||
@ -709,15 +704,15 @@ export const Minting = ({
|
|||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: "var(--danger)",
|
backgroundColor: 'var(--danger)',
|
||||||
color: "black",
|
color: 'black',
|
||||||
fontWeight: "bold",
|
fontWeight: 'bold',
|
||||||
opacity: 0.7,
|
opacity: 0.7,
|
||||||
maxWidth: "90%",
|
maxWidth: '90%',
|
||||||
width: "200px",
|
width: '200px',
|
||||||
"&:hover": {
|
'&:hover': {
|
||||||
backgroundColor: "var(--danger)",
|
backgroundColor: 'var(--danger)',
|
||||||
color: "black",
|
color: 'black',
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
@ -745,17 +740,17 @@ export const Minting = ({
|
|||||||
{!isPartOfMintingGroup && (
|
{!isPartOfMintingGroup && (
|
||||||
<Card
|
<Card
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: "var(--bg-2)",
|
backgroundColor: 'var(--bg-2)',
|
||||||
padding: "10px",
|
padding: '10px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
gap: "5px",
|
gap: '5px',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
width: "100%",
|
width: '100%',
|
||||||
alignItems: "center",
|
alignItems: 'center',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography>
|
<Typography>
|
||||||
@ -768,22 +763,22 @@ export const Minting = ({
|
|||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: "var(--green)",
|
backgroundColor: 'var(--green)',
|
||||||
color: "black",
|
color: 'black',
|
||||||
fontWeight: "bold",
|
fontWeight: 'bold',
|
||||||
opacity: 0.7,
|
opacity: 0.7,
|
||||||
|
|
||||||
"&:hover": {
|
'&:hover': {
|
||||||
backgroundColor: "var(--green)",
|
backgroundColor: 'var(--green)',
|
||||||
color: "black",
|
color: 'black',
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
executeEvent("addTab", {
|
executeEvent('addTab', {
|
||||||
data: { service: "APP", name: "q-mintership" },
|
data: { service: 'APP', name: 'q-mintership' },
|
||||||
});
|
});
|
||||||
executeEvent("open-apps-mode", {});
|
executeEvent('open-apps-mode', {});
|
||||||
setIsOpenMinting(false);
|
setIsOpenMinting(false);
|
||||||
}}
|
}}
|
||||||
variant="contained"
|
variant="contained"
|
||||||
@ -801,29 +796,32 @@ export const Minting = ({
|
|||||||
aria-describedby="alert-dialog-description"
|
aria-describedby="alert-dialog-description"
|
||||||
>
|
>
|
||||||
<DialogTitle id="alert-dialog-title">
|
<DialogTitle id="alert-dialog-title">
|
||||||
{isShowNext ? "Confirmed" : "Please Wait"}
|
{isShowNext ? 'Confirmed' : 'Please Wait'}
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
{!isShowNext && (
|
{!isShowNext && (
|
||||||
<Typography>
|
<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
|
||||||
</Typography>
|
patient, this could take up to 90 seconds.
|
||||||
|
</Typography>
|
||||||
)}
|
)}
|
||||||
{isShowNext && (
|
{isShowNext && (
|
||||||
<Typography>
|
<Typography>
|
||||||
Rewardshare confirmed. Please click Next.
|
Rewardshare confirmed. Please click Next.
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button disabled={!isShowNext} variant="contained" onClick={onOk} autoFocus>
|
<Button
|
||||||
|
disabled={!isShowNext}
|
||||||
|
variant="contained"
|
||||||
|
onClick={onOk}
|
||||||
|
autoFocus
|
||||||
|
>
|
||||||
Next
|
Next
|
||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
|
|
||||||
|
|
||||||
</Dialog>
|
</Dialog>
|
||||||
)}
|
)}
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
@ -837,7 +835,7 @@ export const Minting = ({
|
|||||||
</Button>
|
</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
<Snackbar
|
<Snackbar
|
||||||
anchorOrigin={{ vertical: "bottom", horizontal: "center" }}
|
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
|
||||||
open={openSnack}
|
open={openSnack}
|
||||||
autoHideDuration={6000}
|
autoHideDuration={6000}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
@ -846,7 +844,7 @@ export const Minting = ({
|
|||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
severity={info?.type}
|
severity={info?.type}
|
||||||
variant="filled"
|
variant="filled"
|
||||||
sx={{ width: "100%" }}
|
sx={{ width: '100%' }}
|
||||||
>
|
>
|
||||||
{info?.message}
|
{info?.message}
|
||||||
</Alert>
|
</Alert>
|
||||||
|
@ -1,167 +1,170 @@
|
|||||||
import { Box, CircularProgress } from '@mui/material';
|
import { Box, CircularProgress } from '@mui/material';
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react';
|
||||||
import { CustomButton, CustomInput, CustomLabel, TextP } from '../App-styles';
|
import {
|
||||||
|
CustomButton,
|
||||||
|
CustomInput,
|
||||||
|
CustomLabel,
|
||||||
|
TextP,
|
||||||
|
} from '../styles/App-styles';
|
||||||
import { Spacer } from '../common/Spacer';
|
import { Spacer } from '../common/Spacer';
|
||||||
import BoundedNumericTextField from '../common/BoundedNumericTextField';
|
import BoundedNumericTextField from '../common/BoundedNumericTextField';
|
||||||
import { PasswordField } from './PasswordField/PasswordField';
|
import { PasswordField } from './PasswordField/PasswordField';
|
||||||
import { ErrorText } from './ErrorText/ErrorText';
|
import { ErrorText } from './ErrorText/ErrorText';
|
||||||
import { getFee } from '../background';
|
import { getFee } from '../background';
|
||||||
|
|
||||||
export const QortPayment = ({balance, show, onSuccess, defaultPaymentTo}) => {
|
export const QortPayment = ({ balance, show, onSuccess, defaultPaymentTo }) => {
|
||||||
const [paymentTo, setPaymentTo] = useState<string>(defaultPaymentTo);
|
const [paymentTo, setPaymentTo] = useState<string>(defaultPaymentTo);
|
||||||
const [paymentAmount, setPaymentAmount] = useState<number>(0);
|
const [paymentAmount, setPaymentAmount] = useState<number>(0);
|
||||||
const [paymentPassword, setPaymentPassword] = useState<string>("");
|
const [paymentPassword, setPaymentPassword] = useState<string>('');
|
||||||
const [sendPaymentError, setSendPaymentError] = useState<string>("");
|
const [sendPaymentError, setSendPaymentError] = useState<string>('');
|
||||||
const [sendPaymentSuccess, setSendPaymentSuccess] = useState<string>("");
|
const [sendPaymentSuccess, setSendPaymentSuccess] = useState<string>('');
|
||||||
const [isLoadingSendCoin, setIsLoadingSendCoin] = useState<boolean>(false);
|
const [isLoadingSendCoin, setIsLoadingSendCoin] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const sendCoinFunc = async () => {
|
||||||
|
try {
|
||||||
|
setSendPaymentError('');
|
||||||
|
setSendPaymentSuccess('');
|
||||||
|
if (!paymentTo) {
|
||||||
|
setSendPaymentError('Please enter a recipient');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!paymentAmount) {
|
||||||
|
setSendPaymentError('Please enter an amount greater than 0');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!paymentPassword) {
|
||||||
|
setSendPaymentError('Please enter your wallet password');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const fee = await getFee('PAYMENT');
|
||||||
|
|
||||||
|
await show({
|
||||||
const sendCoinFunc = async() => {
|
message: `Would you like to transfer ${Number(paymentAmount)} QORT?`,
|
||||||
try {
|
paymentFee: fee.fee + ' QORT',
|
||||||
setSendPaymentError("");
|
});
|
||||||
setSendPaymentSuccess("");
|
setIsLoadingSendCoin(true);
|
||||||
if (!paymentTo) {
|
window
|
||||||
setSendPaymentError("Please enter a recipient");
|
.sendMessage('sendCoin', {
|
||||||
return;
|
amount: Number(paymentAmount),
|
||||||
|
receiver: paymentTo.trim(),
|
||||||
|
password: paymentPassword,
|
||||||
|
})
|
||||||
|
.then((response) => {
|
||||||
|
if (response?.error) {
|
||||||
|
setSendPaymentError(response.error);
|
||||||
|
} else {
|
||||||
|
onSuccess();
|
||||||
}
|
}
|
||||||
if (!paymentAmount) {
|
setIsLoadingSendCoin(false);
|
||||||
setSendPaymentError("Please enter an amount greater than 0");
|
})
|
||||||
return;
|
.catch((error) => {
|
||||||
}
|
console.error('Failed to send coin:', error);
|
||||||
if (!paymentPassword) {
|
setIsLoadingSendCoin(false);
|
||||||
setSendPaymentError("Please enter your wallet password");
|
});
|
||||||
return;
|
} catch (error) {
|
||||||
}
|
// error
|
||||||
const fee = await getFee('PAYMENT')
|
}
|
||||||
|
};
|
||||||
await show({
|
|
||||||
message: `Would you like to transfer ${Number(paymentAmount)} QORT?` ,
|
|
||||||
paymentFee: fee.fee + ' QORT'
|
|
||||||
})
|
|
||||||
setIsLoadingSendCoin(true);
|
|
||||||
window
|
|
||||||
.sendMessage("sendCoin", {
|
|
||||||
amount: Number(paymentAmount),
|
|
||||||
receiver: paymentTo.trim(),
|
|
||||||
password: paymentPassword,
|
|
||||||
})
|
|
||||||
.then((response) => {
|
|
||||||
if (response?.error) {
|
|
||||||
setSendPaymentError(response.error);
|
|
||||||
} else {
|
|
||||||
onSuccess()
|
|
||||||
|
|
||||||
}
|
|
||||||
setIsLoadingSendCoin(false);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error("Failed to send coin:", error);
|
|
||||||
setIsLoadingSendCoin(false);
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
// error
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: 'flex',
|
||||||
flexDirection: "column",
|
flexDirection: 'column',
|
||||||
alignItems: "flex-start",
|
alignItems: 'flex-start',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TextP
|
<TextP
|
||||||
sx={{
|
sx={{
|
||||||
textAlign: "start",
|
textAlign: 'start',
|
||||||
lineHeight: "24px",
|
lineHeight: '24px',
|
||||||
fontSize: "20px",
|
fontSize: '20px',
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Transfer QORT
|
Transfer QORT
|
||||||
</TextP>
|
</TextP>
|
||||||
<Spacer height="35px" />
|
<Spacer height="35px" />
|
||||||
<TextP
|
<TextP
|
||||||
sx={{
|
sx={{
|
||||||
textAlign: "start",
|
textAlign: 'start',
|
||||||
lineHeight: "16px",
|
lineHeight: '16px',
|
||||||
fontSize: "20px",
|
fontSize: '20px',
|
||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
color: "rgba(255, 255, 255, 0.5)",
|
color: 'rgba(255, 255, 255, 0.5)',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Balance:
|
Balance:
|
||||||
</TextP>
|
</TextP>
|
||||||
<TextP
|
<TextP
|
||||||
sx={{
|
sx={{
|
||||||
textAlign: "start",
|
textAlign: 'start',
|
||||||
lineHeight: "24px",
|
lineHeight: '24px',
|
||||||
fontSize: "20px",
|
fontSize: '20px',
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{balance?.toFixed(2)} QORT
|
{balance?.toFixed(2)} QORT
|
||||||
</TextP>
|
</TextP>
|
||||||
</Box>
|
</Box>
|
||||||
<Spacer height="35px" />
|
<Spacer height="35px" />
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<CustomLabel htmlFor="standard-adornment-name">To</CustomLabel>
|
<CustomLabel htmlFor="standard-adornment-name">To</CustomLabel>
|
||||||
<Spacer height="5px" />
|
<Spacer height="5px" />
|
||||||
<CustomInput
|
<CustomInput
|
||||||
id="standard-adornment-name"
|
id="standard-adornment-name"
|
||||||
value={paymentTo}
|
value={paymentTo}
|
||||||
onChange={(e) => setPaymentTo(e.target.value)}
|
onChange={(e) => setPaymentTo(e.target.value)}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
<Spacer height="6px" />
|
<Spacer height="6px" />
|
||||||
<CustomLabel htmlFor="standard-adornment-amount">
|
<CustomLabel htmlFor="standard-adornment-amount">Amount</CustomLabel>
|
||||||
Amount
|
<Spacer height="5px" />
|
||||||
</CustomLabel>
|
<BoundedNumericTextField
|
||||||
<Spacer height="5px" />
|
value={paymentAmount}
|
||||||
<BoundedNumericTextField
|
minValue={0}
|
||||||
value={paymentAmount}
|
maxValue={+balance}
|
||||||
minValue={0}
|
allowDecimals={true}
|
||||||
maxValue={+balance}
|
initialValue={'0'}
|
||||||
allowDecimals={true}
|
allowNegatives={false}
|
||||||
initialValue={'0'}
|
afterChange={(e: string) => setPaymentAmount(+e)}
|
||||||
allowNegatives={false}
|
/>
|
||||||
afterChange={(e: string) => setPaymentAmount(+e)}
|
<Spacer height="6px" />
|
||||||
/>
|
<CustomLabel htmlFor="standard-adornment-password">
|
||||||
<Spacer height="6px" />
|
Confirm Wallet Password
|
||||||
<CustomLabel htmlFor="standard-adornment-password">
|
</CustomLabel>
|
||||||
Confirm Wallet Password
|
<Spacer height="5px" />
|
||||||
</CustomLabel>
|
<PasswordField
|
||||||
<Spacer height="5px" />
|
id="standard-adornment-password"
|
||||||
<PasswordField
|
value={paymentPassword}
|
||||||
id="standard-adornment-password"
|
onChange={(e) => setPaymentPassword(e.target.value)}
|
||||||
value={paymentPassword}
|
autoComplete="off"
|
||||||
onChange={(e) => setPaymentPassword(e.target.value)}
|
/>
|
||||||
autoComplete="off"
|
</Box>
|
||||||
/>
|
<Spacer height="10px" />
|
||||||
</Box>
|
<ErrorText>{sendPaymentError}</ErrorText>
|
||||||
<Spacer height="10px" />
|
{/* <Typography>{sendPaymentSuccess}</Typography> */}
|
||||||
<ErrorText>{sendPaymentError}</ErrorText>
|
<Spacer height="25px" />
|
||||||
{/* <Typography>{sendPaymentSuccess}</Typography> */}
|
<CustomButton
|
||||||
<Spacer height="25px" />
|
sx={{
|
||||||
<CustomButton
|
cursor: isLoadingSendCoin ? 'default' : 'pointer',
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
if (isLoadingSendCoin) return;
|
||||||
|
sendCoinFunc();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{isLoadingSendCoin && (
|
||||||
|
<CircularProgress
|
||||||
|
size={16}
|
||||||
sx={{
|
sx={{
|
||||||
cursor: isLoadingSendCoin ? 'default' : 'pointer'
|
color: 'white',
|
||||||
}}
|
}}
|
||||||
onClick={() => {
|
/>
|
||||||
if(isLoadingSendCoin) return
|
)}
|
||||||
sendCoinFunc();
|
Send
|
||||||
}}
|
</CustomButton>
|
||||||
>
|
|
||||||
{isLoadingSendCoin && (
|
|
||||||
<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