Skip to content

Commit

Permalink
Merge pull request #4085 from tloncorp/lb/onboarding-loader
Browse files Browse the repository at this point in the history
native: update signup waiting screen to reflect design
  • Loading branch information
latter-bolden authored Oct 18, 2024
2 parents 93bcc8d + ab1e639 commit c2969d1
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 43 deletions.
2 changes: 1 addition & 1 deletion apps/tlon-mobile/src/App.main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const App = () => {
<View flex={1} alignItems="center" justifyContent="center">
<LoadingSpinner />
</View>
) : isAuthenticated && !signupContext.isOngoing ? (
) : isAuthenticated && !signupContext.didBeginSignup ? (
<AuthenticatedApp />
) : (
<OnboardingStack />
Expand Down
106 changes: 92 additions & 14 deletions apps/tlon-mobile/src/screens/Onboarding/ReserveShipScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
import type { NativeStackScreenProps } from '@react-navigation/native-stack';
import { useLureMetadata } from '@tloncorp/app/contexts/branch';
import { useSignupContext } from '@tloncorp/app/contexts/signup';
import { BootPhaseExplanations } from '@tloncorp/app/lib/bootHelpers';
import { Spinner, Text, View, YStack } from '@tloncorp/ui';
import { useEffect } from 'react';
import { NodeBootPhase } from '@tloncorp/app/lib/bootHelpers';
import {
ArvosDiscussing,
IconType,
ListItem,
LoadingSpinner,
OnboardingTextBlock,
ScreenHeader,
View,
YStack,
} from '@tloncorp/ui';
import { useEffect, useMemo } from 'react';

import type { OnboardingStackParamList } from '../../types';

type Props = NativeStackScreenProps<OnboardingStackParamList, 'ReserveShip'>;

export const ReserveShipScreen = ({ navigation }: Props) => {
const signupContext = useSignupContext();
const lureMeta = useLureMetadata();

// Disable back button once you reach this screen
useEffect(
Expand All @@ -27,17 +38,84 @@ export const ReserveShipScreen = ({ navigation }: Props) => {
}, [signupContext]);

return (
<View flex={1} padding="$2xl" alignItems="center" justifyContent="center">
<YStack alignItems="center" gap="$xl">
<Spinner size="large" />
<Text textAlign="center" color="$primaryText">
Booting your new P2P node for the first time...
</Text>
{/* TOOD: add back in when design is ready */}
{/* <Text textAlign="center" color="$secondaryText" fontSize="$m">
{BootPhaseExplanations[signupContext.bootPhase]}
</Text> */}
</YStack>
<View flex={1} backgroundColor="$secondaryBackground">
<ScreenHeader
title={
signupContext.bootPhase < NodeBootPhase.READY
? "We're setting you up"
: 'Setup complete!'
}
showSessionStatus={false}
/>
<OnboardingTextBlock marginTop="$5xl" gap="$5xl">
<ArvosDiscussing width="100%" height={200} />
<BootStepDisplay
bootPhase={signupContext.bootPhase}
withInvites={Boolean(lureMeta)}
/>
</OnboardingTextBlock>
</View>
);
};

interface DisplayStep {
description: string;
icon: IconType;
startExclusive: NodeBootPhase;
endInclusive: NodeBootPhase;
}
function BootStepDisplay(props: {
bootPhase: NodeBootPhase;
withInvites: boolean;
}) {
const displaySteps = useMemo(() => {
const steps: DisplayStep[] = [
{
description: 'Unboxing your new peer',
icon: 'Gift',
startExclusive: NodeBootPhase.IDLE,
endInclusive: NodeBootPhase.BOOTING,
},
{
description: 'Connecting to the network',
icon: 'Link',
startExclusive: NodeBootPhase.BOOTING,
endInclusive: NodeBootPhase.CONNECTING,
},
];

if (props.withInvites) {
steps.push({
description: 'Finding peers on the network',
icon: 'ChannelGalleries',
startExclusive: NodeBootPhase.CONNECTING,
endInclusive: NodeBootPhase.ACCEPTING_INVITES,
});
}

return steps;
}, [props.withInvites]);

return (
<YStack width="100%">
{displaySteps.map((step, index) => {
const isOnStep =
props.bootPhase > step.startExclusive &&
props.bootPhase <= step.endInclusive;
const hasCompleted = props.bootPhase > step.endInclusive;
return (
<ListItem backgroundColor="unset" key={index} paddingVertical={0}>
<ListItem.SystemIcon color="$primaryText" icon={step.icon} />
<ListItem.MainContent>
<ListItem.Title>{step.description}</ListItem.Title>
</ListItem.MainContent>
<ListItem.EndContent width="$3xl" alignItems="center">
{isOnStep && <LoadingSpinner size="small" />}
{hasCompleted && <ListItem.SystemIcon icon="Checkmark" />}
</ListItem.EndContent>
</ListItem>
);
})}
</YStack>
);
}
42 changes: 25 additions & 17 deletions packages/app/contexts/signup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,23 +130,31 @@ export const SignupProvider = ({ children }: { children: React.ReactNode }) => {
values.didCompleteSignup &&
bootPhase === NodeBootPhase.READY
) {
logger.log('running post-signup actions');
const postSignupParams = {
nickname: values.nickname,
telemetry: values.telemetry,
notificationToken: values.notificationToken,
};
handlePostSignup(postSignupParams);
clear();
logger.trackEvent('hosted signup report', {
bootDuration: bootReport
? bootReport.completedAt - bootReport.startedAt
: null,
userSatWaitingFor: values.userWasReadyAt
? Date.now() - values.userWasReadyAt
: null,
timeUnit: 'ms',
});
try {
logger.log('running post-signup actions');
const postSignupParams = {
nickname: values.nickname,
telemetry: values.telemetry,
notificationToken: values.notificationToken,
};
handlePostSignup(postSignupParams);
logger.trackEvent('hosted signup report', {
bootDuration: bootReport
? bootReport.completedAt - bootReport.startedAt
: null,
userSatWaitingFor: values.userWasReadyAt
? Date.now() - values.userWasReadyAt
: null,
timeUnit: 'ms',
});
} catch (e) {
logger.trackError('post signup error', {
errorMessage: e.message,
errorStack: e.stack,
});
} finally {
setTimeout(() => clear(), 2000);
}
}
}, [values, bootPhase, clear, bootReport]);

