import { Fragment, useContext, useEffect, useState } from 'react'; import List from '@mui/material/List'; import ListItem from '@mui/material/ListItem'; import Divider from '@mui/material/Divider'; import ListItemText from '@mui/material/ListItemText'; import ListItemAvatar from '@mui/material/ListItemAvatar'; import Avatar from '@mui/material/Avatar'; import Typography from '@mui/material/Typography'; import { Box, Button, ButtonBase, Dialog, DialogActions, DialogContent, DialogTitle, IconButton, Input, useTheme, } from '@mui/material'; import { CustomButton } from './styles/App-styles'; import { useDropzone } from 'react-dropzone'; import EditIcon from '@mui/icons-material/Edit'; import { Label } from './components/Group/AddGroup'; import { Spacer } from './common/Spacer'; import { getWallets, storeWallets, walletVersion } from './background'; import { useModal } from './common/useModal'; import PhraseWallet from './utils/generateWallet/phrase-wallet'; import { decryptStoredWalletFromSeedPhrase } from './utils/decryptWallet'; import { crypto } from './constants/decryptWallet'; import { LoadingButton } from '@mui/lab'; import { PasswordField } from './components'; import { HtmlTooltip } from './components/NotAuthenticated'; import { QORTAL_APP_CONTEXT } from './App'; import { useTranslation } from 'react-i18next'; const parsefilenameQortal = (filename) => { return filename.startsWith('qortal_backup_') ? filename.slice(14) : filename; }; export const Wallets = ({ setExtState, setRawWallet, rawWallet }) => { const [wallets, setWallets] = useState([]); const [isLoading, setIsLoading] = useState(true); const [seedValue, setSeedValue] = useState(''); const [seedName, setSeedName] = useState(''); const [seedError, setSeedError] = useState(''); const { hasSeenGettingStarted } = useContext(QORTAL_APP_CONTEXT); const [password, setPassword] = useState(''); const [isOpenSeedModal, setIsOpenSeedModal] = useState(false); const [isLoadingEncryptSeed, setIsLoadingEncryptSeed] = useState(false); const theme = useTheme(); const { t } = useTranslation(['auth', 'core', 'group']); const { isShow, onCancel, onOk, show } = useModal(); const { getRootProps, getInputProps } = useDropzone({ accept: { 'application/json': ['.json'], // Only accept JSON files }, onDrop: async (acceptedFiles) => { const files: any = acceptedFiles; let importedWallets: any = []; for (const file of files) { try { const fileContents = await new Promise((resolve, reject) => { const reader = new FileReader(); reader.onabort = () => reject('File reading was aborted'); reader.onerror = () => reject('File reading has failed'); reader.onload = () => { // Resolve the promise with the reader result when reading completes resolve(reader.result); }; // Read the file as text reader.readAsText(file); }); if (typeof fileContents !== 'string') continue; const parsedData = JSON.parse(fileContents); importedWallets.push({ ...parsedData, filename: file?.name }); } catch (error) { console.error(error); } } const uniqueInitialMap = new Map(); // Only add a message if it doesn't already exist in the Map importedWallets.forEach((wallet) => { if (!wallet?.address0) return; if (!uniqueInitialMap.has(wallet?.address0)) { uniqueInitialMap.set(wallet?.address0, wallet); } }); const data = Array.from(uniqueInitialMap.values()); if (data && data?.length > 0) { const uniqueNewWallets = data.filter( (newWallet) => !wallets.some( (existingWallet) => existingWallet?.address0 === newWallet?.address0 ) ); setWallets([...wallets, ...uniqueNewWallets]); } }, }); const updateWalletItem = (idx, wallet) => { setWallets((prev) => { let copyPrev = [...prev]; if (wallet === null) { copyPrev.splice(idx, 1); // Use splice to remove the item return copyPrev; } else { copyPrev[idx] = wallet; // Update the wallet at the specified index return copyPrev; } }); }; const handleSetSeedValue = async () => { try { setIsOpenSeedModal(true); const { seedValue, seedName, password } = await show({ message: '', publishFee: '', }); setIsLoadingEncryptSeed(true); const res = await decryptStoredWalletFromSeedPhrase(seedValue); const wallet2 = new PhraseWallet(res, walletVersion); const wallet = await wallet2.generateSaveWalletData( password, crypto.kdfThreads, () => {} ); if (wallet?.address0) { setWallets([ ...wallets, { ...wallet, name: seedName, }, ]); setIsOpenSeedModal(false); setSeedValue(''); setSeedName(''); setPassword(''); setSeedError(''); } else { setSeedError( t('auth:message.error.account_creation', { postProcess: 'capitalizeFirstChar', }) ); } } catch (error) { setSeedError( error?.message || t('auth:message.error.account_creation', { postProcess: 'capitalizeFirstChar', }) ); } finally { setIsLoadingEncryptSeed(false); } }; const selectedWalletFunc = (wallet) => { setRawWallet(wallet); setExtState('wallet-dropped'); }; useEffect(() => { setIsLoading(true); getWallets() .then((res) => { if (res && Array.isArray(res)) { setWallets(res); } setIsLoading(false); }) .catch((error) => { console.error(error); setIsLoading(false); }); }, []); useEffect(() => { if (!isLoading && wallets && Array.isArray(wallets)) { storeWallets(wallets); } }, [wallets, isLoading]); if (isLoading) return null; return (