import { makeStyles } from '@material-ui/core' import { Form, Formik } from 'formik' import * as R from 'ramda' import React, { useState } from 'react' import ErrorMessage from 'src/components/ErrorMessage' import Modal from 'src/components/Modal' import Stepper from 'src/components/Stepper' import { Button } from 'src/components/buttons' import ChooseType, { validationSchema as chooseTypeSchema, defaultValues as chooseTypeDefaults } from './Forms/ChooseType' import NameOfRequirement, { validationSchema as nameOfReqSchema, defaultValues as nameOfReqDefaults } from './Forms/NameOfRequirement' import Screen1Information, { validationSchema as screen1InfoSchema, defaultValues as screen1InfoDefaults } from './Forms/Screen1Information' import Screen2Information, { validationSchema as screen2InfoSchema, defaultValues as screen2InfoDefaults } from './Forms/Screen2Information' import TypeFields, { defaultValues as typeFieldsDefaults, validationSchema as typeFieldsValidationSchema } from './Forms/TypeFields' import WizardSplash from './WizardSplash' const LAST_STEP = 5 const styles = { stepper: { margin: [[16, 0, 14, 0]] }, submit: { display: 'flex', flexDirection: 'row', margin: [['auto', 0, 24]] }, button: { marginLeft: 'auto' }, form: { height: '100%', display: 'flex', flexDirection: 'column' } } const useStyles = makeStyles(styles) const getStep = (step, existingRequirements) => [ { validationSchema: nameOfReqSchema(existingRequirements), Component: NameOfRequirement }, { validationSchema: screen1InfoSchema, Component: Screen1Information }, { validationSchema: chooseTypeSchema, Component: ChooseType }, { validationSchema: screen2InfoSchema, Component: Screen2Information }, { validationSchema: typeFieldsValidationSchema, Component: TypeFields } ][step - 1] const nonEmptyStr = obj => obj.text && obj.text.length const formatValues = (values, isEditing) => { const isChoiceList = values.inputType === 'choiceList' const choices = isChoiceList ? isEditing ? R.path(['listChoices'])(values) : R.map(o => o.text)(R.filter(nonEmptyStr)(values.listChoices) ?? []) : [] const hasInputLength = values.constraintType === 'length' const inputLength = hasInputLength ? values.inputLength : '' let resObj = { name: values.requirementName, screen1: { text: values.screen1Text, title: values.screen1Title }, screen2: { title: values.screen2Title, text: values.screen2Text }, input: { type: values.inputType, constraintType: values.constraintType } } if (isChoiceList) { resObj = R.assocPath(['input', 'choiceList'], choices, resObj) } if (hasInputLength) { resObj = R.assocPath(['input', 'numDigits'], inputLength, resObj) } if (values.inputLabel1) { resObj = R.assocPath(['input', 'label1'], values.inputLabel1, resObj) } if (values.inputLabel2) { resObj = R.assocPath(['input', 'label2'], values.inputLabel2, resObj) } if (isEditing) { resObj = R.assocPath(['id'], values.id, resObj) } return resObj } const makeEditingValues = ({ customRequest, id }) => { return { id, requirementName: customRequest.name, screen1Title: customRequest.screen1.title, screen1Text: customRequest.screen1.text, screen2Title: customRequest.screen2.title, screen2Text: customRequest.screen2.text, inputType: customRequest.input.type, inputLabel1: customRequest.input.label1, inputLabel2: customRequest.input.label2, listChoices: customRequest.input.choiceList, constraintType: customRequest.input.constraintType, inputLength: customRequest.input.numDigits } } const chooseNotNull = (a, b) => (R.isNil(b) ? a : b) const Wizard = ({ onClose, error = false, toBeEdited, onSave, hasError, existingRequirements }) => { const classes = useStyles() const isEditing = !R.isNil(toBeEdited) const [step, setStep] = useState(isEditing ? 1 : 0) const defaultValues = { ...nameOfReqDefaults, ...screen1InfoDefaults, ...screen2InfoDefaults, ...chooseTypeDefaults, ...typeFieldsDefaults } // If we're editing, filter out the requirement being edited so that validation schemas don't enter in circular conflicts existingRequirements = isEditing ? R.filter(it => it.id !== toBeEdited.id, existingRequirements) : existingRequirements const stepOptions = getStep(step, existingRequirements) const isLastStep = step === LAST_STEP const onContinue = (values, actions) => { const showScreen2 = values.inputType === 'numerical' || values.inputType === 'choiceList' if (isEditing && step === 2) { return showScreen2 ? setStep(4) : onSave(formatValues(values, isEditing), isEditing) } if (isEditing && step === 4) { return onSave(formatValues(values, isEditing), isEditing) } if (step === 3) { return showScreen2 ? setStep(step + 1) : setStep(step + 2) } if (!isLastStep) { return setStep(step + 1) } return onSave(formatValues(values, isEditing), isEditing) } const editingValues = isEditing ? makeEditingValues(toBeEdited) : {} const initialValues = R.mergeWith(chooseNotNull, defaultValues, editingValues) const wizardTitle = isEditing ? 'Editing custom requirement' : 'New custom requirement' return ( 0 ? wizardTitle : ''} handleClose={onClose} width={520} height={620} open={true}> {step > 0 && ( )} {step === 0 && !isEditing && } {step > 0 && ( {({ errors }) => (
{(hasError || !R.isEmpty(errors)) && ( {R.head(R.values(errors)) ?? `Failed to save`} )}
)}
)}
) } export default Wizard