Skip to content
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

Connection Screens Revamp Follow-up #780

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
2e4f6ab
Merge branch 'develop' into mahmoud/eng-3370-improve-get-address-screen
m-aboelenein Dec 18, 2023
ac2429a
init getAddress screen revamp
m-aboelenein Dec 18, 2023
83ad1c5
Merge branch 'develop' into mahmoud/eng-3370-improve-get-address-screen
m-aboelenein Dec 18, 2023
c1f2fd4
Merge branch 'develop' into mahmoud/eng-3370-improve-get-address-screen
m-aboelenein Dec 19, 2023
4cc9a5a
update ui
m-aboelenein Dec 20, 2023
3d2ea7d
update btc address select request
m-aboelenein Dec 22, 2023
3954e2b
Merge branch 'develop' into mahmoud/eng-3370-improve-get-address-screen
m-aboelenein Jan 8, 2024
53b7f28
Merge branch 'develop' into mahmoud/eng-3370-improve-get-address-screen
m-aboelenein Jan 10, 2024
e4b422c
update stx screen and add btcAddress to stacks connect response
m-aboelenein Jan 10, 2024
8fb1916
Merge remote-tracking branch 'origin/develop' into mahmoud/eng-3370-i…
m-aboelenein Jan 22, 2024
7ceee45
ui fixes
m-aboelenein Jan 23, 2024
f2368a3
minor fixes
m-aboelenein Jan 23, 2024
87bdd48
Merge remote-tracking branch 'origin/develop' into mahmoud/eng-3370-i…
m-aboelenein Jan 23, 2024
c173dae
disable account actions on connection requests
m-aboelenein Jan 23, 2024
067bb8b
added icon borderRadius
m-aboelenein Jan 24, 2024
c0cfa1d
remove debug log
m-aboelenein Jan 24, 2024
2275097
Merge remote-tracking branch 'origin/develop' into mahmoud/eng-3370-i…
m-aboelenein Jan 25, 2024
89a240b
Fix typing between sats connect and extension for providers (#768)
victorkirov Jan 25, 2024
f4c2a2b
Merge branch 'develop' into mahmoud/eng-3370-improve-get-address-screen
m-aboelenein Jan 25, 2024
ce85735
resolve ui issues
m-aboelenein Jan 26, 2024
8a2cc53
Merge remote-tracking branch 'origin/develop' into mahmoud/eng-3370-i…
m-aboelenein Jan 26, 2024
e10c7a0
missing stx-address call out
m-aboelenein Jan 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 54 additions & 31 deletions src/app/screens/connect/authenticationRequest/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,19 @@ import { MESSAGE_SOURCE } from '@common/types/message-types';
import { delay } from '@common/utils/ledger';
import BottomModal from '@components/bottomModal';
import ActionButton from '@components/button';
import InfoContainer from '@components/infoContainer';
import LedgerConnectionView from '@components/ledger/connectLedgerView';
import useSeedVault from '@hooks/useSeedVault';
import useWalletSelector from '@hooks/useWalletSelector';
import Transport from '@ledgerhq/hw-transport-webusb';
import { animated, useSpring } from '@react-spring/web';
import SelectAccount from '@screens/connect/selectAccount';
import {
AuthRequest,
createAuthResponse,
handleLedgerStxJWTAuth,
} from '@secretkeylabs/xverse-core';
import { AddressVersion, StacksMessageType, publicKeyToAddress } from '@stacks/transactions';
import Callout from '@ui-library/callout';
import { StickyHorizontalSplitButtonContainer } from '@ui-library/common.styled';
import { isHardwareAccount } from '@utils/helper';
import { decodeToken } from 'jsontokens';
Expand All @@ -30,9 +31,10 @@ import validUrl from 'valid-url';
import AddressPurposeBox from '../addressPurposeBox';
import PermissionsList from '../permissionsList';

const MainContainer = styled.div((props) => ({
const MainContainer = styled(animated.div)((props) => ({
display: 'flex',
flexDirection: 'column',
flex: 1,
paddingLeft: props.theme.space.m,
paddingRight: props.theme.space.m,
...props.theme.scrollbar,
Expand Down Expand Up @@ -76,8 +78,8 @@ const DappName = styled.h2((props) => ({
}));

const InfoContainerWrapper = styled.div((props) => ({
margin: props.theme.spacing(10),
marginBottom: 0,
marginTop: props.theme.spacing(10),
marginBottom: 'auto',
}));

const AddressesContainer = styled.div((props) => ({
Expand Down Expand Up @@ -109,6 +111,17 @@ function AuthenticationRequest() {
const { getSeed } = useSeedVault();
const isDisabled = !selectedAccount?.stxAddress;

const styles = useSpring({
from: {
opacity: 0,
y: 24,
},
to: {
y: 0,
opacity: 1,
},
});

const confirmCallback = async () => {
setLoading(true);
try {
Expand Down Expand Up @@ -243,42 +256,52 @@ function AuthenticationRequest() {
};

return (
<MainContainer>
<MainContainer style={styles}>
{getDappLogo()}
<Title>{t('TITLE')}</Title>
<DappName>{`${t('REQUEST_TOOLTIP')} ${authRequest.payload.appDetails?.name}`}</DappName>
<SelectAccount account={selectedAccount!} handlePressAccount={handleSwitchAccount} />
<AddressesContainer>
<AddressPurposeBox
purpose={AddressPurpose.Stacks}
icon={stxIcon}
title={t('STX_ADDRESS')}
address={selectedAccount?.stxAddress || stxAddress}
bnsName={selectedAccount?.bnsName}
/>
<AddressPurposeBox
purpose={AddressPurpose.Payment}
icon={BitcoinIcon}
title={t('BITCOIN_ADDRESS')}
address={selectedAccount?.btcAddress || btcAddress}
/>
</AddressesContainer>
<PermissionsContainer>
<PermissionsList />
</PermissionsContainer>
<StickyHorizontalSplitButtonContainer>
<ActionButton text={t('CANCEL_BUTTON')} transparent onPress={cancelCallback} />
<ActionButton text={t('CONNECT_BUTTON')} processing={loading} onPress={confirmCallback} />
</StickyHorizontalSplitButtonContainer>
{isDisabled && (
{!isDisabled ? (
<>
<AddressesContainer>
<AddressPurposeBox
purpose={AddressPurpose.Stacks}
icon={stxIcon}
title={t('STX_ADDRESS')}
address={selectedAccount?.stxAddress || stxAddress}
bnsName={selectedAccount?.bnsName}
/>
<AddressPurposeBox
purpose={AddressPurpose.Payment}
icon={BitcoinIcon}
title={t('BITCOIN_ADDRESS')}
address={selectedAccount?.btcAddress || btcAddress}
/>
</AddressesContainer>
<PermissionsContainer>
<PermissionsList />
</PermissionsContainer>
</>
) : (
<InfoContainerWrapper>
<InfoContainer
<Callout
bodyText={t('NO_STACKS_AUTH_SUPPORT.TITLE')}
redirectText={t('NO_STACKS_AUTH_SUPPORT.LINK')}
onClick={handleAddStxLedgerAccount}
onClickRedirect={handleAddStxLedgerAccount}
/>
</InfoContainerWrapper>
)}

<StickyHorizontalSplitButtonContainer>
<ActionButton text={t('CANCEL_BUTTON')} transparent onPress={cancelCallback} />
<ActionButton
text={t('CONNECT_BUTTON')}
processing={loading}
onPress={confirmCallback}
disabled={isDisabled}
/>
</StickyHorizontalSplitButtonContainer>

<BottomModal header="" visible={isModalVisible} onClose={() => setIsModalVisible(false)}>
{currentStepIndex === 0 && (
<LedgerConnectionView
Expand Down Expand Up @@ -306,7 +329,7 @@ function AuthenticationRequest() {
<ActionButton
onPress={isTxRejected || isConnectFailed ? handleRetry : handleConnectAndConfirm}
text={t(isTxRejected || isConnectFailed ? 'LEDGER.RETRY_BUTTON' : 'CONNECT_BUTTON')}
disabled={isButtonDisabled}
disabled={isButtonDisabled || isDisabled}
processing={isButtonDisabled}
/>
<ActionButton onPress={cancelCallback} text={t('CANCEL_BUTTON')} transparent />
Expand Down
76 changes: 48 additions & 28 deletions src/app/screens/connect/btcSelectAddressScreen/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,20 @@ import OrdinalsIcon from '@assets/img/nftDashboard/white_ordinals_icon.svg';
import ActionButton from '@components/button';
import useBtcAddressRequest from '@hooks/useBtcAddressRequest';
import useWalletSelector from '@hooks/useWalletSelector';
import { animated, useSpring } from '@react-spring/web';
import { animated, useTransition } from '@react-spring/web';
import SelectAccount from '@screens/connect/selectAccount';
import { StickyHorizontalSplitButtonContainer } from '@ui-library/common.styled';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import { MoonLoader } from 'react-spinners';
import { AddressPurpose } from 'sats-connect';
import styled from 'styled-components';
import AddressPurposeBox from '../addressPurposeBox';
import PermissionsList from '../permissionsList';
import { getAppIconFromWebManifest } from './helper';

const OuterContainer = styled(animated.div)((props) => ({
const OuterContainer = styled.div((props) => ({
display: 'flex',
flexDirection: 'column',
paddingLeft: props.theme.space.m,
Expand Down Expand Up @@ -71,25 +72,28 @@ const PermissionsContainer = styled.div((props) => ({
paddingBottom: props.theme.space.xxl,
}));

const LoaderContainer = styled.div(() => ({
justifySelf: 'center',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
flex: 1,
}));

function BtcSelectAddressScreen() {
const [loading, setLoading] = useState(false);
const navigate = useNavigate();
const { t } = useTranslation('translation', { keyPrefix: 'SELECT_BTC_ADDRESS_SCREEN' });
const { network, btcAddress, ordinalsAddress, stxAddress, selectedAccount } = useWalletSelector();
const [appIcon, setAppIcon] = useState<string>('');
const [isLoadingIcon, setIsLoadingIcon] = useState(false);
const { payload, origin, approveBtcAddressRequest, cancelAddressRequest } =
useBtcAddressRequest();
const appUrl = useMemo(() => origin.replace(/(^\w+:|^)\/\//, ''), [origin]);

const styles = useSpring({
from: {
opacity: 0,
y: 24,
},
to: {
y: 0,
opacity: 1,
},
const transition = useTransition(isLoadingIcon, {
from: { opacity: 0, y: 30 },
enter: { opacity: 1, y: 0 },
});

const confirmCallback = async () => {
Expand Down Expand Up @@ -139,8 +143,10 @@ function BtcSelectAddressScreen() {
useEffect(() => {
(async () => {
if (origin !== '') {
setIsLoadingIcon(true);
getAppIconFromWebManifest(origin).then((appIcons) => {
setAppIcon(appIcons);
setIsLoadingIcon(false);
});
}
})();
Expand Down Expand Up @@ -188,23 +194,37 @@ function BtcSelectAddressScreen() {
navigate('/account-list?hideListActions=true');
};

return (
<OuterContainer style={styles}>
<HeadingContainer>
{appIcon !== '' ? <TopImage src={appIcon} alt="Dapp Logo" /> : null}
<Title>{t('TITLE')}</Title>
<DapURL>{appUrl}</DapURL>
</HeadingContainer>
{payload.message ? <RequestMessage>{payload.message.substring(0, 80)}</RequestMessage> : null}
<SelectAccount account={selectedAccount!} handlePressAccount={handleSwitchAccount} />
<AddressBoxContainer>{payload.purposes.map(AddressPurposeRow)}</AddressBoxContainer>
<PermissionsContainer>
<PermissionsList />
</PermissionsContainer>
<StickyHorizontalSplitButtonContainer>
<ActionButton text={t('CANCEL_BUTTON')} transparent onPress={cancelCallback} />
<ActionButton text={t('CONNECT_BUTTON')} processing={loading} onPress={confirmCallback} />
</StickyHorizontalSplitButtonContainer>
return isLoadingIcon ? (
<LoaderContainer>
<MoonLoader color="white" size={50} />
</LoaderContainer>
) : (
<OuterContainer>
{transition((style) => (
<animated.div style={style}>
<HeadingContainer>
{appIcon !== '' ? <TopImage src={appIcon} alt="Dapp Logo" /> : null}
<Title>{t('TITLE')}</Title>
<DapURL>{appUrl}</DapURL>
</HeadingContainer>
{payload.message ? (
<RequestMessage>{payload.message.substring(0, 80)}</RequestMessage>
) : null}
<SelectAccount account={selectedAccount!} handlePressAccount={handleSwitchAccount} />
<AddressBoxContainer>{payload.purposes.map(AddressPurposeRow)}</AddressBoxContainer>
<PermissionsContainer>
<PermissionsList />
</PermissionsContainer>
<StickyHorizontalSplitButtonContainer>
<ActionButton text={t('CANCEL_BUTTON')} transparent onPress={cancelCallback} />
<ActionButton
text={t('CONNECT_BUTTON')}
processing={loading}
onPress={confirmCallback}
/>
</StickyHorizontalSplitButtonContainer>
</animated.div>
))}
</OuterContainer>
);
}
Expand Down
52 changes: 33 additions & 19 deletions src/app/screens/connect/selectAccount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,17 @@ const AccountInfoContainer = styled.button((props) => ({
padding: props.theme.space.m,
}));

const CurrentAccountContainer = styled.div((props) => ({
const CurrentAccountContainer = styled.div({
display: 'flex',
alignItems: 'center',
}));
});

const CurrentAccountTextContainer = styled.div((props) => ({
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
gap: props.theme.spacing(4),
paddingLeft: props.theme.spacing(4),
paddingLeft: props.theme.space.xs,
}));

const CurrentSelectedAccountText = styled.h1((props) => ({
Expand All @@ -48,6 +48,11 @@ const GradientCircle = styled.div<GradientCircleProps>((props) => ({
background: `linear-gradient(to bottom,${props.firstGradient}, ${props.secondGradient},${props.thirdGradient} )`,
}));

const AccountTag = styled.div(() => ({
display: 'flex',
alignItems: 'center',
}));

const SwitchAccountContainer = styled.div(() => ({
display: 'flex',
alignItems: 'center',
Expand All @@ -66,28 +71,37 @@ type SelectAccountProps = {

function SelectAccount({ account, handlePressAccount }: SelectAccountProps) {
const gradient = getAccountGradient(account?.stxAddress || account?.btcAddress!);
// const { t } = useTranslation('translation', { keyPrefix: 'DASHBOARD_SCREEN' });
const { t } = useTranslation('translation', { keyPrefix: 'SELECT_BTC_ADDRESS_SCREEN' });
const theme = useTheme();
const getName = () =>
account?.accountName ??
account?.bnsName ??
`${t('ACCOUNT_NAME')} ${`${(account?.id ?? 0) + 1}`}`;
const getName = () => {
const maxNameCharacters = isHardwareAccount(account) || account.bnsName ? 12 : 20;
const maxLength =
account?.accountName && account?.accountName?.length > maxNameCharacters ? '...' : '';
if (account.accountName) {
return `${account?.accountName?.slice(0, maxNameCharacters)}${maxLength}`;
}
if (account.bnsName) {
return `${account.bnsName.slice(0, maxNameCharacters)}${maxLength}`;
}
return `${t('ACCOUNT_NAME')} ${`${(account?.id ?? 0) + 1}`}`;
};

return (
<AccountInfoContainer onClick={handlePressAccount}>
<CurrentAccountContainer>
<GradientCircle
firstGradient={gradient[0]}
secondGradient={gradient[1]}
thirdGradient={gradient[2]}
/>
{account && (
<CurrentAccountTextContainer>
<CurrentSelectedAccountText>{getName()}</CurrentSelectedAccountText>
{isHardwareAccount(account) && <img src={LedgerBadge} alt="Ledger icon" />}
</CurrentAccountTextContainer>
)}
<AccountTag>
<GradientCircle
firstGradient={gradient[0]}
secondGradient={gradient[1]}
thirdGradient={gradient[2]}
/>
{account && (
<CurrentAccountTextContainer>
<CurrentSelectedAccountText>{getName()}</CurrentSelectedAccountText>
{isHardwareAccount(account) && <img src={LedgerBadge} alt="Ledger icon" />}
</CurrentAccountTextContainer>
)}
</AccountTag>
</CurrentAccountContainer>
<SwitchAccountContainer>
<SwitchAccountText>{t('CHANGE_ACCOUNT_BUTTON')}</SwitchAccountText>
Expand Down
4 changes: 2 additions & 2 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,7 @@
"PERMISSION_REQUEST_TX": "Request transaction signing",
"NO_STACKS_AUTH_SUPPORT": {
"TITLE": "This wallet does not have a Stacks address.",
"LINK": "Create an address here"
"LINK": "Create a Stacks address"
},
"LEDGER": {
"CONNECT": {
Expand Down Expand Up @@ -1050,7 +1050,7 @@
"BITCOIN_ADDRESS": "Payments address",
"ORDINAL_ADDRESS": "Ordinals address",
"STX_ADDRESS": "Stacks address",
"CHANGE_ACCOUNT_BUTTON": "Change account",
"CHANGE_ACCOUNT_BUTTON": "Select",
"NETWORK_MISMATCH_ERROR_TITLE": "Mismatched Network",
"NETWORK_MISMATCH_ERROR_DESCRIPTION": "The app is requesting your wallet address for a different network. You may have to switch your active network in wallet settings.",
"INVALID_PURPOSE_ERROR_TITLE": "Invalid Request",
Expand Down