From a8d642449ab1b24c2bfe8ab517dd9624e5b4d9d8 Mon Sep 17 00:00:00 2001 From: Inokentii Mazhara Date: Mon, 4 Mar 2024 17:08:35 +0200 Subject: [PATCH 1/4] TW-1362 Implement moving users from Talent Mainnet to Tezos Mainnet --- .../icon-title-no-bg/icon-title-no-bg.tsx | 7 +++--- src/components/styled-radio-group/index.tsx | 12 +++++++++- .../radio-group/radio-group.tsx | 16 ++++++++++--- .../styled-radio-group/radio-group/types.ts | 4 ++++ src/components/styled-radio-group/styles.ts | 5 ++++ .../custom-rpc-modals/add-modal/add-modal.tsx | 24 +++++++++++++++---- .../edit-modal/edit-modal.tsx | 3 +++ .../custom-rpc-modals/edit-modal/styles.ts | 7 ++++++ src/screens/node-settings/node-settings.tsx | 6 +++-- src/store/migrations.ts | 18 ++++++++++++++ src/store/root-state.reducers.ts | 2 +- src/utils/network.utils.ts | 2 ++ 12 files changed, 92 insertions(+), 14 deletions(-) create mode 100644 src/modals/custom-rpc-modals/edit-modal/styles.ts diff --git a/src/components/icon-title-no-bg/icon-title-no-bg.tsx b/src/components/icon-title-no-bg/icon-title-no-bg.tsx index 81d9c0f42..1a35c95ed 100644 --- a/src/components/icon-title-no-bg/icon-title-no-bg.tsx +++ b/src/components/icon-title-no-bg/icon-title-no-bg.tsx @@ -1,5 +1,5 @@ import React, { FC } from 'react'; -import { Text } from 'react-native'; +import { StyleProp, Text, TextStyle } from 'react-native'; import { TouchableOpacity } from 'react-native-gesture-handler'; import { TestIdProps } from 'src/interfaces/test-id.props'; @@ -12,16 +12,17 @@ import { useIconTitleNoBgStyles } from './icon-title-no-bg.styles'; interface Props extends TestIdProps { text: string; icon: IconNameEnum; + textStyle?: StyleProp; onPress: EmptyFn; } -export const IconTitleNoBg: FC = ({ text, icon, onPress, testID }) => { +export const IconTitleNoBg: FC = ({ text, icon, textStyle, onPress, testID }) => { const styles = useIconTitleNoBgStyles(); return ( - {text} + {text} ); }; diff --git a/src/components/styled-radio-group/index.tsx b/src/components/styled-radio-group/index.tsx index e13cdfdd7..3371d63c3 100644 --- a/src/components/styled-radio-group/index.tsx +++ b/src/components/styled-radio-group/index.tsx @@ -16,9 +16,17 @@ interface Props extends StyledRadioGroupProps, TestIdProps value: T; onChange: (value: T) => void; labelStyle?: ViewStyle; + disabledLabelStyle?: ViewStyle; } -export const StyledRadioGroup = ({ value, items, onChange, labelStyle, testID }: Props) => { +export const StyledRadioGroup = ({ + value, + items, + onChange, + disabledLabelStyle, + labelStyle, + testID +}: Props) => { const colors = useColors(); const styles = useStyledRadioButtonsGroupStyles(); @@ -29,8 +37,10 @@ export const StyledRadioGroup = ({ value, items, onChange, lab value={value} onPress={onChange} color={colors.orange} + disabledColor={colors.disabled} itemContainerStyle={styles.itemContainer} itemLabelStyle={[styles.label, labelStyle]} + disabledItemLabelStyle={[styles.label, disabledLabelStyle ?? styles.disabledLabel]} testID={testID} /> diff --git a/src/components/styled-radio-group/radio-group/radio-group.tsx b/src/components/styled-radio-group/radio-group/radio-group.tsx index f1aeeb2fc..648f0cbc1 100644 --- a/src/components/styled-radio-group/radio-group/radio-group.tsx +++ b/src/components/styled-radio-group/radio-group/radio-group.tsx @@ -1,8 +1,10 @@ import React, { useMemo } from 'react'; import { View } from 'react-native'; +import { showWarningToast } from 'src/toast/toast.utils'; import { AnalyticsEventCategory } from 'src/utils/analytics/analytics-event.enum'; import { useAnalytics } from 'src/utils/analytics/use-analytics.hook'; +import { isDefined } from 'src/utils/is-defined'; import { RadioItem } from './radio-item'; import { groupStyles } from './styles'; @@ -12,7 +14,9 @@ export const RadioGroup = ({ items, value: currentValue, color = '#444', + disabledColor = '#ccc', itemContainerStyle, + disabledItemLabelStyle: disabledLabelStyle, itemLabelStyle, onPress, testID @@ -31,18 +35,24 @@ export const RadioGroup = ({ key: item.value, ...item, selected: item.value === currentValue, - onPress: handlePress + onPress: (value: string) => + isDefined(item.disabledMessage) ? showWarningToast({ description: item.disabledMessage }) : handlePress(value) })); }, [items, currentValue, trackEvent, testID]); + const totalDisabledLabelStyle = useMemo( + () => [itemLabelStyle, disabledLabelStyle].flat(), + [itemLabelStyle, disabledLabelStyle] + ); + return ( {itemsLocal.map(item => ( ))} diff --git a/src/components/styled-radio-group/radio-group/types.ts b/src/components/styled-radio-group/radio-group/types.ts index 8a1712b17..10a34026c 100644 --- a/src/components/styled-radio-group/radio-group/types.ts +++ b/src/components/styled-radio-group/radio-group/types.ts @@ -10,6 +10,8 @@ export interface RadioItemInterface { value: T; label?: string; buttons?: ItemButtonInterface[]; + /** If specified, the item cannot be selected but this message is displayed on an attempt to select the item */ + disabledMessage?: string; } export interface RadioItemProps extends RadioItemInterface, TestIdProps { @@ -24,7 +26,9 @@ export interface RadioGroupProps extends TestIdProps { items: RadioItemInterface[]; value?: T; color?: string; + disabledColor?: string; itemContainerStyle?: StyleType; + disabledItemLabelStyle?: StyleType; itemLabelStyle?: StyleType; onPress: (value: T) => void; } diff --git a/src/components/styled-radio-group/styles.ts b/src/components/styled-radio-group/styles.ts index 8b43fe090..6c9eef369 100644 --- a/src/components/styled-radio-group/styles.ts +++ b/src/components/styled-radio-group/styles.ts @@ -16,5 +16,10 @@ export const useStyledRadioButtonsGroupStyles = createUseStyles(({ colors, typog ...typography.body15Semibold, color: colors.black, flex: 1 + }, + disabledLabel: { + ...typography.body15Semibold, + color: colors.disabled, + flex: 1 } })); diff --git a/src/modals/custom-rpc-modals/add-modal/add-modal.tsx b/src/modals/custom-rpc-modals/add-modal/add-modal.tsx index 76b96b328..1a39916e3 100644 --- a/src/modals/custom-rpc-modals/add-modal/add-modal.tsx +++ b/src/modals/custom-rpc-modals/add-modal/add-modal.tsx @@ -1,3 +1,4 @@ +import { TezosToolkit } from '@taquito/taquito'; import { Formik } from 'formik'; import React, { FC } from 'react'; import { View } from 'react-native'; @@ -18,7 +19,9 @@ import { useNavigation } from 'src/navigator/hooks/use-navigation.hook'; import { addCustomRpc, setSelectedRpcUrl } from 'src/store/settings/settings-actions'; import { useRpcListSelector } from 'src/store/settings/settings-selectors'; import { formatSize } from 'src/styles/format-size'; +import { showWarningToast } from 'src/toast/toast.utils'; import { usePageAnalytic } from 'src/utils/analytics/use-analytics.hook'; +import { TALENT_MAINNET_CHAIN_ID } from 'src/utils/network.utils'; import { formInitialValues, formValidationSchema, confirmUniqueRPC } from '../form.utils'; @@ -29,14 +32,27 @@ export const AddCustomRpcModal: FC = () => { const { goBack } = useNavigation(); const rpcList = useRpcListSelector(); - const handleSubmit = (newRpc: RpcInterface) => { + const handleSubmit = async (newRpc: RpcInterface) => { if (confirmUniqueRPC(rpcList, newRpc) === false) { return; } - dispatch(addCustomRpc(newRpc)); - dispatch(setSelectedRpcUrl(newRpc.url)); - goBack(); + let isTalentNet = false; + try { + const tezos = new TezosToolkit(newRpc.url); + const chainId = await tezos.rpc.getChainId(); + isTalentNet = chainId === TALENT_MAINNET_CHAIN_ID; + } catch (e) { + console.error(e); + } + + if (isTalentNet) { + showWarningToast({ description: 'The T4L3NT Mainnet RPC is temporarily unavailable.' }); + } else { + dispatch(addCustomRpc(newRpc)); + dispatch(setSelectedRpcUrl(newRpc.url)); + goBack(); + } }; usePageAnalytic(ModalsEnum.AddCustomRpc); diff --git a/src/modals/custom-rpc-modals/edit-modal/edit-modal.tsx b/src/modals/custom-rpc-modals/edit-modal/edit-modal.tsx index 10abd0177..f3b6bd513 100644 --- a/src/modals/custom-rpc-modals/edit-modal/edit-modal.tsx +++ b/src/modals/custom-rpc-modals/edit-modal/edit-modal.tsx @@ -28,6 +28,7 @@ import { useAnalytics, usePageAnalytic } from 'src/utils/analytics/use-analytics import { formInitialValues, formValidationSchema, confirmUniqueRPC } from '../form.utils'; import { EditModalSelectors } from './edit-modal.selectors'; +import { useEditModalStyles } from './styles'; export const EditCustomRpcModal: FC = () => { const { url } = useRoute>().params; @@ -36,6 +37,7 @@ export const EditCustomRpcModal: FC = () => { const { goBack } = useNavigation(); const { trackEvent } = useAnalytics(); const rpcList = useRpcListSelector(); + const styles = useEditModalStyles(); const initialValues = useMemo(() => { const rpc = rpcList.find(rpc => rpc.url === url); @@ -105,6 +107,7 @@ export const EditCustomRpcModal: FC = () => { diff --git a/src/modals/custom-rpc-modals/edit-modal/styles.ts b/src/modals/custom-rpc-modals/edit-modal/styles.ts new file mode 100644 index 000000000..d8eebdeaa --- /dev/null +++ b/src/modals/custom-rpc-modals/edit-modal/styles.ts @@ -0,0 +1,7 @@ +import { createUseStylesMemoized } from 'src/styles/create-use-styles'; + +export const useEditModalStyles = createUseStylesMemoized(({ colors }) => ({ + destructive: { + color: colors.destructive + } +})); diff --git a/src/screens/node-settings/node-settings.tsx b/src/screens/node-settings/node-settings.tsx index e0b593b84..07e3e3ead 100644 --- a/src/screens/node-settings/node-settings.tsx +++ b/src/screens/node-settings/node-settings.tsx @@ -14,6 +14,7 @@ import { useNavigation } from 'src/navigator/hooks/use-navigation.hook'; import { setSelectedRpcUrl } from 'src/store/settings/settings-actions'; import { useRpcListSelector, useSelectedRpcUrlSelector } from 'src/store/settings/settings-selectors'; import { usePageAnalytic } from 'src/utils/analytics/use-analytics.hook'; +import { isDcpNode } from 'src/utils/network.utils'; import { TEMPLE_RPC } from 'src/utils/rpc/rpc-list'; import { NodeSettingsSelectors } from './node-settings.selectors'; @@ -34,10 +35,11 @@ export const NodeSettings = () => { { key: 'edit', iconName: IconNameEnum.Edit, - disabled: rpc.url === TEMPLE_RPC.url ? true : undefined, + disabled: rpc.url === TEMPLE_RPC.url || isDcpNode(rpc.url) ? true : undefined, onPress: () => void navigate(ModalsEnum.EditCustomRpc, { url: rpc.url }) } - ] + ], + disabledMessage: isDcpNode(rpc.url) ? 'The T4L3NT Mainnet RPC is temporarily unavailable.' : undefined })), [rpcList] ); diff --git a/src/store/migrations.ts b/src/store/migrations.ts index 5b28f1e41..64aa41b8a 100644 --- a/src/store/migrations.ts +++ b/src/store/migrations.ts @@ -7,6 +7,7 @@ import { KNOWN_TOKENS_SLUGS } from 'src/token/data/token-slugs'; import { OVERRIDEN_MAINNET_TOKENS_METADATA, PREDEFINED_DCP_TOKENS_METADATA } from 'src/token/data/tokens-metadata'; import { getTokenSlug } from 'src/token/utils/token.utils'; import { isDefined } from 'src/utils/is-defined'; +import { isDcpNode } from 'src/utils/network.utils'; import { DCP_RPC, MARIGOLD_RPC, OLD_TEMPLE_RPC_URLS, TEMPLE_RPC } from 'src/utils/rpc/rpc-list'; import type { RootState } from './types'; @@ -153,5 +154,22 @@ export const MIGRATIONS: MigrationManifest = { accountsStateRecord } }; + }, + '6': (untypedState: PersistedState): undefined | TypedPersistedRootState => { + if (!untypedState) { + return untypedState; + } + + const state = untypedState as TypedPersistedRootState; + + return isDcpNode(state.settings.selectedRpcUrl) + ? { + ...state, + settings: { + ...state.settings, + selectedRpcUrl: TEMPLE_RPC.url + } + } + : state; } }; diff --git a/src/store/root-state.reducers.ts b/src/store/root-state.reducers.ts index ffdbd3d5c..7a98178ca 100644 --- a/src/store/root-state.reducers.ts +++ b/src/store/root-state.reducers.ts @@ -45,7 +45,7 @@ const persistConfigBlacklist: (keyof RootState)[] = [ const persistConfig: PersistConfig = { key: 'root', - version: 5, + version: 6, storage: SlicedAsyncStorage, stateReconciler: autoMergeLevel2, writeFailHandler: persistFailHandler, diff --git a/src/utils/network.utils.ts b/src/utils/network.utils.ts index bef5b966b..7e70641a7 100644 --- a/src/utils/network.utils.ts +++ b/src/utils/network.utils.ts @@ -8,3 +8,5 @@ export const isDcpNode = (selectedRpcUrl: string) => new URL(selectedRpcUrl).hre export const getNetworkGasTokenMetadata = (selectedRpcUrl: string) => isDcpNode(selectedRpcUrl) ? FILM_TOKEN_METADATA : TEZ_TOKEN_METADATA; + +export const TALENT_MAINNET_CHAIN_ID = 'NetXooyhiru73tk'; From 9b4114406c0be30a7f7c8fef2066914d6cf23cc0 Mon Sep 17 00:00:00 2001 From: Inokentii Mazhara Date: Wed, 6 Mar 2024 13:43:07 +0200 Subject: [PATCH 2/4] TW-1362 Remove migration to mainnet and prevention of adding TalentNet --- .../custom-rpc-modals/add-modal/add-modal.tsx | 24 ++++--------------- src/store/migrations.ts | 18 -------------- 2 files changed, 4 insertions(+), 38 deletions(-) diff --git a/src/modals/custom-rpc-modals/add-modal/add-modal.tsx b/src/modals/custom-rpc-modals/add-modal/add-modal.tsx index 1a39916e3..76b96b328 100644 --- a/src/modals/custom-rpc-modals/add-modal/add-modal.tsx +++ b/src/modals/custom-rpc-modals/add-modal/add-modal.tsx @@ -1,4 +1,3 @@ -import { TezosToolkit } from '@taquito/taquito'; import { Formik } from 'formik'; import React, { FC } from 'react'; import { View } from 'react-native'; @@ -19,9 +18,7 @@ import { useNavigation } from 'src/navigator/hooks/use-navigation.hook'; import { addCustomRpc, setSelectedRpcUrl } from 'src/store/settings/settings-actions'; import { useRpcListSelector } from 'src/store/settings/settings-selectors'; import { formatSize } from 'src/styles/format-size'; -import { showWarningToast } from 'src/toast/toast.utils'; import { usePageAnalytic } from 'src/utils/analytics/use-analytics.hook'; -import { TALENT_MAINNET_CHAIN_ID } from 'src/utils/network.utils'; import { formInitialValues, formValidationSchema, confirmUniqueRPC } from '../form.utils'; @@ -32,27 +29,14 @@ export const AddCustomRpcModal: FC = () => { const { goBack } = useNavigation(); const rpcList = useRpcListSelector(); - const handleSubmit = async (newRpc: RpcInterface) => { + const handleSubmit = (newRpc: RpcInterface) => { if (confirmUniqueRPC(rpcList, newRpc) === false) { return; } - let isTalentNet = false; - try { - const tezos = new TezosToolkit(newRpc.url); - const chainId = await tezos.rpc.getChainId(); - isTalentNet = chainId === TALENT_MAINNET_CHAIN_ID; - } catch (e) { - console.error(e); - } - - if (isTalentNet) { - showWarningToast({ description: 'The T4L3NT Mainnet RPC is temporarily unavailable.' }); - } else { - dispatch(addCustomRpc(newRpc)); - dispatch(setSelectedRpcUrl(newRpc.url)); - goBack(); - } + dispatch(addCustomRpc(newRpc)); + dispatch(setSelectedRpcUrl(newRpc.url)); + goBack(); }; usePageAnalytic(ModalsEnum.AddCustomRpc); diff --git a/src/store/migrations.ts b/src/store/migrations.ts index 64aa41b8a..5b28f1e41 100644 --- a/src/store/migrations.ts +++ b/src/store/migrations.ts @@ -7,7 +7,6 @@ import { KNOWN_TOKENS_SLUGS } from 'src/token/data/token-slugs'; import { OVERRIDEN_MAINNET_TOKENS_METADATA, PREDEFINED_DCP_TOKENS_METADATA } from 'src/token/data/tokens-metadata'; import { getTokenSlug } from 'src/token/utils/token.utils'; import { isDefined } from 'src/utils/is-defined'; -import { isDcpNode } from 'src/utils/network.utils'; import { DCP_RPC, MARIGOLD_RPC, OLD_TEMPLE_RPC_URLS, TEMPLE_RPC } from 'src/utils/rpc/rpc-list'; import type { RootState } from './types'; @@ -154,22 +153,5 @@ export const MIGRATIONS: MigrationManifest = { accountsStateRecord } }; - }, - '6': (untypedState: PersistedState): undefined | TypedPersistedRootState => { - if (!untypedState) { - return untypedState; - } - - const state = untypedState as TypedPersistedRootState; - - return isDcpNode(state.settings.selectedRpcUrl) - ? { - ...state, - settings: { - ...state.settings, - selectedRpcUrl: TEMPLE_RPC.url - } - } - : state; } }; From 19605100d84afbdbd6cd95606134365e3ce6796a Mon Sep 17 00:00:00 2001 From: Inokentii Mazhara Date: Wed, 6 Mar 2024 13:46:52 +0200 Subject: [PATCH 3/4] TW-1362 Remove an unused variable --- src/utils/network.utils.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/utils/network.utils.ts b/src/utils/network.utils.ts index 7e70641a7..bef5b966b 100644 --- a/src/utils/network.utils.ts +++ b/src/utils/network.utils.ts @@ -8,5 +8,3 @@ export const isDcpNode = (selectedRpcUrl: string) => new URL(selectedRpcUrl).hre export const getNetworkGasTokenMetadata = (selectedRpcUrl: string) => isDcpNode(selectedRpcUrl) ? FILM_TOKEN_METADATA : TEZ_TOKEN_METADATA; - -export const TALENT_MAINNET_CHAIN_ID = 'NetXooyhiru73tk'; From 62ad6dd30a9b2c7f8664c1a2274004091aff64c8 Mon Sep 17 00:00:00 2001 From: Inokentii Mazhara Date: Wed, 6 Mar 2024 14:01:24 +0200 Subject: [PATCH 4/4] TW-1362 Revert store version change --- src/store/root-state.reducers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/store/root-state.reducers.ts b/src/store/root-state.reducers.ts index 7a98178ca..ffdbd3d5c 100644 --- a/src/store/root-state.reducers.ts +++ b/src/store/root-state.reducers.ts @@ -45,7 +45,7 @@ const persistConfigBlacklist: (keyof RootState)[] = [ const persistConfig: PersistConfig = { key: 'root', - version: 6, + version: 5, storage: SlicedAsyncStorage, stateReconciler: autoMergeLevel2, writeFailHandler: persistFailHandler,