Add navigation ability to wizard buttons, close wizard on final

Co-authored-by: Daniel Campbell <metalwhirlwind@gmail.com>
Co-authored-by: Deniz Kusefoglu <deniz@influxdata.com>
generic-wizard
Daniel Campbell 2018-07-19 15:46:17 -07:00
parent d14a9f4dac
commit 0e22181190
5 changed files with 133 additions and 23 deletions

View File

@ -1,11 +1,14 @@
import React, {PureComponent, ReactElement, ReactNode} from 'react'
import WizardProgressBar from 'src/reusable_ui/components/wizard/WizardProgressBar'
import WizardStep from 'src/reusable_ui/components/wizard/WizardStep'
interface WizardStepProps {
children: ReactNode
title: string
isComplete: () => boolean
onPrevious: () => void
onNext: () => void
increment?: () => void
decrement?: () => void
}
enum StepStatus {
@ -25,12 +28,13 @@ interface State {
}
interface Props {
children: ReactElement<WizardStep>
children: Array<ReactElement<WizardStepProps>>
toggleVisibility: (isVisible: boolean) => () => void
}
class WizardCloak extends PureComponent<Props, State> {
public static getDerivedStateFromProps(props: Props) {
let currentStepIndex = -1
public static getDerivedStateFromProps(props: Props, state: State) {
let {currentStepIndex} = state
const childSteps = React.Children.map(
props.children,
(child: ReactElement<WizardStepProps>, i) => {
@ -50,6 +54,14 @@ class WizardCloak extends PureComponent<Props, State> {
return {steps: childSteps, currentStepIndex}
}
constructor(props: Props) {
super(props)
this.state = {
steps: [],
currentStepIndex: -1,
}
}
public render() {
const {steps, currentStepIndex} = this.state
@ -61,11 +73,37 @@ class WizardCloak extends PureComponent<Props, State> {
)
}
private get CurrentChild(): JSX.Element {
const {children} = this.props
private incrementStep = () => {
const {currentStepIndex} = this.state
return children[currentStepIndex]
this.setState({
currentStepIndex: currentStepIndex + 1,
})
}
private decrementStep = () => {
const {currentStepIndex} = this.state
this.setState({
currentStepIndex: currentStepIndex - 1,
})
}
private get CurrentChild(): JSX.Element {
const {children, toggleVisibility} = this.props
const {currentStepIndex, steps} = this.state
const advance =
currentStepIndex === steps.length - 1
? toggleVisibility(false)
: this.incrementStep
const retreat = currentStepIndex === 0 ? null : this.decrementStep
return React.cloneElement<WizardStepProps>(children[currentStepIndex], {
increment: advance,
decrement: retreat,
})
}
}

View File

@ -1,28 +1,39 @@
import React, {PureComponent, ReactNode} from 'react'
import React, {PureComponent, ReactElement, ReactNode} from 'react'
import OverlayBody from 'src/reusable_ui/components/overlays/OverlayBody'
import OverlayContainer from 'src/reusable_ui/components/overlays/OverlayContainer'
import OverlayTechnology from 'src/reusable_ui/components/overlays/OverlayTechnology'
import WizardCloak from 'src/reusable_ui/components/wizard/WizardCloak'
import OverlayHeading from 'src/reusable_ui/components/overlays/OverlayHeading'
interface WizardStepProps {
children: ReactNode
title: string
isComplete: () => boolean
onPrevious: () => void
onNext: () => void
increment?: () => void
decrement?: () => void
}
// import {} from 'src/types'
interface Props {
children: ReactNode
children: Array<ReactElement<WizardStepProps>>
visible: boolean
title: string
toggleVisibility: (isVisible: boolean) => () => void
}
class WizardOverlay extends PureComponent<Props> {
public render() {
const {children, visible, title} = this.props
const {children, visible, title, toggleVisibility} = this.props
return (
<OverlayTechnology visible={visible}>
<OverlayContainer>
<OverlayHeading title={title} />
<OverlayBody>
<WizardCloak>{children}</WizardCloak>
<WizardCloak toggleVisibility={toggleVisibility}>
{children}
</WizardCloak>
</OverlayBody>
</OverlayContainer>
</OverlayTechnology>

View File

@ -10,27 +10,49 @@ interface Props {
isComplete: () => boolean
onPrevious: () => void
onNext: () => void
increment?: () => void
decrement?: () => void
}
class WizardStep extends PureComponent<Props> {
public render() {
const {children, title, onPrevious, onNext} = this.props
const {children, title, decrement} = this.props
return (
<div className="progress-step">
<h2>{title}</h2>
{children}
<div className="button-bar">
<button className="btn btn-md btn-default" onClick={onPrevious}>
{decrement && (
<button
className="btn btn-md btn-default"
onClick={this.handleClickPrevious}
>
Alakazam
</button>
<button className="btn btn-md btn-primary" onClick={onNext}>
)}
<button
className="btn btn-md btn-primary"
onClick={this.handleClickNext}
>
Abrakabra
</button>
</div>
</div>
)
}
private handleClickPrevious = () => {
const {onPrevious, decrement} = this.props
onPrevious() // TODO wait if async function
decrement()
}
private handleClickNext = () => {
const {onNext, increment} = this.props
onNext()
increment()
}
}
export default WizardStep

View File

@ -6,6 +6,7 @@ import WizardStep from 'src/reusable_ui/components/wizard/WizardStep'
interface Props {
wizardVisibility: boolean
toggleVisibility: (isVisible: boolean) => () => void
}
interface State {
@ -13,24 +14,29 @@ interface State {
}
class WizardWithSteps extends PureComponent<Props, State> {
constructor(props) {
constructor(props: Props) {
super(props)
this.state = {
completion: {
first: false,
first: true,
second: false,
third: false,
},
}
}
public render() {
const {wizardVisibility} = this.props
const {wizardVisibility, toggleVisibility} = this.props
return (
<WizardOverlay visible={wizardVisibility} title="Grand Wizard">
<WizardOverlay
visible={wizardVisibility}
toggleVisibility={toggleVisibility}
title="Grand Wizard"
>
<WizardStep
title="First Real Step"
isComplete={this.completeTest('first')}
onNext={this.handleFirstNext}
onPrevious={this.handleFirstPrev}
>
some first children
</WizardStep>
@ -38,6 +44,7 @@ class WizardWithSteps extends PureComponent<Props, State> {
title="Second Real Step"
isComplete={this.completeTest('second')}
onNext={this.handleSecondNext}
onPrevious={this.handleSecondPrev}
>
some second children
</WizardStep>
@ -45,6 +52,7 @@ class WizardWithSteps extends PureComponent<Props, State> {
title="Third Real Step"
isComplete={this.completeTest('third')}
onNext={this.handleThirdNext}
onPrevious={this.handleThirdPrev}
>
some third children
</WizardStep>
@ -57,6 +65,13 @@ class WizardWithSteps extends PureComponent<Props, State> {
return completion[curr]
}
private handleFirstNext = () => {
const {completion} = this.state
this.setState({
completion: {...completion, first: true},
})
}
private handleSecondNext = () => {
const {completion} = this.state
this.setState({
@ -70,6 +85,27 @@ class WizardWithSteps extends PureComponent<Props, State> {
completion: {...completion, third: true},
})
}
private handleFirstPrev = () => {
const {completion} = this.state
this.setState({
completion: {...completion, first: false},
})
}
private handleSecondPrev = () => {
const {completion} = this.state
this.setState({
completion: {...completion, second: false},
})
}
private handleThirdPrev = () => {
const {completion} = this.state
this.setState({
completion: {...completion, third: false},
})
}
}
export default WizardWithSteps

View File

@ -78,7 +78,10 @@ class ManageSources extends PureComponent<Props, State> {
<p className="version-number">Chronograf Version: {VERSION}</p>
</div>
</FancyScrollbar>
<GrandWizard wizardVisibility={wizardVisibility} />
<GrandWizard
wizardVisibility={wizardVisibility}
toggleVisibility={this.toggleVisibility}
/>
</div>
)
}