add address book

This commit is contained in:
apoorvlathey
2023-06-15 03:38:10 +05:30
parent 43c1523772
commit c33693b4e6
6 changed files with 278 additions and 89 deletions

View File

@@ -58,5 +58,11 @@
">0.2%",
"not dead",
"not op_mini all"
]
],
"resolutions": {
"react-error-overlay": "6.0.9"
},
"devDependencies": {
"react-error-overlay": "6.0.9"
}
}

View File

@@ -1,83 +0,0 @@
import {
FormControl,
FormLabel,
InputGroup,
Input,
InputRightElement,
Button,
} from "@chakra-ui/react";
import { DeleteIcon } from "@chakra-ui/icons";
interface AddressInputParams {
showAddress: string;
setShowAddress: (value: string) => void;
setAddress: (value: string) => void;
setIsAddressValid: (value: boolean) => void;
bg: string;
isAddressValid: boolean;
selectedTabIndex: number;
isConnected: boolean;
appUrl: string | undefined;
isIFrameLoading: boolean;
updateAddress: () => void;
}
function AddressInput({
showAddress,
setShowAddress,
setAddress,
setIsAddressValid,
bg,
isAddressValid,
selectedTabIndex,
isConnected,
appUrl,
isIFrameLoading,
updateAddress,
}: AddressInputParams) {
return (
<FormControl>
<FormLabel>Enter Address or ENS to Impersonate</FormLabel>
<InputGroup>
<Input
placeholder="vitalik.eth"
autoComplete="off"
value={showAddress}
onChange={(e) => {
const _showAddress = e.target.value;
setShowAddress(_showAddress);
setAddress(_showAddress);
setIsAddressValid(true); // remove inValid warning when user types again
}}
bg={bg}
isInvalid={!isAddressValid}
/>
{(selectedTabIndex === 0 && isConnected) ||
(selectedTabIndex === 1 && appUrl && !isIFrameLoading) ? (
<InputRightElement width="4.5rem" mr="1rem">
<Button h="1.75rem" size="sm" onClick={updateAddress}>
Update
</Button>
</InputRightElement>
) : (
showAddress && (
<InputRightElement px="1rem" mr="0.5rem">
<Button
h="1.75rem"
size="sm"
onClick={() => {
setShowAddress("");
setAddress("");
}}
>
<DeleteIcon />
</Button>
</InputRightElement>
)
)}
</InputGroup>
</FormControl>
);
}
export default AddressInput;

View File

@@ -0,0 +1,160 @@
import { useState, useEffect } from "react";
import {
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
HStack,
ModalCloseButton,
ModalBody,
Text,
Input,
Center,
Button,
Box,
} from "@chakra-ui/react";
import { DeleteIcon } from "@chakra-ui/icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faSave } from "@fortawesome/free-solid-svg-icons";
import { slicedText } from "../../TransactionRequests";
const STORAGE_KEY = "address-book";
interface SavedAddressInfo {
address: string;
label: string;
}
interface AddressBookParams {
isAddressBookOpen: boolean;
closeAddressBook: () => void;
showAddress: string;
setShowAddress: (value: string) => void;
setAddress: (value: string) => void;
}
function AddressBook({
isAddressBookOpen,
closeAddressBook,
showAddress,
setShowAddress,
setAddress,
}: AddressBookParams) {
const [newAddressInput, setNewAddressInput] = useState<string>("");
const [newLableInput, setNewLabelInput] = useState<string>("");
const [savedAddresses, setSavedAddresses] = useState<SavedAddressInfo[]>([]);
useEffect(() => {
setSavedAddresses(JSON.parse(localStorage.getItem(STORAGE_KEY) ?? "[]"));
}, []);
useEffect(() => {
setNewAddressInput(showAddress);
}, [showAddress]);
useEffect(() => {
localStorage.setItem(STORAGE_KEY, JSON.stringify(savedAddresses));
}, [savedAddresses]);
// reset label when modal is reopened
useEffect(() => {
setNewLabelInput("");
}, [isAddressBookOpen]);
return (
<Modal isOpen={isAddressBookOpen} onClose={closeAddressBook} isCentered>
<ModalOverlay bg="none" backdropFilter="auto" backdropBlur="5px" />
<ModalContent
minW={{
base: 0,
sm: "30rem",
md: "40rem",
lg: "60rem",
}}
pb="6"
>
<ModalHeader>Address Book</ModalHeader>
<ModalCloseButton />
<ModalBody>
<HStack>
<Input
placeholder="address / ens"
value={newAddressInput}
onChange={(e) => setNewAddressInput(e.target.value)}
/>
<Input
placeholder="label"
value={newLableInput}
onChange={(e) => setNewLabelInput(e.target.value)}
/>
</HStack>
<Center mt="3">
<Button
colorScheme={"blue"}
isDisabled={
newAddressInput.length === 0 || newLableInput.length === 0
}
onClick={() =>
setSavedAddresses([
...savedAddresses,
{
address: newAddressInput,
label: newLableInput,
},
])
}
>
<HStack>
<FontAwesomeIcon icon={faSave} />
<Text>Save</Text>
</HStack>
</Button>
</Center>
{savedAddresses.length > 0 && (
<Box mt="6" px="20">
<Text fontWeight={"bold"}>Select from saved addresses:</Text>
<Box mt="3" px="10">
{savedAddresses.map(({ address, label }, i) => (
<HStack key={i} mt="2">
<Button
key={i}
w="100%"
onClick={() => {
setShowAddress(address);
setAddress(address);
closeAddressBook();
}}
>
{label} (
{address.indexOf(".eth") >= 0
? address
: slicedText(address)}
)
</Button>
<Button
ml="2"
_hover={{
bg: "red.500",
}}
onClick={() => {
const _savedAddresses = savedAddresses;
_savedAddresses.splice(i, 1);
// using spread operator, else useEffect doesn't detect state change
setSavedAddresses([..._savedAddresses]);
}}
>
<DeleteIcon />
</Button>
</HStack>
))}
</Box>
</Box>
)}
</ModalBody>
</ModalContent>
</Modal>
);
}
export default AddressBook;

