mirror of
https://github.com/RoboSats/robosats.git
synced 2025-08-11 01:40:28 +00:00
304 lines
10 KiB
TypeScript
304 lines
10 KiB
TypeScript
import React, { useContext, useState } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import {
|
|
Alert,
|
|
Box,
|
|
Button,
|
|
ButtonGroup,
|
|
Collapse,
|
|
Grid,
|
|
LinearProgress,
|
|
Link,
|
|
Typography,
|
|
Accordion,
|
|
AccordionSummary,
|
|
AccordionDetails,
|
|
} from '@mui/material';
|
|
import { type Robot } from '../../models';
|
|
import { Casino, Bolt, Check, Storefront, AddBox, School } from '@mui/icons-material';
|
|
import RobotAvatar from '../../components/RobotAvatar';
|
|
import TokenInput from './TokenInput';
|
|
import { genBase62Token } from '../../utils';
|
|
import { NewTabIcon } from '../../components/Icons';
|
|
import { AppContext, type UseAppStoreType } from '../../contexts/AppContext';
|
|
import { GarageContext, type UseGarageStoreType } from '../../contexts/GarageContext';
|
|
import { type UseFederationStoreType, FederationContext } from '../../contexts/FederationContext';
|
|
|
|
interface OnboardingProps {
|
|
setView: (state: 'welcome' | 'onboarding' | 'profile') => void;
|
|
robot: Robot;
|
|
setRobot: (state: Robot) => void;
|
|
inputToken: string;
|
|
setInputToken: (state: string) => void;
|
|
baseUrl: string;
|
|
}
|
|
|
|
const Onboarding = ({ setView, inputToken, setInputToken }: OnboardingProps): React.JSX.Element => {
|
|
const { t } = useTranslation();
|
|
const navigate = useNavigate();
|
|
|
|
const { navigateToPage } = useContext<UseAppStoreType>(AppContext);
|
|
const { garage } = useContext<UseGarageStoreType>(GarageContext);
|
|
const { federation } = useContext<UseFederationStoreType>(FederationContext);
|
|
|
|
const [step, setStep] = useState<'1' | '2' | '3'>('1');
|
|
const [generatedToken, setGeneratedToken] = useState<boolean>(false);
|
|
const [loading, setLoading] = useState<boolean>(false);
|
|
|
|
const generateToken = (): void => {
|
|
setGeneratedToken(true);
|
|
setInputToken(genBase62Token(36));
|
|
setLoading(true);
|
|
setTimeout(() => {
|
|
setLoading(false);
|
|
}, 1000);
|
|
};
|
|
|
|
const slot = garage.getSlot();
|
|
|
|
return (
|
|
<Box>
|
|
<Accordion expanded={step === '1'} disableGutters={true}>
|
|
<AccordionSummary>
|
|
<Typography variant='h5' color={step === '1' ? 'text.primary' : 'text.disabled'}>
|
|
{t('1. Generate a token')}
|
|
</Typography>
|
|
</AccordionSummary>
|
|
<AccordionDetails>
|
|
<Grid container direction='column' alignItems='center' spacing={1} padding={1}>
|
|
<Grid item>
|
|
<Typography>
|
|
{t(
|
|
'This temporary key gives you access to a unique and private robot identity for your trade.',
|
|
)}
|
|
</Typography>
|
|
</Grid>
|
|
{!generatedToken ? (
|
|
<Grid item>
|
|
<Button autoFocus onClick={generateToken} variant='contained' size='large'>
|
|
<Casino />
|
|
{t('Generate token')}
|
|
</Button>
|
|
</Grid>
|
|
) : (
|
|
<Grid item>
|
|
<Collapse in={generatedToken}>
|
|
<Grid container direction='column' alignItems='center' spacing={1}>
|
|
<Grid item>
|
|
<Alert variant='outlined' severity='info'>
|
|
<b>{`${t('Store it somewhere safe!')} `}</b>
|
|
{t(
|
|
`This token is the one and only key to your robot, you will need it later to recover your order. Keep it secret, sharing it could put your funds at risk.`,
|
|
)}
|
|
</Alert>
|
|
</Grid>
|
|
<Grid item sx={{ width: '100%' }}>
|
|
<TokenInput
|
|
loading={loading}
|
|
autoFocusTarget='copyButton'
|
|
inputToken={inputToken}
|
|
setInputToken={setInputToken}
|
|
onPressEnter={() => null}
|
|
/>
|
|
</Grid>
|
|
<Grid item>
|
|
<Typography>
|
|
{t('You can also add your own random characters into the token or')}
|
|
<Button size='small' onClick={generateToken}>
|
|
<Casino />
|
|
{t('roll again')}
|
|
</Button>
|
|
</Typography>
|
|
</Grid>
|
|
|
|
<Grid item>
|
|
<Button
|
|
onClick={() => {
|
|
setStep('2');
|
|
void garage.createRobot(federation, inputToken);
|
|
}}
|
|
disabled={loading}
|
|
variant='contained'
|
|
size='large'
|
|
>
|
|
<Check />
|
|
{t('Continue')}
|
|
</Button>
|
|
</Grid>
|
|
</Grid>
|
|
</Collapse>
|
|
</Grid>
|
|
)}
|
|
</Grid>
|
|
</AccordionDetails>
|
|
</Accordion>
|
|
|
|
<Accordion expanded={step === '2'} disableGutters={true}>
|
|
<AccordionSummary>
|
|
<Typography variant='h5' color={step === '2' ? 'text.primary' : 'text.disabled'}>
|
|
{t('2. Meet your robot identity')}
|
|
</Typography>
|
|
</AccordionSummary>
|
|
<AccordionDetails>
|
|
<Grid container direction='column' alignItems='center' spacing={1}>
|
|
<Grid item>
|
|
<Typography>
|
|
{slot?.hashId ? (
|
|
t('This is your trading avatar')
|
|
) : (
|
|
<>
|
|
<b>{t('Building your robot!')}</b>
|
|
<LinearProgress />
|
|
</>
|
|
)}
|
|
</Typography>
|
|
</Grid>
|
|
|
|
<Grid item sx={{ width: '13.5em' }}>
|
|
<RobotAvatar
|
|
hashId={slot?.hashId ?? ''}
|
|
smooth={true}
|
|
style={{ maxWidth: '12.5em', maxHeight: '12.5em' }}
|
|
placeholderType='generating'
|
|
imageStyle={{
|
|
transform: '',
|
|
border: '2px solid #555',
|
|
filter: 'drop-shadow(1px 1px 1px #000000)',
|
|
height: '12.4em',
|
|
width: '12.4em',
|
|
}}
|
|
tooltipPosition='top'
|
|
/>
|
|
</Grid>
|
|
|
|
{slot?.nickname ? (
|
|
<Grid item>
|
|
<Typography align='center'>{t('Hi! My name is')}</Typography>
|
|
<Typography component='h5' variant='h5'>
|
|
<div
|
|
style={{
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
flexWrap: 'wrap',
|
|
}}
|
|
>
|
|
<Bolt
|
|
sx={{
|
|
color: '#fcba03',
|
|
height: '1.5em',
|
|
width: '1.5em',
|
|
}}
|
|
/>
|
|
<b>{slot?.nickname}</b>
|
|
<Bolt
|
|
sx={{
|
|
color: '#fcba03',
|
|
height: '1.5em',
|
|
width: '1.5em',
|
|
}}
|
|
/>
|
|
</div>
|
|
</Typography>
|
|
</Grid>
|
|
) : null}
|
|
<Grid item>
|
|
<Collapse in={!!slot?.hashId}>
|
|
<Button
|
|
onClick={() => {
|
|
setStep('3');
|
|
}}
|
|
variant='contained'
|
|
size='large'
|
|
>
|
|
<Check />
|
|
{t('Continue')}
|
|
</Button>
|
|
</Collapse>
|
|
</Grid>
|
|
</Grid>
|
|
</AccordionDetails>
|
|
</Accordion>
|
|
|
|
<Accordion expanded={step === '3'} disableGutters={true}>
|
|
<AccordionSummary>
|
|
<Typography variant='h5' color={step === '3' ? 'text.primary' : 'text.disabled'}>
|
|
{t('3. Browse or create an order')}
|
|
</Typography>
|
|
</AccordionSummary>
|
|
<AccordionDetails>
|
|
<Grid container direction='column' alignItems='center' spacing={1} padding={1.5}>
|
|
<Grid item>
|
|
<Typography>
|
|
{t(
|
|
'RoboSats is a peer-to-peer marketplace. You can browse the public offers or create a new one.',
|
|
)}
|
|
</Typography>
|
|
</Grid>
|
|
|
|
<Grid item>
|
|
<ButtonGroup variant='contained'>
|
|
<Button
|
|
color='primary'
|
|
onClick={() => {
|
|
navigateToPage('offers', navigate);
|
|
}}
|
|
>
|
|
<Storefront /> <div style={{ width: '0.5em' }} />
|
|
{t('Offers')}
|
|
</Button>
|
|
<Button
|
|
color='secondary'
|
|
onClick={() => {
|
|
navigateToPage('create', navigate);
|
|
}}
|
|
>
|
|
<AddBox /> <div style={{ width: '0.5em' }} />
|
|
{t('Create')}
|
|
</Button>
|
|
</ButtonGroup>
|
|
</Grid>
|
|
|
|
<Grid item>
|
|
<Typography>
|
|
{`${t('If you need help on your RoboSats journey join our public support')} `}
|
|
<Link target='_blank' href='https://t.me/robosats_es' rel='noreferrer'>
|
|
{t('Telegram group')}
|
|
</Link>
|
|
{`, ${t('or visit the robot school for documentation.')} `}
|
|
</Typography>
|
|
</Grid>
|
|
<Grid item>
|
|
<Button
|
|
component={Link}
|
|
href='https://learn.robosats.org'
|
|
target='_blank'
|
|
color='inherit'
|
|
variant='contained'
|
|
>
|
|
<School /> <div style={{ width: '0.5em' }} />
|
|
{t('Learn RoboSats')}
|
|
<div style={{ width: '0.5em' }} />
|
|
<NewTabIcon sx={{ width: '0.8em' }} />
|
|
</Button>
|
|
</Grid>
|
|
<Grid item sx={{ position: 'relative', top: '0.6em' }}>
|
|
<Button
|
|
color='inherit'
|
|
onClick={() => {
|
|
setView('profile');
|
|
}}
|
|
>
|
|
{t('See profile')}
|
|
</Button>
|
|
</Grid>
|
|
</Grid>
|
|
</AccordionDetails>
|
|
</Accordion>
|
|
</Box>
|
|
);
|
|
};
|
|
|
|
export default Onboarding;
|