Skip to content

Commit

Permalink
refactor: move steps to feature
Browse files Browse the repository at this point in the history
  • Loading branch information
fbwoolf committed May 31, 2022
1 parent 00d22f5 commit 52b0c30
Show file tree
Hide file tree
Showing 24 changed files with 559 additions and 427 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { useCallback } from 'react';
import { useNavigate } from 'react-router-dom';

import { useAnalytics } from '@app/common/hooks/analytics/use-analytics';
import { useSuggestedFirstStepsStatus } from '@app/store/onboarding/onboarding.selectors';
import AddFundsFull from '@assets/images/onboarding/steps/add-funds-light.png';
import AddFundsFullDone from '@assets/images/onboarding/steps/add-funds-light-done.png';
import AddFundsPopup from '@assets/images/onboarding/steps/add-funds-light-sm.png';
import AddFundsPopupDone from '@assets/images/onboarding/steps/add-funds-light-done-sm.png';
import { SuggestedFirstSteps, SuggestedFirstStepStatus } from '@shared/models/onboarding-types';
import { RouteUrls } from '@shared/route-urls';

import { SuggestedFirstStep } from './suggested-first-step';

export function AddFundsStep() {
const analytics = useAnalytics();
const navigate = useNavigate();
const suggestedFirstStepsStatus = useSuggestedFirstStepsStatus();

const onSelectStep = useCallback(() => {
void analytics.track('select_next_step', { step: SuggestedFirstSteps.AddFunds });
navigate(RouteUrls.Fund);
}, [analytics, navigate]);

return (
<SuggestedFirstStep
action="Get STX"
body="Get some STX so you can start using apps"
imageFull={AddFundsFull}
imageFullDone={AddFundsFullDone}
imagePopup={AddFundsPopup}
imagePopupDone={AddFundsPopupDone}
isDone={
suggestedFirstStepsStatus[SuggestedFirstSteps.AddFunds] === SuggestedFirstStepStatus.Done
}
key={SuggestedFirstSteps.AddFunds}
onClick={onSelectStep}
title="Add funds"
/>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useCallback } from 'react';
import { useNavigate } from 'react-router-dom';

import { useAnalytics } from '@app/common/hooks/analytics/use-analytics';
import { useSuggestedFirstStepsStatus } from '@app/store/onboarding/onboarding.selectors';
import BackUpSecretKeyFull from '@assets/images/onboarding/steps/backup-key-light.png';
import BackUpSecretKeyFullDone from '@assets/images/onboarding/steps/backup-key-light-done.png';
import BackUpSecretKeyPopup from '@assets/images/onboarding/steps/backup-key-light-sm.png';
import BackUpSecretKeyPopupDone from '@assets/images/onboarding/steps/backup-key-light-done-sm.png';
import { SuggestedFirstSteps, SuggestedFirstStepStatus } from '@shared/models/onboarding-types';
import { RouteUrls } from '@shared/route-urls';

import { SuggestedFirstStep } from './suggested-first-step';

export function BackUpSecretKeyStep() {
const analytics = useAnalytics();
const navigate = useNavigate();
const suggestedFirstStepsStatus = useSuggestedFirstStepsStatus();

const onSelectStep = useCallback(() => {
void analytics.track('select_next_step', { step: SuggestedFirstSteps.BackUpSecretKey });
navigate(RouteUrls.ViewSecretKey);
}, [analytics, navigate]);

return (
<SuggestedFirstStep
action="View secret key"
body="Don't lose access to your account and crypto"
imageFull={BackUpSecretKeyFull}
imageFullDone={BackUpSecretKeyFullDone}
imagePopup={BackUpSecretKeyPopup}
imagePopupDone={BackUpSecretKeyPopupDone}
isDone={
suggestedFirstStepsStatus[SuggestedFirstSteps.BackUpSecretKey] ===
SuggestedFirstStepStatus.Done
}
key={SuggestedFirstSteps.BackUpSecretKey}
onClick={onSelectStep}
title="Back up secret key"
/>
);
}
42 changes: 42 additions & 0 deletions src/app/features/suggested-first-steps/components/buy-nft-step.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useCallback } from 'react';

import { useAnalytics } from '@app/common/hooks/analytics/use-analytics';
import { openInNewTab } from '@app/common/utils/open-in-new-tab';
import { useSuggestedFirstStepsStatus } from '@app/store/onboarding/onboarding.selectors';
import BuyNftFull from '@assets/images/onboarding/steps/buy-nft-light.png';
import BuyNftFullDone from '@assets/images/onboarding/steps/buy-nft-light-done.png';
import BuyNftPopup from '@assets/images/onboarding/steps/buy-nft-light-sm.png';
import BuyNftPopupDone from '@assets/images/onboarding/steps/buy-nft-light-done-sm.png';
import { SuggestedFirstSteps, SuggestedFirstStepStatus } from '@shared/models/onboarding-types';

