Skip to content

Commit

Permalink
fix: error message page
Browse files Browse the repository at this point in the history
  • Loading branch information
fbwoolf authored and kyranjamie committed Apr 23, 2022
1 parent 9a9771e commit 228e9b7
Show file tree
Hide file tree
Showing 11 changed files with 148 additions and 57 deletions.
Binary file added public/assets/images/generic-error.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
67 changes: 67 additions & 0 deletions src/app/components/generic-error/generic-error.layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { ReactNode } from 'react';
import { Box, Flex, Text, color, Button } from '@stacks/ui';

import { Title } from '@app/components/typography';
import GenericError from '@assets/images/generic-error.png';

interface ErrorProps {
body: string;
helpTextList: ReactNode[];
onClose(): void;
title: string;
}
export function GenericErrorLayout(props: ErrorProps) {
const { body, helpTextList, onClose, title } = props;

return (
<Flex alignItems="center" flexDirection="column" px={['loose', 'unset']} width="100%">
<Box mt="loose">
<img src={GenericError} width="106px" />
</Box>
<Title fontSize={4} mt="loose">
{title}
</Title>
<Text
color={color('text-caption')}
fontSize="16px"
lineHeight="1.6"
mt="base"
textAlign="center"
>
{body}
</Text>
<Box
as="ul"
border="2px solid #EFEFF2"
borderRadius="12px"
color={color('text-caption')}
fontSize="14px"
lineHeight="1.6"
mt="extra-loose"
pb="loose"
pl="40px"
pr="loose"
pt="tight"
width="100%"
>
{helpTextList}
<Box as="li" mt="base">
Still stuck? Reach out to{' '}
<Text
as="button"
color={color('accent')}
onClick={() => {
window.open('mailto:[email protected]');
window.close();
}}
>
[email protected]
</Text>
</Box>
</Box>
<Button fontSize="14px" mt="base-tight" onClick={onClose} p="base" variant="link">
Close window
</Button>
</Flex>
);
}
22 changes: 22 additions & 0 deletions src/app/components/generic-error/generic-error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ReactNode } from 'react';

import { Header } from '@app/components/header';
import { useRouteHeader } from '@app/common/hooks/use-route-header';

import { GenericErrorLayout } from './generic-error.layout';

