@adaptabletools/adaptable
Version:
Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements
169 lines (168 loc) • 8.04 kB
JavaScript
import * as React from 'react';
import { WizardLegend } from './WizardLegend';
import { ArrayExtensions } from '../../Utilities/Extensions/ArrayExtensions';
import { Flex } from 'rebass';
import Dialog from '../../components/Dialog';
import SimpleButton from '../../components/SimpleButton';
import Panel from '../../components/Panel';
import kebabCase from 'lodash/kebabCase';
export const AdaptableWizardContext = React.createContext({
data: null,
updateGoBackState: () => { },
onRender: (ActiveStep) => { },
api: null,
});
export const useWizardContext = () => {
return React.useContext(AdaptableWizardContext);
};
class DummyActiveStep {
canNext() {
return false;
}
canBack() {
return false;
}
next() {
// no implementation for this
}
back() {
// no implementation for this
}
getIndexStepIncrement() {
return 1;
}
getIndexStepDecrement() {
return 1;
}
}
//Remark : the component doesnt handle the change of props once displayed... It's easy to do but not sure it's needed
//as in the top component we do the render with a ternary expression so we add/remove the element from the render instead of having a property
//Show/hide.
export class AdaptableWizard extends React.Component {
constructor(props) {
super(props);
//we need to init with a dummy one as Ref is a callback once the component is rendered. So once set we force Re render....
//I have no idea so far how to do it differently
this.ActiveStep = new DummyActiveStep();
let indexStart = 0;
if (this.props.stepStartIndex) {
indexStart = this.props.stepStartIndex;
}
let BodyElement = this.props.steps[indexStart].Element;
this.stepName = this.props.steps[indexStart].StepName;
let newElement = this.cloneWizardStep(BodyElement);
this.state = { ActiveState: newElement, IndexState: indexStart };
}
render() {
let wizardStepNames = ArrayExtensions.RetrieveDistinct(this.props.steps.map((x) => {
return x.StepName;
}));
const hasNext = this.props.steps.length > 1;
const hasBack = hasNext;
return (React.createElement(AdaptableWizardContext.Provider, { value: {
data: this.props.data,
updateGoBackState: () => this.ForceUpdateGoBackState(),
api: this.props.api,
onRender: (ActiveStep) => {
this.ActiveStep = ActiveStep;
this.forceUpdate();
},
} },
React.createElement(Dialog, { modal: true, isOpen: true, showCloseButton: false, onDismiss: () => (this.props.onHide ? this.props.onHide() : null) },
React.createElement(Flex, { flexDirection: "column", "data-name": this.props.moduleInfo.FriendlyName
? `${kebabCase(this.props.moduleInfo.FriendlyName)}-wizard`
: '', style: {
height: '100%',
width: '70vw',
maxWidth: 1000,
maxHeight: '80vh',
...this.props.style,
} },
React.createElement(Panel, { header: this.props.moduleInfo.FriendlyName, border: "none", className: "ab-WizardDialog__steps", borderRadius: "none", variant: "primary", style: { flex: 'none' } }, this.props.showStepsLegend === false ? null : (React.createElement(WizardLegend, { StepNames: wizardStepNames, ActiveStepName: this.stepName, FriendlyName: '', CanShowAllSteps: this.canFinishWizard(), onStepButtonClicked: (s) => this.onStepButtonClicked(s) }))),
React.createElement(Flex, { style: { flex: 1, overflow: 'auto' }, flexDirection: "column" }, this.state.ActiveState),
React.createElement(Flex, { flexDirection: "row", padding: 2, backgroundColor: "primary", alignItems: "center", className: "ab-WizardDialog__footer" },
React.createElement(SimpleButton, { tone: "neutral", variant: "text", "data-name": "close", onClick: () => this.props.onHide(), tooltip: this.props.closeTooltip ?? 'Close wizard', accessLevel: 'Full' }, this.props.closeText ?? 'CLOSE'),
React.createElement("div", { style: { flex: 1 } }),
hasBack ? (React.createElement(SimpleButton, { "data-name": "back", variant: "outlined", disabled: !this.ActiveStep.canBack() || this.isFirstStep(), onClick: () => this.handleClickBack(), icon: "arrow-left", accessLevel: 'Full' }, "Back")) : null,
hasNext ? (React.createElement(SimpleButton, { variant: "outlined", "data-name": "next", disabled: !this.ActiveStep.canNext() || this.isLastStep(), onClick: () => this.handleClickNext(), icon: "arrow-right", iconPosition: "end", accessLevel: 'Full', marginLeft: 2, marginRight: 2 }, "Next")) : null,
React.createElement(SimpleButton, { tone: "accent", "data-name": "finish", variant: "raised", disabled: !this.canFinishWizard(), onClick: () => this.handleClickFinish(), icon: 'check', accessLevel: 'Full' }, "Finish"))))));
}
onStepButtonClicked(stepName) {
let wizardStepInfo = this.props.steps.find((s) => s.StepName == stepName);
let bodyElement = wizardStepInfo.Element;
let newElement = this.cloneWizardStep(bodyElement);
this.stepName = wizardStepInfo.StepName;
this.setState({
ActiveState: newElement,
IndexState: wizardStepInfo.Index,
});
}
ForceUpdateGoBackState() {
this.forceUpdate();
}
isLastStep() {
return this.state.IndexState == this.props.steps.length - 1;
}
isFirstStep() {
return this.state.IndexState == 0;
}
canFinishWizard() {
return this.ActiveStep.canNext() && this.props.canFinishWizard();
}
handleClickBack() {
if (!this.isFirstStep()) {
if (this.ActiveStep.canBack()) {
let decrement = this.ActiveStep.getIndexStepDecrement();
this.ActiveStep.back();
let activeWizardInfo = this.props.steps[this.state.IndexState - decrement];
let bodyElement = activeWizardInfo.Element;
let newElement = this.cloneWizardStep(bodyElement);
this.stepName = activeWizardInfo.StepName;
this.setState({
ActiveState: newElement,
IndexState: this.state.IndexState - decrement,
});
}
}
}
handleClickNext() {
if (this.ActiveStep.canNext()) {
let increment = this.ActiveStep.getIndexStepIncrement();
this.ActiveStep.next();
let activeWizardInfo = this.props.steps[this.state.IndexState + increment];
let bodyElement = activeWizardInfo.Element;
let newElement = this.cloneWizardStep(bodyElement);
this.stepName = activeWizardInfo.StepName;
this.setState({
ActiveState: newElement,
IndexState: this.state.IndexState + increment,
});
}
}
handleClickFinish() {
if (this.ActiveStep.canNext()) {
this.ActiveStep.next();
if (this.props.onFinish) {
this.props.onFinish();
}
this.props.onHide();
}
}
//So we inject everything needed for the Wizard
cloneWizardStep(step) {
return React.cloneElement(step, {
ref: (Element) => {
if (Element) {
this.ActiveStep = Element;
this.forceUpdate();
}
else {
this.ActiveStep = null;
}
},
data: this.props.data,
updateGoBackState: () => this.ForceUpdateGoBackState(),
api: this.props.api,
});
}
}