View File

@@ -0,0 +1,106 @@
import {
FormControl,
FormLabel,
InputGroup,
Input,
InputRightElement,
Button,
HStack,
useDisclosure,
} from "@chakra-ui/react";
import { DeleteIcon } from "@chakra-ui/icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faBook } from "@fortawesome/free-solid-svg-icons";
import AddressBook from "./AddressBook";
interface AddressInputParams {
showAddress: string;
setShowAddress: (value: string) => void;
setAddress: (value: string) => void;
setIsAddressValid: (value: boolean) => void;
bg: string;
isAddressValid: boolean;
selectedTabIndex: number;
isConnected: boolean;
appUrl: string | undefined;
isIFrameLoading: boolean;
updateAddress: () => void;
}
function AddressInput({
showAddress,
setShowAddress,
setAddress,
setIsAddressValid,
bg,
isAddressValid,
selectedTabIndex,
isConnected,
appUrl,
isIFrameLoading,
updateAddress,
}: AddressInputParams) {
const {
isOpen: isAddressBookOpen,
onOpen: openAddressBook,
onClose: closeAddressBook,
} = useDisclosure();
return (
<FormControl>
<FormLabel>Enter Address or ENS to Impersonate</FormLabel>
<HStack>
<InputGroup>
<Input
placeholder="vitalik.eth"
autoComplete="off"
value={showAddress}
onChange={(e) => {
const _showAddress = e.target.value;
setShowAddress(_showAddress);
setAddress(_showAddress);
setIsAddressValid(true); // remove inValid warning when user types again
}}
bg={bg}
isInvalid={!isAddressValid}
/>
{(selectedTabIndex === 0 && isConnected) ||
(selectedTabIndex === 1 && appUrl && !isIFrameLoading) ? (
<InputRightElement width="4.5rem" mr="1rem">
<Button h="1.75rem" size="sm" onClick={updateAddress}>
Update
</Button>
</InputRightElement>
) : (
showAddress && (
<InputRightElement px="1rem" mr="0.5rem">
<Button
h="1.75rem"
size="sm"
onClick={() => {
setShowAddress("");
setAddress("");
}}
>
<DeleteIcon />
</Button>
</InputRightElement>
)
)}
</InputGroup>
<Button onClick={openAddressBook}>
<FontAwesomeIcon icon={faBook} />
</Button>
<AddressBook
isAddressBookOpen={isAddressBookOpen}
closeAddressBook={closeAddressBook}
showAddress={showAddress}
setShowAddress={setShowAddress}
setAddress={setAddress}
/>
</HStack>
</FormControl>
);
}
export default AddressInput;

View File

@@ -26,7 +26,7 @@ import {
import CopyToClipboard from "./CopyToClipboard";
import { TxnDataType } from "../../types";
const slicedText = (txt: string) => {
export const slicedText = (txt: string) => {
return txt.length > 6
? `${txt.slice(0, 4)}...${txt.slice(txt.length - 2, txt.length)}`
: txt;

View File

@@ -11492,10 +11492,10 @@ react-dom@^17.0.2:
object-assign "^4.1.1"
scheduler "^0.20.2"
react-error-overlay@^6.0.9:
version "6.0.11"
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.11.tgz#92835de5841c5cf08ba00ddd2d677b6d17ff9adb"
integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==
react-error-overlay@6.0.9, react-error-overlay@^6.0.9:
version "6.0.9"
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a"
integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==
react-fast-compare@3.2.0:
version "3.2.0"