* fix: eslint operator-linebreak issue * fix: eslint quotes issue * fix: react jsx indent and props issues * fix: eslint trailing spaces issues * fix: eslint line around directives issue * fix: eslint semi rule * fix: eslint newline per chain rule * fix: eslint space infix ops rule * fix: eslint space-in-parens issue * fix: eslint space before function paren issue * fix: eslint space before blocks issue * fix: eslint arrow body style issue * fix: eslint dot-location issue * fix: eslint quotes issue * fix: eslint quote props issue * fix: eslint operator assignment issue * fix: eslint new line after import issue * fix: indent issues * fix: operator assignment issue * fix: all autofixable eslint issues * fix: all react related fixable issues * fix: autofixable eslint issues * chore: remove all template literals * fix: remaining autofixable issues * fix: failing js test
125 lines
4.6 KiB
JavaScript
125 lines
4.6 KiB
JavaScript
/* global gettext */
|
|
import React from 'react';
|
|
import isFunction from 'lodash/isFunction';
|
|
|
|
const Page = ({children}) => children;
|
|
const Header = () => null;
|
|
const Closer = () => null;
|
|
const ErrorPage = () => null;
|
|
export default class Wizard extends React.Component {
|
|
constructor(props) {
|
|
super(props);
|
|
this.findSubComponentByType = this.findSubComponentByType.bind(this);
|
|
this.handleNext = this.handleNext.bind(this);
|
|
this.state = {
|
|
currentPage: 1,
|
|
totalPages: 0,
|
|
pages: [],
|
|
wizardContext: {},
|
|
};
|
|
|
|
this.wizardComplete = this.wizardComplete.bind(this);
|
|
}
|
|
|
|
componentDidMount() {
|
|
const pages = this.findSubComponentByType(Wizard.Page.name);
|
|
const totalPages = pages.length;
|
|
const wizardContext = this.props.wizardContext;
|
|
const closer = this.findSubComponentByType(Wizard.Closer.name)[0];
|
|
pages.push(closer);
|
|
this.setState({pages, totalPages, wizardContext});
|
|
}
|
|
|
|
handleNext() {
|
|
if (this.state.currentPage < this.props.children.length) {
|
|
this.setState(prevState => ({currentPage: prevState.currentPage + 1}));
|
|
}
|
|
}
|
|
|
|
findSubComponentByType(type) {
|
|
return React.Children.toArray(this.props.children).filter(child => child.type.name === type);
|
|
}
|
|
|
|
// this needs to handle the case of no provided header
|
|
renderHeader() {
|
|
const header = this.findSubComponentByType(Wizard.Header.name)[0];
|
|
return header.props.children({currentPage: this.state.currentPage, totalPages: this.state.totalPages});
|
|
}
|
|
|
|
renderPage() {
|
|
if (this.state.totalPages) {
|
|
const page = this.state.pages[this.state.currentPage - 1];
|
|
if (page.type.name === Wizard.Closer.name) {
|
|
return page.props.children;
|
|
}
|
|
|
|
if (isFunction(page.props.children)) {
|
|
return page.props.children({wizardConsumer: this.props.wizardContext});
|
|
} else {
|
|
return page.props.children;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// this needs to handle the case of no provided errorPage
|
|
renderError() {
|
|
const errorPage = this.findSubComponentByType(Wizard.ErrorPage.name)[0];
|
|
return (
|
|
<div className="wizard-container" role="dialog" aria-label={gettext('demographics questionnaire')}>
|
|
<div className="wizard-header">
|
|
{errorPage.props.children}
|
|
</div>
|
|
<div className="wizard-footer justify-content-end h-100 d-flex flex-column">
|
|
<button className="wizard-button colored" arial-label={gettext('close questionnaire')} onClick={this.props.onWizardComplete}>{gettext('Close')}</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Utility method that helps determine if the learner is on the final page of the modal.
|
|
*/
|
|
onFinalPage() {
|
|
return this.state.pages.length === this.state.currentPage;
|
|
}
|
|
|
|
/**
|
|
* Utility method for closing the modal and returning the learner back to the Course Dashboard.
|
|
* If a learner is on the final page of the modal, meaning they have answered all of the
|
|
* questions, clicking the "Return to my dashboard" button will also dismiss the CTA from the
|
|
* course dashboard.
|
|
*/
|
|
async wizardComplete() {
|
|
if (this.onFinalPage()) {
|
|
this.props.dismissBanner();
|
|
}
|
|
|
|
this.props.onWizardComplete();
|
|
}
|
|
|
|
render() {
|
|
const finalPage = this.onFinalPage();
|
|
if (this.props.error) {
|
|
return this.renderError();
|
|
}
|
|
return (
|
|
<div className="wizard-container" role="dialog" aria-label={gettext('demographics questionnaire')}>
|
|
<div className="wizard-header mb-4">
|
|
{this.state.totalPages >= this.state.currentPage && this.renderHeader()}
|
|
</div>
|
|
{this.renderPage()}
|
|
<div className="wizard-footer justify-content-end h-100 d-flex flex-column">
|
|
<button className={`wizard-button ${finalPage && 'colored'}`} onClick={this.wizardComplete} aria-label={gettext('finish later')}>{finalPage ? gettext('Return to my dashboard') : gettext('Finish later')}</button>
|
|
<button className="wizard-button colored" hidden={finalPage} onClick={this.handleNext} aria-label={gettext('next page')}>{gettext('Next')}</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
}
|
|
|
|
Wizard.Page = Page;
|
|
Wizard.Header = Header;
|
|
Wizard.Closer = Closer;
|
|
Wizard.ErrorPage = ErrorPage;
|