mirror of
https://github.com/Qortal/chrome-extension.git
synced 2025-02-11 17:55:49 +00:00
batch of updates 5
This commit is contained in:
parent
69888c271a
commit
7a56f3c803
167
src/App.tsx
167
src/App.tsx
@ -45,6 +45,8 @@ import Info from "./assets/svgs/Info.svg";
|
|||||||
import CloseIcon from "@mui/icons-material/Close";
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
import { JsonView, allExpanded, darkStyles } from 'react-json-view-lite';
|
import { JsonView, allExpanded, darkStyles } from 'react-json-view-lite';
|
||||||
import 'react-json-view-lite/dist/index.css';
|
import 'react-json-view-lite/dist/index.css';
|
||||||
|
import HelpIcon from '@mui/icons-material/Help';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
createAccount,
|
createAccount,
|
||||||
generateRandomSentence,
|
generateRandomSentence,
|
||||||
@ -112,6 +114,7 @@ import { useFetchResources } from "./common/useFetchResources";
|
|||||||
import { Tutorials } from "./components/Tutorials/Tutorials";
|
import { Tutorials } from "./components/Tutorials/Tutorials";
|
||||||
import { useHandleTutorials } from "./components/Tutorials/useHandleTutorials";
|
import { useHandleTutorials } from "./components/Tutorials/useHandleTutorials";
|
||||||
import { CoreSyncStatus } from "./components/CoreSyncStatus";
|
import { CoreSyncStatus } from "./components/CoreSyncStatus";
|
||||||
|
import BoundedNumericTextField from "./common/BoundedNumericTextField";
|
||||||
|
|
||||||
type extStates =
|
type extStates =
|
||||||
| "not-authenticated"
|
| "not-authenticated"
|
||||||
@ -447,7 +450,16 @@ function App() {
|
|||||||
isFocusedRef.current = isFocused;
|
isFocusedRef.current = isFocused;
|
||||||
}, [isFocused]);
|
}, [isFocused]);
|
||||||
|
|
||||||
|
useEffect(()=> {
|
||||||
|
if(!shownTutorialsInitiated) return
|
||||||
|
if(extState === 'not-authenticated'){
|
||||||
|
showTutorial('create-account')
|
||||||
|
} else if(extState === "create-wallet" && walletToBeDownloaded){
|
||||||
|
showTutorial('important-information')
|
||||||
|
} else if(extState === "authenticated"){
|
||||||
|
showTutorial('getting-started')
|
||||||
|
}
|
||||||
|
}, [extState, walletToBeDownloaded, shownTutorialsInitiated])
|
||||||
|
|
||||||
// const checkIfUserHasLocalNode = useCallback(async () => {
|
// const checkIfUserHasLocalNode = useCallback(async () => {
|
||||||
// try {
|
// try {
|
||||||
@ -532,7 +544,7 @@ function App() {
|
|||||||
let wallet = structuredClone(rawWallet);
|
let wallet = structuredClone(rawWallet);
|
||||||
|
|
||||||
const res = await decryptStoredWallet(password, wallet);
|
const res = await decryptStoredWallet(password, wallet);
|
||||||
const wallet2 = new PhraseWallet(res, walletVersion);
|
const wallet2 = new PhraseWallet(res, wallet?.version || walletVersion);
|
||||||
wallet = await wallet2.generateSaveWalletData(
|
wallet = await wallet2.generateSaveWalletData(
|
||||||
password,
|
password,
|
||||||
crypto.kdfThreads,
|
crypto.kdfThreads,
|
||||||
@ -588,43 +600,54 @@ function App() {
|
|||||||
setLtcBalanceLoading(false);
|
setLtcBalanceLoading(false);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const sendCoinFunc = () => {
|
const sendCoinFunc = async () => {
|
||||||
setSendPaymentError("");
|
try {
|
||||||
setSendPaymentSuccess("");
|
setSendPaymentError("");
|
||||||
if (!paymentTo) {
|
setSendPaymentSuccess("");
|
||||||
setSendPaymentError("Please enter a recipient");
|
if (!paymentTo) {
|
||||||
return;
|
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;
|
|
||||||
}
|
|
||||||
setIsLoading(true);
|
|
||||||
chrome?.runtime?.sendMessage(
|
|
||||||
{
|
|
||||||
action: "sendCoin",
|
|
||||||
payload: {
|
|
||||||
amount: Number(paymentAmount),
|
|
||||||
receiver: paymentTo.trim(),
|
|
||||||
password: paymentPassword,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
(response) => {
|
|
||||||
if (response?.error) {
|
|
||||||
setSendPaymentError(response.error);
|
|
||||||
} else {
|
|
||||||
setIsOpenSendQort(false);
|
|
||||||
setIsOpenSendQortSuccess(true);
|
|
||||||
// setExtstate("transfer-success-regular");
|
|
||||||
// setSendPaymentSuccess("Payment successfully sent");
|
|
||||||
}
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
}
|
||||||
);
|
if (!paymentAmount) {
|
||||||
|
setSendPaymentError("Please enter an amount greater than 0");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!paymentPassword) {
|
||||||
|
setSendPaymentError("Please enter your wallet password");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const fee = await getFee('PAYMENT')
|
||||||
|
|
||||||
|
await show({
|
||||||
|
message: `Would you like to transfer ${Number(paymentAmount)} QORT?` ,
|
||||||
|
paymentFee: fee.fee + ' QORT'
|
||||||
|
})
|
||||||
|
setIsLoading(true);
|
||||||
|
chrome?.runtime?.sendMessage(
|
||||||
|
{
|
||||||
|
action: "sendCoin",
|
||||||
|
payload: {
|
||||||
|
amount: Number(paymentAmount),
|
||||||
|
receiver: paymentTo.trim(),
|
||||||
|
password: paymentPassword,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
(response) => {
|
||||||
|
if (response?.error) {
|
||||||
|
setSendPaymentError(response.error);
|
||||||
|
} else {
|
||||||
|
setIsOpenSendQort(false);
|
||||||
|
setIsOpenSendQortSuccess(true);
|
||||||
|
// setExtstate("transfer-success-regular");
|
||||||
|
// setSendPaymentSuccess("Payment successfully sent");
|
||||||
|
}
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
//error
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const clearAllStates = () => {
|
const clearAllStates = () => {
|
||||||
@ -1046,6 +1069,11 @@ function App() {
|
|||||||
try {
|
try {
|
||||||
if(hasSettingsChanged){
|
if(hasSettingsChanged){
|
||||||
await showUnsavedChanges({message: 'Your settings have changed. If you logout you will lose your changes. Click on the save button in the header to keep your changed settings.'})
|
await showUnsavedChanges({message: 'Your settings have changed. If you logout you will lose your changes. Click on the save button in the header to keep your changed settings.'})
|
||||||
|
} if(extState === 'authenticated') {
|
||||||
|
await showUnsavedChanges({
|
||||||
|
message:
|
||||||
|
"Are you sure you would like to logout?",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
chrome?.runtime?.sendMessage({ action: "logout" }, (response) => {
|
chrome?.runtime?.sendMessage({ action: "logout" }, (response) => {
|
||||||
if (response) {
|
if (response) {
|
||||||
@ -1580,6 +1608,23 @@ function App() {
|
|||||||
alignItems: 'center'
|
alignItems: 'center'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{(desktopViewMode === "apps" || desktopViewMode === "home") && (
|
||||||
|
<ButtonBase onClick={()=> {
|
||||||
|
if(desktopViewMode === "apps"){
|
||||||
|
showTutorial('qapps', true)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
showTutorial('create-account', true)
|
||||||
|
|
||||||
|
}
|
||||||
|
}} >
|
||||||
|
<HelpIcon sx={{
|
||||||
|
color: 'var(--unread)'
|
||||||
|
}} />
|
||||||
|
</ButtonBase>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Spacer height="20px" />
|
||||||
<img
|
<img
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setExtstate("download-wallet");
|
setExtstate("download-wallet");
|
||||||
@ -1767,12 +1812,14 @@ function App() {
|
|||||||
Amount
|
Amount
|
||||||
</CustomLabel>
|
</CustomLabel>
|
||||||
<Spacer height="5px" />
|
<Spacer height="5px" />
|
||||||
<CustomInput
|
<BoundedNumericTextField
|
||||||
id="standard-adornment-amount"
|
|
||||||
type="number"
|
|
||||||
value={paymentAmount}
|
value={paymentAmount}
|
||||||
onChange={(e) => setPaymentAmount(+e.target.value)}
|
minValue={0}
|
||||||
autoComplete="off"
|
maxValue={+balance}
|
||||||
|
allowDecimals={true}
|
||||||
|
initialValue={'0'}
|
||||||
|
allowNegatives={false}
|
||||||
|
afterChange={(e: string) => setPaymentAmount(+e)}
|
||||||
/>
|
/>
|
||||||
<Spacer height="6px" />
|
<Spacer height="6px" />
|
||||||
<CustomLabel htmlFor="standard-adornment-password">
|
<CustomLabel htmlFor="standard-adornment-password">
|
||||||
@ -2648,19 +2695,27 @@ function App() {
|
|||||||
aria-labelledby="alert-dialog-title"
|
aria-labelledby="alert-dialog-title"
|
||||||
aria-describedby="alert-dialog-description"
|
aria-describedby="alert-dialog-description"
|
||||||
>
|
>
|
||||||
<DialogTitle id="alert-dialog-title">{"Publish"}</DialogTitle>
|
<DialogTitle id="alert-dialog-title">{message.paymentFee ? "Payment" : "Publish"}</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogContentText id="alert-dialog-description">
|
<DialogContentText id="alert-dialog-description">
|
||||||
{message.message}
|
{message.message}
|
||||||
</DialogContentText>
|
</DialogContentText>
|
||||||
<DialogContentText id="alert-dialog-description2">
|
{message?.paymentFee && (
|
||||||
publish fee: {message.publishFee}
|
<DialogContentText id="alert-dialog-description2">
|
||||||
</DialogContentText>
|
payment fee: {message.paymentFee}
|
||||||
|
</DialogContentText>
|
||||||
|
)}
|
||||||
|
{message?.publishFee && (
|
||||||
|
<DialogContentText id="alert-dialog-description2">
|
||||||
|
publish fee: {message.publishFee}
|
||||||
|
</DialogContentText>
|
||||||
|
)}
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button sx={{
|
<Button sx={{
|
||||||
backgroundColor: 'var(--green)',
|
backgroundColor: 'var(--green)',
|
||||||
color: 'black',
|
color: 'black',
|
||||||
|
fontWeight: 'bold',
|
||||||
opacity: 0.7,
|
opacity: 0.7,
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
backgroundColor: 'var(--green)',
|
backgroundColor: 'var(--green)',
|
||||||
@ -2671,11 +2726,12 @@ function App() {
|
|||||||
accept
|
accept
|
||||||
</Button>
|
</Button>
|
||||||
<Button sx={{
|
<Button sx={{
|
||||||
backgroundColor: 'var(--unread)',
|
backgroundColor: 'var(--danger)',
|
||||||
color: 'black',
|
color: 'black',
|
||||||
|
fontWeight: 'bold',
|
||||||
opacity: 0.7,
|
opacity: 0.7,
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
backgroundColor: 'var(--unread)',
|
backgroundColor: 'var(--danger)',
|
||||||
color: 'black',
|
color: 'black',
|
||||||
opacity: 1
|
opacity: 1
|
||||||
},
|
},
|
||||||
@ -3038,6 +3094,19 @@ function App() {
|
|||||||
{renderProfile()}
|
{renderProfile()}
|
||||||
</DrawerComponent>
|
</DrawerComponent>
|
||||||
</GlobalContext.Provider>
|
</GlobalContext.Provider>
|
||||||
|
{extState === "create-wallet" && walletToBeDownloaded && (
|
||||||
|
<ButtonBase onClick={()=> {
|
||||||
|
showTutorial('important-information', true)
|
||||||
|
}} sx={{
|
||||||
|
position: 'fixed',
|
||||||
|
bottom: '25px',
|
||||||
|
right: '25px'
|
||||||
|
}}>
|
||||||
|
<HelpIcon sx={{
|
||||||
|
color: 'var(--unread)'
|
||||||
|
}} />
|
||||||
|
</ButtonBase>
|
||||||
|
)}
|
||||||
</AppContainer>
|
</AppContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2601,14 +2601,14 @@ export async function sendCoin({ password, amount, receiver }, skipConfirmPasswo
|
|||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
const response = await decryptStoredWallet(password, wallet);
|
const response = await decryptStoredWallet(password, wallet);
|
||||||
const wallet2 = new PhraseWallet(response, walletVersion);
|
const wallet2 = new PhraseWallet(response, wallet?.version || walletVersion);
|
||||||
|
|
||||||
keyPair = wallet2._addresses[0].keyPair;
|
keyPair = wallet2._addresses[0].keyPair;
|
||||||
}
|
}
|
||||||
|
|
||||||
const lastRef = await getLastRef();
|
const lastRef = await getLastRef();
|
||||||
const fee = await sendQortFee();
|
const fee = await sendQortFee();
|
||||||
const validApi = await findUsableApi();
|
const validApi = null;
|
||||||
|
|
||||||
const res = await makeTransactionRequest(
|
const res = await makeTransactionRequest(
|
||||||
confirmReceiver,
|
confirmReceiver,
|
||||||
@ -3254,7 +3254,7 @@ chrome?.runtime?.onMessage.addListener((request, sender, sendResponse) => {
|
|||||||
decryptWallet({
|
decryptWallet({
|
||||||
password,
|
password,
|
||||||
wallet,
|
wallet,
|
||||||
walletVersion,
|
walletVersion: wallet?.version || walletVersion,
|
||||||
})
|
})
|
||||||
.then((hasDecrypted) => {
|
.then((hasDecrypted) => {
|
||||||
sendResponse(hasDecrypted);
|
sendResponse(hasDecrypted);
|
||||||
|
158
src/common/BoundedNumericTextField.tsx
Normal file
158
src/common/BoundedNumericTextField.tsx
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
import {
|
||||||
|
IconButton,
|
||||||
|
InputAdornment,
|
||||||
|
TextField,
|
||||||
|
TextFieldProps,
|
||||||
|
} from "@mui/material";
|
||||||
|
import React, { useRef, useState } from "react";
|
||||||
|
import AddIcon from "@mui/icons-material/Add";
|
||||||
|
import RemoveIcon from "@mui/icons-material/Remove";
|
||||||
|
import {
|
||||||
|
removeTrailingZeros,
|
||||||
|
setNumberWithinBounds,
|
||||||
|
} from "./numberFunctions.ts";
|
||||||
|
import { CustomInput } from "../App-styles.ts";
|
||||||
|
|
||||||
|
type eventType = React.ChangeEvent<HTMLInputElement>;
|
||||||
|
type BoundedNumericTextFieldProps = {
|
||||||
|
minValue: number;
|
||||||
|
maxValue: number;
|
||||||
|
addIconButtons?: boolean;
|
||||||
|
allowDecimals?: boolean;
|
||||||
|
allowNegatives?: boolean;
|
||||||
|
afterChange?: (s: string) => void;
|
||||||
|
initialValue?: string;
|
||||||
|
maxSigDigits?: number;
|
||||||
|
} & TextFieldProps;
|
||||||
|
|
||||||
|
export const BoundedNumericTextField = ({
|
||||||
|
minValue,
|
||||||
|
maxValue,
|
||||||
|
addIconButtons = true,
|
||||||
|
allowDecimals = true,
|
||||||
|
allowNegatives = false,
|
||||||
|
afterChange,
|
||||||
|
initialValue,
|
||||||
|
maxSigDigits = 6,
|
||||||
|
...props
|
||||||
|
}: BoundedNumericTextFieldProps) => {
|
||||||
|
const [textFieldValue, setTextFieldValue] = useState<string>(
|
||||||
|
initialValue || ""
|
||||||
|
);
|
||||||
|
const ref = useRef<HTMLInputElement | null>(null);
|
||||||
|
|
||||||
|
const stringIsEmpty = (value: string) => {
|
||||||
|
return value === "";
|
||||||
|
};
|
||||||
|
const isAllZerosNum = /^0*\.?0*$/;
|
||||||
|
const isFloatNum = /^-?[0-9]*\.?[0-9]*$/;
|
||||||
|
const isIntegerNum = /^-?[0-9]+$/;
|
||||||
|
const skipMinMaxCheck = (value: string) => {
|
||||||
|
const lastIndexIsDecimal = value.charAt(value.length - 1) === ".";
|
||||||
|
const isEmpty = stringIsEmpty(value);
|
||||||
|
const isAllZeros = isAllZerosNum.test(value);
|
||||||
|
const isInteger = isIntegerNum.test(value);
|
||||||
|
// skipping minMax on all 0s allows values less than 1 to be entered
|
||||||
|
|
||||||
|
return lastIndexIsDecimal || isEmpty || (isAllZeros && !isInteger);
|
||||||
|
};
|
||||||
|
|
||||||
|
const setMinMaxValue = (value: string): string => {
|
||||||
|
if (skipMinMaxCheck(value)) return value;
|
||||||
|
const valueNum = Number(value);
|
||||||
|
|
||||||
|
const boundedNum = setNumberWithinBounds(valueNum, minValue, maxValue);
|
||||||
|
|
||||||
|
const numberInBounds = boundedNum === valueNum;
|
||||||
|
return numberInBounds ? value : boundedNum.toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
const getSigDigits = (number: string) => {
|
||||||
|
if (isIntegerNum.test(number)) return 0;
|
||||||
|
const decimalSplit = number.split(".");
|
||||||
|
return decimalSplit[decimalSplit.length - 1].length;
|
||||||
|
};
|
||||||
|
|
||||||
|
const sigDigitsExceeded = (number: string, sigDigits: number) => {
|
||||||
|
return getSigDigits(number) > sigDigits;
|
||||||
|
};
|
||||||
|
|
||||||
|
const filterTypes = (value: string) => {
|
||||||
|
if (allowDecimals === false) value = value.replace(".", "");
|
||||||
|
if (allowNegatives === false) value = value.replace("-", "");
|
||||||
|
if (sigDigitsExceeded(value, maxSigDigits)) {
|
||||||
|
value = value.substring(0, value.length - 1);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
const filterValue = (value: string) => {
|
||||||
|
if (stringIsEmpty(value)) return "";
|
||||||
|
value = filterTypes(value);
|
||||||
|
if (isFloatNum.test(value)) {
|
||||||
|
return setMinMaxValue(value);
|
||||||
|
}
|
||||||
|
return textFieldValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
const listeners = (e: eventType) => {
|
||||||
|
const newValue = filterValue(e.target.value);
|
||||||
|
setTextFieldValue(newValue);
|
||||||
|
if (afterChange) afterChange(newValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeValueWithIncDecButton = (changeAmount: number) => {
|
||||||
|
const changedValue = (+textFieldValue + changeAmount).toString();
|
||||||
|
const inBoundsValue = setMinMaxValue(changedValue);
|
||||||
|
setTextFieldValue(inBoundsValue);
|
||||||
|
if (afterChange) afterChange(inBoundsValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatValueOnBlur = (e: eventType) => {
|
||||||
|
let value = e.target.value;
|
||||||
|
if (stringIsEmpty(value) || value === ".") {
|
||||||
|
setTextFieldValue("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = setMinMaxValue(value);
|
||||||
|
value = removeTrailingZeros(value);
|
||||||
|
if (isAllZerosNum.test(value)) value = minValue.toString();
|
||||||
|
|
||||||
|
setTextFieldValue(value);
|
||||||
|
};
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const { onChange, ...noChangeProps } = { ...props };
|
||||||
|
return (
|
||||||
|
<CustomInput
|
||||||
|
{...noChangeProps}
|
||||||
|
InputProps={{
|
||||||
|
...props?.InputProps,
|
||||||
|
endAdornment: addIconButtons ? (
|
||||||
|
<InputAdornment position="end">
|
||||||
|
<IconButton size="small" onClick={() => changeValueWithIncDecButton(1)}>
|
||||||
|
<AddIcon sx={{
|
||||||
|
color: 'white'
|
||||||
|
}} />{" "}
|
||||||
|
</IconButton>
|
||||||
|
<IconButton size="small" onClick={() => changeValueWithIncDecButton(-1)}>
|
||||||
|
<RemoveIcon sx={{
|
||||||
|
color: 'white'
|
||||||
|
}} />{" "}
|
||||||
|
</IconButton>
|
||||||
|
</InputAdornment>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
onChange={e => listeners(e as eventType)}
|
||||||
|
onBlur={e => {
|
||||||
|
formatValueOnBlur(e as eventType);
|
||||||
|
}}
|
||||||
|
autoComplete="off"
|
||||||
|
value={textFieldValue}
|
||||||
|
inputRef={ref}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default BoundedNumericTextField;
|
63
src/common/numberFunctions.ts
Normal file
63
src/common/numberFunctions.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
export const truncateNumber = (value: string | number, sigDigits: number) => {
|
||||||
|
return Number(value).toFixed(sigDigits);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const removeTrailingZeros = (s: string) => {
|
||||||
|
return Number(s).toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
export const setNumberWithinBounds = (
|
||||||
|
num: number,
|
||||||
|
minValue: number,
|
||||||
|
maxValue: number
|
||||||
|
) => {
|
||||||
|
if (num > maxValue) return maxValue;
|
||||||
|
if (num < minValue) return minValue;
|
||||||
|
return num;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const numberToInt = (num: number) => {
|
||||||
|
return Math.floor(num);
|
||||||
|
};
|
||||||
|
|
||||||
|
type ByteFormat = "Decimal" | "Binary";
|
||||||
|
export function formatBytes(
|
||||||
|
bytes: number,
|
||||||
|
decimals = 2,
|
||||||
|
format: ByteFormat = "Binary"
|
||||||
|
) {
|
||||||
|
if (bytes === 0) return "0 Bytes";
|
||||||
|
|
||||||
|
const k = format === "Binary" ? 1024 : 1000;
|
||||||
|
const dm = decimals < 0 ? 0 : decimals;
|
||||||
|
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
||||||
|
|
||||||
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||||
|
|
||||||
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formatTime(seconds: number): string {
|
||||||
|
seconds = Math.floor(seconds);
|
||||||
|
const minutes: number | string = Math.floor(seconds / 60);
|
||||||
|
let hours: number | string = Math.floor(minutes / 60);
|
||||||
|
|
||||||
|
let remainingSeconds: number | string = seconds % 60;
|
||||||
|
let remainingMinutes: number | string = minutes % 60;
|
||||||
|
|
||||||
|
if (remainingSeconds < 10) {
|
||||||
|
remainingSeconds = "0" + remainingSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remainingMinutes < 10) {
|
||||||
|
remainingMinutes = "0" + remainingMinutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hours === 0) {
|
||||||
|
hours = "";
|
||||||
|
} else {
|
||||||
|
hours = hours + ":";
|
||||||
|
}
|
||||||
|
|
||||||
|
return hours + remainingMinutes + ":" + remainingSeconds;
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { AppsHomeDesktop } from "./AppsHomeDesktop";
|
import { AppsHomeDesktop } from "./AppsHomeDesktop";
|
||||||
import { Spacer } from "../../common/Spacer";
|
import { Spacer } from "../../common/Spacer";
|
||||||
import { MyContext, getBaseApiReact } from "../../App";
|
import { GlobalContext, MyContext, getBaseApiReact } from "../../App";
|
||||||
import { AppInfo } from "./AppInfo";
|
import { AppInfo } from "./AppInfo";
|
||||||
import {
|
import {
|
||||||
executeEvent,
|
executeEvent,
|
||||||
@ -32,6 +32,8 @@ export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktop
|
|||||||
const [isNewTabWindow, setIsNewTabWindow] = useState(false);
|
const [isNewTabWindow, setIsNewTabWindow] = useState(false);
|
||||||
const [categories, setCategories] = useState([])
|
const [categories, setCategories] = useState([])
|
||||||
const iframeRefs = useRef({});
|
const iframeRefs = useRef({});
|
||||||
|
const { showTutorial } = useContext(GlobalContext);
|
||||||
|
|
||||||
const myApp = useMemo(()=> {
|
const myApp = useMemo(()=> {
|
||||||
|
|
||||||
return availableQapps.find((app)=> app.name === myName && app.service === 'APP')
|
return availableQapps.find((app)=> app.name === myName && app.service === 'APP')
|
||||||
@ -53,6 +55,13 @@ export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktop
|
|||||||
}, 100);
|
}, 100);
|
||||||
}, [show, tabs, selectedTab, isNewTabWindow]);
|
}, [show, tabs, selectedTab, isNewTabWindow]);
|
||||||
|
|
||||||
|
useEffect(()=> {
|
||||||
|
if(show){
|
||||||
|
showTutorial('qapps')
|
||||||
|
}
|
||||||
|
}, [show])
|
||||||
|
|
||||||
|
|
||||||
const getCategories = React.useCallback(async () => {
|
const getCategories = React.useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
const url = `${getBaseApiReact()}/arbitrary/categories`;
|
const url = `${getBaseApiReact()}/arbitrary/categories`;
|
||||||
|
@ -230,7 +230,7 @@ export const AddGroupList = ({ setInfoSnack, setOpenSnack }) => {
|
|||||||
)}
|
)}
|
||||||
{group?.isOpen === true && (
|
{group?.isOpen === true && (
|
||||||
<NoEncryptionGmailerrorredIcon sx={{
|
<NoEncryptionGmailerrorredIcon sx={{
|
||||||
color: 'var(--unread)'
|
color: 'var(--danger)'
|
||||||
}} />
|
}} />
|
||||||
)}
|
)}
|
||||||
<Spacer width="15px" />
|
<Spacer width="15px" />
|
||||||
|
@ -538,14 +538,12 @@ export const NewThread = ({
|
|||||||
</NewMessageSendP>
|
</NewMessageSendP>
|
||||||
{isMessage ? (
|
{isMessage ? (
|
||||||
<SendNewMessage
|
<SendNewMessage
|
||||||
color="red"
|
|
||||||
opacity={1}
|
opacity={1}
|
||||||
height="25px"
|
height="25px"
|
||||||
width="25px"
|
width="25px"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<CreateThreadIcon
|
<CreateThreadIcon
|
||||||
color="red"
|
|
||||||
opacity={1}
|
opacity={1}
|
||||||
height="25px"
|
height="25px"
|
||||||
width="25px"
|
width="25px"
|
||||||
|
@ -718,7 +718,7 @@ export const Group = ({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
return hasUnread;
|
return hasUnread;
|
||||||
}, [timestampEnterData, groups, myAddress]);
|
}, [timestampEnterData, groups, myAddress, groupChatTimestamps]);
|
||||||
|
|
||||||
const groupsAnnHasUnread = useMemo(() => {
|
const groupsAnnHasUnread = useMemo(() => {
|
||||||
let hasUnread = false;
|
let hasUnread = false;
|
||||||
@ -1318,6 +1318,7 @@ export const Group = ({
|
|||||||
setSecretKeyDetails(null);
|
setSecretKeyDetails(null);
|
||||||
setNewEncryptionNotification(null);
|
setNewEncryptionNotification(null);
|
||||||
setMemberCountFromSecretKeyData(null);
|
setMemberCountFromSecretKeyData(null);
|
||||||
|
setIsForceShowCreationKeyPopup(false)
|
||||||
setSelectedGroup(null);
|
setSelectedGroup(null);
|
||||||
setSelectedDirect(null);
|
setSelectedDirect(null);
|
||||||
setGroups([]);
|
setGroups([]);
|
||||||
@ -1384,6 +1385,7 @@ export const Group = ({
|
|||||||
setAdminsWithNames([]);
|
setAdminsWithNames([]);
|
||||||
setMembers([]);
|
setMembers([]);
|
||||||
setMemberCountFromSecretKeyData(null);
|
setMemberCountFromSecretKeyData(null);
|
||||||
|
setIsForceShowCreationKeyPopup(false)
|
||||||
setTriedToFetchSecretKey(false);
|
setTriedToFetchSecretKey(false);
|
||||||
setFirstSecretKeyInCreation(false);
|
setFirstSecretKeyInCreation(false);
|
||||||
setIsOpenSideViewDirects(false)
|
setIsOpenSideViewDirects(false)
|
||||||
@ -1439,6 +1441,7 @@ export const Group = ({
|
|||||||
setAdminsWithNames([]);
|
setAdminsWithNames([]);
|
||||||
setMembers([]);
|
setMembers([]);
|
||||||
setMemberCountFromSecretKeyData(null);
|
setMemberCountFromSecretKeyData(null);
|
||||||
|
setIsForceShowCreationKeyPopup(false)
|
||||||
setTriedToFetchSecretKey(false);
|
setTriedToFetchSecretKey(false);
|
||||||
setFirstSecretKeyInCreation(false);
|
setFirstSecretKeyInCreation(false);
|
||||||
setGroupSection("chat");
|
setGroupSection("chat");
|
||||||
@ -1490,6 +1493,7 @@ export const Group = ({
|
|||||||
setAdminsWithNames([]);
|
setAdminsWithNames([]);
|
||||||
setMembers([]);
|
setMembers([]);
|
||||||
setMemberCountFromSecretKeyData(null);
|
setMemberCountFromSecretKeyData(null);
|
||||||
|
setIsForceShowCreationKeyPopup(false)
|
||||||
setTriedToFetchSecretKey(false);
|
setTriedToFetchSecretKey(false);
|
||||||
setFirstSecretKeyInCreation(false);
|
setFirstSecretKeyInCreation(false);
|
||||||
setGroupSection("announcement");
|
setGroupSection("announcement");
|
||||||
@ -1551,6 +1555,7 @@ export const Group = ({
|
|||||||
setAdminsWithNames([]);
|
setAdminsWithNames([]);
|
||||||
setMembers([]);
|
setMembers([]);
|
||||||
setMemberCountFromSecretKeyData(null);
|
setMemberCountFromSecretKeyData(null);
|
||||||
|
setIsForceShowCreationKeyPopup(false)
|
||||||
setTriedToFetchSecretKey(false);
|
setTriedToFetchSecretKey(false);
|
||||||
setFirstSecretKeyInCreation(false);
|
setFirstSecretKeyInCreation(false);
|
||||||
setGroupSection("forum");
|
setGroupSection("forum");
|
||||||
@ -1607,6 +1612,7 @@ export const Group = ({
|
|||||||
setAdminsWithNames([]);
|
setAdminsWithNames([]);
|
||||||
setMembers([]);
|
setMembers([]);
|
||||||
setMemberCountFromSecretKeyData(null);
|
setMemberCountFromSecretKeyData(null);
|
||||||
|
setIsForceShowCreationKeyPopup(false)
|
||||||
setTriedToFetchSecretKey(false);
|
setTriedToFetchSecretKey(false);
|
||||||
setFirstSecretKeyInCreation(false);
|
setFirstSecretKeyInCreation(false);
|
||||||
setIsOpenSideViewDirects(false)
|
setIsOpenSideViewDirects(false)
|
||||||
@ -1843,7 +1849,7 @@ export const Group = ({
|
|||||||
direct?.timestamp) && (
|
direct?.timestamp) && (
|
||||||
<MarkChatUnreadIcon
|
<MarkChatUnreadIcon
|
||||||
sx={{
|
sx={{
|
||||||
color: "red",
|
color: "var(--unread)",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@ -2105,6 +2111,7 @@ export const Group = ({
|
|||||||
setGroupOwner(null)
|
setGroupOwner(null)
|
||||||
setMembers([]);
|
setMembers([]);
|
||||||
setMemberCountFromSecretKeyData(null);
|
setMemberCountFromSecretKeyData(null);
|
||||||
|
setIsForceShowCreationKeyPopup(false)
|
||||||
setHideCommonKeyPopup(false);
|
setHideCommonKeyPopup(false);
|
||||||
setFirstSecretKeyInCreation(false);
|
setFirstSecretKeyInCreation(false);
|
||||||
// setGroupSection("announcement");
|
// setGroupSection("announcement");
|
||||||
@ -2226,7 +2233,7 @@ export const Group = ({
|
|||||||
!groupAnnouncements[group?.groupId]?.seentimestamp && (
|
!groupAnnouncements[group?.groupId]?.seentimestamp && (
|
||||||
<CampaignIcon
|
<CampaignIcon
|
||||||
sx={{
|
sx={{
|
||||||
color: "red",
|
color: "var(--unread)",
|
||||||
marginRight: "5px",
|
marginRight: "5px",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -2242,7 +2249,7 @@ export const Group = ({
|
|||||||
group?.timestamp) && (
|
group?.timestamp) && (
|
||||||
<MarkChatUnreadIcon
|
<MarkChatUnreadIcon
|
||||||
sx={{
|
sx={{
|
||||||
color: "red",
|
color: "var(--unread)",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -499,7 +499,7 @@ export const ListOfGroupPromotions = () => {
|
|||||||
)}
|
)}
|
||||||
{promotion?.isOpen === true && (
|
{promotion?.isOpen === true && (
|
||||||
<NoEncryptionGmailerrorredIcon sx={{
|
<NoEncryptionGmailerrorredIcon sx={{
|
||||||
color: 'var(--unread)'
|
color: 'var(--danger)'
|
||||||
}} />
|
}} />
|
||||||
)}
|
)}
|
||||||
<Typography
|
<Typography
|
||||||
|
@ -182,7 +182,7 @@ export const UserListOfInvites = ({myAddress, setInfoSnack, setOpenSnack}) => {
|
|||||||
)}
|
)}
|
||||||
{invite?.isOpen === true && (
|
{invite?.isOpen === true && (
|
||||||
<NoEncryptionGmailerrorredIcon sx={{
|
<NoEncryptionGmailerrorredIcon sx={{
|
||||||
color: 'var(--unread)'
|
color: 'var(--danger)'
|
||||||
}} />
|
}} />
|
||||||
)}
|
)}
|
||||||
<Spacer width="15px" />
|
<Spacer width="15px" />
|
||||||
|
@ -34,11 +34,10 @@
|
|||||||
--bg-primary : rgba(31, 32, 35, 1);
|
--bg-primary : rgba(31, 32, 35, 1);
|
||||||
--bg-2: #27282c;
|
--bg-2: #27282c;
|
||||||
--bg-3: rgba(0, 0, 0, 0.1);
|
--bg-3: rgba(0, 0, 0, 0.1);
|
||||||
--unread: #B14646;
|
--unread: #4297e2;
|
||||||
--apps-circle: #1F2023;
|
--apps-circle: #1F2023;
|
||||||
--green: #5EB049;
|
--green: #5EB049;
|
||||||
--danger: #B14646;
|
--danger: #B14646;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user