Files
donetick/src/views/Onboarding/GetStartedView.jsx
Mohamad Tarbin d641710a41 Reshape onboarding v1.3 (#185)
* Initialize Onboarding Flow

* Shorten Onboarding

* Add Setup circle  and what are the current way to add tasks to the onboarding.
update donetick logo

* improve wording

* Skip onboarding flow for now

* Enable onboarding flow
2026-08-02 20:53:28 -04:00

176 lines
4.9 KiB
JavaScript

import { DnsOutlined } from '@mui/icons-material'
import { Box, Button, Link, Typography } from '@mui/joy'
import { useNavigate } from 'react-router-dom'
import Logo from '../../Logo'
import { useResource } from '../../queries/ResourceQueries'
import { haptic, isNativeApp, markOnboardingSeen } from '../../utils/Onboarding'
import { LegalLinks } from '../Authorization/AuthFields'
import { authButtonSx } from '../Authorization/authStyles'
const EASE = 'cubic-bezier(0.22, 1, 0.36, 1)'
const enter = (delay = 0) => ({
animation: `getStartedIn 520ms ${EASE} ${delay}ms both`,
'@keyframes getStartedIn': {
from: { opacity: 0, transform: 'translateY(12px)' },
to: { opacity: 1, transform: 'none' },
},
'@media (prefers-reduced-motion: reduce)': { animation: 'none' },
})
/**
* The fork at the end of onboarding: create an account or sign in. Kept
* deliberately thin — one decision, no form — so the actual auth screens stay
* the only place credentials are handled.
*/
const GetStartedView = () => {
const navigate = useNavigate()
const { data: resource } = useResource()
const signupDisabled = Boolean(resource?.is_user_creation_disabled)
const go = path => {
// Reaching this screen means onboarding is done, even if the user came
// here from a deep link rather than the carousel.
markOnboardingSeen()
haptic()
navigate(path)
}
return (
<Box
component='main'
sx={{
minHeight: 'calc(100dvh - var(--safe-area-inset-top, 0px))',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
px: 3,
pb: 3,
bgcolor: 'background.body',
}}
>
<Box
sx={{
width: '100%',
maxWidth: 420,
my: 'auto',
display: 'flex',
flexDirection: 'column',
}}
>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
textAlign: 'center',
gap: 1.5,
mb: 4,
...enter(0),
}}
>
<Box
sx={{
position: 'relative',
display: 'grid',
placeItems: 'center',
// Same primary wash the onboarding vignettes sit on.
'&::before': {
content: '""',
position: 'absolute',
width: 190,
height: 190,
borderRadius: '50%',
bgcolor: 'primary.softBg',
opacity: 0.6,
filter: 'blur(30px)',
},
'& > *': { position: 'relative' },
}}
>
<Logo size='96px' />
</Box>
<Typography
level='h1'
sx={{
fontSize: '2rem',
fontWeight: 700,
letterSpacing: '-0.02em',
textWrap: 'balance',
}}
>
Done
<Box component='span' sx={{ color: 'primary.500' }}>
tick
</Box>
</Typography>
<Typography
level='body-md'
sx={{
color: 'text.secondary',
maxWidth: '30ch',
textWrap: 'pretty',
}}
>
{signupDisabled
? 'Sign in to your account to pick up where you left off.'
: 'Create an account to sync everywhere, or sign in and pick up where you left off.'}
</Typography>
</Box>
<Box
sx={{
display: 'flex',
flexDirection: 'column',
gap: 1.5,
...enter(90),
}}
>
{!signupDisabled && (
<Button
size='lg'
fullWidth
onClick={() => go('/signup')}
sx={authButtonSx}
>
Create an account
</Button>
)}
<Button
size='lg'
fullWidth
variant={signupDisabled ? 'solid' : 'outlined'}
color={signupDisabled ? 'primary' : 'neutral'}
onClick={() => go('/login')}
sx={authButtonSx}
>
{signupDisabled ? 'Sign in' : 'I already have an account'}
</Button>
</Box>
{isNativeApp() && (
<Box sx={{ mt: 2.5, textAlign: 'center', ...enter(160) }}>
<Link
component='button'
type='button'
level='body-sm'
color='neutral'
underline='hover'
startDecorator={<DnsOutlined fontSize='small' />}
onClick={() => navigate('/login/settings')}
>
Connect to a self-hosted server
</Link>
</Box>
)}
</Box>
<Box sx={{ width: '100%', maxWidth: 420, ...enter(220) }}>
<LegalLinks />
</Box>
</Box>
)
}
export default GetStartedView