142 lines
3.9 KiB
TypeScript
142 lines
3.9 KiB
TypeScript
import { Dictionary } from "lodash";
|
|
import React from "react";
|
|
import { SPACE_BETWEEN_HORIZONTALLY } from "../../../utils/styles";
|
|
import Select from "../Select/Select";
|
|
|
|
export type formInput = {
|
|
name: string;
|
|
label: string;
|
|
validationMessage: string;
|
|
inputProps: React.DetailedHTMLProps<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>;
|
|
options?: Dictionary<string>;
|
|
};
|
|
|
|
export type FormProps = {
|
|
onSubmitForm: (fields: Dictionary<any>) => void;
|
|
submitFormButtonText: string;
|
|
submitFormButtonColor?: string;
|
|
formInputs: formInput[];
|
|
};
|
|
|
|
type FormState = {
|
|
fields: Dictionary<any>;
|
|
};
|
|
|
|
// Generates a Form Message for every invalid matcher. This is used instead of manually creating
|
|
// a Form Message for every invalid case.
|
|
// function formMessageMatchAll(message: string) {
|
|
// const invalidMatchers: ReactForm.ValidityMatcher[] = [
|
|
// "badInput",
|
|
// "patternMismatch",
|
|
// "rangeOverflow",
|
|
// "rangeUnderflow",
|
|
// "stepMismatch",
|
|
// "tooLong",
|
|
// "tooShort",
|
|
// "typeMismatch",
|
|
// "valueMissing"
|
|
// ];
|
|
|
|
// return invalidMatchers.map((matcher) => (
|
|
// <div key={"match-" + matcher} className="FormMessage">
|
|
// {message}
|
|
// </div>
|
|
// ));
|
|
// }
|
|
|
|
export default class Form extends React.Component<FormProps, FormState> {
|
|
clickedButtonName = "";
|
|
|
|
constructor(props: FormProps | Readonly<FormProps>) {
|
|
super(props);
|
|
|
|
// initialize state from defaultValues provided
|
|
const fields: { [index: string]: any } = {};
|
|
|
|
props.formInputs.forEach((formInput) => {
|
|
if (formInput.inputProps.defaultValue) fields[formInput.name] = formInput.inputProps.defaultValue;
|
|
});
|
|
|
|
this.state = { fields };
|
|
}
|
|
|
|
handleFormInput = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
const { name, value } = event.target;
|
|
const fields = this.state.fields;
|
|
this.setState({ fields: { ...fields, ...{ [name]: value } } });
|
|
};
|
|
|
|
onSubmit = (event: any) => {
|
|
event.preventDefault();
|
|
if (this.clickedButtonName == this.props.submitFormButtonText) this.props.onSubmitForm(this.state.fields);
|
|
};
|
|
|
|
handleClick = (event: any) => {
|
|
this.clickedButtonName = event.target.name;
|
|
};
|
|
|
|
render() {
|
|
// console.log("new Form state: " + JSON.stringify(this.state, null, 4))
|
|
|
|
const { formInputs, submitFormButtonText, submitFormButtonColor } = this.props;
|
|
|
|
return (
|
|
<form className="FormRoot" onSubmit={this.onSubmit}>
|
|
{formInputs.map((formInput) => {
|
|
return (
|
|
<div key={formInput.name} className="FormField">
|
|
{/* Range Input additional label */}
|
|
{formInput.inputProps.type && formInput.inputProps.type === "range" ? (
|
|
<label className="FormLabel">
|
|
{formInput.label} Slider:
|
|
<em style={{ color: "grey" }}>
|
|
{this.state.fields[formInput.name] || formInput.inputProps.defaultValue || 1}
|
|
</em>
|
|
</label>
|
|
) : (
|
|
<span style={{ color: "#494F55" }}>{formInput.label}</span>
|
|
)}
|
|
|
|
{/* Validations */}
|
|
{/* {formMessageMatchAll(formInput.validationMessage)} */}
|
|
|
|
{/* Input */}
|
|
<span>
|
|
{formInput.options !== undefined ? (
|
|
<Select
|
|
values={formInput.options}
|
|
defaultValue={Object.keys(formInput.options)[0]}
|
|
onUpdate={(value) => {
|
|
const fields = this.state.fields;
|
|
this.setState({ fields: { ...fields, ...{ [formInput.name]: value } } });
|
|
}}
|
|
triggerStyle={{ ...SPACE_BETWEEN_HORIZONTALLY, width: "100%", }}
|
|
/>
|
|
) : (
|
|
<input
|
|
className="Input"
|
|
name={formInput.name}
|
|
onChange={this.handleFormInput}
|
|
{...formInput.inputProps}
|
|
/>
|
|
)}
|
|
</span>
|
|
</div>
|
|
);
|
|
})}
|
|
<div style={{ display: "flex", marginTop: 25 }}>
|
|
<div style={{ marginRight: 25 }}>
|
|
<button
|
|
className={`Button ${submitFormButtonColor || "green"}`}
|
|
name={submitFormButtonText}
|
|
onClick={this.handleClick}
|
|
>
|
|
{submitFormButtonText}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
);
|
|
}
|
|
}
|