Browse Source

Skeleton for the new onboarding

master
meriadec 7 years ago
committed by NastiaS
parent
commit
9b1e24c9ad
  1. 32
      src/components/Onboarding/OnboardingBreadcrumb.js
  2. 118
      src/components/Onboarding/index.js
  3. 18
      src/components/Onboarding/steps/Init.js
  4. 17
      src/components/Onboarding/steps/UserChoice.js
  5. 4
      src/reducers/index.js
  6. 84
      src/reducers/onboarding.js

32
src/components/Onboarding/OnboardingBreadcrumb.js

@ -0,0 +1,32 @@
// @flow
import React from 'react'
import { connect } from 'react-redux'
import findIndex from 'lodash/findIndex'
import type { OnboardingState } from 'reducers/onboarding'
import Breadcrumb from 'components/Breadcrumb'
const mapStateToProps = state => ({
onboarding: state.onboarding,
})
type Props = {
onboarding: OnboardingState,
}
function OnboardingBreadcrumb(props: Props) {
const { onboarding } = props
const { stepName } = onboarding
const filteredSteps = onboarding.steps
.filter(step => !step.external)
.map(step => ({ ...step, label: step.label })) // TODO: translate
const stepIndex = findIndex(filteredSteps, s => s.name === stepName)
return <Breadcrumb currentStep={stepIndex} items={filteredSteps} />
}
export default connect(mapStateToProps)(OnboardingBreadcrumb)

118
src/components/Onboarding/index.js

