added wallets page

This commit is contained in:
PhilReact 2024-11-19 08:25:25 +02:00
parent e8b2196b01
commit 144f3e26c5
4 changed files with 404 additions and 16 deletions

View File

@ -122,6 +122,7 @@ import {
import { fileToBase64 } from "./utils/fileReading";
import { handleGetFileFromIndexedDB } from "./utils/indexedDB";
import { CoreSyncStatus } from "./components/CoreSyncStatus";
import { Wallets } from "./Wallets";
type extStates =
| "not-authenticated"
@ -137,6 +138,7 @@ type extStates =
| "wallet-dropped"
| "web-app-request-buy-order"
| "buy-order-submitted"
| "wallets"
| "group";
interface MyContextInterface {
@ -238,6 +240,8 @@ export const resumeAllQueues = () => {
});
};
export const MyContext = createContext<MyContextInterface>(defaultValues);
export let globalApiKey: string | null = null;
@ -2184,9 +2188,9 @@ function App() {
</CustomButton>
</>
)}
{rawWallet && extState === "wallet-dropped" && (
{extState === "wallets" && (
<>
<Spacer height="22px" />
<Spacer height="22px" />
<Box
sx={{
display: "flex",
@ -2208,6 +2212,34 @@ function App() {
src={Return}
/>
</Box>
<Wallets setRawWallet={setRawWallet} setExtState={setExtstate} rawWallet={rawWallet} />
</>
)}
{rawWallet && extState === "wallet-dropped" && (
<>
<Spacer height="22px" />
<Box
sx={{
display: "flex",
width: "100%",
justifyContent: "flex-start",
paddingLeft: "22px",
boxSizing: "border-box",
}}
>
<img
style={{
cursor: "pointer",
}}
onClick={() => {
setRawWallet(null);
setExtstate("wallets");
logoutFunc();
}}
src={Return}
/>
</Box>
<Spacer height="10px" />
<div
className="image-container"
@ -2224,9 +2256,11 @@ function App() {
sx={{
display: "flex",
flexDirection: "column",
alignItems: "flex-start",
alignItems: "center",
}}
>
<Typography>{rawWallet?.name ? rawWallet?.name : rawWallet?.address0}</Typography>
<Spacer height="10px" />
<TextP
sx={{
textAlign: "start",

View File

@ -270,16 +270,15 @@ export const NotAuthenticated = ({
display: "flex",
gap: "10px",
alignItems: "center",
marginLeft: "28px",
}}
>
<CustomButton {...getRootProps()}>
<input {...getInputProps()} />
Authenticate
<CustomButton onClick={()=> setExtstate('wallets')}>
{/* <input {...getInputProps()} /> */}
Wallets
</CustomButton>
<Tooltip title="Authenticate by importing your Qortal JSON file" arrow>
{/* <Tooltip title="Authenticate by importing your Qortal JSON file" arrow>
<img src={Info} />
</Tooltip>
</Tooltip> */}
</Box>
<Spacer height="6px" />
@ -288,7 +287,6 @@ export const NotAuthenticated = ({
display: "flex",
gap: "10px",
alignItems: "center",
marginLeft: "28px",
}}
>
<CustomButton
@ -299,12 +297,7 @@ export const NotAuthenticated = ({
Create account
</CustomButton>
<img
src={Info}
style={{
visibility: "hidden",
}}
/>
</Box>
<Spacer height="15px" />

344
src/Wallets.tsx Normal file
View File

@ -0,0 +1,344 @@
import React, { useEffect, useRef, 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, IconButton, Input } from "@mui/material";
import { CustomButton } from "./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 } from "./background";
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(false);
const hasFetchedWalletsRef = useRef(false)
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);
}
}
let error: any = null;
let 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) {
console.log("entered");
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 selectedWalletFunc = (wallet) => {
setRawWallet(wallet);
setExtState("wallet-dropped");
};
useEffect(()=> {
setIsLoading(true)
getWallets().then((res)=> {
hasFetchedWalletsRef.current = true
if(res && Array.isArray(res)){
setWallets(res)
}
setIsLoading(false)
}).catch((error)=> {
console.error(error)
setIsLoading(false)
})
}, [])
useEffect(()=> {
if(hasFetchedWalletsRef.current && wallets && Array.isArray(wallets)){
storeWallets(wallets)
}
}, [wallets])
if(isLoading) return null
return (
<div>
{(wallets?.length === 0 ||
!wallets) ? (
<>
<Typography>No wallets saved</Typography>
<Spacer height="75px" />
</>
): (
<>
<Typography>Your saved wallets</Typography>
<Spacer height="30px" />
</>
)}
{rawWallet && (
<Box>
<Typography>Selected Wallet:</Typography>
{rawWallet?.name && <Typography>{rawWallet.name}</Typography>}
{rawWallet?.address0 && (
<Typography>{rawWallet?.address0}</Typography>
)}
</Box>
)}
{wallets?.length > 0 && (
<List
sx={{
width: "100%",
maxWidth: "500px",
bgcolor: "background.paper",
maxHeight: "60vh",
overflow: "auto",
}}
>
{wallets?.map((wallet, idx) => {
return (
<>
<WalletItem
setSelectedWallet={selectedWalletFunc}
key={wallet?.address0}
wallet={wallet}
idx={idx}
updateWalletItem={updateWalletItem}
/>
<Divider variant="inset" component="li" />
</>
);
})}
</List>
)}
<Box
sx={{
display: "flex",
gap: "10px",
alignItems: "center",
position: wallets?.length === 0 ? 'relative' : 'fixed',
bottom: '20px',
right: '20px'
}}
>
<CustomButton {...getRootProps()}>
<input {...getInputProps()} />
Add wallets
</CustomButton>
</Box>
</div>
);
};
const WalletItem = ({ wallet, updateWalletItem, idx, setSelectedWallet }) => {
const [name, setName] = useState("");
const [note, setNote] = useState("");
const [isEdit, setIsEdit] = useState(false);
useEffect(() => {
if (wallet?.name) {
setName(wallet.name);
}
if (wallet?.note) {
setNote(wallet.note);
}
}, [wallet]);
return (
<>
<ButtonBase
onClick={() => {
setSelectedWallet(wallet);
}}
sx={{
width: '100%'
}}
>
<ListItem
secondaryAction={
<IconButton
onClick={(e) => {
e.stopPropagation();
setIsEdit(true);
}}
edge="end"
aria-label="edit"
>
<EditIcon
sx={{
color: "white",
}}
/>
</IconButton>
}
alignItems="flex-start"
>
<ListItemAvatar>
<Avatar alt="" src="/static/images/avatar/1.jpg" />
</ListItemAvatar>
<ListItemText
primary={wallet?.name ? wallet.name : wallet?.filename ? parsefilenameQortal(wallet?.filename) : "No name"}
secondary={
<Box
sx={{
display: "flex",
flexDirection: "column",
}}
>
<Typography
component="span"
variant="body2"
sx={{ color: "text.primary", display: "inline" }}
>
{wallet?.address0}
</Typography>
{wallet?.note}
</Box>
}
/>
</ListItem>
</ButtonBase>
{isEdit && (
<Box
sx={{
padding: "8px",
}}
>
<Label>Name</Label>
<Input
placeholder="Name"
value={name}
onChange={(e) => setName(e.target.value)}
sx={{
width: "100%",
}}
/>
<Spacer height="10px" />
<Label>Note</Label>
<Input
placeholder="Note"
value={note}
onChange={(e) => setNote(e.target.value)}
inputProps={{
maxLength: 100,
}}
sx={{
width: "100%",
}}
/>
<Spacer height="10px" />
<Box
sx={{
display: "flex",
gap: "20px",
justifyContent: "flex-end",
width: "100%",
}}
>
<Button size="small" variant="contained" onClick={() => setIsEdit(false)}>
Close
</Button>
<Button
sx={{
backgroundColor: 'var(--unread)',
"&:hover": {
backgroundColor: "var(--unread)",
},
"&:focus": {
backgroundColor: "var(--unread)",
},
}}
size="small"
variant="contained"
onClick={() => updateWalletItem(idx, null)}
>
Remove
</Button>
<Button
sx={{
backgroundColor: "#5EB049",
"&:hover": {
backgroundColor: "#5EB049",
},
"&:focus": {
backgroundColor: "#5EB049",
},
}}
size="small"
variant="contained"
onClick={() => {
updateWalletItem(idx, {
...wallet,
name,
note,
});
setIsEdit(false);
}}
>
Save
</Button>
</Box>
</Box>
)}
</>
);
};

View File

@ -851,6 +851,23 @@ export async function getSaveWallet() {
}
}
export async function getWallets() {
const res = await getData<any>("wallets").catch(() => null);
if (res) {
return res;
} else {
throw new Error("No wallet saved");
}
}
export async function storeWallets(wallets) {
storeData("wallets", wallets)
.catch((error) => {
reject(new Error(error.message || "Error saving data"));
});
}
export async function clearAllNotifications() {
// const notifications = await chrome.notifications.getAll();
// for (const notificationId of Object.keys(notifications)) {