radlab-ui/webapp/src/components/forms/PublishCreateForm.tsx (198 lines of code) (raw):

import StepCreator from "@/components/forms/StepCreator" import { alertStore } from "@/store" import { classNames } from "@/utils/dom" import { initialFormikData } from "@/utils/terraform" import { ALERT_TYPE, IFormData, IModuleFormData, IPayloadPublishData, IUIVariable, } from "@/utils/types" import { mergeAllSafe } from "@/utils/variables" import axios from "axios" import { Form, Formik } from "formik" import startCase from "lodash/startCase" import { useTranslation } from "next-i18next" import React, { useEffect, useState } from "react" import { useNavigate } from "react-router-dom" interface IPublishCreateFormProps { formVariables: IModuleFormData[] payloadVariables: IPayloadPublishData[] defaultSettingVariables: Record<string, any> handleLoading: Function } const PublishCreateForm: React.FC<IPublishCreateFormProps> = ({ formVariables, payloadVariables, defaultSettingVariables, handleLoading, }) => { const { t } = useTranslation() const [formData, setFormData] = useState<IFormData>([]) const [initialFormData, setInitialData] = useState({}) const setAlert = alertStore((state) => state.setAlert) const navigate = useNavigate() const [step, setStep] = useState(0) const [completed, setCompleted] = useState(false) const [isSubmitLoading, setSubmitLoading] = useState(false) const [isSubmit, setSubmit] = useState(false) const currentVarsData = formVariables[step] if (!currentVarsData) { throw new Error() } function isLastStep() { return step === Object.keys(formVariables).length - 1 } const goBack = () => { setStep((s) => s - 1) } const onSubmit = async (values: IFormData, action: any) => { action.setSubmitting(false) window.scrollTo(0, 0) if (isLastStep()) { setCompleted(true) } else { if (!isSubmit) { setStep((s) => s + 1) } action.setTouched({}) // uncomment in case not need previous data as default //action.resetForm() } captureSubmitData(values) } // to get all submit data into the API let captureSubmitFormat: IPayloadPublishData[] = payloadVariables const captureSubmitData = (formSubmitValues: IFormData) => { const currentModuleName = currentVarsData?.moduleName const index = captureSubmitFormat.findIndex( (item) => item.name === currentModuleName, ) // set submit data to an array captureSubmitFormat[index]!.variables = formSubmitValues if (isSubmit) { submitDataAPI(captureSubmitFormat) } } const submitDataAPI = async (formatPayloadArr: IPayloadPublishData[]) => { handleLoading(true) setSubmitLoading(true) const payload = { modules: formatPayloadArr, } //POST publish API with payload await axios .post(`/api/modules`, payload) .then((res) => { if (res.status === 200) { setAlert({ message: t("publish-success"), type: ALERT_TYPE.SUCCESS, durationMs: 10000, }) navigate("/modules") } else { setAlert({ message: t("publish-error"), type: ALERT_TYPE.ERROR, }) } }) .catch((error) => { console.error(error) setAlert({ message: error.message, type: ALERT_TYPE.ERROR, }) }) .finally(() => { setSubmitLoading(false) handleLoading(false) }) } // To set matching deafult setting variables as default const setDefaultSettingVariables = () => { const initialFormVarData = initialFormikData(currentVarsData.variables) const indexPublishedModuleVars = payloadVariables.findIndex( (item) => item.name === currentVarsData.moduleName, ) const updateFormData = payloadVariables[indexPublishedModuleVars]!.variables // Remove emptry strings as values so merging works return mergeAllSafe([ defaultSettingVariables, initialFormVarData, updateFormData, ]) } useEffect(() => { const initialFormVariable = setDefaultSettingVariables() setInitialData(initialFormVariable) setFormData([currentVarsData.variables]) }, [currentVarsData.variables]) return ( <div className="w-full"> {formData.length && initialFormData && ( <> <ul className="steps w-full mb-4 text-sm"> {Object.keys(formVariables).map((child: string, index) => ( <li key={child} className={classNames( "step cursor-pointer", step + 1 > index || completed ? "step-primary" : "", )} onClick={() => setStep(() => index)} > {startCase(formVariables[index]?.moduleName)} </li> ))} </ul> <Formik enableReinitialize initialValues={initialFormData} onSubmit={async (values, action) => { await onSubmit(values, action) }} validateOnMount > {({ isSubmitting, isValid }) => ( <Form autoComplete="off"> {Object.keys(formData).map((grpId, index) => { const group: undefined | IUIVariable[] = formData[grpId] return group ? ( <StepCreator variableList={group} idx={index} key={grpId} /> ) : ( <></> ) })} <div className="flex-row justify-center gap-x-4"> {step > 0 ? ( <button type="button" className="btn btn-outline btn-primary w-32" disabled={isSubmitting || isSubmitLoading} onClick={goBack} > Previous </button> ) : null} <button type="submit" className="btn btn-primary float-right w-32" disabled={!isValid || isSubmitting || isSubmitLoading} onClick={() => setSubmit(true)} > {isSubmitting || isSubmitLoading ? "Submitting" : "Submit"} </button> {!isLastStep() ? ( <button type="submit" className="btn btn-primary float-right w-32 sm:mr-2" disabled={!isValid || isSubmitting || isSubmitLoading} > Next </button> ) : ( <></> )} </div> </Form> )} </Formik> </> )} </div> ) } export default PublishCreateForm