127 lines
3.2 KiB
TypeScript
127 lines
3.2 KiB
TypeScript
|
|
import { FC, useState } from "react";
|
||
|
|
import {
|
||
|
|
TextField as InternalTextField,
|
||
|
|
Grid,
|
||
|
|
Box,
|
||
|
|
IconButton,
|
||
|
|
} from "@mui/material";
|
||
|
|
import {
|
||
|
|
AddCircle as AddCircleIcon,
|
||
|
|
RemoveCircle as RemoveCircleIcon,
|
||
|
|
} from "@mui/icons-material";
|
||
|
|
import { colors, typography } from "../styles/theme";
|
||
|
|
|
||
|
|
const TextField: FC<any> = (props) => {
|
||
|
|
return (
|
||
|
|
<InternalTextField
|
||
|
|
fullWidth
|
||
|
|
size="small"
|
||
|
|
InputProps={{
|
||
|
|
sx: {
|
||
|
|
backgroundColor: "#fff",
|
||
|
|
},
|
||
|
|
}}
|
||
|
|
{...props}
|
||
|
|
/>
|
||
|
|
);
|
||
|
|
};
|
||
|
|
|
||
|
|
type MultiValueFieldProps = {
|
||
|
|
name: string;
|
||
|
|
label: string;
|
||
|
|
formState: Record<string, any>;
|
||
|
|
helperText?: string;
|
||
|
|
};
|
||
|
|
|
||
|
|
export const MultiValueField: FC<MultiValueFieldProps> = ({
|
||
|
|
name,
|
||
|
|
label,
|
||
|
|
formState,
|
||
|
|
helperText,
|
||
|
|
}) => {
|
||
|
|
const { darkMediumGray, mediumBlue, brightRed } = colors;
|
||
|
|
const { body } = typography;
|
||
|
|
const value = formState.values[name] || {};
|
||
|
|
const [fields, setFields] = useState<any[]>(Object.entries(value));
|
||
|
|
|
||
|
|
const addField = () => {
|
||
|
|
setFields([...fields, ["", ""]]);
|
||
|
|
};
|
||
|
|
|
||
|
|
const removeField = (index: number) => {
|
||
|
|
const newFields = [...fields];
|
||
|
|
newFields.splice(index, 1);
|
||
|
|
setFields(newFields);
|
||
|
|
};
|
||
|
|
|
||
|
|
const updateField = (index: number, position: number, value: any) => {
|
||
|
|
const newFields = [...fields];
|
||
|
|
newFields[index][position] = value;
|
||
|
|
setFields(newFields);
|
||
|
|
// formState.values[name] = Object.fromEntries(newFields);
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Box component="fieldset" sx={{ border: `1px solid ${darkMediumGray}` }}>
|
||
|
|
<Box
|
||
|
|
component="input"
|
||
|
|
name={name}
|
||
|
|
value={JSON.stringify(Object.fromEntries(fields))}
|
||
|
|
readOnly
|
||
|
|
hidden
|
||
|
|
/>
|
||
|
|
<Box
|
||
|
|
component="legend"
|
||
|
|
sx={{ ...body, color: darkMediumGray, fontSize: 14 }}
|
||
|
|
>
|
||
|
|
{label}
|
||
|
|
</Box>
|
||
|
|
<Grid container direction="column" spacing={2}>
|
||
|
|
<Grid
|
||
|
|
item
|
||
|
|
container
|
||
|
|
xs={12}
|
||
|
|
direction="row"
|
||
|
|
justifyContent="space-between"
|
||
|
|
alignItems="center"
|
||
|
|
>
|
||
|
|
<Grid item xs={10}>
|
||
|
|
<Box sx={{ ...body, color: darkMediumGray }}> {helperText}</Box>
|
||
|
|
</Grid>
|
||
|
|
<Grid item>
|
||
|
|
<IconButton sx={{ color: mediumBlue }} onClick={addField}>
|
||
|
|
<AddCircleIcon />
|
||
|
|
</IconButton>
|
||
|
|
</Grid>
|
||
|
|
</Grid>
|
||
|
|
{fields.map(([key, value], index) => (
|
||
|
|
<Grid key={index} item container direction="row" xs={12} spacing={2}>
|
||
|
|
<Grid item xs={5}>
|
||
|
|
<TextField
|
||
|
|
label="Key"
|
||
|
|
defaultValue={key}
|
||
|
|
onChange={(e: any) => updateField(index, 0, e.target.value)}
|
||
|
|
/>
|
||
|
|
</Grid>
|
||
|
|
<Grid item xs={6}>
|
||
|
|
<TextField
|
||
|
|
label="Value"
|
||
|
|
defaultValue={value}
|
||
|
|
onChange={(e: any) => updateField(index, 1, e.target.value)}
|
||
|
|
/>
|
||
|
|
</Grid>
|
||
|
|
<Grid item xs={1} sx={{ textAlign: "right" }}>
|
||
|
|
<IconButton
|
||
|
|
sx={{ color: brightRed }}
|
||
|
|
onClick={() => removeField(index)}
|
||
|
|
>
|
||
|
|
<RemoveCircleIcon />
|
||
|
|
</IconButton>
|
||
|
|
</Grid>
|
||
|
|
</Grid>
|
||
|
|
))}
|
||
|
|
</Grid>
|
||
|
|
</Box>
|
||
|
|
);
|
||
|
|
};
|