import React from "react" import * as antd from "antd" import loadable from "@loadable/component" import { Translation } from "react-i18next" import { Icons, createIconRender } from "components/Icons" import { ActionsBar } from "components" import "./index.less" export default class StepsForm extends React.Component { state = { steps: [...(this.props.steps ?? []), ...(this.props.children ?? [])], step: 0, values: {}, canNext: true, renderStep: null, } api = window.app.request componentDidMount = async () => { if (this.props.defaultValues) { await this.setState({ values: this.props.defaultValues }) } await this.handleNext(0) } next = (to) => { if (!this.state.canNext) { return antd.message.error("Please complete the step.") } return this.handleNext(to) } prev = () => this.handlePrev() handleNext = (to) => { const index = to ?? (this.state.step + 1) this.setState({ step: index, renderStep: this.renderStep(index) }) } handlePrev = () => { this.handleNext(this.state.step - 1) } handleError = (error) => { this.setState({ submitting: false, submittingError: error }) } handleUpdate = (key, value) => { this.setState({ values: { ...this.state.values, [key]: value } }, () => { if (typeof this.props.onChange === "function") { this.props.onChange(this.state.values) } }) } handleValidation = (result) => { this.setState({ canNext: result }) } canSubmit = () => { if (typeof this.props.canSubmit === "function") { return this.props.canSubmit(this.state.values) } return true } onSubmit = async () => { if (!this.state.canNext) { console.warn("Cannot submit form, validation failed") return false } if (typeof this.props.onSubmit === "function") { this.setState({ submitting: true, submittingError: null }) await this.props.onSubmit(this.state.values).catch((error) => { console.error(error) this.handleError(error) }) } } renderStep = (stepIndex) => { const step = this.state.steps[stepIndex] let content = step.content let value = this.state.values[step.key] if (typeof step.key === "undefined") { console.error("[StepsForm] step.key is required") return null } if (typeof step.required !== "undefined" && step.required) { this.handleValidation(Boolean(value && value.length > 0)) } else { this.setState({ canNext: true }) } if (typeof step.stateValidation === "function") { const validationResult = step.stateValidation(value) this.handleValidation(validationResult) } const componentProps = { handleUpdate: (to) => { value = to if (typeof step.onUpdateValue === "function") { value = step.onUpdateValue(value, to) } let validationResult = true if (typeof step.stateValidation === "function") { validationResult = step.stateValidation(to) } if (typeof step.required !== "undefined" && step.required) { validationResult = Boolean(to && to.length > 0) } this.handleUpdate(step.key, to) this.handleValidation(validationResult) }, handleError: (error) => { if (typeof props.handleError === "function") { this.handleError(error) } }, onPressEnter: () => this.next(), value: value, } if (typeof step.content === "function") { content = loadable(async () => { try { const component = React.createElement(step.content, componentProps) return () => component } catch (error) { console.log(error) antd.notification.error({ message: "Error", description: "Error loading step content", }) return () =>