import { SuggestedFirstStep } from './suggested-first-step';

const buyNftExternalRoute = 'https://www.hiro.so/wallet-faq/nfts';

export function BuyNftStep() {
const analytics = useAnalytics();
const suggestedFirstStepsStatus = useSuggestedFirstStepsStatus();

const onSelectStep = useCallback(() => {
void analytics.track('select_next_step', { step: SuggestedFirstSteps.BuyNft });
openInNewTab(buyNftExternalRoute);
}, [analytics]);

return (
<SuggestedFirstStep
action="Find NFT"
body="Collect and trade NFTs secured by Bitcoin"
imageFull={BuyNftFull}
imageFullDone={BuyNftFullDone}
imagePopup={BuyNftPopup}
imagePopupDone={BuyNftPopupDone}
isDone={
suggestedFirstStepsStatus[SuggestedFirstSteps.BuyNft] === SuggestedFirstStepStatus.Done
}
isExternalRoute
key={SuggestedFirstSteps.BuyNft}
onClick={onSelectStep}
title="Buy an NFT"
/>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { useCallback } from 'react';

import { useAnalytics } from '@app/common/hooks/analytics/use-analytics';
import { openInNewTab } from '@app/common/utils/open-in-new-tab';
import { useAppDispatch } from '@app/store';
import { useSuggestedFirstStepsStatus } from '@app/store/onboarding/onboarding.selectors';
import ExploreAppsFull from '@assets/images/onboarding/steps/explore-apps-light.png';
import ExploreAppsFullDone from '@assets/images/onboarding/steps/explore-apps-light-done.png';
import ExploreAppsPopup from '@assets/images/onboarding/steps/explore-apps-light-sm.png';
import ExploreAppsPopupDone from '@assets/images/onboarding/steps/explore-apps-light-done-sm.png';
import { SuggestedFirstSteps, SuggestedFirstStepStatus } from '@shared/models/onboarding-types';

import { SuggestedFirstStep } from './suggested-first-step';
import { onboardingActions } from '@app/store/onboarding/onboarding.actions';

const exploreAppsExternalRoute = 'https://www.stacks.co/explore/discover-apps#apps';

export function ExploreAppsStep() {
const analytics = useAnalytics();
const dispatch = useAppDispatch();
const suggestedFirstStepsStatus = useSuggestedFirstStepsStatus();

const onSelectStep = useCallback(() => {
void analytics.track('select_next_step', { step: SuggestedFirstSteps.ExploreApps });
dispatch(
onboardingActions.updateSuggestedFirstStepsStatus({
...suggestedFirstStepsStatus,
[SuggestedFirstSteps.ExploreApps]: SuggestedFirstStepStatus.Done,
})
);
openInNewTab(exploreAppsExternalRoute);
}, [analytics, dispatch, suggestedFirstStepsStatus]);

return (
<SuggestedFirstStep
action="Find apps"
body="Try Stacks apps for finance, NFTs, blogging and more"
imageFull={ExploreAppsFull}
imageFullDone={ExploreAppsFullDone}
imagePopup={ExploreAppsPopup}
imagePopupDone={ExploreAppsPopupDone}
isDone={
suggestedFirstStepsStatus[SuggestedFirstSteps.ExploreApps] === SuggestedFirstStepStatus.Done
}
isExternalRoute
key={SuggestedFirstSteps.ExploreApps}
onClick={onSelectStep}
title="Explore apps"
/>
);
}
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
import { FiCheck } from 'react-icons/fi';
import { Box, color, Stack } from '@stacks/ui';
import { color, Stack } from '@stacks/ui';

import { Caption } from '@app/components/typography';
import { OnboardingSelectors } from '@tests/integration/onboarding/onboarding.selectors';

export function StepDoneBadge() {
return (
<Box
<Stack
alignItems="center"
data-testid={OnboardingSelectors.StepItemDone}
border="2px solid"
borderColor={color('bg-4')}
borderRadius="25px"
color={color('text-caption')}
height="24px"
width="62px"
isInline
justifyContent="center"
maxWidth="62px"
paddingX="tight"
paddingY="extra-tight"
spacing="extra-tight"
>
<Stack
alignItems="center"
height="100%"
isInline
justifyContent="center"
spacing="extra-tight"
>
<FiCheck />
<Caption fontWeight={400} variant="c2">
Done
</Caption>
</Stack>
</Box>
<FiCheck />
<Caption fontWeight={400} variant="c2">
Done
</Caption>
</Stack>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { FiArrowRight } from 'react-icons/fi';
import { Box, color, Flex, Stack } from '@stacks/ui';

import { Tooltip } from '@app/components/tooltip';
import { Body, Text, Title } from '@app/components/typography';
import { Link } from '@app/components/link';
import { OnboardingSelectors } from '@tests/integration/onboarding/onboarding.selectors';

import { StepDoneBadge } from './step-done-badge';
import { externalLinkInfo, StepIllustration } from './suggested-first-step';

interface StepFullPageProps {
action: string;
body: string;
imageFull: string;
imageFullDone: string;
isDone: boolean;
isExternalRoute?: boolean;
onClick(): void;
title: string;
}
export function StepFullPage(props: StepFullPageProps) {
const { action, body, imageFull, imageFullDone, isDone, isExternalRoute, onClick, title } = props;

return (
<Stack
border={['1px solid', 'unset']}
borderColor={color('border')}
borderRadius={['10px', 'unset']}
flexGrow={1}
pl={['base', 'unset']}
pr="base"
py={['base', 'unset']}
spacing="base"
>
<Box height={['46px', '100px']} width={['55px', '132px']}>
<StepIllustration image={isDone ? imageFullDone : imageFull} />
</Box>
<Flex alignItems={['center', 'unset']} flexDirection={['unset', 'column']}>
<Title
color={isDone ? color('text-caption') : color('text-title')}
fontSize={[1, 2]}
lineHeight="24px"
mr="extra-tight"
>
{title}
</Title>
<Body display={['none', 'block']} mt="tight">
{body}
</Body>
</Flex>
{isDone ? (
<StepDoneBadge />
) : (
<Link
data-testid={OnboardingSelectors.StepItemStart}
_hover={{ textDecoration: 'none' }}
fontSize="14px"
mr="4px !important"
onClick={onClick}
>
<Flex alignItems="center">
<Tooltip
disabled={!isExternalRoute}
label={externalLinkInfo}
maxWidth="250px"
placement="top"
>
<Flex alignItems="center">
<Text color={color('accent')} fontWeight={500} mr="extra-tight">
{action}
</Text>
{isExternalRoute ? <Box as={FiArrowRight} transform="rotate(-45deg)" /> : null}
</Flex>
</Tooltip>
</Flex>
</Link>
)}
</Stack>
);
}
60 changes: 60 additions & 0 deletions src/app/features/suggested-first-steps/components/step-popup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { FiArrowRight } from 'react-icons/fi';
import { Box, color, Flex, Stack } from '@stacks/ui';

import { Tooltip } from '@app/components/tooltip';
import { Body, Title } from '@app/components/typography';

import { externalLinkInfo, StepIllustration } from './suggested-first-step';

interface StepPopupProps {
body: string;
imagePopup: string;
imagePopupDone: string;
isDone: boolean;
isExternalRoute?: boolean;
onClick(): void;
title: string;
}
export function StepPopup(props: StepPopupProps) {
const { body, imagePopup, imagePopupDone, isDone, isExternalRoute, onClick, title } = props;

return (
<Stack
_hover={{ cursor: !isDone ? 'pointer' : 'unset' }}
border={['1px solid', 'unset']}
borderColor={color('border')}
borderRadius={['10px', 'unset']}
flexGrow={1}
onClick={!isDone ? onClick : undefined}
pl={['base', 'unset']}
pr="base"
py={['base', 'unset']}
spacing="base"
>
<Box height={['46px', '100px']} width={['55px', '132px']}>
<StepIllustration image={isDone ? imagePopupDone : imagePopup} />
</Box>
<Tooltip
disabled={isDone || !isExternalRoute}
label={externalLinkInfo}
maxWidth="250px"
placement="top"
>
<Flex alignItems={['center', 'unset']} flexDirection={['unset', 'column']}>
<Title
color={isDone ? color('text-caption') : color('text-title')}
fontSize={[1, 2]}
lineHeight="24px"
mr="extra-tight"
>
{title}
</Title>
{isExternalRoute ? <Box as={FiArrowRight} transform={'rotate(-45deg)'} /> : null}
<Body display={['none', 'block']} mt="tight">
{body}
</Body>
</Flex>
</Tooltip>
</Stack>
);
}
Loading

0 comments on commit 52b0c30

Please sign in to comment.