-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor(wallet-mobile): Receive funnel fixes and refactor #3092
Conversation
stackchain
commented
Feb 26, 2024
•
edited
Loading
edited
- query fixes missing wallet.id
- collocated code
- renamed the screens to reflect the use cases
- bug fixes
- major bug on transfer (not resetting state properly)
- dropped unnecessary code
- refactored the hooks
@@ -971,4 +971,4 @@ SPEC CHECKSUMS: | |||
|
|||
PODFILE CHECKSUM: 4045625f1556b4d232075df8dbd22524a7010c3f | |||
|
|||
COCOAPODS: 1.14.3 | |||
COCOAPODS: 1.15.2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
all bump your Xcodes / cocoa pods
|
||
const ACTION_PROPS = { | ||
size: 24, | ||
color: String(colors.actionColor), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dropped unnecessary String
const wallet = useSelectedWallet() | ||
|
||
const {isSingle, addressDerivation} = useAddressDerivationManager() | ||
const {next: nextReceiveAddress} = useReceiveAddressesStatus(addressDerivation) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
on ActionsBanner, there is no receive address selected, only the next
that depends on wallet state, the context is only for the details, since we avoid params.
1fc7ecd
to
32e87a1
Compare
const stakingKey = useStakingKey(wallet) | ||
const swapManager = React.useMemo(() => { | ||
const aggregatorTokenId = isMainnetNetworkId(wallet.networkId) ? milkTokenId.mainnet : milkTokenId.preprod |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved inside memo
@@ -75,19 +75,15 @@ export const TxHistoryNavigator = () => { | |||
const storage = useAsyncStorage() | |||
const {theme} = useTheme() | |||
|
|||
// receive | |||
const receiveAddresses = useReceiveAddresses(wallet) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dropped
@@ -126,7 +122,7 @@ export const TxHistoryNavigator = () => { | |||
const headerRightHistory = React.useCallback(() => <HeaderRightHistory />, []) | |||
|
|||
return ( | |||
<ReceiveProvider key={wallet.id} initialCurrentAddress={currentAddress}> | |||
<ReceiveProvider key={wallet.id}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
initial state is mainly for testing / stories.
<ReceiveProvider> | ||
<AddressDetailCard address={mocks.address} title="Test Title" /> | ||
</ReceiveProvider> | ||
.addDecorator((story) => ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved the provider as decorator.
import {useKeyHashes} from '../../../../yoroi-wallets/hooks' | ||
import {useReceive} from '../ReceiveProvider' | ||
import {ShareDetailsCard} from '../ShareDetailsCard/ShareDetailsCard' | ||
import {ShareQRCodeCard} from '../ShareQRCodeCard/ShareQRCodeCard' | ||
|
||
type ShareProps = { | ||
address: string | ||
type AddressDetailCardProps = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
consistency
if (selectedAddress === undefined) { | ||
return | ||
const index = Math.floor(offset / (itemsPerPage * screenWidth - minToSwitchPage)) | ||
setScrollPosition(Math.max(index, 0)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
otherwise when swiping left at first page will cause no index be off while holding the first page, causing the indicator to be wrong until the page is released.
title, | ||
}, | ||
] as const | ||
|
||
const screenWidth = useWindowDimensions().width |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need for caps.
const totalPages = Math.ceil(cards.length / itemsPerPage) | ||
const circleIndex = Array.from({length: totalPages}, (_, index) => index + 1) | ||
const cardIndicators = Array.from({length: totalPages}, (_, index) => index) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
declarative
} & ( | ||
| { | ||
cardType: 'QRCode' | ||
} | ||
| ({cardType: 'Details'} & AddressDetailsProps) | ||
) | ||
|
||
export const AddressDetailCard = ({title}: ShareProps) => { | ||
const [scrollPosition, setScrollPosition] = useState(0) | ||
const [isSecondPage, setIsSecondPage] = useState(false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dropped unnecessary state
onLongPress={() => copy(item.address)} | ||
isCopying={isCopying} | ||
/> | ||
) | ||
case 'Details': | ||
if (Boolean(item.address) && Boolean(item.stakingHash) && Boolean(item.spendingHash) && Boolean(item.title)) { | ||
setIsSecondPage(true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unnecessary state
<ShareDetailsCard address={item.address} stakingHash={item.stakingHash} spendingHash={item.spendingHash} /> | ||
) | ||
default: | ||
return null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
only to satisfy TS.
@@ -116,21 +104,19 @@ export const AddressDetailCard = ({title}: ShareProps) => { | |||
|
|||
<Spacer height={12} /> | |||
|
|||
{isSecondPage && ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unnecessary
@@ -156,8 +142,8 @@ const useStyles = () => { | |||
}) | |||
|
|||
const colors = { | |||
indexActive: theme.color.primary[600], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
leaky
@@ -8,26 +8,14 @@ import {Spacer, Text} from '../../../../components' | |||
import {YoroiLogoIllustration} from '../../illustrations/YoroiLogo' | |||
|
|||
type ShareProps = { | |||
address?: string | |||
title?: string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a lot of unused props
} | ||
|
||
type AddressDetailsProps = { | ||
address: string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ibid idem
const {styles, colors} = useStyles() | ||
|
||
return ( | ||
<View style={[styles.touchableCard]}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
@@ -37,23 +25,23 @@ export const CaptureShareQRCodeCard = ({address}: ShareProps) => { | |||
|
|||
<Spacer height={16} /> | |||
|
|||
<YoroiLogoIllustration height={logoHeight} width={logoWidth} /> | |||
<YoroiLogoIllustration height={37} width={35} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need for constant, is not a magic number, the api is very declarative
}: { | ||
children: React.ReactNode | ||
initialState?: Partial<ReceiveState> | ||
initialCurrentAddress?: string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dropped part of the state already
}) => { | ||
const [state, dispatch] = React.useReducer(receiveReducer, { | ||
...defaultState, | ||
...initialState, | ||
}) | ||
|
||
const actions = React.useRef<ReceiveActions>({ | ||
currentAddressChanged: (address: string) => dispatch({type: ReceiveActionType.CurrentAddressChanged, address}), | ||
selectedAddressChanged: (address: string) => dispatch({type: ReceiveActionType.SelectedAddressChanged, address}), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
consistency
} | ||
|
||
const defaultState: ReceiveState = Object.freeze({ | ||
selectedAddress: null, | ||
defaultAddress: null, | ||
selectedAddress: '', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
receive address can't never be null, since is created on wallet basis
stakingHash={mocks.stakinghash} | ||
title="Test Title" | ||
/> | ||
<ShareDetailsCard address={mocks.address} spendingHash={mocks.spendinghash} stakingHash={mocks.stakinghash} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unused prop
@@ -7,7 +8,9 @@ import {ShareQRCodeCard} from './ShareQRCodeCard' | |||
|
|||
storiesOf('Receive ShareQRCodeCard', module) | |||
.addDecorator((story) => <View style={styles.container}>{story()}</View>) | |||
.add('default', () => <ShareQRCodeCard address={mocks.address} />) | |||
.add('with content', () => ( | |||
<ShareQRCodeCard content={mocks.address} onLongPress={action('onLongPress')} title="Title" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
most components in common are actually useCases of just one screen, it needs a second refactor later
|
||
const query = useQuery({ | ||
suspense: true, | ||
queryKey: [wallet.id, isShowingMultipleAddressInfoKey], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ibid idem
|
||
const parsed = parseSafe(storedStorage) | ||
// old wallets wont have this key, so we default to true | ||
return isBoolean(parsed) ? parsed : true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
marking to display by default (empty storage), it affects only multiple funnel so needs to be configured, looks right needs confirmation cc: @SorinC6
@@ -7,7 +7,7 @@ export const useNavigateTo = () => { | |||
const navigation = useNavigation<TxHistoryRouteNavigation>() | |||
|
|||
return useRef({ | |||
receiceDetails: () => navigation.navigate('receive-single'), | |||
receiveDetails: () => navigation.navigate('receive-single'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also part of package candidate
{used: [], unused: []} as Omit<ReceiveAddressesStatus, 'next'>, | ||
) | ||
const multipleAddress = addressesStatus.unused[0] ?? addressesStatus.used[0] | ||
const nextAddress = isSingle ? singleAddress : multipleAddress |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
next can only be calculated after the unused are discovered for multiple addresses, (first unused), if single always path index 0
@@ -57,18 +38,16 @@ export const SingleAddressScreen = () => { | |||
textStyles={{ | |||
color: colors.buttonBackgroundBlue, | |||
}} | |||
onPress={() => navigate.specificAmount()} | |||
disabled={currentAddress === null} | |||
onPress={navigate.specificAmount} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clean ups
address: string | ||
} | ||
|
||
export const MultipleAddressesScreen = () => { | ||
export const ListMultipleAddressesScreen = () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
declarative use case
}} | ||
// date={mocks.usedAddressDate} // TODO don't have the date?? | ||
// date={} // TODO define with project |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
needs checking, it should be dropped for the 1st iteration, it will require to scrap all txs. cc: @SorinC6
) | ||
|
||
return ( | ||
<SafeAreaView style={styles.root} edges={['left', 'right', 'bottom']}> | ||
{mappedAddresses.length >= BIP32_HD_GAP_LIMIT && ( | ||
{hasReachedGapLimit && ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clean ups less overhead, declarative
@@ -159,7 +160,7 @@ const useStyles = () => { | |||
return {styles, colors} as const | |||
} | |||
|
|||
const mapAddresses = (addresses: {unused: string[]; used: string[]}): AddressInfo[] => { | |||
const toAddressInfos = (addresses: {unused: string[]; used: string[]}): AddressInfo[] => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
transformer, was leaking impl
import {useStrings} from '../common/useStrings' | ||
|
||
export const EnterAmountScreen = () => { | ||
export const RequestSpecificAmountScreen = () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use case
|
||
const screenHeight = useWindowDimensions().height |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
collocated
@@ -83,13 +79,11 @@ export const EnterAmountScreen = () => { | |||
) | |||
} | |||
|
|||
const Modal = ({amount, address}: {amount: string; address?: string}) => { | |||
const Modal = ({amount, address}: {amount: string; address: string}) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not optional
const {setMultipleAddressesOn, setMultipleAddressesOff, isToggleReceiveTypeLoading} = useMultipleAddresses() | ||
const [isLocalMultipleAddressOff, setIsLocalMultipleAddressesOff] = React.useState(isMultipleAddressesOff) | ||
const AddresseDerivationSwitcher = (props: {isSingle: boolean}) => { | ||
const addressDerivation = useAddressDerivationManager() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
refactor mainly for the new hooks
@@ -33,6 +33,8 @@ const transferReducer = (state: TransferState, action: TransferAction) => { | |||
draft.selectedTokenId = defaultTransferState.selectedTokenId | |||
draft.memo = defaultTransferState.memo | |||
draft.unsignedTx = castDraft(defaultTransferState.unsignedTx) | |||
draft.selectedTargetIndex = defaultTransferState.selectedTargetIndex |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bug when resetting state, was not setting back some properties cc: @banklesss (maybe there is a better way of settings the entire draft as initialState)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
need to have a look
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
amazing catch
entry: { | ||
address: '', | ||
amounts: {}, | ||
export const defaultTransferState: TransferState = freeze( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as const is shallow
singleMode: () => setAddressDerivationMode('single'), | ||
multipleMode: () => setAddressDerivationMode('multiple'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest enableSingleMode
and enableMultipleMode
share functionality will be refactored here https://emurgo.atlassian.net/browse/YOMO-1201 |