interface ErrorProps {
body: string;
helpTextList: ReactNode[];
onClose?(): void;
title: string;
}
export function GenericError(props: ErrorProps) {
const { body, helpTextList, onClose = () => window.close(), title } = props;

useRouteHeader(<Header hideActions />);

return (
<GenericErrorLayout body={body} helpTextList={helpTextList} onClose={onClose} title={title} />
);
}
40 changes: 21 additions & 19 deletions src/app/components/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,29 +62,31 @@ export const Header: React.FC<HeaderProps> = memo(props => {
</Box>
) : null}
{!title && (!onClose || desktopViewport) ? (
<Stack
alignItems="flex-end"
<Flex
alignItems="center"
flexBasis="60%"
height="36px"
isInline
justifyContent={onClose ? 'center' : 'unset'}
>
<HiroWalletLogo
data-testid={OnboardingSelectors.HiroWalletLogoRouteToHome}
isClickable={hiroWalletLogoIsClickable}
onClick={hiroWalletLogoIsClickable ? () => navigate(RouteUrls.Home) : undefined}
/>
<Caption
color={color('text-caption')}
display={!version ? 'none' : 'unset'}
fontFamily="mono"
marginRight="10px"
mb="2px"
variant="c3"
>
{version}
</Caption>
</Stack>
<Flex alignItems="flex-end">
<HiroWalletLogo
data-testid={OnboardingSelectors.HiroWalletLogoRouteToHome}
isClickable={hiroWalletLogoIsClickable}
onClick={hiroWalletLogoIsClickable ? () => navigate(RouteUrls.Home) : undefined}
/>
<Caption
color={color('text-caption')}
display={!version ? 'none' : 'unset'}
fontFamily="mono"
marginRight="10px"
mb="2px"
ml="tight"
variant="c3"
>
{version}
</Caption>
</Flex>
</Flex>
) : (
<Title
alignSelf="center"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { memo } from 'react';
import { Navigate } from 'react-router-dom';
import { STXTransferPayload, TransactionTypes } from '@stacks/connect';
import { color, Stack, useClipboard, Fade, Flex } from '@stacks/ui';
import { truncateMiddle } from '@stacks/ui-utils';
Expand All @@ -16,6 +17,7 @@ import {
} from '@app/store/transactions/requests.hooks';
import { useCurrentAccountAvailableStxBalance } from '@app/store/accounts/account.hooks';
import { useCurrentAccount } from '@app/store/accounts/account.hooks';
import { RouteUrls } from '@shared/route-urls';

export const FeeInsufficientFundsErrorMessage = memo(props => {
const currentAccount = useCurrentAccount();
Expand Down Expand Up @@ -116,44 +118,11 @@ export const IncorrectContractAddressMessage = memo(props => {
);
});

export const UnauthorizedErrorMessage = memo(props => {
useScrollLock(true);
return (
<Fade in>
{styles => (
<Flex
position="absolute"
width="100%"
height="100vh"
zIndex={99}
left={0}
top={0}
alignItems="center"
justifyContent="center"
p="loose"
bg="rgba(0,0,0,0.35)"
backdropFilter="blur(10px)"
style={styles}
>
<ErrorMessage
title="Unauthorized request"
body="The transaction request was not properly authorized by any of your accounts. If you've logged in to this app before, then you might need to re-authenticate into this application before attempting to sign a transaction with the Hiro Wallet."
border={'1px solid'}
borderColor={color('border')}
boxShadow="high"
css={{
'& > *': {
pointerEvents: 'all',
},
}}
{...props}
/>
</Flex>
)}
</Fade>
);
export const UnauthorizedRequestRedirect = memo(() => {
return <Navigate to={RouteUrls.UnauthorizedRequest} />;
});

// TODO: Change this to new Error component?
export const ExpiredRequestErrorMessage = memo(props => {
useScrollLock(true);
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
IncorrectContractAddressMessage,
NoContractErrorMessage,
StxTransferInsufficientFundsErrorMessage,
UnauthorizedErrorMessage,
UnauthorizedRequestRedirect,
} from './error-messages';

export enum TransactionErrorReason {
Expand Down Expand Up @@ -49,7 +49,7 @@ const TransactionErrorSuspense = memo(() => {
case TransactionErrorReason.FeeInsufficientFunds:
return <FeeInsufficientFundsErrorMessage />;
case TransactionErrorReason.Unauthorized:
return <UnauthorizedErrorMessage />;
return <UnauthorizedRequestRedirect />;
case TransactionErrorReason.ExpiredRequest:
return <ExpiredRequestErrorMessage />;
default:
Expand Down
16 changes: 16 additions & 0 deletions src/app/pages/unauthorized-request/unauthorized-request.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Box } from '@stacks/ui';

import { GenericError } from '@app/components/generic-error/generic-error';

const body = `The transaction request was not properly authorized by any of your Hiro Wallet accounts. This typically happens if you've logged into this app before using another account.`;
const helpTextList = [
<Box as="li" mt="base">
Please sign out of the app and sign back in to re-authenticate into the application. This should
help you successfully sign your transaction with the Hiro Wallet.
</Box>,
];
const title = 'Unauthorized request';

export function UnauthorizedRequest() {
return <GenericError body={body} helpTextList={helpTextList} title={title} />;
}
2 changes: 2 additions & 0 deletions src/app/routes/app-routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { BuyPage } from '@app/pages/buy/buy';
import { BackUpSecretKeyPage } from '@app/pages/onboarding/back-up-secret-key/back-up-secret-key';
import { WelcomePage } from '@app/pages/onboarding/welcome/welcome';
import { useHasStateRehydrated } from '@app/store';
import { UnauthorizedRequest } from '@app/pages/unauthorized-request/unauthorized-request';
import { RouteUrls } from '@shared/route-urls';

import { useOnWalletLock } from './hooks/use-on-wallet-lock';
Expand Down Expand Up @@ -145,6 +146,7 @@ export function AppRoutes(): JSX.Element | null {
</AccountGate>
}
/>
<Route path={RouteUrls.UnauthorizedRequest} element={<UnauthorizedRequest />} />
<Route
path={RouteUrls.ViewSecretKey}
element={
Expand Down
1 change: 1 addition & 0 deletions src/shared/route-urls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export enum RouteUrls {
Send = '/send',
SignOutConfirm = '/sign-out',
TransactionRequest = '/transaction',
UnauthorizedRequest = '/unauthorized-request',
ViewSecretKey = '/view-secret-key',
// Locked wallet route
Unlock = '/unlock',
Expand Down
8 changes: 8 additions & 0 deletions tests/integration/settings/settings.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ describe(`Settings integration tests`, () => {
await wallet.signUp();
await wallet.waitForHideOnboardingsStepsButton();
await wallet.clickHideSteps();
await delay(500);
});

afterAll(async () => {
Expand All @@ -27,6 +28,7 @@ describe(`Settings integration tests`, () => {
});

it('should be able to create a new account', async () => {
await wallet.waitForSettingsButton();
await wallet.clickSettingsButton();
await wallet.page.click(createTestSelector(SettingsSelectors.CreateAccountBtn));
await delay(500);
Expand All @@ -39,13 +41,15 @@ describe(`Settings integration tests`, () => {

it(`should be able to create ${numOfAccountsToTest} new accounts then switch between them`, async () => {
for (let i = 0; i < numOfAccountsToTest - 1; i++) {
await wallet.waitForSettingsButton();
await wallet.clickSettingsButton();
await wallet.page.click(createTestSelector(SettingsSelectors.CreateAccountBtn));
await delay(500);
await wallet.waitForHomePage();
}

for (let i = 0; i < numOfAccountsToTest; i++) {
await wallet.waitForSettingsButton();
await wallet.clickSettingsButton();
await wallet.page.click(createTestSelector(SettingsSelectors.SwitchAccount));
await delay(500);
Expand All @@ -64,6 +68,7 @@ describe(`Settings integration tests`, () => {
});

it('should be able to view and save secret key to clipboard', async () => {
await wallet.waitForSettingsButton();
await wallet.clickSettingsButton();
await wallet.page.click(createTestSelector(SettingsSelectors.ViewSecretKeyListItem));
await wallet.page.click(createTestSelector(SettingsSelectors.CopyKeyToClipboardBtn));
Expand All @@ -75,6 +80,7 @@ describe(`Settings integration tests`, () => {

it('should be able to sign out, lock and unlock the extension', async () => {
const secretKey = await wallet.getSecretKey();
await wallet.waitForSettingsButton();
await wallet.clickSettingsButton();
await wallet.page.click(createTestSelector(SettingsSelectors.SignOutListItem));
await wallet.page.click(wallet.$signOutConfirmHasBackupCheckbox);
Expand All @@ -84,6 +90,7 @@ describe(`Settings integration tests`, () => {
const password = randomString(15);
await wallet.enterNewPassword(password);
await wallet.enterConfirmPasswordAndClickDone(password);
await wallet.waitForSettingsButton();
await wallet.clickSettingsButton();
await wallet.page.click(createTestSelector(SettingsSelectors.LockListItem));
await wallet.enterPasswordAndUnlockWallet(password);
Expand All @@ -94,6 +101,7 @@ describe(`Settings integration tests`, () => {
});

it('should be able to change network', async () => {
await wallet.waitForSettingsButton();
await wallet.clickSettingsButton();
const currentNetwork = await wallet.page.textContent(
createTestSelector(SettingsSelectors.CurrentNetwork)
Expand Down
4 changes: 4 additions & 0 deletions tests/page-objects/wallet.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ export class WalletPage {
await this.page.click(this.$hideStepsBtn);
}

async waitForSettingsButton() {
await this.page.waitForSelector(this.$settingsButton, { timeout: 30000 });
}

async waitForHomePage() {
await this.page.waitForSelector(this.$homePageBalancesList, { timeout: 30000 });
}
Expand Down

0 comments on commit 228e9b7

Please sign in to comment.