Directory/client/src/shared/basiccomponents/FormModal/Form.tsx

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>
);
}
}