@ -7,108 +7,83 @@ import { connect } from 'react-redux'
import styled from 'styled-components'
import type { T } from 'types/common'
import type { OnboardingState } from 'reducers/onboarding'
import { saveSettings } from 'actions/settings'
import { nextStep, prevStep, jumpStep } from 'reducers/onboarding'
import Box from 'components/base/Box'
import Button from 'components/base/Button'
const STEPS = [
{
title: ({ t }) => t('onboarding:step1.title'),
render: ({ t }: StepProps) => <Box>{t('onboarding:step1.greetings')}</Box>,
},
{
title: ({ t }) => t('onboarding:step2.title'),
render: ({ t }: StepProps) => <Box>{t('onboarding:step2.greetings')}</Box>,
},
{
title: ({ t }) => t('onboarding:step3.title'),
render: ({ t }: StepProps) => (
<Box>
{t('onboarding:step3.greetings')}
<Box bg="grey" align="center" justify="center" style={{ width: 200, height: 200 }}>
{'step 3 image'}
</Box>
{t('onboarding:step3.description')}
</Box>
),
},
{
title: ({ t }) => t('onboarding:step4.title'),
render: ({ t }: StepProps) => <Box>{t('onboarding:step4.greetings')}</Box>,
},
]
import OnboardingBreadcrumb from './OnboardingBreadcrumb'
import InitStep from './steps/Init'
import UserChoice from './steps/UserChoice'
const STEPS = {
init: InitStep,
userChoice: UserChoice,
}
const mapStateToProps = state => ({
hasCompletedOnboarding: state.settings.hasCompletedOnboarding,
onboarding: state.onboarding,
})
const mapDispatchToProps = {
saveSettings,
nextStep,
prevStep,
jumpStep,
}
type Props = {
t: T,
hasCompletedOnboarding: boolean,
saveSettings: Function,
onboarding: OnboardingState,
prevStep: Function,
nextStep: Function,
jumpStep: Function,
}
type StepProps = {
export type StepProps = {
t: T,
prevStep: Function,
nextStep: Function,
jumpStep: Function,
finish: Function,
}
type State = {
stepIndex: number,
}
class Onboarding extends PureComponent<Props, State> {
state = {
stepIndex: 0,
}
prev = () => this.setState({ stepIndex: Math.max(0, this.state.stepIndex - 1) })
next = () => this.setState({ stepIndex: Math.min(STEPS.length - 1, this.state.stepIndex + 1) })
class Onboarding extends PureComponent<Props> {
finish = () => this.props.saveSettings({ hasCompletedOnboarding: true })
render() {
const { hasCompletedOnboarding, t } = this.props
const { stepIndex } = this.state
const { hasCompletedOnboarding, onboarding, prevStep, nextStep, jumpStep, t } = this.props
if (hasCompletedOnboarding) {
return null
}
const step = STEPS[stepIndex]
const StepComponent = STEPS[onboarding.stepName]
const step = onboarding.steps[onboarding.stepIndex]
if (!step) {
if (!StepComponent || !step) {
console.warn(`You reached an impossible onboarding step.`) // eslint-disable-line
return null
}
const stepProps = {
const stepProps: StepProps = {
t,
onboarding,
prevStep,
nextStep,
jumpStep,
finish: this.finish,
}
return (
<Container>
<Inner>
<Box horizontal flow={2}>
<Button primary onClick={this.prev}>
{'prev step'}
</Button>
{stepIndex === STEPS.length - 1 ? (
<Button danger onClick={this.finish}>
{'finish'}
</Button>
) : (
<Button primary onClick={this.next}>
{'next step'}
</Button>
)}
</Box>
<StepTitle>{step.title(stepProps)}</StepTitle>
{step.render(stepProps)}
</Inner>
{step.options.showBreadcrumb && <OnboardingBreadcrumb />}
<StepComponent {...stepProps} />
</Container>
)
}
@ -116,9 +91,6 @@ class Onboarding extends PureComponent<Props, State> {
const Container = styled(Box).attrs({
bg: 'white',
p: 6,
align: 'center',
justify: 'center',
})`
position: fixed;
top: 0;
@ -128,18 +100,4 @@ const Container = styled(Box).attrs({
z-index: 100;
`
const Inner = styled(Box).attrs({
bg: 'lightGraphite',
p: 4,
})`
border: 1px solid rgba(0, 0, 0, 0.1);
height: 400px;
width: 400px;
border-radius: 3px;
`
const StepTitle = styled(Box).attrs({
fontSize: 8,
})``
export default compose(connect(mapStateToProps, mapDispatchToProps), translate())(Onboarding)

18
src/components/Onboarding/steps/Init.js

@ -0,0 +1,18 @@
// @flow
import React from 'react'
import Button from 'components/base/Button'
import Box from 'components/base/Box'
import type { StepProps } from '..'
export default (props: StepProps) => {
const { nextStep } = props
return (
<Box>
hey im step init
<Button onClick={() => nextStep()}>press me for going to prev</Button>
</Box>
)
}

17
src/components/Onboarding/steps/UserChoice.js

@ -0,0 +1,17 @@
// @flow
import React from 'react'
import Button from 'components/base/Button'
import type { StepProps } from '..'
export default (props: StepProps) => {
const { jumpStep } = props
return (
<div>
hey im step user choice
<Button onClick={() => jumpStep('init')}>press me for going to prev</Button>
</div>
)
}

4
src/reducers/index.js

@ -13,6 +13,7 @@ import devices from './devices'
import modals from './modals'
import settings from './settings'
import update from './update'
import onboarding from './onboarding'
import type { AccountsState } from './accounts'
import type { ApplicationState } from './application'
@ -20,6 +21,7 @@ import type { DevicesState } from './devices'
import type { ModalsState } from './modals'
import type { SettingsState } from './settings'
import type { UpdateState } from './update'
import type { OnboardingState } from './onboarding'
export type State = {
accounts: AccountsState,
@ -30,6 +32,7 @@ export type State = {
router: LocationShape,
settings: SettingsState,
update: UpdateState,
onboarding: OnboardingState,
}
export default combineReducers({
@ -41,4 +44,5 @@ export default combineReducers({
router,
settings,
update,
onboarding,
})

84
src/reducers/onboarding.js

@ -0,0 +1,84 @@
// @flow
import { handleActions, createAction } from 'redux-actions'
type Step = {
name: string,
external?: boolean,
label?: string,
options: {
showFooter: boolean,
showBackground: boolean,
showBreadcrumb: boolean,
},
}
export type OnboardingState = {
stepIndex: number,
stepName: string, // TODO: specify that the string comes from Steps type
steps: Step[],
}
const state: OnboardingState = {
stepIndex: 0,
stepName: 'init',
steps: [
{
name: 'init',
external: true,
options: {
showFooter: false,
showBackground: true,
showBreadcrumb: false,
},
},
{
name: 'userChoice',
label: 'something:translated',
options: {
showFooter: false,
showBackground: true,
showBreadcrumb: true,
},
},
],
}
const handlers = {
ONBOARDING_NEXT_STEP: state => {
const step = state.steps.find(step => step.name === state.stepName)
if (!step) {
return state
}
const index = state.steps.indexOf(step)
if (index > state.steps.length - 2) {
return state
}
return { ...state, stepName: state.steps[index + 1].name, stepIndex: index + 1 }
},
ONBOARDING_PREV_STEP: state => {
const step = state.steps.find(step => step.name === state.stepName)
if (!step) {
return state
}
const index = state.steps.indexOf(step)
if (index < 1) {
return state
}
return { ...state, stepName: state.steps[index - 1].name, stepIndex: index - 1 }
},
ONBOARDING_JUMP_STEP: (state, { payload: stepName }) => {
const step = state.steps.find(step => step.name === stepName)
if (!step) {
return state
}
const index = state.steps.indexOf(step)
return { ...state, stepName: step.name, stepIndex: index }
},
}
export default handleActions(handlers, state)
export const nextStep = createAction('ONBOARDING_NEXT_STEP')
export const prevStep = createAction('ONBOARDING_PREV_STEP')
export const jumpStep = createAction('ONBOARDING_JUMP_STEP')
Loading…
Cancel
Save