modifies field types to rely on path instead of name

This commit is contained in:
James
2020-06-03 13:49:11 -04:00
parent b8d44204c2
commit 48bb2cb8a6
21 changed files with 108 additions and 105 deletions

View File

@@ -18,7 +18,7 @@ const DraggableSection = (props) => {
addRow,
removeRow,
rowIndex,
parentName,
parentPath,
fieldSchema,
defaultValue,
dispatchCollapsibleStates,
@@ -77,7 +77,7 @@ const DraggableSection = (props) => {
{blockType === 'flexible'
&& (
<EditableBlockTitle
fieldName={`${parentName}.${rowIndex}.blockName`}
fieldName={`${parentPath}.${rowIndex}.blockName`}
/>
)
}
@@ -106,15 +106,14 @@ const DraggableSection = (props) => {
duration={0}
>
<RenderFields
initialData={defaultValue}
customComponentsPath={customComponentsPath}
fieldTypes={fieldTypes}
key={rowIndex}
fieldSchema={fieldSchema.map((field) => {
const fieldName = `${parentName}.${rowIndex}${field.name ? `.${field.name}` : ''}`;
return ({
...field,
name: fieldName,
defaultValue: field.name ? defaultValue?.[field.name] : defaultValue,
path: `${parentPath}.${rowIndex}${field.name ? `.${field.name}` : ''}`,
});
})}
/>
@@ -139,7 +138,7 @@ DraggableSection.propTypes = {
addRow: PropTypes.func.isRequired,
removeRow: PropTypes.func.isRequired,
rowIndex: PropTypes.number.isRequired,
parentName: PropTypes.string.isRequired,
parentPath: PropTypes.string.isRequired,
singularLabel: PropTypes.string,
fieldSchema: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
rowCount: PropTypes.number,

View File

@@ -165,7 +165,7 @@ const Form = (props) => {
}}
>
<HiddenInput
name="locale"
path="locale"
defaultValue={locale}
/>
{children}

View File

@@ -36,12 +36,12 @@ function fieldReducer(state, action) {
};
case 'REMOVE_ROW': {
const { rowIndex, name } = action;
const { unflattenedRows, remainingFlattenedState } = unflattenRowsFromState(state, name);
const { rowIndex, path } = action;
const { unflattenedRows, remainingFlattenedState } = unflattenRowsFromState(state, path);
unflattenedRows.splice(rowIndex, 1);
const flattenedRowState = unflattenedRows.length > 0 ? flatten({ [name]: unflattenedRows }, { filters: flattenFilters }) : {};
const flattenedRowState = unflattenedRows.length > 0 ? flatten({ [path]: unflattenedRows }, { filters: flattenFilters }) : {};
return {
...remainingFlattenedState,
@@ -51,9 +51,9 @@ function fieldReducer(state, action) {
case 'ADD_ROW': {
const {
rowIndex, name, fieldSchema, blockType,
rowIndex, path, fieldSchema, blockType,
} = action;
const { unflattenedRows, remainingFlattenedState } = unflattenRowsFromState(state, name);
const { unflattenedRows, remainingFlattenedState } = unflattenRowsFromState(state, path);
// Get names of sub fields
const subFields = fieldSchema.reduce((acc, field) => {
@@ -63,7 +63,7 @@ function fieldReducer(state, action) {
return {
...acc,
[field.name]: {
[field.path]: {
value: null,
valid: !field.required,
},
@@ -82,15 +82,15 @@ function fieldReducer(state, action) {
const newState = {
...remainingFlattenedState,
...(flatten({ [name]: unflattenedRows }, { filters: flattenFilters })),
...(flatten({ [path]: unflattenedRows }, { filters: flattenFilters })),
};
return newState;
}
case 'MOVE_ROW': {
const { moveFromIndex, moveToIndex, name } = action;
const { unflattenedRows, remainingFlattenedState } = unflattenRowsFromState(state, name);
const { moveFromIndex, moveToIndex, path } = action;
const { unflattenedRows, remainingFlattenedState } = unflattenRowsFromState(state, path);
// copy the row to move
const copyOfMovingRow = unflattenedRows[moveFromIndex];
@@ -101,20 +101,20 @@ function fieldReducer(state, action) {
return {
...remainingFlattenedState,
...(flatten({ [name]: unflattenedRows }, { filters: flattenFilters })),
...(flatten({ [path]: unflattenedRows }, { filters: flattenFilters })),
};
}
case 'REMOVE': {
const newState = { ...state };
delete newState[action.name];
delete newState[action.path];
return newState;
}
default:
return {
...state,
[action.name]: {
[action.path]: {
value: action.value,
valid: action.valid,
errorMessage: action.errorMessage,

View File

@@ -15,8 +15,6 @@ const RenderFields = ({
const customComponentsPath = customComponentsPathFromProps || customComponentsPathFromContext;
// console.log(customComponentsPath);
if (fieldSchema) {
return (
<RenderedFieldContext.Provider value={{ customComponentsPath }}>
@@ -29,7 +27,7 @@ const RenderFields = ({
if (!field.name) {
defaultValue = initialData;
} else if (initialData[field.name]) {
} else if (initialData?.[field.name]) {
defaultValue = initialData[field.name];
}
@@ -37,10 +35,11 @@ const RenderFields = ({
return (
<RenderCustomComponent
key={field.name || `field-${i}`}
path={`${customComponentsPath}${field.name ? `${field.name.split('.').pop()}.field` : ''}`}
path={`${customComponentsPath}${field.name ? `${field.name}.field` : ''}`}
DefaultComponent={FieldComponent}
componentProps={{
...field,
path: field.path || field.name,
fieldTypes,
defaultValue,
}}

View File

@@ -10,7 +10,7 @@ import './index.scss';
const Checkbox = (props) => {
const {
name,
path,
required,
defaultValue,
validate,
@@ -26,7 +26,7 @@ const Checkbox = (props) => {
onFieldChange,
formProcessing,
} = useFieldType({
name,
path,
required,
defaultValue,
validate,
@@ -53,7 +53,7 @@ const Checkbox = (props) => {
<StyledCheckbox
onClick={onFieldChange}
isChecked={value || false}
name={name}
name={path}
label={label}
isDisabled={formProcessing}
hasError={showError}
@@ -73,7 +73,7 @@ Checkbox.defaultProps = {
};
Checkbox.propTypes = {
name: PropTypes.string.isRequired,
path: PropTypes.string.isRequired,
required: PropTypes.bool,
defaultValue: PropTypes.bool,
validate: PropTypes.func,

View File

@@ -16,7 +16,7 @@ const baseClass = 'date-time-field';
const DateTime = (props) => {
const {
name,
path,
required,
defaultValue,
validate,
@@ -32,7 +32,7 @@ const DateTime = (props) => {
onFieldChange,
formProcessing,
} = useFieldType({
name,
path,
required,
defaultValue,
validate,
@@ -58,7 +58,7 @@ const DateTime = (props) => {
message={errorMessage}
/>
<Label
htmlFor={name}
htmlFor={path}
label={label}
required={required}
/>
@@ -85,6 +85,7 @@ DateTime.defaultProps = {
DateTime.propTypes = {
name: PropTypes.string.isRequired,
path: PropTypes.string.isRequired,
label: PropTypes.string,
required: PropTypes.bool,
defaultValue: PropTypes.string,

View File

@@ -10,7 +10,7 @@ import './index.scss';
const Email = (props) => {
const {
name,
path,
required,
defaultValue,
validate,
@@ -28,7 +28,7 @@ const Email = (props) => {
onFieldChange,
errorMessage,
} = useFieldType({
name,
path,
required,
defaultValue,
validate,
@@ -53,7 +53,7 @@ const Email = (props) => {
message={errorMessage}
/>
<Label
htmlFor={name}
htmlFor={path}
label={label}
required={required}
/>
@@ -63,8 +63,8 @@ const Email = (props) => {
disabled={processing ? 'disabled' : undefined}
placeholder={placeholder}
type="email"
id={name}
name={name}
id={path}
name={path}
autoComplete={autoComplete}
/>
</div>
@@ -84,6 +84,7 @@ Email.defaultProps = {
Email.propTypes = {
name: PropTypes.string.isRequired,
path: PropTypes.string.isRequired,
required: PropTypes.bool,
placeholder: PropTypes.string,
defaultValue: PropTypes.string,

View File

@@ -12,6 +12,7 @@ import FormContext from '../../Form/Context';
import AddRowModal from './AddRowModal';
import collapsibleReducer from './reducer';
import DraggableSection from '../../DraggableSection';
import { useRenderedFields } from '../../RenderFields';
import './index.scss';
@@ -21,6 +22,7 @@ const Flexible = (props) => {
const {
label,
name,
path,
blocks,
defaultValue,
singularLabel,
@@ -34,7 +36,8 @@ const Flexible = (props) => {
const [rowCount, setRowCount] = useState(0);
const [collapsibleStates, dispatchCollapsibleStates] = useReducer(collapsibleReducer, []);
const formContext = useContext(FormContext);
const modalSlug = `flexible-${name}`;
const modalSlug = `flexible-${path}`;
const { customComponentsPath } = useRenderedFields();
const { fields: fieldState, dispatchFields, countRows } = formContext;
@@ -42,7 +45,7 @@ const Flexible = (props) => {
const blockToAdd = blocks.find(block => block.slug === blockType);
dispatchFields({
type: 'ADD_ROW', rowIndex, name, fieldSchema: blockToAdd.fields, blockType,
type: 'ADD_ROW', rowIndex, path, fieldSchema: blockToAdd.fields, blockType,
});
dispatchCollapsibleStates({
@@ -55,7 +58,7 @@ const Flexible = (props) => {
const removeRow = (rowIndex) => {
dispatchFields({
type: 'REMOVE_ROW', rowIndex, name,
type: 'REMOVE_ROW', rowIndex, path,
});
dispatchCollapsibleStates({
@@ -69,7 +72,7 @@ const Flexible = (props) => {
const moveRow = (moveFromIndex, moveToIndex) => {
dispatchFields({
type: 'MOVE_ROW', moveFromIndex, moveToIndex, name,
type: 'MOVE_ROW', moveFromIndex, moveToIndex, path,
});
dispatchCollapsibleStates({
@@ -92,7 +95,7 @@ const Flexible = (props) => {
};
const updateRowCountOnParentRowModified = () => {
const countedRows = countRows(name);
const countedRows = countRows(path);
setRowCount(countedRows);
};
@@ -119,7 +122,7 @@ const Flexible = (props) => {
{...provided.droppableProps}
>
{rowCount !== 0 && Array.from(Array(rowCount).keys()).map((_, rowIndex) => {
let blockType = fieldState[`${name}.${rowIndex}.blockType`]?.value;
let blockType = fieldState[`${path}.${rowIndex}.blockType`]?.value;
if (!lastModified && !blockType) {
blockType = defaultValue?.[rowIndex]?.blockType;
@@ -132,7 +135,7 @@ const Flexible = (props) => {
<DraggableSection
fieldTypes={fieldTypes}
key={rowIndex}
parentName={name}
parentPath={path}
addRow={() => openAddRowModal(rowIndex)}
removeRow={() => removeRow(rowIndex)}
rowIndex={rowIndex}
@@ -158,6 +161,7 @@ const Flexible = (props) => {
dispatchCollapsibleStates={dispatchCollapsibleStates}
collapsibleStates={collapsibleStates}
blockType="flexible"
customComponentsPath={`${customComponentsPath}${name}.fields.`}
/>
);
}
@@ -207,6 +211,7 @@ Flexible.propTypes = {
label: PropTypes.string,
singularLabel: PropTypes.string,
name: PropTypes.string.isRequired,
path: PropTypes.string.isRequired,
fieldTypes: PropTypes.shape({}).isRequired,
};

View File

@@ -7,7 +7,7 @@ import './index.scss';
const Group = (props) => {
const {
label, fields, name, defaultValue, fieldTypes,
label, fields, name, path, defaultValue, fieldTypes,
} = props;
const { customComponentsPath } = useRenderedFields();
@@ -16,13 +16,13 @@ const Group = (props) => {
<div className="field-type group">
<h3>{label}</h3>
<RenderFields
initialData={defaultValue}
fieldTypes={fieldTypes}
customComponentsPath={`${customComponentsPath}${name}.fields.`}
fieldSchema={fields.map((subField) => {
return {
...subField,
name: `${name}${subField.name ? `.${subField.name}` : ''}`,
defaultValue: subField.name ? defaultValue[subField.name] : defaultValue,
path: `${path}${subField.name ? `.${subField.name}` : ''}`,
};
})}
/>
@@ -42,6 +42,7 @@ Group.propTypes = {
).isRequired,
label: PropTypes.string,
name: PropTypes.string.isRequired,
path: PropTypes.string.isRequired,
fieldTypes: PropTypes.shape({}).isRequired,
};

View File

@@ -5,13 +5,13 @@ import withCondition from '../../withCondition';
const HiddenInput = (props) => {
const {
name,
path,
required,
defaultValue,
} = props;
const { value, onChange } = useFieldType({
name,
path,
required,
defaultValue,
});
@@ -21,8 +21,8 @@ const HiddenInput = (props) => {
type="hidden"
value={value || ''}
onChange={onChange}
id={name}
name={name}
id={path}
name={path}
/>
);
};
@@ -33,7 +33,7 @@ HiddenInput.defaultProps = {
};
HiddenInput.propTypes = {
name: PropTypes.string.isRequired,
path: PropTypes.string.isRequired,
required: PropTypes.bool,
defaultValue: PropTypes.string,
};

View File

@@ -9,7 +9,7 @@ import './index.scss';
const NumberField = (props) => {
const {
name,
path,
required,
defaultValue,
validate,
@@ -33,7 +33,7 @@ const NumberField = (props) => {
formProcessing,
errorMessage,
} = useFieldType({
name,
path,
required,
defaultValue,
validate: memoizedValidate,
@@ -59,7 +59,7 @@ const NumberField = (props) => {
message={errorMessage}
/>
<Label
htmlFor={name}
htmlFor={path}
label={label}
required={required}
/>
@@ -69,8 +69,8 @@ const NumberField = (props) => {
disabled={formProcessing ? 'disabled' : undefined}
placeholder={placeholder}
type="number"
id={name}
name={name}
id={path}
name={path}
/>
</div>
);

View File

@@ -10,7 +10,7 @@ import './index.scss';
const Password = (props) => {
const {
name,
path,
required,
defaultValue,
validate,
@@ -26,7 +26,7 @@ const Password = (props) => {
onFieldChange,
errorMessage,
} = useFieldType({
name,
path,
required,
defaultValue,
validate,
@@ -51,7 +51,7 @@ const Password = (props) => {
message={errorMessage}
/>
<Label
htmlFor={name}
htmlFor={path}
label={label}
required={required}
/>
@@ -61,8 +61,8 @@ const Password = (props) => {
disabled={processing ? 'disabled' : undefined}
type="password"
autoComplete="current-password"
id={name}
name={name}
id={path}
name={path}
/>
</div>
);
@@ -77,7 +77,7 @@ Password.defaultProps = {
};
Password.propTypes = {
name: PropTypes.string.isRequired,
path: PropTypes.string.isRequired,
required: PropTypes.bool,
defaultValue: PropTypes.string,
width: PropTypes.string,

View File

@@ -191,7 +191,7 @@ class Relationship extends Component {
const { options } = this.state;
const {
name,
path,
required,
style,
width,
@@ -229,7 +229,7 @@ class Relationship extends Component {
message={errorMessage}
/>
<Label
htmlFor={name}
htmlFor={path}
label={label}
required={required}
/>
@@ -277,7 +277,7 @@ Relationship.propTypes = {
errorMessage: PropTypes.string,
showError: PropTypes.bool,
label: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
path: PropTypes.string.isRequired,
formProcessing: PropTypes.bool,
width: PropTypes.string,
hasMany: PropTypes.bool,

View File

@@ -27,6 +27,7 @@ const Repeater = (props) => {
const {
name,
path,
fields,
defaultValue,
singularLabel,
@@ -35,7 +36,7 @@ const Repeater = (props) => {
const addRow = (rowIndex) => {
dispatchFields({
type: 'ADD_ROW', rowIndex, name, fieldSchema: fields,
type: 'ADD_ROW', rowIndex, path, fieldSchema: fields,
});
dispatchCollapsibleStates({
@@ -48,7 +49,7 @@ const Repeater = (props) => {
const removeRow = (rowIndex) => {
dispatchFields({
type: 'REMOVE_ROW', rowIndex, name, fields,
type: 'REMOVE_ROW', rowIndex, path, fields,
});
dispatchCollapsibleStates({
@@ -62,7 +63,7 @@ const Repeater = (props) => {
const moveRow = (moveFromIndex, moveToIndex) => {
dispatchFields({
type: 'MOVE_ROW', moveFromIndex, moveToIndex, name,
type: 'MOVE_ROW', moveFromIndex, moveToIndex, path,
});
dispatchCollapsibleStates({
@@ -83,7 +84,7 @@ const Repeater = (props) => {
}, [defaultValue]);
const updateRowCountOnParentRowModified = () => {
const countedRows = countRows(name);
const countedRows = countRows(path);
setRowCount(countedRows);
};
@@ -112,7 +113,7 @@ const Repeater = (props) => {
<DraggableSection
fieldTypes={fieldTypes}
key={rowIndex}
parentName={name}
parentPath={path}
singularLabel={singularLabel}
addRow={() => addRow(rowIndex)}
removeRow={() => removeRow(rowIndex)}
@@ -162,6 +163,7 @@ Repeater.propTypes = {
label: PropTypes.string,
singularLabel: PropTypes.string,
name: PropTypes.string.isRequired,
path: PropTypes.string.isRequired,
fieldTypes: PropTypes.shape({}).isRequired,
};

View File

@@ -7,7 +7,7 @@ import './index.scss';
const Row = (props) => {
const {
fields, fieldTypes, name, defaultValue,
fields, fieldTypes, defaultValue, path,
} = props;
return (
@@ -17,7 +17,7 @@ const Row = (props) => {
fieldSchema={fields.map((field) => {
return {
...field,
name: `${name ? `${name}.` : ''}${field.name}`,
path: `${path ? `${path}.` : ''}${field.name}`,
defaultValue: defaultValue ? defaultValue[field.name] : null,
};
})}
@@ -27,7 +27,7 @@ const Row = (props) => {
};
Row.defaultProps = {
name: '',
path: '',
defaultValue: null,
};
@@ -36,7 +36,7 @@ Row.propTypes = {
PropTypes.shape({}),
).isRequired,
fieldTypes: PropTypes.shape({}).isRequired,
name: PropTypes.string,
path: PropTypes.string,
defaultValue: PropTypes.shape({}),
};

View File

@@ -53,7 +53,7 @@ const formatRenderValue = (value) => {
const Select = (props) => {
const {
name,
path,
required,
defaultValue,
validate,
@@ -71,7 +71,7 @@ const Select = (props) => {
onFieldChange,
errorMessage,
} = useFieldType({
name,
path,
label,
required,
defaultValue,
@@ -97,7 +97,7 @@ const Select = (props) => {
message={errorMessage}
/>
<Label
htmlFor={name}
htmlFor={path}
label={label}
required={required}
/>
@@ -132,7 +132,7 @@ Select.propTypes = {
PropTypes.array,
]),
validate: PropTypes.func,
name: PropTypes.string.isRequired,
path: PropTypes.string.isRequired,
width: PropTypes.string,
options: PropTypes.oneOfType([
PropTypes.arrayOf(

View File

@@ -10,7 +10,7 @@ import './index.scss';
const Text = (props) => {
const {
name,
path,
required,
defaultValue,
validate,
@@ -27,7 +27,7 @@ const Text = (props) => {
formProcessing,
errorMessage,
} = useFieldType({
name,
path,
required,
defaultValue,
validate,
@@ -52,7 +52,7 @@ const Text = (props) => {
message={errorMessage}
/>
<Label
htmlFor={name}
htmlFor={path}
label={label}
required={required}
/>
@@ -62,8 +62,8 @@ const Text = (props) => {
disabled={formProcessing ? 'disabled' : undefined}
placeholder={placeholder}
type="text"
id={name}
name={name}
id={path}
name={path}
/>
</div>
);
@@ -80,7 +80,7 @@ Text.defaultProps = {
};
Text.propTypes = {
name: PropTypes.string.isRequired,
path: PropTypes.string.isRequired,
required: PropTypes.bool,
placeholder: PropTypes.string,
defaultValue: PropTypes.string,

View File

@@ -10,7 +10,7 @@ import './index.scss';
const Textarea = (props) => {
const {
name,
path,
required,
defaultValue,
validate,
@@ -27,7 +27,7 @@ const Textarea = (props) => {
formProcessing,
errorMessage,
} = useFieldType({
name,
path,
required,
defaultValue,
validate,
@@ -52,7 +52,7 @@ const Textarea = (props) => {
message={errorMessage}
/>
<Label
htmlFor={name}
htmlFor={path}
label={label}
required={required}
/>
@@ -61,8 +61,8 @@ const Textarea = (props) => {
onChange={onFieldChange}
disabled={formProcessing ? 'disabled' : undefined}
placeholder={placeholder}
id={name}
name={name}
id={path}
name={path}
/>
</div>
);
@@ -79,7 +79,7 @@ Textarea.defaultProps = {
};
Textarea.propTypes = {
name: PropTypes.string.isRequired,
path: PropTypes.string.isRequired,
required: PropTypes.bool,
defaultValue: PropTypes.string,
validate: PropTypes.func,

View File

@@ -44,8 +44,8 @@ class Media extends Component {
value={this.props.value || ''}
onChange={this.props.onChange}
type="hidden"
id={this.props.id ? this.props.id : this.props.name}
name={this.props.name}
id={this.props.id ? this.props.id : this.props.path}
name={this.props.path}
/>
{!this.props.value
&& (

View File

@@ -6,7 +6,7 @@ import './index.scss';
const useFieldType = (options) => {
const {
name,
path,
required,
defaultValue,
onChange,
@@ -20,12 +20,12 @@ const useFieldType = (options) => {
dispatchFields, submitted, processing, fields,
} = formContext;
let mountValue = formContext.fields[name]?.value;
let mountValue = formContext.fields[path]?.value;
if (!mountValue && mountValue !== false) mountValue = null;
const sendField = useCallback((valueToSend) => {
const fieldToDispatch = { name, value: valueToSend };
const fieldToDispatch = { path, value: valueToSend };
fieldToDispatch.valid = (required && typeof validate === 'function') ? validate(valueToSend || '') : true;
@@ -35,7 +35,7 @@ const useFieldType = (options) => {
}
dispatchFields(fieldToDispatch);
}, [name, required, dispatchFields, validate]);
}, [path, required, dispatchFields, validate]);
// Send value up to form on mount and when value changes
useEffect(() => {
@@ -48,8 +48,8 @@ const useFieldType = (options) => {
// Remove field from state on "unmount"
useEffect(() => {
return () => dispatchFields({ name, type: 'REMOVE' });
}, [dispatchFields, name]);
return () => dispatchFields({ path, type: 'REMOVE' });
}, [dispatchFields, path]);
// Send up new value when default is loaded
// only if it's not null
@@ -57,20 +57,17 @@ const useFieldType = (options) => {
if (defaultValue != null) sendField(defaultValue);
}, [defaultValue, sendField]);
const valid = formContext.fields[name] ? formContext.fields[name].valid : true;
const valid = formContext.fields[path] ? formContext.fields[path].valid : true;
const showError = valid === false && formContext.submitted;
const valueToRender = formContext.fields[name] ? formContext.fields[name].value : '';
const valueToRender = formContext.fields[path] ? formContext.fields[path].value : '';
// if (!valid) {
// console.log(formContext.fields[name]);
// }
return {
...options,
showError,
sendField,
errorMessage: formContext?.fields[name]?.errorMessage,
errorMessage: formContext?.fields[path]?.errorMessage,
value: valueToRender,
formSubmitted: submitted,
formProcessing: processing,

View File

@@ -6,8 +6,6 @@ import Loading from '../../elements/Loading';
const RenderCustomComponent = (props) => {
const { path, DefaultComponent, componentProps } = props;
console.log(path);
if (path) {
const CustomComponent = path.split('.').reduce((res, prop) => {
const potentialRowIndex = parseInt(prop, 10);