Skip to content

Commit

Permalink
CORE-1967 Refactor metadata template form fields
Browse files Browse the repository at this point in the history
Try to simplify the logic for building and validating form fields.
  • Loading branch information
psarando committed Mar 15, 2024
1 parent 0e48342 commit f7f1898
Show file tree
Hide file tree
Showing 13 changed files with 423 additions and 186 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
* @author psarando sriram
*/
import React from "react";

import { FastField } from "formik";
import PropTypes from "prop-types";

import { useTranslation } from "i18n";
import FormSearchField from "components/forms/FormSearchField";

import { ListItemText } from "@mui/material";
Expand All @@ -12,8 +15,9 @@ const AstroThesaurusOption = (option) => (
<ListItemText primary={option.label} secondary={option.iri} />
);

const AstroThesaurusSearchField = (props) => {
const { searchAstroThesaurusTerms, ...custom } = props;
const AstroThesaurusSearchFieldComponent = (props) => {
const { searchAstroThesaurusTerms, attribute, writable, ...custom } = props;

const [options, setOptions] = React.useState([]);

const handleSearch = (event, value, reason) => {
Expand Down Expand Up @@ -59,11 +63,31 @@ const AstroThesaurusSearchField = (props) => {
options={options}
labelKey="label"
valueKey="label"
label={attribute.name}
required={attribute.required && writable}
readOnly={!writable}
{...custom}
/>
);
};

const AstroThesaurusSearchField = ({ avu, avuFieldName, ...props }) => {
const { t } = useTranslation("metadata");

return (
<FastField
name={`${avuFieldName}.value`}
component={AstroThesaurusSearchFieldComponent}
validate={(value) => {
if (props.attribute?.required && !value) {
return t("required");
}
}}
{...props}
/>
);
};

AstroThesaurusSearchField.propTypes = {
searchAstroThesaurusTerms: PropTypes.func.isRequired,
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* @author psarando
*/
import React from "react";

import { FastField } from "formik";

import FormCheckboxStringValue from "components/forms/FormCheckboxStringValue";

const CheckboxStringValueField = ({
attribute,
avu,
avuFieldName,
writable,
...props
}) => {
return (
<FastField
name={`${avuFieldName}.value`}
component={FormCheckboxStringValue}
label={attribute.name}
disabled={!writable}
{...props}
/>
);
};

export default CheckboxStringValueField;
40 changes: 40 additions & 0 deletions src/components/metadata/templates/fields/EnumField.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* @author psarando
*/
import React from "react";

import { FastField } from "formik";

import { useTranslation } from "i18n";
import FormTextField from "components/forms/FormTextField";
import { MenuItem } from "@mui/material";

const EnumField = ({ attribute, avu, avuFieldName, writable, ...props }) => {
const { t } = useTranslation("metadata");

return (
<FastField
name={`${avuFieldName}.value`}
component={FormTextField}
select
label={attribute.name}
required={attribute.required && writable}
inputProps={{ readOnly: !writable }}
validate={(value) => {
if (attribute.required && !value) {
return t("required");
}
}}
{...props}
>
{attribute.values &&
attribute.values.map((enumVal, index) => (
<MenuItem key={index} value={enumVal.value}>
{enumVal.value}
</MenuItem>
))}
</FastField>
);
};

export default EnumField;
20 changes: 20 additions & 0 deletions src/components/metadata/templates/fields/GroupingField.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* @author psarando
*/
import React from "react";

import { FastField } from "formik";

const GroupingField = ({
attribute,
avu,
avuFieldName,
writable,
...props
}) => {
return (
<FastField name={`${avuFieldName}.value`} component="span" {...props} />
);
};

export default GroupingField;
35 changes: 35 additions & 0 deletions src/components/metadata/templates/fields/IntegerField.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* @author psarando
*/
import React from "react";

import { FastField } from "formik";

import { useTranslation } from "i18n";
import FormIntegerField from "components/forms/FormIntegerField";

const IntegerField = ({ attribute, avu, avuFieldName, writable, ...props }) => {
const { t } = useTranslation("metadata");

return (
<FastField
name={`${avuFieldName}.value`}
component={FormIntegerField}
label={attribute.name}
required={attribute.required && writable}
inputProps={{ readOnly: !writable }}
validate={(value) => {
if (attribute.required && !value && value !== 0) {
return t("required");
}

if (isNaN(Number(value))) {
return t("templateValidationErrMsgNumber");
}
}}
{...props}
/>
);
};

export default IntegerField;
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,20 @@
*/
import React from "react";

import { FastField } from "formik";
import { useQuery } from "react-query";

import { useTranslation } from "i18n";

import LocalContextsLabelDisplay from "../LocalContextsLabelDisplay";
import LocalContextsLabelDisplay from "../../LocalContextsLabelDisplay";

import ErrorTypographyWithDialog from "components/error/ErrorTypographyWithDialog";
import getFormError from "components/forms/getFormError";
import {
LocalContextsAttrs,
parseProjectID,
} from "components/models/metadata/LocalContexts";
import { urlField } from "components/utils/validations";

import {
LOCAL_CONTEXTS_QUERY_KEY,
Expand All @@ -29,15 +31,18 @@ import { Skeleton, TextField } from "@mui/material";

const findAVU = (avus, attr) => avus?.find((avu) => avu.attr === attr);

const LocalContextsField = ({
const LocalContextsFieldComponent = ({
attribute,
avu,
onUpdate,
avuFieldName,
writable,
helperText,
form: { setFieldValue, ...form },
form,
field: { value, onChange, ...field },
...props
}) => {
const { t } = useTranslation("localcontexts");
const { t } = useTranslation(["localcontexts", "metadata"]);
const { i18nUtil } = useTranslation("util");

const [rightsURIAVU, setRightsURIAVU] = React.useState(
() =>
Expand Down Expand Up @@ -87,8 +92,7 @@ const LocalContextsField = ({
return schemeURI;
});

const { touched, errors } = form;
const fieldError = getFormError(field.name, touched, errors);
const fieldError = getFormError(avuFieldName, form.touched, form.errors);
const projectID = parseProjectID(projectHubURI);

const { data: project, isFetching } = useQuery({
Expand All @@ -99,6 +103,8 @@ const LocalContextsField = ({
}),
enabled: !!projectHubURI && !fieldError,
onSuccess: (project) => {
if (!writable) return;

let newValue = avu.value || "";

const projectLabels = [
Expand Down Expand Up @@ -163,7 +169,11 @@ const LocalContextsField = ({
})),
];

onUpdate({ ...avu, value: newValue, avus: newAVUs });
form.setFieldValue(avuFieldName, {
...avu,
value: newValue,
avus: newAVUs,
});
}
},
onError: (error) => {
Expand All @@ -179,6 +189,10 @@ const LocalContextsField = ({
const updateProjectHubURI = (uri) => {
setProjectHubURI(uri);
setProjectHubError(null);
form.setFieldError(
avuFieldName,
!uri ? t("metadata:required") : urlField(uri, i18nUtil)
);

let newAVUs = avu.avus || [];

Expand All @@ -204,7 +218,7 @@ const LocalContextsField = ({
rightsIDSchemeURIAVU,
];

onUpdate({ ...avu, avus: newAVUs });
form.setFieldValue(avuFieldName, { ...avu, avus: newAVUs });
}
};

Expand All @@ -213,6 +227,7 @@ const LocalContextsField = ({
return (
<>
<TextField
inputProps={{ readOnly: !writable }}
error={!!errorMsg}
helperText={errorMsg || helperText}
variant="outlined"
Expand All @@ -238,4 +253,12 @@ const LocalContextsField = ({
);
};

const LocalContextsField = (props) => (
<FastField
name={props.avuFieldName}
component={LocalContextsFieldComponent}
{...props}
/>
);

export default LocalContextsField;
37 changes: 37 additions & 0 deletions src/components/metadata/templates/fields/MultilineTextField.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* @author psarando
*/
import React from "react";

import { FastField } from "formik";

import { useTranslation } from "i18n";
import FormMultilineTextField from "components/forms/FormMultilineTextField";

const MultilineTextField = ({
attribute,
avu,
avuFieldName,
writable,
...props
}) => {
const { t } = useTranslation("metadata");

return (
<FastField
name={`${avuFieldName}.value`}
component={FormMultilineTextField}
label={attribute.name}
required={attribute.required && writable}
inputProps={{ readOnly: !writable }}
validate={(value) => {
if (attribute.required && !value) {
return t("required");
}
}}
{...props}
/>
);
};

export default MultilineTextField;
35 changes: 35 additions & 0 deletions src/components/metadata/templates/fields/NumberField.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* @author psarando
*/
import React from "react";

import { FastField } from "formik";

import { useTranslation } from "i18n";
import FormNumberField from "components/forms/FormNumberField";

const NumberField = ({ attribute, avu, avuFieldName, writable, ...props }) => {
const { t } = useTranslation("metadata");

return (
<FastField
name={`${avuFieldName}.value`}
component={FormNumberField}
label={attribute.name}
required={attribute.required && writable}
inputProps={{ readOnly: !writable }}
validate={(value) => {
if (attribute.required && !value && value !== 0.0) {
return t("required");
}

if (isNaN(Number(value))) {
return t("templateValidationErrMsgNumber");
}
}}
{...props}
/>
);
};

export default NumberField;
Loading

0 comments on commit f7f1898

Please sign in to comment.