Expand Down
4 changes: 2 additions & 2 deletions packages/app/hooks/useBootSequence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useCallback, useEffect, useRef, useState } from 'react';

import { useLureMetadata } from '../contexts/branch';
import { useShip } from '../contexts/ship';
import { NodeBootPhase } from '../lib/bootHelpers';
import { BootPhaseNames, NodeBootPhase } from '../lib/bootHelpers';
import BootHelpers from '../lib/bootHelpers';
import { getShipFromCookie } from '../utils/ship';
import { useConfigureUrbitClient } from './useConfigureUrbitClient';
Expand Down Expand Up @@ -264,7 +264,7 @@ export function useBootSequence({

lastRunPhaseRef.current = bootPhase;
lastRunErrored.current = false;
logger.log(`running boot sequence phase: ${bootPhase}`);
logger.log(`running boot sequence phase: ${BootPhaseNames[bootPhase]}`);

const nextBootPhase = await runBootPhase();
setBootPhase(nextBootPhase);
Expand Down
30 changes: 21 additions & 9 deletions packages/app/lib/bootHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ import { trackOnboardingAction } from '../utils/posthog';
import { getShipFromCookie, getShipUrl } from '../utils/ship';

export enum NodeBootPhase {
IDLE = 'idle',
RESERVING = 'reserving',
BOOTING = 'booting',
AUTHENTICATING = 'authenticating',
CONNECTING = 'connecting',
CHECKING_FOR_INVITE = 'checking-for-invite',
ACCEPTING_INVITES = 'accepting-invites',
READY = 'ready',
ERROR = 'error',
IDLE = 1,
RESERVING = 2,
BOOTING = 3,
AUTHENTICATING = 4,
CONNECTING = 5,
CHECKING_FOR_INVITE = 6,
ACCEPTING_INVITES = 7,
READY = 200,
ERROR = 400,
}

export const BootPhaseExplanations: Record<NodeBootPhase, string> = {
Expand All @@ -31,6 +31,18 @@ export const BootPhaseExplanations: Record<NodeBootPhase, string> = {
[NodeBootPhase.ERROR]: 'Your node errored while initializing',
};

export const BootPhaseNames: Record<NodeBootPhase, string> = {
[NodeBootPhase.IDLE]: 'Idle',
[NodeBootPhase.RESERVING]: 'Reserving',
[NodeBootPhase.BOOTING]: 'Booting',
[NodeBootPhase.AUTHENTICATING]: 'Authenticating',
[NodeBootPhase.CONNECTING]: 'Connecting',
[NodeBootPhase.CHECKING_FOR_INVITE]: 'Checking for Invites',
[NodeBootPhase.ACCEPTING_INVITES]: 'Accepting Invites',
[NodeBootPhase.READY]: 'Ready',
[NodeBootPhase.ERROR]: 'Error',
};

export default {
NodeBootPhase,
reserveNode,
Expand Down
1 change: 1 addition & 0 deletions packages/ui/src/assets/arvos_discussing.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions packages/ui/src/components/ArvosDiscussing.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { styled } from 'tamagui';

import ArvosDiscussingSvg from '../assets/arvos_discussing.svg';

export const ArvosDiscussing = styled(
ArvosDiscussingSvg,
{
color: '$primaryText',
},
{
accept: {
color: 'color',
width: 'size',
height: 'size',
},
}
);
1 change: 1 addition & 0 deletions packages/ui/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export * from './components/UserProfileScreenView';
export * from './components/View';
export * from './components/WelcomeSheet';
export * from './components/Image';
export * from './components/ArvosDiscussing';
export * as Form from './components/Form';
export * from './contexts';
export * from './tamagui.config';
Expand Down

0 comments on commit c2969d1

Please sign in to comment.