@boomerang-io/carbon-addons-boomerang-react
Version:
Carbon Addons for Boomerang apps
153 lines (150 loc) • 5.94 kB
JavaScript
import React, { useEffect } from 'react';
import { ModalHeader, ProgressIndicator, ProgressStep } from '@carbon/react';
import ConfirmModal from '../ConfirmModal/ConfirmModal.js';
import { Modal } from '../Modal/Modal.js';
import cx from 'classnames';
import useSetState from '../../tools/useSetState.js';
import { prefix } from '../../internal/settings.js';
/*
IBM Confidential
694970X, 69497O0
© Copyright IBM Corp. 2022, 2024
*/
FlowModalContainer.defaultProps = {
composedModalProps: {},
isOpen: false,
modalHeaderProps: {},
};
function FlowModalContainer(props) {
const [state, setState] = useSetState({
formData: new Map(),
isConfirmModalOpen: false,
isOpen: props.isOpen,
shouldConfirmModalClose: false,
step: 0,
...props.initialState,
});
// Let it be externally controlled
useEffect(() => {
setState({ isOpen: props.isOpen });
}, [props.isOpen, setState]);
/**
* Change step value to the requested value
* @param {number} stepRequested - requested value
*/
function goToStep(stepRequested) {
setState({ step: stepRequested });
}
/**
* Change step to next one
*/
function requestNextStep() {
goToStep(state.step + 1);
}
/**
* Change step to previous one
*/
function requestPreviousStep() {
goToStep(state.step - 1);
}
/**
* Save data colected by user input into formData
* @param {obj} data - the new data to be saved
*/
function saveValues(data) {
setState({ formData: { ...state.formData, ...data } });
if (typeof props.onFormDataChange === "function") {
props.onFormDataChange(state.formData);
}
}
/**
* Reset to initial state
* and let parent know
*/
function resetInitialState(stateUpdate) {
setState({
formData: new Map(),
isConfirmModalOpen: false,
shouldConfirmModalClose: false,
step: 0,
...props.initialState,
...stateUpdate,
});
if (typeof props.onFormDataChange === "function") {
props.onFormDataChange(state.formData);
}
}
function handleOpenModal() {
setState({ isOpen: true });
}
/**
* Close modal and call event function for parent if provided
*/
function handleCloseModal() {
resetInitialState({ isOpen: false });
if (typeof props.onCloseModal === "function") {
props.onCloseModal();
}
}
/**
* Check if should confirm exit with confirm modal or just exit modal flow
*/
function handleShouldCloseModal() {
if (state.shouldConfirmModalClose) {
setState({ isConfirmModalOpen: true });
}
else {
handleCloseModal();
}
}
function closeConfirmModal() {
setState({ isConfirmModalOpen: false });
}
/**
* Method passed to children components and they determine if should confirm exit of modal
* @param {bool} shouldConfirmModalClose - boolean of current component
*/
function handleSetShouldConfirmModalClose(shouldConfirmModalClose) {
setState({ shouldConfirmModalClose });
}
/**
* Determine which child to render based on the current step in the flow
*/
function determineChildToRender() {
const { step } = state;
let childToRender;
if (React.Children.count(props.children) > 0) {
React.Children.forEach(props.children, (child, index) => {
if (index === step) {
childToRender = child;
}
});
}
return childToRender;
}
const { containerClassName, ...restComposedModalProps } = props.composedModalProps;
const { subtitle, ...restModalHeaderProps } = props.modalHeaderProps;
const childToRender = determineChildToRender();
return (React.createElement(React.Fragment, null,
props.modalTrigger && props.modalTrigger({ openModal: handleOpenModal }),
React.createElement(Modal, { appElement: props.appElement, containerClassName: cx(`${prefix}--bmrg-modal-flow-container`, `${prefix}--modal-container`, props.size ? `${prefix}--modal-container--${props.size}` : "modal-container-fix-width", containerClassName), isOpen: state.isOpen, onRequestClose: handleShouldCloseModal, shouldCloseOnOverlayClick: false, ...restComposedModalProps },
React.createElement(ModalHeader, { closeModal: handleShouldCloseModal, ...restModalHeaderProps }, subtitle && React.createElement("p", { className: `${prefix}--bmrg-modal-flow-subtitle` }, subtitle)),
Array.isArray(props.progressSteps) && (React.createElement(ProgressIndicator, { currentIndex: state.step }, props.progressSteps.map((stepProps, index) => (React.createElement(ProgressStep, { key: index, ...stepProps }))))),
childToRender &&
state.isOpen &&
React.cloneElement(childToRender, {
closeModal: handleShouldCloseModal,
forceCloseModal: handleCloseModal,
formData: state.formData,
goToStep,
requestNextStep,
requestPreviousStep,
resetInitialState,
saveValues,
setShouldConfirmModalClose: handleSetShouldConfirmModalClose,
shouldConfirmModalClose: state.shouldConfirmModalClose,
step: state.step,
}),
React.createElement(ConfirmModal, { affirmativeAction: handleCloseModal, appElement: props.appElement, negativeAction: closeConfirmModal, isOpen: state.isConfirmModalOpen, onCloseModal: closeConfirmModal, ...props.confirmModalProps }))));
}
export { FlowModalContainer, FlowModalContainer as default };