diff --git a/src/App.tsx b/src/App.tsx index 5b8d70c..d08f201 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -28,6 +28,7 @@ import { EIP155_SIGNING_METHODS } from './utils/wallet-connect/EIP155Data'; import { getSignParamsMessage } from './utils/wallet-connect/helpers'; import ApproveTransaction from './screens/ApproveTransaction'; import AddNetwork from './screens/AddNetwork'; +import EditNetwork from './screens/EditNetwork'; import { COSMOS, EIP155 } from './utils/constants'; import { useNetworks } from './context/NetworksContext'; import { NETWORK_METHODS } from './utils/wallet-connect/common-data'; @@ -281,6 +282,13 @@ const App = (): React.JSX.Element => { title: 'Add Network', }} /> + { + + { + navigation.navigate('EditNetwork', { + selectedNetwork: selectedNetwork!, + }); + }}> + + Edit Network + + + + {!selectedNetwork!.isDefault && ( void; networksData: NetworksDataState[]; setNetworksData: React.Dispatch>; networkType: string; @@ -16,8 +14,6 @@ const NetworksContext = createContext<{ React.SetStateAction >; }>({ - currentIndex: 0, - setCurrentIndex: () => {}, networksData: [], setNetworksData: () => {}, networkType: '', @@ -33,7 +29,6 @@ const useNetworks = () => { const NetworksProvider = ({ children }: { children: any }) => { const [networksData, setNetworksData] = useState([]); - const [currentIndex, setCurrentIndex] = useState(0); const [networkType, setNetworkType] = useState(EIP155); const [selectedNetwork, setSelectedNetwork] = useState(); @@ -50,14 +45,22 @@ const NetworksProvider = ({ children }: { children: any }) => { setSelectedNetwork(retrievedNewNetworks[0]); }; - fetchData(); - }, []); + if (networksData.length === 0) { + fetchData(); + } + }, [networksData]); + + useEffect(() => { + setSelectedNetwork(prevSelectedNetwork => { + return networksData.find( + networkData => networkData.networkId === prevSelectedNetwork?.networkId, + ); + }); + }, [networksData]); return ( { const { setNetworksData } = useNetworks(); const [namespace, setNamespace] = useState(EIP155); + const [isLoading, setIsLoading] = useState(false); const networksFormDataSchema = namespace === EIP155 ? ethNetworkDataSchema : cosmosNetworkDataSchema; @@ -114,6 +118,7 @@ const AddNetwork = () => { const submit = useCallback( async (data: z.infer) => { + setIsLoading(true); const newNetworkData = { ...data, namespace, @@ -176,6 +181,7 @@ const AddNetwork = () => { ), ]); + setIsLoading(false); navigation.navigate('Laconic'); }, [navigation, namespace, setNetworksData], @@ -358,8 +364,12 @@ const AddNetwork = () => { /> )} - ); diff --git a/src/screens/EditNetwork.tsx b/src/screens/EditNetwork.tsx new file mode 100644 index 0000000..ef787c8 --- /dev/null +++ b/src/screens/EditNetwork.tsx @@ -0,0 +1,148 @@ +import React, { useCallback, useState } from 'react'; +import { ScrollView, View } from 'react-native'; +import { useForm, Controller } from 'react-hook-form'; +import { TextInput, Button, HelperText, Text } from 'react-native-paper'; +import { setInternetCredentials } from 'react-native-keychain'; +import { z } from 'zod'; + +import { zodResolver } from '@hookform/resolvers/zod'; +import { + NativeStackNavigationProp, + NativeStackScreenProps, +} from '@react-navigation/native-stack'; +import { useNavigation } from '@react-navigation/native'; + +import { StackParamsList } from '../types'; +import styles from '../styles/stylesheet'; +import { retrieveNetworksData } from '../utils/accounts'; +import { useNetworks } from '../context/NetworksContext'; +import { EMPTY_FIELD_ERROR, INVALID_URL_ERROR } from '../utils/constants'; + +const networksFormDataSchema = z.object({ + networkName: z.string().nonempty({ message: EMPTY_FIELD_ERROR }), + rpcUrl: z.string().url({ message: INVALID_URL_ERROR }), + blockExplorerUrl: z + .string() + .url({ message: INVALID_URL_ERROR }) + .or(z.literal('')), +}); + +type EditNetworkProps = NativeStackScreenProps; + +const EditNetwork = ({ route }: EditNetworkProps) => { + const [isLoading, setIsLoading] = useState(false); + + const { setNetworksData } = useNetworks(); + const navigation = + useNavigation>(); + + const { + control, + formState: { errors }, + handleSubmit, + } = useForm>({ + mode: 'onChange', + resolver: zodResolver(networksFormDataSchema), + }); + const networkData = route.params.selectedNetwork; + + const submit = useCallback( + async (data: z.infer) => { + setIsLoading(true); + + const retrievedNetworksData = await retrieveNetworksData(); + + const newNetworkData = { ...networkData, ...data }; + const index = retrievedNetworksData.findIndex( + network => network.networkId === networkData.networkId, + ); + + retrievedNetworksData.splice(index, 1, newNetworkData); + + await setInternetCredentials( + 'networks', + '_', + JSON.stringify(retrievedNetworksData), + ); + + setNetworksData(retrievedNetworksData); + + setIsLoading(false); + navigation.navigate('Laconic'); + }, + [networkData, navigation, setNetworksData], + ); + + return ( + + + + Edit {networkData?.networkName} details + + + ( + <> + onChange(textValue)} + /> + {errors.networkName?.message} + + )} + /> + ( + <> + onChange(textValue)} + /> + {errors.rpcUrl?.message} + + )} + /> + + ( + <> + onChange(textValue)} + /> + + {errors.blockExplorerUrl?.message} + + + )} + /> + + + ); +}; + +export default EditNetwork; diff --git a/src/screens/HomeScreen.tsx b/src/screens/HomeScreen.tsx index 91df6bc..1e09b37 100644 --- a/src/screens/HomeScreen.tsx +++ b/src/screens/HomeScreen.tsx @@ -92,16 +92,13 @@ const HomeScreen = () => { }; const confirmResetWallet = useCallback(async () => { - const updatedNetworks = networksData.filter( - networkData => networkData.isDefault, - ); - setNetworksData(updatedNetworks); - setSelectedNetwork(undefined); setIsWalletCreated(false); setIsWalletCreating(false); setAccounts([]); setCurrentIndex(0); - await resetWallet(updatedNetworks); + setNetworksData([]); + setSelectedNetwork(undefined); + await resetWallet(); const sessions = web3wallet!.getActiveSessions(); Object.keys(sessions).forEach(async sessionId => { @@ -114,7 +111,6 @@ const HomeScreen = () => { hideResetDialog(); }, [ - networksData, setAccounts, setActiveSessions, setCurrentIndex, diff --git a/src/styles/stylesheet.js b/src/styles/stylesheet.js index e925b5d..e5a579e 100644 --- a/src/styles/stylesheet.js +++ b/src/styles/stylesheet.js @@ -204,7 +204,9 @@ const styles = StyleSheet.create({ }, subHeading: { textAlign: 'center', - fontWeight: '600', + fontWeight: 'bold', + marginBottom: 10, + marginTop: 10, }, centerText: { textAlign: 'center', diff --git a/src/types.ts b/src/types.ts index f2f4975..5aafdb3 100644 --- a/src/types.ts +++ b/src/types.ts @@ -26,6 +26,9 @@ export type StackParamsList = { WalletConnect: undefined; AddSession: undefined; AddNetwork: undefined; + EditNetwork: { + selectedNetwork: NetworksDataState; + }; }; export type Account = { diff --git a/src/utils/accounts.ts b/src/utils/accounts.ts index e46cca0..cfa0d52 100644 --- a/src/utils/accounts.ts +++ b/src/utils/accounts.ts @@ -225,13 +225,13 @@ const retrieveSingleAccount = async ( return loadedAccounts.find(account => account.address === address); }; -const resetWallet = async (networks: NetworksDataState[]) => { +const resetWallet = async () => { try { await Promise.all([ resetInternetCredentials('mnemonicServer'), resetKeyServers(EIP155), resetKeyServers(COSMOS), - setInternetCredentials('networks', '_', JSON.stringify(networks)), + setInternetCredentials('networks', '_', JSON.stringify([])), ]); } catch (error) { console.error('Error resetting wallet:', error); diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 87c304b..aea8e6a 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -26,3 +26,6 @@ export const DEFAULT_NETWORKS = [ ]; export const CHAINID_DEBOUNCE_DELAY = 250; + +export const EMPTY_FIELD_ERROR = 'Field cannot be empty'; +export const INVALID_URL_ERROR = 'Invalid URL';